gestion_table_tournante_libre/src/interface/plan/Reserve.svelte
Mathieu Benoit 13bf16b5be [REF] interface: read every key through the shortcut table
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
2026-10-10 17:25:03 -04:00

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>