@starterlib/ui 0.8.0 → 0.9.1

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.
Files changed (55) hide show
  1. package/LICENCES-TIERCES.md +236 -0
  2. package/README.md +101 -47
  3. package/assets/icones/catalogue.json +3296 -0
  4. package/assets/icones/sprite.svg +235 -35
  5. package/fesm2022/starterlib-ui-arbre.mjs +473 -80
  6. package/fesm2022/starterlib-ui-arbre.mjs.map +1 -1
  7. package/fesm2022/starterlib-ui-donnees.mjs +3551 -522
  8. package/fesm2022/starterlib-ui-donnees.mjs.map +1 -1
  9. package/fesm2022/starterlib-ui-formulaires.mjs +3186 -443
  10. package/fesm2022/starterlib-ui-formulaires.mjs.map +1 -1
  11. package/fesm2022/starterlib-ui-libelles-en.mjs +380 -139
  12. package/fesm2022/starterlib-ui-libelles-en.mjs.map +1 -1
  13. package/fesm2022/starterlib-ui-listes.mjs +5354 -658
  14. package/fesm2022/starterlib-ui-listes.mjs.map +1 -1
  15. package/fesm2022/starterlib-ui-messagerie.mjs +737 -0
  16. package/fesm2022/starterlib-ui-messagerie.mjs.map +1 -0
  17. package/fesm2022/starterlib-ui-navigation.mjs +506 -243
  18. package/fesm2022/starterlib-ui-navigation.mjs.map +1 -1
  19. package/fesm2022/starterlib-ui-onglets.mjs +369 -135
  20. package/fesm2022/starterlib-ui-onglets.mjs.map +1 -1
  21. package/fesm2022/starterlib-ui-parcours.mjs +2449 -0
  22. package/fesm2022/starterlib-ui-parcours.mjs.map +1 -0
  23. package/fesm2022/starterlib-ui-qr.mjs +907 -0
  24. package/fesm2022/starterlib-ui-qr.mjs.map +1 -0
  25. package/fesm2022/starterlib-ui-saisie.mjs +8566 -1589
  26. package/fesm2022/starterlib-ui-saisie.mjs.map +1 -1
  27. package/fesm2022/starterlib-ui-selection.mjs +1340 -268
  28. package/fesm2022/starterlib-ui-selection.mjs.map +1 -1
  29. package/fesm2022/starterlib-ui-sens.mjs +59 -0
  30. package/fesm2022/starterlib-ui-sens.mjs.map +1 -0
  31. package/fesm2022/starterlib-ui-surfaces.mjs +5140 -1387
  32. package/fesm2022/starterlib-ui-surfaces.mjs.map +1 -1
  33. package/fesm2022/starterlib-ui.mjs +10721 -2871
  34. package/fesm2022/starterlib-ui.mjs.map +1 -1
  35. package/package.json +27 -18
  36. package/styles/amorce.css +69 -0
  37. package/styles/couches.css +178 -0
  38. package/types/starterlib-ui-arbre.d.ts +199 -25
  39. package/types/starterlib-ui-donnees.d.ts +1441 -180
  40. package/types/starterlib-ui-formulaires.d.ts +1174 -139
  41. package/types/starterlib-ui-libelles-en.d.ts +3 -23
  42. package/types/starterlib-ui-listes.d.ts +2310 -255
  43. package/types/starterlib-ui-messagerie.d.ts +317 -0
  44. package/types/starterlib-ui-navigation.d.ts +201 -63
  45. package/types/starterlib-ui-onglets.d.ts +172 -43
  46. package/types/starterlib-ui-parcours.d.ts +916 -0
  47. package/types/starterlib-ui-qr.d.ts +105 -0
  48. package/types/starterlib-ui-saisie.d.ts +3431 -549
  49. package/types/starterlib-ui-selection.d.ts +441 -65
  50. package/types/starterlib-ui-sens.d.ts +44 -0
  51. package/types/starterlib-ui-surfaces.d.ts +1899 -510
  52. package/types/starterlib-ui.d.ts +4749 -1115
  53. package/fesm2022/starterlib-ui-interactions.mjs +0 -43
  54. package/fesm2022/starterlib-ui-interactions.mjs.map +0 -1
  55. package/types/starterlib-ui-interactions.d.ts +0 -4
@@ -1,9 +1,8 @@
1
- import { DateIso, PlageDeDates, DescriptionDeFichier } from '@starterlib/util';
2
- import { ValidationError, FormValueControl, FormCheckboxControl } from '@angular/forms/signals';
3
- import * as _starterlib_ui from '@starterlib/ui';
4
- import { LibellesUi, AnnonceLocale } from '@starterlib/ui';
5
- import * as _angular_core from '@angular/core';
6
-
1
+ import { Adresse, DateIso, DescriptionDeFichier, FormatDAdresse, HeureIso, NatureDeRegion, PartieDAdresse, PlageDeDates, sansCommandesDeDirection } from "@starterlib/util";
2
+ import { DisabledReason, FormCheckboxControl, FormValueControl, ValidationError, WithOptionalFieldTree } from "@angular/forms/signals";
3
+ import { AnnonceLocale, EtiquetteDeGroupe, Icone, LibellesUi } from "@starterlib/ui";
4
+ import * as i0 from "@angular/core";
5
+ import { InjectionToken, Signal } from "@angular/core";
7
6
  /**
8
7
  * Forme minimale d'une erreur de validation, telle que Signal Forms la rend :
9
8
  * un genre, et parfois un message.
@@ -12,9 +11,45 @@ import * as _angular_core from '@angular/core';
12
11
  * vague 3, V3-1). Les proprietes propres a chaque genre — `minLength`, `max`… —
13
12
  * se lisent par leur nom.
14
13
  */
15
- interface ErreurAffichable {
16
- readonly kind: string;
17
- readonly message?: string;
14
+ export interface ErreurAffichable {
15
+ readonly kind: string;
16
+ readonly message?: string;
17
+ }
18
+ /** Erreur de longueur : `minLength`, `maxLength`, et `longueur` (les deux bornes, du serveur). */
19
+ export interface ErreurDeLongueur extends ErreurAffichable {
20
+ readonly kind: 'minLength' | 'maxLength' | 'longueur';
21
+ readonly minLength?: number;
22
+ readonly maxLength?: number;
23
+ }
24
+ /**
25
+ * Erreur de borne : un nombre (`min`, `max`), une date ISO (`dateMin`, `dateMax`) ou une heure
26
+ * ISO (`heureMin`, `heureMax`) ; `DateIso` et `HeureIso` sont deux chaines.
27
+ */
28
+ export interface ErreurDeBorne extends ErreurAffichable {
29
+ readonly kind: 'min' | 'max' | 'dateMin' | 'dateMax' | 'heureMin' | 'heureMax';
30
+ readonly min?: number | DateIso;
31
+ readonly max?: number | DateIso;
32
+ /** Borne EXCLUSIVE du serveur (`@DecimalMin(inclusive = false)`) : dite strictement (lot 201). */
33
+ readonly strict?: boolean;
34
+ }
35
+ /** Erreur d'un fichier ou d'une liste de fichiers : lequel, et la limite franchie. */
36
+ export interface ErreurDeFichier extends ErreurAffichable {
37
+ readonly kind: 'fichierTaille' | 'fichierType' | 'fichiersNombre';
38
+ readonly fichier?: string;
39
+ /** En octets pour `fichierTaille`, en nombre de fichiers pour `fichiersNombre`. */
40
+ readonly max?: number;
41
+ }
42
+ /**
43
+ * Erreur d'une adresse, sur une PARTIE (cle `partie`, comme `st-date-range`) : `adresse` pour une
44
+ * partie exigee restee vide, `codePostal` pour un code qui n'a pas la forme du pays (avec un
45
+ * exemple reel), `pays` pour un pays hors de la liste admise.
46
+ */
47
+ export interface ErreurDAdresse extends ErreurAffichable {
48
+ readonly kind: 'adresse' | 'codePostal' | 'pays';
49
+ readonly partie: PartieDAdresse;
50
+ /** Ce que la region designe dans le pays : le message la nomme comme le champ. */
51
+ readonly nature?: NatureDeRegion;
52
+ readonly exemple?: string;
18
53
  }
19
54
  /**
20
55
  * Le texte d'une erreur, dans la langue courante.
@@ -27,17 +62,30 @@ interface ErreurAffichable {
27
62
  * Afficher `ibanChecksum` a une personne qui saisit un IBAN, c'est lui montrer le
28
63
  * code source.
29
64
  *
30
- * La locale sert aux messages qui citent un format, une date ou une taille : « au
31
- * format jj/mm/aaaa » n'est pas « mm/dd/yyyy ».
65
+ * La locale sert aux messages qui citent un format, une date, une taille ou un nombre : « au
66
+ * format jj/mm/aaaa » n'est pas « mm/dd/yyyy », et « 1 000,5 » n'est pas « 1,000.5 ». Les
67
+ * composants la lisent dans `ST_LOCALE`.
68
+ *
69
+ * ⚠️ **Un parametre malforme rend le message generique, il ne leve jamais** : l'appel vit dans
70
+ * un `computed` du champ, et une exception y viderait le champ, voire la page (constat A1132). Une
71
+ * date qui n'est pas ISO, une devise qui n'est pas un code de trois lettres : « valeur invalide ».
72
+ *
73
+ * `minLength` et `maxLength` sur une LISTE (les options cochees d'un `st-checkbox-group`, lot 248)
74
+ * comptent des options : « Choisissez au moins 1 option. », et non « Saisissez au moins
75
+ * 1 caracteres. ».
32
76
  */
33
- declare function messageDErreur(erreur: ErreurAffichable, libelles: LibellesUi, locale?: string): string;
77
+ export declare function messageDErreur(erreur: ErreurAffichable, libelles: LibellesUi, locale?: string): string;
78
+ /** Le libelle d'une partie d'adresse, tel que le champ l'affiche. */
79
+ export declare function libelleDePartie(libelles: LibellesUi, partie: string, nature?: string): string;
34
80
  /** Le motif a taper dans la langue courante : `jj/mm/aaaa`. */
35
- declare function motifLocal(libelles: LibellesUi, locale: string): string;
81
+ export declare function motifLocal(libelles: LibellesUi, locale: string): string;
82
+ /** Le motif d'une heure dans la langue courante : `hh:mm`, `hh:mm AM/PM`. */
83
+ export declare function motifDHeureLocal(libelles: LibellesUi, locale: string, secondes?: boolean): string;
36
84
  /**
37
85
  * Un jour superieur a 12 : « 31/03/2026 » montre sans ambiguite ou va le jour,
38
86
  * ce que « 01/02/2026 » ne dit pas.
39
87
  */
40
- declare function exempleDeDate(locale: string): string;
88
+ export declare function exempleDeDate(locale: string): string;
41
89
  /**
42
90
  * Erreur d'IBAN, a brancher sur un schema :
43
91
  *
@@ -53,23 +101,40 @@ declare function exempleDeDate(locale: string): string;
53
101
  * vide n'est pas « invalide » ici — c'est `required` qui le dit, avec le bon
54
102
  * message.
55
103
  */
56
- declare function erreurIban(valeur: string): ErreurAffichable | null;
104
+ export declare function erreurIban(valeur: string): ErreurAffichable | null;
57
105
  /**
58
- * Erreur de FORME d'un numero de telephone : chiffres, `+` de tete facultatif,
59
- * de 4 a 15 chiffres — la longueur maximale d'un numero international (E.164).
106
+ * Erreur de FORME d'un numero de telephone : chiffres et separateurs usuels (espace, point,
107
+ * tiret, parentheses), `+` de tete facultatif, de 4 a 15 chiffres — la longueur maximale d'un
108
+ * numero international (E.164).
60
109
  *
61
110
  * ```ts
62
111
  * validate(chemin.telephone, ({ value }) => erreurTelephone(value()));
63
112
  * ```
64
113
  *
114
+ * ⚠️ La forme se juge sur le texte RECU : « 06 12 AB » est refuse, meme si `normaliserTelephone`
115
+ * en tire « 0612 ». `st-phone-field` le signale aussi sur sa saisie, dont le modele ne garde que
116
+ * les chiffres et le `+` de tete.
117
+ *
65
118
  * ⚠️ Une forme valide ne dit pas que le numero existe : seul le serveur le sait.
66
119
  * Un champ vide n'est pas une erreur de forme : l'obligation est une autre regle.
67
120
  */
68
- declare function erreurTelephone(valeur: string): ErreurAffichable | null;
121
+ export declare function erreurTelephone(valeur: string): ErreurAffichable | null;
122
+ /**
123
+ * Erreur d'un code a usage unique : exactement `longueur` chiffres (6 par defaut), rien d'autre.
124
+ *
125
+ * ```ts
126
+ * validate(chemin.code, ({ value }) => erreurCode(value(), 6));
127
+ * ```
128
+ *
129
+ * ⚠️ Vide, le code n'est pas « incomplet » : l'obligation est une autre regle, avec son message.
130
+ * Le message dit la longueur attendue (« Saisissez les 6 chiffres du code. ») et non « invalide » :
131
+ * un code refuse par le serveur (« Code incorrect. ») arrive par `errors`, avec son propre texte.
132
+ */
133
+ export declare function erreurCode(valeur: string, longueur?: number): ErreurAffichable | null;
69
134
  /** Bornes d'une date, en ISO. Absente : pas de borne. */
70
- interface BornesDeDate {
71
- readonly min?: DateIso | null;
72
- readonly max?: DateIso | null;
135
+ export interface BornesDeDate {
136
+ readonly min?: DateIso | null;
137
+ readonly max?: DateIso | null;
73
138
  }
74
139
  /**
75
140
  * Erreur de bornes d'une date, a brancher sur un schema :
@@ -81,16 +146,59 @@ interface BornesDeDate {
81
146
  * Les bornes du schema et celles passees au calendrier doivent etre les memes :
82
147
  * le calendrier grise, le schema refuse une date tapee a la main.
83
148
  */
84
- declare function erreurDate(valeur: DateIso | null, bornes: BornesDeDate): ErreurAffichable | null;
149
+ export declare function erreurDate(valeur: DateIso | null, bornes: BornesDeDate): ErreurDeBorne | null;
150
+ /** Bornes d'une heure, `HH:MM` ou `HH:MM:SS`. Absente : pas de borne. */
151
+ export interface BornesDHeure {
152
+ readonly min?: HeureIso | null;
153
+ readonly max?: HeureIso | null;
154
+ }
155
+ /**
156
+ * Erreur de bornes d'une heure, a brancher sur un schema, comme `erreurDate` :
157
+ *
158
+ * ```ts
159
+ * validate(chemin.execution, ({ value }) => erreurHeure(value(), { min: '08:00', max: '18:00' }));
160
+ * ```
161
+ *
162
+ * Les bornes du schema et celles passees au champ (`heureMin`, `heureMax`, dites dans l'aide)
163
+ * doivent etre les memes. Une heure absente n'est pas hors bornes : c'est `required` qui le dit.
164
+ */
165
+ export declare function erreurHeure(valeur: HeureIso | null, bornes: BornesDHeure): ErreurDeBorne | null;
85
166
  /** Une fin anterieure au debut. Une borne manquante n'est pas une erreur de plage. */
86
- declare function erreurPlageDeDates(plage: PlageDeDates): ErreurAffichable | null;
167
+ export declare function erreurPlageDeDates(plage: PlageDeDates): ErreurAffichable | null;
168
+ /** Regles d'une adresse, les memes que les entrees de `st-address-fieldset`. */
169
+ export interface ReglesDAdresse {
170
+ /** Faux : une adresse vide est admise ; une adresse commencee doit quand meme etre complete. */
171
+ readonly requise?: boolean;
172
+ /** Les pays admis (codes ISO) ; absent : tous. */
173
+ readonly codesDesPays?: readonly string[];
174
+ }
175
+ /**
176
+ * Erreurs d'une adresse, une par partie a corriger, dans l'ordre du champ (le pays d'abord) :
177
+ *
178
+ * ```ts
179
+ * required(chemin.adresse); // la mention « obligatoire » et aria-required
180
+ * validate(chemin.adresse, ({ value }) => erreursDAdresse(value()));
181
+ * ```
182
+ *
183
+ * ⚠️ `required` seul ne suffit pas : une adresse est un objet, jamais « vide » pour Signal Forms.
184
+ * Ce sont ces erreurs qui bloquent l'envoi. Les parties exigees suivent le format du pays
185
+ * (`partiesExigees`) : la province au Canada, rien de tel en France.
186
+ *
187
+ * ⚠️ Confort de saisie (SEC-5) : le serveur revalide ; le motif d'un code postal n'est qu'une forme.
188
+ */
189
+ export declare function erreursDAdresse(adresse: Adresse, regles?: ReglesDAdresse): ErreurDAdresse[];
190
+ /**
191
+ * Un pays hors de la liste admise (`st-country-field` avec `codes`) : la valeur deja dans le
192
+ * modele reste affichee, et cette erreur dit pourquoi elle ne passe pas.
193
+ */
194
+ export declare function erreurPays(code: string, codesAdmis: readonly string[]): ErreurAffichable | null;
87
195
  /** Regles de `st-file-upload`, les memes que ses entrees. */
88
- interface ReglesDeFichiers {
89
- /** Attribut `accept` : `.pdf, image/*`. */
90
- readonly accept?: string;
91
- /** En octets. */
92
- readonly tailleMax?: number;
93
- readonly nombreMax?: number;
196
+ export interface ReglesDeFichiers {
197
+ /** Attribut `accept` : `.pdf, image/*`. */
198
+ readonly accept?: string;
199
+ /** En octets. */
200
+ readonly tailleMax?: number;
201
+ readonly nombreMax?: number;
94
202
  }
95
203
  /**
96
204
  * Erreurs d'une liste de fichiers, une par fichier refuse, pour dire LEQUEL :
@@ -102,7 +210,7 @@ interface ReglesDeFichiers {
102
210
  * ⚠️ Confort, jamais securite (SEC-5) : le type se deduit de l'extension, et le
103
211
  * serveur relit le contenu.
104
212
  */
105
- declare function erreursDeFichiers(fichiers: readonly DescriptionDeFichier[], regles: ReglesDeFichiers): ErreurAffichable[];
213
+ export declare function erreursDeFichiers(fichiers: readonly DescriptionDeFichier[], regles: ReglesDeFichiers): ErreurDeFichier[];
106
214
  /**
107
215
  * Erreurs a afficher par un champ qui LIT sa saisie (`transformedValue`) : celles
108
216
  * du formulaire, plus les erreurs de lecture qu'il ne connait pas encore.
@@ -112,54 +220,361 @@ declare function erreursDeFichiers(fichiers: readonly DescriptionDeFichier[], re
112
220
  * sans cette fusion, « 12,5,3 » s'afficherait sans le moindre message. Une erreur
113
221
  * deja presente — meme genre, meme partie — n'est pas repetee.
114
222
  */
115
- declare function fusionnerErreurs(formulaire: readonly ValidationError.WithOptionalFieldTree[], lecture: readonly ValidationError.WithoutFieldTree[]): readonly ErreurAffichable[];
116
-
223
+ export declare function fusionnerErreurs(formulaire: readonly ValidationError.WithOptionalFieldTree[], lecture: readonly ValidationError.WithoutFieldTree[]): readonly ErreurAffichable[];
117
224
  /** Elements natifs qui portent la saisie d'un champ du socle. */
118
- type ElementDeSaisie = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
225
+ export type ElementDeSaisie = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
119
226
  /**
120
227
  * Base des champs du socle : le contrat Signal Forms, ecrit une fois — tout sauf
121
- * `value`, dont le type depend du champ (texte, montant, date).
228
+ * `value` (ou `checked`), dont le type depend du champ (texte, montant, date, case).
122
229
  *
123
- * ⚠️ **Une base, et non une copie par champ.** Neuf membres de contrat recopies
124
- * dans six composants, c'est six occasions d'en oublier un — et l'oubli ne se
125
- * voit pas : un champ sans `touched` n'affiche jamais ses erreurs, un champ sans
126
- * reflet de `hidden` ne se masque pas, et rien n'echoue.
230
+ * ⚠️ **Une base, et non une copie par champ.** Seize membres de contrat recopies
231
+ * dans dix-sept composants, c'est dix-sept occasions d'en oublier un — et l'oubli ne se
232
+ * voit pas : [formField] ne pose que les entrees DECLAREES, sans erreur pour les autres. Un
233
+ * champ sans `touched` n'affiche jamais ses erreurs, un champ sans `readonly` reste modifiable
234
+ * sous une regle `readonly()` du schema, un champ sans reflet de `hidden` ne se masque pas.
235
+ *
236
+ * Les bornes de VALEUR (`min`, `max`) sont a part, dans `ContratDeChampABornes` : Signal Forms
237
+ * les type par la valeur du champ, et une borne mal typee casse la liaison `[formField]`.
127
238
  *
128
239
  * Les noms restent anglais : voir le glossaire, § 8.
129
240
  *
130
241
  * Le gabarit du champ doit nommer son element natif `#champ`, et le brancher sur
131
242
  * `touch` a la perte du focus.
132
243
  */
133
- declare abstract class ContratDeChamp {
134
- readonly libelle: _angular_core.InputSignal<string>;
135
- readonly aide: _angular_core.InputSignal<string | null>;
136
- readonly errors: _angular_core.InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
137
- readonly touched: _angular_core.InputSignalWithTransform<boolean, unknown>;
138
- readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
139
- readonly readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
140
- readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
141
- readonly hidden: _angular_core.InputSignalWithTransform<boolean, unknown>;
142
- readonly name: _angular_core.InputSignal<string>;
143
- readonly touch: _angular_core.OutputEmitterRef<void>;
144
- private readonly champ;
145
- /** Appele par Signal Forms pour amener le focus sur un champ en erreur. */
146
- focus(options?: FocusOptions): void;
147
- protected texteSaisi(evenement: Event): string;
148
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContratDeChamp, never>;
149
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ContratDeChamp, never, never, { "libelle": { "alias": "libelle"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hidden": { "alias": "hidden"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "touch": "touch"; }, never, never, true, never>;
244
+ export declare abstract class ContratDeChamp {
245
+ readonly libelle: import("@angular/core").InputSignal<string>;
246
+ readonly aide: import("@angular/core").InputSignal<string | null>;
247
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
248
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
249
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
250
+ /** Une validation asynchrone est en cours (« Verification… »). */
251
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
252
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
253
+ /** Pourquoi le champ est desactive : a dire en aide, jamais a taire. */
254
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
255
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
256
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
257
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
258
+ readonly name: import("@angular/core").InputSignal<string>;
259
+ readonly minLength: import("@angular/core").InputSignal<number | undefined>;
260
+ readonly maxLength: import("@angular/core").InputSignal<number | undefined>;
261
+ readonly pattern: import("@angular/core").InputSignal<readonly RegExp[]>;
262
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
263
+ private readonly champ;
264
+ /** Le groupe (`st-fieldset`) qui contient le champ, s'il y en a un. */
265
+ private readonly groupe;
266
+ /**
267
+ * Desactive par le schema OU par son groupe. ⚠️ `fieldset[disabled]` natif ne gele que les
268
+ * elements natifs : un controle NON natif (declencheur `div role=combobox`) lit ce signal, et
269
+ * non `disabled()`, pour sortir de la tabulation et s'annoncer inactif dans un groupe gele.
270
+ * Le gel du groupe est un etat d'INTERFACE : il ne retire pas le champ de la validation (le
271
+ * schema le fait, par `disabled()`).
272
+ */
273
+ protected readonly desactive: import("@angular/core").Signal<boolean>;
274
+ /**
275
+ * L'aide a afficher : celle du champ, suivie des raisons de desactivation quand il l'est
276
+ * (« Reserve aux comptes Corporate »). Un champ grise sans raison laisse chercher pourquoi.
277
+ */
278
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
279
+ /** Appele par Signal Forms pour amener le focus sur un champ en erreur. */
280
+ focus(options?: FocusOptions): void;
281
+ protected texteSaisi(evenement: Event): string;
282
+ static ɵfac: i0.ɵɵFactoryDeclaration<ContratDeChamp, never>;
283
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ContratDeChamp, never, never, {
284
+ "libelle": {
285
+ "alias": "libelle";
286
+ "required": true;
287
+ "isSignal": true;
288
+ };
289
+ "aide": {
290
+ "alias": "aide";
291
+ "required": false;
292
+ "isSignal": true;
293
+ };
294
+ "errors": {
295
+ "alias": "errors";
296
+ "required": false;
297
+ "isSignal": true;
298
+ };
299
+ "touched": {
300
+ "alias": "touched";
301
+ "required": false;
302
+ "isSignal": true;
303
+ };
304
+ "dirty": {
305
+ "alias": "dirty";
306
+ "required": false;
307
+ "isSignal": true;
308
+ };
309
+ "pending": {
310
+ "alias": "pending";
311
+ "required": false;
312
+ "isSignal": true;
313
+ };
314
+ "disabled": {
315
+ "alias": "disabled";
316
+ "required": false;
317
+ "isSignal": true;
318
+ };
319
+ "disabledReasons": {
320
+ "alias": "disabledReasons";
321
+ "required": false;
322
+ "isSignal": true;
323
+ };
324
+ "readonly": {
325
+ "alias": "readonly";
326
+ "required": false;
327
+ "isSignal": true;
328
+ };
329
+ "required": {
330
+ "alias": "required";
331
+ "required": false;
332
+ "isSignal": true;
333
+ };
334
+ "hidden": {
335
+ "alias": "hidden";
336
+ "required": false;
337
+ "isSignal": true;
338
+ };
339
+ "name": {
340
+ "alias": "name";
341
+ "required": false;
342
+ "isSignal": true;
343
+ };
344
+ "minLength": {
345
+ "alias": "minLength";
346
+ "required": false;
347
+ "isSignal": true;
348
+ };
349
+ "maxLength": {
350
+ "alias": "maxLength";
351
+ "required": false;
352
+ "isSignal": true;
353
+ };
354
+ "pattern": {
355
+ "alias": "pattern";
356
+ "required": false;
357
+ "isSignal": true;
358
+ };
359
+ }, {
360
+ "touch": "touch";
361
+ }, never, never, true, never>;
362
+ }
363
+ /**
364
+ * Base des champs a bornes de valeur (nombre, montant, date) : `min` et `max` du schema, du type
365
+ * de la valeur (`NonNullable<TValeur>`, comme Signal Forms les pose).
366
+ */
367
+ export declare abstract class ContratDeChampABornes<TValeur> extends ContratDeChamp {
368
+ readonly min: import("@angular/core").InputSignal<NonNullable<TValeur> | undefined>;
369
+ readonly max: import("@angular/core").InputSignal<NonNullable<TValeur> | undefined>;
370
+ static ɵfac: i0.ɵɵFactoryDeclaration<ContratDeChampABornes<any>, never>;
371
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ContratDeChampABornes<any>, never, never, {
372
+ "min": {
373
+ "alias": "min";
374
+ "required": false;
375
+ "isSignal": true;
376
+ };
377
+ "max": {
378
+ "alias": "max";
379
+ "required": false;
380
+ "isSignal": true;
381
+ };
382
+ }, {}, never, never, true, never>;
150
383
  }
151
384
  /** Base des champs dont la valeur est le texte saisi. */
152
- declare abstract class ControleDeSaisie extends ContratDeChamp implements FormValueControl<string> {
153
- readonly value: _angular_core.ModelSignal<string>;
154
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ControleDeSaisie, never>;
155
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ControleDeSaisie, never, never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
385
+ export declare abstract class ControleDeSaisie extends ContratDeChamp implements FormValueControl<string> {
386
+ readonly value: import("@angular/core").ModelSignal<string>;
387
+ static ɵfac: i0.ɵɵFactoryDeclaration<ControleDeSaisie, never>;
388
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ControleDeSaisie, never, never, {
389
+ "value": {
390
+ "alias": "value";
391
+ "required": false;
392
+ "isSignal": true;
393
+ };
394
+ }, {
395
+ "value": "valueChange";
396
+ }, never, never, true, never>;
397
+ }
398
+ /**
399
+ * Base des cases a cocher et des interrupteurs : le meme contrat, avec `checked` a la place de
400
+ * `value` (FormCheckboxControl).
401
+ *
402
+ * ⚠️ `readonly` n'existe pas sur une case native : le clic la bascule quand meme. `surClic`
403
+ * l'annule avant la bascule (`preventDefault`), `surBascule` n'ecrit le modele qu'hors lecture
404
+ * seule ; le gabarit pose `aria-readonly`. La case reste focalisable et lue (a l'inverse de
405
+ * `disabled`, qui la retire de la tabulation).
406
+ */
407
+ export declare abstract class ContratDeCase extends ContratDeChamp implements FormCheckboxControl {
408
+ readonly checked: import("@angular/core").ModelSignal<boolean>;
409
+ /**
410
+ * A brancher sur `(click)` de la case native : en lecture seule, le clic (souris, ou Espace qui
411
+ * passe par lui) est annule AVANT la bascule — aucun etat coche transitoire expose a l'arbre
412
+ * d'accessibilite, aucun evenement `input` ni `change`.
413
+ */
414
+ protected surClic(evenement: MouseEvent): void;
415
+ /** A brancher sur `(change)` de la case native : ecrit le modele (filet si le clic passe). */
416
+ protected surBascule(evenement: Event): void;
417
+ static ɵfac: i0.ɵɵFactoryDeclaration<ContratDeCase, never>;
418
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ContratDeCase, never, never, {
419
+ "checked": {
420
+ "alias": "checked";
421
+ "required": false;
422
+ "isSignal": true;
423
+ };
424
+ }, {
425
+ "checked": "checkedChange";
426
+ }, never, never, true, never>;
427
+ }
428
+ /**
429
+ * Un choix d'une liste : `st-select`, `st-combobox`, `st-multiselect`.
430
+ *
431
+ * La `valeur` part dans le modele, le `libelle` s'affiche : un identifiant
432
+ * technique ne s'affiche jamais, et un libelle traduit ne s'envoie jamais.
433
+ */
434
+ export interface OptionDeListe {
435
+ readonly valeur: string;
436
+ readonly libelle: string;
437
+ /** Une precision sous le libelle (« Reglement brut en temps reel »), lue avec l'option. */
438
+ readonly aide?: string;
439
+ readonly desactivee?: boolean;
440
+ /** Regroupe les options consecutives sous un intitule (`optgroup`). */
441
+ readonly groupe?: string;
156
442
  }
157
-
158
443
  /**
159
444
  * `empilee` : etiquette au-dessus du controle, pour un champ texte.
160
- * `case` : controle AVANT son etiquette, pour une case a cocher ou un interrupteur.
445
+ * `case` : controle AVANT son etiquette, centre sur la colonne de textes, pour une case a cocher.
446
+ * `reglage` : controle APRES son etiquette (texte a gauche, commande a droite), pour un
447
+ * interrupteur dans sa ligne de reglage (planches 3a, 3b).
448
+ * `en-ligne` : etiquette A GAUCHE du controle, sur une colonne commune reglable
449
+ * par `--st-champ-largeur-libelle` (formulaire horizontal de back-office).
450
+ */
451
+ export type DispositionDeChamp = 'empilee' | 'case' | 'reglage' | 'en-ligne';
452
+ /**
453
+ * Les jetons d'`autocomplete` qu'un champ du socle emploie (WHATWG, « autofill field names ») :
454
+ * WCAG 1.3.5 demande le bon jeton sur tout champ qui porte une donnee de la personne. Un jeton
455
+ * absent de la liste reste possible (`section-*`, `shipping`…) par la chaine libre.
456
+ */
457
+ export type TypeDAutocompletion = 'off' | 'on' | 'name' | 'honorific-prefix' | 'given-name' | 'additional-name' | 'family-name' | 'nickname' | 'email' | 'username' | 'new-password' | 'current-password' | 'one-time-code' | 'organization-title' | 'organization' | 'street-address' | 'address-line1' | 'address-line2' | 'address-line3' | 'address-level1' | 'address-level2' | 'country' | 'country-name' | 'postal-code' | 'cc-name' | 'cc-number' | 'cc-exp' | 'cc-csc' | 'transaction-currency' | 'transaction-amount' | 'language' | 'bday' | 'sex' | 'tel' | 'tel-national' | 'url' | (string & Record<never, never>);
458
+ /** Le clavier virtuel adapte (`inputmode`) : `numeric` pour un code, `decimal` pour un montant. */
459
+ export type ModeDeSaisie = 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
460
+ /**
461
+ * Sans accents ni casse : « eleve » trouve « Eleve ».
462
+ *
463
+ * La casse se replie dans la langue de la page (`ST_LOCALE`), passee par le composant qui cherche :
464
+ * les regles de casse ne sont pas les memes d'une langue a l'autre. Sans locale, celle du moteur.
465
+ */
466
+ export declare function normaliserPourRecherche(texte: string, locale?: string): string;
467
+ /** Options dont le libelle CONTIENT le texte cherche, sans accents ni casse. */
468
+ export declare function filtrerOptions(options: readonly OptionDeListe[], recherche: string, locale?: string): readonly OptionDeListe[];
469
+ /** Un bloc d'options consecutives partageant le meme `groupe` (ou aucun). */
470
+ export interface BlocDOptions {
471
+ /** Identite stable du bloc dans un `@for track` : la valeur de sa premiere option. */
472
+ readonly cle: string;
473
+ readonly groupe: string | null;
474
+ readonly options: readonly OptionDeListe[];
475
+ }
476
+ /**
477
+ * Regroupe des options CONSECUTIVES d'un meme `groupe`, dans l'ordre fourni (`st-select`,
478
+ * `st-combobox`, `st-multiselect`) : un `optgroup` natif ou un `role=group` ARIA se construit sur
479
+ * des blocs adjacents, jamais en triant par nom de groupe.
480
+ */
481
+ export declare function groupesDOptions(options: readonly OptionDeListe[]): readonly BlocDOptions[];
482
+ /** Identifiants que la base cite dans `aria-describedby`. */
483
+ interface IdentifiantsDeDescription {
484
+ readonly aide: string;
485
+ readonly erreur: string;
486
+ }
487
+ /**
488
+ * Ce que le champ et le groupe partagent : l'aide, les erreurs, l'obligation, et le calcul des
489
+ * descriptions qui les relie.
490
+ *
491
+ * ⚠️ **Une base, et non deux copies** (lot 215). `st-form-field` et `st-fieldset` recopiaient le
492
+ * meme calcul ; la copie du groupe avait garde le defaut que le champ avait perdu (une aide vide
493
+ * citee dans `aria-describedby`, constat A1163). Le repere d'erreur est donc le meme partout :
494
+ * memes messages, meme ordre, meme invalidite.
495
+ *
496
+ * ⚠️ **Un champ montre une seule erreur par defaut** : la premiere, celle que le recapitulatif
497
+ * d'erreurs dit pour ce champ. Deux messages differents pour un meme champ, l'un sous les yeux et
498
+ * l'autre dans le recapitulatif, font chercher la seconde erreur qui n'existe pas.
499
+ * `toutesLesErreurs` les montre toutes, pour un champ dont chaque regle se corrige a part (mot de
500
+ * passe) ou dont chaque erreur vise une partie distincte (un fichier refuse chacun).
501
+ *
502
+ * ⚠️ **Un groupe les montre toutes par defaut** (`st-fieldset` redefinit l'entree a vrai) : ses
503
+ * erreurs visent des parties distinctes (debut ET fin d'une plage), et taire la seconde laisserait
504
+ * une partie `aria-invalid` sans aucun texte qui dise pourquoi (WCAG 3.3.1).
505
+ */
506
+ declare abstract class PorteurDErreurs {
507
+ private readonly libelles;
508
+ private readonly locale;
509
+ /** Aide permanente : format attendu, exemple. Une chaine vide n'est pas une aide. */
510
+ readonly aide: import("@angular/core").InputSignal<string | null>;
511
+ readonly erreurs: import("@angular/core").InputSignal<readonly ErreurAffichable[]>;
512
+ /**
513
+ * ⚠️ Faux tant que la personne n'a pas quitte le champ ou tente l'envoi (UX-3) : un formulaire
514
+ * vierge couvert d'erreurs accuse avant qu'on ait rien fait.
515
+ */
516
+ readonly afficherErreurs: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
517
+ /** Montre toutes les erreurs au lieu de la premiere (vrai par defaut sur un groupe). */
518
+ readonly toutesLesErreurs: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
519
+ readonly obligatoire: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
520
+ /** Racine des identifiants, tiree du service d'application (jamais d'un compteur de module). */
521
+ protected readonly racine: string;
522
+ /** Les identifiants de l'aide et de l'erreur, construits par la classe fille depuis `racine`. */
523
+ abstract readonly identifiants: IdentifiantsDeDescription;
524
+ protected readonly libelleObligatoire: import("@angular/core").Signal<string>;
525
+ /** L'aide a rendre : `null` pour une aide absente OU vide, le gabarit et `aria-describedby` d'accord. */
526
+ protected readonly aideRendue: import("@angular/core").Signal<string | null>;
527
+ /** Messages a afficher, dans la langue courante. Vide tant qu'ils ne doivent pas l'etre. */
528
+ protected readonly messages: import("@angular/core").Signal<string[]>;
529
+ /** Vrai quand des messages sont AFFICHES : c'est lui que lisent `aria-invalid` et le lisere. */
530
+ readonly enErreur: import("@angular/core").Signal<boolean>;
531
+ /**
532
+ * ⚠️ Seuls les elements PRESENTS sont references : un `aria-describedby` qui vise un identifiant
533
+ * absent est ignore par certains lecteurs d'ecran — tout entier, y compris les references valides
534
+ * qui l'accompagnent. Ordre de lecture : aide, descriptions propres (complement), erreur.
535
+ */
536
+ readonly descriptions: import("@angular/core").Signal<string | null>;
537
+ /** `st-champ` ou `st-groupe` : lu une fois, a la construction. */
538
+ protected abstract prefixeDIdentifiant(): string;
539
+ /** Identifiants propres a la classe fille, lus entre l'aide et l'erreur. */
540
+ protected descriptionsPropres(): readonly string[];
541
+ static ɵfac: i0.ɵɵFactoryDeclaration<PorteurDErreurs, never>;
542
+ static ɵdir: i0.ɵɵDirectiveDeclaration<PorteurDErreurs, never, never, {
543
+ "aide": {
544
+ "alias": "aide";
545
+ "required": false;
546
+ "isSignal": true;
547
+ };
548
+ "erreurs": {
549
+ "alias": "erreurs";
550
+ "required": false;
551
+ "isSignal": true;
552
+ };
553
+ "afficherErreurs": {
554
+ "alias": "afficherErreurs";
555
+ "required": false;
556
+ "isSignal": true;
557
+ };
558
+ "toutesLesErreurs": {
559
+ "alias": "toutesLesErreurs";
560
+ "required": false;
561
+ "isSignal": true;
562
+ };
563
+ "obligatoire": {
564
+ "alias": "obligatoire";
565
+ "required": false;
566
+ "isSignal": true;
567
+ };
568
+ }, {}, never, never, true, never>;
569
+ }
570
+ /** Un texte a rendre, ou `null` : une chaine vide ou blanche ne se rend pas. */
571
+ declare function texteRendu(texte: string | null | undefined): string | null;
572
+ /**
573
+ * `libelle` : l'etiquette de champ, 14/500 (D18).
574
+ * `micro-capitales` : 11/600 en capitales espacees, pour un champ de dialogue ou de panneau dense
575
+ * (planches 4, 5, 13) ; le controle, lui, ne change pas.
161
576
  */
162
- type DispositionDeChamp = 'empilee' | 'case';
577
+ export type PresentationDeLibelle = 'libelle' | 'micro-capitales';
163
578
  /**
164
579
  * Etiquette, aide, erreur et controle d'un champ de saisie — et le cablage qui
165
580
  * les relie.
@@ -169,73 +584,123 @@ type DispositionDeChamp = 'empilee' | 'case';
169
584
  * `aria-invalid` : c'est precisement le code que l'on croit fini et qui se perd,
170
585
  * un champ specialise a la fois.
171
586
  *
172
- * L'ordre visuel suit celui de la lecture : etiquette, aide, erreur, controle.
173
- * L'erreur est AU-DESSUS du controle, pour etre vue avant de retaper.
587
+ * Anatomie (planche 3b, reference unique D23) : une ligne d'en-tete (etiquette 14/500, mention
588
+ * « (obligatoire) » ou meta `[stMeta]` a droite), l'aide, puis le message — l'erreur, ou a
589
+ * defaut l'indication projetee `[stIndication]` (« Conforme au registre », « Selectionnable &
590
+ * copiable ») —, puis le controle. L'erreur est AU-DESSUS du controle, pour etre vue avant de
591
+ * retaper.
592
+ *
593
+ * ⚠️ **Le lisere d'erreur vit dans la gouttiere**, a -12 px du controle et sur SA hauteur : il
594
+ * ne decale rien, et le controle garde sa largeur et son bord. Le MESSAGE, lui, est au-dessus du
595
+ * controle (D23) : il le pousse vers le bas de sa hauteur (30 px pour une ligne). Chromium compte
596
+ * ce decalage au CLS, meme juste apres Tab : il est mesure au banc, et non nie.
174
597
  *
175
598
  * ⚠️ **L'erreur n'est pas une region vivante.** Annoncee a la perte du focus, elle
176
599
  * couperait la lecture du champ suivant, ou la personne est deja passee. Elle est
177
600
  * reliee au controle, donc lue quand on y revient ; a l'envoi, c'est le
178
601
  * recapitulatif d'erreurs qui prend le focus et les enumere.
179
602
  */
180
- declare class StFormField {
181
- private readonly libelles;
182
- private readonly locale;
183
- private readonly element;
184
- /**
185
- * ⚠️ OBLIGATOIRE et toujours visible (UX-1). Un texte indicatif ne le remplace
186
- * jamais : il disparait a la premiere frappe.
187
- */
188
- readonly libelle: _angular_core.InputSignal<string>;
189
- /** Aide permanente : format attendu, exemple. Lue apres l'etiquette. */
190
- readonly aide: _angular_core.InputSignal<string | null>;
191
- /** Texte complementaire tenu a jour par le controle, comme un compteur. */
192
- readonly complement: _angular_core.InputSignal<string | null>;
193
- readonly erreurs: _angular_core.InputSignal<readonly ErreurAffichable[]>;
194
- /**
195
- * ⚠️ Faux tant que la personne n'a pas quitte le champ ou tente l'envoi (UX-3) :
196
- * un formulaire vierge couvert d'erreurs accuse avant qu'on ait rien fait.
197
- */
198
- readonly afficherErreurs: _angular_core.InputSignalWithTransform<boolean, unknown>;
199
- readonly obligatoire: _angular_core.InputSignalWithTransform<boolean, unknown>;
200
- /**
201
- * ⚠️ Change l'ordre VISUEL, jamais celui du document : l'etiquette reste
202
- * reliee par `for`, et l'ordre de tabulation ne passe que par le controle.
203
- */
204
- readonly disposition: _angular_core.InputSignal<DispositionDeChamp>;
205
- /**
206
- * Etiquette lue mais non affichee.
207
- *
208
- * ⚠️ Reservee a la RECHERCHE, ou l'icone, le bouton et la position en tete de
209
- * page disent deja le but du champ. Partout ailleurs, une etiquette masquee est
210
- * l'etiquette qui manque au moment ou l'on tape (UX-1).
211
- */
212
- readonly libelleMasque: _angular_core.InputSignalWithTransform<boolean, unknown>;
213
- /** Identifiants du champ, lus par `stControleDeChamp` et par le gabarit. */
214
- readonly identifiants: {
215
- readonly controle: string;
216
- readonly libelle: `${string}-libelle`;
217
- readonly aide: `${string}-aide`;
218
- readonly complement: `${string}-complement`;
219
- readonly erreur: `${string}-erreur`;
220
- };
221
- protected readonly libelleObligatoire: _angular_core.Signal<string>;
222
- /** Messages a afficher, dans la langue courante. Vide tant qu'ils ne doivent pas l'etre. */
223
- protected readonly messages: _angular_core.Signal<string[]>;
224
- /**
225
- * Un clic sur l'etiquette d'un controle non natif n'y mene pas de lui-meme :
226
- * on y amene le focus, comme le navigateur le fait pour un champ natif.
227
- */
228
- protected focaliserLeControle(): void;
229
- /** Lu par le controle pour `aria-invalid`. */
230
- readonly enErreur: _angular_core.Signal<boolean>;
231
- /**
232
- * ⚠️ Seuls les elements PRESENTS sont references : un `aria-describedby` qui
233
- * vise un identifiant absent est ignore par certains lecteurs d'ecran — tout
234
- * entier, y compris les references valides qui l'accompagnent.
235
- */
236
- readonly descriptions: _angular_core.Signal<string | null>;
237
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StFormField, never>;
238
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StFormField, "st-form-field", never, { "libelle": { "alias": "libelle"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "complement": { "alias": "complement"; "required": false; "isSignal": true; }; "erreurs": { "alias": "erreurs"; "required": false; "isSignal": true; }; "afficherErreurs": { "alias": "afficherErreurs"; "required": false; "isSignal": true; }; "obligatoire": { "alias": "obligatoire"; "required": false; "isSignal": true; }; "disposition": { "alias": "disposition"; "required": false; "isSignal": true; }; "libelleMasque": { "alias": "libelleMasque"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
603
+ export declare class StFormField extends PorteurDErreurs {
604
+ /**
605
+ * ⚠️ OBLIGATOIRE et toujours visible (UX-1). Un texte indicatif ne le remplace
606
+ * jamais : il disparait a la premiere frappe.
607
+ */
608
+ readonly libelle: import("@angular/core").InputSignal<string>;
609
+ /** Texte complementaire tenu a jour par le controle, comme un compteur. Lu apres l'aide. */
610
+ readonly complement: import("@angular/core").InputSignal<string | null>;
611
+ /**
612
+ * ⚠️ Change l'ordre VISUEL, jamais celui du document : l'etiquette reste
613
+ * reliee par `for`, et l'ordre de tabulation ne passe que par le controle.
614
+ * `en-ligne` revient a `empilee` sous la rupture `md` de sa propre largeur.
615
+ */
616
+ readonly disposition: import("@angular/core").InputSignal<DispositionDeChamp>;
617
+ /** Le style de l'etiquette ; n'agit qu'en disposition `empilee` ou `en-ligne`. */
618
+ readonly presentation: import("@angular/core").InputSignal<PresentationDeLibelle>;
619
+ /**
620
+ * Etiquette lue mais non affichee.
621
+ *
622
+ * ⚠️ Reservee a la RECHERCHE, ou l'icone, le bouton et la position en tete de
623
+ * page disent deja le but du champ. Partout ailleurs, une etiquette masquee est
624
+ * l'etiquette qui manque au moment ou l'on tape (UX-1).
625
+ */
626
+ readonly libelleMasque: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
627
+ /**
628
+ * Identifiants d'elements DU CONTROLE qui le decrivent (le suffixe « Contrats » d'un
629
+ * `st-input`), lus apres la meta : une unite dite dans le cadre n'est pas perdue au focus.
630
+ */
631
+ readonly descriptionsDuControle: import("@angular/core").InputSignal<readonly string[]>;
632
+ /** Identifiants du champ, lus par `stControleDeChamp` et par le gabarit. */
633
+ readonly identifiants: {
634
+ readonly controle: string;
635
+ readonly libelle: `${string}-libelle`;
636
+ readonly aide: `${string}-aide`;
637
+ readonly meta: `${string}-meta`;
638
+ readonly indication: `${string}-indication`;
639
+ readonly complement: `${string}-complement`;
640
+ readonly erreur: `${string}-erreur`;
641
+ };
642
+ protected readonly complementRendu: import("@angular/core").Signal<string | null>;
643
+ /**
644
+ * Le controle projete, par reference : c'est lui que le clic sur l'etiquette focalise (et non
645
+ * un `querySelector` sur un identifiant, qui trouverait le controle d'un champ imbrique).
646
+ */
647
+ private readonly controle;
648
+ /**
649
+ * La meta et l'indication projetees existent-elles ? Relevees au rendu, et non par une requete
650
+ * de contenu : relayees par un champ du socle (`st-input` projette `[stMeta]` et
651
+ * `[stIndication]` plus loin), elles echappent aux requetes de `st-form-field`.
652
+ */
653
+ private readonly zoneDeMeta;
654
+ private readonly zoneDIndication;
655
+ private readonly metaPresente;
656
+ private readonly indicationPresente;
657
+ /**
658
+ * Un libelle riche `[stLibelle]` est-il projete (lot 218) ? Il remplace alors le texte de
659
+ * `libelle`, qui reste le nom cite par le recapitulatif d'erreurs et doit dire la meme chose.
660
+ */
661
+ private readonly zoneDuLibelleRiche;
662
+ protected readonly libelleRichePresent: import("@angular/core").WritableSignal<boolean>;
663
+ constructor();
664
+ protected prefixeDIdentifiant(): string;
665
+ protected descriptionsPropres(): readonly string[];
666
+ /**
667
+ * Un clic sur l'etiquette d'un controle non natif n'y mene pas de lui-meme :
668
+ * on y amene le focus, comme le navigateur le fait pour un champ natif.
669
+ */
670
+ protected focaliserLeControle(): void;
671
+ static ɵfac: i0.ɵɵFactoryDeclaration<StFormField, never>;
672
+ static ɵcmp: i0.ɵɵComponentDeclaration<StFormField, "st-form-field", never, {
673
+ "libelle": {
674
+ "alias": "libelle";
675
+ "required": true;
676
+ "isSignal": true;
677
+ };
678
+ "complement": {
679
+ "alias": "complement";
680
+ "required": false;
681
+ "isSignal": true;
682
+ };
683
+ "disposition": {
684
+ "alias": "disposition";
685
+ "required": false;
686
+ "isSignal": true;
687
+ };
688
+ "presentation": {
689
+ "alias": "presentation";
690
+ "required": false;
691
+ "isSignal": true;
692
+ };
693
+ "libelleMasque": {
694
+ "alias": "libelleMasque";
695
+ "required": false;
696
+ "isSignal": true;
697
+ };
698
+ "descriptionsDuControle": {
699
+ "alias": "descriptionsDuControle";
700
+ "required": false;
701
+ "isSignal": true;
702
+ };
703
+ }, {}, ["controle"], ["[stLibelle]", "[stAide]", "[stMeta]", "[stIndication]", "*"], true, never>;
239
704
  }
240
705
  /**
241
706
  * Pose sur l'element natif d'un champ le cablage de son `st-form-field` :
@@ -245,21 +710,74 @@ declare class StFormField {
245
710
  * validation du navigateur a l'envoi : une bulle « Veuillez renseigner ce champ »
246
711
  * dans la langue du NAVIGATEUR, pas dans celle de l'application, et qui double
247
712
  * le message du socle.
713
+ *
714
+ * `aria-errormessage` s'AJOUTE a `aria-describedby` (qui garde l'erreur) : les lecteurs
715
+ * d'ecran qui le lisent annoncent l'erreur comme telle, les autres la lisent en description.
248
716
  */
249
- declare class StControleDeChamp {
250
- protected readonly champ: StFormField;
251
- /**
252
- * ⚠️ `label for` n'etiquette que les elements natifs de formulaire. Le
253
- * declencheur d'une selection multiple est un `div` de role `combobox` : sans
254
- * `aria-labelledby`, il n'aurait aucun nom, et l'etiquette visible ne dirait
255
- * rien au lecteur d'ecran.
256
- */
257
- protected readonly etiquetable: boolean;
258
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StControleDeChamp, never>;
259
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<StControleDeChamp, "[stControleDeChamp]", never, {}, {}, never, never, true, never>;
717
+ export declare class StControleDeChamp {
718
+ protected readonly champ: StFormField;
719
+ /**
720
+ * ⚠️ `label for` n'etiquette que les elements natifs de formulaire. Le
721
+ * declencheur d'une selection multiple est un `div` de role `combobox` : sans
722
+ * `aria-labelledby`, il n'aurait aucun nom, et l'etiquette visible ne dirait
723
+ * rien au lecteur d'ecran.
724
+ */
725
+ protected readonly etiquetable: boolean;
726
+ static ɵfac: i0.ɵɵFactoryDeclaration<StControleDeChamp, never>;
727
+ static ɵdir: i0.ɵɵDirectiveDeclaration<StControleDeChamp, "[stControleDeChamp]", never, {}, {}, never, never, true, never>;
260
728
  }
261
-
262
- type TypeDeSaisie = 'text' | 'email' | 'tel' | 'url' | 'search';
729
+ /**
730
+ * Base des champs de texte dont la LONGUEUR se compte (`st-input`, `st-textarea`, lot 217) : un
731
+ * comportement, ecrit une fois.
732
+ *
733
+ * - `maxLength` (du schema ou pose a la main) : compteur en complement, « N caracteres
734
+ * restants », puis « N caracteres en trop » au depassement.
735
+ * - `minLength` : « Saisissez au moins N caracteres. » en aide, si l'appelant n'en donne pas.
736
+ *
737
+ * ⚠️ **Le compteur n'est pas annonce a chaque frappe** : une region vivante qui change a chaque
738
+ * caractere recouvre ce que la personne tape. Il est RELIE au champ — donc lu quand on y
739
+ * revient — et seuls les seuils (20, 10, 0 restants) et le depassement s'annoncent (UX-11), par
740
+ * `annonce`, que le gabarit rend dans sa region `polite`.
741
+ *
742
+ * ⚠️ **Pas de `maxlength` natif** : un texte colle serait tronque en silence. Pendant la frappe,
743
+ * le compteur SEUL dit le depassement (rouge, « N en trop », annonce polie) : rien ne s'insere
744
+ * au-dessus du champ sous le curseur (P6). Hors formulaire, le depassement devient une erreur
745
+ * LOCALE (`maxLength`), affichee et posee en `aria-invalid` a la SORTIE du champ ; dans un
746
+ * formulaire, l'erreur du schema suit `touched`, comme avant.
747
+ *
748
+ * Le gabarit relie `compteur()` au `complement` de `st-form-field`, `aideAffichee()`, `erreurs()`
749
+ * et `afficherErreurs()` a l'enveloppe, et branche `surSortie()` sur la perte du focus ; l'hote
750
+ * pose `data-depassement` quand `enDepassement()`.
751
+ */
752
+ declare abstract class ControleDeSaisieCompte extends ControleDeSaisie {
753
+ protected readonly libelles: Signal<import("@starterlib/ui").LibellesUi>;
754
+ protected readonly annonce: AnnonceLocale;
755
+ private readonly restants;
756
+ protected readonly enDepassement: Signal<boolean>;
757
+ protected readonly compteur: Signal<string | null>;
758
+ /**
759
+ * L'aide fournie (et les raisons de desactivation), sinon « Saisissez au moins N caracteres. »
760
+ * quand le schema le demande ; puis « Verification… » pendant une validation asynchrone.
761
+ */
762
+ protected readonly aideAffichee: Signal<string | null>;
763
+ /** Les erreurs du formulaire, et le depassement local s'il n'y est pas deja. */
764
+ protected readonly erreurs: Signal<readonly ErreurAffichable[]>;
765
+ /** La personne est-elle deja sortie du champ ? Pose au `blur`, pour l'erreur LOCALE seulement. */
766
+ private readonly sorti;
767
+ /**
768
+ * Les erreurs se montrent a la sortie du champ, jamais pendant la frappe : `touched` dans un
769
+ * formulaire ; hors formulaire (personne ne pose `touched`), la sortie du champ, pour que le
770
+ * depassement local devienne une erreur affichee.
771
+ */
772
+ protected readonly afficherErreurs: Signal<boolean>;
773
+ constructor();
774
+ protected surSortie(): void;
775
+ static ɵfac: i0.ɵɵFactoryDeclaration<ControleDeSaisieCompte, never>;
776
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ControleDeSaisieCompte, never, never, {}, {}, never, never, true, never>;
777
+ }
778
+ export type TypeDeSaisie = 'text' | 'email' | 'tel' | 'url' | 'search';
779
+ /** Presentation des chiffres de la valeur saisie. */
780
+ export type ChiffresDeSaisie = 'texte' | 'reference';
263
781
  /**
264
782
  * Champ de saisie d'une ligne, integre a Signal Forms.
265
783
  *
@@ -267,6 +785,10 @@ type TypeDeSaisie = 'text' | 'email' | 'tel' | 'url' | 'search';
267
785
  * <st-input libelle="Nom du beneficiaire" autocomplete="name" [formField]="virement.beneficiaire" />
268
786
  * <!-- ou, sans formulaire : -->
269
787
  * <st-input libelle="Reference" [(value)]="reference" />
788
+ * <!-- prefixe et suffixe DANS le cadre du champ : -->
789
+ * <st-input libelle="Quantite" [(value)]="quantite">
790
+ * <span stSuffixe>Contrats</span>
791
+ * </st-input>
270
792
  * ```
271
793
  *
272
794
  * ⚠️ **Contrat Signal Forms, noms anglais.** `value`, `errors`, `touched`,
@@ -277,49 +799,184 @@ type TypeDeSaisie = 'text' | 'email' | 'tel' | 'url' | 'search';
277
799
  *
278
800
  * ⚠️ **Pas d'attribut `maxlength` natif.** Il TRONQUE en silence un texte colle
279
801
  * trop long : la personne croit avoir saisi sa reference entiere, et n'en envoie
280
- * que le debut. La limite passe par la validation, qui DIT le depassement.
281
- */
282
- declare class StInput extends ControleDeSaisie {
283
- readonly type: _angular_core.InputSignal<TypeDeSaisie>;
284
- /**
285
- * WCAG 1.3.5 : identifie le but du champ, pour le remplissage automatique et les
286
- * aides techniques. `null` : laisse le navigateur decider.
287
- */
288
- readonly autocomplete: _angular_core.InputSignal<string | null>;
289
- /** Clavier virtuel adapte : `numeric`, `decimal`, `email`… */
290
- readonly inputmode: _angular_core.InputSignal<string | null>;
291
- protected surSaisie(evenement: Event): void;
292
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StInput, never>;
293
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StInput, "st-input", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "inputmode": { "alias": "inputmode"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
802
+ * que le debut. La limite passe par la validation, qui DIT le depassement : `maxLength`
803
+ * (du schema ou pose a la main) donne un compteur en complement, `minLength` une aide
804
+ * automatique, comme `st-textarea` (`ControleDeSaisieCompte`, lot 217).
805
+ *
806
+ * ⚠️ **Prefixe et suffixe PROJETES, jamais recomposes a cote** (`[stPrefixe]`,
807
+ * `[stSuffixe]`, ou `icone` pour un glyphe de tete). Le cadre porte alors le filet, le fond,
808
+ * l'anneau et l'erreur : un seul cadre (EA-11), la meme hauteur. Un emplacement n'entre PAS
809
+ * dans le NOM du champ, mais un emplacement de texte entre dans sa DESCRIPTION (lue au focus,
810
+ * apres l'aide et la meta) : l'unite « Contrats (= 303 625.00 CHF) » n'est jamais perdue.
811
+ * Un clic dans le cadre, hors d'un element interactif, donne le focus a la zone de frappe.
812
+ * Trop long pour la largeur, un emplacement de texte se coupe (points de suspension) : la zone
813
+ * de frappe garde toujours au moins huit chiffres visibles (WCAG 1.4.10). Un emplacement
814
+ * interactif se projette directement (`<button stSuffixe stIconButton …>`), jamais dans un
815
+ * `span` : il serait coupe avec lui.
816
+ */
817
+ export declare class StInput extends ControleDeSaisieCompte {
818
+ private readonly racineDuCadre;
819
+ /** Identifiants des emplacements, references en description quand ils portent du texte. */
820
+ protected readonly idPrefixe: string;
821
+ protected readonly idSuffixe: string;
822
+ private readonly zoneDePrefixe;
823
+ private readonly zoneDeSuffixe;
824
+ /** Emplacements qui decrivent le champ, releves au rendu (le contenu projete peut changer). */
825
+ protected readonly emplacementsQuiDecrivent: import("@angular/core").WritableSignal<readonly string[]>;
826
+ readonly type: import("@angular/core").InputSignal<TypeDeSaisie>;
827
+ /**
828
+ * WCAG 1.3.5 : identifie le but du champ, pour le remplissage automatique et les
829
+ * aides techniques. `null` : laisse le navigateur decider.
830
+ */
831
+ readonly autocomplete: import("@angular/core").InputSignal<TypeDAutocompletion | null>;
832
+ /** Clavier virtuel adapte : `numeric`, `decimal`, `email`… */
833
+ readonly inputmode: import("@angular/core").InputSignal<ModeDeSaisie | null>;
834
+ /** Glyphe decoratif de tete, dans le cadre (l'etiquette porte le sens). */
835
+ readonly icone: import("@angular/core").InputSignal<"iban" | "code" | "devise" | "fichier" | "message" | "menu" | "accessibilite" | "appareils" | "arborescence" | "asterisque" | "badge-coche" | "banque" | "batiment" | "bifurcation" | "billets" | "billets-envoi" | "billets-pile" | "boite" | "boite-de-reception" | "bouclier" | "bouclier-alerte" | "bouclier-coche" | "bouclier-coeur" | "bouclier-croix" | "bouclier-moitie" | "bouclier-recherche" | "bouclier-utilisateur" | "boussole" | "bouton-curseur" | "bulle-question" | "cadenas" | "cadenas-horloge" | "cadenas-ouvert" | "cadre-pied" | "cadre-texte" | "calendrier" | "calendrier-evenement" | "calendrier-horloge" | "calendrier-jour" | "calques" | "carte-bancaire" | "carte-bancaire-barre" | "carte-bancaire-cadenas" | "carte-contact" | "carte-identite" | "cartes-empilees" | "case-cochee" | "casse" | "cercle" | "cercle-alerte" | "cercle-chevron-bas" | "cercle-coche" | "cercle-coche-ouvert" | "cercle-croix" | "cercle-info" | "cercle-moins" | "cercle-plus" | "cercle-question" | "certificat" | "chandelier" | "chargement" | "cheque" | "chevron-bas" | "chevron-droite" | "chevron-gauche" | "chevron-haut" | "chevrons-droite" | "chevrons-haut-bas" | "cle" | "cloche" | "cloche-sonnerie" | "coche" | "code-qr" | "code-qr-scanner" | "coffre-fort" | "colonnes" | "connexion" | "contraste" | "copie" | "corbeille" | "corbeille-croix" | "courriel" | "crayon" | "croix" | "curseur-clic" | "deconnexion" | "disposition" | "dollar" | "dossier" | "dossier-barre" | "dossier-ouvert" | "double-coche" | "echange" | "eclair" | "empreinte-digitale" | "enregistrer" | "entree" | "envoyer" | "epaisseur-de-trait" | "epingle" | "etoile" | "euro" | "fichier-image" | "fichier-pdf" | "fichier-texte" | "filtre" | "filtre-barre" | "filtre-lignes" | "fleche-bas" | "fleche-bas-gauche" | "fleche-bas-ligne" | "fleche-droite" | "fleche-gauche" | "fleche-haut" | "fleche-haut-droite" | "fleche-haut-ligne" | "fleche-large-haut" | "fleches-gauche-droite" | "flocon" | "flou" | "formes" | "globe" | "graphique-anneau" | "graphique-barres" | "graphique-barres-cadre" | "graphique-camembert" | "graphique-ligne" | "graphique-lignes" | "grille" | "grille-lignes" | "hexagone" | "historique" | "horloge" | "horloge-fleche" | "imprimer" | "interdit" | "jalons" | "jauge" | "lien" | "lien-externe" | "lignes" | "lignes-crayon" | "liste" | "liste-coche" | "liste-controle" | "liste-numerotee" | "luminosite" | "lune" | "maillet" | "maison" | "marque-page" | "menu-ouvert" | "minuteur" | "mise-au-point" | "mise-en-page-image" | "moins" | "nuage-barre" | "nuage-televerser" | "octogone-alerte" | "oeil" | "oeil-barre" | "panneau-gauche" | "parametres" | "parapluie" | "parchemin" | "pieces" | "plus" | "pointeur" | "points" | "points-verticaux" | "portefeuille" | "portefeuille-cartes" | "presse-papiers-coche" | "presse-papiers-horloge" | "priorite-haute" | "rafraichir" | "recherche" | "recherche-barre" | "recherche-texte" | "rectangle-points" | "recu" | "redemarrer" | "reglages" | "regle" | "reseau-jauge" | "rotation-arriere" | "routeur" | "sablier" | "sablier-bas" | "sablier-haut" | "sac-argent" | "sans-contact" | "serveur" | "soleil" | "style-de-trait" | "synchro" | "synchro-probleme" | "tableau" | "tableau-de-bord" | "tableau-de-bord-plus" | "tablette" | "tabulation" | "telecharger" | "telephone-mobile" | "televerser" | "tendance-baisse" | "tendance-hausse" | "terminal" | "tirelire" | "triangle-alerte" | "triangle-bas" | "triangle-haut" | "trombone" | "utilisateur" | "utilisateur-crayon" | "utilisateurs" | "wifi" | "wifi-barre" | null>;
836
+ /**
837
+ * `reference` : IBAN, BIC, reference structuree — chasse fixe, chiffres a zero barre
838
+ * (`--st-chiffres-references`), pour qu'un 0 ne se lise pas O ; de gauche a droite en RTL.
839
+ */
840
+ readonly chiffres: import("@angular/core").InputSignal<ChiffresDeSaisie>;
841
+ /** Le style de l'etiquette (voir `st-form-field`). */
842
+ readonly presentation: import("@angular/core").InputSignal<PresentationDeLibelle>;
843
+ /**
844
+ * Identifiants d'autres textes qui decrivent le champ (`aria-describedby`), lus entre l'aide et
845
+ * l'erreur : les essais restants de `st-challenge` (audit UI du 2026-09-27, D-20). Des elements
846
+ * PRESENTS seulement : un identifiant absent fait ignorer toute la description par certains
847
+ * lecteurs d'ecran.
848
+ */
849
+ readonly decritPar: import("@angular/core").InputSignal<readonly string[]>;
850
+ /** Ce qui decrit le controle : les textes de l'appelant, puis les emplacements de texte. */
851
+ protected readonly descriptionsDuControle: import("@angular/core").Signal<readonly string[]>;
852
+ /**
853
+ * Des valeurs a PROPOSER, jamais a imposer : une liste `datalist` native, que le navigateur offre
854
+ * sous le champ et filtre a la frappe ; toute autre saisie reste admise (la ville d'une adresse,
855
+ * D133). `null` ou vide : aucune. Une liste FERMEE est un `st-select` ; une longue liste a filtrer
856
+ * dans une liste du socle, un `st-combobox`.
857
+ */
858
+ readonly suggestions: import("@angular/core").InputSignal<readonly string[] | null>;
859
+ protected readonly idDesSuggestions: string;
860
+ protected readonly avecSuggestions: import("@angular/core").Signal<boolean>;
861
+ /**
862
+ * L'indicateur d'attente n'apparait qu'apres `rythme.delai.attente` et reste au moins
863
+ * `rythme.tenue.affichageMinimal` : une verification de 150 ms ne fait rien clignoter.
864
+ */
865
+ protected readonly attenteVisible: import("@angular/core").Signal<boolean>;
866
+ /**
867
+ * Un courriel, un telephone, une adresse web, une reference structuree (IBAN, BIC) restent de
868
+ * gauche a droite en RTL : latins par nature, ils s'y alignaient a droite et un IBAN trop long
869
+ * pour la largeur y perdait son debut (« H93 0076… » au lieu de « CH93 0076… », instantanes du
870
+ * lot 217).
871
+ */
872
+ protected readonly sens: import("@angular/core").Signal<"ltr" | null>;
873
+ constructor();
874
+ /**
875
+ * Le cadre est UN champ : un clic sur le prefixe, l'icone, le suffixe texte ou la marge donne
876
+ * le focus a la zone de frappe (le survol du cadre l'a promis). Un bouton projete garde le sien.
877
+ */
878
+ protected surPressionDuCadre(evenement: MouseEvent): void;
879
+ protected surSaisie(evenement: Event): void;
880
+ static ɵfac: i0.ɵɵFactoryDeclaration<StInput, never>;
881
+ static ɵcmp: i0.ɵɵComponentDeclaration<StInput, "st-input", never, {
882
+ "type": {
883
+ "alias": "type";
884
+ "required": false;
885
+ "isSignal": true;
886
+ };
887
+ "autocomplete": {
888
+ "alias": "autocomplete";
889
+ "required": false;
890
+ "isSignal": true;
891
+ };
892
+ "inputmode": {
893
+ "alias": "inputmode";
894
+ "required": false;
895
+ "isSignal": true;
896
+ };
897
+ "icone": {
898
+ "alias": "icone";
899
+ "required": false;
900
+ "isSignal": true;
901
+ };
902
+ "chiffres": {
903
+ "alias": "chiffres";
904
+ "required": false;
905
+ "isSignal": true;
906
+ };
907
+ "presentation": {
908
+ "alias": "presentation";
909
+ "required": false;
910
+ "isSignal": true;
911
+ };
912
+ "decritPar": {
913
+ "alias": "decritPar";
914
+ "required": false;
915
+ "isSignal": true;
916
+ };
917
+ "suggestions": {
918
+ "alias": "suggestions";
919
+ "required": false;
920
+ "isSignal": true;
921
+ };
922
+ }, {}, never, ["[stMeta]", "[stAide]", "[stIndication]", "[stPrefixe]", "[stSuffixe]"], true, never>;
294
923
  }
295
-
296
924
  /**
297
925
  * Zone de texte, integree a Signal Forms, avec compteur quand une longueur
298
- * maximale est fixee.
299
- *
300
- * ⚠️ **Le compteur n'est pas annonce a chaque frappe** : une region vivante qui
301
- * change a chaque caractere recouvre ce que la personne tape. Il est RELIE a la
302
- * zone — donc lu quand on y revient — et seuls les seuils (20, 10, 0 restants)
303
- * et le depassement s'annoncent (UX-11).
304
- *
305
- * ⚠️ **Pas de `maxlength` natif**, meme raison que `st-input` : un texte colle
306
- * serait tronque en silence. Le compteur affiche le depassement, la validation
307
- * le refuse.
308
- */
309
- declare class StTextarea extends ControleDeSaisie {
310
- private readonly libelles;
311
- readonly lignes: _angular_core.InputSignal<number>;
312
- /** Contrat Signal Forms : la longueur maximale fixee par le schema. */
313
- readonly maxLength: _angular_core.InputSignal<number | undefined>;
314
- protected readonly annonce: AnnonceLocale;
315
- private readonly restants;
316
- protected readonly compteur: _angular_core.Signal<string | null>;
317
- constructor();
318
- protected surSaisie(evenement: Event): void;
319
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StTextarea, never>;
320
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StTextarea, "st-textarea", never, { "lignes": { "alias": "lignes"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
926
+ * maximale est fixee : le compteur, ses annonces aux seuils, le depassement local et l'aide de
927
+ * longueur minimale sont ceux de `ControleDeSaisieCompte`, partages avec `st-input`.
928
+ *
929
+ * La zone suit son texte (`field-sizing: content`), bornee entre `lignes` et `lignesMax` :
930
+ * jamais une fente d'une ligne, jamais une page entiere ; la poignee respecte les memes bornes.
931
+ */
932
+ export declare class StTextarea extends ControleDeSaisieCompte {
933
+ /** Hauteur de depart, et hauteur minimale, en lignes. */
934
+ readonly lignes: import("@angular/core").InputSignalWithTransform<number, unknown>;
935
+ /** Hauteur maximale en lignes : au-dela, la zone defile. */
936
+ readonly lignesMax: import("@angular/core").InputSignalWithTransform<number, unknown>;
937
+ /** Bornes effectives : `lignesMax` ne descend jamais sous `lignes`. */
938
+ protected readonly bornes: import("@angular/core").Signal<{
939
+ lignes: number;
940
+ lignesMax: number;
941
+ }>;
942
+ protected surSaisie(evenement: Event): void;
943
+ static ɵfac: i0.ɵɵFactoryDeclaration<StTextarea, never>;
944
+ static ɵcmp: i0.ɵɵComponentDeclaration<StTextarea, "st-textarea", never, {
945
+ "lignes": {
946
+ "alias": "lignes";
947
+ "required": false;
948
+ "isSignal": true;
949
+ };
950
+ "lignesMax": {
951
+ "alias": "lignesMax";
952
+ "required": false;
953
+ "isSignal": true;
954
+ };
955
+ }, {}, never, never, true, never>;
321
956
  }
322
-
957
+ /**
958
+ * Ce qu'un groupe (`st-fieldset`) dit a ses controles.
959
+ *
960
+ * ⚠️ `fieldset[disabled]` natif ne desactive que les elements de formulaire NATIFS. Un controle
961
+ * non natif (le declencheur `div role=combobox` d'une selection multiple) resterait focalisable,
962
+ * annonce actif et ouvrable dans un groupe gele : il lit donc ce jeton, par `ContratDeChamp`.
963
+ */
964
+ interface GroupeDeSaisie {
965
+ /** Vrai quand le groupe entier est desactive. */
966
+ readonly disabled: Signal<boolean>;
967
+ }
968
+ declare const ST_GROUPE_DE_SAISIE: InjectionToken<GroupeDeSaisie>;
969
+ /**
970
+ * `champs` : des champs empiles a 20 px (nom et IBAN d'un beneficiaire).
971
+ * `choix` : des cases ou des radios a 12 px (un groupe d'options, `st-radio-group`).
972
+ */
973
+ export type ContenuDeGroupe = 'champs' | 'choix';
974
+ /**
975
+ * `colonne` : les controles l'un sous l'autre.
976
+ * `en-ligne` : cote a cote, pour deux champs courts (une plage de dates) ; en colonne sous la
977
+ * rupture `sm` de la largeur du groupe.
978
+ */
979
+ export type DispositionDeGroupe = 'colonne' | 'en-ligne';
323
980
  /**
324
981
  * Groupe de controles, nomme par sa QUESTION.
325
982
  *
@@ -327,34 +984,105 @@ declare class StTextarea extends ControleDeSaisie {
327
984
  * annonce « Oui, bouton radio » et « Non, bouton radio » : la reponse, jamais la
328
985
  * question. La legende est lue a l'entree dans le groupe.
329
986
  *
330
- * C'est le pendant de `st-form-field` pour un GROUPE : l'aide et l'erreur sont
331
- * reliees au `fieldset` par `aria-describedby`, et l'erreur porte sur le groupe
332
- * entier — « Choisissez un mode de reglement » — et non sur chaque option.
987
+ * C'est le pendant de `st-form-field` pour un GROUPE, sur la meme base (`PorteurDErreurs`) :
988
+ * l'aide et l'erreur sont reliees au `fieldset` par `aria-describedby`, l'erreur porte sur le
989
+ * groupe entier — « Choisissez un mode de reglement » — et non sur chaque option, et son lisere
990
+ * est a la place de celui du champ : dans la gouttiere, sur la hauteur des controles.
333
991
  *
334
992
  * ⚠️ L'obligation se dit dans la legende, en texte : `aria-required` n'est pas
335
993
  * valide sur un groupe, et `required` natif ferait parler le navigateur dans sa
336
- * propre langue.
337
- */
338
- declare class StFieldset {
339
- private readonly libelles;
340
- private readonly locale;
341
- /** La question posee par le groupe. Obligatoire. */
342
- readonly legende: _angular_core.InputSignal<string>;
343
- readonly aide: _angular_core.InputSignal<string | null>;
344
- readonly erreurs: _angular_core.InputSignal<readonly ErreurAffichable[]>;
345
- readonly afficherErreurs: _angular_core.InputSignalWithTransform<boolean, unknown>;
346
- readonly obligatoire: _angular_core.InputSignalWithTransform<boolean, unknown>;
347
- private readonly base;
348
- protected readonly identifiantAide: string;
349
- protected readonly identifiantErreur: string;
350
- protected readonly libelleObligatoire: _angular_core.Signal<string>;
351
- protected readonly messages: _angular_core.Signal<string[]>;
352
- protected readonly enErreur: _angular_core.Signal<boolean>;
353
- protected readonly descriptions: _angular_core.Signal<string | null>;
354
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StFieldset, never>;
355
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StFieldset, "st-fieldset", never, { "legende": { "alias": "legende"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "erreurs": { "alias": "erreurs"; "required": false; "isSignal": true; }; "afficherErreurs": { "alias": "afficherErreurs"; "required": false; "isSignal": true; }; "obligatoire": { "alias": "obligatoire"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
994
+ * propre langue. Un groupe a choix EXCLUSIF (`choixExclusif`, pose par `st-radio-group`) est un
995
+ * `radiogroup` : lui porte aussi `aria-required`, `aria-invalid` et `aria-readonly`.
996
+ *
997
+ * ⚠️ `disabled` pose le `fieldset[disabled]` NATIF, qui desactive d'un coup les controles natifs
998
+ * du groupe, et le fournit aux controles du socle (`ST_GROUPE_DE_SAISIE`) : un controle non natif
999
+ * (declencheur `div role=combobox`) doit lire `desactive()` de `ContratDeChamp` pour s'y plier
1000
+ * (adoption par st-combobox et st-multiselect : lot 227). C'est un gel d'INTERFACE : la validation
1001
+ * continue, le schema seul retire un champ (`disabled()`). La raison se dit en aide.
1002
+ *
1003
+ * ⚠️ Toutes les erreurs du groupe sont montrees par defaut (`toutesLesErreurs` vrai) : elles visent
1004
+ * des parties distinctes, et chacune doit dire pourquoi sa partie est invalide.
1005
+ */
1006
+ export declare class StFieldset extends PorteurDErreurs implements GroupeDeSaisie {
1007
+ /** La question posee par le groupe. Obligatoire. */
1008
+ readonly legende: import("@angular/core").InputSignal<string>;
1009
+ /** L'ecart entre les controles : 20 px entre des champs, 12 entre des cases ou des radios. */
1010
+ readonly contenu: import("@angular/core").InputSignal<ContenuDeGroupe>;
1011
+ readonly disposition: import("@angular/core").InputSignal<DispositionDeGroupe>;
1012
+ /** Toutes les erreurs du groupe, par defaut : chacune vise une partie distincte. */
1013
+ readonly toutesLesErreurs: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1014
+ /**
1015
+ * Des radios : le `fieldset` devient un `radiogroup`, qui porte l'obligation, l'erreur et la
1016
+ * lecture seule du groupe (ARIA ne les prevoit ni sur `group` ni sur `radio`).
1017
+ */
1018
+ readonly choixExclusif: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1019
+ /** Lecture seule du groupe, annoncee par `aria-readonly` (groupe a `choixExclusif` seulement). */
1020
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1021
+ /** Desactive tous les controles du groupe (`fieldset[disabled]` natif, et jeton de groupe). */
1022
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1023
+ /** Masque le groupe entier. */
1024
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1025
+ /**
1026
+ * Identifiants d'autres textes qui decrivent le groupe (`aria-describedby`), lus entre l'aide et
1027
+ * l'erreur : le recapitulatif de `st-recurrence-field` (lot 255), relie sans etre annonce.
1028
+ */
1029
+ readonly decritPar: import("@angular/core").InputSignal<readonly string[]>;
1030
+ /** Identifiants de l'aide et de l'erreur, cites par `aria-describedby`. */
1031
+ readonly identifiants: {
1032
+ readonly aide: `${string}-aide`;
1033
+ readonly erreur: `${string}-erreur`;
1034
+ };
1035
+ protected prefixeDIdentifiant(): string;
1036
+ protected descriptionsPropres(): readonly string[];
1037
+ static ɵfac: i0.ɵɵFactoryDeclaration<StFieldset, never>;
1038
+ static ɵcmp: i0.ɵɵComponentDeclaration<StFieldset, "st-fieldset", never, {
1039
+ "legende": {
1040
+ "alias": "legende";
1041
+ "required": true;
1042
+ "isSignal": true;
1043
+ };
1044
+ "contenu": {
1045
+ "alias": "contenu";
1046
+ "required": false;
1047
+ "isSignal": true;
1048
+ };
1049
+ "disposition": {
1050
+ "alias": "disposition";
1051
+ "required": false;
1052
+ "isSignal": true;
1053
+ };
1054
+ "toutesLesErreurs": {
1055
+ "alias": "toutesLesErreurs";
1056
+ "required": false;
1057
+ "isSignal": true;
1058
+ };
1059
+ "choixExclusif": {
1060
+ "alias": "choixExclusif";
1061
+ "required": false;
1062
+ "isSignal": true;
1063
+ };
1064
+ "readonly": {
1065
+ "alias": "readonly";
1066
+ "required": false;
1067
+ "isSignal": true;
1068
+ };
1069
+ "disabled": {
1070
+ "alias": "disabled";
1071
+ "required": false;
1072
+ "isSignal": true;
1073
+ };
1074
+ "hidden": {
1075
+ "alias": "hidden";
1076
+ "required": false;
1077
+ "isSignal": true;
1078
+ };
1079
+ "decritPar": {
1080
+ "alias": "decritPar";
1081
+ "required": false;
1082
+ "isSignal": true;
1083
+ };
1084
+ }, {}, never, ["*"], true, never>;
356
1085
  }
357
-
358
1086
  /**
359
1087
  * Case a cocher, integree a Signal Forms.
360
1088
  *
@@ -362,39 +1090,71 @@ declare class StFieldset {
362
1090
  * <st-checkbox libelle="J'accepte les conditions generales" [formField]="inscription.conditions" />
363
1091
  * ```
364
1092
  *
365
- * Un element `input type="checkbox"` natif : Espace coche, l'etat est annonce,
366
- * et la case suit le reglage de contraste du systeme sans rien ecrire.
1093
+ * Un element `input type="checkbox"` natif, dessine par le socle (planches 3a, 3b) : Espace coche,
1094
+ * l'etat est annonce, et la case est la meme sous Windows, macOS et Android. La ligne entiere (case,
1095
+ * etiquette, aide) fait 44 px au moins ; cochee, elle se teinte ; en erreur, elle rougit, la case
1096
+ * double son filet et le message s'ecrit sous l'etiquette.
367
1097
  *
368
1098
  * ⚠️ **Pour un choix a envoyer avec un formulaire.** Un reglage qui s'applique
369
1099
  * IMMEDIATEMENT est un `st-switch` : la case promet un effet a l'envoi, et
370
1100
  * l'interrupteur un effet tout de suite (UX-8).
1101
+ *
1102
+ * `indetermine` (« tout selectionner » d'une liste partiellement choisie) pose l'etat natif
1103
+ * `indeterminate`, que le lecteur d'ecran annonce « partiellement coche » (`mixed`) ; un clic le
1104
+ * leve et coche la case, comme le fait le navigateur.
1105
+ *
1106
+ * `readonly` (regle `readonly()` du schema) : la case reste focalisable et lue, mais ni le clic ni
1107
+ * Espace ne la basculent (`ContratDeCase`).
1108
+ *
1109
+ * Libelle riche (lot 218) : un element `[stLibelle]` projete remplace le texte de l'etiquette, pour
1110
+ * un lien dans la phrase. L'etiquette reste le `label` de la case, et le lien son nom accessible ;
1111
+ * un clic sur le lien suit le lien sans cocher (un contenu interactif dans un `label` ne l'active
1112
+ * pas). `libelle` reste obligatoire et dit la meme chose en texte : c'est lui que cite le
1113
+ * recapitulatif d'erreurs.
1114
+ *
1115
+ * ```html
1116
+ * <st-checkbox libelle="J'accepte les conditions generales" [formField]="inscription.conditions">
1117
+ * <span stLibelle>J'accepte les <a stLink href="/cgu">conditions generales</a></span>
1118
+ * </st-checkbox>
1119
+ * ```
371
1120
  */
372
- declare class StCheckbox implements FormCheckboxControl {
373
- readonly libelle: _angular_core.InputSignal<string>;
374
- readonly aide: _angular_core.InputSignal<string | null>;
375
- /** Contrat Signal Forms. */
376
- readonly checked: _angular_core.ModelSignal<boolean>;
377
- readonly errors: _angular_core.InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
378
- readonly touched: _angular_core.InputSignalWithTransform<boolean, unknown>;
379
- readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
380
- readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
381
- readonly hidden: _angular_core.InputSignalWithTransform<boolean, unknown>;
382
- readonly name: _angular_core.InputSignal<string>;
383
- readonly touch: _angular_core.OutputEmitterRef<void>;
384
- private readonly champ;
385
- focus(options?: FocusOptions): void;
386
- protected surChangement(evenement: Event): void;
387
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StCheckbox, never>;
388
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StCheckbox, "st-checkbox", never, { "libelle": { "alias": "libelle"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hidden": { "alias": "hidden"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "touch": "touch"; }, never, never, true, never>;
1121
+ export declare class StCheckbox extends ContratDeCase {
1122
+ /**
1123
+ * Etat intermediaire (« 3 sur 7 »). Un modele : la bascule par la personne le leve, et
1124
+ * l'application le lit (`[(indetermine)]`) pour savoir que le choix est devenu franc.
1125
+ */
1126
+ readonly indetermine: import("@angular/core").ModelSignal<boolean>;
1127
+ /**
1128
+ * L'aide dit l'etat OBTENU (« Recommande · Actif », planche 3a) : une fois la case cochee, elle
1129
+ * passe au vert de succes, en 500. A choisir explicitement : une aide ordinaire (« Un courriel
1130
+ * vous sera envoye. ») ne prend pas la couleur du succes parce qu'on a coche.
1131
+ */
1132
+ readonly aideDEtat: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1133
+ /** L'erreur se montre-t-elle ? La meme regle que le champ : apres la sortie du controle. */
1134
+ protected readonly enErreur: import("@angular/core").Signal<boolean>;
1135
+ protected surChangement(evenement: Event): void;
1136
+ static ɵfac: i0.ɵɵFactoryDeclaration<StCheckbox, never>;
1137
+ static ɵcmp: i0.ɵɵComponentDeclaration<StCheckbox, "st-checkbox", never, {
1138
+ "indetermine": {
1139
+ "alias": "indetermine";
1140
+ "required": false;
1141
+ "isSignal": true;
1142
+ };
1143
+ "aideDEtat": {
1144
+ "alias": "aideDEtat";
1145
+ "required": false;
1146
+ "isSignal": true;
1147
+ };
1148
+ }, {
1149
+ "indetermine": "indetermineChange";
1150
+ }, never, ["[stLibelle]"], true, never>;
389
1151
  }
390
-
391
- /** Une option du groupe. */
392
- interface OptionRadio {
393
- readonly valeur: string;
394
- readonly libelle: string;
395
- /** Precision sous le libelle, reliee a l'option. */
396
- readonly aide?: string;
397
- readonly desactivee?: boolean;
1152
+ /**
1153
+ * Une option du groupe : la forme d'option de toutes les listes (`OptionDeListe`), avec la RAISON
1154
+ * d'une option desactivee, lue en aide (« Indisponible pour ce compte. ») plutot que tue.
1155
+ */
1156
+ export interface OptionRadio extends OptionDeListe {
1157
+ readonly raison?: string;
398
1158
  }
399
1159
  /**
400
1160
  * Groupe de boutons radio, integre a Signal Forms.
@@ -407,44 +1167,1209 @@ interface OptionRadio {
407
1167
  * groupe, deplacement aux fleches, « 2 sur 3 » annonce. Les recrire en ARIA,
408
1168
  * c'est cent lignes pour obtenir moins bien — meme raison que `st-theme-toggle`.
409
1169
  *
410
- * ⚠️ **L'erreur porte sur le groupe**, par `st-fieldset`, et non sur chaque option :
411
- * « Choisissez un mode de reglement », une fois.
1170
+ * ⚠️ **Le message d'erreur porte sur le groupe**, par `st-fieldset` : « Choisissez un mode de
1171
+ * reglement », une fois. L'ETAT d'erreur, lui, est pose sur chaque radio (`aria-invalid`) : le
1172
+ * lecteur d'ecran le dit sur l'option ou se trouve le focus (WCAG 4.1.2), pas seulement a
1173
+ * l'entree du groupe. Le `fieldset` est un `radiogroup` (`choixExclusif`) : c'est lui qui porte
1174
+ * `aria-required`, `aria-invalid` et `aria-readonly`, qu'ARIA ne prevoit pas sur un radio.
1175
+ *
1176
+ * Chaque option est une ligne de 44 px au moins (planches 3a, 3b) : radio de 24, libelle et aide ;
1177
+ * l'option choisie se teinte.
412
1178
  *
413
1179
  * `touch` n'est emis que lorsque le focus QUITTE le groupe : passer d'une option a
414
1180
  * l'autre aux fleches n'est pas une fin de saisie, et l'erreur n'a pas a surgir
415
1181
  * pendant qu'on choisit.
1182
+ *
1183
+ * `readonly` : les options restent focalisables et lues, mais le choix ne change pas (un clic ou
1184
+ * une fleche est annule, l'option du modele reste cochee) ; le groupe l'annonce
1185
+ * (`aria-readonly` du `radiogroup`) et le curseur reste celui par defaut.
1186
+ */
1187
+ export declare class StRadioGroup implements FormValueControl<string> {
1188
+ private readonly element;
1189
+ readonly legende: import("@angular/core").InputSignal<string>;
1190
+ readonly aide: import("@angular/core").InputSignal<string | null>;
1191
+ readonly options: import("@angular/core").InputSignal<readonly OptionRadio[]>;
1192
+ /** `en-ligne` : options cote a cote (deux ou trois choix courts), en colonne quand la place manque. */
1193
+ readonly disposition: import("@angular/core").InputSignal<DispositionDeGroupe>;
1194
+ /** Contrat Signal Forms. */
1195
+ readonly value: import("@angular/core").ModelSignal<string>;
1196
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
1197
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1198
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1199
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1200
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1201
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
1202
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1203
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1204
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1205
+ readonly name: import("@angular/core").InputSignal<string>;
1206
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
1207
+ private readonly radios;
1208
+ /** Nom partage par les options : sans lui, chaque radio forme son propre groupe. */
1209
+ private readonly nomParDefaut;
1210
+ /** L'erreur se montre apres la sortie du groupe, comme son message. */
1211
+ protected readonly enErreur: import("@angular/core").Signal<boolean>;
1212
+ /** L'aide du groupe, suivie des raisons de sa desactivation. */
1213
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
1214
+ protected nomDuGroupe(): string;
1215
+ protected identifiantOption(indice: number): string;
1216
+ protected identifiantAide(indice: number): string;
1217
+ /** L'aide d'une option : la sienne, et la raison de sa desactivation. */
1218
+ protected aideDe(option: OptionRadio): string | null;
1219
+ /**
1220
+ * Focus sur l'option du MODELE, sinon la premiere active : c'est l'arret de tabulation du groupe.
1221
+ * Lu sur l'etat (valeur et options), et non sur le DOM coche.
1222
+ */
1223
+ focus(options?: FocusOptions): void;
1224
+ protected choisir(evenement: Event, valeur: string): void;
1225
+ /** En lecture seule, le clic est annule avant que l'option ne change. */
1226
+ protected surClic(evenement: MouseEvent): void;
1227
+ protected aLaSortie(evenement: FocusEvent): void;
1228
+ static ɵfac: i0.ɵɵFactoryDeclaration<StRadioGroup, never>;
1229
+ static ɵcmp: i0.ɵɵComponentDeclaration<StRadioGroup, "st-radio-group", never, {
1230
+ "legende": {
1231
+ "alias": "legende";
1232
+ "required": true;
1233
+ "isSignal": true;
1234
+ };
1235
+ "aide": {
1236
+ "alias": "aide";
1237
+ "required": false;
1238
+ "isSignal": true;
1239
+ };
1240
+ "options": {
1241
+ "alias": "options";
1242
+ "required": true;
1243
+ "isSignal": true;
1244
+ };
1245
+ "disposition": {
1246
+ "alias": "disposition";
1247
+ "required": false;
1248
+ "isSignal": true;
1249
+ };
1250
+ "value": {
1251
+ "alias": "value";
1252
+ "required": false;
1253
+ "isSignal": true;
1254
+ };
1255
+ "errors": {
1256
+ "alias": "errors";
1257
+ "required": false;
1258
+ "isSignal": true;
1259
+ };
1260
+ "touched": {
1261
+ "alias": "touched";
1262
+ "required": false;
1263
+ "isSignal": true;
1264
+ };
1265
+ "dirty": {
1266
+ "alias": "dirty";
1267
+ "required": false;
1268
+ "isSignal": true;
1269
+ };
1270
+ "pending": {
1271
+ "alias": "pending";
1272
+ "required": false;
1273
+ "isSignal": true;
1274
+ };
1275
+ "disabled": {
1276
+ "alias": "disabled";
1277
+ "required": false;
1278
+ "isSignal": true;
1279
+ };
1280
+ "disabledReasons": {
1281
+ "alias": "disabledReasons";
1282
+ "required": false;
1283
+ "isSignal": true;
1284
+ };
1285
+ "readonly": {
1286
+ "alias": "readonly";
1287
+ "required": false;
1288
+ "isSignal": true;
1289
+ };
1290
+ "required": {
1291
+ "alias": "required";
1292
+ "required": false;
1293
+ "isSignal": true;
1294
+ };
1295
+ "hidden": {
1296
+ "alias": "hidden";
1297
+ "required": false;
1298
+ "isSignal": true;
1299
+ };
1300
+ "name": {
1301
+ "alias": "name";
1302
+ "required": false;
1303
+ "isSignal": true;
1304
+ };
1305
+ }, {
1306
+ "value": "valueChange";
1307
+ "touch": "touch";
1308
+ }, never, never, true, never>;
1309
+ }
1310
+ /**
1311
+ * Une option du groupe : la forme d'option de toutes les listes (`OptionDeListe`), avec la RAISON
1312
+ * d'une option desactivee, lue en aide (« Obligatoire pour les virements. ») plutot que tue. La meme
1313
+ * forme que `OptionRadio`.
416
1314
  */
417
- declare class StRadioGroup implements FormValueControl<string> {
418
- private readonly element;
419
- readonly legende: _angular_core.InputSignal<string>;
420
- readonly aide: _angular_core.InputSignal<string | null>;
421
- readonly options: _angular_core.InputSignal<readonly OptionRadio[]>;
422
- /** Contrat Signal Forms. */
423
- readonly value: _angular_core.ModelSignal<string>;
424
- readonly errors: _angular_core.InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
425
- readonly touched: _angular_core.InputSignalWithTransform<boolean, unknown>;
426
- readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
427
- readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
428
- readonly hidden: _angular_core.InputSignalWithTransform<boolean, unknown>;
429
- readonly name: _angular_core.InputSignal<string>;
430
- readonly touch: _angular_core.OutputEmitterRef<void>;
431
- /** Nom partage par les options : sans lui, chaque radio forme son propre groupe. */
432
- private readonly nomParDefaut;
433
- protected nomDuGroupe(): string;
434
- protected identifiantAide(indice: number): string;
435
- /** Focus sur l'option cochee, sinon la premiere disponible : c'est l'arret du groupe. */
436
- focus(options?: FocusOptions): void;
437
- protected choisir(valeur: string): void;
438
- protected aLaSortie(evenement: FocusEvent): void;
439
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StRadioGroup, never>;
440
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StRadioGroup, "st-radio-group", never, { "legende": { "alias": "legende"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hidden": { "alias": "hidden"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, never, never, true, never>;
1315
+ export interface OptionDeChoix extends OptionDeListe {
1316
+ readonly raison?: string;
1317
+ }
1318
+ /** Ce que montre la case « Tout selectionner » : rien, une partie, ou toutes les options libres. */
1319
+ type EtatDuTout$1 = 'vide' | 'partiel' | 'coche';
1320
+ /**
1321
+ * Groupe de cases a cocher, integre a Signal Forms : la valeur est la LISTE des options cochees.
1322
+ *
1323
+ * ```html
1324
+ * <st-checkbox-group
1325
+ * legende="Canaux de notification"
1326
+ * toutSelectionner
1327
+ * [options]="canaux"
1328
+ * [formField]="preferences.canaux"
1329
+ * />
1330
+ * ```
1331
+ *
1332
+ * Le pendant multiple de `st-radio-group`, sur le meme `st-fieldset` : la legende pose la
1333
+ * question, chaque option est une case native de 24 px sur une ligne de 44 px au moins (la hauteur
1334
+ * de commande), avec son aide et la raison de sa desactivation.
1335
+ *
1336
+ * ⚠️ **Les bornes viennent du schema** : `minLength(chemin.canaux, 1)` et `maxLength(chemin.canaux,
1337
+ * 3)` de Signal Forms comptent les options cochees ; leur message parle d'options, pas de
1338
+ * caracteres (`messageDErreur` lit la valeur visee). Le groupe n'ajoute aucune entree de borne.
1339
+ *
1340
+ * ⚠️ **Le message d'erreur porte sur le groupe**, par `st-fieldset` : « Choisissez au moins
1341
+ * 1 option. », une fois. L'ETAT d'erreur, lui, est pose sur chaque case (`aria-invalid`), comme
1342
+ * sur chaque radio : le lecteur d'ecran le dit sur la case ou se trouve le focus (WCAG 4.1.2).
1343
+ * L'obligation se dit dans la legende, en texte : `aria-required` sur une case voudrait dire que
1344
+ * CETTE case doit etre cochee.
1345
+ *
1346
+ * `toutSelectionner` pose une case « Tout selectionner » en tete du groupe, hors de la valeur : elle
1347
+ * est cochee quand toutes les options libres le sont, PARTIELLE (`indeterminate`, annonce
1348
+ * « mixed ») quand une partie l'est, et nomme par `aria-controls` les cases qu'elle commande. Un
1349
+ * clic coche toutes les options libres, ou les decoche toutes quand elles l'etaient deja. Une
1350
+ * option desactivee garde son etat : la personne ne peut pas la changer, la case « Tout » non plus.
1351
+ *
1352
+ * `touch` n'est emis que lorsque le focus QUITTE le groupe : passer d'une case a l'autre n'est pas
1353
+ * une fin de saisie, et « choisissez au moins une option » n'a pas a surgir pendant qu'on coche.
1354
+ *
1355
+ * `readonly` : les cases restent focalisables et lues (`aria-readonly`), mais ni le clic ni Espace
1356
+ * ne les basculent, la case « Tout » comprise.
1357
+ *
1358
+ * La valeur suit l'ordre des options, quel que soit l'ordre des clics ; une valeur que les options
1359
+ * ne connaissent pas est gardee a la fin, jamais effacee en silence.
1360
+ */
1361
+ export declare class StCheckboxGroup implements FormValueControl<readonly string[]> {
1362
+ private readonly element;
1363
+ private readonly libelles;
1364
+ readonly legende: import("@angular/core").InputSignal<string>;
1365
+ readonly aide: import("@angular/core").InputSignal<string | null>;
1366
+ readonly options: import("@angular/core").InputSignal<readonly OptionDeChoix[]>;
1367
+ /** `en-ligne` : cases cote a cote (deux ou trois choix courts), en colonne quand la place manque. */
1368
+ readonly disposition: import("@angular/core").InputSignal<DispositionDeGroupe>;
1369
+ /** Une case « Tout selectionner » en tete du groupe, partielle quand une partie est cochee. */
1370
+ readonly toutSelectionner: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1371
+ /** Contrat Signal Forms. */
1372
+ readonly value: import("@angular/core").ModelSignal<readonly string[]>;
1373
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
1374
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1375
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1376
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1377
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1378
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
1379
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1380
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1381
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1382
+ readonly name: import("@angular/core").InputSignal<string>;
1383
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
1384
+ private readonly cases;
1385
+ /** Racine des identifiants des cases et de leurs aides. */
1386
+ private readonly racine;
1387
+ protected readonly identifiantDuTout: string;
1388
+ protected readonly libelleDuTout: import("@angular/core").Signal<string>;
1389
+ /** L'erreur se montre apres la sortie du groupe, comme son message. */
1390
+ protected readonly enErreur: import("@angular/core").Signal<boolean>;
1391
+ private readonly choisies;
1392
+ /** Les options que la personne peut changer : celles que la case « Tout » commande. */
1393
+ private readonly libres;
1394
+ protected readonly etatDuTout: import("@angular/core").Signal<EtatDuTout$1>;
1395
+ /** Les cases que commande la case « Tout », pour `aria-controls`. */
1396
+ protected readonly casesCommandees: import("@angular/core").Signal<string>;
1397
+ /** L'aide du groupe, suivie des raisons de sa desactivation. */
1398
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
1399
+ protected estChoisie(valeur: string): boolean;
1400
+ protected identifiantOption(indice: number): string;
1401
+ protected identifiantAide(indice: number): string;
1402
+ /** L'aide d'une option : la sienne, et la raison de sa desactivation. */
1403
+ protected aideDe(option: OptionDeChoix): string | null;
1404
+ /**
1405
+ * Focus sur la premiere option libre (Signal Forms l'appelle pour « choisissez au moins une
1406
+ * option ») : une case qui compte, jamais la case « Tout ».
1407
+ */
1408
+ focus(options?: FocusOptions): void;
1409
+ /** En lecture seule, le clic (souris, ou Espace qui passe par lui) est annule avant la bascule. */
1410
+ protected surClic(evenement: MouseEvent): void;
1411
+ protected basculer(evenement: Event, valeur: string): void;
1412
+ protected basculerTout(evenement: Event): void;
1413
+ protected aLaSortie(evenement: FocusEvent): void;
1414
+ /** Les valeurs dans l'ordre des options, puis celles que les options ne connaissent pas. */
1415
+ private dansLOrdre;
1416
+ static ɵfac: i0.ɵɵFactoryDeclaration<StCheckboxGroup, never>;
1417
+ static ɵcmp: i0.ɵɵComponentDeclaration<StCheckboxGroup, "st-checkbox-group", never, {
1418
+ "legende": {
1419
+ "alias": "legende";
1420
+ "required": true;
1421
+ "isSignal": true;
1422
+ };
1423
+ "aide": {
1424
+ "alias": "aide";
1425
+ "required": false;
1426
+ "isSignal": true;
1427
+ };
1428
+ "options": {
1429
+ "alias": "options";
1430
+ "required": true;
1431
+ "isSignal": true;
1432
+ };
1433
+ "disposition": {
1434
+ "alias": "disposition";
1435
+ "required": false;
1436
+ "isSignal": true;
1437
+ };
1438
+ "toutSelectionner": {
1439
+ "alias": "toutSelectionner";
1440
+ "required": false;
1441
+ "isSignal": true;
1442
+ };
1443
+ "value": {
1444
+ "alias": "value";
1445
+ "required": false;
1446
+ "isSignal": true;
1447
+ };
1448
+ "errors": {
1449
+ "alias": "errors";
1450
+ "required": false;
1451
+ "isSignal": true;
1452
+ };
1453
+ "touched": {
1454
+ "alias": "touched";
1455
+ "required": false;
1456
+ "isSignal": true;
1457
+ };
1458
+ "dirty": {
1459
+ "alias": "dirty";
1460
+ "required": false;
1461
+ "isSignal": true;
1462
+ };
1463
+ "pending": {
1464
+ "alias": "pending";
1465
+ "required": false;
1466
+ "isSignal": true;
1467
+ };
1468
+ "disabled": {
1469
+ "alias": "disabled";
1470
+ "required": false;
1471
+ "isSignal": true;
1472
+ };
1473
+ "disabledReasons": {
1474
+ "alias": "disabledReasons";
1475
+ "required": false;
1476
+ "isSignal": true;
1477
+ };
1478
+ "readonly": {
1479
+ "alias": "readonly";
1480
+ "required": false;
1481
+ "isSignal": true;
1482
+ };
1483
+ "required": {
1484
+ "alias": "required";
1485
+ "required": false;
1486
+ "isSignal": true;
1487
+ };
1488
+ "hidden": {
1489
+ "alias": "hidden";
1490
+ "required": false;
1491
+ "isSignal": true;
1492
+ };
1493
+ "name": {
1494
+ "alias": "name";
1495
+ "required": false;
1496
+ "isSignal": true;
1497
+ };
1498
+ }, {
1499
+ "value": "valueChange";
1500
+ "touch": "touch";
1501
+ }, never, never, true, never>;
1502
+ }
1503
+ /** Une ligne de la matrice : un evenement (« Operation carte »), et sa precision eventuelle. */
1504
+ export interface LigneDeMatrice {
1505
+ readonly cle: string;
1506
+ readonly libelle: string;
1507
+ readonly precision?: string;
1508
+ }
1509
+ /** Une colonne de la matrice : un canal (« Courriel »), et son icone eventuelle (decorative). */
1510
+ export interface ColonneDeMatrice {
1511
+ readonly cle: string;
1512
+ readonly libelle: string;
1513
+ readonly icone?: Icone;
1514
+ }
1515
+ /** Une cellule qu'on ne peut pas changer, et pourquoi (D39 : elle reste focalisable et le dit). */
1516
+ export interface CelluleIndisponible {
1517
+ /** `ligne:colonne`. */
1518
+ readonly cle: string;
1519
+ readonly raison: string;
1520
+ }
1521
+ /**
1522
+ * `formulaire` : la valeur part avec le formulaire (contrat Signal Forms, erreurs a la sortie).
1523
+ * `immediat` : chaque case s'applique tout de suite (un reglage, UX-8) : aucune erreur de
1524
+ * validation, `aria-busy` sur les cellules que l'application enregistre, et l'issue de chaque
1525
+ * enregistrement annoncee.
1526
+ */
1527
+ export type ModeDeMatrice = 'formulaire' | 'immediat';
1528
+ type EtatDuTout = 'vide' | 'partiel' | 'coche';
1529
+ /**
1530
+ * Matrice de cases : des evenements en lignes, des canaux en colonnes (preferences d'alertes,
1531
+ * droits par role, documents par canal). La valeur est la liste des cles `ligne:colonne` cochees.
1532
+ *
1533
+ * ```html
1534
+ * <st-choice-matrix
1535
+ * legende="Alertes"
1536
+ * [lignes]="evenements"
1537
+ * [colonnes]="canaux"
1538
+ * toutParColonne
1539
+ * [formField]="preferences.alertes"
1540
+ * />
1541
+ * ```
1542
+ *
1543
+ * ⚠️ **Un tableau natif, pas une grille ARIA ni des cartes** (UX-5) : `caption` pour son nom,
1544
+ * `th scope="col"` et `th scope="row"` : le lecteur d'ecran lit l'en-tete de ligne et de colonne en
1545
+ * se deplacant. Chaque case porte son nom COMPLET et unique (« Operation carte, Courriel ») :
1546
+ * quinze cases « Courriel » seraient indiscernables hors du tableau (liste des champs d'un lecteur
1547
+ * d'ecran). Sous la largeur du tableau, il defile dans une zone NOMMEE par la legende, focalisable
1548
+ * quand elle deborde ; il ne se transforme jamais en cartes.
1549
+ *
1550
+ * `toutParColonne` et `toutParLigne` posent une case « tout » dans chaque en-tete : partielle
1551
+ * (`indeterminate`) quand une partie des cases disponibles l'est, elle coche ou decoche les cases
1552
+ * disponibles de sa ligne ou de sa colonne. Une cellule indisponible (`cellulesIndisponibles`) reste
1553
+ * focalisable (`aria-disabled`, D39), dit sa raison, et garde son etat.
1554
+ *
1555
+ * Le message d'erreur porte sur la matrice (mode `formulaire`), une fois, a la sortie de la matrice ;
1556
+ * l'etat (`aria-invalid`) sur chaque case. `readonly` : rien ne bascule. `focus()` : la premiere case
1557
+ * disponible.
1558
+ *
1559
+ * ⚠️ **Mode immediat : l'issue de l'enregistrement se dit, et elle seule.** La case native dit
1560
+ * deja son nouvel etat a la bascule ; l'annoncer en plus le disait deux fois (audit UI du
1561
+ * 2026-09-27, D-21). Une cellule basculee par la personne, puis posee dans `cellulesEnAttente` par
1562
+ * l'application, se dit en en sortant : enregistree (`celluleBasculee`) si elle garde l'etat
1563
+ * demande, refusee (`choixNonEnregistre`) si l'application l'a rendu. L'application rend donc la
1564
+ * valeur d'avant AVANT ou AVEC la sortie de `cellulesEnAttente`. Sans `cellulesEnAttente`, rien de
1565
+ * plus ne se dit que la case elle-meme.
1566
+ */
1567
+ export declare class StChoiceMatrix implements FormValueControl<readonly string[]> {
1568
+ private readonly element;
1569
+ private readonly destruction;
1570
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
1571
+ private readonly locale;
1572
+ readonly legende: import("@angular/core").InputSignal<string>;
1573
+ readonly aide: import("@angular/core").InputSignal<string | null>;
1574
+ readonly lignes: import("@angular/core").InputSignal<readonly LigneDeMatrice[]>;
1575
+ readonly colonnes: import("@angular/core").InputSignal<readonly ColonneDeMatrice[]>;
1576
+ readonly toutParColonne: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1577
+ readonly toutParLigne: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1578
+ readonly cellulesIndisponibles: import("@angular/core").InputSignal<readonly CelluleIndisponible[]>;
1579
+ readonly mode: import("@angular/core").InputSignal<ModeDeMatrice>;
1580
+ /** Mode `immediat` : les cles `ligne:colonne` que l'application enregistre (`aria-busy`). */
1581
+ readonly cellulesEnAttente: import("@angular/core").InputSignal<readonly string[]>;
1582
+ /** Contrat Signal Forms. */
1583
+ readonly value: import("@angular/core").ModelSignal<readonly string[]>;
1584
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
1585
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1586
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1587
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1588
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1589
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
1590
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1591
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1592
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1593
+ readonly name: import("@angular/core").InputSignal<string>;
1594
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
1595
+ private readonly cases;
1596
+ private readonly zone;
1597
+ private readonly racine;
1598
+ protected readonly identifiants: {
1599
+ readonly legende: `${string}-legende`;
1600
+ readonly aide: `${string}-aide`;
1601
+ readonly erreur: `${string}-erreur`;
1602
+ readonly deborde: `${string}-deborde`;
1603
+ };
1604
+ protected readonly annonce: AnnonceLocale;
1605
+ /** La zone deborde : elle devient focalisable, pour defiler au clavier (UX-6). */
1606
+ protected readonly deborde: import("@angular/core").WritableSignal<boolean>;
1607
+ private readonly choisies;
1608
+ private readonly indisponibles;
1609
+ private readonly enAttente;
1610
+ /** Mode immediat : les bascules de la personne dont l'issue n'est pas encore dite, par cle. */
1611
+ private readonly bascules;
1612
+ /** Les erreurs ne se disent qu'en mode formulaire, apres la sortie de la matrice. */
1613
+ protected readonly enErreur: import("@angular/core").Signal<boolean>;
1614
+ protected readonly messages: import("@angular/core").Signal<string[]>;
1615
+ /** L'aide de la matrice, suivie des raisons de sa desactivation. */
1616
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
1617
+ /** Ce qui decrit le tableau : l'aide, le debordement, puis l'erreur. */
1618
+ protected readonly descriptions: import("@angular/core").Signal<string | null>;
1619
+ constructor();
1620
+ /** Protegee : lue par la classe et son gabarit seuls, elle n'est pas de la surface (Q-17). */
1621
+ protected cle(ligne: LigneDeMatrice, colonne: ColonneDeMatrice): string;
1622
+ protected estCochee(ligne: LigneDeMatrice, colonne: ColonneDeMatrice): boolean;
1623
+ protected raisonDe(ligne: LigneDeMatrice, colonne: ColonneDeMatrice): string | null;
1624
+ protected estEnAttente(ligne: LigneDeMatrice, colonne: ColonneDeMatrice): boolean;
1625
+ protected idColonne(indice: number): string;
1626
+ protected idLigne(indice: number): string;
1627
+ protected idCase(ligne: number, colonne: number): string;
1628
+ protected idRaison(ligne: number, colonne: number): string;
1629
+ /** Les cases disponibles d'une colonne ou d'une ligne, par leurs cles. */
1630
+ private disponibles;
1631
+ private clesDeColonne;
1632
+ private clesDeLigne;
1633
+ private etatDe;
1634
+ protected etatDeColonne(colonne: ColonneDeMatrice): EtatDuTout;
1635
+ protected etatDeLigne(ligne: LigneDeMatrice): EtatDuTout;
1636
+ /** Les cases qu'une case « tout » commande, pour `aria-controls`. */
1637
+ protected casesDeColonne(colonne: ColonneDeMatrice, indice: number): string;
1638
+ protected casesDeLigne(ligne: LigneDeMatrice, indice: number): string;
1639
+ /** La premiere case disponible : ce que Signal Forms appelle pour une erreur de la matrice. */
1640
+ focus(options?: FocusOptions): void;
1641
+ /**
1642
+ * Le clic est annule AVANT la bascule quand rien ne doit changer : lecture seule, cellule
1643
+ * indisponible (aucun etat coche transitoire, aucun evenement `change`).
1644
+ */
1645
+ protected surClic(evenement: MouseEvent, indisponible?: boolean): void;
1646
+ protected basculer(evenement: Event, ligne: LigneDeMatrice, colonne: ColonneDeMatrice): void;
1647
+ protected basculerColonne(evenement: Event, colonne: ColonneDeMatrice): void;
1648
+ protected basculerLigne(evenement: Event, ligne: LigneDeMatrice): void;
1649
+ private basculerTout;
1650
+ /** La valeur dans l'ordre de la matrice (lignes, puis colonnes), les cles inconnues a la fin. */
1651
+ private ecrire;
1652
+ protected aLaSortie(evenement: FocusEvent): void;
1653
+ static ɵfac: i0.ɵɵFactoryDeclaration<StChoiceMatrix, never>;
1654
+ static ɵcmp: i0.ɵɵComponentDeclaration<StChoiceMatrix, "st-choice-matrix", never, {
1655
+ "legende": {
1656
+ "alias": "legende";
1657
+ "required": true;
1658
+ "isSignal": true;
1659
+ };
1660
+ "aide": {
1661
+ "alias": "aide";
1662
+ "required": false;
1663
+ "isSignal": true;
1664
+ };
1665
+ "lignes": {
1666
+ "alias": "lignes";
1667
+ "required": true;
1668
+ "isSignal": true;
1669
+ };
1670
+ "colonnes": {
1671
+ "alias": "colonnes";
1672
+ "required": true;
1673
+ "isSignal": true;
1674
+ };
1675
+ "toutParColonne": {
1676
+ "alias": "toutParColonne";
1677
+ "required": false;
1678
+ "isSignal": true;
1679
+ };
1680
+ "toutParLigne": {
1681
+ "alias": "toutParLigne";
1682
+ "required": false;
1683
+ "isSignal": true;
1684
+ };
1685
+ "cellulesIndisponibles": {
1686
+ "alias": "cellulesIndisponibles";
1687
+ "required": false;
1688
+ "isSignal": true;
1689
+ };
1690
+ "mode": {
1691
+ "alias": "mode";
1692
+ "required": false;
1693
+ "isSignal": true;
1694
+ };
1695
+ "cellulesEnAttente": {
1696
+ "alias": "cellulesEnAttente";
1697
+ "required": false;
1698
+ "isSignal": true;
1699
+ };
1700
+ "value": {
1701
+ "alias": "value";
1702
+ "required": false;
1703
+ "isSignal": true;
1704
+ };
1705
+ "errors": {
1706
+ "alias": "errors";
1707
+ "required": false;
1708
+ "isSignal": true;
1709
+ };
1710
+ "touched": {
1711
+ "alias": "touched";
1712
+ "required": false;
1713
+ "isSignal": true;
1714
+ };
1715
+ "dirty": {
1716
+ "alias": "dirty";
1717
+ "required": false;
1718
+ "isSignal": true;
1719
+ };
1720
+ "pending": {
1721
+ "alias": "pending";
1722
+ "required": false;
1723
+ "isSignal": true;
1724
+ };
1725
+ "disabled": {
1726
+ "alias": "disabled";
1727
+ "required": false;
1728
+ "isSignal": true;
1729
+ };
1730
+ "disabledReasons": {
1731
+ "alias": "disabledReasons";
1732
+ "required": false;
1733
+ "isSignal": true;
1734
+ };
1735
+ "readonly": {
1736
+ "alias": "readonly";
1737
+ "required": false;
1738
+ "isSignal": true;
1739
+ };
1740
+ "required": {
1741
+ "alias": "required";
1742
+ "required": false;
1743
+ "isSignal": true;
1744
+ };
1745
+ "hidden": {
1746
+ "alias": "hidden";
1747
+ "required": false;
1748
+ "isSignal": true;
1749
+ };
1750
+ "name": {
1751
+ "alias": "name";
1752
+ "required": false;
1753
+ "isSignal": true;
1754
+ };
1755
+ }, {
1756
+ "value": "valueChange";
1757
+ "touch": "touch";
1758
+ }, never, never, true, never>;
1759
+ }
1760
+ /**
1761
+ * Largeur LOGIQUE d'un champ dans une rangee : sa part de la ligne, jamais des px. Un champ en px
1762
+ * ne suit ni la police de la personne ni le reflow a 320 px ; une part, si.
1763
+ */
1764
+ export type LargeurDeChamp = 'etroite' | 'normale' | 'large';
1765
+ /**
1766
+ * Deux ou trois champs courts cote a cote : code postal et ville, indicatif et numero, quantite et
1767
+ * unite.
1768
+ *
1769
+ * ```html
1770
+ * <st-form-row [largeurs]="['etroite', 'large']">
1771
+ * <st-input libelle="Code postal" [formField]="adresse.codePostal" />
1772
+ * <st-input libelle="Ville" [formField]="adresse.ville" />
1773
+ * </st-form-row>
1774
+ * ```
1775
+ *
1776
+ * ⚠️ **Aucun etat, aucune semantique** : chaque champ garde son `st-form-field`, son etiquette et
1777
+ * ses erreurs ; la rangee n'ajoute ni role ni nom. L'ordre du DOM est l'ordre de lecture et de
1778
+ * tabulation.
1779
+ *
1780
+ * La rangee repasse en colonne sous la rupture `sm` de SON conteneur (30 rem), et non de l'ecran :
1781
+ * dans une colonne etroite comme a 320 px, et quand la personne agrandit le texte a 200 % (le
1782
+ * conteneur, mesure en rem, retrecit d'autant). Les colonnes : `colonnes` (2, 3, ou `auto`, autant
1783
+ * que la place en laisse), ou `largeurs`, une part logique par champ ; une largeur inconnue (des px)
1784
+ * est refusee en developpement et vaut `normale`.
1785
+ */
1786
+ export declare class StFormRow {
1787
+ /** `auto` : autant de colonnes que la place en laisse, 10 rem au moins chacune. */
1788
+ readonly colonnes: import("@angular/core").InputSignal<2 | 3 | "auto">;
1789
+ /** Une part logique par champ, dans l'ordre ; l'emporte sur `colonnes`. */
1790
+ readonly largeurs: import("@angular/core").InputSignal<readonly LargeurDeChamp[] | null>;
1791
+ protected readonly gabarit: import("@angular/core").Signal<string>;
1792
+ static ɵfac: i0.ɵɵFactoryDeclaration<StFormRow, never>;
1793
+ static ɵcmp: i0.ɵɵComponentDeclaration<StFormRow, "st-form-row", never, {
1794
+ "colonnes": {
1795
+ "alias": "colonnes";
1796
+ "required": false;
1797
+ "isSignal": true;
1798
+ };
1799
+ "largeurs": {
1800
+ "alias": "largeurs";
1801
+ "required": false;
1802
+ "isSignal": true;
1803
+ };
1804
+ }, {}, never, ["*"], true, never>;
1805
+ }
1806
+ /**
1807
+ * Ce qu'un `st-consent-group` offre a ses `st-consent-row` : la valeur de chaque cle, l'ecriture
1808
+ * d'une decision, et les etats du groupe (mode, desactive, lecture seule, erreur). Une ligne hors
1809
+ * d'un groupe n'a pas de sens (sa valeur vit dans le groupe) : elle echoue a l'injection.
1810
+ */
1811
+ interface GroupeDeConsentements {
1812
+ readonly mode: Signal<'formulaire' | 'immediat'>;
1813
+ readonly desactive: Signal<boolean>;
1814
+ readonly lectureSeule: Signal<boolean>;
1815
+ readonly enErreur: Signal<boolean>;
1816
+ valeurDe(cle: string): boolean | undefined;
1817
+ ecrire(cle: string, valeur: boolean): void;
1818
+ }
1819
+ declare const ST_GROUPE_DE_CONSENTEMENTS: InjectionToken<GroupeDeConsentements>;
1820
+ /**
1821
+ * `formulaire` : les choix partent avec le formulaire (cases, contrat Signal Forms, erreurs a la
1822
+ * sortie). `immediat` : chaque choix s'applique tout de suite (interrupteurs, UX-8) : aucune erreur
1823
+ * de validation ; l'application enregistre chaque `decision` et dit un refus par la ligne.
1824
+ */
1825
+ export type ModeDeConsentement = 'formulaire' | 'immediat';
1826
+ /**
1827
+ * Consentements et acceptations : finalites RGPD (prospection, partage, profilage), CGU a une
1828
+ * version donnee, mandat SEPA. La valeur est un dictionnaire `cle -> accepte` ; chaque ligne est un
1829
+ * `st-consent-row`.
1830
+ *
1831
+ * ```html
1832
+ * <st-consent-group legende="Vos choix" toutAccepter toutRefuser [formField]="inscription.choix">
1833
+ * <st-consent-row cle="offres" titre="Offres commerciales" description="Par courriel." />
1834
+ * <st-consent-row cle="cgu" titre="Conditions generales" obligatoire versionDuDocument="3.2" />
1835
+ * </st-consent-group>
1836
+ * ```
1837
+ *
1838
+ * Un `st-fieldset` (la legende pose la question). `toutAccepter` et `toutRefuser` posent deux boutons
1839
+ * de MEME POIDS (CNIL : refuser aussi simplement qu'accepter ; deux boutons secondaires, jamais un
1840
+ * lien ni un bouton plus discret que l'autre). Ils n'agissent que sur les lignes FACULTATIVES : une
1841
+ * ligne obligatoire (les CGU) ne s'accepte que par sa propre case, et « Tout refuser » ne la decoche
1842
+ * pas. Le retrait d'un consentement n'exige aucune confirmation.
1843
+ *
1844
+ * Le message d'erreur porte sur le groupe (mode formulaire), a la sortie du groupe ; `aria-invalid`
1845
+ * sur chaque ligne obligatoire non acceptee. `readonly` : rien ne change (les boutons restent
1846
+ * focalisables, `aria-disabled`). `focus()` : la premiere ligne.
1847
+ */
1848
+ export declare class StConsentGroup implements FormValueControl<Readonly<Record<string, boolean>>>, GroupeDeConsentements {
1849
+ private readonly element;
1850
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
1851
+ readonly legende: import("@angular/core").InputSignal<string>;
1852
+ readonly aide: import("@angular/core").InputSignal<string | null>;
1853
+ readonly mode: import("@angular/core").InputSignal<ModeDeConsentement>;
1854
+ readonly toutAccepter: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1855
+ readonly toutRefuser: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1856
+ /** Contrat Signal Forms. */
1857
+ readonly value: import("@angular/core").ModelSignal<Readonly<Record<string, boolean>>>;
1858
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
1859
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1860
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1861
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1862
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1863
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
1864
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1865
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1866
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1867
+ readonly name: import("@angular/core").InputSignal<string>;
1868
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
1869
+ private readonly lignes;
1870
+ readonly desactive: import("@angular/core").Signal<boolean>;
1871
+ readonly lectureSeule: import("@angular/core").Signal<boolean>;
1872
+ /** Les erreurs ne se disent qu'en mode formulaire, apres la sortie du groupe. */
1873
+ readonly enErreur: import("@angular/core").Signal<boolean>;
1874
+ /** L'aide du groupe, suivie des raisons de sa desactivation. */
1875
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
1876
+ valeurDe(cle: string): boolean | undefined;
1877
+ ecrire(cle: string, valeur: boolean): void;
1878
+ focus(options?: FocusOptions): void;
1879
+ /** Les lignes FACULTATIVES seulement : une ligne obligatoire ne s'accepte que par sa case. */
1880
+ protected toutDecider(valeur: boolean): void;
1881
+ protected aLaSortie(evenement: FocusEvent): void;
1882
+ static ɵfac: i0.ɵɵFactoryDeclaration<StConsentGroup, never>;
1883
+ static ɵcmp: i0.ɵɵComponentDeclaration<StConsentGroup, "st-consent-group", never, {
1884
+ "legende": {
1885
+ "alias": "legende";
1886
+ "required": true;
1887
+ "isSignal": true;
1888
+ };
1889
+ "aide": {
1890
+ "alias": "aide";
1891
+ "required": false;
1892
+ "isSignal": true;
1893
+ };
1894
+ "mode": {
1895
+ "alias": "mode";
1896
+ "required": false;
1897
+ "isSignal": true;
1898
+ };
1899
+ "toutAccepter": {
1900
+ "alias": "toutAccepter";
1901
+ "required": false;
1902
+ "isSignal": true;
1903
+ };
1904
+ "toutRefuser": {
1905
+ "alias": "toutRefuser";
1906
+ "required": false;
1907
+ "isSignal": true;
1908
+ };
1909
+ "value": {
1910
+ "alias": "value";
1911
+ "required": false;
1912
+ "isSignal": true;
1913
+ };
1914
+ "errors": {
1915
+ "alias": "errors";
1916
+ "required": false;
1917
+ "isSignal": true;
1918
+ };
1919
+ "touched": {
1920
+ "alias": "touched";
1921
+ "required": false;
1922
+ "isSignal": true;
1923
+ };
1924
+ "dirty": {
1925
+ "alias": "dirty";
1926
+ "required": false;
1927
+ "isSignal": true;
1928
+ };
1929
+ "pending": {
1930
+ "alias": "pending";
1931
+ "required": false;
1932
+ "isSignal": true;
1933
+ };
1934
+ "disabled": {
1935
+ "alias": "disabled";
1936
+ "required": false;
1937
+ "isSignal": true;
1938
+ };
1939
+ "disabledReasons": {
1940
+ "alias": "disabledReasons";
1941
+ "required": false;
1942
+ "isSignal": true;
1943
+ };
1944
+ "readonly": {
1945
+ "alias": "readonly";
1946
+ "required": false;
1947
+ "isSignal": true;
1948
+ };
1949
+ "required": {
1950
+ "alias": "required";
1951
+ "required": false;
1952
+ "isSignal": true;
1953
+ };
1954
+ "hidden": {
1955
+ "alias": "hidden";
1956
+ "required": false;
1957
+ "isSignal": true;
1958
+ };
1959
+ "name": {
1960
+ "alias": "name";
1961
+ "required": false;
1962
+ "isSignal": true;
1963
+ };
1964
+ }, {
1965
+ "value": "valueChange";
1966
+ "touch": "touch";
1967
+ }, ["lignes"], ["*"], true, never>;
1968
+ }
1969
+ /** Ce qu'une ligne emet a chaque decision de la personne : l'application le journalise (audit). */
1970
+ export interface DecisionDeConsentement {
1971
+ readonly cle: string;
1972
+ readonly valeur: boolean;
1973
+ /** La version du document que la personne a vue en decidant. */
1974
+ readonly version: string | null;
1975
+ }
1976
+ /**
1977
+ * Un consentement dans un `st-consent-group` : une finalite (« Offres commerciales »), les CGU a une
1978
+ * version donnee, un mandat SEPA.
1979
+ *
1980
+ * ```html
1981
+ * <st-consent-row cle="cgu" titre="Conditions generales" obligatoire versionDuDocument="3.2">
1982
+ * <span stLibelle>J'accepte les <a stLink href="/cgu">conditions generales</a></span>
1983
+ * </st-consent-row>
1984
+ * ```
1985
+ *
1986
+ * Une case (mode `formulaire` du groupe) ou un interrupteur (mode `immediat`, UX-8), son titre
1987
+ * (`titre`, et un titre riche projete `[stLibelle]` pour le lien vers le document : le lien reste
1988
+ * un arret de tabulation a part, hors de la case), sa description et la mention de version, datee
1989
+ * par `decideLe` (« Version 3.2, acceptee le 12 septembre 2026. »), reliees a la case.
1990
+ *
1991
+ * ⚠️ **Jamais cochee d'office** (CNIL) : une cle a `true` sans decision enregistree (`decideLe`)
1992
+ * ni decision de la personne dans la page s'affiche DECOCHEE, et le developpement le signale. Une
1993
+ * ligne `obligatoire` dit « (obligatoire) » en texte ; les actions de groupe ne la touchent jamais.
1994
+ *
1995
+ * Mode immediat : `enregistrement` pose `aria-busy` pendant que l'application enregistre ; un
1996
+ * `refus` (le message du serveur) remet la ligne a son etat d'avant la decision, s'affiche relie a
1997
+ * la ligne et s'annonce (« Choix non enregistre. »). Chaque decision sort par `decision`
1998
+ * (`{ cle, valeur, version }`) : le socle ne journalise ni n'appelle rien. L'application remet
1999
+ * `refus` a `null` a chaque nouvelle decision : un meme message deux fois de suite ne change rien
2000
+ * a un signal, et le second refus ne rendrait rien.
2001
+ *
2002
+ * ⚠️ **L'enregistrement avale toute nouvelle decision** (la case, et les actions du groupe) :
2003
+ * `aria-disabled`, focalisable, comme la lecture seule. Une seconde decision pendant la premiere
2004
+ * ecrasait l'etat d'avant retenu, et un refus de la premiere rendait l'etat intermediaire, qu'aucun
2005
+ * enregistrement n'avait jamais porte. Un refus sans decision a rendre (deja rendu, ou present des
2006
+ * l'affichage) ne s'annonce pas : il n'y a aucun choix a dire perdu (audit UI du 2026-09-27, D-10).
2007
+ */
2008
+ export declare class StConsentRow {
2009
+ protected readonly groupe: GroupeDeConsentements;
2010
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
2011
+ private readonly locale;
2012
+ readonly cle: import("@angular/core").InputSignal<string>;
2013
+ /** Le titre en texte : le nom de la case sans titre riche, et celui du recapitulatif d'erreurs. */
2014
+ readonly titre: import("@angular/core").InputSignal<string>;
2015
+ readonly description: import("@angular/core").InputSignal<string | null>;
2016
+ readonly obligatoire: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2017
+ readonly versionDuDocument: import("@angular/core").InputSignal<string | null>;
2018
+ /** Date de la derniere decision enregistree, `null` si la personne n'a jamais decide. */
2019
+ readonly decideLe: import("@angular/core").InputSignal<string | null>;
2020
+ /** Mode immediat : l'application enregistre la decision (`aria-busy`). */
2021
+ readonly enregistrement: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2022
+ /** Mode immediat : le refus du serveur, dit a la personne ; la ligne revient a son etat d'avant. */
2023
+ readonly refus: import("@angular/core").InputSignal<string | null>;
2024
+ readonly decision: import("@angular/core").OutputEmitterRef<DecisionDeConsentement>;
2025
+ private readonly champ;
2026
+ protected readonly identifiantDuRefus: string;
2027
+ protected readonly annonce: AnnonceLocale;
2028
+ /** La personne a decide dans la page : sa decision s'affiche, meme sans `decideLe`. */
2029
+ private readonly decideeIci;
2030
+ /** Mode immediat : la valeur d'avant la derniere decision, rendue sur un refus. */
2031
+ private precedente;
2032
+ protected readonly immediat: import("@angular/core").Signal<boolean>;
2033
+ protected readonly coche: import("@angular/core").Signal<boolean>;
2034
+ protected readonly enAttente: import("@angular/core").Signal<boolean>;
2035
+ protected readonly enErreur: import("@angular/core").Signal<boolean>;
2036
+ /** La description, puis la version du document et la decision datee. */
2037
+ protected readonly aide: import("@angular/core").Signal<string | null>;
2038
+ protected readonly descriptionsDuRefus: import("@angular/core").Signal<string[]>;
2039
+ constructor();
2040
+ /**
2041
+ * Une decision de la personne (sa case, ou une action du groupe) : ecrite dans le groupe et
2042
+ * emise. Rien en lecture seule, desactive, ni pendant l'enregistrement de la precedente :
2043
+ * `precedente` reste l'etat d'avant la decision en cours d'enregistrement, le seul qu'un refus
2044
+ * puisse rendre (D-10).
2045
+ */
2046
+ decider(valeur: boolean): void;
2047
+ focus(options?: FocusOptions): void;
2048
+ /** En lecture seule et pendant l'enregistrement, le clic (souris, ou Espace) est annule. */
2049
+ protected surClic(evenement: MouseEvent): void;
2050
+ protected surBascule(evenement: Event): void;
2051
+ static ɵfac: i0.ɵɵFactoryDeclaration<StConsentRow, never>;
2052
+ static ɵcmp: i0.ɵɵComponentDeclaration<StConsentRow, "st-consent-row", never, {
2053
+ "cle": {
2054
+ "alias": "cle";
2055
+ "required": true;
2056
+ "isSignal": true;
2057
+ };
2058
+ "titre": {
2059
+ "alias": "titre";
2060
+ "required": true;
2061
+ "isSignal": true;
2062
+ };
2063
+ "description": {
2064
+ "alias": "description";
2065
+ "required": false;
2066
+ "isSignal": true;
2067
+ };
2068
+ "obligatoire": {
2069
+ "alias": "obligatoire";
2070
+ "required": false;
2071
+ "isSignal": true;
2072
+ };
2073
+ "versionDuDocument": {
2074
+ "alias": "versionDuDocument";
2075
+ "required": false;
2076
+ "isSignal": true;
2077
+ };
2078
+ "decideLe": {
2079
+ "alias": "decideLe";
2080
+ "required": false;
2081
+ "isSignal": true;
2082
+ };
2083
+ "enregistrement": {
2084
+ "alias": "enregistrement";
2085
+ "required": false;
2086
+ "isSignal": true;
2087
+ };
2088
+ "refus": {
2089
+ "alias": "refus";
2090
+ "required": false;
2091
+ "isSignal": true;
2092
+ };
2093
+ }, {
2094
+ "decision": "decision";
2095
+ }, never, ["[stLibelle]"], true, never>;
2096
+ }
2097
+ /**
2098
+ * Ce qu'un `st-choice-group` offre a ses `st-choice` : le mode (radios ou cases), le nom partage
2099
+ * par les controles, les etats du groupe, et la lecture et l'ecriture de la valeur. Une carte hors
2100
+ * d'un groupe n'a pas de sens (sa valeur vit dans le groupe) : elle echoue a l'injection.
2101
+ */
2102
+ interface GroupeDeChoix {
2103
+ readonly multiple: Signal<boolean>;
2104
+ readonly nom: Signal<string>;
2105
+ readonly desactive: Signal<boolean>;
2106
+ readonly lectureSeule: Signal<boolean>;
2107
+ readonly enErreur: Signal<boolean>;
2108
+ estChoisie(valeur: string): boolean;
2109
+ choisir(valeur: string, coche: boolean): void;
2110
+ /** Remet chaque controle natif a l'etat du modele, apres une bascule refusee. */
2111
+ resynchroniser(): void;
2112
+ }
2113
+ declare const ST_GROUPE_DE_CHOIX: InjectionToken<GroupeDeChoix>;
2114
+ /** `unique` : des radios, un seul choix. `multiple` : des cases, plusieurs choix. */
2115
+ export type ModeDeChoix = 'unique' | 'multiple';
2116
+ /**
2117
+ * La valeur d'un groupe de cartes : une chaine en mode `unique` (vide tant que rien n'est choisi),
2118
+ * la LISTE des valeurs choisies en mode `multiple`.
2119
+ */
2120
+ export type ChoixDeGroupe = string | readonly string[];
2121
+ /** `colonne` : les cartes l'une sous l'autre. `grille` : deux colonnes des la rupture `md`. */
2122
+ export type DispositionDeChoix = 'colonne' | 'grille';
2123
+ /**
2124
+ * Cartes de choix : un compte a debiter, un beneficiaire, une offre, un moyen de connexion. Chaque
2125
+ * option est un `st-choice` projete, qui porte un titre, une precision riche (`st-masked`,
2126
+ * `st-money`), une icone ou un avatar, et un detail revele quand il est choisi.
2127
+ *
2128
+ * ```html
2129
+ * <st-choice-group legende="Compte a debiter" [formField]="virement.compte">
2130
+ * <st-choice valeur="courant">
2131
+ * <st-icon nom="compte" />
2132
+ * Compte courant
2133
+ * <st-masked precision type="iban" valeur="FR76 •••• •••• •••• •••• •••• 189" />
2134
+ * </st-choice>
2135
+ * <st-choice valeur="epargne" desactivee raisonDIndisponibilite="Solde insuffisant.">
2136
+ * Livret d'epargne
2137
+ * <st-money precision [valeur]="solde" />
2138
+ * </st-choice>
2139
+ * </st-choice-group>
2140
+ * ```
2141
+ *
2142
+ * ⚠️ **De vrais radios ou de vraies cases, visibles** (`mode`) : un seul arret de tabulation et les
2143
+ * fleches en mode `unique`, « 2 sur 3 » annonce, Espace coche. La carte entiere est l'ETIQUETTE du
2144
+ * controle, jamais une carte cliquable sans nom ni clavier (UX-3) : c'est ce que le groupe
2145
+ * remplace, et pourquoi `st-choice-card` n'existe pas.
2146
+ *
2147
+ * Un `st-fieldset` : la legende pose la question, l'aide la precise ; le message d'erreur porte sur
2148
+ * le groupe, a la sortie du groupe, et l'ETAT d'erreur sur chaque controle (`aria-invalid`). En mode
2149
+ * `unique`, le `fieldset` est un `radiogroup` qui porte l'obligation et la lecture seule (ARIA ne
2150
+ * les prevoit pas sur un radio) ; en mode `multiple`, chaque case porte `aria-readonly`.
2151
+ *
2152
+ * La valeur est une chaine en mode `unique` et une liste en mode `multiple` (`ChoixDeGroupe`) : le
2153
+ * champ lie par `[formField]` a le type de son mode, et le developpement signale une valeur de
2154
+ * l'autre forme. En mode `multiple`, la liste suit l'ordre des cartes quel que soit l'ordre des
2155
+ * clics ; une valeur qu'aucune carte ne porte est gardee a la fin, jamais effacee en silence. Les
2156
+ * bornes (`minLength`, `maxLength`) viennent du schema, comme pour `st-checkbox-group`.
2157
+ *
2158
+ * `touch` n'est emis que lorsque le focus QUITTE le groupe. `readonly` : les cartes restent
2159
+ * focalisables et lues, mais rien ne change. `focus()` : la carte choisie en mode `unique`, sinon
2160
+ * la premiere disponible.
2161
+ */
2162
+ export declare class StChoiceGroup implements FormValueControl<ChoixDeGroupe>, GroupeDeChoix {
2163
+ private readonly element;
2164
+ readonly legende: import("@angular/core").InputSignal<string>;
2165
+ readonly aide: import("@angular/core").InputSignal<string | null>;
2166
+ readonly mode: import("@angular/core").InputSignal<ModeDeChoix>;
2167
+ readonly disposition: import("@angular/core").InputSignal<DispositionDeChoix>;
2168
+ /** Contrat Signal Forms. */
2169
+ readonly value: import("@angular/core").ModelSignal<ChoixDeGroupe>;
2170
+ readonly errors: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
2171
+ readonly touched: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2172
+ readonly dirty: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2173
+ readonly pending: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2174
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2175
+ readonly disabledReasons: import("@angular/core").InputSignal<readonly WithOptionalFieldTree<DisabledReason>[]>;
2176
+ readonly readonly: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2177
+ readonly required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2178
+ readonly hidden: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2179
+ readonly name: import("@angular/core").InputSignal<string>;
2180
+ readonly touch: import("@angular/core").OutputEmitterRef<void>;
2181
+ private readonly cartes;
2182
+ /** Nom partage par les controles : sans lui, chaque radio forme son propre groupe. */
2183
+ private readonly nomParDefaut;
2184
+ readonly multiple: import("@angular/core").Signal<boolean>;
2185
+ readonly nom: import("@angular/core").Signal<string>;
2186
+ readonly desactive: import("@angular/core").Signal<boolean>;
2187
+ readonly lectureSeule: import("@angular/core").Signal<boolean>;
2188
+ /** L'erreur se montre apres la sortie du groupe, comme son message. */
2189
+ readonly enErreur: import("@angular/core").Signal<boolean>;
2190
+ /** Les valeurs choisies, quelle que soit la forme de la valeur. */
2191
+ private readonly choisies;
2192
+ /** L'aide du groupe, suivie des raisons de sa desactivation. */
2193
+ protected readonly aideEtRaisons: import("@angular/core").Signal<string | null>;
2194
+ constructor();
2195
+ estChoisie(valeur: string): boolean;
2196
+ /** Une decision de la personne : en mode `unique`, seul un choix coche ecrit la valeur. */
2197
+ choisir(valeur: string, coche: boolean): void;
2198
+ resynchroniser(): void;
2199
+ /**
2200
+ * Focus sur la carte choisie (mode `unique` : c'est l'arret de tabulation du groupe), sinon sur la
2201
+ * premiere disponible. Lu sur l'etat (valeur et cartes), et non sur le DOM coche.
2202
+ */
2203
+ focus(options?: FocusOptions): void;
2204
+ protected aLaSortie(evenement: FocusEvent): void;
2205
+ /** Les valeurs dans l'ordre des cartes, puis celles qu'aucune carte ne porte. */
2206
+ private dansLOrdre;
2207
+ static ɵfac: i0.ɵɵFactoryDeclaration<StChoiceGroup, never>;
2208
+ static ɵcmp: i0.ɵɵComponentDeclaration<StChoiceGroup, "st-choice-group", never, {
2209
+ "legende": {
2210
+ "alias": "legende";
2211
+ "required": true;
2212
+ "isSignal": true;
2213
+ };
2214
+ "aide": {
2215
+ "alias": "aide";
2216
+ "required": false;
2217
+ "isSignal": true;
2218
+ };
2219
+ "mode": {
2220
+ "alias": "mode";
2221
+ "required": false;
2222
+ "isSignal": true;
2223
+ };
2224
+ "disposition": {
2225
+ "alias": "disposition";
2226
+ "required": false;
2227
+ "isSignal": true;
2228
+ };
2229
+ "value": {
2230
+ "alias": "value";
2231
+ "required": false;
2232
+ "isSignal": true;
2233
+ };
2234
+ "errors": {
2235
+ "alias": "errors";
2236
+ "required": false;
2237
+ "isSignal": true;
2238
+ };
2239
+ "touched": {
2240
+ "alias": "touched";
2241
+ "required": false;
2242
+ "isSignal": true;
2243
+ };
2244
+ "dirty": {
2245
+ "alias": "dirty";
2246
+ "required": false;
2247
+ "isSignal": true;
2248
+ };
2249
+ "pending": {
2250
+ "alias": "pending";
2251
+ "required": false;
2252
+ "isSignal": true;
2253
+ };
2254
+ "disabled": {
2255
+ "alias": "disabled";
2256
+ "required": false;
2257
+ "isSignal": true;
2258
+ };
2259
+ "disabledReasons": {
2260
+ "alias": "disabledReasons";
2261
+ "required": false;
2262
+ "isSignal": true;
2263
+ };
2264
+ "readonly": {
2265
+ "alias": "readonly";
2266
+ "required": false;
2267
+ "isSignal": true;
2268
+ };
2269
+ "required": {
2270
+ "alias": "required";
2271
+ "required": false;
2272
+ "isSignal": true;
2273
+ };
2274
+ "hidden": {
2275
+ "alias": "hidden";
2276
+ "required": false;
2277
+ "isSignal": true;
2278
+ };
2279
+ "name": {
2280
+ "alias": "name";
2281
+ "required": false;
2282
+ "isSignal": true;
2283
+ };
2284
+ }, {
2285
+ "value": "valueChange";
2286
+ "touch": "touch";
2287
+ }, ["cartes"], ["*"], true, never>;
2288
+ }
2289
+ /**
2290
+ * Une carte de choix dans un `st-choice-group` : un radio (mode `unique`) ou une case (mode
2291
+ * `multiple`) natifs et visibles, que la carte entiere etiquette.
2292
+ *
2293
+ * ```html
2294
+ * <st-choice valeur="courant">
2295
+ * <st-icon nom="compte" />
2296
+ * Compte courant
2297
+ * <st-masked precision type="iban" valeur="FR76 •••• •••• •••• •••• •••• 189" />
2298
+ * <div detail><st-input libelle="Reference du virement" /></div>
2299
+ * </st-choice>
2300
+ * ```
2301
+ *
2302
+ * Projections : le TITRE (contenu par defaut), la PRECISION (`[precision]` : `st-masked`,
2303
+ * `st-money`, un texte discret), une icone ou un avatar (`st-icon`, `st-avatar`), et le DETAIL
2304
+ * (`[detail]`), revele sous la carte tant qu'elle est choisie (motif « conditional reveal » de
2305
+ * GOV.UK, dans le flux, jamais dans un dialogue).
2306
+ *
2307
+ * ⚠️ Le nom du controle est le texte de son etiquette : le titre, puis la precision (`st-masked`
2308
+ * y donne « IBAN se terminant par 0189 »). L'etiquette ne contient donc AUCUN autre controle :
2309
+ * pas de `st-masked` a bouton de revelation (`charger`), pas de lien. Ce qui se manipule va dans
2310
+ * le detail, hors de l'etiquette.
2311
+ *
2312
+ * Le detail est relie au controle par `aria-controls` ; une case porte aussi `aria-expanded`
2313
+ * (ARIA ne le prevoit pas sur un radio). Le focus n'y est jamais deplace d'office (WCAG 3.2.2) :
2314
+ * il suit la carte dans l'ordre de tabulation, et n'y entre que visible.
2315
+ *
2316
+ * `desactivee` : la carte reste FOCALISABLE (`aria-disabled`, D39, comme une cellule de
2317
+ * `st-choice-matrix`), dit sa raison (`raisonDIndisponibilite`, reliee par `aria-describedby`) et
2318
+ * ne se choisit pas. Le groupe desactive (le schema) gele toutes ses cartes nativement.
2319
+ */
2320
+ export declare class StChoice {
2321
+ protected readonly groupe: GroupeDeChoix;
2322
+ readonly valeur: import("@angular/core").InputSignal<string>;
2323
+ /** La carte ne se choisit pas, mais reste focalisable et dit pourquoi (D39). */
2324
+ readonly desactivee: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2325
+ /** Pourquoi la carte ne se choisit pas : lu avec le controle, affiche sous la carte. */
2326
+ readonly raisonDIndisponibilite: import("@angular/core").InputSignal<string | null>;
2327
+ private readonly controle;
2328
+ private readonly zoneDuDetail;
2329
+ private readonly racine;
2330
+ protected readonly identifiantDeLaRaison: string;
2331
+ protected readonly identifiantDuDetail: string;
2332
+ protected readonly coche: import("@angular/core").Signal<boolean>;
2333
+ /** La raison ne se dit que d'une carte indisponible. */
2334
+ protected readonly raison: import("@angular/core").Signal<string | null>;
2335
+ /** Un detail est projete : le controle le designe (`aria-controls`). */
2336
+ protected readonly aUnDetail: import("@angular/core").WritableSignal<boolean>;
2337
+ constructor();
2338
+ focus(options?: FocusOptions): void;
2339
+ /** Remet le controle natif a l'etat du modele (le groupe l'appelle apres une bascule refusee). */
2340
+ resynchroniser(): void;
2341
+ private immobile;
2342
+ /**
2343
+ * Le clic est annule AVANT la bascule quand rien ne doit changer (lecture seule, carte
2344
+ * indisponible). Chromium rend alors la coche a l'option du modele, mais pas tous les moteurs
2345
+ * (jsdom ne restaure que le radio clique) : le groupe la rend lui-meme, l'evenement retombe.
2346
+ */
2347
+ protected surClic(evenement: MouseEvent): void;
2348
+ protected surBascule(evenement: Event): void;
2349
+ static ɵfac: i0.ɵɵFactoryDeclaration<StChoice, never>;
2350
+ static ɵcmp: i0.ɵɵComponentDeclaration<StChoice, "st-choice", never, {
2351
+ "valeur": {
2352
+ "alias": "valeur";
2353
+ "required": true;
2354
+ "isSignal": true;
2355
+ };
2356
+ "desactivee": {
2357
+ "alias": "desactivee";
2358
+ "required": false;
2359
+ "isSignal": true;
2360
+ };
2361
+ "raisonDIndisponibilite": {
2362
+ "alias": "raisonDIndisponibilite";
2363
+ "required": false;
2364
+ "isSignal": true;
2365
+ };
2366
+ }, {}, never, ["st-icon, st-avatar", "*", "[precision]", "[detail]"], true, never>;
441
2367
  }
442
-
443
2368
  /**
444
2369
  * Interrupteur : un reglage qui s'applique IMMEDIATEMENT.
445
2370
  *
446
2371
  * ```html
447
- * <st-switch libelle="Notifications par SMS" [(checked)]="sms" (checkedChange)="enregistrer($event)" />
2372
+ * <st-switch libelle="Notifications par SMS" libelleEtat [(checked)]="sms" (checkedChange)="enregistrer($event)" />
448
2373
  * ```
449
2374
  *
450
2375
  * ⚠️ **Jamais dans un formulaire a envoyer** (UX-8). Un interrupteur promet que
@@ -454,83 +2379,233 @@ declare class StRadioGroup implements FormValueControl<string> {
454
2379
  *
455
2380
  * C'est pourquoi il n'affiche aucune erreur de validation : un reglage immediat
456
2381
  * ne se valide pas a l'envoi. Un refus du serveur se dit par un message, et
457
- * l'interrupteur revient a son etat precedent.
2382
+ * l'interrupteur revient a son etat precedent. Une regle du schema posee sur lui (`required`,
2383
+ * `validate`) bloquerait pourtant l'envoi d'un formulaire sans rien montrer : en developpement,
2384
+ * il le signale une fois dans la console.
458
2385
  *
459
2386
  * ⚠️ Une case a cocher native avec `role="switch"` : Espace bascule, l'etiquette
460
2387
  * est reliee par `for`, et le lecteur d'ecran annonce « active » ou
461
2388
  * « desactive » — mieux qu'un `div` qui imiterait tout cela.
2389
+ *
2390
+ * Une ligne de reglage (planches 3a, 3b) : l'etiquette et son etat a gauche, le rail de 44 x 24 a
2391
+ * droite (a gauche en RTL). `libelleEtat` ecrit l'etat en mots sous l'etiquette (« Etat :
2392
+ * Active », en vert ; « Etat : Desactive ») : la position d'un curseur n'est pas lue par tous.
2393
+ *
2394
+ * Enregistrement en attente (03 §3.3) : `enAttente` pose `aria-busy` sur le
2395
+ * controle pendant que l'appelant enregistre, et remplace l'aide par « Enregistrement en cours… »
2396
+ * (ou `libelleAttente`), relie au controle. Le curseur est DEJA a sa nouvelle position
2397
+ * (optimiste) ; sur un refus, l'appelant remet `checked` et dit pourquoi.
2398
+ *
2399
+ * ⚠️ **L'attente avale toute nouvelle bascule** (`aria-disabled`, focalisable, comme la lecture
2400
+ * seule) : une seconde bascule partait pendant la premiere, et le retour d'un refus ne savait plus
2401
+ * quel etat rendre. Un `checked` remis par l'appelant pendant l'attente, ou en la levant, est un
2402
+ * refus : le curseur revenait en silence, il s'annonce (`choixNonEnregistre`, comme
2403
+ * `st-consent-row`). Aboutie, l'attente ne dit rien : l'etat obtenu s'est dit a la bascule (audit
2404
+ * UI du 2026-09-27, D-10).
462
2405
  */
463
- declare class StSwitch implements FormCheckboxControl {
464
- readonly libelle: _angular_core.InputSignal<string>;
465
- readonly aide: _angular_core.InputSignal<string | null>;
466
- /** Contrat Signal Forms. */
467
- readonly checked: _angular_core.ModelSignal<boolean>;
468
- readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
469
- readonly hidden: _angular_core.InputSignalWithTransform<boolean, unknown>;
470
- readonly name: _angular_core.InputSignal<string>;
471
- readonly touch: _angular_core.OutputEmitterRef<void>;
472
- private readonly champ;
473
- focus(options?: FocusOptions): void;
474
- protected surChangement(evenement: Event): void;
475
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StSwitch, never>;
476
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StSwitch, "st-switch", never, { "libelle": { "alias": "libelle"; "required": true; "isSignal": true; }; "aide": { "alias": "aide"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hidden": { "alias": "hidden"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "touch": "touch"; }, never, never, true, never>;
2406
+ export declare class StSwitch extends ContratDeCase {
2407
+ private readonly libelles;
2408
+ protected readonly annonce: AnnonceLocale;
2409
+ /**
2410
+ * Le reglage s'enregistre : `aria-busy`, curseur d'attente ; le controle reste focalisable, et
2411
+ * avale toute nouvelle bascule jusqu'a la fin de l'attente.
2412
+ */
2413
+ readonly enAttente: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2414
+ /** Le texte de l'attente ; `null` : « Enregistrement en cours… », du dictionnaire. */
2415
+ readonly libelleAttente: import("@angular/core").InputSignal<string | null>;
2416
+ /**
2417
+ * L'aide dit l'etat OBTENU (« Actif · Chiffrement HSM », planche 3a) : actif, elle passe au vert
2418
+ * de succes, en 500. A choisir explicitement, comme sur `st-checkbox`.
2419
+ */
2420
+ readonly aideDEtat: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2421
+ /** Ecrit l'etat en mots sous l'etiquette (« Etat : Active » / « Etat : Desactive »). */
2422
+ readonly libelleEtat: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2423
+ constructor();
2424
+ /** En attente, une nouvelle bascule est annulee AVANT d'avoir lieu, comme en lecture seule. */
2425
+ protected surClic(evenement: MouseEvent): void;
2426
+ /** Filet si le clic passe malgre tout : en attente, la case reprend l'etat du modele. */
2427
+ protected surBascule(evenement: Event): void;
2428
+ /** Pendant l'attente, l'aide cede la place au texte d'attente. */
2429
+ protected readonly aideAffichee: import("@angular/core").Signal<string | null>;
2430
+ /** La ligne d'etat, s'il y en a une : l'attente, sinon l'etat en mots. */
2431
+ protected readonly etat: import("@angular/core").Signal<string | null>;
2432
+ static ɵfac: i0.ɵɵFactoryDeclaration<StSwitch, never>;
2433
+ static ɵcmp: i0.ɵɵComponentDeclaration<StSwitch, "st-switch", never, {
2434
+ "enAttente": {
2435
+ "alias": "enAttente";
2436
+ "required": false;
2437
+ "isSignal": true;
2438
+ };
2439
+ "libelleAttente": {
2440
+ "alias": "libelleAttente";
2441
+ "required": false;
2442
+ "isSignal": true;
2443
+ };
2444
+ "aideDEtat": {
2445
+ "alias": "aideDEtat";
2446
+ "required": false;
2447
+ "isSignal": true;
2448
+ };
2449
+ "libelleEtat": {
2450
+ "alias": "libelleEtat";
2451
+ "required": false;
2452
+ "isSignal": true;
2453
+ };
2454
+ }, {}, never, never, true, never>;
477
2455
  }
478
-
2456
+ /**
2457
+ * Ce qu'un formulaire dit de son envoi a ce qu'il contient (lot 247). Fourni par `form[stForm]`
2458
+ * (`@starterlib/ui/formulaires`) ; le `st-error-summary` qu'il contient le lit, et n'a alors rien
2459
+ * a lier. Une application qui ecrit sa propre directive de formulaire peut le fournir a son tour.
2460
+ */
2461
+ export interface EtatDEnvoi {
2462
+ /**
2463
+ * Les erreurs a recapituler : aucune avant la premiere tentative, pendant l'envoi, ni apres un
2464
+ * envoi reussi.
2465
+ */
2466
+ readonly recapitulatif: Signal<readonly ValidationError.WithOptionalFieldTree[]>;
2467
+ /** Les tentatives depuis le dernier envoi reussi : chacune ramene le focus au recapitulatif. */
2468
+ readonly tentative: Signal<number>;
2469
+ /** Un envoi court. */
2470
+ readonly enCours: Signal<boolean>;
2471
+ }
2472
+ export declare const ST_ETAT_D_ENVOI: InjectionToken<EtatDEnvoi>;
2473
+ /** Niveau du titre du recapitulatif, selon sa place dans la page. */
2474
+ export type NiveauDeRecapitulatif = 2 | 3 | 4;
479
2475
  /** Une ligne du recapitulatif. */
480
2476
  interface LigneDErreur {
481
- readonly libelle: string | null;
482
- readonly message: string;
483
- readonly aller: () => void;
2477
+ /** Cle stable : le champ, ou le rang d'une erreur de formulaire entier. */
2478
+ readonly cle: unknown;
2479
+ /** « Montant du virement : », ponctuation de la langue ; `null` pour une ligne sans champ. */
2480
+ readonly libelle: string | null;
2481
+ readonly message: string;
2482
+ readonly aller: () => void;
484
2483
  }
485
2484
  /**
486
2485
  * Recapitulatif des erreurs d'un formulaire, a l'envoi.
487
2486
  *
2487
+ * Dans un `form[stForm]` (`@starterlib/ui/formulaires`, lot 247), il n'a rien a lier : le
2488
+ * formulaire lui fournit ses erreurs et ses tentatives.
2489
+ *
488
2490
  * ```html
489
- * <st-error-summary [erreurs]="tentative() ? virement().errorSummary() : []" />
2491
+ * <form [stForm]="virement" [envoyerAvec]="envoyer">
2492
+ * <st-error-summary />
2493
+ * ...
2494
+ * </form>
490
2495
  * ```
491
2496
  *
492
- * ⚠️ **Il prend le focus en apparaissant** (UX-5). Sans lui, une personne au
493
- * clavier ou au lecteur d'ecran appuie sur « Envoyer », et rien ne se passe : le
494
- * champ refuse est en haut de la page, hors de sa vue, et personne ne le lui dit.
2497
+ * Hors d'un tel formulaire (en tete de page, loin du formulaire), il se lie :
2498
+ *
2499
+ * ```html
2500
+ * <st-error-summary [erreurs]="formulaire.recapitulatif()" [tentative]="formulaire.tentative()" />
2501
+ * ```
2502
+ *
2503
+ * ⚠️ **Il prend le focus en apparaissant, ET a chaque nouvelle tentative** (UX-5). Sans lui, une
2504
+ * personne au clavier ou au lecteur d'ecran appuie sur « Envoyer », et rien ne se passe : le
2505
+ * champ refuse est en haut de la page, hors de sa vue, et personne ne le lui dit. Un second envoi
2506
+ * refuse (meme avec le meme nombre d'erreurs) incremente `tentative` : le focus revient au cadre
2507
+ * sans que l'application appelle `focus()`. Il ne le reprend PAS a chaque correction : ce serait
2508
+ * arracher la personne au champ qu'elle corrige.
495
2509
  *
496
2510
  * ⚠️ **Chaque ligne nomme son champ.** « Ce champ est obligatoire. » repete cinq
497
2511
  * fois n'apprend rien ; « Nom du beneficiaire : ce champ est obligatoire. », si.
498
- * Le libelle est lu sur l'element lie au champ, par Signal Forms — sans registre,
499
- * et quel que soit le composant.
2512
+ * Le libelle est celui du champ LIE (son `st-form-field` direct, sinon son etiquette native, sinon
2513
+ * `aria-label`) ; un champ sans nom lisible donne quand meme un lien (« Champ 2 »).
500
2514
  *
501
2515
  * ⚠️ **Une ligne par champ**, la premiere erreur seulement : trois erreurs sur le
502
2516
  * meme IBAN font trois lignes pour une seule correction.
503
2517
  *
504
- * ⚠️ **Une region nommee par son titre.** Un `div` sans role ne PEUT pas porter
505
- * `aria-labelledby` : le nom serait ignore, et le focus n'annoncerait rien. En
506
- * region, il annonce « 2 erreurs a corriger » a l'arrivee du focus, et se
507
- * retrouve dans la liste des reperes.
508
- *
509
- * Chaque ligne amene le focus sur son champ : c'est le champ, et non la ligne,
510
- * qu'il faut corriger. Une erreur rattachee au formulaire entier — un refus du
511
- * serveur sur un champ inconnu — s'affiche sans lien.
512
- */
513
- declare class StErrorSummary {
514
- private readonly libelles;
515
- private readonly locale;
516
- private readonly element;
517
- private readonly injecteur;
518
- readonly erreurs: _angular_core.InputSignal<readonly ValidationError.WithOptionalFieldTree[]>;
519
- /** `null` : « N erreurs a corriger », du dictionnaire. */
520
- readonly titre: _angular_core.InputSignal<string | null>;
521
- /** Unique par instance : deux recapitulatifs sur une page partageraient leur titre. */
522
- protected readonly identifiantDuTitre: string;
523
- protected readonly lignes: _angular_core.Signal<readonly LigneDErreur[]>;
524
- protected readonly titreLu: _angular_core.Signal<string>;
525
- constructor();
526
- /** A appeler apres un envoi refuse, quand le recapitulatif etait deja visible. */
527
- focus(): void;
528
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StErrorSummary, never>;
529
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StErrorSummary, "st-error-summary", never, { "erreurs": { "alias": "erreurs"; "required": true; "isSignal": true; }; "titre": { "alias": "titre"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2518
+ * ⚠️ **Une region nommee par son titre.** L'hote est la region focalisee : le focus annonce
2519
+ * « 3 erreurs a corriger » a l'arrivee, et la region se retrouve dans la liste des reperes. Ni
2520
+ * `alert` ni `aria-live` : c'est le focus qui annonce.
2521
+ *
2522
+ * Anatomie (planche 3b) : icone, titre (`niveau` 2 a 4), etiquette projetee `[stEtiquette]` a
2523
+ * droite (« Blocage »), `introduction` facultative, puis une ligne par erreur. Chaque ligne amene
2524
+ * le focus sur son champ : c'est le champ, et non la ligne, qu'il faut corriger. Une erreur
2525
+ * rattachee au formulaire entier — un refus du serveur sur un champ inconnu — s'affiche sans lien.
2526
+ */
2527
+ export declare class StErrorSummary {
2528
+ private readonly libelles;
2529
+ private readonly locale;
2530
+ private readonly element;
2531
+ private readonly injecteur;
2532
+ private readonly envoi;
2533
+ /**
2534
+ * Les erreurs a recapituler. A omettre dans un `form[stForm]`, qui les fournit avec ses
2535
+ * tentatives ; liees, elles l'emportent, et `tentative` se lie avec elles.
2536
+ */
2537
+ readonly erreurs: import("@angular/core").InputSignal<readonly ValidationError.WithOptionalFieldTree[] | undefined>;
2538
+ /** `null` : « N erreurs a corriger », du dictionnaire. */
2539
+ readonly titre: import("@angular/core").InputSignal<string | null>;
2540
+ /** Niveau du titre : 2 en tete de page, 3 ou 4 dans une section ou un dialogue. */
2541
+ readonly niveau: import("@angular/core").InputSignal<NiveauDeRecapitulatif>;
2542
+ /** Phrase d'introduction sous le titre (« Cliquez sur une anomalie pour aller au champ. »). */
2543
+ readonly introduction: import("@angular/core").InputSignal<string | null>;
2544
+ /**
2545
+ * Compteur d'envois refuses, tenu par l'application (ou `form[stForm]`) : chaque changement
2546
+ * ramene le focus au recapitulatif, meme quand ses lignes n'ont pas change.
2547
+ *
2548
+ * ⚠️ Un NOMBRE, jamais un booleen : `[tentative]="aEnvoye()"` resterait `true` au second envoi
2549
+ * (aucun retour du focus). Le type refuse le booleen a la compilation ; une valeur illisible
2550
+ * (chaine vide, `NaN`) vaut 0, et la comparaison par `Object.is` ne voit pas `NaN` changer.
2551
+ */
2552
+ readonly tentative: import("@angular/core").InputSignalWithTransform<number, number | `${number}`>;
2553
+ /** Les erreurs lues : celles liees, sinon celles du formulaire qui l'entoure. */
2554
+ private readonly erreursLues;
2555
+ /** La tentative lue : celle du formulaire qui l'entoure, quand les erreurs viennent de lui. */
2556
+ private readonly tentativeLue;
2557
+ /** Unique par instance : deux recapitulatifs sur une page partageraient leur titre. */
2558
+ protected readonly identifiantDuTitre: string;
2559
+ protected readonly lignes: import("@angular/core").Signal<readonly LigneDErreur[]>;
2560
+ protected readonly titreLu: import("@angular/core").Signal<string>;
2561
+ constructor();
2562
+ /** Amene le focus sur le recapitulatif (s'il est visible). */
2563
+ focus(options?: FocusOptions): void;
2564
+ static ɵfac: i0.ɵɵFactoryDeclaration<StErrorSummary, never>;
2565
+ static ɵcmp: i0.ɵɵComponentDeclaration<StErrorSummary, "st-error-summary", never, {
2566
+ "erreurs": {
2567
+ "alias": "erreurs";
2568
+ "required": false;
2569
+ "isSignal": true;
2570
+ };
2571
+ "titre": {
2572
+ "alias": "titre";
2573
+ "required": false;
2574
+ "isSignal": true;
2575
+ };
2576
+ "niveau": {
2577
+ "alias": "niveau";
2578
+ "required": false;
2579
+ "isSignal": true;
2580
+ };
2581
+ "introduction": {
2582
+ "alias": "introduction";
2583
+ "required": false;
2584
+ "isSignal": true;
2585
+ };
2586
+ "tentative": {
2587
+ "alias": "tentative";
2588
+ "required": false;
2589
+ "isSignal": true;
2590
+ };
2591
+ }, {}, never, ["[stEtiquette]"], true, never>;
530
2592
  }
531
-
532
2593
  /** `connexion` : un mot de passe existant. `creation` : un nouveau. */
533
- type UsageDuMotDePasse = 'connexion' | 'creation';
2594
+ export type UsageDuMotDePasse = 'connexion' | 'creation';
2595
+ /**
2596
+ * Une regle de creation, montree AVANT la saisie. `respectee` la coche pendant la frappe ; sans
2597
+ * elle, la regle reste a respecter (le serveur juge, SEC-5).
2598
+ */
2599
+ export interface RegleDeMotDePasse {
2600
+ /** Une phrase complete, avec son point : « Au moins 12 caracteres. » */
2601
+ readonly texte: string;
2602
+ readonly respectee?: (motDePasse: string) => boolean;
2603
+ }
2604
+ /** Une regle telle que le gabarit la rend. */
2605
+ interface RegleRendue {
2606
+ readonly texte: string;
2607
+ readonly respectee: boolean;
2608
+ }
534
2609
  /**
535
2610
  * Mot de passe, avec revelation.
536
2611
  *
@@ -546,41 +2621,88 @@ type UsageDuMotDePasse = 'connexion' | 'creation';
546
2621
  * pousse vers des mots de passe courts, retenus de tete, et casse les
547
2622
  * gestionnaires de mots de passe.
548
2623
  *
549
- * ⚠️ **Revele, il se remasque des que le focus quitte le champ, et a l'envoi du
550
- * formulaire** (SEC-4) : un mot de passe laisse en clair reste lisible par-dessus
551
- * l'epaule, sur l'ecran suivant comme sur celui-ci. L'envoi par Entree ne fait
552
- * pas quitter le champ : d'ou l'ecoute de `submit`, qui remonte jusqu'au document.
2624
+ * ⚠️ **Revele, il se remasque des que le focus quitte le champ, a l'envoi du
2625
+ * formulaire et avant l'impression** (SEC-4) : un mot de passe laisse en clair reste lisible
2626
+ * par-dessus l'epaule, sur l'ecran suivant comme sur celui-ci, et sur le papier. L'envoi par
2627
+ * Entree ne fait pas quitter le champ : d'ou l'ecoute de `submit`, UNE pour toute la page
2628
+ * (`EnvoisDeFormulaire`), et non une par champ.
2629
+ *
2630
+ * Le bouton de revelation est un bouton bascule DANS le cadre du champ (planche 3a) :
2631
+ * `aria-pressed` porte l'etat, et l'etiquette ne change PAS — « Masquer le mot de passe,
2632
+ * enfonce » se lirait comme une double negation. En lecture seule, il est desactive : on ne
2633
+ * revele pas ce qu'on ne peut pas modifier.
553
2634
  *
554
- * Le bouton de revelation est un bouton bascule : `aria-pressed` porte l'etat, et
555
- * l'etiquette ne change PAS — « Masquer le mot de passe, enfonce » se lirait
556
- * comme une double negation.
2635
+ * ⚠️ **Verrouillage des majuscules** : dit SOUS le champ (ton avertissement, icone et texte,
2636
+ * jamais la couleur seule) et annonce une fois (WCAG 4.1.3). Le champ, lui, ne bouge pas ; a la
2637
+ * creation, la ligne du message est reservee entre le champ et les regles, qui ne sautent pas.
557
2638
  *
558
2639
  * ⚠️ **Aucun indicateur de « force »**, et c'est un refus. Une estimation faite
559
2640
  * dans le navigateur donne « fort » a `Motdepasse1!` : elle rassure a tort. Les
560
- * regles sont affichees AVANT la saisie (UX-10), et c'est le serveur qui verifie —
561
- * y compris contre les mots de passe deja divulgues, qu'aucune regle locale ne
562
- * voit.
563
- */
564
- declare class StPasswordField extends ControleDeSaisie {
565
- protected readonly libelles: _angular_core.Signal<_starterlib_ui.LibellesUi>;
566
- private readonly element;
567
- readonly usage: _angular_core.InputSignal<UsageDuMotDePasse>;
568
- /** Regles affichees avant la saisie, comme aide du champ. */
569
- readonly regles: _angular_core.InputSignal<readonly string[]>;
570
- protected readonly revele: _angular_core.WritableSignal<boolean>;
571
- protected readonly autocomplete: _angular_core.Signal<"current-password" | "new-password">;
572
- protected readonly aideLue: _angular_core.Signal<string | null>;
573
- protected basculer(): void;
574
- protected surSaisie(evenement: Event): void;
575
- protected aLEnvoi(evenement: Event): void;
576
- protected aLaSortie(evenement: FocusEvent): void;
577
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StPasswordField, never>;
578
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StPasswordField, "st-password-field", never, { "usage": { "alias": "usage"; "required": false; "isSignal": true; }; "regles": { "alias": "regles"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2641
+ * regles sont affichees AVANT la saisie (UX-10), en liste, a la creation seulement, et
2642
+ * chacune se coche quand la saisie la respecte ; c'est le serveur qui verifie — y compris
2643
+ * contre les mots de passe deja divulgues, qu'aucune regle locale ne voit.
2644
+ *
2645
+ * `maxLength` du schema montre un compteur (« 12 caracteres restants ») en complement.
2646
+ */
2647
+ export declare class StPasswordField extends ControleDeSaisie {
2648
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
2649
+ private readonly element;
2650
+ protected readonly annonce: AnnonceLocale;
2651
+ private readonly racineDesParties;
2652
+ protected readonly idRegles: string;
2653
+ protected readonly idMajuscules: string;
2654
+ readonly usage: import("@angular/core").InputSignal<UsageDuMotDePasse>;
2655
+ /**
2656
+ * Regles de creation, montrees sous le champ en `usage="creation"` seulement : une phrase
2657
+ * seule, ou une phrase et le test qui la coche.
2658
+ */
2659
+ readonly regles: import("@angular/core").InputSignal<readonly (string | RegleDeMotDePasse)[]>;
2660
+ /** Titre de la liste des regles ; par defaut « Exigences du mot de passe : ». */
2661
+ readonly titreDesRegles: import("@angular/core").InputSignal<string | null>;
2662
+ protected readonly revele: import("@angular/core").WritableSignal<boolean>;
2663
+ /** La touche Verr. Maj est active pendant la frappe dans le champ. */
2664
+ protected readonly majusculesVerrouillees: import("@angular/core").WritableSignal<boolean>;
2665
+ protected readonly autocomplete: import("@angular/core").Signal<"new-password" | "current-password">;
2666
+ protected readonly reglesRendues: import("@angular/core").Signal<readonly RegleRendue[]>;
2667
+ protected readonly titreRendu: import("@angular/core").Signal<string>;
2668
+ /** « 12 caracteres restants », quand le schema borne la longueur. */
2669
+ protected readonly compteur: import("@angular/core").Signal<string | null>;
2670
+ /** Les regles et l'avertissement Verr. Maj decrivent le champ : lus au focus, apres l'aide. */
2671
+ protected readonly descriptionsDuControle: import("@angular/core").Signal<string[]>;
2672
+ constructor();
2673
+ protected basculer(): void;
2674
+ protected surSaisie(evenement: Event): void;
2675
+ /** Lit Verr. Maj a chaque touche : l'etat se voit des la premiere frappe, et s'annonce. */
2676
+ protected surTouche(evenement: KeyboardEvent): void;
2677
+ protected remasquer(): void;
2678
+ protected aLaSortie(evenement: FocusEvent): void;
2679
+ static ɵfac: i0.ɵɵFactoryDeclaration<StPasswordField, never>;
2680
+ static ɵcmp: i0.ɵɵComponentDeclaration<StPasswordField, "st-password-field", never, {
2681
+ "usage": {
2682
+ "alias": "usage";
2683
+ "required": false;
2684
+ "isSignal": true;
2685
+ };
2686
+ "regles": {
2687
+ "alias": "regles";
2688
+ "required": false;
2689
+ "isSignal": true;
2690
+ };
2691
+ "titreDesRegles": {
2692
+ "alias": "titreDesRegles";
2693
+ "required": false;
2694
+ "isSignal": true;
2695
+ };
2696
+ }, {}, never, ["[stMeta]", "[stAide]", "[stIndication]"], true, never>;
579
2697
  }
580
-
581
2698
  /**
582
2699
  * Code a usage unique : second facteur, code recu par SMS ou par courriel.
583
2700
  *
2701
+ * ```html
2702
+ * <st-otp-field libelle="Code recu par SMS" [formField]="verification.code" />
2703
+ * <!-- schema : validate(chemin.code, ({ value }) => erreurCode(value(), 6)) -->
2704
+ * ```
2705
+ *
584
2706
  * ⚠️ **UN seul champ, pas six cases** (UX-9). Six champs cassent le collage, le
585
2707
  * remplissage automatique du code recu par SMS, et la lecture au lecteur d'ecran,
586
2708
  * qui annonce six champs sans nom au lieu d'un seul.
@@ -591,45 +2713,126 @@ declare class StPasswordField extends ControleDeSaisie {
591
2713
  *
592
2714
  * ⚠️ **Aucun envoi automatique** a la sixieme saisie : un formulaire qui part de
593
2715
  * lui-meme surprend (WCAG 3.2.2), et part aussi avec un code mal colle. Le code
594
- * colle est nettoye de ses espaces et tirets — « 123 456 » —, jamais tronque.
2716
+ * colle est nettoye de tout ce qui n'est pas un chiffre — « 123 456 », un tiret, un caractere
2717
+ * invisible colle avec le SMS — ; un chiffre d'une autre ecriture (clavier arabe, pleine chasse
2718
+ * d'un IME) est lu comme son chiffre ASCII, pas avale. Jamais tronque (aucun `maxlength`) : un code trop long se voit
2719
+ * et se dit (`erreurCode`), il ne part pas ampute.
2720
+ *
2721
+ * Le renvoi du code est projete a droite du champ (`[stRenvoi]` : un `st-timer`, un lien) : le
2722
+ * composant ne l'envoie jamais lui-meme.
2723
+ *
2724
+ * Chasse fixe a zero barre, 700, centree, un pas d'espacement entre chiffres (planches 3 et 8) :
2725
+ * six chiffres qui se comptent d'un regard, sans six cases. Le champ reste de gauche a droite en
2726
+ * ecriture inverse.
595
2727
  */
596
- declare class StOtpField extends ControleDeSaisie {
597
- private readonly libelles;
598
- readonly longueur: _angular_core.InputSignal<number>;
599
- protected readonly aideLue: _angular_core.Signal<string>;
600
- protected surSaisie(evenement: Event): void;
601
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StOtpField, never>;
602
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StOtpField, "st-otp-field", never, { "longueur": { "alias": "longueur"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2728
+ export declare class StOtpField extends ControleDeSaisie {
2729
+ private readonly libelles;
2730
+ /** Nombre de chiffres attendus : il ecrit l'aide (« Code a 6 chiffres. »). */
2731
+ readonly longueur: import("@angular/core").InputSignalWithTransform<number, unknown>;
2732
+ /**
2733
+ * Identifiants d'autres textes qui decrivent le champ (`aria-describedby`), lus entre l'aide et
2734
+ * l'erreur : les essais restants de `st-challenge` (audit UI du 2026-09-27, D-20). Des elements
2735
+ * PRESENTS seulement : un identifiant absent fait ignorer toute la description par certains
2736
+ * lecteurs d'ecran.
2737
+ */
2738
+ readonly decritPar: import("@angular/core").InputSignal<readonly string[]>;
2739
+ protected readonly aideLue: import("@angular/core").Signal<string>;
2740
+ protected surSaisie(evenement: Event): void;
2741
+ static ɵfac: i0.ɵɵFactoryDeclaration<StOtpField, never>;
2742
+ static ɵcmp: i0.ɵɵComponentDeclaration<StOtpField, "st-otp-field", never, {
2743
+ "longueur": {
2744
+ "alias": "longueur";
2745
+ "required": false;
2746
+ "isSignal": true;
2747
+ };
2748
+ "decritPar": {
2749
+ "alias": "decritPar";
2750
+ "required": false;
2751
+ "isSignal": true;
2752
+ };
2753
+ }, {}, never, ["[stMeta]", "[stAide]", "[stIndication]", "[stRenvoi]"], true, never>;
603
2754
  }
604
-
605
2755
  /**
606
2756
  * Champ de recherche : un repere, un champ, un bouton.
607
2757
  *
608
2758
  * ```html
609
2759
  * <st-search-field libelle="Rechercher un beneficiaire" (recherche)="filtrer($event)" />
2760
+ * <!-- Barre de filtres (planches 4 et 10) : sans bouton, etiquette visible, raccourci. -->
2761
+ * <st-search-field compact libelleVisible presentation="micro-capitales" libelle="Recherche"
2762
+ * [(value)]="terme"><kbd stRaccourci>⌘K</kbd></st-search-field>
610
2763
  * ```
611
2764
  *
612
- * ⚠️ **Un repere `search`** : la recherche se retrouve dans la liste des reperes du
613
- * lecteur d'ecran, a cote de la navigation et du contenu.
2765
+ * ⚠️ **Un repere `search` NOMME** (`aria-label` = `libelle`) : deux recherches d'une page se
2766
+ * distinguent dans la liste des reperes du lecteur d'ecran.
614
2767
  *
615
2768
  * L'etiquette est lue sans etre affichee — seule exception au socle (UX-1) : la
616
- * loupe, le bouton et la position disent deja le but du champ.
2769
+ * loupe, le bouton et la position disent deja le but du champ. `libelleVisible` l'affiche
2770
+ * (barre de filtres, ou chaque filtre porte son etiquette).
2771
+ *
2772
+ * La croix « Effacer la recherche » est celle du socle, atteignable au clavier : celle de
2773
+ * WebKit n'etait ni stylee ni tabulable. Echap vide aussi le champ (comportement natif de
2774
+ * `type="search"`).
2775
+ *
2776
+ * ⚠️ **Recherche en cours** : `chargement` passe au BOUTON (`aria-busy`, indicateur differe),
2777
+ * jamais `disabled` — le focus ne tombe pas au milieu de l'attente. En `compact`, sans bouton,
2778
+ * l'indicateur du socle prend la place de la loupe, avec le meme rythme que celui du bouton
2779
+ * (rien avant `rythme.delai.attente`, puis au moins la tenue minimale) et MUET : une barre de
2780
+ * filtres cherche a chaque Entree, et « Chargement en cours » y etait dit a chaque fois, avant
2781
+ * les resultats que l'application annonce (audit UI du 2026-09-27, D-13).
617
2782
  *
618
2783
  * ⚠️ **Jamais dans l'adresse quand le terme est personnel** (SEC-6). Chercher un
619
2784
  * nom, un IBAN ou un numero en `?q=` inscrit la donnee dans l'historique, dans les
620
2785
  * journaux des intermediaires, et dans l'en-tete `Referer` des pages suivantes.
621
2786
  * `recherche` emet le terme : c'est a l'appelant de ne pas le mettre dans l'URL.
622
2787
  */
623
- declare class StSearchField extends ControleDeSaisie {
624
- protected readonly libelles: _angular_core.Signal<_starterlib_ui.LibellesUi>;
625
- /** Emis a la validation — Entree ou bouton —, et non a chaque frappe. */
626
- readonly recherche: _angular_core.OutputEmitterRef<string>;
627
- protected surSaisie(evenement: Event): void;
628
- protected lancer(evenement?: Event): void;
629
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StSearchField, never>;
630
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StSearchField, "st-search-field", never, {}, { "recherche": "recherche"; }, never, never, true, never>;
2788
+ export declare class StSearchField extends ControleDeSaisie {
2789
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
2790
+ private readonly saisie;
2791
+ /** Sans bouton « Rechercher » : Entree lance (barres de filtres, planches 4, 10, 12, 14, 15). */
2792
+ readonly compact: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2793
+ /** Etiquette affichee au-dessus du champ (barre de filtres) ; lue dans tous les cas. */
2794
+ readonly libelleVisible: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2795
+ /** Style de l'etiquette affichee : `micro-capitales` dans une barre de filtres (EA-90). */
2796
+ readonly presentation: import("@angular/core").InputSignal<PresentationDeLibelle>;
2797
+ /**
2798
+ * Recherche en cours : le bouton attend (`aria-busy`), il n'est jamais desactive ; en `compact`,
2799
+ * un indicateur muet remplace la loupe.
2800
+ */
2801
+ readonly chargement: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2802
+ /** Emis a la validation — Entree ou bouton —, et non a chaque frappe. */
2803
+ readonly recherche: import("@angular/core").OutputEmitterRef<string>;
2804
+ /** L'indicateur compact, differe et tenu : une reponse en 150 ms ne fait rien clignoter. */
2805
+ protected readonly attenteVisible: import("@angular/core").Signal<boolean>;
2806
+ protected surSaisie(evenement: Event): void;
2807
+ protected lancer(evenement?: Event): void;
2808
+ /** La croix vide le champ et rend le focus au champ : la saisie reprend la ou elle etait. */
2809
+ protected effacer(): void;
2810
+ static ɵfac: i0.ɵɵFactoryDeclaration<StSearchField, never>;
2811
+ static ɵcmp: i0.ɵɵComponentDeclaration<StSearchField, "st-search-field", never, {
2812
+ "compact": {
2813
+ "alias": "compact";
2814
+ "required": false;
2815
+ "isSignal": true;
2816
+ };
2817
+ "libelleVisible": {
2818
+ "alias": "libelleVisible";
2819
+ "required": false;
2820
+ "isSignal": true;
2821
+ };
2822
+ "presentation": {
2823
+ "alias": "presentation";
2824
+ "required": false;
2825
+ "isSignal": true;
2826
+ };
2827
+ "chargement": {
2828
+ "alias": "chargement";
2829
+ "required": false;
2830
+ "isSignal": true;
2831
+ };
2832
+ }, {
2833
+ "recherche": "recherche";
2834
+ }, never, ["[stRaccourci]"], true, never>;
631
2835
  }
632
-
633
2836
  /**
634
2837
  * IBAN. La valeur du modele est NORMALISEE — sans espaces, en majuscules —, et
635
2838
  * l'affichage groupe par quatre.
@@ -637,94 +2840,115 @@ declare class StSearchField extends ControleDeSaisie {
637
2840
  * ```html
638
2841
  * <st-iban-field libelle="IBAN du beneficiaire" [formField]="virement.iban" />
639
2842
  * <!-- schema : validate(chemin.iban, ({ value }) => erreurIban(value())) -->
2843
+ * <!-- un IBAN deja connu, masque au repos : -->
2844
+ * <st-iban-field libelle="IBAN du compte" masque readonly [value]="compte.iban" />
640
2845
  * ```
641
2846
  *
642
2847
  * ⚠️ **Le groupement se fait a la sortie du champ, jamais pendant la frappe.**
643
2848
  * Reformater a chaque caractere deplace le curseur a la fin : corriger une
644
2849
  * erreur au milieu de 27 caracteres devient impossible, chaque frappe renvoyant a
645
- * la fin de la ligne.
2850
+ * la fin de la ligne. Le changement de forme s'annonce (« IBAN : FR76 3000 … »).
646
2851
  *
647
2852
  * ⚠️ **Aucune verification de validite ici** : elle appartient au schema, par
648
2853
  * `erreurIban`, pour s'afficher au bon moment et par le bon canal. Et elle reste un
649
2854
  * confort (SEC-5) : le serveur revalide.
650
2855
  *
651
- * `autocapitalize="characters"` et correction orthographique coupee : un IBAN
652
- * n'est pas un mot, et une correction automatique le fausserait.
653
- */
654
- declare class StIbanField extends ControleDeSaisie {
655
- private readonly libelles;
656
- private readonly enSaisie;
657
- private readonly brut;
658
- protected readonly aideLue: _angular_core.Signal<string>;
659
- /**
660
- * Brut pendant la saisie ; groupe par quatre au repos. Une valeur changee de
661
- * l'exterieur pendant la saisie — remise a zero du formulaire — l'emporte sur
662
- * le brut, qui ne la represente plus.
663
- */
664
- protected readonly affichage: _angular_core.Signal<string>;
665
- protected auFocus(): void;
666
- protected surSaisie(evenement: Event): void;
667
- protected aLaSortie(): void;
668
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StIbanField, never>;
669
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StIbanField, "st-iban-field", never, {}, {}, never, never, true, never>;
670
- }
671
-
672
- /** `tel` : numero complet, indicatif compris. `tel-national` : sans indicatif. */
673
- type RemplissageDeTelephone = 'tel' | 'tel-national';
674
- /**
675
- * Numero de telephone. La valeur du modele ne garde que les chiffres et le `+` de
676
- * tete ; la saisie s'affiche telle qu'elle a ete tapee.
677
- *
678
- * ```html
679
- * <st-phone-field libelle="Telephone portable" [formField]="contact.telephone" />
680
- * <!-- schema : validate(chemin.telephone, ({ value }) => erreurTelephone(value())) -->
681
- * ```
2856
+ * ⚠️ **`masque` : un IBAN connu ne s'expose pas par-dessus l'epaule.** Au repos, le champ montre
2857
+ * `masquerIban` (« CH74 •••• •••• •••• •291 1 ») ; « Reveler 30s », bouton bascule a
2858
+ * `aria-pressed` dans le cadre, le montre en clair pour `rythme.tenue.revelation`, puis il se
2859
+ * remasque — aussi a la sortie du champ, a l'envoi du formulaire et avant l'impression. Modifiable,
2860
+ * le champ montre la valeur en clair pendant la saisie et en erreur : on ne corrige pas des points.
2861
+ * En lecture seule, il reste masque meme en erreur ; sur papier, il est toujours masque.
682
2862
  *
683
- * ⚠️ **Aucun formatage automatique.** Le groupement des chiffres depend du pays,
684
- * et reformater pendant la frappe renvoie le curseur en fin de ligne. La saisie
685
- * reste celle de la personne, espaces et points compris.
2863
+ * ⚠️ **`aria-pressed` dit ce qui est A L'ECRAN** : vrai des que la valeur est en clair, quelle
2864
+ * qu'en soit la raison (revelation, saisie, erreur). Enfonce, le bouton masque : en saisie, il
2865
+ * prend le focus, et la sortie du champ masque la valeur (on ne tape pas dans des points). Le
2866
+ * fond enfonce et l'oeil barre, eux, disent la revelation A LA DEMANDE, pour sa duree. Le nom
2867
+ * « Reveler 30s » est complete par une description : l'etiquette du champ et la duree en toutes
2868
+ * lettres (« 30s » se lirait « thirties » en anglais).
686
2869
  *
687
- * ⚠️ **Pas de selecteur de pays, pas de verification par pays.** Il faudrait une
688
- * table des plans de numerotation, lourde et souvent perimee : c'est au serveur
689
- * de dire si le numero existe (SEC-5). `erreurTelephone` ne verifie que la forme.
2870
+ * Le glyphe `banque` en tete du cadre est DECORATIF : l'etiquette porte le sens. Chasse fixe a
2871
+ * zero barre (O et 0 ne se confondent plus), ilot de gauche a droite en ecriture inverse.
690
2872
  *
691
- * `type="tel"`, et jamais `type="number"` : un numero n'est pas une quantite, et le
692
- * champ numerique retire le zero de tete et le `+`.
2873
+ * `autocapitalize="characters"` et correction orthographique coupee : un IBAN
2874
+ * n'est pas un mot, et une correction automatique le fausserait.
693
2875
  */
694
- declare class StPhoneField extends ControleDeSaisie {
695
- readonly autocomplete: _angular_core.InputSignal<RemplissageDeTelephone>;
696
- private readonly brut;
697
- /**
698
- * La saisie telle que tapee, tant qu'elle represente encore la valeur ; une
699
- * valeur changee de l'exterieur — remise a zero, pre-remplissage — l'emporte.
700
- */
701
- protected readonly affichage: _angular_core.Signal<string>;
702
- protected surSaisie(evenement: Event): void;
703
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StPhoneField, never>;
704
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StPhoneField, "st-phone-field", never, { "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2876
+ export declare class StIbanField extends ControleDeSaisie {
2877
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
2878
+ private readonly locale;
2879
+ private readonly element;
2880
+ protected readonly annonce: AnnonceLocale;
2881
+ /** Masque au repos, revelable pour `rythme.tenue.revelation` (un IBAN deja connu). */
2882
+ readonly masque: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
2883
+ private readonly detection;
2884
+ private readonly bouton;
2885
+ protected readonly idDuBouton: string;
2886
+ private readonly enSaisie;
2887
+ private readonly brut;
2888
+ protected readonly revele: import("@angular/core").WritableSignal<boolean>;
2889
+ /** Masque demande par le bouton alors que la valeur etait en clair (erreur). */
2890
+ private readonly masqueDemande;
2891
+ /** Impression en cours : sur papier, la valeur est masquee quoi qu'il arrive. */
2892
+ private readonly impression;
2893
+ private minuterie;
2894
+ /** L'exemple aide a TAPER : en lecture seule, il n'a rien a dire. */
2895
+ protected readonly aideLue: import("@angular/core").Signal<string | null>;
2896
+ /** « Reveler 30s » : la duree de la revelation dite dans le nom du bouton, qui ne change pas. */
2897
+ protected readonly libelleDuBouton: import("@angular/core").Signal<string>;
2898
+ /** Ce que le bouton revele, et pour combien de temps : « IBAN du compte : 30 secondes ». */
2899
+ protected readonly descriptionDuBouton: import("@angular/core").Signal<string>;
2900
+ /**
2901
+ * Masquee : au repos ; en lecture seule, meme au focus et meme en erreur ; toujours a
2902
+ * l'impression. Modifiable, jamais pendant la saisie ni en erreur — un IBAN refuse n'est pas un
2903
+ * IBAN connu, et on ne corrige pas des points (planche 3b) —, sauf masque demande par le bouton.
2904
+ */
2905
+ protected readonly masquee: import("@angular/core").Signal<boolean>;
2906
+ /** Valeur en clair dans un champ `masque` : l'etat que dit le bouton bascule. */
2907
+ protected readonly enClair: import("@angular/core").Signal<boolean>;
2908
+ /**
2909
+ * Brut pendant la saisie ; groupe par quatre au repos ; masque si demande. Une valeur changee de
2910
+ * l'exterieur pendant la saisie — remise a zero du formulaire — l'emporte sur le brut, qui ne
2911
+ * la represente plus.
2912
+ */
2913
+ protected readonly affichage: import("@angular/core").Signal<string>;
2914
+ constructor();
2915
+ protected auFocus(): void;
2916
+ protected surSaisie(evenement: Event): void;
2917
+ protected aLaSortie(): void;
2918
+ protected basculer(): void;
2919
+ protected remasquer(): void;
2920
+ /** Avant l'impression : masque, et rendu tout de suite (l'impression n'attend pas le rendu). */
2921
+ protected avantImpression(): void;
2922
+ protected apresImpression(): void;
2923
+ /**
2924
+ * Enfonce, le bouton masque. En saisie, la valeur ne se masque qu'a la sortie du champ (on ne
2925
+ * tape pas dans des points) : le focus passe au bouton, ou le clic l'avait laisse au champ.
2926
+ */
2927
+ private masquerALaDemande;
2928
+ private duree;
2929
+ /** Le focus quitte le champ ET son bouton : la valeur revelee se remasque. */
2930
+ protected aLaSortieDuChamp(evenement: FocusEvent): void;
2931
+ private arreterLaMinuterie;
2932
+ static ɵfac: i0.ɵɵFactoryDeclaration<StIbanField, never>;
2933
+ static ɵcmp: i0.ɵɵComponentDeclaration<StIbanField, "st-iban-field", never, {
2934
+ "masque": {
2935
+ "alias": "masque";
2936
+ "required": false;
2937
+ "isSignal": true;
2938
+ };
2939
+ }, {}, never, ["[stMeta]", "[stAide]", "[stIndication]"], true, never>;
705
2940
  }
706
-
707
2941
  /**
708
- * Un choix d'une liste : `st-select`, `st-combobox`, `st-multiselect`.
709
- *
710
- * La `valeur` part dans le modele, le `libelle` s'affiche : un identifiant
711
- * technique ne s'affiche jamais, et un libelle traduit ne s'envoie jamais.
2942
+ * `standard` : le controle pose sur la surface. `tonale` : le meme controle sur un fond teinte
2943
+ * (`surfaceConteneurBas`), sous le meme filet lisible (EA-07) : une barre de filtres, le compte
2944
+ * debiteur d'une coquille etroite (planches 10 et 6, D108).
712
2945
  */
713
- interface OptionDeListe {
714
- readonly valeur: string;
715
- readonly libelle: string;
716
- readonly desactivee?: boolean;
717
- /** Regroupe les options consecutives sous un intitule (`optgroup`). */
718
- readonly groupe?: string;
719
- }
720
- /** Sans accents ni casse : « eleve » trouve « Élève ». */
721
- declare function normaliserPourRecherche(texte: string): string;
722
- /** Options dont le libelle CONTIENT le texte cherche, sans accents ni casse. */
723
- declare function filtrerOptions(options: readonly OptionDeListe[], recherche: string): readonly OptionDeListe[];
724
-
725
- interface BlocDOptions {
726
- readonly groupe: string | null;
727
- readonly options: readonly OptionDeListe[];
2946
+ export type VarianteDeSelect = 'standard' | 'tonale';
2947
+ interface BlocDOptions$1 {
2948
+ /** Identite stable du bloc : la valeur de sa premiere option. */
2949
+ readonly cle: string;
2950
+ readonly groupe: string | null;
2951
+ readonly options: readonly OptionDeListe[];
728
2952
  }
729
2953
  /**
730
2954
  * Liste deroulante, sur un `select` NATIF.
@@ -743,45 +2967,120 @@ interface BlocDOptions {
743
2967
  * option paraitrait choisie alors que personne ne l'a fait. Le modele vaut
744
2968
  * alors `''`, que `required` refuse.
745
2969
  *
746
- * `readonly` n'existe pas sur un `select` : le champ annonce `aria-readonly` et
747
- * ignore le changement, plutot que d'etre desactive — un champ desactive sort de
748
- * l'ordre de tabulation, et sa valeur ne se lit plus.
749
- */
750
- declare class StSelect extends ControleDeSaisie {
751
- protected readonly libelles: _angular_core.Signal<_starterlib_ui.LibellesUi>;
752
- readonly options: _angular_core.InputSignal<readonly OptionDeListe[]>;
753
- /** Texte de l'option vide. Par defaut : « Choisir… ». */
754
- readonly texteVide: _angular_core.InputSignal<string | null>;
755
- /** WCAG 1.3.5 : `country`, `sex`, `honorific-prefix`… */
756
- readonly autocomplete: _angular_core.InputSignal<string | null>;
757
- /** Options consecutives d'un meme groupe, dans l'ordre fourni. */
758
- protected readonly blocs: _angular_core.Signal<readonly BlocDOptions[]>;
759
- protected surChoix(evenement: Event): void;
760
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StSelect, never>;
761
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StSelect, "st-select", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "texteVide": { "alias": "texteVide"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2970
+ * `readonly` n'existe pas sur un `select` : le champ annonce `aria-readonly`, et le
2971
+ * selecteur ne s'ouvre plus (clic et touches annules) plutot que d'etre desactive — un
2972
+ * champ desactive sort de l'ordre de tabulation, et sa valeur ne se lit plus. Sans chevron :
2973
+ * une liste qui ne s'ouvre pas ne promet pas de s'ouvrir.
2974
+ *
2975
+ * ⚠️ **Une valeur absente des options n'est jamais tue** (A1131). Beneficiaire cloture,
2976
+ * options rechargees : le modele garde un identifiant qu'aucune option ne porte, et le
2977
+ * navigateur afficherait « Choisir… » pendant que le formulaire part avec la valeur
2978
+ * invisible. Elle s'affiche « Valeur non affichable » (option desactivee, choisie), et un
2979
+ * avertissement le dit en developpement — SANS la valeur, qui peut etre un compte ou un IBAN
2980
+ * (une valeur sensible n'est jamais journalisee).
2981
+ */
2982
+ export declare class StSelect extends ControleDeSaisie {
2983
+ /**
2984
+ * Un texte de donnees : sans commande de direction, et isole par son element (`dir="auto"` ou
2985
+ * `<bdi>`), il ne reordonne ni lui-meme ni ce qui l'entoure (audit du 2026-09-26, S-1 ; audit
2986
+ * etendu du 2026-09-27, A-2).
2987
+ */
2988
+ protected readonly affichable: typeof sansCommandesDeDirection;
2989
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
2990
+ readonly options: import("@angular/core").InputSignal<readonly OptionDeListe[]>;
2991
+ /** Texte de l'option vide. Par defaut : « Choisir… ». */
2992
+ readonly texteVide: import("@angular/core").InputSignal<string | null>;
2993
+ /** WCAG 1.3.5 : `country`, `sex`, `honorific-prefix`… */
2994
+ readonly autocomplete: import("@angular/core").InputSignal<TypeDAutocompletion | null>;
2995
+ /** Glyphe decoratif de tete, dans le cadre (l'etiquette porte le sens). */
2996
+ readonly icone: import("@angular/core").InputSignal<"iban" | "code" | "devise" | "fichier" | "message" | "menu" | "accessibilite" | "appareils" | "arborescence" | "asterisque" | "badge-coche" | "banque" | "batiment" | "bifurcation" | "billets" | "billets-envoi" | "billets-pile" | "boite" | "boite-de-reception" | "bouclier" | "bouclier-alerte" | "bouclier-coche" | "bouclier-coeur" | "bouclier-croix" | "bouclier-moitie" | "bouclier-recherche" | "bouclier-utilisateur" | "boussole" | "bouton-curseur" | "bulle-question" | "cadenas" | "cadenas-horloge" | "cadenas-ouvert" | "cadre-pied" | "cadre-texte" | "calendrier" | "calendrier-evenement" | "calendrier-horloge" | "calendrier-jour" | "calques" | "carte-bancaire" | "carte-bancaire-barre" | "carte-bancaire-cadenas" | "carte-contact" | "carte-identite" | "cartes-empilees" | "case-cochee" | "casse" | "cercle" | "cercle-alerte" | "cercle-chevron-bas" | "cercle-coche" | "cercle-coche-ouvert" | "cercle-croix" | "cercle-info" | "cercle-moins" | "cercle-plus" | "cercle-question" | "certificat" | "chandelier" | "chargement" | "cheque" | "chevron-bas" | "chevron-droite" | "chevron-gauche" | "chevron-haut" | "chevrons-droite" | "chevrons-haut-bas" | "cle" | "cloche" | "cloche-sonnerie" | "coche" | "code-qr" | "code-qr-scanner" | "coffre-fort" | "colonnes" | "connexion" | "contraste" | "copie" | "corbeille" | "corbeille-croix" | "courriel" | "crayon" | "croix" | "curseur-clic" | "deconnexion" | "disposition" | "dollar" | "dossier" | "dossier-barre" | "dossier-ouvert" | "double-coche" | "echange" | "eclair" | "empreinte-digitale" | "enregistrer" | "entree" | "envoyer" | "epaisseur-de-trait" | "epingle" | "etoile" | "euro" | "fichier-image" | "fichier-pdf" | "fichier-texte" | "filtre" | "filtre-barre" | "filtre-lignes" | "fleche-bas" | "fleche-bas-gauche" | "fleche-bas-ligne" | "fleche-droite" | "fleche-gauche" | "fleche-haut" | "fleche-haut-droite" | "fleche-haut-ligne" | "fleche-large-haut" | "fleches-gauche-droite" | "flocon" | "flou" | "formes" | "globe" | "graphique-anneau" | "graphique-barres" | "graphique-barres-cadre" | "graphique-camembert" | "graphique-ligne" | "graphique-lignes" | "grille" | "grille-lignes" | "hexagone" | "historique" | "horloge" | "horloge-fleche" | "imprimer" | "interdit" | "jalons" | "jauge" | "lien" | "lien-externe" | "lignes" | "lignes-crayon" | "liste" | "liste-coche" | "liste-controle" | "liste-numerotee" | "luminosite" | "lune" | "maillet" | "maison" | "marque-page" | "menu-ouvert" | "minuteur" | "mise-au-point" | "mise-en-page-image" | "moins" | "nuage-barre" | "nuage-televerser" | "octogone-alerte" | "oeil" | "oeil-barre" | "panneau-gauche" | "parametres" | "parapluie" | "parchemin" | "pieces" | "plus" | "pointeur" | "points" | "points-verticaux" | "portefeuille" | "portefeuille-cartes" | "presse-papiers-coche" | "presse-papiers-horloge" | "priorite-haute" | "rafraichir" | "recherche" | "recherche-barre" | "recherche-texte" | "rectangle-points" | "recu" | "redemarrer" | "reglages" | "regle" | "reseau-jauge" | "rotation-arriere" | "routeur" | "sablier" | "sablier-bas" | "sablier-haut" | "sac-argent" | "sans-contact" | "serveur" | "soleil" | "style-de-trait" | "synchro" | "synchro-probleme" | "tableau" | "tableau-de-bord" | "tableau-de-bord-plus" | "tablette" | "tabulation" | "telecharger" | "telephone-mobile" | "televerser" | "tendance-baisse" | "tendance-hausse" | "terminal" | "tirelire" | "triangle-alerte" | "triangle-bas" | "triangle-haut" | "trombone" | "utilisateur" | "utilisateur-crayon" | "utilisateurs" | "wifi" | "wifi-barre" | null>;
2997
+ /** Le style de l'etiquette (voir `st-form-field`). */
2998
+ readonly presentation: import("@angular/core").InputSignal<PresentationDeLibelle>;
2999
+ /**
3000
+ * `tonale` pose le controle sur un fond teinte, memes etats et meme filet (D108). La lecture
3001
+ * seule et la desactivation gardent leur fond propre : elles se lisent d'abord.
3002
+ */
3003
+ readonly variante: import("@angular/core").InputSignal<VarianteDeSelect>;
3004
+ /** Options consecutives d'un meme groupe, dans l'ordre fourni. */
3005
+ protected readonly blocs: import("@angular/core").Signal<readonly BlocDOptions$1[]>;
3006
+ /** La valeur du modele, quand aucune option ne la porte (sinon `null`). */
3007
+ protected readonly valeurInconnue: import("@angular/core").Signal<string | null>;
3008
+ constructor();
3009
+ /** Lecture seule : le selecteur ne s'ouvre pas au clic (le focus, lui, se prend). */
3010
+ protected surPression(evenement: MouseEvent): void;
3011
+ /** Lecture seule : ni Espace, ni Entree, ni fleches, ni lettres ne changent la valeur. */
3012
+ protected surTouche(evenement: KeyboardEvent): void;
3013
+ protected surChoix(evenement: Event): void;
3014
+ static ɵfac: i0.ɵɵFactoryDeclaration<StSelect, never>;
3015
+ static ɵcmp: i0.ɵɵComponentDeclaration<StSelect, "st-select", never, {
3016
+ "options": {
3017
+ "alias": "options";
3018
+ "required": true;
3019
+ "isSignal": true;
3020
+ };
3021
+ "texteVide": {
3022
+ "alias": "texteVide";
3023
+ "required": false;
3024
+ "isSignal": true;
3025
+ };
3026
+ "autocomplete": {
3027
+ "alias": "autocomplete";
3028
+ "required": false;
3029
+ "isSignal": true;
3030
+ };
3031
+ "icone": {
3032
+ "alias": "icone";
3033
+ "required": false;
3034
+ "isSignal": true;
3035
+ };
3036
+ "presentation": {
3037
+ "alias": "presentation";
3038
+ "required": false;
3039
+ "isSignal": true;
3040
+ };
3041
+ "variante": {
3042
+ "alias": "variante";
3043
+ "required": false;
3044
+ "isSignal": true;
3045
+ };
3046
+ }, {}, never, ["[stMeta]", "[stAide]", "[stIndication]"], true, never>;
762
3047
  }
763
-
3048
+ /**
3049
+ * Disque plein d'un jour : borne de debut ou de fin d'une plage (capsule d'un cote), ou date
3050
+ * seule (jour choisi, plage d'un jour, borne sans son autre).
3051
+ */
3052
+ type Borne = 'debut' | 'fin' | 'seule';
764
3053
  interface Jour {
765
- readonly date: DateIso;
766
- /** Jour d'un mois voisin : cellule vide, la date vit dans son propre mois. */
767
- readonly horsDuMois: boolean;
768
- readonly numero: string;
769
- readonly nom: string;
770
- readonly horsBornes: boolean;
771
- readonly choisi: boolean;
772
- readonly dansLaPlage: boolean;
773
- readonly aujourdHui: boolean;
3054
+ readonly date: DateIso;
3055
+ /** Jour d'un mois voisin : cellule vide, la date vit dans son propre mois. */
3056
+ readonly horsDuMois: boolean;
3057
+ readonly numero: string;
3058
+ readonly nom: string;
3059
+ readonly horsBornes: boolean;
3060
+ readonly borne: Borne | null;
3061
+ readonly dansLaPlage: boolean;
3062
+ readonly aujourdHui: boolean;
3063
+ readonly rejete: boolean;
3064
+ }
3065
+ /** Annees offertes par le saut d'annee, bornes comprises. */
3066
+ export interface AnneesDuCalendrier {
3067
+ readonly min: number;
3068
+ readonly max: number;
774
3069
  }
775
3070
  /**
776
- * Calendrier d'un mois, pour choisir une date.
3071
+ * Calendrier d'un mois, pour choisir une date ou montrer une periode.
777
3072
  *
778
3073
  * ```html
779
3074
  * <st-calendar [selection]="depart()" dateMin="2026-09-17" (choix)="depart.set($event)" />
3075
+ * <st-calendar pleineLargeur [plage]="periode()" [annees]="{ min: 1900, max: 2026 }">
3076
+ * <span stPied>Periode : 8 jours</span>
3077
+ * </st-calendar>
780
3078
  * ```
781
3079
  *
782
3080
  * ⚠️ **Une aide, jamais la seule voie.** Dans `st-date-field`, le calendrier
783
3081
  * complete un champ texte : une date de naissance se tape plus vite qu'elle ne se
784
- * cherche mois par mois, et un calendrier reste penible au lecteur d'ecran.
3082
+ * cherche mois par mois, et un calendrier reste penible au lecteur d'ecran. Le saut
3083
+ * d'annee (liste native) evite les quarante Maj + Page d'une date de naissance.
785
3084
  *
786
3085
  * ⚠️ **Le clavier navigue de DATE en date, pas de cellule en cellule** (decision
787
3086
  * D7 de l'audit de la vague 3). Fleche droite le 30 septembre mene au 1er
@@ -790,71 +3089,179 @@ interface Jour {
790
3089
  * entre cellules affichees : il aurait fallu la contourner sur chaque touche qui
791
3090
  * compte, et elle aurait fait entrer le CDK dans les formulaires.
792
3091
  *
793
- * Semaine commencant au jour de la locale, noms de jours et de mois dans la
794
- * langue courante, « aujourd'hui » dans le fuseau de la personne
795
- * (`FUSEAU_PAR_DEFAUT`) et non celui du poste.
796
- */
797
- declare class StCalendar {
798
- protected readonly libelles: _angular_core.Signal<_starterlib_ui.LibellesUi>;
799
- private readonly locale;
800
- private readonly element;
801
- private readonly injecteur;
802
- private readonly aujourdHui;
803
- readonly selection: _angular_core.InputSignal<string | null>;
804
- readonly dateMin: _angular_core.InputSignal<string | null>;
805
- readonly dateMax: _angular_core.InputSignal<string | null>;
806
- /** Periode a faire ressortir, pour un choix de plage. */
807
- readonly plage: _angular_core.InputSignal<PlageDeDates | null>;
808
- readonly choix: _angular_core.OutputEmitterRef<string>;
809
- /** Echap : le conteneur decide de fermer, et ou rendre le focus. */
810
- readonly fermeture: _angular_core.OutputEmitterRef<void>;
811
- protected readonly identifiants: {
812
- readonly titre: `${string}-titre`;
813
- readonly aide: `${string}-aide`;
814
- };
815
- /** La date qui porte le focus. Suit la selection, bornee. */
816
- private readonly active;
817
- private readonly premierJour;
818
- protected readonly titre: _angular_core.Signal<string>;
819
- protected readonly joursDeLaSemaine: _angular_core.Signal<{
820
- court: string;
821
- long: string;
822
- }[]>;
823
- protected readonly semaines: _angular_core.Signal<readonly (readonly Jour[])[]>;
824
- protected readonly moisPrecedentPossible: _angular_core.Signal<boolean>;
825
- protected readonly moisSuivantPossible: _angular_core.Signal<boolean>;
826
- protected estActive(date: DateIso): boolean;
827
- /** Amene le focus sur la date active. */
828
- focus(): void;
829
- protected changerDeMois(ecart: number): void;
830
- protected choisir(jour: Jour): void;
831
- protected surTouche(evenement: KeyboardEvent): void;
832
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StCalendar, never>;
833
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StCalendar, "st-calendar", never, { "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "dateMin": { "alias": "dateMin"; "required": false; "isSignal": true; }; "dateMax": { "alias": "dateMax"; "required": false; "isSignal": true; }; "plage": { "alias": "plage"; "required": false; "isSignal": true; }; }, { "choix": "choix"; "fermeture": "fermeture"; }, never, never, true, never>;
3092
+ * ⚠️ **Echap n'appartient au calendrier que s'il est `fermable`** (pose par
3093
+ * `st-date-field` et `st-date-range`) : il la consomme alors, et l'arrete — sans quoi le
3094
+ * `st-dialog` qui contient le formulaire se fermerait avec lui. Seul, il la laisse passer.
3095
+ *
3096
+ * ⚠️ **Un clic ne deplace pas le focus** (`mousedown` annule partout, sauf sur la liste
3097
+ * d'annees) : sous WebKit, un bouton clique ne prend pas le focus mais retire celui de l'element
3098
+ * actif, et un clic dans le blanc le donnait a l'ancetre focalisable (`cdk-dialog-container`) ;
3099
+ * le conteneur qui ferme a la sortie du focus retirait le calendrier avant le clic. Quand le
3100
+ * focus est dans la grille, un changement de mois ou un choix au clic le pose sur la nouvelle
3101
+ * date active : le bouton du jour qui le portait disparait avec son mois.
3102
+ *
3103
+ * Reference Claude Design (planches 3a et 3b) : bornes et jour choisi en disques pleins de
3104
+ * 40 px, capsule de plage coupee carrement au changement de ligne, aujourd'hui marque d'un point.
3105
+ * Semaine commencant au jour de la locale, noms de jours et de mois dans la langue courante,
3106
+ * « aujourd'hui » dans le fuseau de la personne (`FUSEAU_PAR_DEFAUT`) et non celui du poste,
3107
+ * relu a chaque prise de focus (un calendrier ouvert la veille ne garde pas la veille).
3108
+ */
3109
+ export declare class StCalendar {
3110
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
3111
+ private readonly locale;
3112
+ private readonly fuseau;
3113
+ private readonly element;
3114
+ private readonly injecteur;
3115
+ private readonly aujourdHui;
3116
+ readonly selection: import("@angular/core").InputSignal<string | null>;
3117
+ readonly dateMin: import("@angular/core").InputSignal<string | null>;
3118
+ readonly dateMax: import("@angular/core").InputSignal<string | null>;
3119
+ /** Periode a faire ressortir, pour un choix de plage. */
3120
+ readonly plage: import("@angular/core").InputSignal<PlageDeDates | null>;
3121
+ /**
3122
+ * Date refusee par une regle de l'application (validation differee) : tuile rouge barree. La
3123
+ * raison se dit dans le pied (`[stPied]`), en texte.
3124
+ */
3125
+ readonly rejet: import("@angular/core").InputSignal<string | null>;
3126
+ /**
3127
+ * Annees du saut d'annee. Par defaut : celles des bornes, sinon dix ans de part et d'autre
3128
+ * de l'annee courante. Une date de naissance passe `{ min: 1900, max: <annee courante> }`.
3129
+ */
3130
+ readonly annees: import("@angular/core").InputSignal<AnneesDuCalendrier | null>;
3131
+ /** Occupe la largeur de son conteneur (cases fluides, 44 px de haut) : calendrier deploye. */
3132
+ readonly pleineLargeur: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
3133
+ /** Un conteneur ecoute `fermeture` : Echap lui appartient, et l'aide le dit. */
3134
+ readonly fermable: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
3135
+ readonly choix: import("@angular/core").OutputEmitterRef<string>;
3136
+ /** Echap (calendrier `fermable`) : le conteneur decide de fermer, et ou rendre le focus. */
3137
+ readonly fermeture: import("@angular/core").OutputEmitterRef<void>;
3138
+ protected readonly identifiants: {
3139
+ readonly titre: `${string}-titre`;
3140
+ readonly aide: `${string}-aide`;
3141
+ readonly pied: `${string}-pied`;
3142
+ };
3143
+ /** La date qui porte le focus. Suit la selection, bornee. */
3144
+ private readonly active;
3145
+ private readonly premierJour;
3146
+ protected readonly anneeActive: import("@angular/core").Signal<number>;
3147
+ protected readonly titre: import("@angular/core").Signal<string>;
3148
+ protected readonly listeDAnnees: import("@angular/core").Signal<readonly number[]>;
3149
+ /** « Lun », « Mar » : l'abreviation de la langue, sans son point, a l'initiale. */
3150
+ protected readonly joursDeLaSemaine: import("@angular/core").Signal<{
3151
+ court: string;
3152
+ long: string;
3153
+ }[]>;
3154
+ protected readonly semaines: import("@angular/core").Signal<readonly (readonly Jour[])[]>;
3155
+ protected readonly moisPrecedentPossible: import("@angular/core").Signal<boolean>;
3156
+ protected readonly moisSuivantPossible: import("@angular/core").Signal<boolean>;
3157
+ constructor();
3158
+ protected estActive(date: DateIso): boolean;
3159
+ /** Amene le focus sur la date active. */
3160
+ focus(): void;
3161
+ protected relireAujourdHui(): void;
3162
+ protected changerDeMois(ecart: number): void;
3163
+ protected changerDAnnee(evenement: Event): void;
3164
+ protected choisir(jour: Jour): void;
3165
+ /** Un clic ne deplace pas le focus, sauf sur la liste d'annees (liste native a ouvrir). */
3166
+ protected surAppui(evenement: MouseEvent): void;
3167
+ private focusDansLaGrille;
3168
+ private focusApresRendu;
3169
+ protected surTouche(evenement: KeyboardEvent): void;
3170
+ /**
3171
+ * Le sens d'ecriture HERITE, sans style calcule (ni global `getComputedStyle`, ni mise en
3172
+ * page) : `:dir()` quand le moteur le connait, sinon l'attribut `dir` le plus proche.
3173
+ */
3174
+ private ecritDeDroiteAGauche;
3175
+ static ɵfac: i0.ɵɵFactoryDeclaration<StCalendar, never>;
3176
+ static ɵcmp: i0.ɵɵComponentDeclaration<StCalendar, "st-calendar", never, {
3177
+ "selection": {
3178
+ "alias": "selection";
3179
+ "required": false;
3180
+ "isSignal": true;
3181
+ };
3182
+ "dateMin": {
3183
+ "alias": "dateMin";
3184
+ "required": false;
3185
+ "isSignal": true;
3186
+ };
3187
+ "dateMax": {
3188
+ "alias": "dateMax";
3189
+ "required": false;
3190
+ "isSignal": true;
3191
+ };
3192
+ "plage": {
3193
+ "alias": "plage";
3194
+ "required": false;
3195
+ "isSignal": true;
3196
+ };
3197
+ "rejet": {
3198
+ "alias": "rejet";
3199
+ "required": false;
3200
+ "isSignal": true;
3201
+ };
3202
+ "annees": {
3203
+ "alias": "annees";
3204
+ "required": false;
3205
+ "isSignal": true;
3206
+ };
3207
+ "pleineLargeur": {
3208
+ "alias": "pleineLargeur";
3209
+ "required": false;
3210
+ "isSignal": true;
3211
+ };
3212
+ "fermable": {
3213
+ "alias": "fermable";
3214
+ "required": false;
3215
+ "isSignal": true;
3216
+ };
3217
+ }, {
3218
+ "choix": "choix";
3219
+ "fermeture": "fermeture";
3220
+ }, never, ["[stPied]"], true, never>;
834
3221
  }
835
-
836
3222
  /**
837
3223
  * Cle d'un fichier choisi : deux choix du meme fichier ne l'ajoutent pas deux
838
3224
  * fois, et l'application s'en sert pour dire ou en est chaque televersement.
839
3225
  */
840
- declare function cleDeFichier(fichier: File): string;
3226
+ export declare function cleDeFichier(fichier: File): string;
841
3227
  /**
842
3228
  * Ou en est un fichier, vu de l'application. `message` dit POURQUOI un fichier
843
3229
  * est refuse — « antivirus indisponible » et « type refuse » n'appellent pas la
844
3230
  * meme suite (UX-3 de la 0.6.0).
845
3231
  */
846
- interface EtatDeTeleversementAffiche {
847
- readonly etape: 'en-cours' | 'depose' | 'refuse';
848
- /** 0 a 100, pendant l'envoi. */
849
- readonly progression?: number;
850
- readonly message?: string;
3232
+ export interface EtatDeTeleversementAffiche {
3233
+ readonly etape: 'en-cours' | 'depose' | 'refuse';
3234
+ /** 0 a 100, pendant l'envoi. */
3235
+ readonly progression?: number;
3236
+ /** Ce que dit la ligne sous le nom : « Chiffrement en cours... », la raison d'un refus. */
3237
+ readonly message?: string;
3238
+ /**
3239
+ * Texte court en fin de ligne : debit, duree, verdict (« 68 % (1,4 Mo/s) »). Par defaut, le
3240
+ * pourcentage pendant l'envoi, et rien ensuite.
3241
+ */
3242
+ readonly detail?: string;
3243
+ /**
3244
+ * Pendant l'envoi : `false` quand il ne peut plus etre interrompu (confirmation du depot en
3245
+ * cours). Le bouton « Annuler » n'est alors pas rendu. Vrai par defaut.
3246
+ */
3247
+ readonly annulable?: boolean;
3248
+ }
3249
+ /** Un morceau d'une phrase affichee : du texte, ou un nom de fichier a isoler. */
3250
+ interface MorceauDePhrase {
3251
+ readonly texte: string;
3252
+ readonly nom: boolean;
3253
+ }
3254
+ /** Des fichiers ecartes par `nombreMax` : leur phrase (annonce, presence), et ses morceaux. */
3255
+ interface RefusDuNombre {
3256
+ readonly texte: string;
3257
+ readonly morceaux: readonly MorceauDePhrase[];
851
3258
  }
852
3259
  /**
853
3260
  * Choix de fichiers, sur un `input type="file"` natif.
854
3261
  *
855
3262
  * ```html
856
3263
  * <st-file-upload libelle="Justificatifs" accept=".pdf, image/*" [tailleMax]="5_000_000" multiple
857
- * [formField]="dossier.pieces" />
3264
+ * [nombreMax]="3" [formField]="dossier.pieces" />
858
3265
  * <!-- schema : validate(chemin.pieces, ({ value }) => erreursDeFichiers(value(), regles)) -->
859
3266
  * ```
860
3267
  *
@@ -863,62 +3270,537 @@ interface EtatDeTeleversementAffiche {
863
3270
  *
864
3271
  * ⚠️ **L'element natif reste la voie principale** (FE-4) : il ouvre le selecteur
865
3272
  * du systeme, l'appareil photo sur mobile, et se commande au clavier. Il est
866
- * masque visuellement, pas retire : le bouton affiche est son etiquette. Le
867
- * depot par glisser est un complement a la souris, jamais la seule voie.
3273
+ * masque visuellement, pas retire : le bouton affiche est son substitut a la souris,
3274
+ * et montre son focus. Le depot par glisser est un complement, jamais la seule voie
3275
+ * (WCAG 2.5.7).
868
3276
  *
869
3277
  * ⚠️ **Aucun apercu d'image** (SEC-7). Un apercu passe par une adresse `blob:`
870
3278
  * que la politique de securite du contenu doit autoriser, et un SVG affiche peut
871
3279
  * porter du script. Le nom et la taille suffisent a reconnaitre un fichier.
872
3280
  *
873
- * ⚠️ **`accept`, `tailleMax` et `nombreMax` sont un confort** (SEC-5) : ils
874
- * s'affichent en aide et filtrent le selecteur du systeme, mais la verification
875
- * est dans le schema — `erreursDeFichiers` —, et le serveur relit le contenu.
3281
+ * ⚠️ **Les noms s'affichent sans commandes de direction** (`nomAffichable`) : un
3282
+ * `facture\u202efdp.exe` ne se presente pas en PDF, ni a l'ecran, ni dans les etiquettes, ni
3283
+ * dans les annonces. Cite dans une phrase du dictionnaire (un statut, des fichiers ecartes), le
3284
+ * nom est en plus isole dans son ilot de gauche a droite : la phrase ne se reordonne pas autour
3285
+ * d'un nom en hebreu ou en arabe (audit UI du 2026-09-27, D-4).
876
3286
  *
877
- * Chaque changement de la liste s'annonce : « 2 fichiers choisis ». Un fichier
878
- * retire rend le focus au bouton de retrait suivant, ou au choix de fichiers : le
879
- * focus ne tombe jamais sur le document.
3287
+ * ⚠️ **`accept`, `tailleMax` et `nombreMax` sont un confort** (SEC-5) : ils
3288
+ * s'affichent en consignes et filtrent le choix, mais la verification est dans le schema —
3289
+ * `erreursDeFichiers` —, et le serveur relit le contenu.
3290
+ *
3291
+ * ⚠️ **`readonly` ne desactive pas** : le champ natif reste dans la tabulation (sa liste se
3292
+ * parcourt et se lit) et n'ouvre ni selecteur ni depot ; les retraits sont indisponibles
3293
+ * (`aria-disabled`), pas retires. Chromium expose `input type="file"` en role `button`, qui ne
3294
+ * prend pas `aria-readonly` en charge : le champ natif porte donc `aria-disabled` (focalisable,
3295
+ * annonce indisponible), et le substitut dit « Lecture seule », lu en description.
3296
+ *
3297
+ * Chaque changement s'annonce : « 2 fichiers choisis. », « X depose. », « X refuse : raison. ».
3298
+ * Des fichiers qui changent d'etat ensemble se disent en UNE annonce (D-15). Les fichiers ecartes
3299
+ * par `nombreMax` sont NOMMES en texte visible, en liste de la langue, relie au champ natif, et
3300
+ * l'annonce reprend ce texte. Un fichier retire rend le focus au bouton de retrait suivant, ou au
3301
+ * choix de fichiers ; un fichier remplace, au bouton de sa nouvelle ligne : le focus ne tombe
3302
+ * jamais sur le document.
880
3303
  *
881
3304
  * ⚠️ **Il ne televerse pas.** `etats` dit ou en est chaque fichier, et le bouton
882
- * de la ligne devient « Annuler » pendant l'envoi : le trajet — declaration, depot
3305
+ * de la ligne devient « Annuler » pendant l'envoi (le MEME bouton : il garde le focus a
3306
+ * l'arrivee ; absent quand l'envoi n'est plus annulable, le focus passant alors au choix de
3307
+ * fichiers) : le trajet — declaration, depot
883
3308
  * pre-signe, confirmation antivirus — vit dans `StTeleversement`
884
3309
  * (`@starterlib/core`), seul a parler au reseau.
885
3310
  */
886
- declare class StFileUpload extends ContratDeChamp implements FormValueControl<readonly File[]> {
887
- protected readonly libelles: _angular_core.Signal<_starterlib_ui.LibellesUi>;
888
- private readonly locale;
889
- private readonly element;
890
- private readonly injecteur;
891
- readonly value: _angular_core.ModelSignal<readonly File[]>;
892
- /** Attribut `accept` natif : `.pdf, image/*`. */
893
- readonly accept: _angular_core.InputSignal<string>;
894
- readonly multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
895
- /** En octets. Affiche en aide ; la verification est dans le schema. */
896
- readonly tailleMax: _angular_core.InputSignal<number | null>;
897
- /**
898
- * Ou en est chaque fichier, par `cleDeFichier`. Le composant AFFICHE ce trajet,
899
- * il ne le fait pas : `StTeleversement` de `@starterlib/core` s'en charge.
900
- */
901
- readonly etats: _angular_core.InputSignal<ReadonlyMap<string, EtatDeTeleversementAffiche> | null>;
902
- protected readonly annonce: AnnonceLocale;
903
- protected readonly survol: _angular_core.WritableSignal<boolean>;
904
- protected readonly aideLue: _angular_core.Signal<string | null>;
905
- protected readonly lignes: _angular_core.Signal<{
906
- fichier: File;
907
- cle: string;
908
- taille: string;
909
- etat: EtatDeTeleversementAffiche | null;
910
- }[]>;
911
- protected surChoix(evenement: Event): void;
912
- protected surSurvol(evenement: DragEvent): void;
913
- protected surDepot(evenement: DragEvent): void;
914
- /** Emis quand la personne interrompt un envoi : c'est l'application qui annule. */
915
- readonly annulation: _angular_core.OutputEmitterRef<File>;
916
- protected retirer(indice: number): void;
917
- protected aLaSortie(evenement: FocusEvent): void;
918
- private ajouter;
919
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<StFileUpload, never>;
920
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<StFileUpload, "st-file-upload", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "tailleMax": { "alias": "tailleMax"; "required": false; "isSignal": true; }; "etats": { "alias": "etats"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "annulation": "annulation"; }, never, never, true, never>;
3311
+ export declare class StFileUpload extends ContratDeChamp implements FormValueControl<readonly File[]> {
3312
+ protected readonly libelles: import("@angular/core").Signal<LibellesUi>;
3313
+ private readonly locale;
3314
+ private readonly element;
3315
+ private readonly document;
3316
+ private readonly injecteur;
3317
+ private readonly natif;
3318
+ readonly value: import("@angular/core").ModelSignal<readonly File[]>;
3319
+ /** Attribut `accept` natif : `.pdf, image/*`. Dit en clair dans les consignes. */
3320
+ readonly accept: import("@angular/core").InputSignal<string>;
3321
+ readonly multiple: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
3322
+ /** En octets. Dit dans les consignes ; la verification est dans le schema. */
3323
+ readonly tailleMax: import("@angular/core").InputSignal<number | null>;
3324
+ /**
3325
+ * Nombre de fichiers au plus, en choix multiple : dit dans les consignes, et un choix qui le
3326
+ * depasse n'ajoute que ce qui tient ; les fichiers ecartes sont nommes en texte visible.
3327
+ */
3328
+ readonly nombreMax: import("@angular/core").InputSignal<number | null>;
3329
+ /** Texte du bouton de choix. `null` : « Choisir un fichier » ou « Choisir des fichiers ». */
3330
+ readonly libelleDuChoix: import("@angular/core").InputSignal<string | null>;
3331
+ /**
3332
+ * Ou en est chaque fichier, par `cleDeFichier`. Le composant AFFICHE ce trajet,
3333
+ * il ne le fait pas : `StTeleversement` de `@starterlib/core` s'en charge.
3334
+ */
3335
+ readonly etats: import("@angular/core").InputSignal<ReadonlyMap<string, EtatDeTeleversementAffiche> | null>;
3336
+ /** Emis quand la personne interrompt un envoi : c'est l'application qui annule. */
3337
+ readonly annulation: import("@angular/core").OutputEmitterRef<File>;
3338
+ /**
3339
+ * Emis avec le fichier REMPLACE (« Remplacer » d'une ligne refusee), une fois le nouveau
3340
+ * choisi : l'application oublie son etat, le nouveau fichier est deja dans le modele.
3341
+ */
3342
+ readonly remplacement: import("@angular/core").OutputEmitterRef<File>;
3343
+ protected readonly annonce: AnnonceLocale;
3344
+ protected readonly survol: import("@angular/core").WritableSignal<boolean>;
3345
+ private readonly identifiants;
3346
+ protected readonly identifiantDesConsignes: string;
3347
+ protected readonly identifiantDeLaLecture: string;
3348
+ protected readonly identifiantDuRefus: string;
3349
+ /** « c.pdf non ajoute : 2 fichiers au plus. », jusqu'au prochain choix ou retrait. */
3350
+ protected readonly refusDuNombre: import("@angular/core").WritableSignal<RefusDuNombre | null>;
3351
+ /** `dragenter` et `dragleave` se repondent a chaque enfant survole : on les compte. */
3352
+ private entreesDuGlisser;
3353
+ /** L'indice de la ligne a remplacer, le temps que le selecteur du systeme reponde. */
3354
+ private aRemplacer;
3355
+ /** Choix et depot ouverts : ni desactive, ni en lecture seule. */
3356
+ protected readonly ouvert: import("@angular/core").Signal<boolean>;
3357
+ protected readonly texteDuChoix: import("@angular/core").Signal<string>;
3358
+ /** Aide, types acceptes, taille et nombre au plus, raisons de desactivation. */
3359
+ protected readonly consignes: import("@angular/core").Signal<string | null>;
3360
+ protected readonly descriptionsDesConsignes: import("@angular/core").Signal<string[]>;
3361
+ protected readonly lignes: import("@angular/core").Signal<{
3362
+ fichier: File;
3363
+ cle: string;
3364
+ nom: string;
3365
+ etape: "en-cours" | "depose" | "refuse" | null;
3366
+ icone: "iban" | "code" | "devise" | "fichier" | "message" | "menu" | "accessibilite" | "appareils" | "arborescence" | "asterisque" | "badge-coche" | "banque" | "batiment" | "bifurcation" | "billets" | "billets-envoi" | "billets-pile" | "boite" | "boite-de-reception" | "bouclier" | "bouclier-alerte" | "bouclier-coche" | "bouclier-coeur" | "bouclier-croix" | "bouclier-moitie" | "bouclier-recherche" | "bouclier-utilisateur" | "boussole" | "bouton-curseur" | "bulle-question" | "cadenas" | "cadenas-horloge" | "cadenas-ouvert" | "cadre-pied" | "cadre-texte" | "calendrier" | "calendrier-evenement" | "calendrier-horloge" | "calendrier-jour" | "calques" | "carte-bancaire" | "carte-bancaire-barre" | "carte-bancaire-cadenas" | "carte-contact" | "carte-identite" | "cartes-empilees" | "case-cochee" | "casse" | "cercle" | "cercle-alerte" | "cercle-chevron-bas" | "cercle-coche" | "cercle-coche-ouvert" | "cercle-croix" | "cercle-info" | "cercle-moins" | "cercle-plus" | "cercle-question" | "certificat" | "chandelier" | "chargement" | "cheque" | "chevron-bas" | "chevron-droite" | "chevron-gauche" | "chevron-haut" | "chevrons-droite" | "chevrons-haut-bas" | "cle" | "cloche" | "cloche-sonnerie" | "coche" | "code-qr" | "code-qr-scanner" | "coffre-fort" | "colonnes" | "connexion" | "contraste" | "copie" | "corbeille" | "corbeille-croix" | "courriel" | "crayon" | "croix" | "curseur-clic" | "deconnexion" | "disposition" | "dollar" | "dossier" | "dossier-barre" | "dossier-ouvert" | "double-coche" | "echange" | "eclair" | "empreinte-digitale" | "enregistrer" | "entree" | "envoyer" | "epaisseur-de-trait" | "epingle" | "etoile" | "euro" | "fichier-image" | "fichier-pdf" | "fichier-texte" | "filtre" | "filtre-barre" | "filtre-lignes" | "fleche-bas" | "fleche-bas-gauche" | "fleche-bas-ligne" | "fleche-droite" | "fleche-gauche" | "fleche-haut" | "fleche-haut-droite" | "fleche-haut-ligne" | "fleche-large-haut" | "fleches-gauche-droite" | "flocon" | "flou" | "formes" | "globe" | "graphique-anneau" | "graphique-barres" | "graphique-barres-cadre" | "graphique-camembert" | "graphique-ligne" | "graphique-lignes" | "grille" | "grille-lignes" | "hexagone" | "historique" | "horloge" | "horloge-fleche" | "imprimer" | "interdit" | "jalons" | "jauge" | "lien" | "lien-externe" | "lignes" | "lignes-crayon" | "liste" | "liste-coche" | "liste-controle" | "liste-numerotee" | "luminosite" | "lune" | "maillet" | "maison" | "marque-page" | "menu-ouvert" | "minuteur" | "mise-au-point" | "mise-en-page-image" | "moins" | "nuage-barre" | "nuage-televerser" | "octogone-alerte" | "oeil" | "oeil-barre" | "panneau-gauche" | "parametres" | "parapluie" | "parchemin" | "pieces" | "plus" | "pointeur" | "points" | "points-verticaux" | "portefeuille" | "portefeuille-cartes" | "presse-papiers-coche" | "presse-papiers-horloge" | "priorite-haute" | "rafraichir" | "recherche" | "recherche-barre" | "recherche-texte" | "rectangle-points" | "recu" | "redemarrer" | "reglages" | "regle" | "reseau-jauge" | "rotation-arriere" | "routeur" | "sablier" | "sablier-bas" | "sablier-haut" | "sac-argent" | "sans-contact" | "serveur" | "soleil" | "style-de-trait" | "synchro" | "synchro-probleme" | "tableau" | "tableau-de-bord" | "tableau-de-bord-plus" | "tablette" | "tabulation" | "telecharger" | "telephone-mobile" | "televerser" | "tendance-baisse" | "tendance-hausse" | "terminal" | "tirelire" | "triangle-alerte" | "triangle-bas" | "triangle-haut" | "trombone" | "utilisateur" | "utilisateur-crayon" | "utilisateurs" | "wifi" | "wifi-barre";
3367
+ statut: string | null;
3368
+ morceauxDuStatut: readonly MorceauDePhrase[] | null;
3369
+ detail: string | null;
3370
+ progression: number | null;
3371
+ taille: string;
3372
+ annulable: boolean;
3373
+ }[]>;
3374
+ constructor();
3375
+ /** Le substitut, a la souris : il ouvre le selecteur du champ natif. */
3376
+ protected ouvrir(): void;
3377
+ /** En lecture seule, le champ natif garde le focus mais n'ouvre pas le selecteur. */
3378
+ protected surClicDuNatif(evenement: MouseEvent): void;
3379
+ protected surChoix(evenement: Event): void;
3380
+ /** Le selecteur ferme sans choix : un « Remplacer » en attente est oublie. */
3381
+ protected surAbandon(): void;
3382
+ protected surEntreeDuGlisser(evenement: DragEvent): void;
3383
+ /**
3384
+ * ⚠️ `preventDefault` sur CHAQUE `dragover`, sans quoi le navigateur ne delivre pas `drop`
3385
+ * (et ouvre le fichier a la place de la page). Fermee, la zone le dit par `dropEffect`.
3386
+ */
3387
+ protected surSurvol(evenement: DragEvent): void;
3388
+ protected surSortieDuGlisser(): void;
3389
+ protected surDepot(evenement: DragEvent): void;
3390
+ /** « Remplacer » d'une ligne : le prochain choix prend sa place. */
3391
+ protected remplacer(indice: number): void;
3392
+ /** Le bouton de la ligne : annuler pendant l'envoi, retirer sinon. */
3393
+ protected agirSurLaLigne(fichier: File, etape: EtatDeTeleversementAffiche['etape'] | null, annulable: boolean, indice: number): void;
3394
+ protected retirer(indice: number): void;
3395
+ protected aLaSortie(evenement: FocusEvent): void;
3396
+ /**
3397
+ * UNE annonce pour tous les fichiers qui changent d'etat ensemble : `annoncer` remplace le texte
3398
+ * encore en attente, et une annonce par fichier ne laissait dire que le dernier (audit UI du
3399
+ * 2026-09-27, D-15). Les fichiers deposes en une phrase, leurs noms en liste de la langue, puis
3400
+ * chaque refus avec sa raison.
3401
+ */
3402
+ private annonceDesEtapes;
3403
+ /** Le refus d'un fichier, et sa raison quand elle n'est pas la phrase du dictionnaire. */
3404
+ private phraseDuRefus;
3405
+ /** Les fichiers ecartes par `nombreMax`, nommes ; chaque nom isole a l'affichage (D-4). */
3406
+ private refusDuNombreMax;
3407
+ private remplacerA;
3408
+ private ajouter;
3409
+ static ɵfac: i0.ɵɵFactoryDeclaration<StFileUpload, never>;
3410
+ static ɵcmp: i0.ɵɵComponentDeclaration<StFileUpload, "st-file-upload", never, {
3411
+ "value": {
3412
+ "alias": "value";
3413
+ "required": false;
3414
+ "isSignal": true;
3415
+ };
3416
+ "accept": {
3417
+ "alias": "accept";
3418
+ "required": false;
3419
+ "isSignal": true;
3420
+ };
3421
+ "multiple": {
3422
+ "alias": "multiple";
3423
+ "required": false;
3424
+ "isSignal": true;
3425
+ };
3426
+ "tailleMax": {
3427
+ "alias": "tailleMax";
3428
+ "required": false;
3429
+ "isSignal": true;
3430
+ };
3431
+ "nombreMax": {
3432
+ "alias": "nombreMax";
3433
+ "required": false;
3434
+ "isSignal": true;
3435
+ };
3436
+ "libelleDuChoix": {
3437
+ "alias": "libelleDuChoix";
3438
+ "required": false;
3439
+ "isSignal": true;
3440
+ };
3441
+ "etats": {
3442
+ "alias": "etats";
3443
+ "required": false;
3444
+ "isSignal": true;
3445
+ };
3446
+ }, {
3447
+ "value": "valueChange";
3448
+ "annulation": "annulation";
3449
+ "remplacement": "remplacement";
3450
+ }, never, never, true, never>;
3451
+ }
3452
+ /**
3453
+ * Plusieurs valeurs LIBRES (courriels a notifier, references, mots-cles), en etiquettes
3454
+ * retirables : ni `st-multiselect` (options fermees) ni `st-input` ne le permettent (lot 252,
3455
+ * ADR 0005 D78, D79, D81).
3456
+ *
3457
+ * ```html
3458
+ * <st-tag-input
3459
+ * libelle="Adresses a notifier"
3460
+ * [valider]="adresseValide"
3461
+ * [nombreMax]="5"
3462
+ * [formField]="notification.adresses"
3463
+ * />
3464
+ * ```
3465
+ *
3466
+ * - Entree ajoute le texte tape, sans soumettre le formulaire englobant ; chaque separateur
3467
+ * aussi (`,` et `;` par defaut), sans s'ecrire. Rien pendant une composition IME : l'Entree
3468
+ * qui la clot valide la composition, pas la valeur.
3469
+ * - Un collage qui contient des separateurs (ou des fins de ligne) ajoute chaque valeur.
3470
+ * - ⚠️ **Le texte en attente reste dans le champ** : jamais ajoute implicitement, ni a la sortie
3471
+ * du champ ni a l'envoi du formulaire. Une valeur ajoutee sans geste serait une valeur que la
3472
+ * personne n'a pas choisie.
3473
+ * - Un doublon, une valeur que `valider` ecarte et une valeur au-dela de `nombreMax` n'entrent
3474
+ * pas : le texte reste a corriger, un message local le dit en texte visible, relie au champ,
3475
+ * et l'annonce le reprend.
3476
+ * - Les valeurs sont un `st-tag-group` nomme par le libelle du champ ; chaque retrait est nomme
3477
+ * par `retirerLEtiquette` (« Retirer x »), rend le focus a la valeur suivante, sinon a la
3478
+ * precedente, sinon au champ. Une seule region d'annonce, celle du champ : ajouts, retraits et
3479
+ * refus y passent.
3480
+ * - `readonly` : le champ reste focalisable, rien n'entre, et les croix sont masquees ;
3481
+ * `disabled` : hors de la tabulation, sur fond blanc (D66).
3482
+ * - Le cadre a une hauteur MINIMALE : les etiquettes passent a la ligne, jamais tronquees.
3483
+ */
3484
+ export declare class StTagInput extends ContratDeChamp implements FormValueControl<readonly string[]> {
3485
+ private readonly libelles;
3486
+ private readonly element;
3487
+ readonly value: import("@angular/core").ModelSignal<readonly string[]>;
3488
+ /** Ce qui ajoute le texte tape, en plus d'Entree. */
3489
+ readonly separateurs: import("@angular/core").InputSignal<readonly string[]>;
3490
+ /** Refus local d'un texte (une adresse mal formee) ; la validation du schema reste l'arbitre. */
3491
+ readonly valider: import("@angular/core").InputSignal<((texte: string) => boolean) | null>;
3492
+ /** Nombre de valeurs au plus (D78 : `max` est une borne de valeur du contrat Signal Forms). */
3493
+ readonly nombreMax: import("@angular/core").InputSignal<number | null>;
3494
+ protected readonly annonce: AnnonceLocale;
3495
+ protected readonly identifiantDuRefus: string;
3496
+ /** Le dernier refus, jusqu'a la prochaine frappe, au prochain ajout ou au prochain retrait. */
3497
+ protected readonly refus: import("@angular/core").WritableSignal<string | null>;
3498
+ protected readonly modifiable: import("@angular/core").Signal<boolean>;
3499
+ protected readonly elements: import("@angular/core").Signal<readonly EtiquetteDeGroupe[]>;
3500
+ protected readonly descriptionsDuRefus: import("@angular/core").Signal<string[]>;
3501
+ constructor();
3502
+ /** Entree et les separateurs ajoutent le texte tape. */
3503
+ protected auClavier(evenement: KeyboardEvent): void;
3504
+ /**
3505
+ * Un separateur arrive aussi sans touche lisible (clavier virtuel, dictee) : le texte se coupe
3506
+ * a chaque separateur, le dernier morceau reste en attente.
3507
+ */
3508
+ protected surSaisie(evenement: Event): void;
3509
+ /** Un collage qui contient des separateurs ou des fins de ligne : chaque valeur est ajoutee. */
3510
+ protected surCollage(evenement: ClipboardEvent): void;
3511
+ protected retirer(valeur: string): void;
3512
+ protected aLaSortie(evenement: FocusEvent): void;
3513
+ /**
3514
+ * Ajoute chaque texte qui peut l'etre, dans l'ordre, et rend ce qui reste a corriger dans le
3515
+ * champ. Un refus se dit en texte visible et dans l'annonce, avec les ajouts.
3516
+ */
3517
+ private ajouter;
3518
+ /** Doublon d'abord, puis la limite, puis `valider` : le blocage le plus utile a lever. */
3519
+ private motifDuRefus;
3520
+ /** Ce qui separe deux textes refuses laisses dans le champ : le premier separateur, puis une espace. */
3521
+ private jointure;
3522
+ static ɵfac: i0.ɵɵFactoryDeclaration<StTagInput, never>;
3523
+ static ɵcmp: i0.ɵɵComponentDeclaration<StTagInput, "st-tag-input", never, {
3524
+ "value": {
3525
+ "alias": "value";
3526
+ "required": false;
3527
+ "isSignal": true;
3528
+ };
3529
+ "separateurs": {
3530
+ "alias": "separateurs";
3531
+ "required": false;
3532
+ "isSignal": true;
3533
+ };
3534
+ "valider": {
3535
+ "alias": "valider";
3536
+ "required": false;
3537
+ "isSignal": true;
3538
+ };
3539
+ "nombreMax": {
3540
+ "alias": "nombreMax";
3541
+ "required": false;
3542
+ "isSignal": true;
3543
+ };
3544
+ }, {
3545
+ "value": "valueChange";
3546
+ }, never, ["[stMeta]", "[stAide]", "[stIndication]"], true, never>;
3547
+ }
3548
+ /**
3549
+ * Ce que `st-address-fieldset` offre a une recherche inseree en son sein (`st-address-search`, de
3550
+ * `@starterlib/ui/selection`) : le champ ne connait pas la recherche, la recherche l'injecte.
3551
+ * `ui/saisie` n'importe que le tronc : c'est le sens de la dependance.
3552
+ */
3553
+ export interface ChampDAdresse {
3554
+ /** Le pays choisi (code ISO), ou `''` : la recherche s'y restreint. */
3555
+ readonly pays: Signal<string>;
3556
+ /** Ni desactive, ni en lecture seule : une recherche inerte sinon. */
3557
+ readonly modifiable: Signal<boolean>;
3558
+ /**
3559
+ * Reporte une adresse trouvee dans les champs. Le complement deja saisi est garde quand
3560
+ * l'adresse n'en porte pas : aucun service ne connait l'appartement.
3561
+ */
3562
+ remplir(adresse: Adresse): void;
3563
+ /** Annonce polie, dans la region unique du champ. */
3564
+ annoncer(message: string): void;
3565
+ }
3566
+ export declare const ST_CHAMP_D_ADRESSE: InjectionToken<ChampDAdresse>;
3567
+ /** Ce qui decide des options d'une liste de pays (`optionsDesPays`). */
3568
+ export interface ParametresDesPays {
3569
+ /** La langue des noms et de leur tri (`ST_LOCALE`). */
3570
+ readonly locale: string;
3571
+ /** Les pays proposes (codes ISO) ; `null` : les 249 pays de la norme. */
3572
+ readonly codes: readonly string[] | null;
3573
+ /** Les pays frequents, en tete de liste et dans cet ordre. */
3574
+ readonly enTete: readonly string[];
3575
+ /** Le code du modele : nomme et desactive quand il n'est pas propose. */
3576
+ readonly courant: string | null;
3577
+ /** Les intitules des deux groupes (« Pays frequents », « Tous les pays »). */
3578
+ readonly groupes: {
3579
+ readonly frequents: string;
3580
+ readonly tous: string;
3581
+ };
3582
+ }
3583
+ /**
3584
+ * Les options d'une liste de pays, partagees par `st-country-field` (select natif) et
3585
+ * `st-country-combobox` (`@starterlib/ui/selection`, filtrable) : noms par `Intl` dans la langue
3586
+ * donnee, tries par sa collation ; les pays frequents dans un premier groupe, sans etre repetes
3587
+ * dans le second ; un pays du modele hors de la liste en tete, nomme et desactive, jamais tu.
3588
+ */
3589
+ export declare function optionsDesPays(parametres: ParametresDesPays): OptionDeListe[];
3590
+ /**
3591
+ * Liste des pays : un `select` natif (`st-select`), la valeur est le code ISO 3166-1 alpha-2.
3592
+ *
3593
+ * ```html
3594
+ * <st-country-field libelle="Pays" [enTete]="['FR', 'BE', 'CH']" [formField]="f.pays" />
3595
+ * ```
3596
+ *
3597
+ * ⚠️ **Les noms viennent d'`Intl`, dans la langue de la page** (`ST_LOCALE`), et se trient par sa
3598
+ * collation : aucune liste de noms n'est ecrite dans le socle, aucune ne reste en francais quand
3599
+ * la page passe en anglais. Le code ISO ne s'affiche jamais.
3600
+ *
3601
+ * `codes` restreint la liste (zone SEPA, pays admis) ; `enTete` place les pays frequents dans un
3602
+ * premier groupe, sans les repeter dans le second. `autocomplete="country"` par defaut : le
3603
+ * navigateur remplit le champ (WCAG 1.3.5).
3604
+ *
3605
+ * ⚠️ **Un pays deja dans le modele et absent de `codes` ne disparait pas** : il reste affiche,
3606
+ * nomme et desactive ; `erreurPays` du schema dit pourquoi il ne passe pas.
3607
+ */
3608
+ export declare class StCountryField extends ControleDeSaisie {
3609
+ private readonly libelles;
3610
+ private readonly locale;
3611
+ /** Les pays proposes (codes ISO) ; absent : les 249 pays de la norme. */
3612
+ readonly codes: import("@angular/core").InputSignal<readonly string[] | null>;
3613
+ /** Les pays frequents, en tete de liste et dans cet ordre. */
3614
+ readonly enTete: import("@angular/core").InputSignal<readonly string[]>;
3615
+ /** WCAG 1.3.5 : `country` par defaut ; `shipping country` dans un formulaire de livraison. */
3616
+ readonly autocomplete: import("@angular/core").InputSignal<TypeDAutocompletion | null>;
3617
+ /** Texte de l'option vide. Par defaut : « Choisir… ». */
3618
+ readonly texteVide: import("@angular/core").InputSignal<string | null>;
3619
+ /** Le style de l'etiquette (voir `st-form-field`). */
3620
+ readonly presentation: import("@angular/core").InputSignal<PresentationDeLibelle>;
3621
+ private readonly liste;
3622
+ protected readonly options: import("@angular/core").Signal<OptionDeListe[]>;
3623
+ /** Signal Forms amene le focus sur le `select` interne. */
3624
+ focus(options?: FocusOptions): void;
3625
+ static ɵfac: i0.ɵɵFactoryDeclaration<StCountryField, never>;
3626
+ static ɵcmp: i0.ɵɵComponentDeclaration<StCountryField, "st-country-field", never, {
3627
+ "codes": {
3628
+ "alias": "codes";
3629
+ "required": false;
3630
+ "isSignal": true;
3631
+ };
3632
+ "enTete": {
3633
+ "alias": "enTete";
3634
+ "required": false;
3635
+ "isSignal": true;
3636
+ };
3637
+ "autocomplete": {
3638
+ "alias": "autocomplete";
3639
+ "required": false;
3640
+ "isSignal": true;
3641
+ };
3642
+ "texteVide": {
3643
+ "alias": "texteVide";
3644
+ "required": false;
3645
+ "isSignal": true;
3646
+ };
3647
+ "presentation": {
3648
+ "alias": "presentation";
3649
+ "required": false;
3650
+ "isSignal": true;
3651
+ };
3652
+ }, {}, never, never, true, never>;
3653
+ }
3654
+ /**
3655
+ * Ce que la region affiche : sa liste fermee (`liste`), la sienne en chemin (`chargement`), un texte
3656
+ * libre faute de liste pour le pays (`texte`), ou faute de liste servie (`panne`, et elle le dit).
3657
+ */
3658
+ export type ModeDeRegion = 'liste' | 'chargement' | 'texte' | 'panne';
3659
+ type PartieDeTexte = Exclude<PartieDAdresse, 'pays'>;
3660
+ /**
3661
+ * Adresse postale, en un groupe : le pays d'abord, puis les champs que son format postal emploie,
3662
+ * dans son ordre, avec ses libelles et ses exigences.
3663
+ *
3664
+ * ```html
3665
+ * <st-address-fieldset libelle="Adresse de residence" [formField]="formulaire.adresse">
3666
+ * <st-address-search /> <!-- facultative : @starterlib/ui/selection -->
3667
+ * </st-address-fieldset>
3668
+ * ```
3669
+ *
3670
+ * ```ts
3671
+ * required(chemin.adresse);
3672
+ * validate(chemin.adresse, ({ value }) => erreursDAdresse(value()));
3673
+ * ```
3674
+ *
3675
+ * ⚠️ **Dynamique par pays** (`formatDAdresse` d'`@starterlib/util`) : le code postal avant la
3676
+ * ville en France, apres elle au Canada, absent au Cameroun ; la region nommee « Province ou
3677
+ * territoire », « Etat » ou « Comte », exigee ou non. Changer de pays ne deplace jamais le focus
3678
+ * (WCAG 3.2.2) ; un format qui change s'annonce poliment. Les parties que le nouveau format
3679
+ * n'affiche plus sont VIDEES : aucune donnee cachee ne part avec le formulaire.
3680
+ *
3681
+ * ⚠️ **Un jeton de remplissage exact par champ** (WCAG 1.3.5) : `address-line1`, `address-line2`,
3682
+ * `postal-code`, `address-level2`, `address-level1`, `country` ; `sectionDeRemplissage` les
3683
+ * prefixe (`shipping`, `billing`) quand deux adresses partagent un formulaire. Le remplissage du
3684
+ * navigateur marche sans la recherche, et la rend inutile a qui l'emploie.
3685
+ *
3686
+ * ⚠️ **La valeur est toujours un objet** (`Adresse`, six chaines) : `required` du schema ne peut
3687
+ * donc pas la dire vide. Ce sont les erreurs de `erreursDAdresse`, une par partie (cle `partie`),
3688
+ * qui bloquent l'envoi ; chacune s'affiche sous son champ, et `focus()` va a la premiere.
3689
+ * L'obligation se lit sur chaque champ exige, jamais sur le complement.
3690
+ *
3691
+ * Une recherche projetee (`st-address-search`) remplit les champs par `ST_CHAMP_D_ADRESSE` ; le
3692
+ * complement deja saisi n'est jamais efface.
3693
+ *
3694
+ * ⚠️ **Listes par pays** (`ST_LISTES_D_ADRESSES`, ADR 0005 D133), quand l'hote en relie une source :
3695
+ * la region devient une liste FERMEE des regions du pays (`st-select`, chargee a chaque pays), la
3696
+ * ville un texte a valeurs PROPOSEES, celles du pays ou de la region choisie (une localite peut
3697
+ * manquer a toute liste : rien n'est refuse). Un pays sans liste garde la region en texte libre ;
3698
+ * une liste qui ne se charge pas aussi, et l'aide de la region le dit. Une region rapportee par son
3699
+ * nom (« Ontario ») s'ecrit a la valeur de sa liste (« ON ») ; une valeur que la liste ne porte pas
3700
+ * reste affichee, nommee, jamais tue. Une region choisie dans la liste d'un pays s'efface quand le
3701
+ * pays change ; une region tapee reste, a corriger.
3702
+ */
3703
+ export declare class StAddressFieldset extends ContratDeChamp implements FormValueControl<Adresse> {
3704
+ protected readonly libelles: import("@angular/core").Signal<import("@starterlib/ui").LibellesUi>;
3705
+ private readonly locale;
3706
+ private readonly element;
3707
+ readonly value: import("@angular/core").ModelSignal<Adresse>;
3708
+ /** Un pays impose (code ISO) : le champ pays disparait, la valeur le porte. */
3709
+ readonly paysFixe: import("@angular/core").InputSignal<string | null>;
3710
+ /** Les pays admis (codes ISO) ; absent : les 249 pays de la norme. */
3711
+ readonly codesDesPays: import("@angular/core").InputSignal<readonly string[] | null>;
3712
+ /** Les pays frequents, en tete de la liste. */
3713
+ readonly paysFrequents: import("@angular/core").InputSignal<readonly string[]>;
3714
+ /** Sans complement d'adresse (une ligne de voie seulement). */
3715
+ readonly ligne2Masquee: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
3716
+ /**
3717
+ * Prefixe des jetons de remplissage (`shipping`, `billing`, `section-<nom>`), quand deux
3718
+ * adresses partagent un formulaire. `null` : les jetons seuls.
3719
+ */
3720
+ readonly sectionDeRemplissage: import("@angular/core").InputSignal<string | null>;
3721
+ protected readonly annonce: AnnonceLocale;
3722
+ private readonly listes;
3723
+ /** Le pays qui decide du format : l'impose, sinon celui de la valeur. */
3724
+ private readonly pays;
3725
+ protected readonly format: import("@angular/core").Signal<FormatDAdresse>;
3726
+ protected readonly parties: import("@angular/core").Signal<PartieDeTexte[]>;
3727
+ private readonly exigees;
3728
+ protected readonly modifiable: import("@angular/core").Signal<boolean>;
3729
+ /** Les erreurs du schema, par partie ; celles sans partie restent au groupe. */
3730
+ private readonly erreursParPartie;
3731
+ protected readonly erreursDuGroupe: import("@angular/core").Signal<ErreurAffichable[]>;
3732
+ /** La liste des regions a demander : le pays, s'il affiche une region et qu'une source existe. */
3733
+ private readonly demandeDeRegions;
3734
+ private readonly regions;
3735
+ /** Les regions du pays, une fois servies ; `null` sans liste. */
3736
+ private readonly listeDesRegions;
3737
+ protected readonly modeDeRegion: import("@angular/core").Signal<ModeDeRegion>;
3738
+ protected readonly regionEnListe: import("@angular/core").Signal<boolean>;
3739
+ /** Les options de la region : sa liste, et la valeur du modele qu'elle ne porte pas, nommee. */
3740
+ protected readonly optionsDeRegion: import("@angular/core").Signal<OptionDeListe[]>;
3741
+ /** Les villes a demander : le pays, et la region seulement si sa liste la porte. */
3742
+ private readonly demandeDeVilles;
3743
+ private readonly villes;
3744
+ /** Les villes proposees sous le champ ; une liste en panne n'en propose aucune, sans rien bloquer. */
3745
+ protected readonly villesProposees: import("@angular/core").Signal<readonly string[] | null>;
3746
+ private readonly listeDesPays;
3747
+ constructor();
3748
+ protected erreursDe(partie: PartieDAdresse): readonly ErreurAffichable[];
3749
+ protected libelleDe(partie: PartieDeTexte): string;
3750
+ protected aideDe(partie: PartieDeTexte): string | null;
3751
+ protected exigee(partie: PartieDAdresse): boolean;
3752
+ protected jeton(partie: PartieDAdresse): TypeDAutocompletion;
3753
+ protected clavier(partie: PartieDeTexte): ModeDeSaisie | null;
3754
+ protected nomDe(partie: PartieDAdresse): string;
3755
+ protected changer(partie: PartieDeTexte, texte: string): void;
3756
+ protected changerDePays(code: string): void;
3757
+ /** A la sortie du code postal : capitales, espaces reduites (« h2x 1y4 » donne « H2X 1Y4 »). */
3758
+ protected aLaSortieDe(partie: PartieDeTexte): void;
3759
+ /** `touch` quand le focus quitte le groupe entier, et non chaque champ. */
3760
+ protected aLaSortie(evenement: FocusEvent): void;
3761
+ /**
3762
+ * Appele par Signal Forms pour amener le focus sur un champ en erreur : la PREMIERE partie en
3763
+ * erreur, dans l'ordre du champ (le pays d'abord), sinon le premier champ.
3764
+ */
3765
+ focus(options?: FocusOptions): void;
3766
+ private remplir;
3767
+ /** Vide les parties que le format du pays n'affiche pas : rien de cache ne part. */
3768
+ private nettoyer;
3769
+ static ɵfac: i0.ɵɵFactoryDeclaration<StAddressFieldset, never>;
3770
+ static ɵcmp: i0.ɵɵComponentDeclaration<StAddressFieldset, "st-address-fieldset", never, {
3771
+ "value": {
3772
+ "alias": "value";
3773
+ "required": false;
3774
+ "isSignal": true;
3775
+ };
3776
+ "paysFixe": {
3777
+ "alias": "paysFixe";
3778
+ "required": false;
3779
+ "isSignal": true;
3780
+ };
3781
+ "codesDesPays": {
3782
+ "alias": "codesDesPays";
3783
+ "required": false;
3784
+ "isSignal": true;
3785
+ };
3786
+ "paysFrequents": {
3787
+ "alias": "paysFrequents";
3788
+ "required": false;
3789
+ "isSignal": true;
3790
+ };
3791
+ "ligne2Masquee": {
3792
+ "alias": "ligne2Masquee";
3793
+ "required": false;
3794
+ "isSignal": true;
3795
+ };
3796
+ "sectionDeRemplissage": {
3797
+ "alias": "sectionDeRemplissage";
3798
+ "required": false;
3799
+ "isSignal": true;
3800
+ };
3801
+ }, {
3802
+ "value": "valueChange";
3803
+ }, never, ["*"], true, never>;
921
3804
  }
922
3805
 
923
- export { ContratDeChamp, ControleDeSaisie, StCalendar, StCheckbox, StControleDeChamp, StErrorSummary, StFieldset, StFileUpload, StFormField, StIbanField, StInput, StOtpField, StPasswordField, StPhoneField, StRadioGroup, StSearchField, StSelect, StSwitch, StTextarea, cleDeFichier, erreurDate, erreurIban, erreurPlageDeDates, erreurTelephone, erreursDeFichiers, exempleDeDate, filtrerOptions, fusionnerErreurs, messageDErreur, motifLocal, normaliserPourRecherche };
924
- export type { BornesDeDate, DispositionDeChamp, ElementDeSaisie, ErreurAffichable, EtatDeTeleversementAffiche, OptionDeListe, OptionRadio, ReglesDeFichiers, RemplissageDeTelephone, TypeDeSaisie, UsageDuMotDePasse };
3806
+ export {};