Composant · Structure
PanelSection
StableUne section d'un PanelStack : un en-tête (titre, contrôles
optionnels) et un corps. C'est la brique d'un panneau latéral découpé en régions —
filtres, détails, conversation. Le corps reste monté en permanence : le
repli est purement CSS, si bien qu'un contenu à état (carte, éditeur, session de chat)
survit à un repli/dépli sans être remonté.
À utiliser dans un PanelStack
PanelSection est conçu pour vivre dans un PanelStack, qui décide
seul de la forme (shape), de la section dépliée et de l'unique section
propriétaire du défilement. Sans stack ancêtre, une section se replie sur un comportement
sain — dépliée, propriétaire du défilement, non primaire — mais elle perd toute
coordination avec ses voisines.
Forme « sticky-item »
Forme par défaut : une seule section dépliée à la fois, tous les en-têtes
restant visibles. Chaque en-tête replié est un bouton de divulgation
(aria-expanded / aria-controls) qui étiquette sa région.
Panneau latéral à trois sections
Voir le code (Svelte)
<div style="block-size:20rem;inline-size:min(100%, 26rem);border:1px solid var(--st-semantic-border-subtle);border-radius:0.5rem;padding:0 0.5rem;overflow:hidden">
<PanelStack label="Panneau latéral" defaultExpanded="filters">
<PanelSection id="filters" label="Filtres">
<p style="margin:0 0 0.75rem;font-size:0.875rem">La section ouverte possède le défilement ; les autres restent réduites à leur en-tête.</p>
<p style="margin:0 0 0.75rem;font-size:0.875rem">Période : 30 derniers jours.</p>
<p style="margin:0 0 0.75rem;font-size:0.875rem">Statut : en cours.</p>
</PanelSection>
<PanelSection id="details" label="Détails">
<p style="margin:0 0 0.75rem;font-size:0.875rem">Métadonnées de l'élément.</p>
</PanelSection>
<PanelSection id="history" label="Historique">
<p style="margin:0 0 0.75rem;font-size:0.875rem">Douze événements.</p>
</PanelSection>
</PanelStack>
</div>Forme « split-primary »
Une section primaire est toujours dépliée et possède le défilement ; les
autres sont des divulgations dimensionnées par leur contenu. La primaire n'affiche
volontairement pas de bouton : elle ne peut pas se replier, une affordance
de repli mentirait. Elle conserve un plancher utile (primaryMinHeight, 160 px
par défaut) : sous ce seuil, c'est une secondaire qui se replie plutôt que la primaire qui
s'écrase.
Conversation primaire + annexes
Voir le code (Svelte)
<div style="block-size:20rem;inline-size:min(100%, 26rem);border:1px solid var(--st-semantic-border-subtle);border-radius:0.5rem;padding:0 0.5rem;overflow:hidden">
<PanelStack shape="split-primary" label="Panneau d'assistance" primary="chat">
<PanelSection id="chat" label="Conversation">
<p style="margin:0 0 0.75rem;font-size:0.875rem">Section primaire : toujours dépliée, sans affordance de repli, propriétaire du défilement.</p>
<p style="margin:0 0 0.75rem;font-size:0.875rem">Message 1</p>
<p style="margin:0 0 0.75rem;font-size:0.875rem">Message 2</p>
<p style="margin:0 0 0.75rem;font-size:0.875rem">Message 3</p>
</PanelSection>
<PanelSection id="sources" label="Sources">
<p style="margin:0 0 0.75rem;font-size:0.875rem">Trois documents cités.</p>
</PanelSection>
<PanelSection id="settings" label="Réglages">
<p style="margin:0 0 0.75rem;font-size:0.875rem">Modèle, température.</p>
</PanelSection>
</PanelStack>
</div>Au plus quatre sections par stack (PANEL_STACK_MAX_SECTIONS) : au-delà, empiler des régions repliables dans un panneau rend le défilement ingérable. Le dépassement est signalé par un avertissement en développement, jamais par une troncature silencieuse.
API du composant
| Prop | Type | Défaut | Description |
|---|---|---|---|
id | string | requis | Identifiant de la section : c'est par lui que le stack la désigne (expanded, primary). |
label | string | requis | Titre affiché dans l'en-tête. |
children | Snippet | — | Contenu du corps de la section. |
actions | Snippet | — | Contrôles en fin d'en-tête (boutons, compteurs). |
class | string | — | Classe CSS supplémentaire sur la racine. |
React, Vue et Angular exposent la même API ; en Angular, actions est un booléen qui active le slot (slot="actions"), faute de pouvoir détecter du contenu projeté optionnel.
Le parent : PanelStack
| Prop | Type | Défaut | Description |
|---|---|---|---|
shape | 'sticky-item' | 'split-primary' | 'sticky-item' | Règle de coordination des sections. |
label | string | — | Nom accessible de la région du stack. |
expanded / defaultExpanded | string | null | — | sticky-item : id de la section dépliée, contrôlé ou en graine. |
onExpandedChange | (id: string | null) => void | — | Notification de changement. |
primary | string | — | split-primary : id de la section propriétaire du défilement. |
primaryMinHeight | number | 160 | Plancher utile de la primaire, en px. |
Angular — limite connue. Déclarez les PanelSection directement
dans le template du PanelStack. Des sections produites par @for, ou
des sections statiques mêlées à des sections sous @if / @for,
reçoivent l'état du stack trop tard : en mode développement, Angular lève NG0100 (ExpressionChangedAfterItHasBeenChecked) ; en production, la première image
montre ces sections avec leurs défauts hors stack (dépliées, chacune propriétaire du défilement),
et dans une application sans zone.js elles restent ainsi tant que rien ne les fait revérifier
(une interaction, par exemple). Limite non corrigée à ce jour.
Tokens CSS
| Variable CSS | Description |
|---|---|
--st-component-accordion-paddingBlock / -paddingInline | Rembourrage de l'en-tête. |
--st-component-accordion-fontSize / -fontWeight / -lineHeight / -text | Typographie du titre de section. |
--st-component-control-hoverBackground | Survol de l'en-tête repliable. |
--st-component-control-border | Séparateur entre deux sections. |
--st-component-panelStack-primaryMinBlockSize | Plancher CSS de la section propriétaire du défilement, émis par PanelStack depuis primaryMinHeight. |
--st-semantic-border-focus | Anneau de focus de l'en-tête. Point de surcharge uniquement : aucun thème ne le définit, le composant retombe sur --st-semantic-brand-default tant que vous ne lui donnez pas de valeur. |