@starterlib/ui 0.1.1 → 0.3.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,8 +1,137 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, input, computed, ChangeDetectionStrategy, Component, ElementRef, DestroyRef, model, output, signal, LOCALE_ID, afterNextRender, isDevMode } from '@angular/core';
2
+ import { InjectionToken, inject, LOCALE_ID, signal, input, computed, ChangeDetectionStrategy, Component, booleanAttribute, ElementRef, DestroyRef, output, model, afterNextRender, effect, TemplateRef, Directive, contentChild, linkedSignal, isDevMode } from '@angular/core';
3
+ import { masquerIban, masquerTelephone, masquerCarte, quatreDerniers, formaterIban, formaterMontant, CHOIX_DE_THEME, LANGUES } from '@starterlib/util';
4
+ export { ETATS_DE_BLOC } from '@starterlib/util';
3
5
  import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
4
- import { masquerIban, masquerTelephone, masquerCarte, quatreDerniers, formaterIban, formaterMontant } from '@starterlib/util';
6
+ import { RouterLink } from '@angular/router';
5
7
 
8
+ /**
9
+ * Defaut francais, identique mot pour mot aux textes ecrits en dur jusqu'a la
10
+ * 0.1.1 : une application qui ne fournit rien ne change pas de comportement.
11
+ *
12
+ * Il existe pour que le socle reste utilisable sans i18n, pas pour dispenser
13
+ * d'en avoir une. Une application bilingue DOIT fournir son propre dictionnaire
14
+ * sous forme de signal — sinon la moitie de l'interface reste en francais quand
15
+ * l'utilisateur passe a l'anglais, et rien ne le signale.
16
+ */
17
+ /**
18
+ * ⚠️ Les textes AFFICHES portent leurs accents. La regle « sans accents » du
19
+ * depot vise la documentation et les commentaires, jamais ce que lit la
20
+ * personne qui utilise l'application : « Reessayer » ou « Aucun resultat » sont
21
+ * des fautes a l'ecran, et une synthese vocale les prononce de travers. La 0.2.0
22
+ * les a livres ainsi. Les accents s'ecrivent en sequence d'echappement, comme
23
+ * l'apostrophe typographique, pour garder la source en ASCII.
24
+ */
25
+ const LIBELLES_FR = {
26
+ chargementEnCours: 'Chargement en cours',
27
+ erreurSurvenue: 'Une erreur est survenue',
28
+ aucunResultat: 'Aucun r\u00e9sultat',
29
+ horsConnexion: 'Hors connexion',
30
+ reessayer: 'R\u00e9essayer',
31
+ identifiantDeTrace: 'Identifiant de trace',
32
+ codeTechnique: 'Code',
33
+ copier: 'Copier',
34
+ copieEffectuee: 'Copi\u00e9',
35
+ copieImpossible: 'Copie impossible. S\u00e9lectionnez le texte pour le copier.',
36
+ afficher: 'Afficher',
37
+ masquer: 'Masquer',
38
+ valeurMasqueeANouveau: 'Valeur masqu\u00e9e \u00e0 nouveau',
39
+ natureIban: 'IBAN',
40
+ natureCarte: 'carte',
41
+ natureTelephone: 'num\u00e9ro',
42
+ seTerminantPar: (nature, quatreDerniers) => `${nature} se terminant par ${quatreDerniers}`,
43
+ nouvelleFenetre: '(nouvelle fen\u00eatre)',
44
+ retirer: 'Retirer',
45
+ filDAriane: 'Fil d\u2019Ariane',
46
+ allerAuContenu: 'Aller au contenu',
47
+ navigationPrincipale: 'Navigation principale',
48
+ theme: 'Th\u00e8me',
49
+ themeSysteme: 'Syst\u00e8me',
50
+ themeClair: 'Clair',
51
+ themeSombre: 'Sombre',
52
+ langue: 'Langue',
53
+ reessayerDans: (duree) => `Nouvel essai possible dans ${duree}`,
54
+ reessayerMaintenant: 'Vous pouvez r\u00e9essayer.',
55
+ sessionBientotExpiree: 'Votre session va expirer',
56
+ sessionExpireDans: (duree) => `Sans activit\u00e9 de votre part, la session sera ferm\u00e9e dans ${duree}.`,
57
+ resterConnecte: 'Rester connect\u00e9',
58
+ seDeconnecter: 'Se d\u00e9connecter',
59
+ fermerLeMessage: 'Fermer le message',
60
+ confirmer: 'Confirmer',
61
+ annuler: 'Annuler',
62
+ recopierPourConfirmer: (texte) => `Pour confirmer, recopiez \u00ab\u202f${texte}\u202f\u00bb`,
63
+ aLInstant: "a l'instant",
64
+ };
65
+ /** Traduction anglaise du meme dictionnaire. La paire est obligatoire. */
66
+ const LIBELLES_EN = {
67
+ chargementEnCours: 'Loading',
68
+ erreurSurvenue: 'Something went wrong',
69
+ aucunResultat: 'No results',
70
+ horsConnexion: 'Offline',
71
+ reessayer: 'Try again',
72
+ identifiantDeTrace: 'Trace identifier',
73
+ codeTechnique: 'Code',
74
+ copier: 'Copy',
75
+ copieEffectuee: 'Copied',
76
+ copieImpossible: 'Could not copy. Select the text to copy it.',
77
+ afficher: 'Show',
78
+ masquer: 'Hide',
79
+ valeurMasqueeANouveau: 'Value hidden again',
80
+ natureIban: 'IBAN',
81
+ natureCarte: 'card',
82
+ natureTelephone: 'number',
83
+ seTerminantPar: (nature, quatreDerniers) => `${nature} ending in ${quatreDerniers}`,
84
+ nouvelleFenetre: '(opens in a new window)',
85
+ retirer: 'Remove',
86
+ filDAriane: 'Breadcrumb',
87
+ allerAuContenu: 'Skip to content',
88
+ navigationPrincipale: 'Main navigation',
89
+ theme: 'Theme',
90
+ themeSysteme: 'System',
91
+ themeClair: 'Light',
92
+ themeSombre: 'Dark',
93
+ langue: 'Language',
94
+ reessayerDans: (duree) => `You can try again in ${duree}`,
95
+ reessayerMaintenant: 'You can try again now.',
96
+ sessionBientotExpiree: 'Your session is about to expire',
97
+ sessionExpireDans: (duree) => `Without any activity, you will be signed out in ${duree}.`,
98
+ resterConnecte: 'Stay signed in',
99
+ seDeconnecter: 'Sign out',
100
+ fermerLeMessage: 'Dismiss message',
101
+ confirmer: 'Confirm',
102
+ annuler: 'Cancel',
103
+ recopierPourConfirmer: (texte) => `To confirm, type \u201c${texte}\u201d`,
104
+ aLInstant: 'just now',
105
+ };
106
+
107
+ /**
108
+ * Locale de formatage des montants, des dates et des nombres, **sous forme de
109
+ * signal**.
110
+ *
111
+ * ⚠️ Pourquoi pas `LOCALE_ID` : il est fige au demarrage de l'application. Or
112
+ * l'ADR 0014 du backend exige de changer de langue SANS recharger — la coquille
113
+ * detient la langue, et tout doit basculer d'un coup. Un composant qui lit
114
+ * `LOCALE_ID` continuerait d'afficher « 1 234,50 € » dans une interface passee
115
+ * a l'anglais.
116
+ *
117
+ * Le defaut lit `LOCALE_ID` : une application qui ne fournit rien garde le
118
+ * comportement d'avant, simplement sans pouvoir changer de langue a chaud.
119
+ */
120
+ const ST_LOCALE = new InjectionToken('st.locale', {
121
+ providedIn: 'root',
122
+ factory: () => {
123
+ const locale = inject(LOCALE_ID);
124
+ return signal(locale).asReadonly();
125
+ },
126
+ });
127
+ /**
128
+ * Textes portes par les composants eux-memes, sous forme de signal pour la
129
+ * meme raison que la locale.
130
+ */
131
+ const ST_LIBELLES = new InjectionToken('st.libelles', {
132
+ providedIn: 'root',
133
+ factory: () => signal(LIBELLES_FR).asReadonly(),
134
+ });
6
135
  /**
7
136
  * Chemin du sprite SVG des icones, **fourni par l'application**.
8
137
  *
@@ -38,6 +167,31 @@ const CHEMIN_DU_SPRITE = new InjectionToken('st.chemin-du-sprite', {
38
167
  function fournirCheminDuSprite(chemin) {
39
168
  return { provide: CHEMIN_DU_SPRITE, useValue: chemin };
40
169
  }
170
+ /**
171
+ * Configure `@starterlib/ui` pour toute l'application.
172
+ *
173
+ * ⚠️ A appeler dans l'HOTE uniquement. Dans un assemblage federe, un remote qui
174
+ * la rappellerait poserait un second jeu de valeurs dans son injecteur de
175
+ * route : deux locales, deux dictionnaires, et la moitie de l'ecran resterait
176
+ * dans l'ancienne langue apres une bascule.
177
+ */
178
+ function provideStarterUi(configuration) {
179
+ const fournisseurs = [fournirCheminDuSprite(configuration.cheminDuSprite)];
180
+ if (configuration.locale !== undefined) {
181
+ fournisseurs.push({ provide: ST_LOCALE, useValue: enSignal(configuration.locale) });
182
+ }
183
+ if (configuration.libelles !== undefined) {
184
+ fournisseurs.push({ provide: ST_LIBELLES, useValue: enSignal(configuration.libelles) });
185
+ }
186
+ if (configuration.fuseau !== undefined) {
187
+ fournisseurs.push({ provide: FUSEAU_PAR_DEFAUT, useValue: configuration.fuseau });
188
+ }
189
+ return fournisseurs;
190
+ }
191
+ /** Une valeur figee reste acceptee : toute application ne change pas de langue. */
192
+ function enSignal(valeur) {
193
+ return typeof valeur === 'function' ? valeur : signal(valeur).asReadonly();
194
+ }
41
195
  /**
42
196
  * Marque la presence d'une region vivante possedee par un ancetre, en pratique
43
197
  * le composant `st-state`.
@@ -59,13 +213,114 @@ const FUSEAU_PAR_DEFAUT = new InjectionToken('st.fuseau-par-defaut', {
59
213
  factory: () => 'Europe/Paris',
60
214
  });
61
215
 
62
- const ETATS_DE_BLOC = [
63
- 'chargement',
64
- 'erreur',
65
- 'vide',
66
- 'hors-ligne',
67
- 'succes',
68
- ];
216
+ /**
217
+ * Les cinq etats de bloc vivent dans `@starterlib/util` depuis la 0.2.0 : le
218
+ * noyau en a besoin pour deriver l'etat d'une ressource, et il ne doit pas
219
+ * dependre des composants. Reexportes ici pour que `@starterlib/ui` reste le
220
+ * seul import necessaire a qui n'ecrit que de l'interface.
221
+ */
222
+
223
+ /**
224
+ * Meme raison que `StAnnonceur` du noyau, qu'`ui` ne peut pas importer : la
225
+ * region doit etre observee avant de recevoir son texte, et un texte identique
226
+ * repose dans la meme tache ne produit aucune mutation, donc aucune annonce.
227
+ */
228
+ const DELAI_D_ANNONCE_MS = 120;
229
+ /** Au-dela, le message est retire : relu plus tard hors contexte, il tromperait. */
230
+ const DUREE_D_AFFICHAGE_MS = 3000;
231
+ /**
232
+ * Texte d'une petite region vivante propre a un composant.
233
+ *
234
+ * ```ts
235
+ * protected readonly annonce = new AnnonceLocale(inject(DestroyRef));
236
+ * // gabarit : <span class="st-vh" aria-live="polite">{{ annonce.texte() }}</span>
237
+ * ```
238
+ *
239
+ * ⚠️ La region doit exister VIDE dans le gabarit des la creation du composant ;
240
+ * cette classe ne gere que son texte.
241
+ *
242
+ * ⚠️ Nee de deux defauts de `st-code` en 0.2.0 : un `onDestroy` enregistre a
243
+ * chaque clic, et une confirmation identique reposee dans la meme tache — la
244
+ * seconde copie n'etait jamais annoncee.
245
+ */
246
+ class AnnonceLocale {
247
+ contenu = signal('', /* @ts-ignore */
248
+ ...(ngDevMode ? [{ debugName: "contenu" }] : /* istanbul ignore next */ []));
249
+ minuteries = [];
250
+ texte = this.contenu.asReadonly();
251
+ constructor(destruction) {
252
+ destruction.onDestroy(() => {
253
+ this.arreter();
254
+ });
255
+ }
256
+ annoncer(message) {
257
+ this.arreter();
258
+ this.contenu.set('');
259
+ this.minuteries.push(setTimeout(() => {
260
+ this.contenu.set(message);
261
+ this.minuteries.push(setTimeout(() => {
262
+ this.contenu.set('');
263
+ }, DUREE_D_AFFICHAGE_MS));
264
+ }, DELAI_D_ANNONCE_MS));
265
+ }
266
+ arreter() {
267
+ for (const minuterie of this.minuteries)
268
+ clearTimeout(minuterie);
269
+ this.minuteries = [];
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Ecrit un texte dans le presse-papiers.
275
+ *
276
+ * ⚠️ Trois issues, et non deux. `navigator.clipboard` n'existe qu'en contexte
277
+ * securise (HTTPS, ou `localhost`) : absent, c'est `indisponible`. Present, il
278
+ * peut encore refuser — permission, document sans focus — et c'est `refusee`.
279
+ * Confondre les deux conduit a cacher un bouton qui aurait fonctionne au clic
280
+ * suivant, ou a laisser croire qu'une copie a eu lieu.
281
+ *
282
+ * ⚠️ Ce qui entre dans le presse-papiers en sort difficilement : les
283
+ * gestionnaires d'historique le conservent, et la synchronisation entre
284
+ * appareils le propage. Jamais de secret — mot de passe, jeton, code a usage
285
+ * unique — et une donnee sensible seulement a la demande explicite de la
286
+ * personne.
287
+ */
288
+ async function copierDansLePressePapiers(document, texte) {
289
+ const presse = document.defaultView?.navigator.clipboard;
290
+ if (presse === undefined)
291
+ return 'indisponible';
292
+ try {
293
+ await presse.writeText(texte);
294
+ return 'copie';
295
+ }
296
+ catch {
297
+ return 'refusee';
298
+ }
299
+ }
300
+ /** Vrai si le navigateur expose un presse-papiers ecrivable par script. */
301
+ function pressePapiersDisponible(document) {
302
+ return document.defaultView?.navigator.clipboard !== undefined;
303
+ }
304
+
305
+ /**
306
+ * Formate une duree en secondes : « 45 s », « 2 min 05 s ».
307
+ *
308
+ * Unites courtes de la langue donnee, par `Intl.NumberFormat` : l'ordre, les
309
+ * espaces et les abreviations suivent la locale, sans table maison.
310
+ */
311
+ function formaterDuree(totalEnSecondes, locale) {
312
+ const total = Math.max(0, Math.round(totalEnSecondes));
313
+ const unite = (valeur, nom) => new Intl.NumberFormat(locale, {
314
+ style: 'unit',
315
+ unit: nom,
316
+ unitDisplay: 'short',
317
+ // « 2 min 05 s » : les secondes sur deux chiffres quand des minutes precedent.
318
+ minimumIntegerDigits: nom === 'second' && total >= 60 ? 2 : 1,
319
+ }).format(valeur);
320
+ if (total < 60)
321
+ return unite(total, 'second');
322
+ return `${unite(Math.floor(total / 60), 'minute')} ${unite(total % 60, 'second')}`;
323
+ }
69
324
 
70
325
  /**
71
326
  * Icone tiree d'un sprite SVG servi en meme origine.
@@ -85,7 +340,7 @@ class StIcon {
85
340
  ...(ngDevMode ? [{ debugName: "nom" }] : /* istanbul ignore next */ []));
86
341
  taille = input('md', /* @ts-ignore */
87
342
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
88
- ton = input('courant', /* @ts-ignore */
343
+ ton = input('neutre', /* @ts-ignore */
89
344
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
90
345
  /** `null` : l'icone est decorative et reste muette pour les lecteurs. */
91
346
  etiquette = input(null, /* @ts-ignore */
@@ -95,7 +350,7 @@ class StIcon {
95
350
  reference = computed(() => `${this.cheminDuSprite}#${this.nom()}`, /* @ts-ignore */
96
351
  ...(ngDevMode ? [{ debugName: "reference" }] : /* istanbul ignore next */ []));
97
352
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
98
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StIcon, isStandalone: true, selector: "st-icon", inputs: { nom: { classPropertyName: "nom", publicName: "nom", isSignal: true, isRequired: true, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-ton": "ton()" }, classAttribute: "st-icon" }, ngImport: i0, template: "<svg\n [attr.aria-hidden]=\"estDecorative() ? 'true' : null\"\n [attr.role]=\"estDecorative() ? null : 'img'\"\n [attr.aria-label]=\"etiquette()\"\n focusable=\"false\"\n>\n <use [attr.href]=\"reference()\" />\n</svg>\n", styles: [":host{display:inline-flex;flex:none;vertical-align:-.125em;color:inherit}svg{inline-size:var(--st-icone-taille, 1.25em);block-size:var(--st-icone-taille, 1.25em)}:host([data-taille=xs]) svg{--st-icone-taille: .75em}:host([data-taille=sm]) svg{--st-icone-taille: 1em}:host([data-taille=lg]) svg{--st-icone-taille: 1.5em}:host([data-taille=xl]) svg{--st-icone-taille: 2em}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
353
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StIcon, isStandalone: true, selector: "st-icon", inputs: { nom: { classPropertyName: "nom", publicName: "nom", isSignal: true, isRequired: true, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-ton": "ton()" }, classAttribute: "st-icon" }, ngImport: i0, template: "<svg\n [attr.aria-hidden]=\"estDecorative() ? 'true' : null\"\n [attr.role]=\"estDecorative() ? null : 'img'\"\n [attr.aria-label]=\"etiquette()\"\n focusable=\"false\"\n>\n <use [attr.href]=\"reference()\" />\n</svg>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;vertical-align:-.125em;color:inherit}svg{inline-size:var(--st-icone-taille, 1.25em);block-size:var(--st-icone-taille, 1.25em)}:host([data-taille=xs]) svg{--st-icone-taille: .75em}:host([data-taille=sm]) svg{--st-icone-taille: 1em}:host([data-taille=lg]) svg{--st-icone-taille: 1.5em}:host([data-taille=xl]) svg{--st-icone-taille: 2em}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
99
354
  }
100
355
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StIcon, decorators: [{
101
356
  type: Component,
@@ -103,7 +358,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
103
358
  class: 'st-icon',
104
359
  '[attr.data-taille]': 'taille()',
105
360
  '[attr.data-ton]': 'ton()',
106
- }, template: "<svg\n [attr.aria-hidden]=\"estDecorative() ? 'true' : null\"\n [attr.role]=\"estDecorative() ? null : 'img'\"\n [attr.aria-label]=\"etiquette()\"\n focusable=\"false\"\n>\n <use [attr.href]=\"reference()\" />\n</svg>\n", styles: [":host{display:inline-flex;flex:none;vertical-align:-.125em;color:inherit}svg{inline-size:var(--st-icone-taille, 1.25em);block-size:var(--st-icone-taille, 1.25em)}:host([data-taille=xs]) svg{--st-icone-taille: .75em}:host([data-taille=sm]) svg{--st-icone-taille: 1em}:host([data-taille=lg]) svg{--st-icone-taille: 1.5em}:host([data-taille=xl]) svg{--st-icone-taille: 2em}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"] }]
361
+ }, template: "<svg\n [attr.aria-hidden]=\"estDecorative() ? 'true' : null\"\n [attr.role]=\"estDecorative() ? null : 'img'\"\n [attr.aria-label]=\"etiquette()\"\n focusable=\"false\"\n>\n <use [attr.href]=\"reference()\" />\n</svg>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;vertical-align:-.125em;color:inherit}svg{inline-size:var(--st-icone-taille, 1.25em);block-size:var(--st-icone-taille, 1.25em)}:host([data-taille=xs]) svg{--st-icone-taille: .75em}:host([data-taille=sm]) svg{--st-icone-taille: 1em}:host([data-taille=lg]) svg{--st-icone-taille: 1.5em}:host([data-taille=xl]) svg{--st-icone-taille: 2em}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"] }]
107
362
  }], propDecorators: { nom: [{ type: i0.Input, args: [{ isSignal: true, alias: "nom", required: true }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }] } });
108
363
 
109
364
  /**
@@ -153,8 +408,7 @@ class StText {
153
408
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
154
409
  graisse = input('normale', /* @ts-ignore */
155
410
  ...(ngDevMode ? [{ debugName: "graisse" }] : /* istanbul ignore next */ []));
156
- enLigne = input(false, /* @ts-ignore */
157
- ...(ngDevMode ? [{ debugName: "enLigne" }] : /* istanbul ignore next */ []));
411
+ enLigne = input(false, { ...(ngDevMode ? { debugName: "enLigne" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
158
412
  /**
159
413
  * Nombre de lignes au-dela duquel le texte est coupe.
160
414
  *
@@ -164,7 +418,7 @@ class StText {
164
418
  tronquerA = input(null, /* @ts-ignore */
165
419
  ...(ngDevMode ? [{ debugName: "tronquerA" }] : /* istanbul ignore next */ []));
166
420
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StText, deps: [], target: i0.ɵɵFactoryTarget.Component });
167
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StText, isStandalone: true, selector: "st-text", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, graisse: { classPropertyName: "graisse", publicName: "graisse", isSignal: true, isRequired: false, transformFunction: null }, enLigne: { classPropertyName: "enLigne", publicName: "enLigne", isSignal: true, isRequired: false, transformFunction: null }, tronquerA: { classPropertyName: "tronquerA", publicName: "tronquerA", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.data-graisse": "graisse()", "attr.data-en-ligne": "enLigne() ? \"\" : null", "attr.data-tronque": "tronquerA() === null ? null : \"\"", "style.--st-text-lignes": "tronquerA()" }, classAttribute: "st-text" }, ngImport: i0, template: "<ng-content />\n", styles: [":host{display:block;margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-normale);line-height:var(--st-interligne-normal);color:var(--st-couleur-texte);max-inline-size:70ch}:host([data-en-ligne]){display:inline;max-inline-size:none}:host([data-variante=corps-sm]){font-size:var(--st-taille-sm)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=legende]){font-size:var(--st-taille-xs);color:var(--st-couleur-texte-discret)}:host([data-variante=mono]){font-family:var(--st-police-mono);font-size:var(--st-taille-sm)}:host([data-graisse=moyenne]){font-weight:var(--st-graisse-moyenne)}:host([data-graisse=semi]){font-weight:var(--st-graisse-semi)}:host([data-tronque]){display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:var(--st-text-lignes, 2);line-clamp:var(--st-text-lignes, 2)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
421
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StText, isStandalone: true, selector: "st-text", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, graisse: { classPropertyName: "graisse", publicName: "graisse", isSignal: true, isRequired: false, transformFunction: null }, enLigne: { classPropertyName: "enLigne", publicName: "enLigne", isSignal: true, isRequired: false, transformFunction: null }, tronquerA: { classPropertyName: "tronquerA", publicName: "tronquerA", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.data-graisse": "graisse()", "attr.data-en-ligne": "enLigne() ? \"\" : null", "attr.data-tronque": "tronquerA() === null ? null : \"\"", "style.--st-text-lignes": "tronquerA()" }, classAttribute: "st-text" }, ngImport: i0, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-normale);line-height:var(--st-interligne-normal);color:var(--st-couleur-texte);max-inline-size:70ch}:host([data-en-ligne]){display:inline;max-inline-size:none}:host([data-variante=corps-sm]){font-size:var(--st-taille-sm)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=legende]){font-size:var(--st-taille-xs);color:var(--st-couleur-texte-discret)}:host([data-variante=mono]){font-family:var(--st-police-mono);font-size:var(--st-taille-sm)}:host([data-graisse=moyenne]){font-weight:var(--st-graisse-moyenne)}:host([data-graisse=semi]){font-weight:var(--st-graisse-semi)}:host([data-tronque]){display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:var(--st-text-lignes, 2);line-clamp:var(--st-text-lignes, 2)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
168
422
  }
169
423
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StText, decorators: [{
170
424
  type: Component,
@@ -175,7 +429,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
175
429
  '[attr.data-en-ligne]': 'enLigne() ? "" : null',
176
430
  '[attr.data-tronque]': 'tronquerA() === null ? null : ""',
177
431
  '[style.--st-text-lignes]': 'tronquerA()',
178
- }, template: "<ng-content />\n", styles: [":host{display:block;margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-normale);line-height:var(--st-interligne-normal);color:var(--st-couleur-texte);max-inline-size:70ch}:host([data-en-ligne]){display:inline;max-inline-size:none}:host([data-variante=corps-sm]){font-size:var(--st-taille-sm)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=legende]){font-size:var(--st-taille-xs);color:var(--st-couleur-texte-discret)}:host([data-variante=mono]){font-family:var(--st-police-mono);font-size:var(--st-taille-sm)}:host([data-graisse=moyenne]){font-weight:var(--st-graisse-moyenne)}:host([data-graisse=semi]){font-weight:var(--st-graisse-semi)}:host([data-tronque]){display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:var(--st-text-lignes, 2);line-clamp:var(--st-text-lignes, 2)}\n"] }]
432
+ }, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-normale);line-height:var(--st-interligne-normal);color:var(--st-couleur-texte);max-inline-size:70ch}:host([data-en-ligne]){display:inline;max-inline-size:none}:host([data-variante=corps-sm]){font-size:var(--st-taille-sm)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=legende]){font-size:var(--st-taille-xs);color:var(--st-couleur-texte-discret)}:host([data-variante=mono]){font-family:var(--st-police-mono);font-size:var(--st-taille-sm)}:host([data-graisse=moyenne]){font-weight:var(--st-graisse-moyenne)}:host([data-graisse=semi]){font-weight:var(--st-graisse-semi)}:host([data-tronque]){display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:var(--st-text-lignes, 2);line-clamp:var(--st-text-lignes, 2)}\n"] }]
179
433
  }], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], graisse: [{ type: i0.Input, args: [{ isSignal: true, alias: "graisse", required: false }] }], enLigne: [{ type: i0.Input, args: [{ isSignal: true, alias: "enLigne", required: false }] }], tronquerA: [{ type: i0.Input, args: [{ isSignal: true, alias: "tronquerA", required: false }] }] } });
180
434
 
181
435
  const TAILLE_PAR_NIVEAU = {
@@ -209,7 +463,7 @@ class StHeading {
209
463
  tailleEffective = computed(() => this.taille() ?? TAILLE_PAR_NIVEAU[this.niveau()], /* @ts-ignore */
210
464
  ...(ngDevMode ? [{ debugName: "tailleEffective" }] : /* istanbul ignore next */ []));
211
465
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHeading, deps: [], target: i0.ɵɵFactoryTarget.Component });
212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StHeading, isStandalone: true, selector: "st-heading", inputs: { niveau: { classPropertyName: "niveau", publicName: "niveau", isSignal: true, isRequired: true, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, identifiant: { classPropertyName: "identifiant", publicName: "identifiant", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "heading" }, properties: { "attr.aria-level": "niveau()", "attr.id": "identifiant()", "attr.data-taille": "tailleEffective()" }, classAttribute: "st-heading" }, ngImport: i0, template: "<ng-content />\n", styles: [":host{display:block;margin:0 0 var(--st-espacement-3);font-family:var(--st-police-base);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}:host([data-taille=\"2xl\"]){font-size:var(--st-taille-2xl)}:host([data-taille=\"3xl\"]){font-size:var(--st-taille-3xl)}:host([data-taille=\"4xl\"]){font-size:var(--st-taille-4xl)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
466
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StHeading, isStandalone: true, selector: "st-heading", inputs: { niveau: { classPropertyName: "niveau", publicName: "niveau", isSignal: true, isRequired: true, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, identifiant: { classPropertyName: "identifiant", publicName: "identifiant", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "heading" }, properties: { "attr.aria-level": "niveau()", "attr.id": "identifiant()", "attr.data-taille": "tailleEffective()" }, classAttribute: "st-heading" }, ngImport: i0, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin:0 0 var(--st-espacement-3);font-family:var(--st-police-base);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}:host([data-taille=\"2xl\"]){font-size:var(--st-taille-2xl)}:host([data-taille=\"3xl\"]){font-size:var(--st-taille-3xl)}:host([data-taille=\"4xl\"]){font-size:var(--st-taille-4xl)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
213
467
  }
214
468
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHeading, decorators: [{
215
469
  type: Component,
@@ -219,7 +473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
219
473
  '[attr.aria-level]': 'niveau()',
220
474
  '[attr.id]': 'identifiant()',
221
475
  '[attr.data-taille]': 'tailleEffective()',
222
- }, template: "<ng-content />\n", styles: [":host{display:block;margin:0 0 var(--st-espacement-3);font-family:var(--st-police-base);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}:host([data-taille=\"2xl\"]){font-size:var(--st-taille-2xl)}:host([data-taille=\"3xl\"]){font-size:var(--st-taille-3xl)}:host([data-taille=\"4xl\"]){font-size:var(--st-taille-4xl)}\n"] }]
476
+ }, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin:0 0 var(--st-espacement-3);font-family:var(--st-police-base);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}:host([data-taille=\"2xl\"]){font-size:var(--st-taille-2xl)}:host([data-taille=\"3xl\"]){font-size:var(--st-taille-3xl)}:host([data-taille=\"4xl\"]){font-size:var(--st-taille-4xl)}\n"] }]
223
477
  }], propDecorators: { niveau: [{ type: i0.Input, args: [{ isSignal: true, alias: "niveau", required: true }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], identifiant: [{ type: i0.Input, args: [{ isSignal: true, alias: "identifiant", required: false }] }] } });
224
478
 
225
479
  /**
@@ -237,16 +491,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
237
491
  */
238
492
  class StSpinner {
239
493
  regionParente = inject(REGION_VIVANTE_PARENTE, { optional: true });
494
+ libelles = inject(ST_LIBELLES);
240
495
  taille = input('md', /* @ts-ignore */
241
496
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
242
497
  ton = input('primaire', /* @ts-ignore */
243
498
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
244
- etiquette = input('Chargement en cours', /* @ts-ignore */
499
+ /** `null` : le texte vient du dictionnaire de l'application. */
500
+ etiquette = input(null, /* @ts-ignore */
245
501
  ...(ngDevMode ? [{ debugName: "etiquette" }] : /* istanbul ignore next */ []));
502
+ etiquetteLue = computed(() => this.etiquette() ?? this.libelles().chargementEnCours, /* @ts-ignore */
503
+ ...(ngDevMode ? [{ debugName: "etiquetteLue" }] : /* istanbul ignore next */ []));
246
504
  sAnnonce = computed(() => this.regionParente === null, /* @ts-ignore */
247
505
  ...(ngDevMode ? [{ debugName: "sAnnonce" }] : /* istanbul ignore next */ []));
248
506
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSpinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
249
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StSpinner, isStandalone: true, selector: "st-spinner", inputs: { taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-ton": "ton()", "attr.role": "sAnnonce() ? \"status\" : null", "attr.aria-label": "sAnnonce() ? etiquette() : null" }, classAttribute: "st-spinner" }, ngImport: i0, template: "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <circle class=\"st-spinner__piste\" cx=\"12\" cy=\"12\" r=\"10\" />\n <circle class=\"st-spinner__arc\" cx=\"12\" cy=\"12\" r=\"10\" />\n</svg>\n", styles: [":host{display:inline-flex;flex:none;color:var(--st-couleur-primaire)}svg{inline-size:var(--st-spinner-taille, 1.5rem);block-size:var(--st-spinner-taille, 1.5rem);fill:none;stroke-width:2.5;transform-origin:center;animation:st-spinner-rotation var(--st-anim-chargement, .9s) linear infinite}.st-spinner__piste{stroke:var(--st-couleur-bordure)}.st-spinner__arc{stroke:currentcolor;stroke-linecap:round;stroke-dasharray:16 47}@keyframes st-spinner-rotation{to{transform:rotate(1turn)}}@keyframes st-spinner-pulsation{0%,to{opacity:1}50%{opacity:.35}}@media(prefers-reduced-motion:reduce){svg{animation:st-spinner-pulsation 1.6s ease-in-out infinite}.st-spinner__arc{stroke-dasharray:none}}:host([data-taille=sm]) svg{--st-spinner-taille: 1rem}:host([data-taille=lg]) svg{--st-spinner-taille: 2.5rem}:host([data-ton=courant]){color:currentcolor}:host([data-ton=inverse]){color:var(--st-couleur-sur-primaire)}:host([data-ton=inverse]) .st-spinner__piste{stroke:color-mix(in srgb,var(--st-couleur-sur-primaire) 30%,transparent)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
507
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StSpinner, isStandalone: true, selector: "st-spinner", inputs: { taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-ton": "ton()", "attr.role": "sAnnonce() ? \"status\" : null", "attr.aria-label": "sAnnonce() ? etiquetteLue() : null" }, classAttribute: "st-spinner" }, ngImport: i0, template: "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <circle class=\"st-spinner__piste\" cx=\"12\" cy=\"12\" r=\"10\" />\n <circle class=\"st-spinner__arc\" cx=\"12\" cy=\"12\" r=\"10\" />\n</svg>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;color:var(--st-couleur-primaire)}svg{inline-size:var(--st-spinner-taille, 1.5rem);block-size:var(--st-spinner-taille, 1.5rem);fill:none;stroke-width:2.5;transform-origin:center;animation:st-spinner-rotation var(--st-anim-chargement, .9s) linear infinite}.st-spinner__piste{stroke:var(--st-couleur-bordure)}.st-spinner__arc{stroke:currentcolor;stroke-linecap:round;stroke-dasharray:16 47}@keyframes st-spinner-rotation{to{transform:rotate(1turn)}}@keyframes st-spinner-pulsation{0%,to{opacity:1}50%{opacity:.35}}@media(prefers-reduced-motion:reduce){svg{animation:st-spinner-pulsation 1.6s ease-in-out infinite}.st-spinner__arc{stroke-dasharray:none}}:host([data-taille=sm]) svg{--st-spinner-taille: 1rem}:host([data-taille=lg]) svg{--st-spinner-taille: 2.5rem}:host([data-ton=neutre]){color:currentcolor}:host([data-ton=inverse]){color:var(--st-couleur-sur-primaire)}:host([data-ton=inverse]) .st-spinner__piste{stroke:color-mix(in srgb,var(--st-couleur-sur-primaire) 30%,transparent)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
250
508
  }
251
509
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSpinner, decorators: [{
252
510
  type: Component,
@@ -255,8 +513,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
255
513
  '[attr.data-taille]': 'taille()',
256
514
  '[attr.data-ton]': 'ton()',
257
515
  '[attr.role]': 'sAnnonce() ? "status" : null',
258
- '[attr.aria-label]': 'sAnnonce() ? etiquette() : null',
259
- }, template: "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <circle class=\"st-spinner__piste\" cx=\"12\" cy=\"12\" r=\"10\" />\n <circle class=\"st-spinner__arc\" cx=\"12\" cy=\"12\" r=\"10\" />\n</svg>\n", styles: [":host{display:inline-flex;flex:none;color:var(--st-couleur-primaire)}svg{inline-size:var(--st-spinner-taille, 1.5rem);block-size:var(--st-spinner-taille, 1.5rem);fill:none;stroke-width:2.5;transform-origin:center;animation:st-spinner-rotation var(--st-anim-chargement, .9s) linear infinite}.st-spinner__piste{stroke:var(--st-couleur-bordure)}.st-spinner__arc{stroke:currentcolor;stroke-linecap:round;stroke-dasharray:16 47}@keyframes st-spinner-rotation{to{transform:rotate(1turn)}}@keyframes st-spinner-pulsation{0%,to{opacity:1}50%{opacity:.35}}@media(prefers-reduced-motion:reduce){svg{animation:st-spinner-pulsation 1.6s ease-in-out infinite}.st-spinner__arc{stroke-dasharray:none}}:host([data-taille=sm]) svg{--st-spinner-taille: 1rem}:host([data-taille=lg]) svg{--st-spinner-taille: 2.5rem}:host([data-ton=courant]){color:currentcolor}:host([data-ton=inverse]){color:var(--st-couleur-sur-primaire)}:host([data-ton=inverse]) .st-spinner__piste{stroke:color-mix(in srgb,var(--st-couleur-sur-primaire) 30%,transparent)}\n"] }]
516
+ '[attr.aria-label]': 'sAnnonce() ? etiquetteLue() : null',
517
+ }, template: "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <circle class=\"st-spinner__piste\" cx=\"12\" cy=\"12\" r=\"10\" />\n <circle class=\"st-spinner__arc\" cx=\"12\" cy=\"12\" r=\"10\" />\n</svg>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;color:var(--st-couleur-primaire)}svg{inline-size:var(--st-spinner-taille, 1.5rem);block-size:var(--st-spinner-taille, 1.5rem);fill:none;stroke-width:2.5;transform-origin:center;animation:st-spinner-rotation var(--st-anim-chargement, .9s) linear infinite}.st-spinner__piste{stroke:var(--st-couleur-bordure)}.st-spinner__arc{stroke:currentcolor;stroke-linecap:round;stroke-dasharray:16 47}@keyframes st-spinner-rotation{to{transform:rotate(1turn)}}@keyframes st-spinner-pulsation{0%,to{opacity:1}50%{opacity:.35}}@media(prefers-reduced-motion:reduce){svg{animation:st-spinner-pulsation 1.6s ease-in-out infinite}.st-spinner__arc{stroke-dasharray:none}}:host([data-taille=sm]) svg{--st-spinner-taille: 1rem}:host([data-taille=lg]) svg{--st-spinner-taille: 2.5rem}:host([data-ton=neutre]){color:currentcolor}:host([data-ton=inverse]){color:var(--st-couleur-sur-primaire)}:host([data-ton=inverse]) .st-spinner__piste{stroke:color-mix(in srgb,var(--st-couleur-sur-primaire) 30%,transparent)}\n"] }]
260
518
  }], propDecorators: { taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }] } });
261
519
 
262
520
  /**
@@ -297,7 +555,7 @@ class StProgress {
297
555
  }, /* @ts-ignore */
298
556
  ...(ngDevMode ? [{ debugName: "pourcentage" }] : /* istanbul ignore next */ []));
299
557
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StProgress, deps: [], target: i0.ɵɵFactoryTarget.Component });
300
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StProgress, isStandalone: true, selector: "st-progress", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, texteDeValeur: { classPropertyName: "texteDeValeur", publicName: "texteDeValeur", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar" }, properties: { "attr.data-ton": "ton()", "attr.data-indetermine": "estIndeterminee() ? \"\" : null", "attr.aria-label": "etiquette()", "attr.aria-valuemin": "0", "attr.aria-valuemax": "max()", "attr.aria-valuenow": "valeurAnnoncee()", "attr.aria-valuetext": "texteDeValeur()", "style.--st-progress-part.%": "pourcentage()" }, classAttribute: "st-progress" }, ngImport: i0, template: "<span class=\"st-progress__barre\"></span>\n", styles: [":host{display:block;block-size:.5rem;overflow:hidden;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}.st-progress__barre{display:block;block-size:100%;inline-size:var(--st-progress-part, 0%);background:var(--st-couleur-primaire);border-radius:inherit;transition:inline-size var(--st-duree-normale) var(--st-courbe-standard)}:host([data-ton=succes]) .st-progress__barre{background:var(--st-couleur-succes)}:host([data-ton=danger]) .st-progress__barre{background:var(--st-couleur-danger)}:host([data-indetermine]) .st-progress__barre{inline-size:35%;animation:st-progress-va-et-vient var(--st-anim-chargement, 1.4s) ease-in-out infinite}@keyframes st-progress-va-et-vient{0%{transform:translate(-100%)}to{transform:translate(calc(100cqi + 100%))}}@keyframes st-progress-pulsation{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){:host([data-indetermine]) .st-progress__barre{inline-size:100%;transform:none;animation:st-progress-pulsation 1.6s ease-in-out infinite}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StProgress, isStandalone: true, selector: "st-progress", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, texteDeValeur: { classPropertyName: "texteDeValeur", publicName: "texteDeValeur", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar" }, properties: { "attr.data-ton": "ton()", "attr.data-indetermine": "estIndeterminee() ? \"\" : null", "attr.aria-label": "etiquette()", "attr.aria-valuemin": "0", "attr.aria-valuemax": "max()", "attr.aria-valuenow": "valeurAnnoncee()", "attr.aria-valuetext": "texteDeValeur()", "style.--st-progress-part.%": "pourcentage()" }, classAttribute: "st-progress" }, ngImport: i0, template: "<span class=\"st-progress__barre\"></span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;block-size:.5rem;overflow:hidden;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}.st-progress__barre{display:block;block-size:100%;inline-size:var(--st-progress-part, 0%);background:var(--st-couleur-primaire);border-radius:inherit;transition:inline-size var(--st-duree-normale) var(--st-courbe-standard)}:host([data-ton=succes]) .st-progress__barre{background:var(--st-couleur-succes)}:host([data-ton=danger]) .st-progress__barre{background:var(--st-couleur-danger)}:host([data-indetermine]) .st-progress__barre{inline-size:35%;animation:st-progress-va-et-vient var(--st-anim-chargement, 1.4s) ease-in-out infinite}@keyframes st-progress-va-et-vient{0%{transform:translate(-100%)}to{transform:translate(calc(100cqi + 100%))}}@keyframes st-progress-pulsation{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){:host([data-indetermine]) .st-progress__barre{inline-size:100%;transform:none;animation:st-progress-pulsation 1.6s ease-in-out infinite}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
301
559
  }
302
560
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StProgress, decorators: [{
303
561
  type: Component,
@@ -312,7 +570,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
312
570
  '[attr.aria-valuenow]': 'valeurAnnoncee()',
313
571
  '[attr.aria-valuetext]': 'texteDeValeur()',
314
572
  '[style.--st-progress-part.%]': 'pourcentage()',
315
- }, template: "<span class=\"st-progress__barre\"></span>\n", styles: [":host{display:block;block-size:.5rem;overflow:hidden;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}.st-progress__barre{display:block;block-size:100%;inline-size:var(--st-progress-part, 0%);background:var(--st-couleur-primaire);border-radius:inherit;transition:inline-size var(--st-duree-normale) var(--st-courbe-standard)}:host([data-ton=succes]) .st-progress__barre{background:var(--st-couleur-succes)}:host([data-ton=danger]) .st-progress__barre{background:var(--st-couleur-danger)}:host([data-indetermine]) .st-progress__barre{inline-size:35%;animation:st-progress-va-et-vient var(--st-anim-chargement, 1.4s) ease-in-out infinite}@keyframes st-progress-va-et-vient{0%{transform:translate(-100%)}to{transform:translate(calc(100cqi + 100%))}}@keyframes st-progress-pulsation{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){:host([data-indetermine]) .st-progress__barre{inline-size:100%;transform:none;animation:st-progress-pulsation 1.6s ease-in-out infinite}}\n"] }]
573
+ }, template: "<span class=\"st-progress__barre\"></span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;block-size:.5rem;overflow:hidden;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}.st-progress__barre{display:block;block-size:100%;inline-size:var(--st-progress-part, 0%);background:var(--st-couleur-primaire);border-radius:inherit;transition:inline-size var(--st-duree-normale) var(--st-courbe-standard)}:host([data-ton=succes]) .st-progress__barre{background:var(--st-couleur-succes)}:host([data-ton=danger]) .st-progress__barre{background:var(--st-couleur-danger)}:host([data-indetermine]) .st-progress__barre{inline-size:35%;animation:st-progress-va-et-vient var(--st-anim-chargement, 1.4s) ease-in-out infinite}@keyframes st-progress-va-et-vient{0%{transform:translate(-100%)}to{transform:translate(calc(100cqi + 100%))}}@keyframes st-progress-pulsation{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){:host([data-indetermine]) .st-progress__barre{inline-size:100%;transform:none;animation:st-progress-pulsation 1.6s ease-in-out infinite}}\n"] }]
316
574
  }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: true }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], texteDeValeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "texteDeValeur", required: false }] }] } });
317
575
 
318
576
  /**
@@ -332,14 +590,13 @@ class StSkeleton {
332
590
  ...(ngDevMode ? [{ debugName: "lignes" }] : /* istanbul ignore next */ []));
333
591
  colonnes = input(4, /* @ts-ignore */
334
592
  ...(ngDevMode ? [{ debugName: "colonnes" }] : /* istanbul ignore next */ []));
335
- anime = input(true, /* @ts-ignore */
336
- ...(ngDevMode ? [{ debugName: "anime" }] : /* istanbul ignore next */ []));
593
+ anime = input(true, { ...(ngDevMode ? { debugName: "anime" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
337
594
  indicesDeLigne = computed(() => Array.from({ length: Math.max(1, this.lignes()) }, (_, index) => index), /* @ts-ignore */
338
595
  ...(ngDevMode ? [{ debugName: "indicesDeLigne" }] : /* istanbul ignore next */ []));
339
596
  indicesDeColonne = computed(() => Array.from({ length: Math.max(1, this.colonnes()) }, (_, index) => index), /* @ts-ignore */
340
597
  ...(ngDevMode ? [{ debugName: "indicesDeColonne" }] : /* istanbul ignore next */ []));
341
598
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
342
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StSkeleton, isStandalone: true, selector: "st-skeleton", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, lignes: { classPropertyName: "lignes", publicName: "lignes", isSignal: true, isRequired: false, transformFunction: null }, colonnes: { classPropertyName: "colonnes", publicName: "colonnes", isSignal: true, isRequired: false, transformFunction: null }, anime: { classPropertyName: "anime", publicName: "anime", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "attr.data-variante": "variante()", "attr.data-anime": "anime() ? \"\" : null" }, classAttribute: "st-skeleton" }, ngImport: i0, template: "@switch (variante()) {\n @case ('tableau') {\n @for (ligne of indicesDeLigne(); track ligne) {\n <div class=\"st-skeleton__rangee\">\n @for (colonne of indicesDeColonne(); track colonne) {\n <span class=\"st-skeleton__cellule\"></span>\n }\n </div>\n }\n }\n @case ('carte') {\n <span class=\"st-skeleton__media\"></span>\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n @default {\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n}\n", styles: [":host{display:flex;flex-direction:column;gap:var(--st-espacement-2)}.st-skeleton__media,.st-skeleton__cellule,.st-skeleton__ligne{display:block;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-sm)}.st-skeleton__ligne{block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__ligne:last-child{inline-size:60%}.st-skeleton__rangee{display:flex;gap:var(--st-espacement-3)}.st-skeleton__cellule{flex:1;block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__media{block-size:8rem;border-radius:var(--st-rayon-md)}:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:linear-gradient(90deg,var(--st-couleur-surface-enfoncee) 25%,var(--st-couleur-surface-survol) 50%,var(--st-couleur-surface-enfoncee) 75%);background-size:200% 100%;animation:st-skeleton-miroitement var(--st-anim-chargement, 1.4s) linear infinite}@keyframes st-skeleton-miroitement{to{background-position:-200% 0}}@keyframes st-skeleton-pulsation{0%,to{opacity:1}50%{opacity:.5}}@media(prefers-reduced-motion:reduce){:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:var(--st-couleur-surface-enfoncee);animation:st-skeleton-pulsation 1.8s ease-in-out infinite}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
599
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StSkeleton, isStandalone: true, selector: "st-skeleton", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, lignes: { classPropertyName: "lignes", publicName: "lignes", isSignal: true, isRequired: false, transformFunction: null }, colonnes: { classPropertyName: "colonnes", publicName: "colonnes", isSignal: true, isRequired: false, transformFunction: null }, anime: { classPropertyName: "anime", publicName: "anime", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "attr.data-variante": "variante()", "attr.data-anime": "anime() ? \"\" : null" }, classAttribute: "st-skeleton" }, ngImport: i0, template: "@switch (variante()) {\n @case ('tableau') {\n @for (ligne of indicesDeLigne(); track ligne) {\n <div class=\"st-skeleton__rangee\">\n @for (colonne of indicesDeColonne(); track colonne) {\n <span class=\"st-skeleton__cellule\"></span>\n }\n </div>\n }\n }\n @case ('carte') {\n <span class=\"st-skeleton__media\"></span>\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n @default {\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;gap:var(--st-espacement-2)}.st-skeleton__media,.st-skeleton__cellule,.st-skeleton__ligne{display:block;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-sm)}.st-skeleton__ligne{block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__ligne:last-child{inline-size:60%}.st-skeleton__rangee{display:flex;gap:var(--st-espacement-3)}.st-skeleton__cellule{flex:1;block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__media{block-size:8rem;border-radius:var(--st-rayon-md)}:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:linear-gradient(90deg,var(--st-couleur-surface-enfoncee) 25%,var(--st-couleur-surface-survol) 50%,var(--st-couleur-surface-enfoncee) 75%);background-size:200% 100%;animation:st-skeleton-miroitement var(--st-anim-chargement, 1.4s) linear infinite}@keyframes st-skeleton-miroitement{to{background-position:-200% 0}}@keyframes st-skeleton-pulsation{0%,to{opacity:1}50%{opacity:.5}}@media(prefers-reduced-motion:reduce){:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:var(--st-couleur-surface-enfoncee);animation:st-skeleton-pulsation 1.8s ease-in-out infinite}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
343
600
  }
344
601
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSkeleton, decorators: [{
345
602
  type: Component,
@@ -348,7 +605,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
348
605
  'aria-hidden': 'true',
349
606
  '[attr.data-variante]': 'variante()',
350
607
  '[attr.data-anime]': 'anime() ? "" : null',
351
- }, template: "@switch (variante()) {\n @case ('tableau') {\n @for (ligne of indicesDeLigne(); track ligne) {\n <div class=\"st-skeleton__rangee\">\n @for (colonne of indicesDeColonne(); track colonne) {\n <span class=\"st-skeleton__cellule\"></span>\n }\n </div>\n }\n }\n @case ('carte') {\n <span class=\"st-skeleton__media\"></span>\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n @default {\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n}\n", styles: [":host{display:flex;flex-direction:column;gap:var(--st-espacement-2)}.st-skeleton__media,.st-skeleton__cellule,.st-skeleton__ligne{display:block;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-sm)}.st-skeleton__ligne{block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__ligne:last-child{inline-size:60%}.st-skeleton__rangee{display:flex;gap:var(--st-espacement-3)}.st-skeleton__cellule{flex:1;block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__media{block-size:8rem;border-radius:var(--st-rayon-md)}:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:linear-gradient(90deg,var(--st-couleur-surface-enfoncee) 25%,var(--st-couleur-surface-survol) 50%,var(--st-couleur-surface-enfoncee) 75%);background-size:200% 100%;animation:st-skeleton-miroitement var(--st-anim-chargement, 1.4s) linear infinite}@keyframes st-skeleton-miroitement{to{background-position:-200% 0}}@keyframes st-skeleton-pulsation{0%,to{opacity:1}50%{opacity:.5}}@media(prefers-reduced-motion:reduce){:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:var(--st-couleur-surface-enfoncee);animation:st-skeleton-pulsation 1.8s ease-in-out infinite}}\n"] }]
608
+ }, template: "@switch (variante()) {\n @case ('tableau') {\n @for (ligne of indicesDeLigne(); track ligne) {\n <div class=\"st-skeleton__rangee\">\n @for (colonne of indicesDeColonne(); track colonne) {\n <span class=\"st-skeleton__cellule\"></span>\n }\n </div>\n }\n }\n @case ('carte') {\n <span class=\"st-skeleton__media\"></span>\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n @default {\n @for (ligne of indicesDeLigne(); track ligne) {\n <span class=\"st-skeleton__ligne\"></span>\n }\n }\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;gap:var(--st-espacement-2)}.st-skeleton__media,.st-skeleton__cellule,.st-skeleton__ligne{display:block;background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-sm)}.st-skeleton__ligne{block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__ligne:last-child{inline-size:60%}.st-skeleton__rangee{display:flex;gap:var(--st-espacement-3)}.st-skeleton__cellule{flex:1;block-size:calc(1em * var(--st-interligne-normal))}.st-skeleton__media{block-size:8rem;border-radius:var(--st-rayon-md)}:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:linear-gradient(90deg,var(--st-couleur-surface-enfoncee) 25%,var(--st-couleur-surface-survol) 50%,var(--st-couleur-surface-enfoncee) 75%);background-size:200% 100%;animation:st-skeleton-miroitement var(--st-anim-chargement, 1.4s) linear infinite}@keyframes st-skeleton-miroitement{to{background-position:-200% 0}}@keyframes st-skeleton-pulsation{0%,to{opacity:1}50%{opacity:.5}}@media(prefers-reduced-motion:reduce){:host([data-anime]) .st-skeleton__ligne,:host([data-anime]) .st-skeleton__cellule,:host([data-anime]) .st-skeleton__media{background:var(--st-couleur-surface-enfoncee);animation:st-skeleton-pulsation 1.8s ease-in-out infinite}}\n"] }]
352
609
  }], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], lignes: [{ type: i0.Input, args: [{ isSignal: true, alias: "lignes", required: false }] }], colonnes: [{ type: i0.Input, args: [{ isSignal: true, alias: "colonnes", required: false }] }], anime: [{ type: i0.Input, args: [{ isSignal: true, alias: "anime", required: false }] }] } });
353
610
 
354
611
  /**
@@ -375,8 +632,7 @@ class StButton {
375
632
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
376
633
  taille = input('md', /* @ts-ignore */
377
634
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
378
- pleineLargeur = input(false, /* @ts-ignore */
379
- ...(ngDevMode ? [{ debugName: "pleineLargeur" }] : /* istanbul ignore next */ []));
635
+ pleineLargeur = input(false, { ...(ngDevMode ? { debugName: "pleineLargeur" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
380
636
  iconeAvant = input(null, /* @ts-ignore */
381
637
  ...(ngDevMode ? [{ debugName: "iconeAvant" }] : /* istanbul ignore next */ []));
382
638
  iconeApres = input(null, /* @ts-ignore */
@@ -386,19 +642,29 @@ class StButton {
386
642
  * mecanisme d'anti double soumission. L'appelant doit le lever DES la
387
643
  * soumission, pas a l'arrivee de la reponse.
388
644
  */
389
- chargement = input(false, /* @ts-ignore */
390
- ...(ngDevMode ? [{ debugName: "chargement" }] : /* istanbul ignore next */ []));
645
+ chargement = input(false, { ...(ngDevMode ? { debugName: "chargement" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
646
+ /**
647
+ * L'action existe mais n'est pas disponible : une condition n'est pas encore
648
+ * remplie.
649
+ *
650
+ * ⚠️ `aria-disabled` et NON l'attribut natif `disabled`, qui retire le bouton
651
+ * de l'ordre de tabulation. Une personne au clavier ne l'atteindrait plus, et
652
+ * ne decouvrirait donc jamais la condition qui le bloque — le bouton aurait
653
+ * simplement disparu de son parcours. Ici il reste atteignable, annonce comme
654
+ * indisponible, et ses clics sont avales.
655
+ */
656
+ indisponible = input(false, { ...(ngDevMode ? { debugName: "indisponible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
391
657
  /**
392
658
  * Le ton suit le FOND du bouton, et non le bouton en general : sur une
393
659
  * variante posee sur la surface (`secondaire`, qui est le defaut, et
394
660
  * `discret`), un indicateur en ton inverse tombait a 1,00:1 — invisible.
395
661
  */
396
- tonDuChargement = computed(() => this.variante() === 'primaire' || this.variante() === 'destructeur' ? 'inverse' : 'courant', /* @ts-ignore */
662
+ tonDuChargement = computed(() => this.variante() === 'primaire' || this.variante() === 'danger' ? 'inverse' : 'neutre', /* @ts-ignore */
397
663
  ...(ngDevMode ? [{ debugName: "tonDuChargement" }] : /* istanbul ignore next */ []));
398
664
  constructor() {
399
665
  const element = inject(ElementRef).nativeElement;
400
666
  const garde = (evenement) => {
401
- if (!this.chargement())
667
+ if (!this.chargement() && !this.indisponible())
402
668
  return;
403
669
  evenement.preventDefault();
404
670
  // `stopImmediatePropagation` et non `stopPropagation` : il faut barrer
@@ -417,7 +683,7 @@ class StButton {
417
683
  });
418
684
  }
419
685
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
420
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StButton, isStandalone: true, selector: "button[stButton]", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, pleineLargeur: { classPropertyName: "pleineLargeur", publicName: "pleineLargeur", isSignal: true, isRequired: false, transformFunction: null }, iconeAvant: { classPropertyName: "iconeAvant", publicName: "iconeAvant", isSignal: true, isRequired: false, transformFunction: null }, iconeApres: { classPropertyName: "iconeApres", publicName: "iconeApres", isSignal: true, isRequired: false, transformFunction: null }, chargement: { classPropertyName: "chargement", publicName: "chargement", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.data-taille": "taille()", "attr.data-pleine-largeur": "pleineLargeur() ? \"\" : null", "attr.aria-disabled": "chargement() ? \"true\" : null", "attr.aria-busy": "chargement() ? \"true\" : null" }, classAttribute: "st-button" }, ngImport: i0, template: "@if (iconeAvant(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n<span class=\"st-button__libelle\"><ng-content /></span>\n\n@if (iconeApres(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n@if (chargement()) {\n <st-spinner\n class=\"st-button__chargement\"\n taille=\"sm\"\n [ton]=\"tonDuChargement()\"\n aria-hidden=\"true\"\n />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host{position:relative;display:inline-flex;gap:var(--st-espacement-2);align-items:center;justify-content:center;min-block-size:var(--st-cible-tactile-min);padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte);border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard),border-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed;border-color:var(--st-couleur-bordure)}:host[aria-disabled=true]{cursor:progress}.st-button__libelle{white-space:normal}:host([aria-busy=true])>:not(.st-button__chargement){opacity:0}.st-button__chargement{position:absolute;inset:0;margin:auto}:host([data-variante=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:transparent}:host([data-variante=primaire]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=primaire]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-primaire-survol)}:host([data-variante=destructeur]){color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border-color:transparent}:host([data-variante=destructeur]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=destructeur]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-danger-survol)}:host([data-variante=discret]){color:var(--st-couleur-primaire);background:transparent;border-color:transparent}:host([data-variante=discret]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host([data-taille=sm]){min-block-size:2.25rem;padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm)}@media(pointer:coarse){:host([data-taille=sm]){min-block-size:var(--st-cible-tactile-min)}}:host([data-taille=lg]){min-block-size:3.25rem;padding-inline:var(--st-espacement-6);font-size:var(--st-taille-lg)}:host([data-pleine-largeur]){display:flex;inline-size:100%}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StSpinner, selector: "st-spinner", inputs: ["taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
686
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StButton, isStandalone: true, selector: "button[stButton]", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, pleineLargeur: { classPropertyName: "pleineLargeur", publicName: "pleineLargeur", isSignal: true, isRequired: false, transformFunction: null }, iconeAvant: { classPropertyName: "iconeAvant", publicName: "iconeAvant", isSignal: true, isRequired: false, transformFunction: null }, iconeApres: { classPropertyName: "iconeApres", publicName: "iconeApres", isSignal: true, isRequired: false, transformFunction: null }, chargement: { classPropertyName: "chargement", publicName: "chargement", isSignal: true, isRequired: false, transformFunction: null }, indisponible: { classPropertyName: "indisponible", publicName: "indisponible", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.data-taille": "taille()", "attr.data-pleine-largeur": "pleineLargeur() ? \"\" : null", "attr.aria-disabled": "chargement() || indisponible() ? \"true\" : null", "attr.aria-busy": "chargement() ? \"true\" : null" }, classAttribute: "st-button" }, ngImport: i0, template: "@if (iconeAvant(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n<span class=\"st-button__libelle\"><ng-content /></span>\n\n@if (iconeApres(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n@if (chargement()) {\n <st-spinner\n class=\"st-button__chargement\"\n taille=\"sm\"\n [ton]=\"tonDuChargement()\"\n aria-hidden=\"true\"\n />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:relative;display:inline-flex;gap:var(--st-espacement-2);align-items:center;justify-content:center;min-block-size:var(--st-cible-tactile-min);padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte);border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard),border-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed;border-color:var(--st-couleur-bordure)}:host[aria-disabled=true]{cursor:progress}.st-button__libelle{white-space:normal}:host([aria-busy=true])>:not(.st-button__chargement){opacity:0}.st-button__chargement{position:absolute;inset:0;margin:auto}:host([data-variante=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:transparent}:host([data-variante=primaire]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=primaire]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-primaire-survol)}:host([data-variante=danger]){color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border-color:transparent}:host([data-variante=danger]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=danger]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-danger-survol)}:host([data-variante=discret]){color:var(--st-couleur-primaire);background:transparent;border-color:transparent}:host([data-variante=discret]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host([data-taille=sm]){min-block-size:2.25rem;padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm)}@media(pointer:coarse){:host([data-taille=sm]){min-block-size:var(--st-cible-tactile-min)}}:host([data-taille=lg]){min-block-size:3.25rem;padding-inline:var(--st-espacement-6);font-size:var(--st-taille-lg)}:host([data-pleine-largeur]){display:flex;inline-size:100%}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StSpinner, selector: "st-spinner", inputs: ["taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
421
687
  }
422
688
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButton, decorators: [{
423
689
  type: Component,
@@ -426,10 +692,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
426
692
  '[attr.data-variante]': 'variante()',
427
693
  '[attr.data-taille]': 'taille()',
428
694
  '[attr.data-pleine-largeur]': 'pleineLargeur() ? "" : null',
429
- '[attr.aria-disabled]': 'chargement() ? "true" : null',
695
+ '[attr.aria-disabled]': 'chargement() || indisponible() ? "true" : null',
430
696
  '[attr.aria-busy]': 'chargement() ? "true" : null',
431
- }, template: "@if (iconeAvant(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n<span class=\"st-button__libelle\"><ng-content /></span>\n\n@if (iconeApres(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n@if (chargement()) {\n <st-spinner\n class=\"st-button__chargement\"\n taille=\"sm\"\n [ton]=\"tonDuChargement()\"\n aria-hidden=\"true\"\n />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host{position:relative;display:inline-flex;gap:var(--st-espacement-2);align-items:center;justify-content:center;min-block-size:var(--st-cible-tactile-min);padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte);border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard),border-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed;border-color:var(--st-couleur-bordure)}:host[aria-disabled=true]{cursor:progress}.st-button__libelle{white-space:normal}:host([aria-busy=true])>:not(.st-button__chargement){opacity:0}.st-button__chargement{position:absolute;inset:0;margin:auto}:host([data-variante=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:transparent}:host([data-variante=primaire]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=primaire]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-primaire-survol)}:host([data-variante=destructeur]){color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border-color:transparent}:host([data-variante=destructeur]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=destructeur]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-danger-survol)}:host([data-variante=discret]){color:var(--st-couleur-primaire);background:transparent;border-color:transparent}:host([data-variante=discret]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host([data-taille=sm]){min-block-size:2.25rem;padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm)}@media(pointer:coarse){:host([data-taille=sm]){min-block-size:var(--st-cible-tactile-min)}}:host([data-taille=lg]){min-block-size:3.25rem;padding-inline:var(--st-espacement-6);font-size:var(--st-taille-lg)}:host([data-pleine-largeur]){display:flex;inline-size:100%}\n"] }]
432
- }], ctorParameters: () => [], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], pleineLargeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "pleineLargeur", required: false }] }], iconeAvant: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconeAvant", required: false }] }], iconeApres: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconeApres", required: false }] }], chargement: [{ type: i0.Input, args: [{ isSignal: true, alias: "chargement", required: false }] }] } });
697
+ }, template: "@if (iconeAvant(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n<span class=\"st-button__libelle\"><ng-content /></span>\n\n@if (iconeApres(); as icone) {\n <st-icon [nom]=\"icone\" taille=\"sm\" />\n}\n\n@if (chargement()) {\n <st-spinner\n class=\"st-button__chargement\"\n taille=\"sm\"\n [ton]=\"tonDuChargement()\"\n aria-hidden=\"true\"\n />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:relative;display:inline-flex;gap:var(--st-espacement-2);align-items:center;justify-content:center;min-block-size:var(--st-cible-tactile-min);padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);font-family:var(--st-police-base);font-size:var(--st-taille-md);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte);border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard),border-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed;border-color:var(--st-couleur-bordure)}:host[aria-disabled=true]{cursor:progress}.st-button__libelle{white-space:normal}:host([aria-busy=true])>:not(.st-button__chargement){opacity:0}.st-button__chargement{position:absolute;inset:0;margin:auto}:host([data-variante=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:transparent}:host([data-variante=primaire]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=primaire]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-primaire-survol)}:host([data-variante=danger]){color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border-color:transparent}:host([data-variante=danger]):focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px;box-shadow:0 0 0 2px var(--st-couleur-surface)}:host([data-variante=danger]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-danger-survol)}:host([data-variante=discret]){color:var(--st-couleur-primaire);background:transparent;border-color:transparent}:host([data-variante=discret]):hover:not([aria-disabled=true],:disabled){background:var(--st-couleur-surface-survol)}:host([data-taille=sm]){min-block-size:2.25rem;padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm)}@media(pointer:coarse){:host([data-taille=sm]){min-block-size:var(--st-cible-tactile-min)}}:host([data-taille=lg]){min-block-size:3.25rem;padding-inline:var(--st-espacement-6);font-size:var(--st-taille-lg)}:host([data-pleine-largeur]){display:flex;inline-size:100%}\n"] }]
698
+ }], ctorParameters: () => [], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], pleineLargeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "pleineLargeur", required: false }] }], iconeAvant: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconeAvant", required: false }] }], iconeApres: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconeApres", required: false }] }], chargement: [{ type: i0.Input, args: [{ isSignal: true, alias: "chargement", required: false }] }], indisponible: [{ type: i0.Input, args: [{ isSignal: true, alias: "indisponible", required: false }] }] } });
433
699
 
434
700
  /**
435
701
  * Bouton reduit a une icone, pose en attribut sur un `<button>` natif.
@@ -448,11 +714,18 @@ class StIconButton {
448
714
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
449
715
  taille = input('md', /* @ts-ignore */
450
716
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
451
- /** `null` : le bouton n'est pas a deux etats et n'annonce aucune pression. */
452
- enfonce = model(null, /* @ts-ignore */
717
+ /**
718
+ * `null` : le bouton n'est pas a deux etats et n'annonce aucune pression.
719
+ *
720
+ * ⚠️ Une ENTREE, et non un `model`. Le composant ne bascule rien de lui-meme :
721
+ * l'etat enfonce reflete une donnee que l'appelant detient. En `model`,
722
+ * `[(enfonce)]` compilait et ne remontait jamais — une liaison bidirectionnelle
723
+ * muette est pire qu'absente, puisqu'elle se relit comme fonctionnelle.
724
+ */
725
+ enfonce = input(null, /* @ts-ignore */
453
726
  ...(ngDevMode ? [{ debugName: "enfonce" }] : /* istanbul ignore next */ []));
454
727
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StIconButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
455
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StIconButton, isStandalone: true, selector: "button[stIconButton]", inputs: { icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: true, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, enfonce: { classPropertyName: "enfonce", publicName: "enfonce", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { enfonce: "enfonceChange" }, host: { properties: { "attr.data-variante": "variante()", "attr.data-taille": "taille()", "attr.aria-label": "etiquette()", "attr.aria-pressed": "enfonce() === null ? null : enfonce()" }, classAttribute: "st-icon-button" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" [taille]=\"taille() === 'sm' ? 'sm' : 'md'\" />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min);color:var(--st-couleur-texte);cursor:pointer;background:transparent;border:1px solid transparent;border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not(:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed}:host[aria-pressed=true]{background:var(--st-couleur-surface-enfoncee)}:host([data-variante=secondaire]){background:var(--st-couleur-surface);border-color:var(--st-couleur-bordure-forte)}:host([data-variante=destructeur]){color:var(--st-couleur-danger)}:host([data-variante=destructeur]):hover:not(:disabled){background:var(--st-couleur-danger-discret)}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
728
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StIconButton, isStandalone: true, selector: "button[stIconButton]", inputs: { icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: true, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, enfonce: { classPropertyName: "enfonce", publicName: "enfonce", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.data-taille": "taille()", "attr.aria-label": "etiquette()", "attr.aria-pressed": "enfonce() === null ? null : enfonce()" }, classAttribute: "st-icon-button" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" [taille]=\"taille() === 'sm' ? 'sm' : 'md'\" />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min);color:var(--st-couleur-texte);cursor:pointer;background:transparent;border:1px solid transparent;border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not(:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed}:host[aria-pressed=true]{background:var(--st-couleur-surface-enfoncee)}:host([data-variante=secondaire]){background:var(--st-couleur-surface);border-color:var(--st-couleur-bordure-forte)}:host([data-variante=danger]){color:var(--st-couleur-danger)}:host([data-variante=danger]):hover:not(:disabled){background:var(--st-couleur-danger-discret)}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
456
729
  }
457
730
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StIconButton, decorators: [{
458
731
  type: Component,
@@ -462,8 +735,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
462
735
  '[attr.data-taille]': 'taille()',
463
736
  '[attr.aria-label]': 'etiquette()',
464
737
  '[attr.aria-pressed]': 'enfonce() === null ? null : enfonce()',
465
- }, template: "<st-icon [nom]=\"icone()\" [taille]=\"taille() === 'sm' ? 'sm' : 'md'\" />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min);color:var(--st-couleur-texte);cursor:pointer;background:transparent;border:1px solid transparent;border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not(:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed}:host[aria-pressed=true]{background:var(--st-couleur-surface-enfoncee)}:host([data-variante=secondaire]){background:var(--st-couleur-surface);border-color:var(--st-couleur-bordure-forte)}:host([data-variante=destructeur]){color:var(--st-couleur-danger)}:host([data-variante=destructeur]):hover:not(:disabled){background:var(--st-couleur-danger-discret)}\n"] }]
466
- }], propDecorators: { icone: [{ type: i0.Input, args: [{ isSignal: true, alias: "icone", required: true }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: true }] }], variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], enfonce: [{ type: i0.Input, args: [{ isSignal: true, alias: "enfonce", required: false }] }, { type: i0.Output, args: ["enfonceChange"] }] } });
738
+ }, template: "<st-icon [nom]=\"icone()\" [taille]=\"taille() === 'sm' ? 'sm' : 'md'\" />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min);color:var(--st-couleur-texte);cursor:pointer;background:transparent;border:1px solid transparent;border-radius:var(--st-rayon-md);transition:background-color var(--st-duree-rapide) var(--st-courbe-standard)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover:not(:disabled){background:var(--st-couleur-surface-survol)}:host:disabled{color:var(--st-couleur-texte-desactive);cursor:not-allowed}:host[aria-pressed=true]{background:var(--st-couleur-surface-enfoncee)}:host([data-variante=secondaire]){background:var(--st-couleur-surface);border-color:var(--st-couleur-bordure-forte)}:host([data-variante=danger]){color:var(--st-couleur-danger)}:host([data-variante=danger]):hover:not(:disabled){background:var(--st-couleur-danger-discret)}\n"] }]
739
+ }], propDecorators: { icone: [{ type: i0.Input, args: [{ isSignal: true, alias: "icone", required: true }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: true }] }], variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], enfonce: [{ type: i0.Input, args: [{ isSignal: true, alias: "enfonce", required: false }] }] } });
467
740
 
468
741
  /**
469
742
  * Lien, pose en attribut sur un `<a>` natif.
@@ -476,16 +749,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
476
749
  * quiconque regarde l'ecran.
477
750
  */
478
751
  class StLink {
752
+ libelles = inject(ST_LIBELLES);
479
753
  variante = input('texte', /* @ts-ignore */
480
754
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
481
755
  /** Ouvre dans un nouvel onglet, et l'annonce dans le nom accessible. */
482
- externe = input(false, /* @ts-ignore */
483
- ...(ngDevMode ? [{ debugName: "externe" }] : /* istanbul ignore next */ []));
484
- /** Mention lue par les lecteurs d'ecran quand le lien sort du site. */
485
- mentionExterne = input('(nouvelle fenetre)', /* @ts-ignore */
756
+ externe = input(false, { ...(ngDevMode ? { debugName: "externe" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
757
+ /**
758
+ * Mention lue par les lecteurs d'ecran quand le lien sort du site.
759
+ * `null` : le texte vient du dictionnaire de l'application.
760
+ */
761
+ mentionExterne = input(null, /* @ts-ignore */
486
762
  ...(ngDevMode ? [{ debugName: "mentionExterne" }] : /* istanbul ignore next */ []));
763
+ mentionExterneLue = computed(() => this.mentionExterne() ?? this.libelles().nouvelleFenetre, /* @ts-ignore */
764
+ ...(ngDevMode ? [{ debugName: "mentionExterneLue" }] : /* istanbul ignore next */ []));
487
765
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
488
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StLink, isStandalone: true, selector: "a[stLink]", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, externe: { classPropertyName: "externe", publicName: "externe", isSignal: true, isRequired: false, transformFunction: null }, mentionExterne: { classPropertyName: "mentionExterne", publicName: "mentionExterne", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.target": "externe() ? \"_blank\" : null", "attr.rel": "externe() ? \"noopener noreferrer\" : null" }, classAttribute: "st-link" }, ngImport: i0, template: "<ng-content />\n@if (externe()) {\n <st-icon nom=\"lien-externe\" taille=\"xs\" />\n <span class=\"st-vh\">{{ mentionExterne() }}</span>\n}\n", styles: [":host{display:inline;gap:var(--st-espacement-1);color:var(--st-couleur-primaire);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;border-radius:var(--st-rayon-xs)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover{color:var(--st-couleur-primaire-survol)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=autonome]){display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:var(--st-cible-tactile-min);text-decoration:none}:host([data-variante=autonome]):hover{text-decoration:underline}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
766
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StLink, isStandalone: true, selector: "a[stLink]", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, externe: { classPropertyName: "externe", publicName: "externe", isSignal: true, isRequired: false, transformFunction: null }, mentionExterne: { classPropertyName: "mentionExterne", publicName: "mentionExterne", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variante": "variante()", "attr.target": "externe() ? \"_blank\" : null", "attr.rel": "externe() ? \"noopener noreferrer\" : null" }, classAttribute: "st-link" }, ngImport: i0, template: "<ng-content />\n@if (externe()) {\n <st-icon nom=\"lien-externe\" taille=\"xs\" />\n <span class=\"st-vh\">{{ mentionExterneLue() }}</span>\n}\n", styles: [":host([hidden]){display:none!important}:host{display:inline;gap:var(--st-espacement-1);color:var(--st-couleur-primaire);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;border-radius:var(--st-rayon-xs)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover{color:var(--st-couleur-primaire-survol)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=autonome]){display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:var(--st-cible-tactile-min);text-decoration:none}:host([data-variante=autonome]):hover{text-decoration:underline}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
489
767
  }
490
768
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLink, decorators: [{
491
769
  type: Component,
@@ -494,7 +772,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
494
772
  '[attr.data-variante]': 'variante()',
495
773
  '[attr.target]': 'externe() ? "_blank" : null',
496
774
  '[attr.rel]': 'externe() ? "noopener noreferrer" : null',
497
- }, template: "<ng-content />\n@if (externe()) {\n <st-icon nom=\"lien-externe\" taille=\"xs\" />\n <span class=\"st-vh\">{{ mentionExterne() }}</span>\n}\n", styles: [":host{display:inline;gap:var(--st-espacement-1);color:var(--st-couleur-primaire);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;border-radius:var(--st-rayon-xs)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover{color:var(--st-couleur-primaire-survol)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=autonome]){display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:var(--st-cible-tactile-min);text-decoration:none}:host([data-variante=autonome]):hover{text-decoration:underline}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
775
+ }, template: "<ng-content />\n@if (externe()) {\n <st-icon nom=\"lien-externe\" taille=\"xs\" />\n <span class=\"st-vh\">{{ mentionExterneLue() }}</span>\n}\n", styles: [":host([hidden]){display:none!important}:host{display:inline;gap:var(--st-espacement-1);color:var(--st-couleur-primaire);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;border-radius:var(--st-rayon-xs)}:host:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}:host:hover{color:var(--st-couleur-primaire-survol)}:host([data-variante=discret]){color:var(--st-couleur-texte-discret)}:host([data-variante=autonome]){display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:var(--st-cible-tactile-min);text-decoration:none}:host([data-variante=autonome]):hover{text-decoration:underline}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
498
776
  }], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], externe: [{ type: i0.Input, args: [{ isSignal: true, alias: "externe", required: false }] }], mentionExterne: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionExterne", required: false }] }] } });
499
777
 
500
778
  /**
@@ -512,10 +790,9 @@ class StButtonGroup {
512
790
  orientation = input('horizontale', /* @ts-ignore */
513
791
  ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
514
792
  /** Boutons jointifs, rayons fusionnes. */
515
- attache = input(false, /* @ts-ignore */
516
- ...(ngDevMode ? [{ debugName: "attache" }] : /* istanbul ignore next */ []));
793
+ attache = input(false, { ...(ngDevMode ? { debugName: "attache" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
517
794
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButtonGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
518
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StButtonGroup, isStandalone: true, selector: "st-button-group", inputs: { etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, attache: { classPropertyName: "attache", publicName: "attache", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "etiquette()", "attr.data-orientation": "orientation()", "attr.data-attache": "attache() ? \"\" : null" }, classAttribute: "st-button-group" }, ngImport: i0, template: "<ng-content />\n", styles: [":host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}:host([data-orientation=verticale]){flex-direction:column;align-items:stretch}:host([data-attache]){flex-wrap:nowrap;gap:0}:host([data-attache]) ::ng-deep>.st-button:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}:host([data-attache]) ::ng-deep>.st-button:not(:last-child){border-start-end-radius:0;border-end-end-radius:0;border-inline-end-width:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
795
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StButtonGroup, isStandalone: true, selector: "st-button-group", inputs: { etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, attache: { classPropertyName: "attache", publicName: "attache", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "etiquette()", "attr.data-orientation": "orientation()", "attr.data-attache": "attache() ? \"\" : null" }, classAttribute: "st-button-group" }, ngImport: i0, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}:host([data-orientation=verticale]){flex-direction:column;align-items:stretch}:host([data-attache]){flex-wrap:nowrap;gap:0}:host([data-attache]) ::ng-deep>.st-button:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}:host([data-attache]) ::ng-deep>.st-button:not(:last-child){border-start-end-radius:0;border-end-end-radius:0;border-inline-end-width:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
519
796
  }
520
797
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButtonGroup, decorators: [{
521
798
  type: Component,
@@ -525,7 +802,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
525
802
  '[attr.aria-label]': 'etiquette()',
526
803
  '[attr.data-orientation]': 'orientation()',
527
804
  '[attr.data-attache]': 'attache() ? "" : null',
528
- }, template: "<ng-content />\n", styles: [":host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}:host([data-orientation=verticale]){flex-direction:column;align-items:stretch}:host([data-attache]){flex-wrap:nowrap;gap:0}:host([data-attache]) ::ng-deep>.st-button:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}:host([data-attache]) ::ng-deep>.st-button:not(:last-child){border-start-end-radius:0;border-end-end-radius:0;border-inline-end-width:0}\n"] }]
805
+ }, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}:host([data-orientation=verticale]){flex-direction:column;align-items:stretch}:host([data-attache]){flex-wrap:nowrap;gap:0}:host([data-attache]) ::ng-deep>.st-button:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}:host([data-attache]) ::ng-deep>.st-button:not(:last-child){border-start-end-radius:0;border-end-end-radius:0;border-inline-end-width:0}\n"] }]
529
806
  }], propDecorators: { etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: true }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], attache: [{ type: i0.Input, args: [{ isSignal: true, alias: "attache", required: false }] }] } });
530
807
 
531
808
  /**
@@ -539,72 +816,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
539
816
  */
540
817
  class StCode {
541
818
  document = inject(DOCUMENT);
542
- destruction = inject(DestroyRef);
819
+ libelles = inject(ST_LIBELLES);
543
820
  valeur = input.required(/* @ts-ignore */
544
821
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
545
- etiquette = input('Identifiant de trace', /* @ts-ignore */
822
+ copiable = input(true, { ...(ngDevMode ? { debugName: "copiable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
823
+ /** `null` : les textes viennent du dictionnaire de l'application. */
824
+ etiquette = input(null, /* @ts-ignore */
546
825
  ...(ngDevMode ? [{ debugName: "etiquette" }] : /* istanbul ignore next */ []));
547
- copiable = input(true, /* @ts-ignore */
548
- ...(ngDevMode ? [{ debugName: "copiable" }] : /* istanbul ignore next */ []));
549
- libelleCopier = input('Copier', /* @ts-ignore */
826
+ libelleCopier = input(null, /* @ts-ignore */
550
827
  ...(ngDevMode ? [{ debugName: "libelleCopier" }] : /* istanbul ignore next */ []));
551
- messageDeConfirmation = input('Copie', /* @ts-ignore */
828
+ messageDeConfirmation = input(null, /* @ts-ignore */
552
829
  ...(ngDevMode ? [{ debugName: "messageDeConfirmation" }] : /* istanbul ignore next */ []));
830
+ etiquetteLue = computed(() => this.etiquette() ?? this.libelles().identifiantDeTrace, /* @ts-ignore */
831
+ ...(ngDevMode ? [{ debugName: "etiquetteLue" }] : /* istanbul ignore next */ []));
832
+ libelleCopierLu = computed(() => this.libelleCopier() ?? this.libelles().copier, /* @ts-ignore */
833
+ ...(ngDevMode ? [{ debugName: "libelleCopierLu" }] : /* istanbul ignore next */ []));
553
834
  copie = output();
554
- confirmation = signal('', /* @ts-ignore */
555
- ...(ngDevMode ? [{ debugName: "confirmation" }] : /* istanbul ignore next */ []));
556
- minuterie = null;
557
- texteDeConfirmation = this.confirmation.asReadonly();
835
+ annonce = new AnnonceLocale(inject(DestroyRef));
558
836
  /**
559
837
  * Le bouton n'apparait que si le navigateur sait copier. Sans presse-papiers,
560
838
  * un bouton qui ne fait rien vaut moins que la selection manuelle, que la
561
839
  * feuille garde possible (`user-select: all`).
562
840
  */
563
- copiePossible = computed(() => {
564
- if (!this.copiable())
565
- return false;
566
- const fenetre = this.document.defaultView;
567
- return fenetre?.navigator.clipboard !== undefined;
568
- }, /* @ts-ignore */
841
+ copiePossible = computed(() => this.copiable() && pressePapiersDisponible(this.document), /* @ts-ignore */
569
842
  ...(ngDevMode ? [{ debugName: "copiePossible" }] : /* istanbul ignore next */ []));
570
843
  async auClicDeCopie() {
571
- const presse = this.document.defaultView?.navigator.clipboard;
572
- if (presse === undefined)
573
- return;
574
- try {
575
- await presse.writeText(this.valeur());
844
+ const issue = await copierDansLePressePapiers(this.document, this.valeur());
845
+ if (issue === 'copie') {
846
+ this.copie.emit(this.valeur());
847
+ this.annonce.annoncer(this.messageDeConfirmation() ?? this.libelles().copieEffectuee);
576
848
  }
577
- catch {
578
- // Le refus du presse-papiers n'est pas une erreur applicative : la
579
- // valeur reste selectionnable a la main.
580
- return;
849
+ else if (issue === 'refusee') {
850
+ // Un refus se DIT : se taire laisserait croire que la copie a eu lieu.
851
+ this.annonce.annoncer(this.libelles().copieImpossible);
581
852
  }
582
- this.copie.emit(this.valeur());
583
- this.confirmation.set(this.messageDeConfirmation());
584
- if (this.minuterie !== null)
585
- clearTimeout(this.minuterie);
586
- this.minuterie = setTimeout(() => {
587
- this.confirmation.set('');
588
- this.minuterie = null;
589
- }, 3000);
590
- this.destruction.onDestroy(() => {
591
- if (this.minuterie !== null)
592
- clearTimeout(this.minuterie);
593
- });
594
853
  }
595
854
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCode, deps: [], target: i0.ɵɵFactoryTarget.Component });
596
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StCode, isStandalone: true, selector: "st-code", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null }, copiable: { classPropertyName: "copiable", publicName: "copiable", isSignal: true, isRequired: false, transformFunction: null }, libelleCopier: { classPropertyName: "libelleCopier", publicName: "libelleCopier", isSignal: true, isRequired: false, transformFunction: null }, messageDeConfirmation: { classPropertyName: "messageDeConfirmation", publicName: "messageDeConfirmation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { copie: "copie" }, host: { classAttribute: "st-code" }, ngImport: i0, template: "<code [attr.aria-label]=\"etiquette() + ' ' + valeur()\">{{ valeur() }}</code>\n\n@if (copiePossible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleCopier()\"\n (click)=\"auClicDeCopie()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ texteDeConfirmation() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-1);align-items:center}code{padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-2);font-family:var(--st-police-mono);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"], outputs: ["enfonceChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
855
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StCode, isStandalone: true, selector: "st-code", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, copiable: { classPropertyName: "copiable", publicName: "copiable", isSignal: true, isRequired: false, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null }, libelleCopier: { classPropertyName: "libelleCopier", publicName: "libelleCopier", isSignal: true, isRequired: false, transformFunction: null }, messageDeConfirmation: { classPropertyName: "messageDeConfirmation", publicName: "messageDeConfirmation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { copie: "copie" }, host: { classAttribute: "st-code" }, ngImport: i0, template: "<code aria-hidden=\"true\">{{ valeur() }}</code>\n<span class=\"st-vh\">{{ etiquetteLue() + ' ' + valeur() }}</span>\n\n@if (copiePossible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleCopierLu()\"\n (click)=\"auClicDeCopie()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-1);align-items:center}code{padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-2);font-family:var(--st-police-mono);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
597
856
  }
598
857
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCode, decorators: [{
599
858
  type: Component,
600
- args: [{ selector: 'st-code', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIconButton], host: { class: 'st-code' }, template: "<code [attr.aria-label]=\"etiquette() + ' ' + valeur()\">{{ valeur() }}</code>\n\n@if (copiePossible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleCopier()\"\n (click)=\"auClicDeCopie()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ texteDeConfirmation() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-1);align-items:center}code{padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-2);font-family:var(--st-police-mono);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
601
- }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }], copiable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiable", required: false }] }], libelleCopier: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleCopier", required: false }] }], messageDeConfirmation: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageDeConfirmation", required: false }] }], copie: [{ type: i0.Output, args: ["copie"] }] } });
859
+ args: [{ selector: 'st-code', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIconButton], host: { class: 'st-code' }, template: "<code aria-hidden=\"true\">{{ valeur() }}</code>\n<span class=\"st-vh\">{{ etiquetteLue() + ' ' + valeur() }}</span>\n\n@if (copiePossible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleCopierLu()\"\n (click)=\"auClicDeCopie()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-1);align-items:center}code{padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-2);font-family:var(--st-police-mono);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
860
+ }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], copiable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiable", required: false }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }], libelleCopier: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleCopier", required: false }] }], messageDeConfirmation: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageDeConfirmation", required: false }] }], copie: [{ type: i0.Output, args: ["copie"] }] } });
602
861
 
603
- const LIBELLE_DU_TYPE = {
604
- iban: 'IBAN',
605
- carte: 'carte',
606
- telephone: 'numero',
607
- };
608
862
  /**
609
863
  * Identifiant sensible, masque par defaut.
610
864
  *
@@ -617,26 +871,37 @@ const LIBELLE_DU_TYPE = {
617
871
  * journal.
618
872
  */
619
873
  class StMasked {
620
- destruction = inject(DestroyRef);
874
+ libelles = inject(ST_LIBELLES);
621
875
  valeur = input.required(/* @ts-ignore */
622
876
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
623
877
  type = input('iban', /* @ts-ignore */
624
878
  ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
625
879
  revele = model(false, /* @ts-ignore */
626
880
  ...(ngDevMode ? [{ debugName: "revele" }] : /* istanbul ignore next */ []));
627
- revelationAutorisee = input(false, /* @ts-ignore */
628
- ...(ngDevMode ? [{ debugName: "revelationAutorisee" }] : /* istanbul ignore next */ []));
881
+ revelationAutorisee = input(false, { ...(ngDevMode ? { debugName: "revelationAutorisee" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
629
882
  dureeDeRevelationEnSecondes = input(30, /* @ts-ignore */
630
883
  ...(ngDevMode ? [{ debugName: "dureeDeRevelationEnSecondes" }] : /* istanbul ignore next */ []));
631
- libelleAfficher = input('Afficher', /* @ts-ignore */
884
+ /** `null` : les textes viennent du dictionnaire de l'application. */
885
+ libelleAfficher = input(null, /* @ts-ignore */
632
886
  ...(ngDevMode ? [{ debugName: "libelleAfficher" }] : /* istanbul ignore next */ []));
633
- libelleMasquer = input('Masquer', /* @ts-ignore */
887
+ libelleMasquer = input(null, /* @ts-ignore */
634
888
  ...(ngDevMode ? [{ debugName: "libelleMasquer" }] : /* istanbul ignore next */ []));
635
889
  revelation = output();
636
- annonce = signal('', /* @ts-ignore */
637
- ...(ngDevMode ? [{ debugName: "annonce" }] : /* istanbul ignore next */ []));
638
- texteDAnnonce = this.annonce.asReadonly();
890
+ /**
891
+ * ⚠️ Par `AnnonceLocale`, et non par un signal pose directement. La 0.2.0
892
+ * reposait « Valeur masquee a nouveau » a l'identique : aucune mutation, donc
893
+ * une seconde remise en masque jamais annoncee.
894
+ */
895
+ annonce = new AnnonceLocale(inject(DestroyRef));
639
896
  minuterie = null;
897
+ constructor() {
898
+ // Enregistre UNE fois. La 0.2.0 l'enregistrait a chaque revelation, et
899
+ // chaque clic empilait un rappel de plus.
900
+ inject(DestroyRef).onDestroy(() => {
901
+ if (this.minuterie !== null)
902
+ clearTimeout(this.minuterie);
903
+ });
904
+ }
640
905
  valeurMasquee = computed(() => {
641
906
  const valeur = this.valeur();
642
907
  switch (this.type()) {
@@ -651,14 +916,26 @@ class StMasked {
651
916
  ...(ngDevMode ? [{ debugName: "valeurMasquee" }] : /* istanbul ignore next */ []));
652
917
  valeurAffichee = computed(() => this.revele() ? this.valeurLisible() : this.valeurMasquee(), /* @ts-ignore */
653
918
  ...(ngDevMode ? [{ debugName: "valeurAffichee" }] : /* istanbul ignore next */ []));
919
+ /**
920
+ * La nature et la tournure viennent du dictionnaire : l'ordre des mots change
921
+ * d'une langue a l'autre, « IBAN se terminant par 2606 » contre « IBAN ending
922
+ * in 2606 ». Une chaine a trous ne suffirait pas.
923
+ */
654
924
  nomAccessible = computed(() => {
655
- const nature = LIBELLE_DU_TYPE[this.type()];
925
+ const libelles = this.libelles();
926
+ const nature = {
927
+ iban: libelles.natureIban,
928
+ carte: libelles.natureCarte,
929
+ telephone: libelles.natureTelephone,
930
+ }[this.type()];
656
931
  if (this.revele())
657
932
  return `${nature} ${this.valeurLisible()}`;
658
- return `${nature} se terminant par ${quatreDerniers(this.valeur())}`;
933
+ return libelles.seTerminantPar(nature, quatreDerniers(this.valeur()));
659
934
  }, /* @ts-ignore */
660
935
  ...(ngDevMode ? [{ debugName: "nomAccessible" }] : /* istanbul ignore next */ []));
661
- libelleDuBouton = computed(() => this.revele() ? this.libelleMasquer() : this.libelleAfficher(), /* @ts-ignore */
936
+ libelleDuBouton = computed(() => this.revele()
937
+ ? (this.libelleMasquer() ?? this.libelles().masquer)
938
+ : (this.libelleAfficher() ?? this.libelles().afficher), /* @ts-ignore */
662
939
  ...(ngDevMode ? [{ debugName: "libelleDuBouton" }] : /* istanbul ignore next */ []));
663
940
  valeurLisible() {
664
941
  return this.type() === 'iban' ? formaterIban(this.valeur()) : this.valeur();
@@ -670,7 +947,6 @@ class StMasked {
670
947
  }
671
948
  this.revele.set(true);
672
949
  this.revelation.emit({ type: this.type() });
673
- this.annonce.set('');
674
950
  // Re-masquage automatique : une valeur revelee puis oubliee a l'ecran est
675
951
  // lisible par quiconque passe derriere.
676
952
  if (this.minuterie !== null)
@@ -678,10 +954,6 @@ class StMasked {
678
954
  this.minuterie = setTimeout(() => {
679
955
  this.masquer();
680
956
  }, this.dureeDeRevelationEnSecondes() * 1000);
681
- this.destruction.onDestroy(() => {
682
- if (this.minuterie !== null)
683
- clearTimeout(this.minuterie);
684
- });
685
957
  }
686
958
  masquer() {
687
959
  if (this.minuterie !== null) {
@@ -691,15 +963,15 @@ class StMasked {
691
963
  if (!this.revele())
692
964
  return;
693
965
  this.revele.set(false);
694
- this.annonce.set('Valeur masquee a nouveau');
966
+ this.annonce.annoncer(this.libelles().valeurMasqueeANouveau);
695
967
  }
696
968
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StMasked, deps: [], target: i0.ɵɵFactoryTarget.Component });
697
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StMasked, isStandalone: true, selector: "st-masked", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, revele: { classPropertyName: "revele", publicName: "revele", isSignal: true, isRequired: false, transformFunction: null }, revelationAutorisee: { classPropertyName: "revelationAutorisee", publicName: "revelationAutorisee", isSignal: true, isRequired: false, transformFunction: null }, dureeDeRevelationEnSecondes: { classPropertyName: "dureeDeRevelationEnSecondes", publicName: "dureeDeRevelationEnSecondes", isSignal: true, isRequired: false, transformFunction: null }, libelleAfficher: { classPropertyName: "libelleAfficher", publicName: "libelleAfficher", isSignal: true, isRequired: false, transformFunction: null }, libelleMasquer: { classPropertyName: "libelleMasquer", publicName: "libelleMasquer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { revele: "reveleChange", revelation: "revelation" }, host: { properties: { "attr.data-type": "type()" }, classAttribute: "st-masked" }, ngImport: i0, template: "<span class=\"st-masked__valeur\" [attr.aria-label]=\"nomAccessible()\">{{ valeurAffichee() }}</span>\n\n@if (revelationAutorisee()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n taille=\"sm\"\n [icone]=\"revele() ? 'oeil-barre' : 'oeil'\"\n [etiquette]=\"libelleDuBouton()\"\n [enfonce]=\"revele()\"\n (click)=\"basculer()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ texteDAnnonce() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-2);align-items:center}.st-masked__valeur{font-family:var(--st-police-mono);color:var(--st-couleur-texte);letter-spacing:.02em}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"], outputs: ["enfonceChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
969
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StMasked, isStandalone: true, selector: "st-masked", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, revele: { classPropertyName: "revele", publicName: "revele", isSignal: true, isRequired: false, transformFunction: null }, revelationAutorisee: { classPropertyName: "revelationAutorisee", publicName: "revelationAutorisee", isSignal: true, isRequired: false, transformFunction: null }, dureeDeRevelationEnSecondes: { classPropertyName: "dureeDeRevelationEnSecondes", publicName: "dureeDeRevelationEnSecondes", isSignal: true, isRequired: false, transformFunction: null }, libelleAfficher: { classPropertyName: "libelleAfficher", publicName: "libelleAfficher", isSignal: true, isRequired: false, transformFunction: null }, libelleMasquer: { classPropertyName: "libelleMasquer", publicName: "libelleMasquer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { revele: "reveleChange", revelation: "revelation" }, host: { properties: { "attr.data-type": "type()" }, classAttribute: "st-masked" }, ngImport: i0, template: "<span class=\"st-masked__valeur\" aria-hidden=\"true\">{{ valeurAffichee() }}</span>\n<span class=\"st-vh\">{{ nomAccessible() }}</span>\n\n@if (revelationAutorisee()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n taille=\"sm\"\n [icone]=\"revele() ? 'oeil-barre' : 'oeil'\"\n [etiquette]=\"libelleDuBouton()\"\n [enfonce]=\"revele()\"\n (click)=\"basculer()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-2);align-items:center}.st-masked__valeur{font-family:var(--st-police-mono);color:var(--st-couleur-texte);letter-spacing:.02em}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
698
970
  }
699
971
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StMasked, decorators: [{
700
972
  type: Component,
701
- args: [{ selector: 'st-masked', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIconButton], host: { class: 'st-masked', '[attr.data-type]': 'type()' }, template: "<span class=\"st-masked__valeur\" [attr.aria-label]=\"nomAccessible()\">{{ valeurAffichee() }}</span>\n\n@if (revelationAutorisee()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n taille=\"sm\"\n [icone]=\"revele() ? 'oeil-barre' : 'oeil'\"\n [etiquette]=\"libelleDuBouton()\"\n [enfonce]=\"revele()\"\n (click)=\"basculer()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ texteDAnnonce() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-2);align-items:center}.st-masked__valeur{font-family:var(--st-police-mono);color:var(--st-couleur-texte);letter-spacing:.02em}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
702
- }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], revele: [{ type: i0.Input, args: [{ isSignal: true, alias: "revele", required: false }] }, { type: i0.Output, args: ["reveleChange"] }], revelationAutorisee: [{ type: i0.Input, args: [{ isSignal: true, alias: "revelationAutorisee", required: false }] }], dureeDeRevelationEnSecondes: [{ type: i0.Input, args: [{ isSignal: true, alias: "dureeDeRevelationEnSecondes", required: false }] }], libelleAfficher: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleAfficher", required: false }] }], libelleMasquer: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleMasquer", required: false }] }], revelation: [{ type: i0.Output, args: ["revelation"] }] } });
973
+ args: [{ selector: 'st-masked', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIconButton], host: { class: 'st-masked', '[attr.data-type]': 'type()' }, template: "<span class=\"st-masked__valeur\" aria-hidden=\"true\">{{ valeurAffichee() }}</span>\n<span class=\"st-vh\">{{ nomAccessible() }}</span>\n\n@if (revelationAutorisee()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n taille=\"sm\"\n [icone]=\"revele() ? 'oeil-barre' : 'oeil'\"\n [etiquette]=\"libelleDuBouton()\"\n [enfonce]=\"revele()\"\n (click)=\"basculer()\"\n ></button>\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-2);align-items:center}.st-masked__valeur{font-family:var(--st-police-mono);color:var(--st-couleur-texte);letter-spacing:.02em}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
974
+ }], ctorParameters: () => [], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], revele: [{ type: i0.Input, args: [{ isSignal: true, alias: "revele", required: false }] }, { type: i0.Output, args: ["reveleChange"] }], revelationAutorisee: [{ type: i0.Input, args: [{ isSignal: true, alias: "revelationAutorisee", required: false }] }], dureeDeRevelationEnSecondes: [{ type: i0.Input, args: [{ isSignal: true, alias: "dureeDeRevelationEnSecondes", required: false }] }], libelleAfficher: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleAfficher", required: false }] }], libelleMasquer: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleMasquer", required: false }] }], revelation: [{ type: i0.Output, args: ["revelation"] }] } });
703
975
 
704
976
  /**
705
977
  * Somme d'argent.
@@ -713,13 +985,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
713
985
  * contraste ne doivent jamais transformer un debit en credit.
714
986
  */
715
987
  class StMoney {
716
- locale = inject(LOCALE_ID);
988
+ locale = inject(ST_LOCALE);
717
989
  valeur = input.required(/* @ts-ignore */
718
990
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
719
- signeExplicite = input(false, /* @ts-ignore */
720
- ...(ngDevMode ? [{ debugName: "signeExplicite" }] : /* istanbul ignore next */ []));
721
- sansDevise = input(false, /* @ts-ignore */
722
- ...(ngDevMode ? [{ debugName: "sansDevise" }] : /* istanbul ignore next */ []));
991
+ signeExplicite = input(false, { ...(ngDevMode ? { debugName: "signeExplicite" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
992
+ sansDevise = input(false, { ...(ngDevMode ? { debugName: "sansDevise" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
723
993
  taille = input('md', /* @ts-ignore */
724
994
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
725
995
  signe = computed(() => {
@@ -732,13 +1002,13 @@ class StMoney {
732
1002
  }, /* @ts-ignore */
733
1003
  ...(ngDevMode ? [{ debugName: "signe" }] : /* istanbul ignore next */ []));
734
1004
  texte = computed(() => formaterMontant(this.valeur(), {
735
- locale: this.locale,
1005
+ locale: this.locale(),
736
1006
  signeExplicite: this.signeExplicite(),
737
1007
  sansDevise: this.sansDevise(),
738
1008
  }), /* @ts-ignore */
739
1009
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
740
1010
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StMoney, deps: [], target: i0.ɵɵFactoryTarget.Component });
741
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StMoney, isStandalone: true, selector: "st-money", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, signeExplicite: { classPropertyName: "signeExplicite", publicName: "signeExplicite", isSignal: true, isRequired: false, transformFunction: null }, sansDevise: { classPropertyName: "sansDevise", publicName: "sansDevise", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-signe": "signe()" }, classAttribute: "st-money" }, ngImport: i0, template: "{{ texte() }}\n", styles: [":host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-signe=negatif]){color:var(--st-couleur-danger)}:host([data-taille=sm]){font-size:var(--st-taille-sm)}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1011
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StMoney, isStandalone: true, selector: "st-money", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, signeExplicite: { classPropertyName: "signeExplicite", publicName: "signeExplicite", isSignal: true, isRequired: false, transformFunction: null }, sansDevise: { classPropertyName: "sansDevise", publicName: "sansDevise", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-signe": "signe()" }, classAttribute: "st-money" }, ngImport: i0, template: "{{ texte() }}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-signe=negatif]){color:var(--st-couleur-danger)}:host([data-taille=sm]){font-size:var(--st-taille-sm)}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
742
1012
  }
743
1013
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StMoney, decorators: [{
744
1014
  type: Component,
@@ -746,7 +1016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
746
1016
  class: 'st-money',
747
1017
  '[attr.data-taille]': 'taille()',
748
1018
  '[attr.data-signe]': 'signe()',
749
- }, template: "{{ texte() }}\n", styles: [":host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-signe=negatif]){color:var(--st-couleur-danger)}:host([data-taille=sm]){font-size:var(--st-taille-sm)}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}\n"] }]
1019
+ }, template: "{{ texte() }}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-signe=negatif]){color:var(--st-couleur-danger)}:host([data-taille=sm]){font-size:var(--st-taille-sm)}:host([data-taille=lg]){font-size:var(--st-taille-lg)}:host([data-taille=xl]){font-size:var(--st-taille-xl)}\n"] }]
750
1020
  }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], signeExplicite: [{ type: i0.Input, args: [{ isSignal: true, alias: "signeExplicite", required: false }] }], sansDevise: [{ type: i0.Input, args: [{ isSignal: true, alias: "sansDevise", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }] } });
751
1021
 
752
1022
  const OPTIONS = {
@@ -773,7 +1043,7 @@ const OPTIONS = {
773
1043
  * ambigu a l'oral, et l'ordre jour-mois n'est pas universel.
774
1044
  */
775
1045
  class StDate {
776
- locale = inject(LOCALE_ID);
1046
+ locale = inject(ST_LOCALE);
777
1047
  fuseauParDefaut = inject(FUSEAU_PAR_DEFAUT);
778
1048
  valeur = input.required(/* @ts-ignore */
779
1049
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
@@ -781,6 +1051,20 @@ class StDate {
781
1051
  ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
782
1052
  fuseau = input(null, /* @ts-ignore */
783
1053
  ...(ngDevMode ? [{ debugName: "fuseau" }] : /* istanbul ignore next */ []));
1054
+ /**
1055
+ * Une DATE DE CALENDRIER (`2026-09-12`) n'est pas un instant : une date de
1056
+ * naissance, une echeance ou un jour de valeur n'ont pas d'heure, et ne
1057
+ * doivent pas changer de jour selon le fuseau de qui les regarde.
1058
+ *
1059
+ * ⚠️ Le piege est dans la norme : `new Date('2026-09-12')` vaut minuit UTC,
1060
+ * donc le 11 septembre partout a l'ouest de Greenwich. Une echeance affichee
1061
+ * la veille est un defaut que personne ne voit depuis l'Europe.
1062
+ */
1063
+ estDateDeCalendrier = computed(() => {
1064
+ const valeur = this.valeur();
1065
+ return typeof valeur === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(valeur);
1066
+ }, /* @ts-ignore */
1067
+ ...(ngDevMode ? [{ debugName: "estDateDeCalendrier" }] : /* istanbul ignore next */ []));
784
1068
  date = computed(() => {
785
1069
  const valeur = this.valeur();
786
1070
  return valeur instanceof Date ? valeur : new Date(valeur);
@@ -788,14 +1072,44 @@ class StDate {
788
1072
  ...(ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []));
789
1073
  estValide = computed(() => !Number.isNaN(this.date().getTime()), /* @ts-ignore */
790
1074
  ...(ngDevMode ? [{ debugName: "estValide" }] : /* istanbul ignore next */ []));
791
- iso = computed(() => (this.estValide() ? this.date().toISOString() : null), /* @ts-ignore */
1075
+ /**
1076
+ * Le fuseau de rendu. Pour une date de calendrier, c'est UTC : la valeur a
1077
+ * ete construite a minuit UTC, la relire en UTC rend donc le jour ecrit.
1078
+ */
1079
+ fuseauDeRendu = computed(() => this.estDateDeCalendrier() ? 'UTC' : (this.fuseau() ?? this.fuseauParDefaut), /* @ts-ignore */
1080
+ ...(ngDevMode ? [{ debugName: "fuseauDeRendu" }] : /* istanbul ignore next */ []));
1081
+ /**
1082
+ * Une date de calendrier porte `2026-09-12`, sans heure ni decalage : c'est
1083
+ * la forme que la norme HTML attend, et la seule qui ne mente pas.
1084
+ */
1085
+ iso = computed(() => {
1086
+ if (!this.estValide())
1087
+ return null;
1088
+ if (this.estDateDeCalendrier())
1089
+ return this.date().toISOString().slice(0, 10);
1090
+ return this.date().toISOString();
1091
+ }, /* @ts-ignore */
792
1092
  ...(ngDevMode ? [{ debugName: "iso" }] : /* istanbul ignore next */ []));
1093
+ /** Une date sans heure ne peut pas en afficher une. */
1094
+ optionsDeFormat = computed(() => {
1095
+ const options = OPTIONS[this.format()];
1096
+ if (!this.estDateDeCalendrier())
1097
+ return options;
1098
+ // Le format « heure » n'a aucun sens ici : il ne resterait rien a afficher.
1099
+ if (this.format() === 'heure')
1100
+ return OPTIONS.court;
1101
+ const sansHeure = { ...options };
1102
+ delete sansHeure.hour;
1103
+ delete sansHeure.minute;
1104
+ return sansHeure;
1105
+ }, /* @ts-ignore */
1106
+ ...(ngDevMode ? [{ debugName: "optionsDeFormat" }] : /* istanbul ignore next */ []));
793
1107
  texte = computed(() => {
794
1108
  if (!this.estValide())
795
1109
  return '';
796
- return new Intl.DateTimeFormat(this.locale, {
797
- ...OPTIONS[this.format()],
798
- timeZone: this.fuseau() ?? this.fuseauParDefaut,
1110
+ return new Intl.DateTimeFormat(this.locale(), {
1111
+ ...this.optionsDeFormat(),
1112
+ timeZone: this.fuseauDeRendu(),
799
1113
  }).format(this.date());
800
1114
  }, /* @ts-ignore */
801
1115
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
@@ -804,20 +1118,20 @@ class StDate {
804
1118
  if (!this.estValide())
805
1119
  return '';
806
1120
  if (this.format() === 'court') {
807
- return new Intl.DateTimeFormat(this.locale, {
1121
+ return new Intl.DateTimeFormat(this.locale(), {
808
1122
  ...OPTIONS.long,
809
- timeZone: this.fuseau() ?? this.fuseauParDefaut,
1123
+ timeZone: this.fuseauDeRendu(),
810
1124
  }).format(this.date());
811
1125
  }
812
1126
  return null;
813
1127
  }, /* @ts-ignore */
814
1128
  ...(ngDevMode ? [{ debugName: "texteAccessible" }] : /* istanbul ignore next */ []));
815
1129
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StDate, deps: [], target: i0.ɵɵFactoryTarget.Component });
816
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StDate, isStandalone: true, selector: "st-date", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, fuseau: { classPropertyName: "fuseau", publicName: "fuseau", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-date" }, ngImport: i0, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" [attr.aria-label]=\"texteAccessible()\">{{ texte() }}</time>\n}\n", styles: [":host{font-variant-numeric:tabular-nums;color:var(--st-couleur-texte);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1130
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StDate, isStandalone: true, selector: "st-date", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, fuseau: { classPropertyName: "fuseau", publicName: "fuseau", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-date" }, ngImport: i0, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" aria-hidden=\"true\">{{ texte() }}</time>\n @if (texteAccessible(); as lu) {\n <!-- Rien quand le format affiche se lit deja : un noeud vide ferait\n croire a un texte de remplacement absent. -->\n <span class=\"st-vh\">{{ lu }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;color:var(--st-couleur-texte);white-space:nowrap}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
817
1131
  }
818
1132
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StDate, decorators: [{
819
1133
  type: Component,
820
- args: [{ selector: 'st-date', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-date' }, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" [attr.aria-label]=\"texteAccessible()\">{{ texte() }}</time>\n}\n", styles: [":host{font-variant-numeric:tabular-nums;color:var(--st-couleur-texte);white-space:nowrap}\n"] }]
1134
+ args: [{ selector: 'st-date', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-date' }, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" aria-hidden=\"true\">{{ texte() }}</time>\n @if (texteAccessible(); as lu) {\n <!-- Rien quand le format affiche se lit deja : un noeud vide ferait\n croire a un texte de remplacement absent. -->\n <span class=\"st-vh\">{{ lu }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;color:var(--st-couleur-texte);white-space:nowrap}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
821
1135
  }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], fuseau: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuseau", required: false }] }] } });
822
1136
 
823
1137
  const MINUTE = 60_000;
@@ -834,12 +1148,12 @@ const JOUR = 24 * HEURE;
834
1148
  * vieille de trois jours reveille l'onglet pour rien.
835
1149
  */
836
1150
  class StRelativeTime {
837
- locale = inject(LOCALE_ID);
1151
+ locale = inject(ST_LOCALE);
1152
+ libelles = inject(ST_LIBELLES);
838
1153
  fuseau = inject(FUSEAU_PAR_DEFAUT);
839
1154
  valeur = input.required(/* @ts-ignore */
840
1155
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
841
- rafraichir = input(true, /* @ts-ignore */
842
- ...(ngDevMode ? [{ debugName: "rafraichir" }] : /* istanbul ignore next */ []));
1156
+ rafraichir = input(true, { ...(ngDevMode ? { debugName: "rafraichir" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
843
1157
  /** Au-dela de ce nombre de jours, la date absolue est plus parlante. */
844
1158
  seuilAbsoluEnJours = input(7, /* @ts-ignore */
845
1159
  ...(ngDevMode ? [{ debugName: "seuilAbsoluEnJours" }] : /* istanbul ignore next */ []));
@@ -887,7 +1201,7 @@ class StRelativeTime {
887
1201
  return '';
888
1202
  const cible = this.dateEnMillisecondes();
889
1203
  if (this.depasseLeSeuil()) {
890
- return new Intl.DateTimeFormat(this.locale, {
1204
+ return new Intl.DateTimeFormat(this.locale(), {
891
1205
  day: 'numeric',
892
1206
  month: 'long',
893
1207
  year: 'numeric',
@@ -898,8 +1212,8 @@ class StRelativeTime {
898
1212
  const absolu = Math.abs(ecart);
899
1213
  // Sous dix secondes, « il y a 0 seconde » est plus deroutant qu'utile.
900
1214
  if (absolu < 10_000)
901
- return "a l'instant";
902
- const format = new Intl.RelativeTimeFormat(this.locale, { numeric: 'auto' });
1215
+ return this.libelles().aLInstant;
1216
+ const format = new Intl.RelativeTimeFormat(this.locale(), { numeric: 'auto' });
903
1217
  if (absolu < MINUTE)
904
1218
  return format.format(Math.round(ecart / 1000), 'second');
905
1219
  if (absolu < HEURE)
@@ -912,7 +1226,7 @@ class StRelativeTime {
912
1226
  texteAccessible = computed(() => {
913
1227
  if (!this.estValide())
914
1228
  return '';
915
- return new Intl.DateTimeFormat(this.locale, {
1229
+ return new Intl.DateTimeFormat(this.locale(), {
916
1230
  day: 'numeric',
917
1231
  month: 'long',
918
1232
  year: 'numeric',
@@ -923,11 +1237,11 @@ class StRelativeTime {
923
1237
  }, /* @ts-ignore */
924
1238
  ...(ngDevMode ? [{ debugName: "texteAccessible" }] : /* istanbul ignore next */ []));
925
1239
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StRelativeTime, deps: [], target: i0.ɵɵFactoryTarget.Component });
926
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StRelativeTime, isStandalone: true, selector: "st-relative-time", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, rafraichir: { classPropertyName: "rafraichir", publicName: "rafraichir", isSignal: true, isRequired: false, transformFunction: null }, seuilAbsoluEnJours: { classPropertyName: "seuilAbsoluEnJours", publicName: "seuilAbsoluEnJours", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-relative-time" }, ngImport: i0, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" [attr.aria-label]=\"texteAccessible()\">{{ texte() }}</time>\n}\n", styles: [":host{font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1240
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StRelativeTime, isStandalone: true, selector: "st-relative-time", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, rafraichir: { classPropertyName: "rafraichir", publicName: "rafraichir", isSignal: true, isRequired: false, transformFunction: null }, seuilAbsoluEnJours: { classPropertyName: "seuilAbsoluEnJours", publicName: "seuilAbsoluEnJours", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-relative-time" }, ngImport: i0, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" aria-hidden=\"true\">{{ texte() }}</time>\n @if (texteAccessible(); as lu) {\n <!-- Rien quand le format affiche se lit deja : un noeud vide ferait\n croire a un texte de remplacement absent. -->\n <span class=\"st-vh\">{{ lu }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
927
1241
  }
928
1242
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StRelativeTime, decorators: [{
929
1243
  type: Component,
930
- args: [{ selector: 'st-relative-time', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-relative-time' }, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" [attr.aria-label]=\"texteAccessible()\">{{ texte() }}</time>\n}\n", styles: [":host{font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}\n"] }]
1244
+ args: [{ selector: 'st-relative-time', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-relative-time' }, template: "@if (estValide()) {\n <time [attr.datetime]=\"iso()\" aria-hidden=\"true\">{{ texte() }}</time>\n @if (texteAccessible(); as lu) {\n <!-- Rien quand le format affiche se lit deja : un noeud vide ferait\n croire a un texte de remplacement absent. -->\n <span class=\"st-vh\">{{ lu }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
931
1245
  }], ctorParameters: () => [], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], rafraichir: [{ type: i0.Input, args: [{ isSignal: true, alias: "rafraichir", required: false }] }], seuilAbsoluEnJours: [{ type: i0.Input, args: [{ isSignal: true, alias: "seuilAbsoluEnJours", required: false }] }] } });
932
1246
 
933
1247
  /**
@@ -940,10 +1254,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
940
1254
  * d'information pour qui ecoute la page.
941
1255
  */
942
1256
  class StCount {
943
- locale = inject(LOCALE_ID);
1257
+ locale = inject(ST_LOCALE);
944
1258
  valeur = input.required(/* @ts-ignore */
945
1259
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
946
- ton = input('courant', /* @ts-ignore */
1260
+ ton = input('neutre', /* @ts-ignore */
947
1261
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
948
1262
  /** `null` : jamais d'abreviation. */
949
1263
  abregerAuDela = input(1000, /* @ts-ignore */
@@ -953,27 +1267,26 @@ class StCount {
953
1267
  return seuil !== null && Math.abs(this.valeur()) >= seuil;
954
1268
  }, /* @ts-ignore */
955
1269
  ...(ngDevMode ? [{ debugName: "estAbrege" }] : /* istanbul ignore next */ []));
956
- texteComplet = computed(() => new Intl.NumberFormat(this.locale).format(this.valeur()), /* @ts-ignore */
1270
+ texteComplet = computed(() => new Intl.NumberFormat(this.locale()).format(this.valeur()), /* @ts-ignore */
957
1271
  ...(ngDevMode ? [{ debugName: "texteComplet" }] : /* istanbul ignore next */ []));
958
1272
  texte = computed(() => {
959
1273
  if (!this.estAbrege())
960
1274
  return this.texteComplet();
961
- return new Intl.NumberFormat(this.locale, {
1275
+ return new Intl.NumberFormat(this.locale(), {
962
1276
  notation: 'compact',
963
1277
  maximumFractionDigits: 1,
964
1278
  }).format(this.valeur());
965
1279
  }, /* @ts-ignore */
966
1280
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
967
1281
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCount, deps: [], target: i0.ɵɵFactoryTarget.Component });
968
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StCount, isStandalone: true, selector: "st-count", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, abregerAuDela: { classPropertyName: "abregerAuDela", publicName: "abregerAuDela", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-ton": "ton()", "attr.aria-label": "estAbrege() ? texteComplet() : null" }, classAttribute: "st-count" }, ngImport: i0, template: "{{ texte() }}\n", styles: [":host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1282
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StCount, isStandalone: true, selector: "st-count", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, abregerAuDela: { classPropertyName: "abregerAuDela", publicName: "abregerAuDela", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-ton": "ton()" }, classAttribute: "st-count" }, ngImport: i0, template: "<span aria-hidden=\"true\">{{ texte() }}</span>\n\n@if (estAbrege()) {\n <!-- Abrege a l'ecran, entier a l'oral : \u00AB 1,2 k \u00BB ne se lit pas. -->\n <span class=\"st-vh\">{{ texteComplet() }}</span>\n}\n", styles: [":host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
969
1283
  }
970
1284
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCount, decorators: [{
971
1285
  type: Component,
972
1286
  args: [{ selector: 'st-count', changeDetection: ChangeDetectionStrategy.OnPush, host: {
973
1287
  class: 'st-count',
974
1288
  '[attr.data-ton]': 'ton()',
975
- '[attr.aria-label]': 'estAbrege() ? texteComplet() : null',
976
- }, template: "{{ texte() }}\n", styles: [":host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}\n"] }]
1289
+ }, template: "<span aria-hidden=\"true\">{{ texte() }}</span>\n\n@if (estAbrege()) {\n <!-- Abrege a l'ecran, entier a l'oral : \u00AB 1,2 k \u00BB ne se lit pas. -->\n <span class=\"st-vh\">{{ texteComplet() }}</span>\n}\n", styles: [":host([hidden]){display:none!important}:host{font-variant-numeric:tabular-nums;font-weight:var(--st-graisse-moyenne);color:var(--st-couleur-texte);white-space:nowrap}:host([data-ton=discret]){color:var(--st-couleur-texte-discret)}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
977
1290
  }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], abregerAuDela: [{ type: i0.Input, args: [{ isSignal: true, alias: "abregerAuDela", required: false }] }] } });
978
1291
 
979
1292
  /**
@@ -1000,7 +1313,7 @@ class StStatusPill {
1000
1313
  ton = input('neutre', /* @ts-ignore */
1001
1314
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1002
1315
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StStatusPill, deps: [], target: i0.ɵɵFactoryTarget.Component });
1003
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StStatusPill, isStandalone: true, selector: "st-status-pill", inputs: { statut: { classPropertyName: "statut", publicName: "statut", isSignal: true, isRequired: true, transformFunction: null }, libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: true, transformFunction: null }, icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-ton": "ton()", "attr.data-statut": "statut()" }, classAttribute: "st-status-pill" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<span class=\"st-status-pill__libelle\">{{ libelle() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-2);align-items:center;min-block-size:1.5rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}:host([data-ton=info]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}.st-status-pill__libelle{white-space:normal}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1316
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StStatusPill, isStandalone: true, selector: "st-status-pill", inputs: { statut: { classPropertyName: "statut", publicName: "statut", isSignal: true, isRequired: true, transformFunction: null }, libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: true, transformFunction: null }, icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: true, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-ton": "ton()", "attr.data-statut": "statut()" }, classAttribute: "st-status-pill" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<span class=\"st-status-pill__libelle\">{{ libelle() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-2);align-items:center;min-block-size:1.5rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}.st-status-pill__libelle{white-space:normal}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1004
1317
  }
1005
1318
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StStatusPill, decorators: [{
1006
1319
  type: Component,
@@ -1008,7 +1321,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1008
1321
  class: 'st-status-pill',
1009
1322
  '[attr.data-ton]': 'ton()',
1010
1323
  '[attr.data-statut]': 'statut()',
1011
- }, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<span class=\"st-status-pill__libelle\">{{ libelle() }}</span>\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-2);align-items:center;min-block-size:1.5rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}:host([data-ton=info]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}.st-status-pill__libelle{white-space:normal}\n"] }]
1324
+ }, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<span class=\"st-status-pill__libelle\">{{ libelle() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-2);align-items:center;min-block-size:1.5rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-moyenne);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-radius:var(--st-rayon-pleine)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}.st-status-pill__libelle{white-space:normal}\n"] }]
1012
1325
  }], propDecorators: { statut: [{ type: i0.Input, args: [{ isSignal: true, alias: "statut", required: true }] }], libelle: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelle", required: true }] }], icone: [{ type: i0.Input, args: [{ isSignal: true, alias: "icone", required: true }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }] } });
1013
1326
 
1014
1327
  /**
@@ -1028,8 +1341,7 @@ class StBadge {
1028
1341
  ton = input('danger', /* @ts-ignore */
1029
1342
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1030
1343
  /** Point seul, sans chiffre : signale une nouveaute sans la quantifier. */
1031
- point = input(false, /* @ts-ignore */
1032
- ...(ngDevMode ? [{ debugName: "point" }] : /* istanbul ignore next */ []));
1344
+ point = input(false, { ...(ngDevMode ? { debugName: "point" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1033
1345
  texte = computed(() => {
1034
1346
  if (this.point())
1035
1347
  return '';
@@ -1042,7 +1354,7 @@ class StBadge {
1042
1354
  }, /* @ts-ignore */
1043
1355
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
1044
1356
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
1045
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StBadge, isStandalone: true, selector: "st-badge", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, point: { classPropertyName: "point", publicName: "point", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "attr.data-ton": "ton()", "attr.data-point": "point() ? \"\" : null" }, classAttribute: "st-badge" }, ngImport: i0, template: "{{ texte() }}\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;min-inline-size:1.25rem;block-size:1.25rem;padding-inline:var(--st-espacement-1);font-size:var(--st-taille-xs);font-weight:var(--st-graisse-semi);line-height:1;color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border:2px solid var(--st-couleur-surface);border-radius:var(--st-rayon-pleine)}:host([data-point]){inline-size:.5rem;min-inline-size:0;block-size:.5rem;padding:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes);background:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement);background:var(--st-couleur-avertissement)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1357
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StBadge, isStandalone: true, selector: "st-badge", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, point: { classPropertyName: "point", publicName: "point", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "attr.data-ton": "ton()", "attr.data-point": "point() ? \"\" : null" }, classAttribute: "st-badge" }, ngImport: i0, template: "{{ texte() }}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center;justify-content:center;min-inline-size:1.25rem;block-size:1.25rem;padding-inline:var(--st-espacement-1);font-size:var(--st-taille-xs);font-weight:var(--st-graisse-semi);line-height:1;color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border:2px solid var(--st-couleur-surface);border-radius:var(--st-rayon-pleine)}:host([data-point]){inline-size:.5rem;min-inline-size:0;block-size:.5rem;padding:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes);background:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement);background:var(--st-couleur-avertissement)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1046
1358
  }
1047
1359
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBadge, decorators: [{
1048
1360
  type: Component,
@@ -1051,7 +1363,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1051
1363
  'aria-hidden': 'true',
1052
1364
  '[attr.data-ton]': 'ton()',
1053
1365
  '[attr.data-point]': 'point() ? "" : null',
1054
- }, template: "{{ texte() }}\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;min-inline-size:1.25rem;block-size:1.25rem;padding-inline:var(--st-espacement-1);font-size:var(--st-taille-xs);font-weight:var(--st-graisse-semi);line-height:1;color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border:2px solid var(--st-couleur-surface);border-radius:var(--st-rayon-pleine)}:host([data-point]){inline-size:.5rem;min-inline-size:0;block-size:.5rem;padding:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes);background:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement);background:var(--st-couleur-avertissement)}\n"] }]
1366
+ }, template: "{{ texte() }}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center;justify-content:center;min-inline-size:1.25rem;block-size:1.25rem;padding-inline:var(--st-espacement-1);font-size:var(--st-taille-xs);font-weight:var(--st-graisse-semi);line-height:1;color:var(--st-couleur-sur-danger);background:var(--st-couleur-danger);border:2px solid var(--st-couleur-surface);border-radius:var(--st-rayon-pleine)}:host([data-point]){inline-size:.5rem;min-inline-size:0;block-size:.5rem;padding:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes);background:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement);background:var(--st-couleur-avertissement)}\n"] }]
1055
1367
  }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], point: [{ type: i0.Input, args: [{ isSignal: true, alias: "point", required: false }] }] } });
1056
1368
 
1057
1369
  /**
@@ -1064,16 +1376,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1064
1376
  */
1065
1377
  class StTag {
1066
1378
  element = inject(ElementRef);
1379
+ libelles = inject(ST_LIBELLES);
1067
1380
  libelle = input.required(/* @ts-ignore */
1068
1381
  ...(ngDevMode ? [{ debugName: "libelle" }] : /* istanbul ignore next */ []));
1069
- supprimable = input(false, /* @ts-ignore */
1070
- ...(ngDevMode ? [{ debugName: "supprimable" }] : /* istanbul ignore next */ []));
1382
+ supprimable = input(false, { ...(ngDevMode ? { debugName: "supprimable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1071
1383
  ton = input('neutre', /* @ts-ignore */
1072
1384
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1073
- prefixeDeSuppression = input('Retirer', /* @ts-ignore */
1385
+ /** `null` : le texte vient du dictionnaire de l'application. */
1386
+ prefixeDeSuppression = input(null, /* @ts-ignore */
1074
1387
  ...(ngDevMode ? [{ debugName: "prefixeDeSuppression" }] : /* istanbul ignore next */ []));
1075
1388
  supprime = output();
1076
- libelleDeSuppression = computed(() => `${this.prefixeDeSuppression()} ${this.libelle()}`, /* @ts-ignore */
1389
+ libelleDeSuppression = computed(() => `${this.prefixeDeSuppression() ?? this.libelles().retirer} ${this.libelle()}`, /* @ts-ignore */
1077
1390
  ...(ngDevMode ? [{ debugName: "libelleDeSuppression" }] : /* istanbul ignore next */ []));
1078
1391
  auRetrait() {
1079
1392
  this.deplacerLeFocus();
@@ -1100,14 +1413,14 @@ class StTag {
1100
1413
  parent.focus();
1101
1414
  }
1102
1415
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StTag, deps: [], target: i0.ɵɵFactoryTarget.Component });
1103
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StTag, isStandalone: true, selector: "st-tag", inputs: { libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: true, transformFunction: null }, supprimable: { classPropertyName: "supprimable", publicName: "supprimable", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, prefixeDeSuppression: { classPropertyName: "prefixeDeSuppression", publicName: "prefixeDeSuppression", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { supprime: "supprime" }, host: { properties: { "attr.data-ton": "ton()" }, classAttribute: "st-tag" }, ngImport: i0, template: "<span class=\"st-tag__libelle\">{{ libelle() }}</span>\n\n@if (supprimable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleDeSuppression()\"\n (click)=\"auRetrait()\"\n ></button>\n}\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:2rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-color:transparent}:host ::ng-deep .st-icon-button{min-inline-size:1.5rem;min-block-size:1.5rem}@media(pointer:coarse){:host ::ng-deep .st-icon-button{min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min)}}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"], outputs: ["enfonceChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1416
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StTag, isStandalone: true, selector: "st-tag", inputs: { libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: true, transformFunction: null }, supprimable: { classPropertyName: "supprimable", publicName: "supprimable", isSignal: true, isRequired: false, transformFunction: null }, ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, prefixeDeSuppression: { classPropertyName: "prefixeDeSuppression", publicName: "prefixeDeSuppression", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { supprime: "supprime" }, host: { properties: { "attr.data-ton": "ton()" }, classAttribute: "st-tag" }, ngImport: i0, template: "<span class=\"st-tag__libelle\">{{ libelle() }}</span>\n\n@if (supprimable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleDeSuppression()\"\n (click)=\"auRetrait()\"\n ></button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:2rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-color:transparent}:host ::ng-deep .st-icon-button{min-inline-size:1.5rem;min-block-size:1.5rem}@media(pointer:coarse){:host ::ng-deep .st-icon-button{min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min)}}\n"], dependencies: [{ kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1104
1417
  }
1105
1418
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StTag, decorators: [{
1106
1419
  type: Component,
1107
1420
  args: [{ selector: 'st-tag', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIconButton], host: {
1108
1421
  class: 'st-tag',
1109
1422
  '[attr.data-ton]': 'ton()',
1110
- }, template: "<span class=\"st-tag__libelle\">{{ libelle() }}</span>\n\n@if (supprimable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleDeSuppression()\"\n (click)=\"auRetrait()\"\n ></button>\n}\n", styles: [":host{display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:2rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-color:transparent}:host ::ng-deep .st-icon-button{min-inline-size:1.5rem;min-block-size:1.5rem}@media(pointer:coarse){:host ::ng-deep .st-icon-button{min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min)}}\n"] }]
1423
+ }, template: "<span class=\"st-tag__libelle\">{{ libelle() }}</span>\n\n@if (supprimable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleDeSuppression()\"\n (click)=\"auRetrait()\"\n ></button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;gap:var(--st-espacement-1);align-items:center;min-block-size:2rem;padding-block:var(--st-espacement-1);padding-inline:var(--st-espacement-3);font-size:var(--st-taille-sm);color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border:1px solid var(--st-couleur-bordure);border-radius:var(--st-rayon-sm)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-color:transparent}:host ::ng-deep .st-icon-button{min-inline-size:1.5rem;min-block-size:1.5rem}@media(pointer:coarse){:host ::ng-deep .st-icon-button{min-inline-size:var(--st-cible-tactile-min);min-block-size:var(--st-cible-tactile-min)}}\n"] }]
1111
1424
  }], propDecorators: { libelle: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelle", required: true }] }], supprimable: [{ type: i0.Input, args: [{ isSignal: true, alias: "supprimable", required: false }] }], ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], prefixeDeSuppression: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefixeDeSuppression", required: false }] }], supprime: [{ type: i0.Output, args: ["supprime"] }] } });
1112
1425
 
1113
1426
  /**
@@ -1142,8 +1455,7 @@ class StAvatar {
1142
1455
  * `true` quand le nom figure deja a cote de l'avatar, ce qui est le cas
1143
1456
  * courant : l'avatar devient alors decoratif et se tait.
1144
1457
  */
1145
- nomAdjacent = input(true, /* @ts-ignore */
1146
- ...(ngDevMode ? [{ debugName: "nomAdjacent" }] : /* istanbul ignore next */ []));
1458
+ nomAdjacent = input(true, { ...(ngDevMode ? { debugName: "nomAdjacent" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1147
1459
  imageEchouee = signal(false, /* @ts-ignore */
1148
1460
  ...(ngDevMode ? [{ debugName: "imageEchouee" }] : /* istanbul ignore next */ []));
1149
1461
  afficheLImage = computed(() => this.sourceImage() !== null && !this.imageEchouee(), /* @ts-ignore */
@@ -1163,7 +1475,7 @@ class StAvatar {
1163
1475
  this.imageEchouee.set(true);
1164
1476
  }
1165
1477
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1166
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StAvatar, isStandalone: true, selector: "st-avatar", inputs: { nom: { classPropertyName: "nom", publicName: "nom", isSignal: true, isRequired: true, transformFunction: null }, sourceImage: { classPropertyName: "sourceImage", publicName: "sourceImage", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, forme: { classPropertyName: "forme", publicName: "forme", isSignal: true, isRequired: false, transformFunction: null }, nomAdjacent: { classPropertyName: "nomAdjacent", publicName: "nomAdjacent", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-forme": "forme()" }, classAttribute: "st-avatar" }, ngImport: i0, template: "@if (afficheLImage()) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc --\n NgOptimizedImage exige des dimensions statiques ou un chargeur configure.\n Une photo de profil vient d'une URL tierce de dimensions inconnues, et\n optimiser une image de 40 px ne rapporte rien. -->\n <img [src]=\"sourceImage()\" [alt]=\"texteAlternatif()\" (error)=\"auxEchecsDImage()\" />\n} @else {\n <span class=\"st-avatar__initiales\" [attr.aria-hidden]=\"nomAdjacent() ? 'true' : null\">{{\n initiales()\n }}</span>\n @if (!nomAdjacent()) {\n <span class=\"st-vh\">{{ nom() }}</span>\n }\n}\n", styles: [":host{display:inline-flex;flex:none;align-items:center;justify-content:center;inline-size:var(--st-avatar-taille, 2.5rem);block-size:var(--st-avatar-taille, 2.5rem);overflow:hidden;color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-radius:var(--st-rayon-pleine)}img{inline-size:100%;block-size:100%;object-fit:cover}.st-avatar__initiales{font-size:.4em;font-weight:var(--st-graisse-semi);line-height:1;letter-spacing:.02em}:host([data-forme=carre]){border-radius:var(--st-rayon-md)}:host([data-taille=xs]){--st-avatar-taille: 1.5rem}:host([data-taille=sm]){--st-avatar-taille: 2rem}:host([data-taille=lg]){--st-avatar-taille: 4rem}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1478
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StAvatar, isStandalone: true, selector: "st-avatar", inputs: { nom: { classPropertyName: "nom", publicName: "nom", isSignal: true, isRequired: true, transformFunction: null }, sourceImage: { classPropertyName: "sourceImage", publicName: "sourceImage", isSignal: true, isRequired: false, transformFunction: null }, taille: { classPropertyName: "taille", publicName: "taille", isSignal: true, isRequired: false, transformFunction: null }, forme: { classPropertyName: "forme", publicName: "forme", isSignal: true, isRequired: false, transformFunction: null }, nomAdjacent: { classPropertyName: "nomAdjacent", publicName: "nomAdjacent", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-taille": "taille()", "attr.data-forme": "forme()" }, classAttribute: "st-avatar" }, ngImport: i0, template: "@if (afficheLImage()) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc --\n NgOptimizedImage exige des dimensions statiques ou un chargeur configure.\n Une photo de profil vient d'une URL tierce de dimensions inconnues, et\n optimiser une image de 40 px ne rapporte rien. -->\n <img [src]=\"sourceImage()\" [alt]=\"texteAlternatif()\" (error)=\"auxEchecsDImage()\" />\n} @else {\n <span class=\"st-avatar__initiales\" [attr.aria-hidden]=\"nomAdjacent() ? 'true' : null\">{{\n initiales()\n }}</span>\n @if (!nomAdjacent()) {\n <span class=\"st-vh\">{{ nom() }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;inline-size:var(--st-avatar-taille, 2.5rem);block-size:var(--st-avatar-taille, 2.5rem);overflow:hidden;color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-radius:var(--st-rayon-pleine)}img{inline-size:100%;block-size:100%;object-fit:cover}.st-avatar__initiales{font-size:.4em;font-weight:var(--st-graisse-semi);line-height:1;letter-spacing:.02em}:host([data-forme=carre]){border-radius:var(--st-rayon-md)}:host([data-taille=xs]){--st-avatar-taille: 1.5rem}:host([data-taille=sm]){--st-avatar-taille: 2rem}:host([data-taille=lg]){--st-avatar-taille: 4rem}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1167
1479
  }
1168
1480
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StAvatar, decorators: [{
1169
1481
  type: Component,
@@ -1171,7 +1483,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1171
1483
  class: 'st-avatar',
1172
1484
  '[attr.data-taille]': 'taille()',
1173
1485
  '[attr.data-forme]': 'forme()',
1174
- }, template: "@if (afficheLImage()) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc --\n NgOptimizedImage exige des dimensions statiques ou un chargeur configure.\n Une photo de profil vient d'une URL tierce de dimensions inconnues, et\n optimiser une image de 40 px ne rapporte rien. -->\n <img [src]=\"sourceImage()\" [alt]=\"texteAlternatif()\" (error)=\"auxEchecsDImage()\" />\n} @else {\n <span class=\"st-avatar__initiales\" [attr.aria-hidden]=\"nomAdjacent() ? 'true' : null\">{{\n initiales()\n }}</span>\n @if (!nomAdjacent()) {\n <span class=\"st-vh\">{{ nom() }}</span>\n }\n}\n", styles: [":host{display:inline-flex;flex:none;align-items:center;justify-content:center;inline-size:var(--st-avatar-taille, 2.5rem);block-size:var(--st-avatar-taille, 2.5rem);overflow:hidden;color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-radius:var(--st-rayon-pleine)}img{inline-size:100%;block-size:100%;object-fit:cover}.st-avatar__initiales{font-size:.4em;font-weight:var(--st-graisse-semi);line-height:1;letter-spacing:.02em}:host([data-forme=carre]){border-radius:var(--st-rayon-md)}:host([data-taille=xs]){--st-avatar-taille: 1.5rem}:host([data-taille=sm]){--st-avatar-taille: 2rem}:host([data-taille=lg]){--st-avatar-taille: 4rem}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
1486
+ }, template: "@if (afficheLImage()) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc --\n NgOptimizedImage exige des dimensions statiques ou un chargeur configure.\n Une photo de profil vient d'une URL tierce de dimensions inconnues, et\n optimiser une image de 40 px ne rapporte rien. -->\n <img [src]=\"sourceImage()\" [alt]=\"texteAlternatif()\" (error)=\"auxEchecsDImage()\" />\n} @else {\n <span class=\"st-avatar__initiales\" [attr.aria-hidden]=\"nomAdjacent() ? 'true' : null\">{{\n initiales()\n }}</span>\n @if (!nomAdjacent()) {\n <span class=\"st-vh\">{{ nom() }}</span>\n }\n}\n", styles: [":host([hidden]){display:none!important}:host{display:inline-flex;flex:none;align-items:center;justify-content:center;inline-size:var(--st-avatar-taille, 2.5rem);block-size:var(--st-avatar-taille, 2.5rem);overflow:hidden;color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret);border-radius:var(--st-rayon-pleine)}img{inline-size:100%;block-size:100%;object-fit:cover}.st-avatar__initiales{font-size:.4em;font-weight:var(--st-graisse-semi);line-height:1;letter-spacing:.02em}:host([data-forme=carre]){border-radius:var(--st-rayon-md)}:host([data-taille=xs]){--st-avatar-taille: 1.5rem}:host([data-taille=sm]){--st-avatar-taille: 2rem}:host([data-taille=lg]){--st-avatar-taille: 4rem}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
1175
1487
  }], propDecorators: { nom: [{ type: i0.Input, args: [{ isSignal: true, alias: "nom", required: true }] }], sourceImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceImage", required: false }] }], taille: [{ type: i0.Input, args: [{ isSignal: true, alias: "taille", required: false }] }], forme: [{ type: i0.Input, args: [{ isSignal: true, alias: "forme", required: false }] }], nomAdjacent: [{ type: i0.Input, args: [{ isSignal: true, alias: "nomAdjacent", required: false }] }] } });
1176
1488
 
1177
1489
  /**
@@ -1191,14 +1503,14 @@ class StEmpty {
1191
1503
  niveauDuTitre = input(3, /* @ts-ignore */
1192
1504
  ...(ngDevMode ? [{ debugName: "niveauDuTitre" }] : /* istanbul ignore next */ []));
1193
1505
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StEmpty, deps: [], target: i0.ɵɵFactoryTarget.Component });
1194
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StEmpty, isStandalone: true, selector: "st-empty", inputs: { titre: { classPropertyName: "titre", publicName: "titre", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: false, transformFunction: null }, niveauDuTitre: { classPropertyName: "niveauDuTitre", publicName: "niveauDuTitre", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-empty" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"xl\" ton=\"discret\" />\n<st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n@if (description(); as texte) {\n <st-text variante=\"discret\">{{ texte }}</st-text>\n}\n<div class=\"st-empty__action\"><ng-content /></div>\n", styles: [":host{display:flex;flex-direction:column;gap:var(--st-espacement-3);align-items:center;justify-content:center;min-block-size:12rem;padding:var(--st-espacement-8);text-align:center}.st-empty__action:empty{display:none}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StHeading, selector: "st-heading", inputs: ["niveau", "taille", "identifiant"] }, { kind: "component", type: StText, selector: "st-text", inputs: ["variante", "graisse", "enLigne", "tronquerA"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1506
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StEmpty, isStandalone: true, selector: "st-empty", inputs: { titre: { classPropertyName: "titre", publicName: "titre", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icone: { classPropertyName: "icone", publicName: "icone", isSignal: true, isRequired: false, transformFunction: null }, niveauDuTitre: { classPropertyName: "niveauDuTitre", publicName: "niveauDuTitre", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-empty" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"xl\" ton=\"discret\" />\n<st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n@if (description(); as texte) {\n <st-text variante=\"discret\">{{ texte }}</st-text>\n}\n<div class=\"st-empty__action\"><ng-content /></div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;gap:var(--st-espacement-3);align-items:center;justify-content:center;min-block-size:12rem;padding:var(--st-espacement-8);text-align:center}.st-empty__action:empty{display:none}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StHeading, selector: "st-heading", inputs: ["niveau", "taille", "identifiant"] }, { kind: "component", type: StText, selector: "st-text", inputs: ["variante", "graisse", "enLigne", "tronquerA"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1195
1507
  }
1196
1508
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StEmpty, decorators: [{
1197
1509
  type: Component,
1198
- args: [{ selector: 'st-empty', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIcon, StHeading, StText], host: { class: 'st-empty' }, template: "<st-icon [nom]=\"icone()\" taille=\"xl\" ton=\"discret\" />\n<st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n@if (description(); as texte) {\n <st-text variante=\"discret\">{{ texte }}</st-text>\n}\n<div class=\"st-empty__action\"><ng-content /></div>\n", styles: [":host{display:flex;flex-direction:column;gap:var(--st-espacement-3);align-items:center;justify-content:center;min-block-size:12rem;padding:var(--st-espacement-8);text-align:center}.st-empty__action:empty{display:none}\n"] }]
1510
+ args: [{ selector: 'st-empty', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIcon, StHeading, StText], host: { class: 'st-empty' }, template: "<st-icon [nom]=\"icone()\" taille=\"xl\" ton=\"discret\" />\n<st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n@if (description(); as texte) {\n <st-text variante=\"discret\">{{ texte }}</st-text>\n}\n<div class=\"st-empty__action\"><ng-content /></div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;gap:var(--st-espacement-3);align-items:center;justify-content:center;min-block-size:12rem;padding:var(--st-espacement-8);text-align:center}.st-empty__action:empty{display:none}\n"] }]
1199
1511
  }], propDecorators: { titre: [{ type: i0.Input, args: [{ isSignal: true, alias: "titre", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], icone: [{ type: i0.Input, args: [{ isSignal: true, alias: "icone", required: false }] }], niveauDuTitre: [{ type: i0.Input, args: [{ isSignal: true, alias: "niveauDuTitre", required: false }] }] } });
1200
1512
 
1201
- const ICONE = {
1513
+ const ICONE$2 = {
1202
1514
  'hors-ligne': 'hors-ligne',
1203
1515
  serveur: 'serveur',
1204
1516
  client: 'triangle-alerte',
@@ -1217,6 +1529,7 @@ const ICONE = {
1217
1529
  */
1218
1530
  class StError {
1219
1531
  regionParente = inject(REGION_VIVANTE_PARENTE, { optional: true });
1532
+ libelles = inject(ST_LIBELLES);
1220
1533
  variante = input('serveur', /* @ts-ignore */
1221
1534
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
1222
1535
  /** Code machine stable, tel que rendu par le backend. */
@@ -1230,21 +1543,26 @@ class StError {
1230
1543
  ...(ngDevMode ? [{ debugName: "traceId" }] : /* istanbul ignore next */ []));
1231
1544
  niveauDuTitre = input(3, /* @ts-ignore */
1232
1545
  ...(ngDevMode ? [{ debugName: "niveauDuTitre" }] : /* istanbul ignore next */ []));
1233
- rejouable = input(true, /* @ts-ignore */
1234
- ...(ngDevMode ? [{ debugName: "rejouable" }] : /* istanbul ignore next */ []));
1235
- libelleRejeu = input('Reessayer', /* @ts-ignore */
1546
+ rejouable = input(true, { ...(ngDevMode ? { debugName: "rejouable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1547
+ rejeuEnCours = input(false, { ...(ngDevMode ? { debugName: "rejeuEnCours" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1548
+ /** `null` : les textes viennent du dictionnaire de l'application. */
1549
+ libelleRejeu = input(null, /* @ts-ignore */
1236
1550
  ...(ngDevMode ? [{ debugName: "libelleRejeu" }] : /* istanbul ignore next */ []));
1237
- rejeuEnCours = input(false, /* @ts-ignore */
1238
- ...(ngDevMode ? [{ debugName: "rejeuEnCours" }] : /* istanbul ignore next */ []));
1239
- etiquetteDeTrace = input('Identifiant de trace', /* @ts-ignore */
1551
+ etiquetteDeTrace = input(null, /* @ts-ignore */
1240
1552
  ...(ngDevMode ? [{ debugName: "etiquetteDeTrace" }] : /* istanbul ignore next */ []));
1241
1553
  rejeu = output();
1242
- icone = computed(() => ICONE[this.variante()], /* @ts-ignore */
1554
+ libelleRejeuLu = computed(() => this.libelleRejeu() ?? this.libelles().reessayer, /* @ts-ignore */
1555
+ ...(ngDevMode ? [{ debugName: "libelleRejeuLu" }] : /* istanbul ignore next */ []));
1556
+ etiquetteDeTraceLue = computed(() => this.etiquetteDeTrace() ?? this.libelles().identifiantDeTrace, /* @ts-ignore */
1557
+ ...(ngDevMode ? [{ debugName: "etiquetteDeTraceLue" }] : /* istanbul ignore next */ []));
1558
+ etiquetteDuCode = computed(() => this.libelles().codeTechnique, /* @ts-ignore */
1559
+ ...(ngDevMode ? [{ debugName: "etiquetteDuCode" }] : /* istanbul ignore next */ []));
1560
+ icone = computed(() => ICONE$2[this.variante()], /* @ts-ignore */
1243
1561
  ...(ngDevMode ? [{ debugName: "icone" }] : /* istanbul ignore next */ []));
1244
1562
  sAnnonce = computed(() => this.regionParente === null, /* @ts-ignore */
1245
1563
  ...(ngDevMode ? [{ debugName: "sAnnonce" }] : /* istanbul ignore next */ []));
1246
1564
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StError, deps: [], target: i0.ɵɵFactoryTarget.Component });
1247
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StError, isStandalone: true, selector: "st-error", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: true, transformFunction: null }, titre: { classPropertyName: "titre", publicName: "titre", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, traceId: { classPropertyName: "traceId", publicName: "traceId", isSignal: true, isRequired: false, transformFunction: null }, niveauDuTitre: { classPropertyName: "niveauDuTitre", publicName: "niveauDuTitre", isSignal: true, isRequired: false, transformFunction: null }, rejouable: { classPropertyName: "rejouable", publicName: "rejouable", isSignal: true, isRequired: false, transformFunction: null }, libelleRejeu: { classPropertyName: "libelleRejeu", publicName: "libelleRejeu", isSignal: true, isRequired: false, transformFunction: null }, rejeuEnCours: { classPropertyName: "rejeuEnCours", publicName: "rejeuEnCours", isSignal: true, isRequired: false, transformFunction: null }, etiquetteDeTrace: { classPropertyName: "etiquetteDeTrace", publicName: "etiquetteDeTrace", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rejeu: "rejeu" }, host: { properties: { "attr.data-variante": "variante()", "attr.role": "sAnnonce() ? \"alert\" : null" }, classAttribute: "st-error" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"lg\" />\n\n<div class=\"st-error__corps\">\n <st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n <st-text variante=\"corps-sm\">{{ message() }}</st-text>\n\n <p class=\"st-error__technique\">\n <st-code [valeur]=\"code()\" etiquette=\"Code\" [copiable]=\"false\" />\n @if (traceId(); as trace) {\n <st-code [valeur]=\"trace\" [etiquette]=\"etiquetteDeTrace()\" />\n }\n </p>\n\n @if (rejouable()) {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelleRejeu() }}\n </button>\n }\n</div>\n", styles: [":host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-4);color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret);border-inline-start:3px solid var(--st-couleur-danger);border-radius:var(--st-rayon-md)}:host([data-variante=hors-ligne]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-inline-start-color:var(--st-couleur-avertissement)}.st-error__corps{display:flex;flex:1;flex-direction:column;gap:var(--st-espacement-2);align-items:flex-start}.st-error__technique{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);margin:0}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StHeading, selector: "st-heading", inputs: ["niveau", "taille", "identifiant"] }, { kind: "component", type: StText, selector: "st-text", inputs: ["variante", "graisse", "enLigne", "tronquerA"] }, { kind: "component", type: StButton, selector: "button[stButton]", inputs: ["variante", "taille", "pleineLargeur", "iconeAvant", "iconeApres", "chargement"] }, { kind: "component", type: StCode, selector: "st-code", inputs: ["valeur", "etiquette", "copiable", "libelleCopier", "messageDeConfirmation"], outputs: ["copie"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1565
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StError, isStandalone: true, selector: "st-error", inputs: { variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: true, transformFunction: null }, titre: { classPropertyName: "titre", publicName: "titre", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, traceId: { classPropertyName: "traceId", publicName: "traceId", isSignal: true, isRequired: false, transformFunction: null }, niveauDuTitre: { classPropertyName: "niveauDuTitre", publicName: "niveauDuTitre", isSignal: true, isRequired: false, transformFunction: null }, rejouable: { classPropertyName: "rejouable", publicName: "rejouable", isSignal: true, isRequired: false, transformFunction: null }, rejeuEnCours: { classPropertyName: "rejeuEnCours", publicName: "rejeuEnCours", isSignal: true, isRequired: false, transformFunction: null }, libelleRejeu: { classPropertyName: "libelleRejeu", publicName: "libelleRejeu", isSignal: true, isRequired: false, transformFunction: null }, etiquetteDeTrace: { classPropertyName: "etiquetteDeTrace", publicName: "etiquetteDeTrace", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rejeu: "rejeu" }, host: { properties: { "attr.data-variante": "variante()", "attr.role": "sAnnonce() ? \"alert\" : null" }, classAttribute: "st-error" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"lg\" />\n\n<div class=\"st-error__corps\">\n <st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n <st-text variante=\"corps-sm\">{{ message() }}</st-text>\n\n <p class=\"st-error__technique\">\n <st-code [valeur]=\"code()\" [etiquette]=\"etiquetteDuCode()\" [copiable]=\"false\" />\n @if (traceId(); as trace) {\n <st-code [valeur]=\"trace\" [etiquette]=\"etiquetteDeTraceLue()\" />\n }\n </p>\n\n @if (rejouable()) {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelleRejeuLu() }}\n </button>\n }\n</div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-4);color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret);border-inline-start:3px solid var(--st-couleur-danger);border-radius:var(--st-rayon-md)}:host([data-variante=hors-ligne]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-inline-start-color:var(--st-couleur-avertissement)}.st-error__corps{display:flex;flex:1;flex-direction:column;gap:var(--st-espacement-2);align-items:flex-start}.st-error__technique{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);margin:0}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StHeading, selector: "st-heading", inputs: ["niveau", "taille", "identifiant"] }, { kind: "component", type: StText, selector: "st-text", inputs: ["variante", "graisse", "enLigne", "tronquerA"] }, { kind: "component", type: StButton, selector: "button[stButton]", inputs: ["variante", "taille", "pleineLargeur", "iconeAvant", "iconeApres", "chargement", "indisponible"] }, { kind: "component", type: StCode, selector: "st-code", inputs: ["valeur", "copiable", "etiquette", "libelleCopier", "messageDeConfirmation"], outputs: ["copie"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1248
1566
  }
1249
1567
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StError, decorators: [{
1250
1568
  type: Component,
@@ -1252,8 +1570,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1252
1570
  class: 'st-error',
1253
1571
  '[attr.data-variante]': 'variante()',
1254
1572
  '[attr.role]': 'sAnnonce() ? "alert" : null',
1255
- }, template: "<st-icon [nom]=\"icone()\" taille=\"lg\" />\n\n<div class=\"st-error__corps\">\n <st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n <st-text variante=\"corps-sm\">{{ message() }}</st-text>\n\n <p class=\"st-error__technique\">\n <st-code [valeur]=\"code()\" etiquette=\"Code\" [copiable]=\"false\" />\n @if (traceId(); as trace) {\n <st-code [valeur]=\"trace\" [etiquette]=\"etiquetteDeTrace()\" />\n }\n </p>\n\n @if (rejouable()) {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelleRejeu() }}\n </button>\n }\n</div>\n", styles: [":host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-4);color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret);border-inline-start:3px solid var(--st-couleur-danger);border-radius:var(--st-rayon-md)}:host([data-variante=hors-ligne]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-inline-start-color:var(--st-couleur-avertissement)}.st-error__corps{display:flex;flex:1;flex-direction:column;gap:var(--st-espacement-2);align-items:flex-start}.st-error__technique{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);margin:0}\n"] }]
1256
- }], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: true }] }], titre: [{ type: i0.Input, args: [{ isSignal: true, alias: "titre", required: true }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], traceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "traceId", required: false }] }], niveauDuTitre: [{ type: i0.Input, args: [{ isSignal: true, alias: "niveauDuTitre", required: false }] }], rejouable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rejouable", required: false }] }], libelleRejeu: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleRejeu", required: false }] }], rejeuEnCours: [{ type: i0.Input, args: [{ isSignal: true, alias: "rejeuEnCours", required: false }] }], etiquetteDeTrace: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquetteDeTrace", required: false }] }], rejeu: [{ type: i0.Output, args: ["rejeu"] }] } });
1573
+ }, template: "<st-icon [nom]=\"icone()\" taille=\"lg\" />\n\n<div class=\"st-error__corps\">\n <st-heading [niveau]=\"niveauDuTitre()\" taille=\"lg\">{{ titre() }}</st-heading>\n <st-text variante=\"corps-sm\">{{ message() }}</st-text>\n\n <p class=\"st-error__technique\">\n <st-code [valeur]=\"code()\" [etiquette]=\"etiquetteDuCode()\" [copiable]=\"false\" />\n @if (traceId(); as trace) {\n <st-code [valeur]=\"trace\" [etiquette]=\"etiquetteDeTraceLue()\" />\n }\n </p>\n\n @if (rejouable()) {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelleRejeuLu() }}\n </button>\n }\n</div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-4);color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret);border-inline-start:3px solid var(--st-couleur-danger);border-radius:var(--st-rayon-md)}:host([data-variante=hors-ligne]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-inline-start-color:var(--st-couleur-avertissement)}.st-error__corps{display:flex;flex:1;flex-direction:column;gap:var(--st-espacement-2);align-items:flex-start}.st-error__technique{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);margin:0}\n"] }]
1574
+ }], propDecorators: { variante: [{ type: i0.Input, args: [{ isSignal: true, alias: "variante", required: false }] }], code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: true }] }], titre: [{ type: i0.Input, args: [{ isSignal: true, alias: "titre", required: true }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], traceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "traceId", required: false }] }], niveauDuTitre: [{ type: i0.Input, args: [{ isSignal: true, alias: "niveauDuTitre", required: false }] }], rejouable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rejouable", required: false }] }], rejeuEnCours: [{ type: i0.Input, args: [{ isSignal: true, alias: "rejeuEnCours", required: false }] }], libelleRejeu: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleRejeu", required: false }] }], etiquetteDeTrace: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquetteDeTrace", required: false }] }], rejeu: [{ type: i0.Output, args: ["rejeu"] }] } });
1257
1575
 
1258
1576
  /**
1259
1577
  * Banniere de perte de connexion.
@@ -1272,64 +1590,1050 @@ class StOfflineBanner {
1272
1590
  ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
1273
1591
  libelleRejeu = input(null, /* @ts-ignore */
1274
1592
  ...(ngDevMode ? [{ debugName: "libelleRejeu" }] : /* istanbul ignore next */ []));
1275
- rejeuEnCours = input(false, /* @ts-ignore */
1276
- ...(ngDevMode ? [{ debugName: "rejeuEnCours" }] : /* istanbul ignore next */ []));
1593
+ rejeuEnCours = input(false, { ...(ngDevMode ? { debugName: "rejeuEnCours" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1277
1594
  rejeu = output();
1278
1595
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StOfflineBanner, deps: [], target: i0.ɵɵFactoryTarget.Component });
1279
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StOfflineBanner, isStandalone: true, selector: "st-offline-banner", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, libelleRejeu: { classPropertyName: "libelleRejeu", publicName: "libelleRejeu", isSignal: true, isRequired: false, transformFunction: null }, rejeuEnCours: { classPropertyName: "rejeuEnCours", publicName: "rejeuEnCours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rejeu: "rejeu" }, host: { attributes: { "role": "status" }, classAttribute: "st-offline-banner" }, ngImport: i0, template: "<st-icon nom=\"hors-ligne\" taille=\"sm\" />\n<span class=\"st-offline-banner__message\">{{ message() }}</span>\n\n@if (libelleRejeu(); as libelle) {\n <button\n stButton\n type=\"button\"\n variante=\"discret\"\n taille=\"sm\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelle }}\n </button>\n}\n", styles: [":host{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;min-block-size:2.5rem;padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-block-end:1px solid var(--st-couleur-avertissement)}.st-offline-banner__message{flex:1;font-size:var(--st-taille-sm)}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StButton, selector: "button[stButton]", inputs: ["variante", "taille", "pleineLargeur", "iconeAvant", "iconeApres", "chargement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1596
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StOfflineBanner, isStandalone: true, selector: "st-offline-banner", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, libelleRejeu: { classPropertyName: "libelleRejeu", publicName: "libelleRejeu", isSignal: true, isRequired: false, transformFunction: null }, rejeuEnCours: { classPropertyName: "rejeuEnCours", publicName: "rejeuEnCours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rejeu: "rejeu" }, host: { attributes: { "role": "status" }, classAttribute: "st-offline-banner" }, ngImport: i0, template: "<st-icon nom=\"hors-ligne\" taille=\"sm\" />\n<span class=\"st-offline-banner__message\">{{ message() }}</span>\n\n@if (libelleRejeu(); as libelle) {\n <button\n stButton\n type=\"button\"\n variante=\"discret\"\n taille=\"sm\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelle }}\n </button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;min-block-size:2.5rem;padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-block-end:1px solid var(--st-couleur-avertissement)}.st-offline-banner__message{flex:1;font-size:var(--st-taille-sm)}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StButton, selector: "button[stButton]", inputs: ["variante", "taille", "pleineLargeur", "iconeAvant", "iconeApres", "chargement", "indisponible"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1280
1597
  }
1281
1598
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StOfflineBanner, decorators: [{
1282
1599
  type: Component,
1283
1600
  args: [{ selector: 'st-offline-banner', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIcon, StButton], host: {
1284
1601
  class: 'st-offline-banner',
1285
1602
  role: 'status',
1286
- }, template: "<st-icon nom=\"hors-ligne\" taille=\"sm\" />\n<span class=\"st-offline-banner__message\">{{ message() }}</span>\n\n@if (libelleRejeu(); as libelle) {\n <button\n stButton\n type=\"button\"\n variante=\"discret\"\n taille=\"sm\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelle }}\n </button>\n}\n", styles: [":host{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;min-block-size:2.5rem;padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-block-end:1px solid var(--st-couleur-avertissement)}.st-offline-banner__message{flex:1;font-size:var(--st-taille-sm)}\n"] }]
1603
+ }, template: "<st-icon nom=\"hors-ligne\" taille=\"sm\" />\n<span class=\"st-offline-banner__message\">{{ message() }}</span>\n\n@if (libelleRejeu(); as libelle) {\n <button\n stButton\n type=\"button\"\n variante=\"discret\"\n taille=\"sm\"\n [chargement]=\"rejeuEnCours()\"\n (click)=\"rejeu.emit()\"\n >\n {{ libelle }}\n </button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;min-block-size:2.5rem;padding-block:var(--st-espacement-2);padding-inline:var(--st-espacement-4);color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret);border-block-end:1px solid var(--st-couleur-avertissement)}.st-offline-banner__message{flex:1;font-size:var(--st-taille-sm)}\n"] }]
1287
1604
  }], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], libelleRejeu: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleRejeu", required: false }] }], rejeuEnCours: [{ type: i0.Input, args: [{ isSignal: true, alias: "rejeuEnCours", required: false }] }], rejeu: [{ type: i0.Output, args: ["rejeu"] }] } });
1288
1605
 
1289
- const ANNONCES_PAR_DEFAUT = {
1290
- chargement: 'Chargement en cours',
1291
- erreur: 'Une erreur est survenue',
1292
- vide: 'Aucun resultat',
1293
- 'hors-ligne': 'Hors connexion',
1294
- succes: '',
1606
+ /**
1607
+ * Surface qui regroupe un contenu.
1608
+ *
1609
+ * ⚠️ **Elle n'est jamais cliquable en entier**, et c'est un refus delibere. Une
1610
+ * carte munie d'un `(click)` produit, pour qui ecoute la page, UN seul controle
1611
+ * dont le nom accessible est tout le texte de la carte — titre, montant, date,
1612
+ * mention legale d'un trait. Elle est aussi injoignable au clavier sans
1613
+ * `tabindex`, qui la ferait alors annoncer deux fois.
1614
+ *
1615
+ * Le motif correct : un lien ou un bouton unique DANS la carte, etendu
1616
+ * visuellement a toute sa surface par la classe `st-carte__lien-etendu`. Le
1617
+ * nom accessible reste celui du lien, le clavier fonctionne sans rien ajouter,
1618
+ * et la zone cliquable est la meme.
1619
+ *
1620
+ * ```html
1621
+ * <st-card>
1622
+ * <st-heading [niveau]="3">
1623
+ * <a class="st-carte__lien-etendu" routerLink="/comptes/12">Compte courant</a>
1624
+ * </st-heading>
1625
+ * <st-money [montant]="solde" />
1626
+ * </st-card>
1627
+ * ```
1628
+ */
1629
+ class StCard {
1630
+ relief = input('pose', /* @ts-ignore */
1631
+ ...(ngDevMode ? [{ debugName: "relief" }] : /* istanbul ignore next */ []));
1632
+ rembourrage = input('md', /* @ts-ignore */
1633
+ ...(ngDevMode ? [{ debugName: "rembourrage" }] : /* istanbul ignore next */ []));
1634
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
1635
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StCard, isStandalone: true, selector: "st-card", inputs: { relief: { classPropertyName: "relief", publicName: "relief", isSignal: true, isRequired: false, transformFunction: null }, rembourrage: { classPropertyName: "rembourrage", publicName: "rembourrage", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-relief": "relief()", "attr.data-rembourrage": "rembourrage()" }, classAttribute: "st-card" }, ngImport: i0, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:relative;display:block;color:var(--st-couleur-texte);background:var(--st-carte-fond, var(--st-couleur-surface));border-radius:var(--st-carte-rayon, var(--st-rayon-lg))}:host([data-relief=plat]){box-shadow:var(--st-ombre-none)}:host([data-relief=pose]){border:1px solid var(--st-couleur-bordure);box-shadow:var(--st-ombre-sm)}:host([data-relief=flottant]){box-shadow:var(--st-ombre-md)}:host([data-rembourrage=aucun]){padding:0}:host([data-rembourrage=sm]){padding:var(--st-espacement-3)}:host([data-rembourrage=md]){padding:var(--st-espacement-4)}:host([data-rembourrage=lg]){padding:var(--st-espacement-6)}@media(forced-colors:active){:host{border:1px solid CanvasText}}:host ::ng-deep .st-carte__lien-etendu:after{position:absolute;inset:0;content:\"\"}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1636
+ }
1637
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCard, decorators: [{
1638
+ type: Component,
1639
+ args: [{ selector: 'st-card', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1640
+ class: 'st-card',
1641
+ '[attr.data-relief]': 'relief()',
1642
+ '[attr.data-rembourrage]': 'rembourrage()',
1643
+ }, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{position:relative;display:block;color:var(--st-couleur-texte);background:var(--st-carte-fond, var(--st-couleur-surface));border-radius:var(--st-carte-rayon, var(--st-rayon-lg))}:host([data-relief=plat]){box-shadow:var(--st-ombre-none)}:host([data-relief=pose]){border:1px solid var(--st-couleur-bordure);box-shadow:var(--st-ombre-sm)}:host([data-relief=flottant]){box-shadow:var(--st-ombre-md)}:host([data-rembourrage=aucun]){padding:0}:host([data-rembourrage=sm]){padding:var(--st-espacement-3)}:host([data-rembourrage=md]){padding:var(--st-espacement-4)}:host([data-rembourrage=lg]){padding:var(--st-espacement-6)}@media(forced-colors:active){:host{border:1px solid CanvasText}}:host ::ng-deep .st-carte__lien-etendu:after{position:absolute;inset:0;content:\"\"}\n"] }]
1644
+ }], propDecorators: { relief: [{ type: i0.Input, args: [{ isSignal: true, alias: "relief", required: false }] }], rembourrage: [{ type: i0.Input, args: [{ isSignal: true, alias: "rembourrage", required: false }] }] } });
1645
+
1646
+ /**
1647
+ * Regroupement de contenu, expose comme REPERE de navigation quand il porte un
1648
+ * nom.
1649
+ *
1650
+ * ⚠️ Le point qui decide de tout : `role="region"` n'est expose comme repere
1651
+ * que s'il a un NOM ACCESSIBLE. Sans nom, la plupart des lecteurs d'ecran
1652
+ * l'ignorent purement et simplement — la balise est la, le repere n'existe pas,
1653
+ * et rien ne le signale. Le composant refuse donc de poser le role quand il ne
1654
+ * peut pas le nommer : une section anonyme reste un simple bloc, ce qu'elle est
1655
+ * reellement.
1656
+ *
1657
+ * Deux facons de la nommer, et la seconde vaut mieux : `titreDe` pointe le
1658
+ * titre deja affiche, ce qui garde un seul texte a traduire et a maintenir.
1659
+ *
1660
+ * ```html
1661
+ * <st-heading [niveau]="2" identifiant="titre-operations">Operations</st-heading>
1662
+ * <st-section titreDe="titre-operations">…</st-section>
1663
+ * ```
1664
+ */
1665
+ class StSection {
1666
+ /** Nom accessible ecrit a la main. A preferer `titreDe` quand un titre existe. */
1667
+ etiquette = input(null, /* @ts-ignore */
1668
+ ...(ngDevMode ? [{ debugName: "etiquette" }] : /* istanbul ignore next */ []));
1669
+ /** Identifiant du titre qui nomme la section. Prime sur `etiquette`. */
1670
+ titreDe = input(null, /* @ts-ignore */
1671
+ ...(ngDevMode ? [{ debugName: "titreDe" }] : /* istanbul ignore next */ []));
1672
+ espacement = input('md', /* @ts-ignore */
1673
+ ...(ngDevMode ? [{ debugName: "espacement" }] : /* istanbul ignore next */ []));
1674
+ estUnRepere = computed(() => this.titreDe() !== null || this.etiquette() !== null, /* @ts-ignore */
1675
+ ...(ngDevMode ? [{ debugName: "estUnRepere" }] : /* istanbul ignore next */ []));
1676
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
1677
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StSection, isStandalone: true, selector: "st-section", inputs: { etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null }, titreDe: { classPropertyName: "titreDe", publicName: "titreDe", isSignal: true, isRequired: false, transformFunction: null }, espacement: { classPropertyName: "espacement", publicName: "espacement", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.role": "estUnRepere() ? \"region\" : null", "attr.aria-label": "titreDe() === null ? etiquette() : null", "attr.aria-labelledby": "titreDe()", "attr.data-espacement": "espacement()" }, classAttribute: "st-section" }, ngImport: i0, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block}:host([data-espacement=aucun]){margin-block-end:0}:host([data-espacement=sm]){margin-block-end:var(--st-espacement-4)}:host([data-espacement=md]){margin-block-end:var(--st-espacement-6)}:host([data-espacement=lg]){margin-block-end:var(--st-espacement-8)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1678
+ }
1679
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSection, decorators: [{
1680
+ type: Component,
1681
+ args: [{ selector: 'st-section', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1682
+ class: 'st-section',
1683
+ '[attr.role]': 'estUnRepere() ? "region" : null',
1684
+ '[attr.aria-label]': 'titreDe() === null ? etiquette() : null',
1685
+ '[attr.aria-labelledby]': 'titreDe()',
1686
+ '[attr.data-espacement]': 'espacement()',
1687
+ }, template: "<ng-content />\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block}:host([data-espacement=aucun]){margin-block-end:0}:host([data-espacement=sm]){margin-block-end:var(--st-espacement-4)}:host([data-espacement=md]){margin-block-end:var(--st-espacement-6)}:host([data-espacement=lg]){margin-block-end:var(--st-espacement-8)}\n"] }]
1688
+ }], propDecorators: { etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }], titreDe: [{ type: i0.Input, args: [{ isSignal: true, alias: "titreDe", required: false }] }], espacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "espacement", required: false }] }] } });
1689
+
1690
+ /**
1691
+ * Trait de separation.
1692
+ *
1693
+ * ⚠️ **Decoratif par defaut, et c'est le bon defaut.** Un `<hr>` porte le role
1694
+ * `separator` de facon implicite, que les lecteurs d'ecran annoncent. Sur une
1695
+ * page qui en compte huit — ce qui est courant dans une liste de reglages — la
1696
+ * lecture est ponctuee de huit « separateur » qui n'apprennent rien.
1697
+ *
1698
+ * Le role ne se pose que lorsque le trait porte vraiment du sens : il separe
1699
+ * alors deux GROUPES que rien d'autre ne distingue, comme les sections d'un
1700
+ * menu. Regle de tri : si le retirer ne retire aucune information, il est
1701
+ * decoratif.
1702
+ */
1703
+ class StDivider {
1704
+ orientation = input('horizontale', /* @ts-ignore */
1705
+ ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
1706
+ /** Le trait separe deux groupes distincts, et doit donc etre annonce. */
1707
+ porteurDeSens = input(false, { ...(ngDevMode ? { debugName: "porteurDeSens" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1708
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StDivider, deps: [], target: i0.ɵɵFactoryTarget.Component });
1709
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StDivider, isStandalone: true, selector: "st-divider", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, porteurDeSens: { classPropertyName: "porteurDeSens", publicName: "porteurDeSens", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.role": "porteurDeSens() ? \"separator\" : \"none\"", "attr.aria-hidden": "porteurDeSens() ? null : \"true\"", "attr.aria-orientation": "porteurDeSens() && orientation() === \"verticale\" ? \"vertical\" : null", "attr.data-orientation": "orientation()" }, classAttribute: "st-divider" }, ngImport: i0, template: "", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;flex:none;background:var(--st-couleur-bordure);border:0}:host([data-orientation=horizontale]){inline-size:100%;block-size:var(--st-separateur-epaisseur, 1px);margin-block:var(--st-separateur-marge, var(--st-espacement-4))}:host([data-orientation=verticale]){inline-size:var(--st-separateur-epaisseur, 1px);align-self:stretch;margin-inline:var(--st-separateur-marge, var(--st-espacement-4))}@media(forced-colors:active){:host{background:CanvasText}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1710
+ }
1711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StDivider, decorators: [{
1712
+ type: Component,
1713
+ args: [{ selector: 'st-divider', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1714
+ class: 'st-divider',
1715
+ '[attr.role]': 'porteurDeSens() ? "separator" : "none"',
1716
+ '[attr.aria-hidden]': 'porteurDeSens() ? null : "true"',
1717
+ // ⚠️ Annonce seulement quand elle differe du defaut d'ARIA, qui est
1718
+ // horizontal : un `aria-orientation="horizontal"` partout est du bruit.
1719
+ '[attr.aria-orientation]': 'porteurDeSens() && orientation() === "verticale" ? "vertical" : null',
1720
+ '[attr.data-orientation]': 'orientation()',
1721
+ }, template: "", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;flex:none;background:var(--st-couleur-bordure);border:0}:host([data-orientation=horizontale]){inline-size:100%;block-size:var(--st-separateur-epaisseur, 1px);margin-block:var(--st-separateur-marge, var(--st-espacement-4))}:host([data-orientation=verticale]){inline-size:var(--st-separateur-epaisseur, 1px);align-self:stretch;margin-inline:var(--st-separateur-marge, var(--st-espacement-4))}@media(forced-colors:active){:host{background:CanvasText}}\n"] }]
1722
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], porteurDeSens: [{ type: i0.Input, args: [{ isSignal: true, alias: "porteurDeSens", required: false }] }] } });
1723
+
1724
+ /**
1725
+ * Titre de page : le `h1`, et les actions qui lui sont attachees.
1726
+ *
1727
+ * ⚠️ Il rend une **vraie balise `h1`**, la ou `st-heading` porte
1728
+ * `role="heading"` sur son hote. La raison est precise : `StNavigation` de
1729
+ * `@starterlib/core` vise le titre de niveau 1 pour y poser le focus apres une
1730
+ * navigation, et une vraie balise est ce que trouvent aussi les extensions, le
1731
+ * mode lecture et les outils d'audit. Un `h1` par page, jamais deux.
1732
+ *
1733
+ * ⚠️ **Il ne gere PAS le focus**, et ce n'est pas un oubli. Le noyau le fait
1734
+ * deja a chaque changement de route. Deux mecanismes qui deplacent le focus a
1735
+ * la meme milliseconde ne se completent pas : ils se battent, et le gagnant
1736
+ * depend de l'ordre de rendu — donc du hasard.
1737
+ *
1738
+ * ```html
1739
+ * <st-page-title>
1740
+ * Mes operations
1741
+ * <button stButton variante="primaire" actions>Exporter</button>
1742
+ * </st-page-title>
1743
+ * ```
1744
+ */
1745
+ class StPageTitle {
1746
+ /** Texte secondaire sous le titre. Jamais porteur d'information critique. */
1747
+ precision = input(null, /* @ts-ignore */
1748
+ ...(ngDevMode ? [{ debugName: "precision" }] : /* istanbul ignore next */ []));
1749
+ /** Cible d'un `aria-labelledby` : une region se nomme par son titre. */
1750
+ identifiant = input(null, /* @ts-ignore */
1751
+ ...(ngDevMode ? [{ debugName: "identifiant" }] : /* istanbul ignore next */ []));
1752
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StPageTitle, deps: [], target: i0.ɵɵFactoryTarget.Component });
1753
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StPageTitle, isStandalone: true, selector: "st-page-title", inputs: { precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null }, identifiant: { classPropertyName: "identifiant", publicName: "identifiant", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-page-title" }, ngImport: i0, template: "<div class=\"st-page-title__ligne\">\n <h1 class=\"st-page-title__titre\" [attr.id]=\"identifiant()\"><ng-content /></h1>\n <div class=\"st-page-title__actions\"><ng-content select=\"[actions]\" /></div>\n</div>\n@if (precision() !== null) {\n <p class=\"st-page-title__precision\">{{ precision() }}</p>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin-block-end:var(--st-espacement-6)}.st-page-title__ligne{display:flex;flex-wrap:wrap;gap:var(--st-espacement-3);align-items:flex-start;justify-content:space-between}.st-page-title__titre:focus{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}.st-page-title__titre{margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-3xl);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}.st-page-title__actions:empty{display:none}.st-page-title__actions{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}.st-page-title__precision{margin:var(--st-espacement-2) 0 0;font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1754
+ }
1755
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StPageTitle, decorators: [{
1756
+ type: Component,
1757
+ args: [{ selector: 'st-page-title', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-page-title' }, template: "<div class=\"st-page-title__ligne\">\n <h1 class=\"st-page-title__titre\" [attr.id]=\"identifiant()\"><ng-content /></h1>\n <div class=\"st-page-title__actions\"><ng-content select=\"[actions]\" /></div>\n</div>\n@if (precision() !== null) {\n <p class=\"st-page-title__precision\">{{ precision() }}</p>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin-block-end:var(--st-espacement-6)}.st-page-title__ligne{display:flex;flex-wrap:wrap;gap:var(--st-espacement-3);align-items:flex-start;justify-content:space-between}.st-page-title__titre:focus{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}.st-page-title__titre{margin:0;font-family:var(--st-police-base);font-size:var(--st-taille-3xl);font-weight:var(--st-graisse-semi);line-height:var(--st-interligne-serre);color:var(--st-couleur-texte);text-wrap:balance}.st-page-title__actions:empty{display:none}.st-page-title__actions{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}.st-page-title__precision{margin:var(--st-espacement-2) 0 0;font-size:var(--st-taille-sm);color:var(--st-couleur-texte-discret)}\n"] }]
1758
+ }], propDecorators: { precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }], identifiant: [{ type: i0.Input, args: [{ isSignal: true, alias: "identifiant", required: false }] }] } });
1759
+
1760
+ /**
1761
+ * Fil d'Ariane.
1762
+ *
1763
+ * ⚠️ **Le dernier maillon n'est pas un lien.** C'est la page courante : un lien
1764
+ * vers l'endroit ou l'on se trouve deja n'apporte rien, et il ajoute un arret
1765
+ * de tabulation sur chaque page du site. Il porte `aria-current="page"`, qui
1766
+ * est ce que le lecteur d'ecran annonce a sa place.
1767
+ *
1768
+ * ⚠️ **Les separateurs sont poses en `aria-hidden`.** Un chevron ou une barre
1769
+ * oblique laisses dans l'arbre d'accessibilite se lit « barre oblique » entre
1770
+ * chaque maillon : « Accueil barre oblique Comptes barre oblique Operations ».
1771
+ * Les poser en contenu engendre par CSS ne suffit pas — Chrome et Firefox
1772
+ * exposent `content` a l'arbre d'accessibilite.
1773
+ *
1774
+ * ⚠️ La liste est ORDONNEE (`ol`) : l'ordre des maillons est l'information.
1775
+ *
1776
+ * ⚠️ **Les liens passent par le routeur.** La premiere version posait des
1777
+ * `href` bruts : dans une SPA, un clic quittait l'application, repassait par la
1778
+ * coquille du BFF et perdait tout l'etat en memoire — sur le composant de
1779
+ * navigation le plus clique apres le menu.
1780
+ */
1781
+ class StBreadcrumb {
1782
+ libelles = inject(ST_LIBELLES);
1783
+ maillons = input.required(/* @ts-ignore */
1784
+ ...(ngDevMode ? [{ debugName: "maillons" }] : /* istanbul ignore next */ []));
1785
+ /** `null` : le texte vient du dictionnaire de l'application. */
1786
+ etiquette = input(null, /* @ts-ignore */
1787
+ ...(ngDevMode ? [{ debugName: "etiquette" }] : /* istanbul ignore next */ []));
1788
+ /** Caractere de separation. Muet pour les technologies d'assistance. */
1789
+ separateur = input('/', /* @ts-ignore */
1790
+ ...(ngDevMode ? [{ debugName: "separateur" }] : /* istanbul ignore next */ []));
1791
+ etiquetteLue = computed(() => this.etiquette() ?? this.libelles().filDAriane, /* @ts-ignore */
1792
+ ...(ngDevMode ? [{ debugName: "etiquetteLue" }] : /* istanbul ignore next */ []));
1793
+ /** Le dernier maillon est la page courante, jamais un lien. */
1794
+ derniereIndice = computed(() => this.maillons().length - 1, /* @ts-ignore */
1795
+ ...(ngDevMode ? [{ debugName: "derniereIndice" }] : /* istanbul ignore next */ []));
1796
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBreadcrumb, deps: [], target: i0.ɵɵFactoryTarget.Component });
1797
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StBreadcrumb, isStandalone: true, selector: "st-breadcrumb", inputs: { maillons: { classPropertyName: "maillons", publicName: "maillons", isSignal: true, isRequired: true, transformFunction: null }, etiquette: { classPropertyName: "etiquette", publicName: "etiquette", isSignal: true, isRequired: false, transformFunction: null }, separateur: { classPropertyName: "separateur", publicName: "separateur", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-breadcrumb" }, ngImport: i0, template: "<nav [attr.aria-label]=\"etiquetteLue()\">\n <ol class=\"st-breadcrumb__liste\">\n @for (maillon of maillons(); track $index; let indice = $index, premier = $first) {\n <li class=\"st-breadcrumb__maillon\">\n @if (!premier) {\n <span class=\"st-breadcrumb__separateur\" aria-hidden=\"true\">{{ separateur() }}</span>\n }\n @if (indice === derniereIndice() || maillon.lien === undefined) {\n <span aria-current=\"page\">{{ maillon.libelle }}</span>\n } @else {\n <a [routerLink]=\"maillon.lien\">{{ maillon.libelle }}</a>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin-block-end:var(--st-espacement-4);font-size:var(--st-taille-sm)}.st-breadcrumb__liste{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;padding:0;margin:0;list-style:none}.st-breadcrumb__maillon{display:flex;gap:var(--st-espacement-2);align-items:center;color:var(--st-couleur-texte-discret)}.st-breadcrumb__separateur{color:var(--st-couleur-texte-discret)}a:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}a{color:var(--st-couleur-texte-discret);text-decoration:underline;border-radius:var(--st-rayon-xs)}a:hover{color:var(--st-couleur-texte)}[aria-current=page]{font-weight:var(--st-graisse-semi);color:var(--st-couleur-texte)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1798
+ }
1799
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBreadcrumb, decorators: [{
1800
+ type: Component,
1801
+ args: [{ selector: 'st-breadcrumb', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink], host: { class: 'st-breadcrumb' }, template: "<nav [attr.aria-label]=\"etiquetteLue()\">\n <ol class=\"st-breadcrumb__liste\">\n @for (maillon of maillons(); track $index; let indice = $index, premier = $first) {\n <li class=\"st-breadcrumb__maillon\">\n @if (!premier) {\n <span class=\"st-breadcrumb__separateur\" aria-hidden=\"true\">{{ separateur() }}</span>\n }\n @if (indice === derniereIndice() || maillon.lien === undefined) {\n <span aria-current=\"page\">{{ maillon.libelle }}</span>\n } @else {\n <a [routerLink]=\"maillon.lien\">{{ maillon.libelle }}</a>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:block;margin-block-end:var(--st-espacement-4);font-size:var(--st-taille-sm)}.st-breadcrumb__liste{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center;padding:0;margin:0;list-style:none}.st-breadcrumb__maillon{display:flex;gap:var(--st-espacement-2);align-items:center;color:var(--st-couleur-texte-discret)}.st-breadcrumb__separateur{color:var(--st-couleur-texte-discret)}a:focus-visible{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}a{color:var(--st-couleur-texte-discret);text-decoration:underline;border-radius:var(--st-rayon-xs)}a:hover{color:var(--st-couleur-texte)}[aria-current=page]{font-weight:var(--st-graisse-semi);color:var(--st-couleur-texte)}\n"] }]
1802
+ }], propDecorators: { maillons: [{ type: i0.Input, args: [{ isSignal: true, alias: "maillons", required: true }] }], etiquette: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiquette", required: false }] }], separateur: [{ type: i0.Input, args: [{ isSignal: true, alias: "separateur", required: false }] }] } });
1803
+
1804
+ /** Identifiant par defaut du contenu principal, pose par `st-app-shell`. */
1805
+ const IDENTIFIANT_DU_CONTENU_PRINCIPAL = 'contenu-principal';
1806
+ /**
1807
+ * Lien d'evitement : aller au contenu sans traverser la navigation.
1808
+ *
1809
+ * WCAG 2.4.1. Sans lui, chaque page impose a qui navigue au clavier de
1810
+ * traverser l'en-tete et tout le menu avant d'atteindre ce qu'il est venu lire —
1811
+ * trente arrets de tabulation, a chaque changement de page.
1812
+ *
1813
+ * ⚠️ **Le focus est pose par script, et la navigation par ancre est annulee.**
1814
+ * Deux raisons, et chacune suffit :
1815
+ *
1816
+ * 1. Un `href="#contenu"` se resout contre `<base href>`. Sous
1817
+ * `/ui/<interface>/`, il vise `/ui/<interface>/#contenu` : un rechargement
1818
+ * complet de la coquille, au lieu d'un saut dans la page.
1819
+ * 2. Suivre une ancre deplace la vue sans toujours deplacer le FOCUS. La
1820
+ * tabulation suivante repart alors du lien d'evitement, et le saut n'a servi
1821
+ * a rien.
1822
+ *
1823
+ * Le `href` reste pose : c'est lui qui fait du lien un lien, pour le lecteur
1824
+ * d'ecran comme pour le clic du milieu.
1825
+ *
1826
+ * ⚠️ Il doit etre le PREMIER element focalisable du document. Le composant ne
1827
+ * peut pas l'imposer ; `st-app-shell` le fait.
1828
+ */
1829
+ class StSkipLink {
1830
+ document = inject(DOCUMENT);
1831
+ libelles = inject(ST_LIBELLES);
1832
+ /** Identifiant de l'element a atteindre. */
1833
+ cible = input(IDENTIFIANT_DU_CONTENU_PRINCIPAL, /* @ts-ignore */
1834
+ ...(ngDevMode ? [{ debugName: "cible" }] : /* istanbul ignore next */ []));
1835
+ /** `null` : le texte vient du dictionnaire de l'application. */
1836
+ libelle = input(null, /* @ts-ignore */
1837
+ ...(ngDevMode ? [{ debugName: "libelle" }] : /* istanbul ignore next */ []));
1838
+ libelleLu = computed(() => this.libelle() ?? this.libelles().allerAuContenu, /* @ts-ignore */
1839
+ ...(ngDevMode ? [{ debugName: "libelleLu" }] : /* istanbul ignore next */ []));
1840
+ ancre = computed(() => `#${this.cible()}`, /* @ts-ignore */
1841
+ ...(ngDevMode ? [{ debugName: "ancre" }] : /* istanbul ignore next */ []));
1842
+ aller(evenement) {
1843
+ const cible = this.document.getElementById(this.cible());
1844
+ if (cible === null)
1845
+ return;
1846
+ evenement.preventDefault();
1847
+ // `tabindex="-1"` : un `main` n'est pas focalisable, et `focus()` sur un
1848
+ // element qui ne l'est pas ne fait rien — en silence.
1849
+ if (!cible.hasAttribute('tabindex'))
1850
+ cible.setAttribute('tabindex', '-1');
1851
+ cible.focus();
1852
+ }
1853
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSkipLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
1854
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StSkipLink, isStandalone: true, selector: "st-skip-link", inputs: { cible: { classPropertyName: "cible", publicName: "cible", isSignal: true, isRequired: false, transformFunction: null }, libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "st-skip-link" }, ngImport: i0, template: "<a class=\"st-skip-link__lien\" [attr.href]=\"ancre()\" (click)=\"aller($event)\">{{ libelleLu() }}</a>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}.st-skip-link__lien{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-skip-link__lien:focus{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}.st-skip-link__lien:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip-path:none;white-space:normal;position:fixed;inset-block-start:var(--st-espacement-2);inset-inline-start:var(--st-espacement-2);z-index:var(--st-plan-notification);padding:var(--st-espacement-2) var(--st-espacement-4);font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-radius:var(--st-rayon-md)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1855
+ }
1856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSkipLink, decorators: [{
1857
+ type: Component,
1858
+ args: [{ selector: 'st-skip-link', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-skip-link' }, template: "<a class=\"st-skip-link__lien\" [attr.href]=\"ancre()\" (click)=\"aller($event)\">{{ libelleLu() }}</a>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}.st-skip-link__lien{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-skip-link__lien:focus{outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}.st-skip-link__lien:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip-path:none;white-space:normal;position:fixed;inset-block-start:var(--st-espacement-2);inset-inline-start:var(--st-espacement-2);z-index:var(--st-plan-notification);padding:var(--st-espacement-2) var(--st-espacement-4);font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-radius:var(--st-rayon-md)}\n"] }]
1859
+ }], propDecorators: { cible: [{ type: i0.Input, args: [{ isSignal: true, alias: "cible", required: false }] }], libelle: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelle", required: false }] }] } });
1860
+
1861
+ /**
1862
+ * Coquille d'une application : lien d'evitement, en-tete, navigation, contenu
1863
+ * principal, pied de page.
1864
+ *
1865
+ * ```html
1866
+ * <st-app-shell>
1867
+ * <ng-container entete>…</ng-container>
1868
+ * <ng-container navigation>…</ng-container>
1869
+ * <router-outlet />
1870
+ * <ng-container pied>…</ng-container>
1871
+ * </st-app-shell>
1872
+ * ```
1873
+ *
1874
+ * ⚠️ Son role est de garantir les REPERES, et un seul de chaque. Une page qui
1875
+ * compte deux `main` — frequent quand une micro-SPA pose le sien dans celui de
1876
+ * la coquille — prive le lecteur d'ecran du raccourci « aller au contenu
1877
+ * principal » : il ne sait plus lequel viser. Les remotes ne posent donc
1878
+ * jamais de `main`, `header` ni `footer` de premier niveau.
1879
+ *
1880
+ * ⚠️ Le lien d'evitement est rendu EN PREMIER, avant l'en-tete : c'est la seule
1881
+ * place ou il sert. Place apres, il faut deja avoir traverse ce qu'il permet
1882
+ * d'eviter.
1883
+ *
1884
+ * Le contenu principal porte l'identifiant vise par le lien d'evitement.
1885
+ * Le focus de navigation, lui, vise le titre de niveau 1 : voir `StNavigation`
1886
+ * de `@starterlib/core`. Les deux se completent — l'un au chargement d'une
1887
+ * page, l'autre a chaque changement de route.
1888
+ *
1889
+ * ⚠️ La coquille ne pose PAS de `<nav>` autour de la navigation : c'est
1890
+ * `st-sidenav` qui porte ce repere. Pose ici aussi, il s'imbriquerait — le
1891
+ * lecteur d'ecran annoncerait « navigation, navigation » — et resterait vide
1892
+ * sur petit ecran, quand le contenu part dans le tiroir.
1893
+ */
1894
+ class StAppShell {
1895
+ identifiantDuContenu = IDENTIFIANT_DU_CONTENU_PRINCIPAL;
1896
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StAppShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
1897
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: StAppShell, isStandalone: true, selector: "st-app-shell", host: { classAttribute: "st-app-shell" }, ngImport: i0, template: "<st-skip-link [cible]=\"identifiantDuContenu\" />\n\n<header class=\"st-app-shell__entete\">\n <ng-content select=\"[entete]\" />\n</header>\n\n<div class=\"st-app-shell__corps\">\n <div class=\"st-app-shell__navigation\">\n <ng-content select=\"[navigation]\" />\n </div>\n\n <main class=\"st-app-shell__contenu\" [id]=\"identifiantDuContenu\">\n <ng-content />\n </main>\n</div>\n\n<footer class=\"st-app-shell__pied\">\n <ng-content select=\"[pied]\" />\n</footer>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;min-block-size:100dvh;color:var(--st-couleur-texte);background:var(--st-couleur-fond)}.st-app-shell__entete{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);background:var(--st-couleur-surface);border-block-end:1px solid var(--st-couleur-bordure)}.st-app-shell__corps{display:flex;flex:1 1 auto;flex-direction:column}.st-app-shell__navigation:empty,.st-app-shell__entete:empty,.st-app-shell__pied:empty{display:none}.st-app-shell__contenu{flex:1 1 auto;min-inline-size:0;padding:var(--st-espacement-6) var(--st-espacement-4)}.st-app-shell__contenu:focus{outline:none}.st-app-shell__pied{padding:var(--st-espacement-4);color:var(--st-couleur-texte-discret);border-block-start:1px solid var(--st-couleur-bordure)}@media(min-width:64rem){.st-app-shell__corps{flex-direction:row}.st-app-shell__navigation{flex:none;inline-size:var(--st-coquille-largeur-navigation, 16rem);border-inline-end:1px solid var(--st-couleur-bordure)}.st-app-shell__contenu{padding:var(--st-espacement-8)}}\n"], dependencies: [{ kind: "component", type: StSkipLink, selector: "st-skip-link", inputs: ["cible", "libelle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1898
+ }
1899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StAppShell, decorators: [{
1900
+ type: Component,
1901
+ args: [{ selector: 'st-app-shell', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StSkipLink], host: { class: 'st-app-shell' }, template: "<st-skip-link [cible]=\"identifiantDuContenu\" />\n\n<header class=\"st-app-shell__entete\">\n <ng-content select=\"[entete]\" />\n</header>\n\n<div class=\"st-app-shell__corps\">\n <div class=\"st-app-shell__navigation\">\n <ng-content select=\"[navigation]\" />\n </div>\n\n <main class=\"st-app-shell__contenu\" [id]=\"identifiantDuContenu\">\n <ng-content />\n </main>\n</div>\n\n<footer class=\"st-app-shell__pied\">\n <ng-content select=\"[pied]\" />\n</footer>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-direction:column;min-block-size:100dvh;color:var(--st-couleur-texte);background:var(--st-couleur-fond)}.st-app-shell__entete{position:sticky;inset-block-start:0;z-index:var(--st-plan-entete);background:var(--st-couleur-surface);border-block-end:1px solid var(--st-couleur-bordure)}.st-app-shell__corps{display:flex;flex:1 1 auto;flex-direction:column}.st-app-shell__navigation:empty,.st-app-shell__entete:empty,.st-app-shell__pied:empty{display:none}.st-app-shell__contenu{flex:1 1 auto;min-inline-size:0;padding:var(--st-espacement-6) var(--st-espacement-4)}.st-app-shell__contenu:focus{outline:none}.st-app-shell__pied{padding:var(--st-espacement-4);color:var(--st-couleur-texte-discret);border-block-start:1px solid var(--st-couleur-bordure)}@media(min-width:64rem){.st-app-shell__corps{flex-direction:row}.st-app-shell__navigation{flex:none;inline-size:var(--st-coquille-largeur-navigation, 16rem);border-inline-end:1px solid var(--st-couleur-bordure)}.st-app-shell__contenu{padding:var(--st-espacement-8)}}\n"] }]
1902
+ }] });
1903
+
1904
+ /**
1905
+ * Contenu de l'en-tete : bouton de navigation, marque, puis actions.
1906
+ *
1907
+ * ```html
1908
+ * <st-app-shell>
1909
+ * <st-header entete>
1910
+ * <button bascule stButton [stSidenavToggle]="navigation">Menu</button>
1911
+ * <a marque routerLink="/"><st-logo nom="Banque Exemple" clair="/logo.svg" /></a>
1912
+ * <st-lang-switch [courante]="langue.courante()" (choisie)="langue.changer($event)" />
1913
+ * <button stButton [stMenuTrigger]="compte">Mon compte</button>
1914
+ * </st-header>
1915
+ * </st-app-shell>
1916
+ * ```
1917
+ *
1918
+ * ⚠️ **Aucun repere pose ici.** Le `header` de `st-app-shell` est deja le
1919
+ * repere « banniere » ; en ajouter un second dans le premier ferait annoncer
1920
+ * deux bannieres.
1921
+ *
1922
+ * ⚠️ **Composition, pas assemblage.** Il ne cree ni menu, ni bascule, ni logo :
1923
+ * il les place. C'est ce qui le garde dans le tronc — importer `st-menu` l'aurait
1924
+ * fait sortir vers un point d'entree secondaire — et qui laisse chaque SPA
1925
+ * choisir ses actions.
1926
+ *
1927
+ * L'ordre du DOM est l'ordre de lecture et de tabulation : bouton de
1928
+ * navigation, marque, actions. Il n'est jamais inverse par le style.
1929
+ */
1930
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class -- composant de mise en page pur : tout est dans son gabarit et sa feuille.
1931
+ class StHeader {
1932
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
1933
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: StHeader, isStandalone: true, selector: "st-header", host: { classAttribute: "st-header" }, ngImport: i0, template: "<div class=\"st-header__debut\">\n <ng-content select=\"[bascule]\" />\n <ng-content select=\"[marque]\" />\n</div>\n<div class=\"st-header__actions\">\n <ng-content />\n</div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-3);align-items:center;justify-content:space-between;min-block-size:3.5rem;padding:var(--st-espacement-2) var(--st-espacement-4)}.st-header__debut,.st-header__actions{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}.st-header__actions:empty{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1934
+ }
1935
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHeader, decorators: [{
1936
+ type: Component,
1937
+ args: [{ selector: 'st-header', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-header' }, template: "<div class=\"st-header__debut\">\n <ng-content select=\"[bascule]\" />\n <ng-content select=\"[marque]\" />\n</div>\n<div class=\"st-header__actions\">\n <ng-content />\n</div>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;flex-wrap:wrap;gap:var(--st-espacement-3);align-items:center;justify-content:space-between;min-block-size:3.5rem;padding:var(--st-espacement-2) var(--st-espacement-4)}.st-header__debut,.st-header__actions{display:flex;flex-wrap:wrap;gap:var(--st-espacement-2);align-items:center}.st-header__actions:empty{display:none}\n"] }]
1938
+ }] });
1939
+
1940
+ const FOCALISABLES = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), ' +
1941
+ 'textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
1942
+ // Valeurs de `Node.DOCUMENT_POSITION_*`, ecrites en clair : `Node` n'existe pas
1943
+ // au rendu serveur, et la comparaison ne doit pas en dependre au chargement.
1944
+ const PRECEDE = 2;
1945
+ const SUIT = 4;
1946
+ /**
1947
+ * ⚠️ L'icone doit differer par sa FORME d'un ton a l'autre, et non seulement
1948
+ * par sa couleur : un message porte par la seule couleur est illisible pour une
1949
+ * personne daltonienne, a l'impression, et sous un theme a fort contraste.
1950
+ */
1951
+ const ICONE$1 = {
1952
+ neutre: 'cercle-info',
1953
+ primaire: 'cercle-info',
1954
+ succes: 'cercle-coche',
1955
+ avertissement: 'triangle-alerte',
1956
+ danger: 'cercle-croix',
1957
+ };
1958
+ /**
1959
+ * Message de page, persistant jusqu'a ce qu'on le ferme.
1960
+ *
1961
+ * Distinct de `st-offline-banner`, qui dit un fait qu'on ne peut pas fermer, et
1962
+ * de `st-error`, qui remplace un contenu au lieu de l'accompagner.
1963
+ *
1964
+ * ⚠️ **Elle est une region vivante, et ce n'est pas redondant au chargement.**
1965
+ * Un lecteur d'ecran annonce les MUTATIONS d'une region qu'il observe deja :
1966
+ * une banniere presente des l'affichage est lue avec la page, une fois, puis
1967
+ * son apparition ulterieure est annoncee. Le meme mecanisme sert les deux cas.
1968
+ *
1969
+ * ⚠️ Le ton `danger` passe en `alert` (assertif) : une operation qui vient
1970
+ * d'echouer doit interrompre. Les autres restent en `status`, sinon une
1971
+ * confirmation couperait la lecture en cours et ferait perdre sa place.
1972
+ *
1973
+ * ⚠️ Comme `st-spinner` et `st-error`, elle se tait dans une region vivante
1974
+ * existante : sans cela, le lecteur annonce deux fois le meme message.
1975
+ */
1976
+ class StBanner {
1977
+ element = inject(ElementRef);
1978
+ regionParente = inject(REGION_VIVANTE_PARENTE, { optional: true });
1979
+ libelles = inject(ST_LIBELLES);
1980
+ ton = input('neutre', /* @ts-ignore */
1981
+ ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1982
+ message = input.required(/* @ts-ignore */
1983
+ ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
1984
+ /** Titre court au-dessus du message. Le message seul suffit le plus souvent. */
1985
+ titre = input(null, /* @ts-ignore */
1986
+ ...(ngDevMode ? [{ debugName: "titre" }] : /* istanbul ignore next */ []));
1987
+ fermable = input(false, { ...(ngDevMode ? { debugName: "fermable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1988
+ /** `null` : le texte vient du dictionnaire de l'application. */
1989
+ libelleFermeture = input(null, /* @ts-ignore */
1990
+ ...(ngDevMode ? [{ debugName: "libelleFermeture" }] : /* istanbul ignore next */ []));
1991
+ ferme = output();
1992
+ icone = computed(() => ICONE$1[this.ton()], /* @ts-ignore */
1993
+ ...(ngDevMode ? [{ debugName: "icone" }] : /* istanbul ignore next */ []));
1994
+ libelleFermetureLu = computed(() => this.libelleFermeture() ?? this.libelles().fermerLeMessage, /* @ts-ignore */
1995
+ ...(ngDevMode ? [{ debugName: "libelleFermetureLu" }] : /* istanbul ignore next */ []));
1996
+ roleLu = computed(() => {
1997
+ if (this.regionParente !== null)
1998
+ return null;
1999
+ return this.ton() === 'danger' ? 'alert' : 'status';
2000
+ }, /* @ts-ignore */
2001
+ ...(ngDevMode ? [{ debugName: "roleLu" }] : /* istanbul ignore next */ []));
2002
+ /**
2003
+ * ⚠️ Le focus est DEPLACE avant l'emission. Sans cela, le bouton disparait
2004
+ * sous le doigt de l'utilisateur clavier, le focus retombe sur le corps du
2005
+ * document, et la navigation repart du haut de la page — le meme defaut que
2006
+ * sur une liste d'etiquettes, et l'un des plus frequents.
2007
+ */
2008
+ fermer() {
2009
+ this.deplacerLeFocus();
2010
+ this.ferme.emit();
2011
+ }
2012
+ /**
2013
+ * Cible, dans l'ordre : le premier element focalisable qui SUIT la banniere
2014
+ * dans le document, sinon le dernier qui la precede, sinon le conteneur s'il
2015
+ * est focalisable par script.
2016
+ *
2017
+ * ⚠️ L'ordre du DOCUMENT, et non les descendants du voisin. La premiere
2018
+ * version cherchait dans `nextElementSibling` : un bouton pose directement
2019
+ * apres la banniere n'etait pas trouve, puisqu'il n'est pas son propre
2020
+ * descendant, et le focus retombait sur le corps du document.
2021
+ */
2022
+ deplacerLeFocus() {
2023
+ const hote = this.element.nativeElement;
2024
+ const candidats = [...hote.ownerDocument.querySelectorAll(FOCALISABLES)].filter((candidat) => !hote.contains(candidat));
2025
+ const suivant = candidats.find((candidat) => (hote.compareDocumentPosition(candidat) & SUIT) !== 0);
2026
+ if (suivant !== undefined) {
2027
+ suivant.focus();
2028
+ return;
2029
+ }
2030
+ const precedent = candidats
2031
+ .reverse()
2032
+ .find((candidat) => (hote.compareDocumentPosition(candidat) & PRECEDE) !== 0);
2033
+ if (precedent !== undefined) {
2034
+ precedent.focus();
2035
+ return;
2036
+ }
2037
+ const parent = hote.parentElement;
2038
+ if (parent?.hasAttribute('tabindex') === true)
2039
+ parent.focus();
2040
+ }
2041
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBanner, deps: [], target: i0.ɵɵFactoryTarget.Component });
2042
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StBanner, isStandalone: true, selector: "st-banner", inputs: { ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, titre: { classPropertyName: "titre", publicName: "titre", isSignal: true, isRequired: false, transformFunction: null }, fermable: { classPropertyName: "fermable", publicName: "fermable", isSignal: true, isRequired: false, transformFunction: null }, libelleFermeture: { classPropertyName: "libelleFermeture", publicName: "libelleFermeture", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { ferme: "ferme" }, host: { properties: { "attr.data-ton": "ton()", "attr.role": "roleLu()" }, classAttribute: "st-banner" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<div class=\"st-banner__corps\">\n @if (titre() !== null) {\n <p class=\"st-banner__titre\">{{ titre() }}</p>\n }\n <p class=\"st-banner__message\">{{ message() }}</p>\n <ng-content />\n</div>\n@if (fermable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleFermetureLu()\"\n (click)=\"fermer()\"\n ></button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-3) var(--st-espacement-4);margin-block-end:var(--st-espacement-4);border:1px solid transparent;border-radius:var(--st-rayon-md)}.st-banner__corps{flex:1 1 auto;min-inline-size:0}.st-banner__titre{margin:0 0 var(--st-espacement-1);font-weight:var(--st-graisse-semi)}.st-banner__message{margin:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-color:var(--st-couleur-bordure)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}@media(forced-colors:active){:host{border-color:CanvasText}}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }, { kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2043
+ }
2044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StBanner, decorators: [{
2045
+ type: Component,
2046
+ args: [{ selector: 'st-banner', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIcon, StIconButton], host: {
2047
+ class: 'st-banner',
2048
+ '[attr.data-ton]': 'ton()',
2049
+ '[attr.role]': 'roleLu()',
2050
+ }, template: "<st-icon [nom]=\"icone()\" taille=\"sm\" />\n<div class=\"st-banner__corps\">\n @if (titre() !== null) {\n <p class=\"st-banner__titre\">{{ titre() }}</p>\n }\n <p class=\"st-banner__message\">{{ message() }}</p>\n <ng-content />\n</div>\n@if (fermable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"croix\"\n taille=\"sm\"\n [etiquette]=\"libelleFermetureLu()\"\n (click)=\"fermer()\"\n ></button>\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-3);align-items:flex-start;padding:var(--st-espacement-3) var(--st-espacement-4);margin-block-end:var(--st-espacement-4);border:1px solid transparent;border-radius:var(--st-rayon-md)}.st-banner__corps{flex:1 1 auto;min-inline-size:0}.st-banner__titre{margin:0 0 var(--st-espacement-1);font-weight:var(--st-graisse-semi)}.st-banner__message{margin:0}:host([data-ton=neutre]){color:var(--st-couleur-texte);background:var(--st-couleur-surface-enfoncee);border-color:var(--st-couleur-bordure)}:host([data-ton=primaire]){color:var(--st-couleur-sur-primaire-discret);background:var(--st-couleur-primaire-discret)}:host([data-ton=succes]){color:var(--st-couleur-sur-succes-discret);background:var(--st-couleur-succes-discret)}:host([data-ton=avertissement]){color:var(--st-couleur-sur-avertissement-discret);background:var(--st-couleur-avertissement-discret)}:host([data-ton=danger]){color:var(--st-couleur-sur-danger-discret);background:var(--st-couleur-danger-discret)}@media(forced-colors:active){:host{border-color:CanvasText}}\n"] }]
2051
+ }], propDecorators: { ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], titre: [{ type: i0.Input, args: [{ isSignal: true, alias: "titre", required: false }] }], fermable: [{ type: i0.Input, args: [{ isSignal: true, alias: "fermable", required: false }] }], libelleFermeture: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelleFermeture", required: false }] }], ferme: [{ type: i0.Output, args: ["ferme"] }] } });
2052
+
2053
+ /** Une FORME par ton, jamais la couleur seule. */
2054
+ const ICONE = {
2055
+ neutre: 'cercle-info',
2056
+ primaire: 'cercle-info',
2057
+ succes: 'cercle-coche',
2058
+ avertissement: 'triangle-alerte',
2059
+ danger: 'cercle-croix',
1295
2060
  };
2061
+ /**
2062
+ * Message court attache a une zone precise : une aide sous un champ, une
2063
+ * consequence sous un choix, une contrainte au-dessus d'un bouton.
2064
+ *
2065
+ * Distinct de `st-banner`, qui parle de la PAGE et se ferme.
2066
+ *
2067
+ * ⚠️ **Aucun role, aucune region vivante**, et c'est la difference qui compte.
2068
+ * Un message en ligne est lu quand on atteint l'endroit auquel il se rattache ;
2069
+ * en faire une region vivante le ferait annoncer hors contexte, et une
2070
+ * vingtaine de champs produiraient vingt annonces a l'ouverture de l'ecran.
2071
+ *
2072
+ * ⚠️ Pour une erreur de SAISIE, ce composant ne suffit pas : le champ doit
2073
+ * porter `aria-describedby` vers l'identifiant du message, sans quoi le lien
2074
+ * entre les deux n'existe que visuellement. C'est `st-form-field` de la
2075
+ * vague 3 qui posera ce lien.
2076
+ */
2077
+ class StInlineMessage {
2078
+ ton = input('neutre', /* @ts-ignore */
2079
+ ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
2080
+ /** Cible d'un `aria-describedby` pose par le champ decrit. */
2081
+ identifiant = input(null, /* @ts-ignore */
2082
+ ...(ngDevMode ? [{ debugName: "identifiant" }] : /* istanbul ignore next */ []));
2083
+ icone = computed(() => ICONE[this.ton()], /* @ts-ignore */
2084
+ ...(ngDevMode ? [{ debugName: "icone" }] : /* istanbul ignore next */ []));
2085
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StInlineMessage, deps: [], target: i0.ɵɵFactoryTarget.Component });
2086
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StInlineMessage, isStandalone: true, selector: "st-inline-message", inputs: { ton: { classPropertyName: "ton", publicName: "ton", isSignal: true, isRequired: false, transformFunction: null }, identifiant: { classPropertyName: "identifiant", publicName: "identifiant", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-ton": "ton()", "attr.id": "identifiant()" }, classAttribute: "st-inline-message" }, ngImport: i0, template: "<st-icon [nom]=\"icone()\" taille=\"xs\" />\n<span class=\"st-inline-message__texte\"><ng-content /></span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-2);align-items:flex-start;font-size:var(--st-taille-sm);line-height:var(--st-interligne-normal)}:host([data-ton=neutre]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"], dependencies: [{ kind: "component", type: StIcon, selector: "st-icon", inputs: ["nom", "taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2087
+ }
2088
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StInlineMessage, decorators: [{
2089
+ type: Component,
2090
+ args: [{ selector: 'st-inline-message', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StIcon], host: {
2091
+ class: 'st-inline-message',
2092
+ '[attr.data-ton]': 'ton()',
2093
+ '[attr.id]': 'identifiant()',
2094
+ }, template: "<st-icon [nom]=\"icone()\" taille=\"xs\" />\n<span class=\"st-inline-message__texte\"><ng-content /></span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:flex;gap:var(--st-espacement-2);align-items:flex-start;font-size:var(--st-taille-sm);line-height:var(--st-interligne-normal)}:host([data-ton=neutre]){color:var(--st-couleur-texte-discret)}:host([data-ton=primaire]){color:var(--st-couleur-primaire)}:host([data-ton=succes]){color:var(--st-couleur-succes)}:host([data-ton=avertissement]){color:var(--st-couleur-avertissement)}:host([data-ton=danger]){color:var(--st-couleur-danger)}\n"] }]
2095
+ }], propDecorators: { ton: [{ type: i0.Input, args: [{ isSignal: true, alias: "ton", required: false }] }], identifiant: [{ type: i0.Input, args: [{ isSignal: true, alias: "identifiant", required: false }] }] } });
2096
+
2097
+ let compteur$1 = 0;
2098
+ /**
2099
+ * Choix du theme : systeme, clair, sombre.
2100
+ *
2101
+ * ⚠️ **Trois etats, donc PAS un interrupteur.** `role="switch"` et
2102
+ * `aria-pressed` sont binaires : poses sur un choix a trois valeurs, ils
2103
+ * annoncent « active » ou « desactive » sans jamais dire lequel des trois est
2104
+ * retenu. Un groupe de boutons radio dit exactement « Sombre, bouton radio,
2105
+ * coche, 3 sur 3 ».
2106
+ *
2107
+ * ⚠️ **Composant de PRESENTATION.** Il n'injecte pas `StTheme` : `ui` ne depend
2108
+ * pas de `@starterlib/core` (ADR 0003). La coquille le relie au noyau :
2109
+ *
2110
+ * ```html
2111
+ * <st-theme-toggle [choix]="theme.choix()" (choisi)="theme.choisir($event)" />
2112
+ * ```
2113
+ */
2114
+ class StThemeToggle {
2115
+ libelles = inject(ST_LIBELLES);
2116
+ choix = input.required(/* @ts-ignore */
2117
+ ...(ngDevMode ? [{ debugName: "choix" }] : /* istanbul ignore next */ []));
2118
+ /** Legende visible. Masquee par defaut, mais toujours lue : elle nomme le groupe. */
2119
+ legendeVisible = input(false, { ...(ngDevMode ? { debugName: "legendeVisible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2120
+ choisi = output();
2121
+ /** Unique par instance : deux bascules sur la meme page partageraient leur groupe radio. */
2122
+ nom = `st-theme-${(compteur$1 += 1).toString()}`;
2123
+ legende = computed(() => this.libelles().theme, /* @ts-ignore */
2124
+ ...(ngDevMode ? [{ debugName: "legende" }] : /* istanbul ignore next */ []));
2125
+ options = computed(() => {
2126
+ const libelles = this.libelles();
2127
+ const texte = {
2128
+ systeme: libelles.themeSysteme,
2129
+ clair: libelles.themeClair,
2130
+ sombre: libelles.themeSombre,
2131
+ };
2132
+ return CHOIX_DE_THEME.map((valeur) => ({ valeur, libelle: texte[valeur] }));
2133
+ }, /* @ts-ignore */
2134
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2135
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StThemeToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
2136
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StThemeToggle, isStandalone: true, selector: "st-theme-toggle", inputs: { choix: { classPropertyName: "choix", publicName: "choix", isSignal: true, isRequired: true, transformFunction: null }, legendeVisible: { classPropertyName: "legendeVisible", publicName: "legendeVisible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { choisi: "choisi" }, host: { classAttribute: "st-theme-toggle" }, ngImport: i0, template: "<fieldset class=\"st-theme-toggle__groupe\">\n <legend [class.st-vh]=\"!legendeVisible()\">{{ legende() }}</legend>\n @for (option of options(); track option.valeur) {\n <label>\n <input\n type=\"radio\"\n [name]=\"nom\"\n [value]=\"option.valeur\"\n [checked]=\"option.valeur === choix()\"\n (change)=\"choisi.emit(option.valeur)\"\n />\n <span>{{ option.libelle }}</span>\n </label>\n }\n</fieldset>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block}.st-theme-toggle__groupe{display:inline-flex;flex-wrap:wrap;gap:0;padding:0;margin:0;border:0}.st-theme-toggle__groupe legend{padding:0;margin-block-end:var(--st-espacement-2);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-semi)}.st-theme-toggle__groupe input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-theme-toggle__groupe label{display:inline-flex;align-items:center;min-block-size:var(--st-cible-tactile-min);padding:var(--st-espacement-1) var(--st-espacement-3);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte)}.st-theme-toggle__groupe label+label{margin-inline-start:-1px}.st-theme-toggle__groupe label:first-of-type{border-start-start-radius:var(--st-rayon-md);border-end-start-radius:var(--st-rayon-md)}.st-theme-toggle__groupe label:last-of-type{border-start-end-radius:var(--st-rayon-md);border-end-end-radius:var(--st-rayon-md)}.st-theme-toggle__groupe label:has(input:checked){position:relative;font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:var(--st-couleur-primaire)}.st-theme-toggle__groupe label:has(input:focus-visible){position:relative;z-index:1;outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}@media(forced-colors:active){.st-theme-toggle__groupe label:has(input:checked){forced-color-adjust:none;color:HighlightText;background:Highlight}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2137
+ }
2138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StThemeToggle, decorators: [{
2139
+ type: Component,
2140
+ args: [{ selector: 'st-theme-toggle', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-theme-toggle' }, template: "<fieldset class=\"st-theme-toggle__groupe\">\n <legend [class.st-vh]=\"!legendeVisible()\">{{ legende() }}</legend>\n @for (option of options(); track option.valeur) {\n <label>\n <input\n type=\"radio\"\n [name]=\"nom\"\n [value]=\"option.valeur\"\n [checked]=\"option.valeur === choix()\"\n (change)=\"choisi.emit(option.valeur)\"\n />\n <span>{{ option.libelle }}</span>\n </label>\n }\n</fieldset>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block}.st-theme-toggle__groupe{display:inline-flex;flex-wrap:wrap;gap:0;padding:0;margin:0;border:0}.st-theme-toggle__groupe legend{padding:0;margin-block-end:var(--st-espacement-2);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-semi)}.st-theme-toggle__groupe input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-theme-toggle__groupe label{display:inline-flex;align-items:center;min-block-size:var(--st-cible-tactile-min);padding:var(--st-espacement-1) var(--st-espacement-3);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte)}.st-theme-toggle__groupe label+label{margin-inline-start:-1px}.st-theme-toggle__groupe label:first-of-type{border-start-start-radius:var(--st-rayon-md);border-end-start-radius:var(--st-rayon-md)}.st-theme-toggle__groupe label:last-of-type{border-start-end-radius:var(--st-rayon-md);border-end-end-radius:var(--st-rayon-md)}.st-theme-toggle__groupe label:has(input:checked){position:relative;font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:var(--st-couleur-primaire)}.st-theme-toggle__groupe label:has(input:focus-visible){position:relative;z-index:1;outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}@media(forced-colors:active){.st-theme-toggle__groupe label:has(input:checked){forced-color-adjust:none;color:HighlightText;background:Highlight}}\n"] }]
2141
+ }], propDecorators: { choix: [{ type: i0.Input, args: [{ isSignal: true, alias: "choix", required: true }] }], legendeVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendeVisible", required: false }] }], choisi: [{ type: i0.Output, args: ["choisi"] }] } });
2142
+
2143
+ /**
2144
+ * Nom de chaque langue ECRIT DANS CETTE LANGUE, et jamais traduit.
2145
+ *
2146
+ * ⚠️ Une personne qui ne lit pas le francais ne cherche pas « Anglais » : elle
2147
+ * cherche « English ». Traduire le nom des langues dans la langue courante rend
2148
+ * le selecteur illisible precisement pour qui en a besoin.
2149
+ */
2150
+ const ENDONYMES = {
2151
+ fr: 'Français',
2152
+ en: 'English',
2153
+ };
2154
+ let compteur = 0;
2155
+ /**
2156
+ * Choix de la langue de l'interface.
2157
+ *
2158
+ * ⚠️ **Chaque option porte son propre `lang`.** Sans lui, un lecteur d'ecran
2159
+ * regle en francais lit « English » avec une voix francaise, et le mot devient
2160
+ * incomprehensible pour la personne anglophone qui cherchait justement a
2161
+ * l'entendre.
2162
+ *
2163
+ * ⚠️ **Composant de PRESENTATION.** Il n'injecte pas `StLangue` : `ui` ne depend
2164
+ * pas de `@starterlib/core` (ADR 0003). La coquille le relie au noyau :
2165
+ *
2166
+ * ```html
2167
+ * <st-lang-switch [courante]="langue.courante()" (choisie)="langue.changer($event)" />
2168
+ * ```
2169
+ */
2170
+ class StLangSwitch {
2171
+ libelles = inject(ST_LIBELLES);
2172
+ courante = input.required(/* @ts-ignore */
2173
+ ...(ngDevMode ? [{ debugName: "courante" }] : /* istanbul ignore next */ []));
2174
+ langues = input(LANGUES, /* @ts-ignore */
2175
+ ...(ngDevMode ? [{ debugName: "langues" }] : /* istanbul ignore next */ []));
2176
+ legendeVisible = input(false, { ...(ngDevMode ? { debugName: "legendeVisible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2177
+ choisie = output();
2178
+ nom = `st-langue-${(compteur += 1).toString()}`;
2179
+ legende = computed(() => this.libelles().langue, /* @ts-ignore */
2180
+ ...(ngDevMode ? [{ debugName: "legende" }] : /* istanbul ignore next */ []));
2181
+ options = computed(() => this.langues().map((code) => ({ code, endonyme: ENDONYMES[code] })), /* @ts-ignore */
2182
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2183
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLangSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
2184
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StLangSwitch, isStandalone: true, selector: "st-lang-switch", inputs: { courante: { classPropertyName: "courante", publicName: "courante", isSignal: true, isRequired: true, transformFunction: null }, langues: { classPropertyName: "langues", publicName: "langues", isSignal: true, isRequired: false, transformFunction: null }, legendeVisible: { classPropertyName: "legendeVisible", publicName: "legendeVisible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { choisie: "choisie" }, host: { classAttribute: "st-lang-switch" }, ngImport: i0, template: "<fieldset class=\"st-lang-switch__groupe\">\n <legend [class.st-vh]=\"!legendeVisible()\">{{ legende() }}</legend>\n @for (option of options(); track option.code) {\n <label>\n <input\n type=\"radio\"\n [name]=\"nom\"\n [value]=\"option.code\"\n [checked]=\"option.code === courante()\"\n (change)=\"choisie.emit(option.code)\"\n />\n <span [attr.lang]=\"option.code\">{{ option.endonyme }}</span>\n </label>\n }\n</fieldset>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block}.st-lang-switch__groupe{display:inline-flex;flex-wrap:wrap;gap:0;padding:0;margin:0;border:0}.st-lang-switch__groupe legend{padding:0;margin-block-end:var(--st-espacement-2);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-semi)}.st-lang-switch__groupe input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-lang-switch__groupe label{display:inline-flex;align-items:center;min-block-size:var(--st-cible-tactile-min);padding:var(--st-espacement-1) var(--st-espacement-3);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte)}.st-lang-switch__groupe label+label{margin-inline-start:-1px}.st-lang-switch__groupe label:first-of-type{border-start-start-radius:var(--st-rayon-md);border-end-start-radius:var(--st-rayon-md)}.st-lang-switch__groupe label:last-of-type{border-start-end-radius:var(--st-rayon-md);border-end-end-radius:var(--st-rayon-md)}.st-lang-switch__groupe label:has(input:checked){position:relative;font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:var(--st-couleur-primaire)}.st-lang-switch__groupe label:has(input:focus-visible){position:relative;z-index:1;outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}@media(forced-colors:active){.st-lang-switch__groupe label:has(input:checked){forced-color-adjust:none;color:HighlightText;background:Highlight}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2185
+ }
2186
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLangSwitch, decorators: [{
2187
+ type: Component,
2188
+ args: [{ selector: 'st-lang-switch', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-lang-switch' }, template: "<fieldset class=\"st-lang-switch__groupe\">\n <legend [class.st-vh]=\"!legendeVisible()\">{{ legende() }}</legend>\n @for (option of options(); track option.code) {\n <label>\n <input\n type=\"radio\"\n [name]=\"nom\"\n [value]=\"option.code\"\n [checked]=\"option.code === courante()\"\n (change)=\"choisie.emit(option.code)\"\n />\n <span [attr.lang]=\"option.code\">{{ option.endonyme }}</span>\n </label>\n }\n</fieldset>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block}.st-lang-switch__groupe{display:inline-flex;flex-wrap:wrap;gap:0;padding:0;margin:0;border:0}.st-lang-switch__groupe legend{padding:0;margin-block-end:var(--st-espacement-2);font-size:var(--st-taille-sm);font-weight:var(--st-graisse-semi)}.st-lang-switch__groupe input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.st-lang-switch__groupe label{display:inline-flex;align-items:center;min-block-size:var(--st-cible-tactile-min);padding:var(--st-espacement-1) var(--st-espacement-3);color:var(--st-couleur-texte);cursor:pointer;background:var(--st-couleur-surface);border:1px solid var(--st-couleur-bordure-forte)}.st-lang-switch__groupe label+label{margin-inline-start:-1px}.st-lang-switch__groupe label:first-of-type{border-start-start-radius:var(--st-rayon-md);border-end-start-radius:var(--st-rayon-md)}.st-lang-switch__groupe label:last-of-type{border-start-end-radius:var(--st-rayon-md);border-end-end-radius:var(--st-rayon-md)}.st-lang-switch__groupe label:has(input:checked){position:relative;font-weight:var(--st-graisse-semi);color:var(--st-couleur-sur-primaire);background:var(--st-couleur-primaire);border-color:var(--st-couleur-primaire)}.st-lang-switch__groupe label:has(input:focus-visible){position:relative;z-index:1;outline:2px solid var(--st-couleur-anneau-focus);outline-offset:2px}@media(forced-colors:active){.st-lang-switch__groupe label:has(input:checked){forced-color-adjust:none;color:HighlightText;background:Highlight}}\n"] }]
2189
+ }], propDecorators: { courante: [{ type: i0.Input, args: [{ isSignal: true, alias: "courante", required: true }] }], langues: [{ type: i0.Input, args: [{ isSignal: true, alias: "langues", required: false }] }], legendeVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendeVisible", required: false }] }], choisie: [{ type: i0.Output, args: ["choisie"] }] } });
2190
+
2191
+ /**
2192
+ * Bouton qui copie une valeur : reference de virement, adresse de depot, lien
2193
+ * de partage.
2194
+ *
2195
+ * ⚠️ **Un element, et non un attribut pose sur un `<button>`.** La confirmation
2196
+ * passe par une region vivante voisine du bouton ; posee DANS le bouton, elle
2197
+ * entrerait dans son nom accessible, qui deviendrait « Copier Copie ».
2198
+ *
2199
+ * ⚠️ **Le libelle du bouton ne change pas** apres la copie, pour la raison que
2200
+ * donne `st-code` : le lecteur d'ecran annoncerait un autre controle que celui
2201
+ * qu'il a sous le doigt.
2202
+ *
2203
+ * ⚠️ **Jamais de secret.** Ce qui entre dans le presse-papiers est conserve par
2204
+ * les gestionnaires d'historique et synchronise entre appareils : ni mot de
2205
+ * passe, ni jeton, ni code a usage unique.
2206
+ *
2207
+ * Sans presse-papiers — hors contexte securise — le bouton n'est pas rendu : un
2208
+ * controle qui ne peut rien faire ne doit pas s'offrir.
2209
+ */
2210
+ class StCopyButton {
2211
+ document = inject(DOCUMENT);
2212
+ libelles = inject(ST_LIBELLES);
2213
+ valeur = input.required(/* @ts-ignore */
2214
+ ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
2215
+ /**
2216
+ * `null` : le texte vient du dictionnaire de l'application.
2217
+ *
2218
+ * ⚠️ En icone seule, c'est le nom accessible du bouton : il doit dire CE qui
2219
+ * est copie quand la page en offre plusieurs — « Copier l'IBAN » et non
2220
+ * « Copier » repete cinq fois.
2221
+ */
2222
+ libelle = input(null, /* @ts-ignore */
2223
+ ...(ngDevMode ? [{ debugName: "libelle" }] : /* istanbul ignore next */ []));
2224
+ iconeSeule = input(false, { ...(ngDevMode ? { debugName: "iconeSeule" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2225
+ messageDeConfirmation = input(null, /* @ts-ignore */
2226
+ ...(ngDevMode ? [{ debugName: "messageDeConfirmation" }] : /* istanbul ignore next */ []));
2227
+ copie = output();
2228
+ annonce = new AnnonceLocale(inject(DestroyRef));
2229
+ disponible = pressePapiersDisponible(this.document);
2230
+ libelleLu = computed(() => this.libelle() ?? this.libelles().copier, /* @ts-ignore */
2231
+ ...(ngDevMode ? [{ debugName: "libelleLu" }] : /* istanbul ignore next */ []));
2232
+ async copier() {
2233
+ const issue = await copierDansLePressePapiers(this.document, this.valeur());
2234
+ if (issue === 'copie') {
2235
+ this.copie.emit(this.valeur());
2236
+ this.annonce.annoncer(this.messageDeConfirmation() ?? this.libelles().copieEffectuee);
2237
+ }
2238
+ else if (issue === 'refusee') {
2239
+ this.annonce.annoncer(this.libelles().copieImpossible);
2240
+ }
2241
+ }
2242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCopyButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StCopyButton, isStandalone: true, selector: "st-copy-button", inputs: { valeur: { classPropertyName: "valeur", publicName: "valeur", isSignal: true, isRequired: true, transformFunction: null }, libelle: { classPropertyName: "libelle", publicName: "libelle", isSignal: true, isRequired: false, transformFunction: null }, iconeSeule: { classPropertyName: "iconeSeule", publicName: "iconeSeule", isSignal: true, isRequired: false, transformFunction: null }, messageDeConfirmation: { classPropertyName: "messageDeConfirmation", publicName: "messageDeConfirmation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { copie: "copie" }, host: { classAttribute: "st-copy-button" }, ngImport: i0, template: "@if (disponible) {\n @if (iconeSeule()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleLu()\"\n (click)=\"copier()\"\n ></button>\n } @else {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n taille=\"sm\"\n iconeAvant=\"copie\"\n (click)=\"copier()\"\n >\n {{ libelleLu() }}\n </button>\n }\n}\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center}\n"], dependencies: [{ kind: "component", type: StButton, selector: "button[stButton]", inputs: ["variante", "taille", "pleineLargeur", "iconeAvant", "iconeApres", "chargement", "indisponible"] }, { kind: "component", type: StIconButton, selector: "button[stIconButton]", inputs: ["icone", "etiquette", "variante", "taille", "enfonce"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2244
+ }
2245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCopyButton, decorators: [{
2246
+ type: Component,
2247
+ args: [{ selector: 'st-copy-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StButton, StIconButton], host: { class: 'st-copy-button' }, template: "@if (disponible) {\n @if (iconeSeule()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content --\n Le contenu vient du gabarit de stIconButton. Le nom accessible est\n impose par le type (`etiquette` est requis) et verifie par axe. -->\n <button\n stIconButton\n type=\"button\"\n icone=\"copie\"\n taille=\"sm\"\n [etiquette]=\"libelleLu()\"\n (click)=\"copier()\"\n ></button>\n } @else {\n <button\n stButton\n type=\"button\"\n variante=\"secondaire\"\n taille=\"sm\"\n iconeAvant=\"copie\"\n (click)=\"copier()\"\n >\n {{ libelleLu() }}\n </button>\n }\n}\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center}\n"] }]
2248
+ }], propDecorators: { valeur: [{ type: i0.Input, args: [{ isSignal: true, alias: "valeur", required: true }] }], libelle: [{ type: i0.Input, args: [{ isSignal: true, alias: "libelle", required: false }] }], iconeSeule: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconeSeule", required: false }] }], messageDeConfirmation: [{ type: i0.Input, args: [{ isSignal: true, alias: "messageDeConfirmation", required: false }] }], copie: [{ type: i0.Output, args: ["copie"] }] } });
2249
+
2250
+ /**
2251
+ * Compte a rebours avant un nouvel essai, pour une reponse `429` et son en-tete
2252
+ * `Retry-After`.
2253
+ *
2254
+ * ```html
2255
+ * @if (erreur.reessayerDans !== null) {
2256
+ * <st-timer [secondes]="erreur.reessayerDans" (termine)="reessayable.set(true)" />
2257
+ * }
2258
+ * ```
2259
+ *
2260
+ * ⚠️ **Il n'annonce PAS chaque seconde.** Une region vivante qui change toutes les
2261
+ * secondes recouvre tout ce que le lecteur d'ecran essaie de dire, et empeche de
2262
+ * lire le formulaire que la personne est justement en train de garder pret. Le
2263
+ * decompte porte `role="timer"`, dont la valeur implicite est
2264
+ * `aria-live="off"` : il se LIT quand on l'atteint. Seule la fin s'annonce.
2265
+ *
2266
+ * ⚠️ **Le temps restant se calcule contre l'horloge, pas en comptant les
2267
+ * battements.** Un onglet en arriere-plan voit ses minuteries ralenties a une par
2268
+ * minute : un compteur decremente a chaque battement afficherait encore
2269
+ * « 45 s » a son retour, bien apres que le serveur a leve la limite.
2270
+ */
2271
+ class StTimer {
2272
+ libelles = inject(ST_LIBELLES);
2273
+ locale = inject(ST_LOCALE);
2274
+ /** Duree d'attente en secondes, telle que `Retry-After` la donne. */
2275
+ secondes = input.required(/* @ts-ignore */
2276
+ ...(ngDevMode ? [{ debugName: "secondes" }] : /* istanbul ignore next */ []));
2277
+ termine = output();
2278
+ annonce = new AnnonceLocale(inject(DestroyRef));
2279
+ restant = signal(0, /* @ts-ignore */
2280
+ ...(ngDevMode ? [{ debugName: "restant" }] : /* istanbul ignore next */ []));
2281
+ echeance = 0;
2282
+ minuterie = null;
2283
+ texte = computed(() => {
2284
+ const restant = this.restant();
2285
+ const libelles = this.libelles();
2286
+ return restant > 0
2287
+ ? libelles.reessayerDans(formaterDuree(restant, this.locale()))
2288
+ : libelles.reessayerMaintenant;
2289
+ }, /* @ts-ignore */
2290
+ ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
2291
+ constructor() {
2292
+ const destruction = inject(DestroyRef);
2293
+ destruction.onDestroy(() => {
2294
+ this.arreter();
2295
+ });
2296
+ // Une nouvelle duree relance le decompte : un second 429 repousse l'echeance.
2297
+ // Demarre apres le rendu, jamais au rendu serveur, ou une minuterie
2298
+ // empecherait la page de se stabiliser.
2299
+ let pret = false;
2300
+ afterNextRender(() => {
2301
+ pret = true;
2302
+ this.demarrer(this.secondes());
2303
+ });
2304
+ effect(() => {
2305
+ const secondes = this.secondes();
2306
+ if (pret)
2307
+ this.demarrer(secondes);
2308
+ });
2309
+ }
2310
+ demarrer(secondes) {
2311
+ this.arreter();
2312
+ this.echeance = Date.now() + Math.max(0, secondes) * 1000;
2313
+ this.battre();
2314
+ this.minuterie = setInterval(() => {
2315
+ this.battre();
2316
+ }, 1000);
2317
+ }
2318
+ battre() {
2319
+ const restant = Math.max(0, Math.ceil((this.echeance - Date.now()) / 1000));
2320
+ this.restant.set(restant);
2321
+ if (restant > 0)
2322
+ return;
2323
+ this.arreter();
2324
+ this.annonce.annoncer(this.libelles().reessayerMaintenant);
2325
+ this.termine.emit();
2326
+ }
2327
+ arreter() {
2328
+ if (this.minuterie !== null)
2329
+ clearInterval(this.minuterie);
2330
+ this.minuterie = null;
2331
+ }
2332
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StTimer, deps: [], target: i0.ɵɵFactoryTarget.Component });
2333
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: StTimer, isStandalone: true, selector: "st-timer", inputs: { secondes: { classPropertyName: "secondes", publicName: "secondes", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { termine: "termine" }, host: { classAttribute: "st-timer" }, ngImport: i0, template: "<span class=\"st-timer__decompte\" role=\"timer\">{{ texte() }}</span>\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block;color:var(--st-couleur-texte-discret);font-variant-numeric:tabular-nums}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2334
+ }
2335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StTimer, decorators: [{
2336
+ type: Component,
2337
+ args: [{ selector: 'st-timer', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'st-timer' }, template: "<span class=\"st-timer__decompte\" role=\"timer\">{{ texte() }}</span>\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce.texte() }}</span>\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-block;color:var(--st-couleur-texte-discret);font-variant-numeric:tabular-nums}\n"] }]
2338
+ }], ctorParameters: () => [], propDecorators: { secondes: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondes", required: true }] }], termine: [{ type: i0.Output, args: ["termine"] }] } });
2339
+
2340
+ /**
2341
+ * Logo de l'organisation, en variante claire, sombre et monochrome.
2342
+ *
2343
+ * ⚠️ **Le texte alternatif est le NOM de l'organisation, jamais « logo ».** Un
2344
+ * lecteur d'ecran annonce deja « image » : « Logo Banque Exemple » se lit
2345
+ * « image, logo Banque Exemple ». Pose dans un lien vers l'accueil, ce nom
2346
+ * devient celui du lien — il doit donc dire ou il mene.
2347
+ *
2348
+ * ⚠️ **Decoratif quand le nom est ecrit a cote.** Le repeter ferait lire
2349
+ * « Banque Exemple Banque Exemple ».
2350
+ *
2351
+ * La variante suit le theme EFFECTIF pose par `StTheme` sur `<html data-theme>`,
2352
+ * et non `prefers-color-scheme` : une personne qui a choisi le clair sur un
2353
+ * systeme sombre doit voir le logo clair. Sous contraste force, la variante
2354
+ * monochrome prend le relais — un logo en couleurs peut y disparaitre sur le
2355
+ * fond impose.
2356
+ *
2357
+ * Les images viennent de la meme origine : la politique de securite du contenu
2358
+ * n'autorise pas d'autre source d'image sans extension explicite cote BFF.
2359
+ */
2360
+ class StLogo {
2361
+ /** Nom de l'organisation : c'est le texte alternatif. */
2362
+ nom = input.required(/* @ts-ignore */
2363
+ ...(ngDevMode ? [{ debugName: "nom" }] : /* istanbul ignore next */ []));
2364
+ clair = input.required(/* @ts-ignore */
2365
+ ...(ngDevMode ? [{ debugName: "clair" }] : /* istanbul ignore next */ []));
2366
+ /** `null` : la variante claire sert aussi sur fond sombre. */
2367
+ sombre = input(null, /* @ts-ignore */
2368
+ ...(ngDevMode ? [{ debugName: "sombre" }] : /* istanbul ignore next */ []));
2369
+ /** `null` : aucune variante dediee au contraste force. */
2370
+ monochrome = input(null, /* @ts-ignore */
2371
+ ...(ngDevMode ? [{ debugName: "monochrome" }] : /* istanbul ignore next */ []));
2372
+ decoratif = input(false, { ...(ngDevMode ? { debugName: "decoratif" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2373
+ hauteur = input('2rem', /* @ts-ignore */
2374
+ ...(ngDevMode ? [{ debugName: "hauteur" }] : /* istanbul ignore next */ []));
2375
+ texteAlternatif = computed(() => (this.decoratif() ? '' : this.nom()), /* @ts-ignore */
2376
+ ...(ngDevMode ? [{ debugName: "texteAlternatif" }] : /* istanbul ignore next */ []));
2377
+ sourceSombre = computed(() => this.sombre() ?? this.clair(), /* @ts-ignore */
2378
+ ...(ngDevMode ? [{ debugName: "sourceSombre" }] : /* istanbul ignore next */ []));
2379
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLogo, deps: [], target: i0.ɵɵFactoryTarget.Component });
2380
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StLogo, isStandalone: true, selector: "st-logo", inputs: { nom: { classPropertyName: "nom", publicName: "nom", isSignal: true, isRequired: true, transformFunction: null }, clair: { classPropertyName: "clair", publicName: "clair", isSignal: true, isRequired: true, transformFunction: null }, sombre: { classPropertyName: "sombre", publicName: "sombre", isSignal: true, isRequired: false, transformFunction: null }, monochrome: { classPropertyName: "monochrome", publicName: "monochrome", isSignal: true, isRequired: false, transformFunction: null }, decoratif: { classPropertyName: "decoratif", publicName: "decoratif", isSignal: true, isRequired: false, transformFunction: null }, hauteur: { classPropertyName: "hauteur", publicName: "hauteur", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-monochrome": "monochrome() === null ? null : \"\"", "style.--st-logo-hauteur": "hauteur()" }, classAttribute: "st-logo" }, ngImport: i0, template: "<!-- `loading=\"lazy\"` : la variante masquee n'est pas telechargee, la visible\n l'est aussitot puisqu'elle est a l'ecran.\n\n `prefer-ngsrc` ecarte pour les trois images : NgOptimizedImage exige une\n largeur et une hauteur fixes, or un logo n'a qu'une hauteur \u2014 sa largeur\n suit ses proportions, propres a chaque organisation. Et un logo est presque\n toujours un SVG, pour lequel un jeu de resolutions ne rapporte rien. -->\n<!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n<img class=\"st-logo__clair\" loading=\"lazy\" [src]=\"clair()\" [alt]=\"texteAlternatif()\" />\n<!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n<img class=\"st-logo__sombre\" loading=\"lazy\" [src]=\"sourceSombre()\" [alt]=\"texteAlternatif()\" />\n@if (monochrome(); as source) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n <img class=\"st-logo__monochrome\" loading=\"lazy\" [src]=\"source\" [alt]=\"texteAlternatif()\" />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center}img{inline-size:auto;block-size:var(--st-logo-hauteur, 2rem);max-inline-size:100%}.st-logo__sombre,.st-logo__monochrome{display:none}:host-context([data-theme=sombre]) .st-logo__clair{display:none}:host-context([data-theme=sombre]) .st-logo__sombre{display:inline}@media(forced-colors:active){:host([data-monochrome]) .st-logo__clair,:host([data-monochrome]) .st-logo__sombre{display:none}:host([data-monochrome]) .st-logo__monochrome{display:inline}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2381
+ }
2382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLogo, decorators: [{
2383
+ type: Component,
2384
+ args: [{ selector: 'st-logo', changeDetection: ChangeDetectionStrategy.OnPush, host: {
2385
+ class: 'st-logo',
2386
+ '[attr.data-monochrome]': 'monochrome() === null ? null : ""',
2387
+ '[style.--st-logo-hauteur]': 'hauteur()',
2388
+ }, template: "<!-- `loading=\"lazy\"` : la variante masquee n'est pas telechargee, la visible\n l'est aussitot puisqu'elle est a l'ecran.\n\n `prefer-ngsrc` ecarte pour les trois images : NgOptimizedImage exige une\n largeur et une hauteur fixes, or un logo n'a qu'une hauteur \u2014 sa largeur\n suit ses proportions, propres a chaque organisation. Et un logo est presque\n toujours un SVG, pour lequel un jeu de resolutions ne rapporte rien. -->\n<!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n<img class=\"st-logo__clair\" loading=\"lazy\" [src]=\"clair()\" [alt]=\"texteAlternatif()\" />\n<!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n<img class=\"st-logo__sombre\" loading=\"lazy\" [src]=\"sourceSombre()\" [alt]=\"texteAlternatif()\" />\n@if (monochrome(); as source) {\n <!-- eslint-disable-next-line @angular-eslint/template/prefer-ngsrc -- voir ci-dessus -->\n <img class=\"st-logo__monochrome\" loading=\"lazy\" [src]=\"source\" [alt]=\"texteAlternatif()\" />\n}\n", styles: [".st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([hidden]){display:none!important}:host{display:inline-flex;align-items:center}img{inline-size:auto;block-size:var(--st-logo-hauteur, 2rem);max-inline-size:100%}.st-logo__sombre,.st-logo__monochrome{display:none}:host-context([data-theme=sombre]) .st-logo__clair{display:none}:host-context([data-theme=sombre]) .st-logo__sombre{display:inline}@media(forced-colors:active){:host([data-monochrome]) .st-logo__clair,:host([data-monochrome]) .st-logo__sombre{display:none}:host([data-monochrome]) .st-logo__monochrome{display:inline}}\n"] }]
2389
+ }], propDecorators: { nom: [{ type: i0.Input, args: [{ isSignal: true, alias: "nom", required: true }] }], clair: [{ type: i0.Input, args: [{ isSignal: true, alias: "clair", required: true }] }], sombre: [{ type: i0.Input, args: [{ isSignal: true, alias: "sombre", required: false }] }], monochrome: [{ type: i0.Input, args: [{ isSignal: true, alias: "monochrome", required: false }] }], decoratif: [{ type: i0.Input, args: [{ isSignal: true, alias: "decoratif", required: false }] }], hauteur: [{ type: i0.Input, args: [{ isSignal: true, alias: "hauteur", required: false }] }] } });
2390
+
2391
+ /**
2392
+ * Les gabarits des cinq etats, declares DANS `<st-state>`.
2393
+ *
2394
+ * ⚠️ Pourquoi des directives de contenu plutot que des entrees `TemplateRef` :
2395
+ * un `<ng-template>` declare a l'exterieur du composant appartient a
2396
+ * l'injecteur de l'endroit ou il est ECRIT, pas de celui qui le rend. Les
2397
+ * fournisseurs de `st-state` — dont `REGION_VIVANTE_PARENTE`, qui fait taire
2398
+ * les annonces en double — ne l'atteignaient donc pas, et l'erreur etait
2399
+ * annoncee deux fois. Passer par le contenu rend la declaration a l'exterieur
2400
+ * impossible : le defaut ne peut plus revenir.
2401
+ */
2402
+ class StSucces {
2403
+ gabarit = inject(TemplateRef);
2404
+ /**
2405
+ * La ressource n'est lue nulle part : elle porte le TYPE de la valeur, pour
2406
+ * que `let-valeur` soit type dans le gabarit au lieu d'etre `unknown`.
2407
+ */
2408
+ stSucces = input(undefined, /* @ts-ignore */
2409
+ ...(ngDevMode ? [{ debugName: "stSucces" }] : /* istanbul ignore next */ []));
2410
+ /**
2411
+ * `Exclude<T, undefined>` : une ressource sans valeur initiale se type
2412
+ * `T | undefined`, mais st-state ne rend ce gabarit QUE lorsqu'une valeur
2413
+ * existe. Sans cela, chaque gabarit de succes devrait ecrire `page?.length`
2414
+ * pour un cas qui ne se produit pas.
2415
+ */
2416
+ static ngTemplateContextGuard(_directive, _contexte) {
2417
+ return true;
2418
+ }
2419
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSucces, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2420
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: StSucces, isStandalone: true, selector: "ng-template[stSucces]", inputs: { stSucces: { classPropertyName: "stSucces", publicName: "stSucces", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
2421
+ }
2422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSucces, decorators: [{
2423
+ type: Directive,
2424
+ args: [{ selector: 'ng-template[stSucces]' }]
2425
+ }], propDecorators: { stSucces: [{ type: i0.Input, args: [{ isSignal: true, alias: "stSucces", required: false }] }] } });
2426
+ /** Erreur. Le contexte porte l'erreur elle-meme, pour l'afficher ou la traduire. */
2427
+ class StErreur {
2428
+ gabarit = inject(TemplateRef);
2429
+ static ngTemplateContextGuard(_directive, _contexte) {
2430
+ return true;
2431
+ }
2432
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StErreur, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2433
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StErreur, isStandalone: true, selector: "ng-template[stErreur]", ngImport: i0 });
2434
+ }
2435
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StErreur, decorators: [{
2436
+ type: Directive,
2437
+ args: [{ selector: 'ng-template[stErreur]' }]
2438
+ }] });
2439
+ class StVide {
2440
+ gabarit = inject(TemplateRef);
2441
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StVide, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2442
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StVide, isStandalone: true, selector: "ng-template[stVide]", ngImport: i0 });
2443
+ }
2444
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StVide, decorators: [{
2445
+ type: Directive,
2446
+ args: [{ selector: 'ng-template[stVide]' }]
2447
+ }] });
2448
+ class StHorsLigne {
2449
+ gabarit = inject(TemplateRef);
2450
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHorsLigne, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2451
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StHorsLigne, isStandalone: true, selector: "ng-template[stHorsLigne]", ngImport: i0 });
2452
+ }
2453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHorsLigne, decorators: [{
2454
+ type: Directive,
2455
+ args: [{ selector: 'ng-template[stHorsLigne]' }]
2456
+ }] });
2457
+ /** Chargement sur mesure. Sans lui, `st-state` rend sa silhouette par defaut. */
2458
+ class StChargement {
2459
+ gabarit = inject(TemplateRef);
2460
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StChargement, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2461
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StChargement, isStandalone: true, selector: "ng-template[stChargement]", ngImport: i0 });
2462
+ }
2463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StChargement, decorators: [{
2464
+ type: Directive,
2465
+ args: [{ selector: 'ng-template[stChargement]' }]
2466
+ }] });
2467
+ /** Toutes les directives de gabarit, a importer d'un coup. */
2468
+ const GABARITS_D_ETAT = [StSucces, StErreur, StVide, StHorsLigne, StChargement];
2469
+
2470
+ /**
2471
+ * Delai avant d'afficher un chargement. En dessous, l'attente ne se voit pas,
2472
+ * et faire clignoter une silhouette coute plus en confort qu'elle ne rapporte
2473
+ * en information.
2474
+ */
2475
+ const DELAI_AVANT_AFFICHAGE_MS = 200;
2476
+ /**
2477
+ * Duree minimale d'affichage une fois la silhouette montree. Sans elle, une
2478
+ * reponse arrivant a 210 ms produit un eclair : apparition, disparition.
2479
+ */
2480
+ const DUREE_MINIMALE_MS = 400;
2481
+ /** Vrai pour une collection vide, une valeur absente, ou une page sans element. */
2482
+ function estVideParDefaut(valeur) {
2483
+ if (valeur === null || valeur === undefined)
2484
+ return true;
2485
+ if (Array.isArray(valeur))
2486
+ return valeur.length === 0;
2487
+ // Les pages du socle backend portent leurs elements dans `content`.
2488
+ if (typeof valeur === 'object' && 'content' in valeur) {
2489
+ const { content: contenu } = valeur;
2490
+ return Array.isArray(contenu) && contenu.length === 0;
2491
+ }
2492
+ return false;
2493
+ }
1296
2494
  /**
1297
2495
  * Impose les cinq etats a un bloc qui consomme l'API, et centralise leur
1298
2496
  * annonce.
1299
2497
  *
2498
+ * Deux usages. Le plus courant passe la ressource, et l'etat s'en deduit :
2499
+ *
2500
+ * ```html
2501
+ * <st-state [ressource]="operations">
2502
+ * <ng-template [stSucces]="operations" let-page>…</ng-template>
2503
+ * <ng-template stErreur let-erreur><st-error … /></ng-template>
2504
+ * <ng-template stVide><st-empty … /></ng-template>
2505
+ * </st-state>
2506
+ * ```
2507
+ *
2508
+ * L'autre pose `[etat]` a la main, pour un bloc qui ne vient pas d'une
2509
+ * ressource — une soumission de formulaire, par exemple.
2510
+ *
2511
+ * ⚠️ Un RECHARGEMENT garde le contenu affiche. Revenir a la silhouette a chaque
2512
+ * changement de filtre fait clignoter la page entiere et perd la position de
2513
+ * lecture ; seul le premier chargement n'a rien a montrer.
2514
+ *
1300
2515
  * ⚠️ L'hote ne porte PAS `role="status"`, contrairement a ce qu'on attendrait :
1301
2516
  * un remplacement de contenu A L'INTERIEUR d'une region vivante fait relire
1302
2517
  * tout le sous-arbre par le lecteur d'ecran a chaque bascule d'etat. Seule une
1303
- * petite zone masquee porte l'annonce, qui tient en quelques mots. L'hote se
1304
- * contente d'`aria-busy`.
1305
- *
1306
- * Il fournit `REGION_VIVANTE_PARENTE` : les composants qu'il rend (indicateur
1307
- * de chargement, erreur) detectent sa presence et se taisent, au lieu
1308
- * d'annoncer une deuxieme fois le meme fait.
2518
+ * petite zone masquee porte l'annonce, qui tient en quelques mots.
1309
2519
  */
1310
2520
  class StState {
1311
- etat = input.required(/* @ts-ignore */
2521
+ libelles = inject(ST_LIBELLES);
2522
+ /** La ressource dont l'etat se deduit. */
2523
+ ressource = input(null, /* @ts-ignore */
2524
+ ...(ngDevMode ? [{ debugName: "ressource" }] : /* istanbul ignore next */ []));
2525
+ /** Etat pose a la main. Il prime sur la ressource quand les deux existent. */
2526
+ etat = input(null, /* @ts-ignore */
1312
2527
  ...(ngDevMode ? [{ debugName: "etat" }] : /* istanbul ignore next */ []));
1313
- /** Le chemin nominal. Obligatoire : un bloc sans succes n'a pas de raison d'etre. */
1314
- succes = input.required(/* @ts-ignore */
1315
- ...(ngDevMode ? [{ debugName: "succes" }] : /* istanbul ignore next */ []));
1316
- chargement = input(null, /* @ts-ignore */
1317
- ...(ngDevMode ? [{ debugName: "chargement" }] : /* istanbul ignore next */ []));
1318
- erreur = input(null, /* @ts-ignore */
1319
- ...(ngDevMode ? [{ debugName: "erreur" }] : /* istanbul ignore next */ []));
1320
- vide = input(null, /* @ts-ignore */
1321
- ...(ngDevMode ? [{ debugName: "vide" }] : /* istanbul ignore next */ []));
1322
- horsLigne = input(null, /* @ts-ignore */
1323
- ...(ngDevMode ? [{ debugName: "horsLigne" }] : /* istanbul ignore next */ []));
2528
+ /** Ce qui compte comme « vide » : par defaut, une collection sans element. */
2529
+ estVide = input(estVideParDefaut, /* @ts-ignore */
2530
+ ...(ngDevMode ? [{ debugName: "estVide" }] : /* istanbul ignore next */ []));
1324
2531
  /** Silhouette par defaut du chargement. `null` : un indicateur tournant. */
1325
2532
  squelette = input('texte', /* @ts-ignore */
1326
2533
  ...(ngDevMode ? [{ debugName: "squelette" }] : /* istanbul ignore next */ []));
1327
2534
  lignesDeSquelette = input(3, /* @ts-ignore */
1328
2535
  ...(ngDevMode ? [{ debugName: "lignesDeSquelette" }] : /* istanbul ignore next */ []));
1329
- annonces = input(ANNONCES_PAR_DEFAUT, /* @ts-ignore */
2536
+ /** `null` : les annonces viennent du dictionnaire de l'application. */
2537
+ annonces = input(null, /* @ts-ignore */
1330
2538
  ...(ngDevMode ? [{ debugName: "annonces" }] : /* istanbul ignore next */ []));
1331
- annonce = computed(() => this.annonces()[this.etat()], /* @ts-ignore */
2539
+ gabaritSucces = contentChild(StSucces, /* @ts-ignore */
2540
+ ...(ngDevMode ? [{ debugName: "gabaritSucces" }] : /* istanbul ignore next */ []));
2541
+ gabaritErreur = contentChild(StErreur, /* @ts-ignore */
2542
+ ...(ngDevMode ? [{ debugName: "gabaritErreur" }] : /* istanbul ignore next */ []));
2543
+ gabaritVide = contentChild(StVide, /* @ts-ignore */
2544
+ ...(ngDevMode ? [{ debugName: "gabaritVide" }] : /* istanbul ignore next */ []));
2545
+ gabaritHorsLigne = contentChild(StHorsLigne, /* @ts-ignore */
2546
+ ...(ngDevMode ? [{ debugName: "gabaritHorsLigne" }] : /* istanbul ignore next */ []));
2547
+ gabaritChargement = contentChild(StChargement, /* @ts-ignore */
2548
+ ...(ngDevMode ? [{ debugName: "gabaritChargement" }] : /* istanbul ignore next */ []));
2549
+ instantane = computed(() => {
2550
+ const ressource = this.ressource();
2551
+ if (ressource === null)
2552
+ return { statut: 'idle', valeur: undefined };
2553
+ return {
2554
+ statut: ressource.status(),
2555
+ valeur: ressource.hasValue() ? ressource.value() : undefined,
2556
+ };
2557
+ }, /* @ts-ignore */
2558
+ ...(ngDevMode ? [{ debugName: "instantane" }] : /* istanbul ignore next */ []));
2559
+ /**
2560
+ * La derniere valeur connue, gardee pendant qu'une autre se charge.
2561
+ *
2562
+ * ⚠️ Necessaire, et pas seulement confortable : un changement de PARAMETRE
2563
+ * n'est pas un `reload`. Angular traite le premier comme une nouvelle
2564
+ * requete — statut « loading », valeur videe. Sans cette memoire, changer un
2565
+ * filtre ou tourner une page ferait donc disparaitre le tableau, clignoter la
2566
+ * page, et perdre la position de lecture. Une erreur, elle, ne garde rien :
2567
+ * afficher des donnees perimees sous un message d'erreur serait mentir.
2568
+ */
2569
+ valeurRetenue = linkedSignal({ ...(ngDevMode ? { debugName: "valeurRetenue" } : /* istanbul ignore next */ {}), source: () => this.instantane(),
2570
+ computation: (source, precedent) => {
2571
+ if (source.valeur !== undefined)
2572
+ return source.valeur;
2573
+ const enCoursDeChargement = source.statut === 'loading' || source.statut === 'reloading';
2574
+ return enCoursDeChargement ? precedent?.value : undefined;
2575
+ } });
2576
+ /** Etat deduit de la ressource, valeur retenue comprise. */
2577
+ etatDeLaRessource = computed(() => {
2578
+ if (this.ressource() === null)
2579
+ return null;
2580
+ const { statut } = this.instantane();
2581
+ if (statut === 'error') {
2582
+ // Une requete qui n'a jamais atteint le serveur rend le statut 0 : c'est
2583
+ // une perte de reseau, pas une panne serveur. Lu par forme plutot que par
2584
+ // type, pour ne pas lier les composants au client HTTP.
2585
+ const erreur = this.ressource()?.error();
2586
+ return erreur?.status === 0 ? 'hors-ligne' : 'erreur';
2587
+ }
2588
+ const valeur = this.valeurRetenue();
2589
+ if (valeur === undefined)
2590
+ return statut === 'idle' || statut === 'loading' ? 'chargement' : 'vide';
2591
+ return this.estVide()(valeur) ? 'vide' : 'succes';
2592
+ }, /* @ts-ignore */
2593
+ ...(ngDevMode ? [{ debugName: "etatDeLaRessource" }] : /* istanbul ignore next */ []));
2594
+ etatEffectif = computed(() => this.etat() ?? this.etatDeLaRessource() ?? 'chargement', /* @ts-ignore */
2595
+ ...(ngDevMode ? [{ debugName: "etatEffectif" }] : /* istanbul ignore next */ []));
2596
+ /**
2597
+ * Une valeur est affichee, et une autre arrive — par rappel explicite ou par
2598
+ * changement de parametre.
2599
+ */
2600
+ enRechargement = computed(() => {
2601
+ const { statut } = this.instantane();
2602
+ if (statut !== 'loading' && statut !== 'reloading')
2603
+ return false;
2604
+ return this.valeurRetenue() !== undefined;
2605
+ }, /* @ts-ignore */
2606
+ ...(ngDevMode ? [{ debugName: "enRechargement" }] : /* istanbul ignore next */ []));
2607
+ enAttente = computed(() => this.etatEffectif() === 'chargement' || this.enRechargement(), /* @ts-ignore */
2608
+ ...(ngDevMode ? [{ debugName: "enAttente" }] : /* istanbul ignore next */ []));
2609
+ annoncesLues = computed(() => {
2610
+ const fournies = this.annonces();
2611
+ if (fournies !== null)
2612
+ return fournies;
2613
+ const libelles = this.libelles();
2614
+ return {
2615
+ chargement: libelles.chargementEnCours,
2616
+ erreur: libelles.erreurSurvenue,
2617
+ vide: libelles.aucunResultat,
2618
+ 'hors-ligne': libelles.horsConnexion,
2619
+ // Le succes ne s'annonce pas : c'est le contenu lui-meme qui parle.
2620
+ succes: '',
2621
+ };
2622
+ }, /* @ts-ignore */
2623
+ ...(ngDevMode ? [{ debugName: "annoncesLues" }] : /* istanbul ignore next */ []));
2624
+ annonce = computed(() => this.annoncesLues()[this.etatEffectif()], /* @ts-ignore */
1332
2625
  ...(ngDevMode ? [{ debugName: "annonce" }] : /* istanbul ignore next */ []));
2626
+ /** Contexte passe au gabarit : la valeur en succes, l'erreur en erreur. */
2627
+ contexte = computed(() => {
2628
+ const ressource = this.ressource();
2629
+ if (ressource === null)
2630
+ return { $implicit: undefined };
2631
+ if (this.etatEffectif() === 'erreur' || this.etatEffectif() === 'hors-ligne') {
2632
+ return { $implicit: ressource.error() };
2633
+ }
2634
+ return { $implicit: this.valeurRetenue() };
2635
+ }, /* @ts-ignore */
2636
+ ...(ngDevMode ? [{ debugName: "contexte" }] : /* istanbul ignore next */ []));
1333
2637
  /**
1334
2638
  * Les etats degrades n'ont pas de rendu par defaut : afficher un texte
1335
2639
  * generique a la place d'un vrai ecran vide ou d'une vraie erreur donnerait
@@ -1337,43 +2641,83 @@ class StState {
1337
2641
  * voie, en developpement.
1338
2642
  */
1339
2643
  gabaritDeLEtat = computed(() => {
1340
- switch (this.etat()) {
2644
+ switch (this.etatEffectif()) {
1341
2645
  case 'erreur':
1342
- return this.signalerSiAbsent(this.erreur(), 'erreur');
2646
+ return this.signalerSiAbsent(this.gabaritErreur()?.gabarit, 'erreur');
1343
2647
  case 'vide':
1344
- return this.signalerSiAbsent(this.vide(), 'vide');
2648
+ return this.signalerSiAbsent(this.gabaritVide()?.gabarit, 'vide');
1345
2649
  case 'hors-ligne':
1346
- return this.signalerSiAbsent(this.horsLigne() ?? this.erreur(), 'hors-ligne');
2650
+ return this.signalerSiAbsent(this.gabaritHorsLigne()?.gabarit ?? this.gabaritErreur()?.gabarit, 'hors-ligne');
1347
2651
  case 'chargement':
1348
- return this.chargement();
2652
+ return this.gabaritChargement()?.gabarit ?? null;
1349
2653
  default:
1350
- return this.succes();
2654
+ return this.signalerSiAbsent(this.gabaritSucces()?.gabarit, 'succes');
1351
2655
  }
1352
2656
  }, /* @ts-ignore */
1353
2657
  ...(ngDevMode ? [{ debugName: "gabaritDeLEtat" }] : /* istanbul ignore next */ []));
1354
- montreLaSilhouetteParDefaut = computed(() => this.etat() === 'chargement' && this.chargement() === null, /* @ts-ignore */
2658
+ chargementVisible = signal(false, /* @ts-ignore */
2659
+ ...(ngDevMode ? [{ debugName: "chargementVisible" }] : /* istanbul ignore next */ []));
2660
+ /** La silhouette par defaut, une fois le delai anti-clignotement passe. */
2661
+ montreLaSilhouetteParDefaut = computed(() => this.etatEffectif() === 'chargement' &&
2662
+ this.gabaritChargement() === undefined &&
2663
+ this.chargementVisible(), /* @ts-ignore */
1355
2664
  ...(ngDevMode ? [{ debugName: "montreLaSilhouetteParDefaut" }] : /* istanbul ignore next */ []));
2665
+ constructor() {
2666
+ let minuterie = null;
2667
+ let afficheDepuis = 0;
2668
+ const arreter = () => {
2669
+ if (minuterie !== null)
2670
+ clearTimeout(minuterie);
2671
+ minuterie = null;
2672
+ };
2673
+ effect(() => {
2674
+ const charge = this.etatEffectif() === 'chargement';
2675
+ arreter();
2676
+ if (charge) {
2677
+ if (this.chargementVisible())
2678
+ return;
2679
+ minuterie = setTimeout(() => {
2680
+ afficheDepuis = Date.now();
2681
+ this.chargementVisible.set(true);
2682
+ }, DELAI_AVANT_AFFICHAGE_MS);
2683
+ return;
2684
+ }
2685
+ if (!this.chargementVisible())
2686
+ return;
2687
+ // Deja affichee : elle reste le temps minimal, sinon elle clignote.
2688
+ const reste = DUREE_MINIMALE_MS - (Date.now() - afficheDepuis);
2689
+ if (reste <= 0) {
2690
+ this.chargementVisible.set(false);
2691
+ return;
2692
+ }
2693
+ minuterie = setTimeout(() => {
2694
+ this.chargementVisible.set(false);
2695
+ }, reste);
2696
+ });
2697
+ inject(DestroyRef).onDestroy(arreter);
2698
+ }
1356
2699
  signalerSiAbsent(gabarit, nom) {
1357
- if (gabarit === null && isDevMode()) {
2700
+ if (gabarit === undefined && isDevMode()) {
1358
2701
  // Volontairement un avertissement et non une exception : casser l'ecran
1359
2702
  // entier pour un etat degrade non traite aggraverait la panne en
1360
2703
  // production. En developpement, le message est impossible a manquer.
1361
2704
  console.warn(`[st-state] Etat « ${nom} » atteint sans gabarit. Les cinq etats doivent etre traites : ` +
1362
- 'fournir [erreur], [vide] et [horsLigne].');
2705
+ 'declarer <ng-template stErreur>, <ng-template stVide> et <ng-template stHorsLigne>.');
1363
2706
  }
1364
- return gabarit;
2707
+ return gabarit ?? null;
1365
2708
  }
1366
2709
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StState, deps: [], target: i0.ɵɵFactoryTarget.Component });
1367
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StState, isStandalone: true, selector: "st-state", inputs: { etat: { classPropertyName: "etat", publicName: "etat", isSignal: true, isRequired: true, transformFunction: null }, succes: { classPropertyName: "succes", publicName: "succes", isSignal: true, isRequired: true, transformFunction: null }, chargement: { classPropertyName: "chargement", publicName: "chargement", isSignal: true, isRequired: false, transformFunction: null }, erreur: { classPropertyName: "erreur", publicName: "erreur", isSignal: true, isRequired: false, transformFunction: null }, vide: { classPropertyName: "vide", publicName: "vide", isSignal: true, isRequired: false, transformFunction: null }, horsLigne: { classPropertyName: "horsLigne", publicName: "horsLigne", isSignal: true, isRequired: false, transformFunction: null }, squelette: { classPropertyName: "squelette", publicName: "squelette", isSignal: true, isRequired: false, transformFunction: null }, lignesDeSquelette: { classPropertyName: "lignesDeSquelette", publicName: "lignesDeSquelette", isSignal: true, isRequired: false, transformFunction: null }, annonces: { classPropertyName: "annonces", publicName: "annonces", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-etat": "etat()", "attr.aria-busy": "etat() === \"chargement\" ? \"true\" : null" }, classAttribute: "st-state" }, providers: [{ provide: REGION_VIVANTE_PARENTE, useValue: true }], ngImport: i0, template: "@if (montreLaSilhouetteParDefaut()) {\n @if (squelette(); as variante) {\n <st-skeleton [variante]=\"variante\" [lignes]=\"lignesDeSquelette()\" />\n } @else {\n <st-spinner />\n }\n} @else if (gabaritDeLEtat(); as gabarit) {\n <ng-container [ngTemplateOutlet]=\"gabarit\" />\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce() }}</span>\n", styles: [":host{display:block}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StSkeleton, selector: "st-skeleton", inputs: ["variante", "lignes", "colonnes", "anime"] }, { kind: "component", type: StSpinner, selector: "st-spinner", inputs: ["taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2710
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: StState, isStandalone: true, selector: "st-state", inputs: { ressource: { classPropertyName: "ressource", publicName: "ressource", isSignal: true, isRequired: false, transformFunction: null }, etat: { classPropertyName: "etat", publicName: "etat", isSignal: true, isRequired: false, transformFunction: null }, estVide: { classPropertyName: "estVide", publicName: "estVide", isSignal: true, isRequired: false, transformFunction: null }, squelette: { classPropertyName: "squelette", publicName: "squelette", isSignal: true, isRequired: false, transformFunction: null }, lignesDeSquelette: { classPropertyName: "lignesDeSquelette", publicName: "lignesDeSquelette", isSignal: true, isRequired: false, transformFunction: null }, annonces: { classPropertyName: "annonces", publicName: "annonces", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-etat": "etatEffectif()", "attr.data-rechargement": "enRechargement() ? \"\" : null", "attr.aria-busy": "enAttente() ? \"true\" : null" }, classAttribute: "st-state" }, providers: [{ provide: REGION_VIVANTE_PARENTE, useValue: true }], queries: [{ propertyName: "gabaritSucces", first: true, predicate: StSucces, descendants: true, isSignal: true }, { propertyName: "gabaritErreur", first: true, predicate: StErreur, descendants: true, isSignal: true }, { propertyName: "gabaritVide", first: true, predicate: StVide, descendants: true, isSignal: true }, { propertyName: "gabaritHorsLigne", first: true, predicate: StHorsLigne, descendants: true, isSignal: true }, { propertyName: "gabaritChargement", first: true, predicate: StChargement, descendants: true, isSignal: true }], ngImport: i0, template: "@if (montreLaSilhouetteParDefaut()) {\n @if (squelette(); as variante) {\n <st-skeleton [variante]=\"variante\" [lignes]=\"lignesDeSquelette()\" />\n } @else {\n <st-spinner />\n }\n} @else if (gabaritDeLEtat(); as gabarit) {\n <ng-container [ngTemplateOutlet]=\"gabarit\" [ngTemplateOutletContext]=\"contexte()\" />\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:block}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StSkeleton, selector: "st-skeleton", inputs: ["variante", "lignes", "colonnes", "anime"] }, { kind: "component", type: StSpinner, selector: "st-spinner", inputs: ["taille", "ton", "etiquette"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1368
2711
  }
1369
2712
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StState, decorators: [{
1370
2713
  type: Component,
1371
2714
  args: [{ selector: 'st-state', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, StSkeleton, StSpinner], providers: [{ provide: REGION_VIVANTE_PARENTE, useValue: true }], host: {
1372
2715
  class: 'st-state',
1373
- '[attr.data-etat]': 'etat()',
1374
- '[attr.aria-busy]': 'etat() === "chargement" ? "true" : null',
1375
- }, template: "@if (montreLaSilhouetteParDefaut()) {\n @if (squelette(); as variante) {\n <st-skeleton [variante]=\"variante\" [lignes]=\"lignesDeSquelette()\" />\n } @else {\n <st-spinner />\n }\n} @else if (gabaritDeLEtat(); as gabarit) {\n <ng-container [ngTemplateOutlet]=\"gabarit\" />\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce() }}</span>\n", styles: [":host{display:block}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
1376
- }], propDecorators: { etat: [{ type: i0.Input, args: [{ isSignal: true, alias: "etat", required: true }] }], succes: [{ type: i0.Input, args: [{ isSignal: true, alias: "succes", required: true }] }], chargement: [{ type: i0.Input, args: [{ isSignal: true, alias: "chargement", required: false }] }], erreur: [{ type: i0.Input, args: [{ isSignal: true, alias: "erreur", required: false }] }], vide: [{ type: i0.Input, args: [{ isSignal: true, alias: "vide", required: false }] }], horsLigne: [{ type: i0.Input, args: [{ isSignal: true, alias: "horsLigne", required: false }] }], squelette: [{ type: i0.Input, args: [{ isSignal: true, alias: "squelette", required: false }] }], lignesDeSquelette: [{ type: i0.Input, args: [{ isSignal: true, alias: "lignesDeSquelette", required: false }] }], annonces: [{ type: i0.Input, args: [{ isSignal: true, alias: "annonces", required: false }] }] } });
2716
+ '[attr.data-etat]': 'etatEffectif()',
2717
+ '[attr.data-rechargement]': 'enRechargement() ? "" : null',
2718
+ '[attr.aria-busy]': 'enAttente() ? "true" : null',
2719
+ }, template: "@if (montreLaSilhouetteParDefaut()) {\n @if (squelette(); as variante) {\n <st-skeleton [variante]=\"variante\" [lignes]=\"lignesDeSquelette()\" />\n } @else {\n <st-spinner />\n }\n} @else if (gabaritDeLEtat(); as gabarit) {\n <ng-container [ngTemplateOutlet]=\"gabarit\" [ngTemplateOutletContext]=\"contexte()\" />\n}\n\n<span class=\"st-vh\" aria-live=\"polite\">{{ annonce() }}</span>\n", styles: [":host([hidden]){display:none!important}:host{display:block}.st-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"] }]
2720
+ }], ctorParameters: () => [], propDecorators: { ressource: [{ type: i0.Input, args: [{ isSignal: true, alias: "ressource", required: false }] }], etat: [{ type: i0.Input, args: [{ isSignal: true, alias: "etat", required: false }] }], estVide: [{ type: i0.Input, args: [{ isSignal: true, alias: "estVide", required: false }] }], squelette: [{ type: i0.Input, args: [{ isSignal: true, alias: "squelette", required: false }] }], lignesDeSquelette: [{ type: i0.Input, args: [{ isSignal: true, alias: "lignesDeSquelette", required: false }] }], annonces: [{ type: i0.Input, args: [{ isSignal: true, alias: "annonces", required: false }] }], gabaritSucces: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StSucces), { isSignal: true }] }], gabaritErreur: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StErreur), { isSignal: true }] }], gabaritVide: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StVide), { isSignal: true }] }], gabaritHorsLigne: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StHorsLigne), { isSignal: true }] }], gabaritChargement: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StChargement), { isSignal: true }] }] } });
1377
2721
 
1378
2722
  /**
1379
2723
  * @starterlib/ui — bibliotheque de composants du socle frontal.
@@ -1387,5 +2731,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1387
2731
  * Generated bundle index. Do not edit.
1388
2732
  */
1389
2733
 
1390
- export { CHEMIN_DU_SPRITE, ETATS_DE_BLOC, FUSEAU_PAR_DEFAUT, NOMS_DICONE, REGION_VIVANTE_PARENTE, StAvatar, StBadge, StButton, StButtonGroup, StCode, StCount, StDate, StEmpty, StError, StHeading, StIcon, StIconButton, StLink, StMasked, StMoney, StOfflineBanner, StProgress, StRelativeTime, StSkeleton, StSpinner, StState, StStatusPill, StTag, StText, fournirCheminDuSprite };
2734
+ export { AnnonceLocale, CHEMIN_DU_SPRITE, FUSEAU_PAR_DEFAUT, GABARITS_D_ETAT, IDENTIFIANT_DU_CONTENU_PRINCIPAL, LIBELLES_EN, LIBELLES_FR, NOMS_DICONE, REGION_VIVANTE_PARENTE, ST_LIBELLES, ST_LOCALE, StAppShell, StAvatar, StBadge, StBanner, StBreadcrumb, StButton, StButtonGroup, StCard, StChargement, StCode, StCopyButton, StCount, StDate, StDivider, StEmpty, StErreur, StError, StHeader, StHeading, StHorsLigne, StIcon, StIconButton, StInlineMessage, StLangSwitch, StLink, StLogo, StMasked, StMoney, StOfflineBanner, StPageTitle, StProgress, StRelativeTime, StSection, StSkeleton, StSkipLink, StSpinner, StState, StStatusPill, StSucces, StTag, StText, StThemeToggle, StTimer, StVide, copierDansLePressePapiers, formaterDuree, fournirCheminDuSprite, pressePapiersDisponible, provideStarterUi };
1391
2735
  //# sourceMappingURL=starterlib-ui.mjs.map