Twelve components still compared key names themselves, so the shortcut table could drift from what they actually did; a guard listed them as pending. Each now reads its effect from RACCOURCIS through effetDe, the pending list and its guard are removed, and the generated shortcut table is unchanged. The keys the old guard pinned without a behaviour test (Escape on the plan root with no active element, ArrowLeft in the grid, and those of the participant and table lists) each gain one. Checked: 3852 node, 766 browser, 101 long tests, from the index alone. --- FR --- [REF] interface : chaque touche lue par la table des raccourcis Douze composants comparaient encore eux-mêmes les noms de touches : la table des raccourcis pouvait s'écarter de ce qu'ils faisaient, et une garde les tenait en attente. Chacun lit désormais son effet dans RACCOURCIS par effetDe ; la liste d'attente et sa garde disparaissent, la table engendrée ne change pas. Les touches que l'ancienne garde figeait sans épreuve de comportement (Échap sur le plan sans élément actif, flèche gauche dans la grille, listes des personnes et des tables) en reçoivent chacune une. Vérifié : 3852 node, 766 navigateur, 101 longues, depuis l'index seul. Assisted-by: Claude Opus 5.5
96 lines
3.1 KiB
Svelte
96 lines
3.1 KiB
Svelte
<!-- © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
|
|
|
|
<script>
|
|
// La réserve visible (§ 7.1, § 5.8) : les personnes en attente au tour
|
|
// affiché, celles de l'état des places (EtatPlaces.reserve, A5) — avant
|
|
// toute proposition, chaque personne qu'aucune réservation n'assied à ce
|
|
// tour —, par identifiant croissant. Chacune est un bouton
|
|
// [data-participant] qui en fait la personne choisie (ui.choix), puis
|
|
// l'oublie ; aria-pressed dit la personne choisie. Aucun glisser ne part
|
|
// d'une liste vers le plan : la place se choisit ensuite sur le plan. Un
|
|
// changement de tour change la liste et oublie le choix (etat_ui.js) ;
|
|
// Échap, sur la réserve ou l'un de ses boutons, l'oublie aussi.
|
|
// Le panneau lit 'seance' et 'ui' au contexte ; etatTour, l'état des
|
|
// places du tour affiché, que SectionPlan calcule, ou null sans événement.
|
|
import { getContext } from 'svelte';
|
|
import { effetDe } from '../raccourcis.js';
|
|
import { nomDeCharge } from './vue_plan.js';
|
|
|
|
let { etatTour } = $props();
|
|
|
|
const t = getContext('t');
|
|
const seance = getContext('seance');
|
|
const ui = getContext('ui');
|
|
const uid = $props.id();
|
|
|
|
const charge = $derived($seance.charge);
|
|
const tour = $derived(etatTour === null ? 1 : etatTour.tour);
|
|
const reserve = $derived(etatTour === null ? [] : etatTour.reserve);
|
|
const nomDe = $derived(charge === null ? null : nomDeCharge(charge));
|
|
const choix = $derived($ui.choix);
|
|
const choisie = (id) => choix !== null && choix.genre === 'personne' && choix.participant === id;
|
|
|
|
function basculer(id) {
|
|
ui.choisir(choisie(id) ? null : { genre: 'personne', participant: id, depuis: null });
|
|
}
|
|
|
|
function surTouche(evenement) {
|
|
if (effetDe('plan', evenement.key) !== 'remonter' || choix === null) return;
|
|
evenement.preventDefault();
|
|
ui.choisir(null);
|
|
}
|
|
</script>
|
|
|
|
<!-- Échap remonte des boutons de la réserve jusqu'à elle, qui oublie le choix. -->
|
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
<section data-reserve={tour} aria-labelledby="{uid}-titre" onkeydown={surTouche}>
|
|
<h3 id="{uid}-titre">{t('plan.reserve.titre')}</h3>
|
|
{#if charge !== null}
|
|
<p>{t('plan.reserve.tour', { tour })}</p>
|
|
{#if reserve.length === 0}
|
|
<p>{t('plan.reserve.vide')}</p>
|
|
{:else}
|
|
<ul>
|
|
{#each reserve as id (id)}
|
|
<li>
|
|
<button type="button" data-participant={id} aria-pressed={choisie(id)} onclick={() => basculer(id)}>{nomDe(id)}</button>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
{/if}
|
|
{/if}
|
|
</section>
|
|
|
|
<style>
|
|
section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--espace-1);
|
|
}
|
|
|
|
h3,
|
|
p {
|
|
margin: 0;
|
|
}
|
|
|
|
h3 {
|
|
font-size: var(--taille-texte);
|
|
}
|
|
|
|
ul {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--espace-1);
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
/* La personne choisie se dit par aria-pressed et par sa forme : un trait
|
|
épais et du gras. */
|
|
button[aria-pressed='true'] {
|
|
border-width: 3px;
|
|
font-weight: 700;
|
|
}
|
|
</style>
|