@starterlib/ui 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,10 @@
1
- import * as _angular_core from '@angular/core';
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Type, TemplateRef, Signal } from '@angular/core';
2
3
  import * as i1 from '@angular/aria/menu';
3
- import { Ton } from '@starterlib/util';
4
+ import { Ton, TonSemantique } from '@starterlib/util';
5
+ import { CdkDialogContainer } from '@angular/cdk/dialog';
6
+ export { DIALOG_DATA as DONNEES_DE_DIALOGUE } from '@angular/cdk/dialog';
7
+ import { NomDIcone, AnnonceLocale } from '@starterlib/ui';
4
8
 
5
9
  type AlignementDeMenu = 'debut' | 'fin';
6
10
  /**
@@ -36,10 +40,10 @@ declare class StMenu {
36
40
  private readonly overlay;
37
41
  private readonly aria;
38
42
  /** Nom du menu pour les technologies d'assistance. */
39
- readonly etiquette: _angular_core.InputSignal<string>;
40
- readonly alignement: _angular_core.InputSignal<AlignementDeMenu>;
43
+ readonly etiquette: i0.InputSignal<string>;
44
+ readonly alignement: i0.InputSignal<AlignementDeMenu>;
41
45
  private readonly ouvertInterne;
42
- readonly ouvert: _angular_core.Signal<boolean>;
46
+ readonly ouvert: i0.Signal<boolean>;
43
47
  private couche;
44
48
  private declencheur;
45
49
  constructor();
@@ -54,8 +58,8 @@ declare class StMenu {
54
58
  basculerDepuis(declencheur: HTMLElement): void;
55
59
  protected auClavier(evenement: KeyboardEvent): void;
56
60
  private detruireLaCouche;
57
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StMenu, never>;
58
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StMenu, "st-menu", never, { "etiquette": { "alias": "etiquette"; "required": true; "isSignal": true; }; "alignement": { "alias": "alignement"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, [{ directive: typeof i1.Menu; inputs: { "wrap": "wrap"; "typeaheadDelay": "typeaheadDelay"; "disabled": "disabled"; }; outputs: { "itemSelected": "selection"; }; }]>;
61
+ static ɵfac: i0.ɵɵFactoryDeclaration<StMenu, never>;
62
+ static ɵcmp: i0.ɵɵComponentDeclaration<StMenu, "st-menu", never, { "etiquette": { "alias": "etiquette"; "required": true; "isSignal": true; }; "alignement": { "alias": "alignement"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, [{ directive: typeof i1.Menu; inputs: { "wrap": "wrap"; "typeaheadDelay": "typeaheadDelay"; "disabled": "disabled"; }; outputs: { "itemSelected": "selection"; }; }]>;
59
63
  }
60
64
 
61
65
  /**
@@ -78,10 +82,10 @@ type TonDElementDeMenu = Extract<Ton, 'neutre' | 'danger'>;
78
82
  * actions par leur libelle, donc par leur traduction.
79
83
  */
80
84
  declare class StMenuItem {
81
- readonly icone: _angular_core.InputSignal<"boite-vide" | "cercle" | "cercle-coche" | "cercle-croix" | "cercle-info" | "chevron-bas" | "chevron-droite" | "chevron-gauche" | "chevron-haut" | "coche" | "copie" | "corbeille" | "croix" | "hors-ligne" | "lien-externe" | "menu" | "oeil" | "oeil-barre" | "plus" | "rafraichir" | "recherche" | "serveur" | "triangle-alerte" | "utilisateur" | null>;
82
- readonly ton: _angular_core.InputSignal<TonDElementDeMenu>;
83
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StMenuItem, never>;
84
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StMenuItem, "button[stMenuItem]", never, { "icone": { "alias": "icone"; "required": false; "isSignal": true; }; "ton": { "alias": "ton"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, [{ directive: typeof i1.MenuItem; inputs: { "value": "valeur"; "disabled": "desactive"; "role": "role"; }; outputs: {}; }]>;
85
+ readonly icone: i0.InputSignal<"boite-vide" | "calendrier" | "cercle" | "cercle-coche" | "cercle-croix" | "cercle-info" | "chevron-bas" | "chevron-droite" | "chevron-gauche" | "chevron-haut" | "coche" | "copie" | "corbeille" | "croix" | "fichier" | "hors-ligne" | "lien-externe" | "menu" | "oeil" | "oeil-barre" | "plus" | "rafraichir" | "recherche" | "serveur" | "televerser" | "triangle-alerte" | "utilisateur" | null>;
86
+ readonly ton: i0.InputSignal<TonDElementDeMenu>;
87
+ static ɵfac: i0.ɵɵFactoryDeclaration<StMenuItem, never>;
88
+ static ɵcmp: i0.ɵɵComponentDeclaration<StMenuItem, "button[stMenuItem]", never, { "icone": { "alias": "icone"; "required": false; "isSignal": true; }; "ton": { "alias": "ton"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, [{ directive: typeof i1.MenuItem; inputs: { "value": "valeur"; "disabled": "desactive"; "role": "role"; }; outputs: {}; }]>;
85
89
  }
86
90
 
87
91
  /**
@@ -97,12 +101,599 @@ declare class StMenuItem {
97
101
  */
98
102
  declare class StMenuTrigger {
99
103
  private readonly element;
100
- readonly menu: _angular_core.InputSignal<StMenu>;
104
+ readonly menu: i0.InputSignal<StMenu>;
101
105
  protected basculer(): void;
102
106
  protected auClavier(evenement: KeyboardEvent): void;
103
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StMenuTrigger, never>;
104
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<StMenuTrigger, "[stMenuTrigger]", never, { "menu": { "alias": "menu"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
107
+ static ɵfac: i0.ɵɵFactoryDeclaration<StMenuTrigger, never>;
108
+ static ɵdir: i0.ɵɵDirectiveDeclaration<StMenuTrigger, "[stMenuTrigger]", never, { "menu": { "alias": "menu"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
105
109
  }
106
110
 
107
- export { StMenu, StMenuItem, StMenuTrigger };
108
- export type { AlignementDeMenu, TonDElementDeMenu };
111
+ /**
112
+ * Identifiant du titre du dialogue, decide a l'ouverture et fourni au contenu.
113
+ *
114
+ * ⚠️ Il est engendre par le service et non par le composant de titre : c'est la
115
+ * configuration du dialogue qui doit porter `aria-labelledby`, et elle est
116
+ * figee a l'ouverture. Un identifiant decide plus tard arriverait apres que le
117
+ * conteneur a lu sa configuration, et le dialogue s'ouvrirait sans nom.
118
+ */
119
+ declare const IDENTIFIANT_DU_TITRE: InjectionToken<string>;
120
+
121
+ /**
122
+ * Ce que l'appelant decrit pour obtenir une confirmation.
123
+ *
124
+ * ⚠️ **Une confirmation d'interface n'est pas un controle.** Elle protege
125
+ * contre le geste distrait, pas contre quelqu'un qui appelle l'API directement.
126
+ * Le serveur autorise, et une action sensible — suppression de compte,
127
+ * changement d'IBAN — merite une re-authentification par second facteur, que le
128
+ * backend sait deja demander.
129
+ */
130
+ interface DemandeDeConfirmation {
131
+ readonly titre: string;
132
+ readonly message: string;
133
+ readonly libelleConfirmation?: string;
134
+ readonly libelleAnnulation?: string;
135
+ /** L'action detruit quelque chose : le bouton passe en `danger`. */
136
+ readonly destructeur?: boolean;
137
+ /**
138
+ * Texte que la personne doit recopier pour confirmer.
139
+ *
140
+ * ⚠️ A reserver a l'irreversible. Ce n'est pas une ceinture de securite de
141
+ * plus : c'est le seul moyen de rompre l'automatisme de qui clique « Oui »
142
+ * sans lire, et son cout — une saisie — n'est justifie que la ou l'erreur ne
143
+ * se repare pas.
144
+ */
145
+ readonly saisieDeConfirmation?: string;
146
+ }
147
+ /**
148
+ * Dialogue de confirmation.
149
+ *
150
+ * ⚠️ **Le bouton de confirmation n'est jamais celui qui recoit le focus.** Le
151
+ * dialogue entier le recoit (voir `StDialog`), et le premier arret de
152
+ * tabulation est l'annulation. Un dialogue destructeur dont le bouton dangereux
153
+ * est deja focalise se valide par une seule touche Entree — c'est-a-dire par le
154
+ * geste que la personne etait en train de faire quand il s'est ouvert.
155
+ */
156
+ declare class StConfirmDialog {
157
+ private readonly reference;
158
+ private readonly libelles;
159
+ protected readonly demande: DemandeDeConfirmation;
160
+ protected readonly saisie: i0.WritableSignal<string>;
161
+ /** Unique par instance : deux confirmations empilees dupliqueraient un identifiant fixe. */
162
+ protected readonly identifiantDeSaisie: string;
163
+ protected readonly ton: i0.Signal<TonSemantique>;
164
+ protected readonly libelleConfirmation: i0.Signal<string>;
165
+ protected readonly libelleAnnulation: i0.Signal<string>;
166
+ protected readonly libelleRecopie: i0.Signal<string>;
167
+ /**
168
+ * ⚠️ La comparaison ignore la casse et les espaces de bord, mais RIEN
169
+ * d'autre. Exiger la casse exacte transforme une confirmation en jeu
170
+ * d'adresse, et pousse a copier-coller — ce qui annule precisement l'effet
171
+ * recherche.
172
+ */
173
+ protected readonly confirmationPossible: i0.Signal<boolean>;
174
+ protected auChangement(evenement: Event): void;
175
+ protected confirmer(): void;
176
+ protected annuler(): void;
177
+ static ɵfac: i0.ɵɵFactoryDeclaration<StConfirmDialog, never>;
178
+ static ɵcmp: i0.ɵɵComponentDeclaration<StConfirmDialog, "st-confirm-dialog", never, {}, {}, never, never, true, never>;
179
+ }
180
+
181
+ /** Ce que l'appelant regle a l'ouverture. */
182
+ interface OptionsDeDialogue<D = unknown> {
183
+ /** Donnees passees au composant, lisibles par `DONNEES_DE_DIALOGUE`. */
184
+ readonly donnees?: D;
185
+ /**
186
+ * Nom accessible quand le dialogue n'affiche pas de `st-dialog-title`.
187
+ * Inutile — et ignore — des qu'un titre est present.
188
+ */
189
+ readonly etiquette?: string;
190
+ /**
191
+ * Interdit Echap et le clic sur le fond.
192
+ *
193
+ * ⚠️ A reserver aux dialogues qui perdraient du travail en se fermant. Un
194
+ * dialogue qu'on ne peut pas fermer au clavier est une impasse pour qui
195
+ * n'utilise pas la souris ; la fermeture doit alors exister ailleurs, en
196
+ * toutes lettres.
197
+ */
198
+ readonly fermetureInterdite?: boolean;
199
+ /**
200
+ * Ignore le clic sur le fond, mais laisse Echap fermer.
201
+ *
202
+ * ⚠️ La distinction compte, et le CDK ne la fait pas : son `disableClose`
203
+ * bloque les DEUX. Or le clic hors du panneau est le geste le plus facile a
204
+ * faire par megarde, tandis qu'Echap est un choix delibere — et, sur une
205
+ * confirmation, il vaut ANNULER, ce qui est sans danger. Bloquer Echap ne
206
+ * protege rien et prive le clavier de sa sortie.
207
+ */
208
+ readonly fondInerte?: boolean;
209
+ /**
210
+ * `alertdialog` pour ce qui exige une reponse immediate : une session qui
211
+ * expire, une perte imminente. Le lecteur d'ecran l'annonce avec plus
212
+ * d'insistance qu'un dialogue ordinaire — a ne pas galvauder.
213
+ */
214
+ readonly role?: 'dialog' | 'alertdialog';
215
+ /**
216
+ * Selecteur de l'element qui recoit le focus a l'ouverture, a la place du
217
+ * dialogue lui-meme.
218
+ *
219
+ * ⚠️ Pour un `alertdialog`, le motif ARIA veut le focus sur l'action la MOINS
220
+ * destructrice : « Rester connecte », jamais « Se deconnecter ». Une touche
221
+ * Entree reflexe ne doit rien detruire.
222
+ */
223
+ readonly focusInitial?: string;
224
+ /** Identifiant du texte qui DECRIT le dialogue, lu a l'ouverture apres son nom. */
225
+ readonly descriptionDe?: string;
226
+ readonly largeur?: string;
227
+ readonly classe?: string;
228
+ /**
229
+ * Ancre le panneau sur un bord : c'est le TIROIR.
230
+ *
231
+ * ⚠️ Un tiroir modal EST un dialogue — meme role, meme piegeage du focus,
232
+ * meme Echap. Seule sa geometrie change. Lui donner son propre service
233
+ * dupliquerait toute la machinerie d'accessibilite pour une difference de
234
+ * position, et la copie finirait par deriver de l'original.
235
+ *
236
+ * `debut` et `fin` suivent le sens d'ecriture ; `bas` donne la feuille
237
+ * inferieure, qui est la forme utile sur telephone.
238
+ */
239
+ readonly cote?: CoteDuTiroir;
240
+ }
241
+ /** Bord auquel un tiroir s'ancre. Logique, donc juste aussi en ecriture droite a gauche. */
242
+ type CoteDuTiroir = 'debut' | 'fin' | 'bas';
243
+ /** Reference sur un dialogue ouvert. */
244
+ interface ReferenceDeDialogue<R> {
245
+ /** Resout a la fermeture. `undefined` quand le dialogue est simplement quitte. */
246
+ readonly ferme: Promise<R | undefined>;
247
+ fermer(resultat?: R): void;
248
+ }
249
+ /**
250
+ * Ouvre des dialogues modaux.
251
+ *
252
+ * ⚠️ Monte sur `@angular/cdk/dialog`, et c'est un choix defendu : le piegeage
253
+ * du focus, sa restauration au declencheur, `aria-modal`, la mise en retrait du
254
+ * reste de la page, Echap et le blocage du defilement sont longs a ecrire,
255
+ * faciles a croire finis, et c'est exactement la que l'accessibilite se perd.
256
+ * Le socle n'en reecrit aucune part.
257
+ *
258
+ * Ce qu'il ajoute au CDK : le focus sur le dialogue, `aria-modal`, un fond inerte
259
+ * qui laisse Echap fermer, et la fermeture a toute navigation du routeur.
260
+ */
261
+ declare class StDialog {
262
+ private readonly cdk;
263
+ private readonly overlay;
264
+ /** Une fonction de fermeture par dialogue ouvert : c'est tout ce qu'il faut garder. */
265
+ private readonly ouverts;
266
+ constructor();
267
+ /**
268
+ * Ouvre un composant, ou un GABARIT.
269
+ *
270
+ * Un gabarit sert quand le contenu vit deja dans le composant appelant — un
271
+ * tiroir de navigation qui deplace ses propres liens sur petit ecran. ⚠️ Son
272
+ * injecteur reste celui de l'endroit ou il est ECRIT : un `st-dialog-title`
273
+ * pose dedans ne recoit pas l'identifiant de titre, et le dialogue se nomme
274
+ * alors par `etiquette`.
275
+ */
276
+ ouvrir<R = unknown, D = unknown>(composant: Type<unknown> | TemplateRef<unknown>, options?: OptionsDeDialogue<D>): ReferenceDeDialogue<R>;
277
+ /**
278
+ * ⚠️ Un tiroir occupe toute la hauteur du bord ou il s'ancre, et une feuille
279
+ * inferieure toute la largeur. Sans cela, le panneau flotte au milieu et ne
280
+ * se lit plus comme un tiroir.
281
+ */
282
+ private geometrie;
283
+ private classes;
284
+ /**
285
+ * Demande une confirmation, et rend `true` seulement si elle est donnee.
286
+ *
287
+ * ⚠️ La fermeture par Echap ou par le fond rend `false` : quitter n'est pas
288
+ * confirmer. C'est pourquoi la valeur est comparee explicitement plutot que
289
+ * testee pour sa veracite — `undefined` doit valoir non.
290
+ */
291
+ confirmer(demande: DemandeDeConfirmation): Promise<boolean>;
292
+ static ɵfac: i0.ɵɵFactoryDeclaration<StDialog, never>;
293
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
294
+ }
295
+
296
+ /**
297
+ * Le panneau du dialogue : sa surface, son arrondi, son ombre.
298
+ *
299
+ * ⚠️ Pourquoi ce composant existe. `CdkDialogContainer` n'a **aucune
300
+ * apparence** : c'est voulu de la part du CDK, qui ne decide d'aucun style. Le
301
+ * dialogue fonctionnait donc parfaitement — role, nom, piegeage du focus,
302
+ * Echap — tout en s'affichant SANS FOND, le texte flottant par-dessus la page.
303
+ * Aucun test ne pouvait le voir : jsdom ne calcule pas la mise en page, et les
304
+ * tests verifiaient le comportement, pas l'aspect.
305
+ *
306
+ * ⚠️ Un conteneur maison plutot qu'une feuille de style globale a importer :
307
+ * une SPA qui oublierait l'import retrouverait exactement le meme defaut, et
308
+ * l'oubli ne se verrait qu'a l'ecran. Ici, l'apparence voyage avec le
309
+ * composant.
310
+ *
311
+ * L'encapsulation reste EMULEE : seuls l'hote et le panneau qui l'enveloppe
312
+ * sont styles, par `:host` et `:host-context()`. Aucun contenu projete n'est
313
+ * vise, donc rien ne justifie de rendre ces styles globaux.
314
+ */
315
+ declare class StDialogContainer extends CdkDialogContainer {
316
+ static ɵfac: i0.ɵɵFactoryDeclaration<StDialogContainer, never>;
317
+ static ɵcmp: i0.ɵɵComponentDeclaration<StDialogContainer, "st-dialog-container", never, {}, {}, never, never, true, never>;
318
+ }
319
+
320
+ /**
321
+ * Titre du dialogue. Il porte l'identifiant que la configuration a designe en
322
+ * `aria-labelledby` : c'est lui qui NOMME le dialogue.
323
+ *
324
+ * ⚠️ Un `h2` et non un `h1` : le dialogue s'ouvre par-dessus une page qui a
325
+ * deja son titre de niveau 1, et deux `h1` cassent la table des matieres que
326
+ * les lecteurs d'ecran construisent.
327
+ */
328
+ declare class StDialogTitle {
329
+ protected readonly identifiant: string | null;
330
+ static ɵfac: i0.ɵɵFactoryDeclaration<StDialogTitle, never>;
331
+ static ɵcmp: i0.ɵɵComponentDeclaration<StDialogTitle, "st-dialog-title", never, {}, {}, never, ["*"], true, never>;
332
+ }
333
+
334
+ /**
335
+ * Corps du dialogue, defilant quand il deborde.
336
+ *
337
+ * ⚠️ Le defilement est ICI et non sur le dialogue entier : titre et actions
338
+ * doivent rester visibles. Un dialogue long dont les boutons partent hors de
339
+ * l'ecran est le defaut classique, et il ne se voit qu'a 200 % d'echelle ou sur
340
+ * un ecran bas.
341
+ *
342
+ * ⚠️ **Focalisable seulement quand il defile.** Une zone defilante sans
343
+ * controle doit recevoir le focus, sinon le clavier ne peut pas la faire
344
+ * defiler — le texte d'une condition generale, par exemple. Mais la premiere
345
+ * version posait `tabindex="0"` sans condition : sur un dialogue court, la zone
346
+ * de texte devenait le premier arret de tabulation, AVANT le bouton
347
+ * d'annulation, contrairement a ce que `StConfirmDialog` affirmait.
348
+ */
349
+ declare class StDialogContent {
350
+ /** `aucun` pour un contenu qui gere ses propres marges, comme un tableau. */
351
+ readonly rembourrage: i0.InputSignal<"aucun" | "md">;
352
+ protected readonly defilante: i0.WritableSignal<boolean>;
353
+ constructor();
354
+ static ɵfac: i0.ɵɵFactoryDeclaration<StDialogContent, never>;
355
+ static ɵcmp: i0.ɵɵComponentDeclaration<StDialogContent, "st-dialog-content", never, { "rembourrage": { "alias": "rembourrage"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
356
+ }
357
+
358
+ /**
359
+ * Barre d'actions du dialogue.
360
+ *
361
+ * ⚠️ L'action de confirmation est a DROITE et l'annulation a gauche, dans cet
362
+ * ordre dans le DOM : l'ordre de tabulation doit suivre l'ordre visuel, sinon
363
+ * le clavier et la souris ne donnent pas le meme parcours. Inverser
364
+ * visuellement par `row-reverse` casserait cette correspondance.
365
+ */
366
+ declare class StDialogActions {
367
+ readonly alignement: i0.InputSignal<"debut" | "fin" | "entre">;
368
+ static ɵfac: i0.ɵɵFactoryDeclaration<StDialogActions, never>;
369
+ static ɵcmp: i0.ɵɵComponentDeclaration<StDialogActions, "st-dialog-actions", never, { "alignement": { "alias": "alignement"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
370
+ }
371
+
372
+ /** Action offerte dans le message, comme « Annuler ». */
373
+ interface ActionDeToast {
374
+ readonly libelle: string;
375
+ readonly faire: () => void;
376
+ }
377
+ /** Ce que l'appelant demande a afficher. */
378
+ interface DemandeDeToast {
379
+ /**
380
+ * ⚠️ Aucune donnee personnelle complete : un message reste a l'ecran le temps
381
+ * qu'il faut pour etre lu — et lu par-dessus l'epaule. Un IBAN, un numero de
382
+ * carte ou de telephone s'y ecrivent masques, comme le fait `st-masked`.
383
+ */
384
+ readonly message: string;
385
+ readonly ton?: TonSemantique;
386
+ /**
387
+ * ⚠️ Un message porteur d'action ne disparait PAS tout seul. WCAG 2.2.1 :
388
+ * un contenu qui s'efface sur minuterie doit pouvoir etre prolonge ou
389
+ * desactive. Un « Annuler » qui s'evanouit en quatre secondes est inutilisable
390
+ * pour qui lit lentement, navigue au clavier ou emploie un lecteur d'ecran —
391
+ * et c'est precisement la personne a qui l'annulation sert le plus.
392
+ */
393
+ readonly action?: ActionDeToast;
394
+ /**
395
+ * Duree d'affichage en millisecondes. Ignoree des qu'une action est fournie.
396
+ * `null` : le message reste jusqu'a sa fermeture.
397
+ */
398
+ readonly dureeMs?: number | null;
399
+ }
400
+ /** Un message affiche, tel que le conteneur le connait. */
401
+ interface Toast extends DemandeDeToast {
402
+ readonly identifiant: number;
403
+ readonly ton: TonSemantique;
404
+ }
405
+
406
+ /**
407
+ * Messages ephemeres.
408
+ *
409
+ * ```ts
410
+ * const messages = inject(StToast);
411
+ * messages.montrer({ message: 'Virement enregistre', ton: 'succes' });
412
+ * messages.montrer({
413
+ * message: 'Beneficiaire supprime',
414
+ * action: { libelle: 'Annuler', faire: () => this.retablir() },
415
+ * });
416
+ * ```
417
+ *
418
+ * ⚠️ **Un seul conteneur pour toute l'application**, cree a la premiere
419
+ * demande. Deux piles superposees se recouvrent, et la seconde masque la
420
+ * premiere sans que rien ne le signale.
421
+ *
422
+ * ⚠️ **A n'employer que pour ce qui peut etre manque.** Un message ephemere
423
+ * n'est pas une facon d'annoncer une erreur : si l'information compte, elle
424
+ * doit rester a l'ecran — `st-banner` pour la page, `st-inline-message` pour un
425
+ * champ. La regle de tri : si la personne qui n'a pas vu le message est
426
+ * penalisee, ce n'est pas un toast.
427
+ */
428
+ declare class StToast {
429
+ private readonly overlay;
430
+ private couche;
431
+ private conteneur;
432
+ constructor();
433
+ /** Affiche un message. Rend son identifiant, pour pouvoir le retirer. */
434
+ montrer(demande: DemandeDeToast): number;
435
+ retirer(identifiant: number): void;
436
+ private pile;
437
+ static ɵfac: i0.ɵɵFactoryDeclaration<StToast, never>;
438
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
439
+ }
440
+
441
+ /**
442
+ * Pile des messages ephemeres. Un seul exemplaire, pose par `StToast`.
443
+ *
444
+ * ⚠️ **Les messages visibles ne portent AUCUN role.** L'annonce passe par deux
445
+ * regions vivantes permanentes, creees vides avec le conteneur. La premiere
446
+ * version posait `role="status"` sur chaque message insere avec son texte :
447
+ * c'est la sequence que les lecteurs d'ecran n'annoncent pas de facon fiable,
448
+ * puisqu'ils rapportent les CHANGEMENTS d'une region deja observee. Les
449
+ * confirmations — le cas courant — risquaient le silence.
450
+ *
451
+ * ⚠️ Il ne prend JAMAIS le focus. Un message qui s'affiche pendant une saisie
452
+ * et vole le curseur fait perdre la frappe en cours.
453
+ */
454
+ declare class StToastContainer {
455
+ private readonly libelles;
456
+ private readonly pile;
457
+ private readonly minuteries;
458
+ private readonly minuteriesDAnnonce;
459
+ private compteur;
460
+ protected readonly messages: i0.Signal<readonly Toast[]>;
461
+ protected readonly annoncePolie: i0.WritableSignal<string>;
462
+ protected readonly annonceAssertive: i0.WritableSignal<string>;
463
+ protected readonly libelleFermeture: i0.Signal<string>;
464
+ constructor();
465
+ ajouter(demande: DemandeDeToast): number;
466
+ retirer(identifiant: number): void;
467
+ /**
468
+ * ⚠️ La minuterie s'arrete au survol ET au focus. Sans la seconde, une
469
+ * personne qui atteint le bouton au clavier le voit disparaitre sous son
470
+ * doigt ; sans la premiere, celle qui lit lentement n'a aucun moyen de
471
+ * retenir le message.
472
+ */
473
+ protected suspendre(identifiant: number): void;
474
+ protected reprendre(identifiant: number): void;
475
+ protected agir(toast: Toast): void;
476
+ protected iconeDe(toast: Toast): NomDIcone;
477
+ /**
478
+ * ⚠️ Un message porteur d'action n'est JAMAIS evince. La premiere version
479
+ * gardait les trois plus recents sans distinction : trois confirmations
480
+ * successives faisaient disparaitre un « Annuler » en silence — exactement ce
481
+ * que WCAG 2.2.1 interdit, et ce que le modele promettait d'eviter.
482
+ *
483
+ * Les plus anciens messages sans action partent d'abord. S'il ne reste que des
484
+ * messages porteurs d'action, la borne cede : mieux vaut une pile haute qu'une
485
+ * annulation perdue.
486
+ */
487
+ private borner;
488
+ private annoncer;
489
+ /**
490
+ * Un message porteur d'action ne s'efface pas seul : voir `DemandeDeToast`,
491
+ * et WCAG 2.2.1.
492
+ */
493
+ private programmer;
494
+ private arreterLaMinuterie;
495
+ static ɵfac: i0.ɵɵFactoryDeclaration<StToastContainer, never>;
496
+ static ɵcmp: i0.ɵɵComponentDeclaration<StToastContainer, "st-toast-container", never, {}, {}, never, never, true, never>;
497
+ }
498
+
499
+ /** Reponse donnee a l'avertissement. */
500
+ type ReponseDInactivite = 'prolonger' | 'deconnecter';
501
+ /** Ce que l'avertissement passe a son panneau. */
502
+ interface DonneesDInactivite {
503
+ readonly restant: Signal<number>;
504
+ readonly identifiantDeDescription: string;
505
+ }
506
+
507
+ /**
508
+ * Avertissement avant fermeture de session pour inactivite.
509
+ *
510
+ * ```html
511
+ * <st-idle-warning
512
+ * [secondesRestantes]="inactivite.secondesRestantes()"
513
+ * (prolonge)="inactivite.prolonger()"
514
+ * (deconnecte)="session.deconnecter()"
515
+ * />
516
+ * ```
517
+ *
518
+ * ⚠️ **Composant de PRESENTATION.** Il n'injecte pas `StInactivite` : `ui` ne
519
+ * depend pas de `@starterlib/core` (ADR 0003). Il s'ouvre quand
520
+ * `secondesRestantes` cesse d'etre `null`, et se ferme quand il y revient. La
521
+ * decision de fermer la session reste au noyau, qui la prend cote serveur.
522
+ *
523
+ * ⚠️ **Un `alertdialog`, focus sur « Rester connecte ».** Le motif ARIA veut le
524
+ * focus sur l'action la moins destructrice : une touche Entree reflexe doit
525
+ * garder la session, jamais la fermer.
526
+ *
527
+ * ⚠️ **Le clic a cote ne prolonge rien**, pour la raison que donne `StInactivite`
528
+ * du noyau : le dialogue disparaitrait sans que la session ait ete prolongee cote
529
+ * serveur. Il faut repondre. Echap, geste delibere, vaut « Rester connecte ».
530
+ */
531
+ declare class StIdleWarning {
532
+ private readonly dialogues;
533
+ /** `null` : aucun avertissement en cours. */
534
+ readonly secondesRestantes: i0.InputSignal<number | null>;
535
+ readonly prolonge: i0.OutputEmitterRef<void>;
536
+ readonly deconnecte: i0.OutputEmitterRef<void>;
537
+ private readonly restant;
538
+ private reference;
539
+ private readonly identifiantDeDescription;
540
+ constructor();
541
+ private ouvrir;
542
+ private fermerSansReponse;
543
+ static ɵfac: i0.ɵɵFactoryDeclaration<StIdleWarning, never>;
544
+ static ɵcmp: i0.ɵɵComponentDeclaration<StIdleWarning, "st-idle-warning", never, { "secondesRestantes": { "alias": "secondesRestantes"; "required": false; "isSignal": true; }; }, { "prolonge": "prolonge"; "deconnecte": "deconnecte"; }, never, never, true, never>;
545
+ }
546
+
547
+ /** Contenu du dialogue d'avertissement. Ouvert par `st-idle-warning`, jamais directement. */
548
+ declare class StIdleWarningPanel {
549
+ private readonly reference;
550
+ private readonly libelles;
551
+ private readonly locale;
552
+ protected readonly donnees: DonneesDInactivite;
553
+ protected readonly annonce: AnnonceLocale;
554
+ protected readonly titre: i0.Signal<string>;
555
+ protected readonly message: i0.Signal<string>;
556
+ protected readonly libelleRester: i0.Signal<string>;
557
+ protected readonly libelleDeconnecter: i0.Signal<string>;
558
+ constructor();
559
+ protected rester(): void;
560
+ protected deconnecter(): void;
561
+ static ɵfac: i0.ɵɵFactoryDeclaration<StIdleWarningPanel, never>;
562
+ static ɵcmp: i0.ɵɵComponentDeclaration<StIdleWarningPanel, "st-idle-warning-panel", never, {}, {}, never, never, true, never>;
563
+ }
564
+
565
+ type PositionDInfobulle = 'haut' | 'bas';
566
+ /**
567
+ * Infobulle : un complement de texte, au survol ET au focus.
568
+ *
569
+ * ```html
570
+ * <button stIconButton icone="corbeille" etiquette="Supprimer" stTooltip="Supprimer le beneficiaire"></button>
571
+ * ```
572
+ *
573
+ * WCAG 1.4.13, les trois exigences, chacune tenue ici :
574
+ *
575
+ * - **Refermable** : Echap la masque SANS deplacer le focus, et sans fermer le
576
+ * dialogue qui la contiendrait — la premiere touche est pour elle.
577
+ * - **Survolable** : le pointeur peut passer du declencheur a la bulle sans
578
+ * qu'elle disparaisse.
579
+ * - **Persistante** : elle reste tant que le survol ou le focus dure.
580
+ *
581
+ * ⚠️ **Le texte est une DESCRIPTION posee des le depart**, par un noeud
582
+ * persistant. Un `aria-describedby` qui viserait la bulle elle-meme pointerait
583
+ * vers un element absent au moment ou le focus arrive : le lecteur d'ecran,
584
+ * qui calcule la description a cet instant, ne lirait rien.
585
+ *
586
+ * ⚠️ **Jamais d'information exclusive, jamais de contenu interactif.** Sur un
587
+ * ecran tactile, il n'y a ni survol ni focus visible : l'infobulle n'existe pas.
588
+ * Ce qu'elle dit doit pouvoir manquer. Un lien ou un bouton dedans serait
589
+ * inatteignable — c'est un `st-popover` qu'il faut alors.
590
+ */
591
+ declare class StTooltip {
592
+ private readonly element;
593
+ private readonly overlay;
594
+ private readonly descripteur;
595
+ private readonly document;
596
+ readonly stTooltip: i0.InputSignal<string>;
597
+ readonly positionDInfobulle: i0.InputSignal<PositionDInfobulle>;
598
+ private couche;
599
+ private minuterie;
600
+ private description;
601
+ private readonly echap;
602
+ constructor();
603
+ protected auSurvol(): void;
604
+ protected auDepartDuPointeur(): void;
605
+ afficher(): void;
606
+ masquer(): void;
607
+ private programmer;
608
+ private annulerLaMinuterie;
609
+ private retirerLaDescription;
610
+ static ɵfac: i0.ɵɵFactoryDeclaration<StTooltip, never>;
611
+ static ɵdir: i0.ɵɵDirectiveDeclaration<StTooltip, "[stTooltip]", never, { "stTooltip": { "alias": "stTooltip"; "required": true; "isSignal": true; }; "positionDInfobulle": { "alias": "positionDInfobulle"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
612
+ }
613
+
614
+ /**
615
+ * Bulle visible d'une infobulle. Posee par `stTooltip`, jamais directement.
616
+ *
617
+ * ⚠️ Muette (`aria-hidden`) : le texte est deja lu comme DESCRIPTION du
618
+ * declencheur, par un noeud persistant. L'exposer aussi ici le ferait lire deux
619
+ * fois.
620
+ */
621
+ declare class StTooltipPanel {
622
+ readonly texte: i0.InputSignal<string>;
623
+ static ɵfac: i0.ɵɵFactoryDeclaration<StTooltipPanel, never>;
624
+ static ɵcmp: i0.ɵɵComponentDeclaration<StTooltipPanel, "st-tooltip-panel", never, { "texte": { "alias": "texte"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
625
+ }
626
+
627
+ type AlignementDePopover = 'debut' | 'fin';
628
+ /**
629
+ * Couche NON modale attachee a un declencheur : filtres rapides, detail d'une
630
+ * ligne, petit formulaire.
631
+ *
632
+ * ```html
633
+ * <button stButton [stPopoverTrigger]="filtres">Filtres</button>
634
+ * <st-popover #filtres etiquette="Filtres des operations">…</st-popover>
635
+ * ```
636
+ *
637
+ * Distinct de l'infobulle, qui ne contient que du texte, et du dialogue, qui
638
+ * piege le focus et met la page en retrait.
639
+ *
640
+ * ⚠️ **Non modale, donc aucun piege.** La tabulation peut en sortir, et la page
641
+ * reste utilisable. Mais une couche que le focus a quittee flotterait sans lien
642
+ * avec ce qu'on fait : elle se ferme quand le focus part ailleurs que sur elle
643
+ * ou son declencheur.
644
+ *
645
+ * ⚠️ **Deux fermetures, deux destinations du focus.** Echap rend le focus au
646
+ * declencheur : la personne n'a rien choisi d'autre. Un clic a l'exterieur le
647
+ * laisse la ou il a ete pose : le lui reprendre annulerait ce clic.
648
+ *
649
+ * Meme structure que `st-menu` : le declencheur DESIGNE la couche, et l'element
650
+ * est DEPLACE dans la couche d'overlay a l'ouverture, avec ses liaisons et son
651
+ * etat.
652
+ */
653
+ declare class StPopover {
654
+ private readonly element;
655
+ private readonly overlay;
656
+ /** Nom accessible : sans lui, la couche s'annonce « dialogue » et rien d'autre. */
657
+ readonly etiquette: i0.InputSignal<string>;
658
+ readonly alignement: i0.InputSignal<AlignementDePopover>;
659
+ readonly identifiant: string;
660
+ private readonly ouvertInterne;
661
+ readonly ouvert: i0.Signal<boolean>;
662
+ private couche;
663
+ private declencheur;
664
+ constructor();
665
+ basculerDepuis(declencheur: HTMLElement): void;
666
+ ouvrirDepuis(declencheur: HTMLElement): void;
667
+ fermer(options?: {
668
+ readonly rendreLeFocus?: boolean;
669
+ }): void;
670
+ protected auClavier(evenement: KeyboardEvent): void;
671
+ /**
672
+ * ⚠️ L'element actif est lu APRES la transition de focus, et non dans
673
+ * `relatedTarget`. Ce dernier est vide quand le focus part vers un element
674
+ * sans focus, et n'est pas renseigne partout ; pendant la transition elle-meme,
675
+ * l'element actif est encore le corps du document.
676
+ */
677
+ protected aLaPerteDuFocus(): void;
678
+ private detruireLaCouche;
679
+ static ɵfac: i0.ɵɵFactoryDeclaration<StPopover, never>;
680
+ static ɵcmp: i0.ɵɵComponentDeclaration<StPopover, "st-popover", never, { "etiquette": { "alias": "etiquette"; "required": true; "isSignal": true; }; "alignement": { "alias": "alignement"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
681
+ }
682
+
683
+ /**
684
+ * Declencheur d'un `st-popover`.
685
+ *
686
+ * ⚠️ `aria-controls` vise la couche meme fermee : le lien entre les deux existe
687
+ * pour les technologies d'assistance avant l'ouverture, et `aria-expanded` dit
688
+ * son etat.
689
+ */
690
+ declare class StPopoverTrigger {
691
+ private readonly element;
692
+ readonly stPopoverTrigger: i0.InputSignal<StPopover>;
693
+ protected basculer(): void;
694
+ static ɵfac: i0.ɵɵFactoryDeclaration<StPopoverTrigger, never>;
695
+ static ɵdir: i0.ɵɵDirectiveDeclaration<StPopoverTrigger, "[stPopoverTrigger]", never, { "stPopoverTrigger": { "alias": "stPopoverTrigger"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
696
+ }
697
+
698
+ export { IDENTIFIANT_DU_TITRE, StConfirmDialog, StDialog, StDialogActions, StDialogContainer, StDialogContent, StDialogTitle, StIdleWarning, StIdleWarningPanel, StMenu, StMenuItem, StMenuTrigger, StPopover, StPopoverTrigger, StToast, StToastContainer, StTooltip, StTooltipPanel };
699
+ export type { ActionDeToast, AlignementDeMenu, AlignementDePopover, CoteDuTiroir, DemandeDeConfirmation, DemandeDeToast, DonneesDInactivite, OptionsDeDialogue, PositionDInfobulle, ReferenceDeDialogue, ReponseDInactivite, Toast, TonDElementDeMenu };