@starterlib/ui 0.1.1 → 0.2.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,90 @@
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';
3
- import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
2
+ import { InjectionToken, inject, LOCALE_ID, signal, input, computed, ChangeDetectionStrategy, Component, booleanAttribute, ElementRef, DestroyRef, output, model, afterNextRender, TemplateRef, Directive, contentChild, linkedSignal, effect, isDevMode } from '@angular/core';
4
3
  import { masquerIban, masquerTelephone, masquerCarte, quatreDerniers, formaterIban, formaterMontant } from '@starterlib/util';
4
+ export { ETATS_DE_BLOC } from '@starterlib/util';
5
+ import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
6
+
7
+ /**
8
+ * Defaut francais, identique mot pour mot aux textes ecrits en dur jusqu'a la
9
+ * 0.1.1 : une application qui ne fournit rien ne change pas de comportement.
10
+ *
11
+ * Il existe pour que le socle reste utilisable sans i18n, pas pour dispenser
12
+ * d'en avoir une. Une application bilingue DOIT fournir son propre dictionnaire
13
+ * sous forme de signal — sinon la moitie de l'interface reste en francais quand
14
+ * l'utilisateur passe a l'anglais, et rien ne le signale.
15
+ */
16
+ const LIBELLES_FR = {
17
+ chargementEnCours: 'Chargement en cours',
18
+ erreurSurvenue: 'Une erreur est survenue',
19
+ aucunResultat: 'Aucun resultat',
20
+ horsConnexion: 'Hors connexion',
21
+ reessayer: 'Reessayer',
22
+ identifiantDeTrace: 'Identifiant de trace',
23
+ codeTechnique: 'Code',
24
+ copier: 'Copier',
25
+ copieEffectuee: 'Copie',
26
+ afficher: 'Afficher',
27
+ masquer: 'Masquer',
28
+ valeurMasqueeANouveau: 'Valeur masquee a nouveau',
29
+ natureIban: 'IBAN',
30
+ natureCarte: 'carte',
31
+ natureTelephone: 'numero',
32
+ seTerminantPar: (nature, quatreDerniers) => `${nature} se terminant par ${quatreDerniers}`,
33
+ nouvelleFenetre: '(nouvelle fenetre)',
34
+ retirer: 'Retirer',
35
+ aLInstant: "a l'instant",
36
+ };
37
+ /** Traduction anglaise du meme dictionnaire. La paire est obligatoire. */
38
+ const LIBELLES_EN = {
39
+ chargementEnCours: 'Loading',
40
+ erreurSurvenue: 'Something went wrong',
41
+ aucunResultat: 'No results',
42
+ horsConnexion: 'Offline',
43
+ reessayer: 'Try again',
44
+ identifiantDeTrace: 'Trace identifier',
45
+ codeTechnique: 'Code',
46
+ copier: 'Copy',
47
+ copieEffectuee: 'Copied',
48
+ afficher: 'Show',
49
+ masquer: 'Hide',
50
+ valeurMasqueeANouveau: 'Value hidden again',
51
+ natureIban: 'IBAN',
52
+ natureCarte: 'card',
53
+ natureTelephone: 'number',
54
+ seTerminantPar: (nature, quatreDerniers) => `${nature} ending in ${quatreDerniers}`,
55
+ nouvelleFenetre: '(opens in a new window)',
56
+ retirer: 'Remove',
57
+ aLInstant: 'just now',
58
+ };
5
59
 
60
+ /**
61
+ * Locale de formatage des montants, des dates et des nombres, **sous forme de
62
+ * signal**.
63
+ *
64
+ * ⚠️ Pourquoi pas `LOCALE_ID` : il est fige au demarrage de l'application. Or
65
+ * l'ADR 0014 du backend exige de changer de langue SANS recharger — la coquille
66
+ * detient la langue, et tout doit basculer d'un coup. Un composant qui lit
67
+ * `LOCALE_ID` continuerait d'afficher « 1 234,50 € » dans une interface passee
68
+ * a l'anglais.
69
+ *
70
+ * Le defaut lit `LOCALE_ID` : une application qui ne fournit rien garde le
71
+ * comportement d'avant, simplement sans pouvoir changer de langue a chaud.
72
+ */
73
+ const ST_LOCALE = new InjectionToken('st.locale', {
74
+ providedIn: 'root',
75
+ factory: () => {
76
+ const locale = inject(LOCALE_ID);
77
+ return signal(locale).asReadonly();
78
+ },
79
+ });
80
+ /**
81
+ * Textes portes par les composants eux-memes, sous forme de signal pour la
82
+ * meme raison que la locale.
83
+ */
84
+ const ST_LIBELLES = new InjectionToken('st.libelles', {
85
+ providedIn: 'root',
86
+ factory: () => signal(LIBELLES_FR).asReadonly(),
87
+ });
6
88
  /**
7
89
  * Chemin du sprite SVG des icones, **fourni par l'application**.
8
90
  *
@@ -38,6 +120,31 @@ const CHEMIN_DU_SPRITE = new InjectionToken('st.chemin-du-sprite', {
38
120
  function fournirCheminDuSprite(chemin) {
39
121
  return { provide: CHEMIN_DU_SPRITE, useValue: chemin };
40
122
  }
123
+ /**
124
+ * Configure `@starterlib/ui` pour toute l'application.
125
+ *
126
+ * ⚠️ A appeler dans l'HOTE uniquement. Dans un assemblage federe, un remote qui
127
+ * la rappellerait poserait un second jeu de valeurs dans son injecteur de
128
+ * route : deux locales, deux dictionnaires, et la moitie de l'ecran resterait
129
+ * dans l'ancienne langue apres une bascule.
130
+ */
131
+ function provideStarterUi(configuration) {
132
+ const fournisseurs = [fournirCheminDuSprite(configuration.cheminDuSprite)];
133
+ if (configuration.locale !== undefined) {
134
+ fournisseurs.push({ provide: ST_LOCALE, useValue: enSignal(configuration.locale) });
135
+ }
136
+ if (configuration.libelles !== undefined) {
137
+ fournisseurs.push({ provide: ST_LIBELLES, useValue: enSignal(configuration.libelles) });
138
+ }
139
+ if (configuration.fuseau !== undefined) {
140
+ fournisseurs.push({ provide: FUSEAU_PAR_DEFAUT, useValue: configuration.fuseau });
141
+ }
142
+ return fournisseurs;
143
+ }
144
+ /** Une valeur figee reste acceptee : toute application ne change pas de langue. */
145
+ function enSignal(valeur) {
146
+ return typeof valeur === 'function' ? valeur : signal(valeur).asReadonly();
147
+ }
41
148
  /**
42
149
  * Marque la presence d'une region vivante possedee par un ancetre, en pratique
43
150
  * le composant `st-state`.
@@ -59,13 +166,12 @@ const FUSEAU_PAR_DEFAUT = new InjectionToken('st.fuseau-par-defaut', {
59
166
  factory: () => 'Europe/Paris',
60
167
  });
61
168
 
62
- const ETATS_DE_BLOC = [
63
- 'chargement',
64
- 'erreur',
65
- 'vide',
66
- 'hors-ligne',
67
- 'succes',
68
- ];
169
+ /**
170
+ * Les cinq etats de bloc vivent dans `@starterlib/util` depuis la 0.2.0 : le
171
+ * noyau en a besoin pour deriver l'etat d'une ressource, et il ne doit pas
172
+ * dependre des composants. Reexportes ici pour que `@starterlib/ui` reste le
173
+ * seul import necessaire a qui n'ecrit que de l'interface.
174
+ */
69
175
 
70
176
  /**
71
177
  * Icone tiree d'un sprite SVG servi en meme origine.
@@ -85,7 +191,7 @@ class StIcon {
85
191
  ...(ngDevMode ? [{ debugName: "nom" }] : /* istanbul ignore next */ []));
86
192
  taille = input('md', /* @ts-ignore */
87
193
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
88
- ton = input('courant', /* @ts-ignore */
194
+ ton = input('neutre', /* @ts-ignore */
89
195
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
90
196
  /** `null` : l'icone est decorative et reste muette pour les lecteurs. */
91
197
  etiquette = input(null, /* @ts-ignore */
@@ -153,8 +259,7 @@ class StText {
153
259
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
154
260
  graisse = input('normale', /* @ts-ignore */
155
261
  ...(ngDevMode ? [{ debugName: "graisse" }] : /* istanbul ignore next */ []));
156
- enLigne = input(false, /* @ts-ignore */
157
- ...(ngDevMode ? [{ debugName: "enLigne" }] : /* istanbul ignore next */ []));
262
+ enLigne = input(false, { ...(ngDevMode ? { debugName: "enLigne" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
158
263
  /**
159
264
  * Nombre de lignes au-dela duquel le texte est coupe.
160
265
  *
@@ -237,16 +342,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
237
342
  */
238
343
  class StSpinner {
239
344
  regionParente = inject(REGION_VIVANTE_PARENTE, { optional: true });
345
+ libelles = inject(ST_LIBELLES);
240
346
  taille = input('md', /* @ts-ignore */
241
347
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
242
348
  ton = input('primaire', /* @ts-ignore */
243
349
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
244
- etiquette = input('Chargement en cours', /* @ts-ignore */
350
+ /** `null` : le texte vient du dictionnaire de l'application. */
351
+ etiquette = input(null, /* @ts-ignore */
245
352
  ...(ngDevMode ? [{ debugName: "etiquette" }] : /* istanbul ignore next */ []));
353
+ etiquetteLue = computed(() => this.etiquette() ?? this.libelles().chargementEnCours, /* @ts-ignore */
354
+ ...(ngDevMode ? [{ debugName: "etiquetteLue" }] : /* istanbul ignore next */ []));
246
355
  sAnnonce = computed(() => this.regionParente === null, /* @ts-ignore */
247
356
  ...(ngDevMode ? [{ debugName: "sAnnonce" }] : /* istanbul ignore next */ []));
248
357
  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 });
358
+ 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: [":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
359
  }
251
360
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSpinner, decorators: [{
252
361
  type: Component,
@@ -255,8 +364,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
255
364
  '[attr.data-taille]': 'taille()',
256
365
  '[attr.data-ton]': 'ton()',
257
366
  '[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"] }]
367
+ '[attr.aria-label]': 'sAnnonce() ? etiquetteLue() : null',
368
+ }, 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=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
369
  }], 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
370
 
262
371
  /**
@@ -332,8 +441,7 @@ class StSkeleton {
332
441
  ...(ngDevMode ? [{ debugName: "lignes" }] : /* istanbul ignore next */ []));
333
442
  colonnes = input(4, /* @ts-ignore */
334
443
  ...(ngDevMode ? [{ debugName: "colonnes" }] : /* istanbul ignore next */ []));
335
- anime = input(true, /* @ts-ignore */
336
- ...(ngDevMode ? [{ debugName: "anime" }] : /* istanbul ignore next */ []));
444
+ anime = input(true, { ...(ngDevMode ? { debugName: "anime" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
337
445
  indicesDeLigne = computed(() => Array.from({ length: Math.max(1, this.lignes()) }, (_, index) => index), /* @ts-ignore */
338
446
  ...(ngDevMode ? [{ debugName: "indicesDeLigne" }] : /* istanbul ignore next */ []));
339
447
  indicesDeColonne = computed(() => Array.from({ length: Math.max(1, this.colonnes()) }, (_, index) => index), /* @ts-ignore */
@@ -375,8 +483,7 @@ class StButton {
375
483
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
376
484
  taille = input('md', /* @ts-ignore */
377
485
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
378
- pleineLargeur = input(false, /* @ts-ignore */
379
- ...(ngDevMode ? [{ debugName: "pleineLargeur" }] : /* istanbul ignore next */ []));
486
+ pleineLargeur = input(false, { ...(ngDevMode ? { debugName: "pleineLargeur" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
380
487
  iconeAvant = input(null, /* @ts-ignore */
381
488
  ...(ngDevMode ? [{ debugName: "iconeAvant" }] : /* istanbul ignore next */ []));
382
489
  iconeApres = input(null, /* @ts-ignore */
@@ -386,14 +493,13 @@ class StButton {
386
493
  * mecanisme d'anti double soumission. L'appelant doit le lever DES la
387
494
  * soumission, pas a l'arrivee de la reponse.
388
495
  */
389
- chargement = input(false, /* @ts-ignore */
390
- ...(ngDevMode ? [{ debugName: "chargement" }] : /* istanbul ignore next */ []));
496
+ chargement = input(false, { ...(ngDevMode ? { debugName: "chargement" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
391
497
  /**
392
498
  * Le ton suit le FOND du bouton, et non le bouton en general : sur une
393
499
  * variante posee sur la surface (`secondaire`, qui est le defaut, et
394
500
  * `discret`), un indicateur en ton inverse tombait a 1,00:1 — invisible.
395
501
  */
396
- tonDuChargement = computed(() => this.variante() === 'primaire' || this.variante() === 'destructeur' ? 'inverse' : 'courant', /* @ts-ignore */
502
+ tonDuChargement = computed(() => this.variante() === 'primaire' || this.variante() === 'danger' ? 'inverse' : 'neutre', /* @ts-ignore */
397
503
  ...(ngDevMode ? [{ debugName: "tonDuChargement" }] : /* istanbul ignore next */ []));
398
504
  constructor() {
399
505
  const element = inject(ElementRef).nativeElement;
@@ -417,7 +523,7 @@ class StButton {
417
523
  });
418
524
  }
419
525
  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 });
526
+ 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=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
527
  }
422
528
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButton, decorators: [{
423
529
  type: Component,
@@ -428,7 +534,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
428
534
  '[attr.data-pleine-largeur]': 'pleineLargeur() ? "" : null',
429
535
  '[attr.aria-disabled]': 'chargement() ? "true" : null',
430
536
  '[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"] }]
537
+ }, 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=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"] }]
432
538
  }], 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 }] }] } });
433
539
 
434
540
  /**
@@ -448,11 +554,18 @@ class StIconButton {
448
554
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
449
555
  taille = input('md', /* @ts-ignore */
450
556
  ...(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 */
557
+ /**
558
+ * `null` : le bouton n'est pas a deux etats et n'annonce aucune pression.
559
+ *
560
+ * ⚠️ Une ENTREE, et non un `model`. Le composant ne bascule rien de lui-meme :
561
+ * l'etat enfonce reflete une donnee que l'appelant detient. En `model`,
562
+ * `[(enfonce)]` compilait et ne remontait jamais — une liaison bidirectionnelle
563
+ * muette est pire qu'absente, puisqu'elle se relit comme fonctionnelle.
564
+ */
565
+ enfonce = input(null, /* @ts-ignore */
453
566
  ...(ngDevMode ? [{ debugName: "enfonce" }] : /* istanbul ignore next */ []));
454
567
  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 });
568
+ 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{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
569
  }
457
570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StIconButton, decorators: [{
458
571
  type: Component,
@@ -462,8 +575,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
462
575
  '[attr.data-taille]': 'taille()',
463
576
  '[attr.aria-label]': 'etiquette()',
464
577
  '[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"] }] } });
578
+ }, 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=danger]){color:var(--st-couleur-danger)}:host([data-variante=danger]):hover:not(:disabled){background:var(--st-couleur-danger-discret)}\n"] }]
579
+ }], 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
580
 
468
581
  /**
469
582
  * Lien, pose en attribut sur un `<a>` natif.
@@ -476,16 +589,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
476
589
  * quiconque regarde l'ecran.
477
590
  */
478
591
  class StLink {
592
+ libelles = inject(ST_LIBELLES);
479
593
  variante = input('texte', /* @ts-ignore */
480
594
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
481
595
  /** 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 */
596
+ externe = input(false, { ...(ngDevMode ? { debugName: "externe" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
597
+ /**
598
+ * Mention lue par les lecteurs d'ecran quand le lien sort du site.
599
+ * `null` : le texte vient du dictionnaire de l'application.
600
+ */
601
+ mentionExterne = input(null, /* @ts-ignore */
486
602
  ...(ngDevMode ? [{ debugName: "mentionExterne" }] : /* istanbul ignore next */ []));
603
+ mentionExterneLue = computed(() => this.mentionExterne() ?? this.libelles().nouvelleFenetre, /* @ts-ignore */
604
+ ...(ngDevMode ? [{ debugName: "mentionExterneLue" }] : /* istanbul ignore next */ []));
487
605
  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 });
606
+ 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{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
607
  }
490
608
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StLink, decorators: [{
491
609
  type: Component,
@@ -494,7 +612,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
494
612
  '[attr.data-variante]': 'variante()',
495
613
  '[attr.target]': 'externe() ? "_blank" : null',
496
614
  '[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"] }]
615
+ }, 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{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
616
  }], 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
617
 
500
618
  /**
@@ -512,8 +630,7 @@ class StButtonGroup {
512
630
  orientation = input('horizontale', /* @ts-ignore */
513
631
  ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
514
632
  /** Boutons jointifs, rayons fusionnes. */
515
- attache = input(false, /* @ts-ignore */
516
- ...(ngDevMode ? [{ debugName: "attache" }] : /* istanbul ignore next */ []));
633
+ attache = input(false, { ...(ngDevMode ? { debugName: "attache" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
517
634
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StButtonGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
518
635
  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 });
519
636
  }
@@ -540,16 +657,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
540
657
  class StCode {
541
658
  document = inject(DOCUMENT);
542
659
  destruction = inject(DestroyRef);
660
+ libelles = inject(ST_LIBELLES);
543
661
  valeur = input.required(/* @ts-ignore */
544
662
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
545
- etiquette = input('Identifiant de trace', /* @ts-ignore */
663
+ copiable = input(true, { ...(ngDevMode ? { debugName: "copiable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
664
+ /** `null` : les textes viennent du dictionnaire de l'application. */
665
+ etiquette = input(null, /* @ts-ignore */
546
666
  ...(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 */
667
+ libelleCopier = input(null, /* @ts-ignore */
550
668
  ...(ngDevMode ? [{ debugName: "libelleCopier" }] : /* istanbul ignore next */ []));
551
- messageDeConfirmation = input('Copie', /* @ts-ignore */
669
+ messageDeConfirmation = input(null, /* @ts-ignore */
552
670
  ...(ngDevMode ? [{ debugName: "messageDeConfirmation" }] : /* istanbul ignore next */ []));
671
+ etiquetteLue = computed(() => this.etiquette() ?? this.libelles().identifiantDeTrace, /* @ts-ignore */
672
+ ...(ngDevMode ? [{ debugName: "etiquetteLue" }] : /* istanbul ignore next */ []));
673
+ libelleCopierLu = computed(() => this.libelleCopier() ?? this.libelles().copier, /* @ts-ignore */
674
+ ...(ngDevMode ? [{ debugName: "libelleCopierLu" }] : /* istanbul ignore next */ []));
553
675
  copie = output();
554
676
  confirmation = signal('', /* @ts-ignore */
555
677
  ...(ngDevMode ? [{ debugName: "confirmation" }] : /* istanbul ignore next */ []));
@@ -580,7 +702,7 @@ class StCode {
580
702
  return;
581
703
  }
582
704
  this.copie.emit(this.valeur());
583
- this.confirmation.set(this.messageDeConfirmation());
705
+ this.confirmation.set(this.messageDeConfirmation() ?? this.libelles().copieEffectuee);
584
706
  if (this.minuterie !== null)
585
707
  clearTimeout(this.minuterie);
586
708
  this.minuterie = setTimeout(() => {
@@ -593,18 +715,13 @@ class StCode {
593
715
  });
594
716
  }
595
717
  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 });
718
+ 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\">{{ 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
597
719
  }
598
720
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCode, decorators: [{
599
721
  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"] }] } });
722
+ 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\">{{ 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"] }]
723
+ }], 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
724
 
603
- const LIBELLE_DU_TYPE = {
604
- iban: 'IBAN',
605
- carte: 'carte',
606
- telephone: 'numero',
607
- };
608
725
  /**
609
726
  * Identifiant sensible, masque par defaut.
610
727
  *
@@ -617,6 +734,7 @@ const LIBELLE_DU_TYPE = {
617
734
  * journal.
618
735
  */
619
736
  class StMasked {
737
+ libelles = inject(ST_LIBELLES);
620
738
  destruction = inject(DestroyRef);
621
739
  valeur = input.required(/* @ts-ignore */
622
740
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
@@ -624,13 +742,13 @@ class StMasked {
624
742
  ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
625
743
  revele = model(false, /* @ts-ignore */
626
744
  ...(ngDevMode ? [{ debugName: "revele" }] : /* istanbul ignore next */ []));
627
- revelationAutorisee = input(false, /* @ts-ignore */
628
- ...(ngDevMode ? [{ debugName: "revelationAutorisee" }] : /* istanbul ignore next */ []));
745
+ revelationAutorisee = input(false, { ...(ngDevMode ? { debugName: "revelationAutorisee" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
629
746
  dureeDeRevelationEnSecondes = input(30, /* @ts-ignore */
630
747
  ...(ngDevMode ? [{ debugName: "dureeDeRevelationEnSecondes" }] : /* istanbul ignore next */ []));
631
- libelleAfficher = input('Afficher', /* @ts-ignore */
748
+ /** `null` : les textes viennent du dictionnaire de l'application. */
749
+ libelleAfficher = input(null, /* @ts-ignore */
632
750
  ...(ngDevMode ? [{ debugName: "libelleAfficher" }] : /* istanbul ignore next */ []));
633
- libelleMasquer = input('Masquer', /* @ts-ignore */
751
+ libelleMasquer = input(null, /* @ts-ignore */
634
752
  ...(ngDevMode ? [{ debugName: "libelleMasquer" }] : /* istanbul ignore next */ []));
635
753
  revelation = output();
636
754
  annonce = signal('', /* @ts-ignore */
@@ -651,14 +769,26 @@ class StMasked {
651
769
  ...(ngDevMode ? [{ debugName: "valeurMasquee" }] : /* istanbul ignore next */ []));
652
770
  valeurAffichee = computed(() => this.revele() ? this.valeurLisible() : this.valeurMasquee(), /* @ts-ignore */
653
771
  ...(ngDevMode ? [{ debugName: "valeurAffichee" }] : /* istanbul ignore next */ []));
772
+ /**
773
+ * La nature et la tournure viennent du dictionnaire : l'ordre des mots change
774
+ * d'une langue a l'autre, « IBAN se terminant par 2606 » contre « IBAN ending
775
+ * in 2606 ». Une chaine a trous ne suffirait pas.
776
+ */
654
777
  nomAccessible = computed(() => {
655
- const nature = LIBELLE_DU_TYPE[this.type()];
778
+ const libelles = this.libelles();
779
+ const nature = {
780
+ iban: libelles.natureIban,
781
+ carte: libelles.natureCarte,
782
+ telephone: libelles.natureTelephone,
783
+ }[this.type()];
656
784
  if (this.revele())
657
785
  return `${nature} ${this.valeurLisible()}`;
658
- return `${nature} se terminant par ${quatreDerniers(this.valeur())}`;
786
+ return libelles.seTerminantPar(nature, quatreDerniers(this.valeur()));
659
787
  }, /* @ts-ignore */
660
788
  ...(ngDevMode ? [{ debugName: "nomAccessible" }] : /* istanbul ignore next */ []));
661
- libelleDuBouton = computed(() => this.revele() ? this.libelleMasquer() : this.libelleAfficher(), /* @ts-ignore */
789
+ libelleDuBouton = computed(() => this.revele()
790
+ ? (this.libelleMasquer() ?? this.libelles().masquer)
791
+ : (this.libelleAfficher() ?? this.libelles().afficher), /* @ts-ignore */
662
792
  ...(ngDevMode ? [{ debugName: "libelleDuBouton" }] : /* istanbul ignore next */ []));
663
793
  valeurLisible() {
664
794
  return this.type() === 'iban' ? formaterIban(this.valeur()) : this.valeur();
@@ -691,14 +821,14 @@ class StMasked {
691
821
  if (!this.revele())
692
822
  return;
693
823
  this.revele.set(false);
694
- this.annonce.set('Valeur masquee a nouveau');
824
+ this.annonce.set(this.libelles().valeurMasqueeANouveau);
695
825
  }
696
826
  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 });
827
+ 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\">{{ 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
698
828
  }
699
829
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StMasked, decorators: [{
700
830
  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"] }]
831
+ 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\">{{ 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
832
  }], 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
833
 
704
834
  /**
@@ -713,13 +843,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
713
843
  * contraste ne doivent jamais transformer un debit en credit.
714
844
  */
715
845
  class StMoney {
716
- locale = inject(LOCALE_ID);
846
+ locale = inject(ST_LOCALE);
717
847
  valeur = input.required(/* @ts-ignore */
718
848
  ...(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 */ []));
849
+ signeExplicite = input(false, { ...(ngDevMode ? { debugName: "signeExplicite" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
850
+ sansDevise = input(false, { ...(ngDevMode ? { debugName: "sansDevise" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
723
851
  taille = input('md', /* @ts-ignore */
724
852
  ...(ngDevMode ? [{ debugName: "taille" }] : /* istanbul ignore next */ []));
725
853
  signe = computed(() => {
@@ -732,7 +860,7 @@ class StMoney {
732
860
  }, /* @ts-ignore */
733
861
  ...(ngDevMode ? [{ debugName: "signe" }] : /* istanbul ignore next */ []));
734
862
  texte = computed(() => formaterMontant(this.valeur(), {
735
- locale: this.locale,
863
+ locale: this.locale(),
736
864
  signeExplicite: this.signeExplicite(),
737
865
  sansDevise: this.sansDevise(),
738
866
  }), /* @ts-ignore */
@@ -773,7 +901,7 @@ const OPTIONS = {
773
901
  * ambigu a l'oral, et l'ordre jour-mois n'est pas universel.
774
902
  */
775
903
  class StDate {
776
- locale = inject(LOCALE_ID);
904
+ locale = inject(ST_LOCALE);
777
905
  fuseauParDefaut = inject(FUSEAU_PAR_DEFAUT);
778
906
  valeur = input.required(/* @ts-ignore */
779
907
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
@@ -781,6 +909,20 @@ class StDate {
781
909
  ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
782
910
  fuseau = input(null, /* @ts-ignore */
783
911
  ...(ngDevMode ? [{ debugName: "fuseau" }] : /* istanbul ignore next */ []));
912
+ /**
913
+ * Une DATE DE CALENDRIER (`2026-09-12`) n'est pas un instant : une date de
914
+ * naissance, une echeance ou un jour de valeur n'ont pas d'heure, et ne
915
+ * doivent pas changer de jour selon le fuseau de qui les regarde.
916
+ *
917
+ * ⚠️ Le piege est dans la norme : `new Date('2026-09-12')` vaut minuit UTC,
918
+ * donc le 11 septembre partout a l'ouest de Greenwich. Une echeance affichee
919
+ * la veille est un defaut que personne ne voit depuis l'Europe.
920
+ */
921
+ estDateDeCalendrier = computed(() => {
922
+ const valeur = this.valeur();
923
+ return typeof valeur === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(valeur);
924
+ }, /* @ts-ignore */
925
+ ...(ngDevMode ? [{ debugName: "estDateDeCalendrier" }] : /* istanbul ignore next */ []));
784
926
  date = computed(() => {
785
927
  const valeur = this.valeur();
786
928
  return valeur instanceof Date ? valeur : new Date(valeur);
@@ -788,14 +930,44 @@ class StDate {
788
930
  ...(ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []));
789
931
  estValide = computed(() => !Number.isNaN(this.date().getTime()), /* @ts-ignore */
790
932
  ...(ngDevMode ? [{ debugName: "estValide" }] : /* istanbul ignore next */ []));
791
- iso = computed(() => (this.estValide() ? this.date().toISOString() : null), /* @ts-ignore */
933
+ /**
934
+ * Le fuseau de rendu. Pour une date de calendrier, c'est UTC : la valeur a
935
+ * ete construite a minuit UTC, la relire en UTC rend donc le jour ecrit.
936
+ */
937
+ fuseauDeRendu = computed(() => this.estDateDeCalendrier() ? 'UTC' : (this.fuseau() ?? this.fuseauParDefaut), /* @ts-ignore */
938
+ ...(ngDevMode ? [{ debugName: "fuseauDeRendu" }] : /* istanbul ignore next */ []));
939
+ /**
940
+ * Une date de calendrier porte `2026-09-12`, sans heure ni decalage : c'est
941
+ * la forme que la norme HTML attend, et la seule qui ne mente pas.
942
+ */
943
+ iso = computed(() => {
944
+ if (!this.estValide())
945
+ return null;
946
+ if (this.estDateDeCalendrier())
947
+ return this.date().toISOString().slice(0, 10);
948
+ return this.date().toISOString();
949
+ }, /* @ts-ignore */
792
950
  ...(ngDevMode ? [{ debugName: "iso" }] : /* istanbul ignore next */ []));
951
+ /** Une date sans heure ne peut pas en afficher une. */
952
+ optionsDeFormat = computed(() => {
953
+ const options = OPTIONS[this.format()];
954
+ if (!this.estDateDeCalendrier())
955
+ return options;
956
+ // Le format « heure » n'a aucun sens ici : il ne resterait rien a afficher.
957
+ if (this.format() === 'heure')
958
+ return OPTIONS.court;
959
+ const sansHeure = { ...options };
960
+ delete sansHeure.hour;
961
+ delete sansHeure.minute;
962
+ return sansHeure;
963
+ }, /* @ts-ignore */
964
+ ...(ngDevMode ? [{ debugName: "optionsDeFormat" }] : /* istanbul ignore next */ []));
793
965
  texte = computed(() => {
794
966
  if (!this.estValide())
795
967
  return '';
796
- return new Intl.DateTimeFormat(this.locale, {
797
- ...OPTIONS[this.format()],
798
- timeZone: this.fuseau() ?? this.fuseauParDefaut,
968
+ return new Intl.DateTimeFormat(this.locale(), {
969
+ ...this.optionsDeFormat(),
970
+ timeZone: this.fuseauDeRendu(),
799
971
  }).format(this.date());
800
972
  }, /* @ts-ignore */
801
973
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
@@ -804,20 +976,20 @@ class StDate {
804
976
  if (!this.estValide())
805
977
  return '';
806
978
  if (this.format() === 'court') {
807
- return new Intl.DateTimeFormat(this.locale, {
979
+ return new Intl.DateTimeFormat(this.locale(), {
808
980
  ...OPTIONS.long,
809
- timeZone: this.fuseau() ?? this.fuseauParDefaut,
981
+ timeZone: this.fuseauDeRendu(),
810
982
  }).format(this.date());
811
983
  }
812
984
  return null;
813
985
  }, /* @ts-ignore */
814
986
  ...(ngDevMode ? [{ debugName: "texteAccessible" }] : /* istanbul ignore next */ []));
815
987
  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 });
988
+ 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{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
989
  }
818
990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StDate, decorators: [{
819
991
  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"] }]
992
+ 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{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
993
  }], 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
994
 
823
995
  const MINUTE = 60_000;
@@ -834,12 +1006,12 @@ const JOUR = 24 * HEURE;
834
1006
  * vieille de trois jours reveille l'onglet pour rien.
835
1007
  */
836
1008
  class StRelativeTime {
837
- locale = inject(LOCALE_ID);
1009
+ locale = inject(ST_LOCALE);
1010
+ libelles = inject(ST_LIBELLES);
838
1011
  fuseau = inject(FUSEAU_PAR_DEFAUT);
839
1012
  valeur = input.required(/* @ts-ignore */
840
1013
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
841
- rafraichir = input(true, /* @ts-ignore */
842
- ...(ngDevMode ? [{ debugName: "rafraichir" }] : /* istanbul ignore next */ []));
1014
+ rafraichir = input(true, { ...(ngDevMode ? { debugName: "rafraichir" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
843
1015
  /** Au-dela de ce nombre de jours, la date absolue est plus parlante. */
844
1016
  seuilAbsoluEnJours = input(7, /* @ts-ignore */
845
1017
  ...(ngDevMode ? [{ debugName: "seuilAbsoluEnJours" }] : /* istanbul ignore next */ []));
@@ -887,7 +1059,7 @@ class StRelativeTime {
887
1059
  return '';
888
1060
  const cible = this.dateEnMillisecondes();
889
1061
  if (this.depasseLeSeuil()) {
890
- return new Intl.DateTimeFormat(this.locale, {
1062
+ return new Intl.DateTimeFormat(this.locale(), {
891
1063
  day: 'numeric',
892
1064
  month: 'long',
893
1065
  year: 'numeric',
@@ -898,8 +1070,8 @@ class StRelativeTime {
898
1070
  const absolu = Math.abs(ecart);
899
1071
  // Sous dix secondes, « il y a 0 seconde » est plus deroutant qu'utile.
900
1072
  if (absolu < 10_000)
901
- return "a l'instant";
902
- const format = new Intl.RelativeTimeFormat(this.locale, { numeric: 'auto' });
1073
+ return this.libelles().aLInstant;
1074
+ const format = new Intl.RelativeTimeFormat(this.locale(), { numeric: 'auto' });
903
1075
  if (absolu < MINUTE)
904
1076
  return format.format(Math.round(ecart / 1000), 'second');
905
1077
  if (absolu < HEURE)
@@ -912,7 +1084,7 @@ class StRelativeTime {
912
1084
  texteAccessible = computed(() => {
913
1085
  if (!this.estValide())
914
1086
  return '';
915
- return new Intl.DateTimeFormat(this.locale, {
1087
+ return new Intl.DateTimeFormat(this.locale(), {
916
1088
  day: 'numeric',
917
1089
  month: 'long',
918
1090
  year: 'numeric',
@@ -923,11 +1095,11 @@ class StRelativeTime {
923
1095
  }, /* @ts-ignore */
924
1096
  ...(ngDevMode ? [{ debugName: "texteAccessible" }] : /* istanbul ignore next */ []));
925
1097
  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 });
1098
+ 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{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
1099
  }
928
1100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StRelativeTime, decorators: [{
929
1101
  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"] }]
1102
+ 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{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
1103
  }], 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
1104
 
933
1105
  /**
@@ -940,10 +1112,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
940
1112
  * d'information pour qui ecoute la page.
941
1113
  */
942
1114
  class StCount {
943
- locale = inject(LOCALE_ID);
1115
+ locale = inject(ST_LOCALE);
944
1116
  valeur = input.required(/* @ts-ignore */
945
1117
  ...(ngDevMode ? [{ debugName: "valeur" }] : /* istanbul ignore next */ []));
946
- ton = input('courant', /* @ts-ignore */
1118
+ ton = input('neutre', /* @ts-ignore */
947
1119
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
948
1120
  /** `null` : jamais d'abreviation. */
949
1121
  abregerAuDela = input(1000, /* @ts-ignore */
@@ -953,27 +1125,26 @@ class StCount {
953
1125
  return seuil !== null && Math.abs(this.valeur()) >= seuil;
954
1126
  }, /* @ts-ignore */
955
1127
  ...(ngDevMode ? [{ debugName: "estAbrege" }] : /* istanbul ignore next */ []));
956
- texteComplet = computed(() => new Intl.NumberFormat(this.locale).format(this.valeur()), /* @ts-ignore */
1128
+ texteComplet = computed(() => new Intl.NumberFormat(this.locale()).format(this.valeur()), /* @ts-ignore */
957
1129
  ...(ngDevMode ? [{ debugName: "texteComplet" }] : /* istanbul ignore next */ []));
958
1130
  texte = computed(() => {
959
1131
  if (!this.estAbrege())
960
1132
  return this.texteComplet();
961
- return new Intl.NumberFormat(this.locale, {
1133
+ return new Intl.NumberFormat(this.locale(), {
962
1134
  notation: 'compact',
963
1135
  maximumFractionDigits: 1,
964
1136
  }).format(this.valeur());
965
1137
  }, /* @ts-ignore */
966
1138
  ...(ngDevMode ? [{ debugName: "texte" }] : /* istanbul ignore next */ []));
967
1139
  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 });
1140
+ 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{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
1141
  }
970
1142
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StCount, decorators: [{
971
1143
  type: Component,
972
1144
  args: [{ selector: 'st-count', changeDetection: ChangeDetectionStrategy.OnPush, host: {
973
1145
  class: 'st-count',
974
1146
  '[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"] }]
1147
+ }, 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{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
1148
  }], 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
1149
 
979
1150
  /**
@@ -1000,7 +1171,7 @@ class StStatusPill {
1000
1171
  ton = input('neutre', /* @ts-ignore */
1001
1172
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1002
1173
  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 });
1174
+ 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=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
1175
  }
1005
1176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StStatusPill, decorators: [{
1006
1177
  type: Component,
@@ -1008,7 +1179,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1008
1179
  class: 'st-status-pill',
1009
1180
  '[attr.data-ton]': 'ton()',
1010
1181
  '[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"] }]
1182
+ }, 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=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
1183
  }], 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
1184
 
1014
1185
  /**
@@ -1028,8 +1199,7 @@ class StBadge {
1028
1199
  ton = input('danger', /* @ts-ignore */
1029
1200
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1030
1201
  /** Point seul, sans chiffre : signale une nouveaute sans la quantifier. */
1031
- point = input(false, /* @ts-ignore */
1032
- ...(ngDevMode ? [{ debugName: "point" }] : /* istanbul ignore next */ []));
1202
+ point = input(false, { ...(ngDevMode ? { debugName: "point" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1033
1203
  texte = computed(() => {
1034
1204
  if (this.point())
1035
1205
  return '';
@@ -1064,16 +1234,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1064
1234
  */
1065
1235
  class StTag {
1066
1236
  element = inject(ElementRef);
1237
+ libelles = inject(ST_LIBELLES);
1067
1238
  libelle = input.required(/* @ts-ignore */
1068
1239
  ...(ngDevMode ? [{ debugName: "libelle" }] : /* istanbul ignore next */ []));
1069
- supprimable = input(false, /* @ts-ignore */
1070
- ...(ngDevMode ? [{ debugName: "supprimable" }] : /* istanbul ignore next */ []));
1240
+ supprimable = input(false, { ...(ngDevMode ? { debugName: "supprimable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1071
1241
  ton = input('neutre', /* @ts-ignore */
1072
1242
  ...(ngDevMode ? [{ debugName: "ton" }] : /* istanbul ignore next */ []));
1073
- prefixeDeSuppression = input('Retirer', /* @ts-ignore */
1243
+ /** `null` : le texte vient du dictionnaire de l'application. */
1244
+ prefixeDeSuppression = input(null, /* @ts-ignore */
1074
1245
  ...(ngDevMode ? [{ debugName: "prefixeDeSuppression" }] : /* istanbul ignore next */ []));
1075
1246
  supprime = output();
1076
- libelleDeSuppression = computed(() => `${this.prefixeDeSuppression()} ${this.libelle()}`, /* @ts-ignore */
1247
+ libelleDeSuppression = computed(() => `${this.prefixeDeSuppression() ?? this.libelles().retirer} ${this.libelle()}`, /* @ts-ignore */
1077
1248
  ...(ngDevMode ? [{ debugName: "libelleDeSuppression" }] : /* istanbul ignore next */ []));
1078
1249
  auRetrait() {
1079
1250
  this.deplacerLeFocus();
@@ -1100,7 +1271,7 @@ class StTag {
1100
1271
  parent.focus();
1101
1272
  }
1102
1273
  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 });
1274
+ 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1104
1275
  }
1105
1276
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StTag, decorators: [{
1106
1277
  type: Component,
@@ -1142,8 +1313,7 @@ class StAvatar {
1142
1313
  * `true` quand le nom figure deja a cote de l'avatar, ce qui est le cas
1143
1314
  * courant : l'avatar devient alors decoratif et se tait.
1144
1315
  */
1145
- nomAdjacent = input(true, /* @ts-ignore */
1146
- ...(ngDevMode ? [{ debugName: "nomAdjacent" }] : /* istanbul ignore next */ []));
1316
+ nomAdjacent = input(true, { ...(ngDevMode ? { debugName: "nomAdjacent" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1147
1317
  imageEchouee = signal(false, /* @ts-ignore */
1148
1318
  ...(ngDevMode ? [{ debugName: "imageEchouee" }] : /* istanbul ignore next */ []));
1149
1319
  afficheLImage = computed(() => this.sourceImage() !== null && !this.imageEchouee(), /* @ts-ignore */
@@ -1217,6 +1387,7 @@ const ICONE = {
1217
1387
  */
1218
1388
  class StError {
1219
1389
  regionParente = inject(REGION_VIVANTE_PARENTE, { optional: true });
1390
+ libelles = inject(ST_LIBELLES);
1220
1391
  variante = input('serveur', /* @ts-ignore */
1221
1392
  ...(ngDevMode ? [{ debugName: "variante" }] : /* istanbul ignore next */ []));
1222
1393
  /** Code machine stable, tel que rendu par le backend. */
@@ -1230,21 +1401,26 @@ class StError {
1230
1401
  ...(ngDevMode ? [{ debugName: "traceId" }] : /* istanbul ignore next */ []));
1231
1402
  niveauDuTitre = input(3, /* @ts-ignore */
1232
1403
  ...(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 */
1404
+ rejouable = input(true, { ...(ngDevMode ? { debugName: "rejouable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1405
+ rejeuEnCours = input(false, { ...(ngDevMode ? { debugName: "rejeuEnCours" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1406
+ /** `null` : les textes viennent du dictionnaire de l'application. */
1407
+ libelleRejeu = input(null, /* @ts-ignore */
1236
1408
  ...(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 */
1409
+ etiquetteDeTrace = input(null, /* @ts-ignore */
1240
1410
  ...(ngDevMode ? [{ debugName: "etiquetteDeTrace" }] : /* istanbul ignore next */ []));
1241
1411
  rejeu = output();
1412
+ libelleRejeuLu = computed(() => this.libelleRejeu() ?? this.libelles().reessayer, /* @ts-ignore */
1413
+ ...(ngDevMode ? [{ debugName: "libelleRejeuLu" }] : /* istanbul ignore next */ []));
1414
+ etiquetteDeTraceLue = computed(() => this.etiquetteDeTrace() ?? this.libelles().identifiantDeTrace, /* @ts-ignore */
1415
+ ...(ngDevMode ? [{ debugName: "etiquetteDeTraceLue" }] : /* istanbul ignore next */ []));
1416
+ etiquetteDuCode = computed(() => this.libelles().codeTechnique, /* @ts-ignore */
1417
+ ...(ngDevMode ? [{ debugName: "etiquetteDuCode" }] : /* istanbul ignore next */ []));
1242
1418
  icone = computed(() => ICONE[this.variante()], /* @ts-ignore */
1243
1419
  ...(ngDevMode ? [{ debugName: "icone" }] : /* istanbul ignore next */ []));
1244
1420
  sAnnonce = computed(() => this.regionParente === null, /* @ts-ignore */
1245
1421
  ...(ngDevMode ? [{ debugName: "sAnnonce" }] : /* istanbul ignore next */ []));
1246
1422
  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 });
1423
+ 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: [":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", "copiable", "etiquette", "libelleCopier", "messageDeConfirmation"], outputs: ["copie"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1248
1424
  }
1249
1425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StError, decorators: [{
1250
1426
  type: Component,
@@ -1252,8 +1428,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1252
1428
  class: 'st-error',
1253
1429
  '[attr.data-variante]': 'variante()',
1254
1430
  '[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"] }] } });
1431
+ }, 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: [":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"] }]
1432
+ }], 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
1433
 
1258
1434
  /**
1259
1435
  * Banniere de perte de connexion.
@@ -1272,8 +1448,7 @@ class StOfflineBanner {
1272
1448
  ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
1273
1449
  libelleRejeu = input(null, /* @ts-ignore */
1274
1450
  ...(ngDevMode ? [{ debugName: "libelleRejeu" }] : /* istanbul ignore next */ []));
1275
- rejeuEnCours = input(false, /* @ts-ignore */
1276
- ...(ngDevMode ? [{ debugName: "rejeuEnCours" }] : /* istanbul ignore next */ []));
1451
+ rejeuEnCours = input(false, { ...(ngDevMode ? { debugName: "rejeuEnCours" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1277
1452
  rejeu = output();
1278
1453
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StOfflineBanner, deps: [], target: i0.ɵɵFactoryTarget.Component });
1279
1454
  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 });
@@ -1286,50 +1461,252 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1286
1461
  }, 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"] }]
1287
1462
  }], 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
1463
 
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: '',
1295
- };
1464
+ /**
1465
+ * Les gabarits des cinq etats, declares DANS `<st-state>`.
1466
+ *
1467
+ * ⚠️ Pourquoi des directives de contenu plutot que des entrees `TemplateRef` :
1468
+ * un `<ng-template>` declare a l'exterieur du composant appartient a
1469
+ * l'injecteur de l'endroit ou il est ECRIT, pas de celui qui le rend. Les
1470
+ * fournisseurs de `st-state` — dont `REGION_VIVANTE_PARENTE`, qui fait taire
1471
+ * les annonces en double — ne l'atteignaient donc pas, et l'erreur etait
1472
+ * annoncee deux fois. Passer par le contenu rend la declaration a l'exterieur
1473
+ * impossible : le defaut ne peut plus revenir.
1474
+ */
1475
+ class StSucces {
1476
+ gabarit = inject(TemplateRef);
1477
+ /**
1478
+ * La ressource n'est lue nulle part : elle porte le TYPE de la valeur, pour
1479
+ * que `let-valeur` soit type dans le gabarit au lieu d'etre `unknown`.
1480
+ */
1481
+ stSucces = input(undefined, /* @ts-ignore */
1482
+ ...(ngDevMode ? [{ debugName: "stSucces" }] : /* istanbul ignore next */ []));
1483
+ /**
1484
+ * `Exclude<T, undefined>` : une ressource sans valeur initiale se type
1485
+ * `T | undefined`, mais st-state ne rend ce gabarit QUE lorsqu'une valeur
1486
+ * existe. Sans cela, chaque gabarit de succes devrait ecrire `page?.length`
1487
+ * pour un cas qui ne se produit pas.
1488
+ */
1489
+ static ngTemplateContextGuard(_directive, _contexte) {
1490
+ return true;
1491
+ }
1492
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSucces, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1493
+ 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 });
1494
+ }
1495
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StSucces, decorators: [{
1496
+ type: Directive,
1497
+ args: [{ selector: 'ng-template[stSucces]' }]
1498
+ }], propDecorators: { stSucces: [{ type: i0.Input, args: [{ isSignal: true, alias: "stSucces", required: false }] }] } });
1499
+ /** Erreur. Le contexte porte l'erreur elle-meme, pour l'afficher ou la traduire. */
1500
+ class StErreur {
1501
+ gabarit = inject(TemplateRef);
1502
+ static ngTemplateContextGuard(_directive, _contexte) {
1503
+ return true;
1504
+ }
1505
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StErreur, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1506
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StErreur, isStandalone: true, selector: "ng-template[stErreur]", ngImport: i0 });
1507
+ }
1508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StErreur, decorators: [{
1509
+ type: Directive,
1510
+ args: [{ selector: 'ng-template[stErreur]' }]
1511
+ }] });
1512
+ class StVide {
1513
+ gabarit = inject(TemplateRef);
1514
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StVide, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1515
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StVide, isStandalone: true, selector: "ng-template[stVide]", ngImport: i0 });
1516
+ }
1517
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StVide, decorators: [{
1518
+ type: Directive,
1519
+ args: [{ selector: 'ng-template[stVide]' }]
1520
+ }] });
1521
+ class StHorsLigne {
1522
+ gabarit = inject(TemplateRef);
1523
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHorsLigne, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1524
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StHorsLigne, isStandalone: true, selector: "ng-template[stHorsLigne]", ngImport: i0 });
1525
+ }
1526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StHorsLigne, decorators: [{
1527
+ type: Directive,
1528
+ args: [{ selector: 'ng-template[stHorsLigne]' }]
1529
+ }] });
1530
+ /** Chargement sur mesure. Sans lui, `st-state` rend sa silhouette par defaut. */
1531
+ class StChargement {
1532
+ gabarit = inject(TemplateRef);
1533
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StChargement, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1534
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: StChargement, isStandalone: true, selector: "ng-template[stChargement]", ngImport: i0 });
1535
+ }
1536
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StChargement, decorators: [{
1537
+ type: Directive,
1538
+ args: [{ selector: 'ng-template[stChargement]' }]
1539
+ }] });
1540
+ /** Toutes les directives de gabarit, a importer d'un coup. */
1541
+ const GABARITS_D_ETAT = [StSucces, StErreur, StVide, StHorsLigne, StChargement];
1542
+
1543
+ /**
1544
+ * Delai avant d'afficher un chargement. En dessous, l'attente ne se voit pas,
1545
+ * et faire clignoter une silhouette coute plus en confort qu'elle ne rapporte
1546
+ * en information.
1547
+ */
1548
+ const DELAI_AVANT_AFFICHAGE_MS = 200;
1549
+ /**
1550
+ * Duree minimale d'affichage une fois la silhouette montree. Sans elle, une
1551
+ * reponse arrivant a 210 ms produit un eclair : apparition, disparition.
1552
+ */
1553
+ const DUREE_MINIMALE_MS = 400;
1554
+ /** Vrai pour une collection vide, une valeur absente, ou une page sans element. */
1555
+ function estVideParDefaut(valeur) {
1556
+ if (valeur === null || valeur === undefined)
1557
+ return true;
1558
+ if (Array.isArray(valeur))
1559
+ return valeur.length === 0;
1560
+ // Les pages du socle backend portent leurs elements dans `content`.
1561
+ if (typeof valeur === 'object' && 'content' in valeur) {
1562
+ const { content: contenu } = valeur;
1563
+ return Array.isArray(contenu) && contenu.length === 0;
1564
+ }
1565
+ return false;
1566
+ }
1296
1567
  /**
1297
1568
  * Impose les cinq etats a un bloc qui consomme l'API, et centralise leur
1298
1569
  * annonce.
1299
1570
  *
1571
+ * Deux usages. Le plus courant passe la ressource, et l'etat s'en deduit :
1572
+ *
1573
+ * ```html
1574
+ * <st-state [ressource]="operations">
1575
+ * <ng-template [stSucces]="operations" let-page>…</ng-template>
1576
+ * <ng-template stErreur let-erreur><st-error … /></ng-template>
1577
+ * <ng-template stVide><st-empty … /></ng-template>
1578
+ * </st-state>
1579
+ * ```
1580
+ *
1581
+ * L'autre pose `[etat]` a la main, pour un bloc qui ne vient pas d'une
1582
+ * ressource — une soumission de formulaire, par exemple.
1583
+ *
1584
+ * ⚠️ Un RECHARGEMENT garde le contenu affiche. Revenir a la silhouette a chaque
1585
+ * changement de filtre fait clignoter la page entiere et perd la position de
1586
+ * lecture ; seul le premier chargement n'a rien a montrer.
1587
+ *
1300
1588
  * ⚠️ L'hote ne porte PAS `role="status"`, contrairement a ce qu'on attendrait :
1301
1589
  * un remplacement de contenu A L'INTERIEUR d'une region vivante fait relire
1302
1590
  * 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.
1591
+ * petite zone masquee porte l'annonce, qui tient en quelques mots.
1309
1592
  */
1310
1593
  class StState {
1311
- etat = input.required(/* @ts-ignore */
1594
+ libelles = inject(ST_LIBELLES);
1595
+ /** La ressource dont l'etat se deduit. */
1596
+ ressource = input(null, /* @ts-ignore */
1597
+ ...(ngDevMode ? [{ debugName: "ressource" }] : /* istanbul ignore next */ []));
1598
+ /** Etat pose a la main. Il prime sur la ressource quand les deux existent. */
1599
+ etat = input(null, /* @ts-ignore */
1312
1600
  ...(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 */ []));
1601
+ /** Ce qui compte comme « vide » : par defaut, une collection sans element. */
1602
+ estVide = input(estVideParDefaut, /* @ts-ignore */
1603
+ ...(ngDevMode ? [{ debugName: "estVide" }] : /* istanbul ignore next */ []));
1324
1604
  /** Silhouette par defaut du chargement. `null` : un indicateur tournant. */
1325
1605
  squelette = input('texte', /* @ts-ignore */
1326
1606
  ...(ngDevMode ? [{ debugName: "squelette" }] : /* istanbul ignore next */ []));
1327
1607
  lignesDeSquelette = input(3, /* @ts-ignore */
1328
1608
  ...(ngDevMode ? [{ debugName: "lignesDeSquelette" }] : /* istanbul ignore next */ []));
1329
- annonces = input(ANNONCES_PAR_DEFAUT, /* @ts-ignore */
1609
+ /** `null` : les annonces viennent du dictionnaire de l'application. */
1610
+ annonces = input(null, /* @ts-ignore */
1330
1611
  ...(ngDevMode ? [{ debugName: "annonces" }] : /* istanbul ignore next */ []));
1331
- annonce = computed(() => this.annonces()[this.etat()], /* @ts-ignore */
1612
+ gabaritSucces = contentChild(StSucces, /* @ts-ignore */
1613
+ ...(ngDevMode ? [{ debugName: "gabaritSucces" }] : /* istanbul ignore next */ []));
1614
+ gabaritErreur = contentChild(StErreur, /* @ts-ignore */
1615
+ ...(ngDevMode ? [{ debugName: "gabaritErreur" }] : /* istanbul ignore next */ []));
1616
+ gabaritVide = contentChild(StVide, /* @ts-ignore */
1617
+ ...(ngDevMode ? [{ debugName: "gabaritVide" }] : /* istanbul ignore next */ []));
1618
+ gabaritHorsLigne = contentChild(StHorsLigne, /* @ts-ignore */
1619
+ ...(ngDevMode ? [{ debugName: "gabaritHorsLigne" }] : /* istanbul ignore next */ []));
1620
+ gabaritChargement = contentChild(StChargement, /* @ts-ignore */
1621
+ ...(ngDevMode ? [{ debugName: "gabaritChargement" }] : /* istanbul ignore next */ []));
1622
+ instantane = computed(() => {
1623
+ const ressource = this.ressource();
1624
+ if (ressource === null)
1625
+ return { statut: 'idle', valeur: undefined };
1626
+ return {
1627
+ statut: ressource.status(),
1628
+ valeur: ressource.hasValue() ? ressource.value() : undefined,
1629
+ };
1630
+ }, /* @ts-ignore */
1631
+ ...(ngDevMode ? [{ debugName: "instantane" }] : /* istanbul ignore next */ []));
1632
+ /**
1633
+ * La derniere valeur connue, gardee pendant qu'une autre se charge.
1634
+ *
1635
+ * ⚠️ Necessaire, et pas seulement confortable : un changement de PARAMETRE
1636
+ * n'est pas un `reload`. Angular traite le premier comme une nouvelle
1637
+ * requete — statut « loading », valeur videe. Sans cette memoire, changer un
1638
+ * filtre ou tourner une page ferait donc disparaitre le tableau, clignoter la
1639
+ * page, et perdre la position de lecture. Une erreur, elle, ne garde rien :
1640
+ * afficher des donnees perimees sous un message d'erreur serait mentir.
1641
+ */
1642
+ valeurRetenue = linkedSignal({ ...(ngDevMode ? { debugName: "valeurRetenue" } : /* istanbul ignore next */ {}), source: () => this.instantane(),
1643
+ computation: (source, precedent) => {
1644
+ if (source.valeur !== undefined)
1645
+ return source.valeur;
1646
+ const enCoursDeChargement = source.statut === 'loading' || source.statut === 'reloading';
1647
+ return enCoursDeChargement ? precedent?.value : undefined;
1648
+ } });
1649
+ /** Etat deduit de la ressource, valeur retenue comprise. */
1650
+ etatDeLaRessource = computed(() => {
1651
+ if (this.ressource() === null)
1652
+ return null;
1653
+ const { statut } = this.instantane();
1654
+ if (statut === 'error') {
1655
+ // Une requete qui n'a jamais atteint le serveur rend le statut 0 : c'est
1656
+ // une perte de reseau, pas une panne serveur. Lu par forme plutot que par
1657
+ // type, pour ne pas lier les composants au client HTTP.
1658
+ const erreur = this.ressource()?.error();
1659
+ return erreur?.status === 0 ? 'hors-ligne' : 'erreur';
1660
+ }
1661
+ const valeur = this.valeurRetenue();
1662
+ if (valeur === undefined)
1663
+ return statut === 'idle' || statut === 'loading' ? 'chargement' : 'vide';
1664
+ return this.estVide()(valeur) ? 'vide' : 'succes';
1665
+ }, /* @ts-ignore */
1666
+ ...(ngDevMode ? [{ debugName: "etatDeLaRessource" }] : /* istanbul ignore next */ []));
1667
+ etatEffectif = computed(() => this.etat() ?? this.etatDeLaRessource() ?? 'chargement', /* @ts-ignore */
1668
+ ...(ngDevMode ? [{ debugName: "etatEffectif" }] : /* istanbul ignore next */ []));
1669
+ /**
1670
+ * Une valeur est affichee, et une autre arrive — par rappel explicite ou par
1671
+ * changement de parametre.
1672
+ */
1673
+ enRechargement = computed(() => {
1674
+ const { statut } = this.instantane();
1675
+ if (statut !== 'loading' && statut !== 'reloading')
1676
+ return false;
1677
+ return this.valeurRetenue() !== undefined;
1678
+ }, /* @ts-ignore */
1679
+ ...(ngDevMode ? [{ debugName: "enRechargement" }] : /* istanbul ignore next */ []));
1680
+ enAttente = computed(() => this.etatEffectif() === 'chargement' || this.enRechargement(), /* @ts-ignore */
1681
+ ...(ngDevMode ? [{ debugName: "enAttente" }] : /* istanbul ignore next */ []));
1682
+ annoncesLues = computed(() => {
1683
+ const fournies = this.annonces();
1684
+ if (fournies !== null)
1685
+ return fournies;
1686
+ const libelles = this.libelles();
1687
+ return {
1688
+ chargement: libelles.chargementEnCours,
1689
+ erreur: libelles.erreurSurvenue,
1690
+ vide: libelles.aucunResultat,
1691
+ 'hors-ligne': libelles.horsConnexion,
1692
+ // Le succes ne s'annonce pas : c'est le contenu lui-meme qui parle.
1693
+ succes: '',
1694
+ };
1695
+ }, /* @ts-ignore */
1696
+ ...(ngDevMode ? [{ debugName: "annoncesLues" }] : /* istanbul ignore next */ []));
1697
+ annonce = computed(() => this.annoncesLues()[this.etatEffectif()], /* @ts-ignore */
1332
1698
  ...(ngDevMode ? [{ debugName: "annonce" }] : /* istanbul ignore next */ []));
1699
+ /** Contexte passe au gabarit : la valeur en succes, l'erreur en erreur. */
1700
+ contexte = computed(() => {
1701
+ const ressource = this.ressource();
1702
+ if (ressource === null)
1703
+ return { $implicit: undefined };
1704
+ if (this.etatEffectif() === 'erreur' || this.etatEffectif() === 'hors-ligne') {
1705
+ return { $implicit: ressource.error() };
1706
+ }
1707
+ return { $implicit: this.valeurRetenue() };
1708
+ }, /* @ts-ignore */
1709
+ ...(ngDevMode ? [{ debugName: "contexte" }] : /* istanbul ignore next */ []));
1333
1710
  /**
1334
1711
  * Les etats degrades n'ont pas de rendu par defaut : afficher un texte
1335
1712
  * generique a la place d'un vrai ecran vide ou d'une vraie erreur donnerait
@@ -1337,43 +1714,83 @@ class StState {
1337
1714
  * voie, en developpement.
1338
1715
  */
1339
1716
  gabaritDeLEtat = computed(() => {
1340
- switch (this.etat()) {
1717
+ switch (this.etatEffectif()) {
1341
1718
  case 'erreur':
1342
- return this.signalerSiAbsent(this.erreur(), 'erreur');
1719
+ return this.signalerSiAbsent(this.gabaritErreur()?.gabarit, 'erreur');
1343
1720
  case 'vide':
1344
- return this.signalerSiAbsent(this.vide(), 'vide');
1721
+ return this.signalerSiAbsent(this.gabaritVide()?.gabarit, 'vide');
1345
1722
  case 'hors-ligne':
1346
- return this.signalerSiAbsent(this.horsLigne() ?? this.erreur(), 'hors-ligne');
1723
+ return this.signalerSiAbsent(this.gabaritHorsLigne()?.gabarit ?? this.gabaritErreur()?.gabarit, 'hors-ligne');
1347
1724
  case 'chargement':
1348
- return this.chargement();
1725
+ return this.gabaritChargement()?.gabarit ?? null;
1349
1726
  default:
1350
- return this.succes();
1727
+ return this.signalerSiAbsent(this.gabaritSucces()?.gabarit, 'succes');
1351
1728
  }
1352
1729
  }, /* @ts-ignore */
1353
1730
  ...(ngDevMode ? [{ debugName: "gabaritDeLEtat" }] : /* istanbul ignore next */ []));
1354
- montreLaSilhouetteParDefaut = computed(() => this.etat() === 'chargement' && this.chargement() === null, /* @ts-ignore */
1731
+ chargementVisible = signal(false, /* @ts-ignore */
1732
+ ...(ngDevMode ? [{ debugName: "chargementVisible" }] : /* istanbul ignore next */ []));
1733
+ /** La silhouette par defaut, une fois le delai anti-clignotement passe. */
1734
+ montreLaSilhouetteParDefaut = computed(() => this.etatEffectif() === 'chargement' &&
1735
+ this.gabaritChargement() === undefined &&
1736
+ this.chargementVisible(), /* @ts-ignore */
1355
1737
  ...(ngDevMode ? [{ debugName: "montreLaSilhouetteParDefaut" }] : /* istanbul ignore next */ []));
1738
+ constructor() {
1739
+ let minuterie = null;
1740
+ let afficheDepuis = 0;
1741
+ const arreter = () => {
1742
+ if (minuterie !== null)
1743
+ clearTimeout(minuterie);
1744
+ minuterie = null;
1745
+ };
1746
+ effect(() => {
1747
+ const charge = this.etatEffectif() === 'chargement';
1748
+ arreter();
1749
+ if (charge) {
1750
+ if (this.chargementVisible())
1751
+ return;
1752
+ minuterie = setTimeout(() => {
1753
+ afficheDepuis = Date.now();
1754
+ this.chargementVisible.set(true);
1755
+ }, DELAI_AVANT_AFFICHAGE_MS);
1756
+ return;
1757
+ }
1758
+ if (!this.chargementVisible())
1759
+ return;
1760
+ // Deja affichee : elle reste le temps minimal, sinon elle clignote.
1761
+ const reste = DUREE_MINIMALE_MS - (Date.now() - afficheDepuis);
1762
+ if (reste <= 0) {
1763
+ this.chargementVisible.set(false);
1764
+ return;
1765
+ }
1766
+ minuterie = setTimeout(() => {
1767
+ this.chargementVisible.set(false);
1768
+ }, reste);
1769
+ });
1770
+ inject(DestroyRef).onDestroy(arreter);
1771
+ }
1356
1772
  signalerSiAbsent(gabarit, nom) {
1357
- if (gabarit === null && isDevMode()) {
1773
+ if (gabarit === undefined && isDevMode()) {
1358
1774
  // Volontairement un avertissement et non une exception : casser l'ecran
1359
1775
  // entier pour un etat degrade non traite aggraverait la panne en
1360
1776
  // production. En developpement, le message est impossible a manquer.
1361
1777
  console.warn(`[st-state] Etat « ${nom} » atteint sans gabarit. Les cinq etats doivent etre traites : ` +
1362
- 'fournir [erreur], [vide] et [horsLigne].');
1778
+ 'declarer <ng-template stErreur>, <ng-template stVide> et <ng-template stHorsLigne>.');
1363
1779
  }
1364
- return gabarit;
1780
+ return gabarit ?? null;
1365
1781
  }
1366
1782
  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 });
1783
+ 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{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
1784
  }
1369
1785
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: StState, decorators: [{
1370
1786
  type: Component,
1371
1787
  args: [{ selector: 'st-state', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, StSkeleton, StSpinner], providers: [{ provide: REGION_VIVANTE_PARENTE, useValue: true }], host: {
1372
1788
  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 }] }] } });
1789
+ '[attr.data-etat]': 'etatEffectif()',
1790
+ '[attr.data-rechargement]': 'enRechargement() ? "" : null',
1791
+ '[attr.aria-busy]': 'enAttente() ? "true" : null',
1792
+ }, 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{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"] }]
1793
+ }], 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
1794
 
1378
1795
  /**
1379
1796
  * @starterlib/ui — bibliotheque de composants du socle frontal.
@@ -1387,5 +1804,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1387
1804
  * Generated bundle index. Do not edit.
1388
1805
  */
1389
1806
 
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 };
1807
+ export { CHEMIN_DU_SPRITE, FUSEAU_PAR_DEFAUT, GABARITS_D_ETAT, LIBELLES_EN, LIBELLES_FR, NOMS_DICONE, REGION_VIVANTE_PARENTE, ST_LIBELLES, ST_LOCALE, StAvatar, StBadge, StButton, StButtonGroup, StChargement, StCode, StCount, StDate, StEmpty, StErreur, StError, StHeading, StHorsLigne, StIcon, StIconButton, StLink, StMasked, StMoney, StOfflineBanner, StProgress, StRelativeTime, StSkeleton, StSpinner, StState, StStatusPill, StSucces, StTag, StText, StVide, fournirCheminDuSprite, provideStarterUi };
1391
1808
  //# sourceMappingURL=starterlib-ui.mjs.map