@ktortu/aaa 0.1.0-beta.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 (49) hide show
  1. package/README.md +27 -9
  2. package/cdk/styles/tabs.css +100 -21
  3. package/fesm2022/ktortu-aaa-button.mjs +18 -11
  4. package/fesm2022/ktortu-aaa-button.mjs.map +1 -1
  5. package/fesm2022/ktortu-aaa-card.mjs +29 -4
  6. package/fesm2022/ktortu-aaa-card.mjs.map +1 -1
  7. package/fesm2022/ktortu-aaa-cdk.mjs +59 -15
  8. package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
  9. package/fesm2022/ktortu-aaa-dialog.mjs +134 -24
  10. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
  11. package/fesm2022/ktortu-aaa-forms.mjs +748 -294
  12. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
  13. package/fesm2022/ktortu-aaa-i18n.mjs +139 -0
  14. package/fesm2022/ktortu-aaa-i18n.mjs.map +1 -0
  15. package/fesm2022/ktortu-aaa-menu.mjs +38 -13
  16. package/fesm2022/ktortu-aaa-menu.mjs.map +1 -1
  17. package/fesm2022/ktortu-aaa-snackbar.mjs +465 -0
  18. package/fesm2022/ktortu-aaa-snackbar.mjs.map +1 -0
  19. package/fesm2022/ktortu-aaa-tabs.mjs +319 -42
  20. package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
  21. package/fesm2022/ktortu-aaa-tooltip.mjs +3 -2
  22. package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
  23. package/fesm2022/ktortu-aaa.mjs +2 -0
  24. package/fesm2022/ktortu-aaa.mjs.map +1 -1
  25. package/forms/checkbox/checkbox-group.css +0 -8
  26. package/forms/chips/chip-list.css +5 -0
  27. package/forms/radio/radio-group.css +0 -8
  28. package/forms/styles/field-box.css +152 -2
  29. package/forms/styles/field-pending.css +46 -0
  30. package/forms/styles/select-panel.css +4 -0
  31. package/forms/styles/tokens.css +3 -0
  32. package/menu/menu.css +8 -4
  33. package/package.json +9 -1
  34. package/snackbar/snackbar-tokens.css +53 -0
  35. package/snackbar/snackbar.css +175 -0
  36. package/styles/forms.css +1 -0
  37. package/styles/snackbar.css +9 -0
  38. package/styles/styles.css +1 -0
  39. package/types/ktortu-aaa-button.d.ts +22 -8
  40. package/types/ktortu-aaa-card.d.ts +24 -4
  41. package/types/ktortu-aaa-cdk.d.ts +38 -0
  42. package/types/ktortu-aaa-dialog.d.ts +129 -31
  43. package/types/ktortu-aaa-forms.d.ts +503 -160
  44. package/types/ktortu-aaa-i18n.d.ts +77 -0
  45. package/types/ktortu-aaa-menu.d.ts +15 -8
  46. package/types/ktortu-aaa-snackbar.d.ts +275 -0
  47. package/types/ktortu-aaa-tabs.d.ts +130 -13
  48. package/types/ktortu-aaa-tooltip.d.ts +5 -0
  49. package/types/ktortu-aaa.d.ts +2 -0
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken, AfterViewInit } from '@angular/core';
2
+ import { InjectionToken, AfterViewInit, Provider } from '@angular/core';
3
3
 
4
4
  /** Axe "emphase" (apparence). */
5
5
  type KtButtonMode = 'filled' | 'tonal' | 'outlined' | 'text';
@@ -7,13 +7,27 @@ type KtButtonMode = 'filled' | 'tonal' | 'outlined' | 'text';
7
7
  type KtButtonColor = 'primary' | 'neutral' | 'danger';
8
8
  /** Taille (la cible md ~44-48px vise le confort tactile / AAA). */
9
9
  type KtButtonSize = 'sm' | 'md' | 'lg';
10
+ /** Défauts applicables à tous les `[ktButton]` (surchargeables par bouton via les inputs). */
10
11
  interface KtButtonConfig {
12
+ /** Garde le bouton focusable même désactivé (via `aria-disabled`). */
11
13
  disabledInteractive: boolean;
14
+ /** Emphase visuelle par défaut (apparence). */
12
15
  mode: KtButtonMode;
16
+ /** Intention sémantique par défaut (couleur). */
13
17
  color: KtButtonColor;
18
+ /** Taille par défaut. */
14
19
  size: KtButtonSize;
15
20
  }
16
21
  declare const KT_BUTTON_CONFIG: InjectionToken<Partial<KtButtonConfig>>;
22
+ /**
23
+ * Fournit des défauts de bouton (mode/couleur/taille…) pour un sous-arbre ou l'application entière.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * providers: [provideKtButton({ mode: 'tonal', size: 'lg' })]
28
+ * ```
29
+ */
30
+ declare function provideKtButton(config: Partial<KtButtonConfig>): Provider;
17
31
  /**
18
32
  * Bouton ou lien stylé par la directive `ktButton`. À poser sur un `<button>`
19
33
  * (action) ou un `<a>` (navigation) — l'accessibilité s'adapte automatiquement
@@ -40,23 +54,23 @@ declare class KtButton implements AfterViewInit {
40
54
  /** Taille ; `md` vise une cible tactile ~44-48px. @default 'md' (ou KT_BUTTON_CONFIG.size) */
41
55
  readonly size: _angular_core.InputSignal<KtButtonSize>;
42
56
  /** Étire le bouton sur toute la largeur disponible. @default false */
43
- readonly fullWidth: _angular_core.InputSignal<boolean>;
57
+ readonly fullWidth: _angular_core.InputSignalWithTransform<boolean, unknown>;
44
58
  /** Bouton carré sans texte ; impose un nom accessible via `ariaLabel`. @default false */
45
59
  readonly iconOnly: _angular_core.InputSignalWithTransform<boolean, unknown>;
46
- /** Nom accessible. Obligatoire si `iconOnly` ; à défaut, l'`aria-label` natif est préservé. */
60
+ /** Nom accessible. **Obligatoire si `iconOnly`** ; à défaut, l'`aria-label` natif est préservé. @default undefined */
47
61
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
48
62
  /** Attribut HTML natif (comportement formulaire), distinct de `mode`. @default 'button' */
49
63
  readonly type: _angular_core.InputSignal<"button" | "submit" | "reset">;
50
64
  /** Affiche l'état de chargement et rend le bouton inerte (`aria-busy`). @default false */
51
- readonly loading: _angular_core.InputSignal<boolean>;
52
- /** Nom de l'icône (rendu via CSS `data-icon`). */
65
+ readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
66
+ /** Nom de l'icône (rendu via CSS `data-icon`). @default undefined */
53
67
  readonly icon: _angular_core.InputSignal<string | undefined>;
54
68
  /** Position de l'icône relative au texte. @default 'start' */
55
69
  readonly iconPosition: _angular_core.InputSignal<"start" | "end">;
56
70
  /** Désactive le bouton. @default false */
57
- readonly disabled: _angular_core.InputSignal<boolean>;
71
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
58
72
  /** Garde le bouton focusable même désactivé (via `aria-disabled`). @default false (ou KT_BUTTON_CONFIG.disabledInteractive) */
59
- readonly disabledInteractive: _angular_core.InputSignal<boolean>;
73
+ readonly disabledInteractive: _angular_core.InputSignalWithTransform<boolean, unknown>;
60
74
  protected readonly isDisabled: _angular_core.Signal<boolean>;
61
75
  protected readonly resolvedAriaLabel: _angular_core.Signal<string | null>;
62
76
  constructor();
@@ -66,5 +80,5 @@ declare class KtButton implements AfterViewInit {
66
80
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KtButton, "button[ktButton], a[ktButton]", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "disabledInteractive": { "alias": "disabledInteractive"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
67
81
  }
68
82
 
69
- export { KT_BUTTON_CONFIG, KtButton };
83
+ export { KT_BUTTON_CONFIG, KtButton, provideKtButton };
70
84
  export type { KtButtonColor, KtButtonConfig, KtButtonMode, KtButtonSize };
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken } from '@angular/core';
2
+ import { InjectionToken, Provider } from '@angular/core';
3
3
 
4
4
  /**
5
5
  * En-tête de la carte (rangée flex : média/avatar + titre + éventuelle action). Marqueur
@@ -67,6 +67,16 @@ declare class KtCardActions {
67
67
  *
68
68
  * Quand la carte ancêtre est `disabled`, le lien sort de l'ordre de tabulation (`tabindex="-1"`)
69
69
  * et est annoncé `aria-disabled` : une carte inerte ne piège pas le focus clavier (WCAG 2.4.3).
70
+ *
71
+ * @example
72
+ * ```html
73
+ * <article ktCard interactive>
74
+ * <div ktCardContent>
75
+ * <h3 id="t1">Titre</h3>
76
+ * <a ktCardLink routerLink="/detail" aria-labelledby="t1">Voir le détail</a>
77
+ * </div>
78
+ * </article>
79
+ * ```
70
80
  */
71
81
  declare class KtCardLink {
72
82
  private readonly host;
@@ -90,6 +100,15 @@ interface KtCardConfig {
90
100
  variant: KtCardVariant;
91
101
  }
92
102
  declare const KT_CARD_CONFIG: InjectionToken<Partial<KtCardConfig>>;
103
+ /**
104
+ * Fournit des défauts de carte (apparence de surface) pour un sous-arbre ou l'application entière.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * providers: [provideKtCard({ variant: 'outlined' })]
109
+ * ```
110
+ */
111
+ declare function provideKtCard(config: Partial<KtCardConfig>): Provider;
93
112
  /**
94
113
  * Carte : SURFACE de contenu. Directive (pas de composant) posée sur l'élément SÉMANTIQUE choisi
95
114
  * par le consommateur (`<article>`, `<section>`, `<li>`, `<a>`…) — la lib n'impose jamais de
@@ -117,6 +136,7 @@ declare const KT_CARD_CONFIG: InjectionToken<Partial<KtCardConfig>>;
117
136
  declare class KtCard {
118
137
  private readonly config;
119
138
  private readonly host;
139
+ private readonly platformId;
120
140
  /** Référence réactive sur le lien primaire de la carte */
121
141
  readonly cardLink: i0.Signal<KtCardLink | undefined>;
122
142
  /** Apparence de la surface : `elevated` | `outlined` | `filled`. @default 'elevated' (ou `KT_CARD_CONFIG.variant`) */
@@ -135,9 +155,9 @@ declare class KtCard {
135
155
 
136
156
  /**
137
157
  * Import ergonomique de toute la famille card en une fois :
138
- * `imports: [KT_CARD]` au lieu d'énumérer chaque directive.
158
+ * `imports: [KtCardImports]` au lieu d'énumérer chaque directive.
139
159
  */
140
- declare const KT_CARD: readonly [typeof KtCard, typeof KtCardHeader, typeof KtCardMedia, typeof KtCardContent, typeof KtCardActions, typeof KtCardLink];
160
+ declare const KtCardImports: readonly [typeof KtCard, typeof KtCardHeader, typeof KtCardMedia, typeof KtCardContent, typeof KtCardActions, typeof KtCardLink];
141
161
 
142
- export { KT_CARD, KT_CARD_CONFIG, KtCard, KtCardActions, KtCardContent, KtCardHeader, KtCardLink, KtCardMedia };
162
+ export { KT_CARD_CONFIG, KtCard, KtCardActions, KtCardContent, KtCardHeader, KtCardImports, KtCardLink, KtCardMedia, provideKtCard };
143
163
  export type { KtCardConfig, KtCardVariant };
@@ -4,7 +4,9 @@ import * as _ktortu_aaa_cdk from '@ktortu/aaa/cdk';
4
4
 
5
5
  /** Contrôleur de drag-to-dismiss d'une bottom-sheet. À câbler sur le `pointerdown` de la poignée. */
6
6
  interface KtSheetDrag {
7
+ /** Démarre le suivi du glissement ; à brancher sur le `pointerdown` de la poignée. */
7
8
  start(event: PointerEvent): void;
9
+ /** Détache les écouteurs et réinitialise l'état ; à appeler à la destruction. */
8
10
  destroy(): void;
9
11
  }
10
12
  interface KtSheetDragOptions {
@@ -25,6 +27,18 @@ interface KtSheetDragOptions {
25
27
  * Geste DOUBLÉ côté appelant par Échap + bouton Fermer + tap-extérieur (WCAG 2.5.1) : ce module ne
26
28
  * gère que le glissement. Le gating « écran compact uniquement » reste à l'appelant (signal `isCompact`
27
29
  * de `KtViewport`) — la primitive est volontairement agnostique.
30
+ *
31
+ * @param opts Élément à translater, callback de fermeture, classe de drag et seuil optionnel.
32
+ * @returns Un contrôleur {@link KtSheetDrag} (`start` à brancher sur `pointerdown`, `destroy` au teardown).
33
+ * @example
34
+ * ```ts
35
+ * const drag = createKtSheetDrag({
36
+ * pane: () => paneEl(),
37
+ * onDismiss: () => dialogRef.close(),
38
+ * draggingClass: 'kt-sheet--dragging',
39
+ * });
40
+ * // <div class="handle" (pointerdown)="drag.start($event)"></div>
41
+ * ```
28
42
  */
29
43
  declare function createKtSheetDrag(opts: KtSheetDragOptions): KtSheetDrag;
30
44
 
@@ -55,20 +69,28 @@ declare const KT_DEFAULT_BREAKPOINTS: KtBreakpoints;
55
69
  declare const KT_BREAKPOINTS: InjectionToken<KtBreakpoints>;
56
70
  /**
57
71
  * À ajouter aux `providers` de `app.config.ts`. Fusionne avec les défauts → surcharge partielle OK.
72
+ * @param overrides Seuils à surcharger ; les clés absentes gardent leur défaut `KT_DEFAULT_BREAKPOINTS`.
73
+ * @returns Provider liant `KT_BREAKPOINTS` aux seuils fusionnés.
58
74
  * @example provideKtBreakpoints({ tablet: 768, desktop: 1200 })
59
75
  * @example provideKtBreakpoints({ tablet: '(min-width: 768px) and (orientation: landscape)' })
60
76
  */
61
77
  declare function provideKtBreakpoints(overrides: Partial<KtBreakpoints>): Provider;
62
78
  /** Trois chaînes de media queries résolues, prêtes pour `matchMedia` / `BreakpointObserver`. */
63
79
  interface KtBreakpointMedia {
80
+ /** Media query de la bande mobile. */
64
81
  mobile: string;
82
+ /** Media query de la bande tablette. */
65
83
  tablet: string;
84
+ /** Media query de la bande desktop. */
66
85
  desktop: string;
67
86
  }
68
87
  /**
69
88
  * Convertit les seuils (nombres et/ou chaînes) en 3 media queries. Un palier-chaîne est repris
70
89
  * verbatim ; un palier-nombre devient la bande `[plancher courant .. plancher suivant[`. Si le
71
90
  * plancher suivant est une chaîne (pas de borne numérique), la bande reste ouverte de ce côté.
91
+ * @param bp Seuils responsive à convertir (nombres et/ou chaînes).
92
+ * @returns Les trois media queries résolues (`mobile`, `tablet`, `desktop`).
93
+ * @example resolveKtBreakpointMedia(KT_DEFAULT_BREAKPOINTS)
72
94
  */
73
95
  declare function resolveKtBreakpointMedia(bp: KtBreakpoints): KtBreakpointMedia;
74
96
 
@@ -98,9 +120,25 @@ declare class KtViewport {
98
120
  static ɵprov: i0.ɵɵInjectableDeclaration<KtViewport>;
99
121
  }
100
122
 
123
+ /**
124
+ * Génère des identifiants numériques incrémentaux uniques au sein de l'application, soit globalement,
125
+ * soit par préfixe (compteur dédié). Sert à construire des `anchor-name` / `id` stables et distincts.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const idGen = inject(KtIdGenerator);
130
+ * const anchor = `--kt-menu-anchor-${idGen.generateId('menu')}`;
131
+ * ```
132
+ */
101
133
  declare class KtIdGenerator {
102
134
  private readonly counters;
103
135
  private nextGlobalId;
136
+ /**
137
+ * Renvoie le prochain identifiant. Sans `prefix`, utilise le compteur global ; avec `prefix`,
138
+ * utilise un compteur dédié à ce préfixe (séquences indépendantes).
139
+ * @param prefix Clé optionnelle de compteur ; chaque préfixe a sa propre séquence.
140
+ * @returns Le compteur courant (number) pour la portée demandée, avant incrément.
141
+ */
104
142
  generateId(prefix?: string): number;
105
143
  static ɵfac: i0.ɵɵFactoryDeclaration<KtIdGenerator, never>;
106
144
  static ɵprov: i0.ɵɵInjectableDeclaration<KtIdGenerator>;
@@ -23,7 +23,10 @@ declare class KtDialogTitle {
23
23
  private readonly host;
24
24
  private readonly renderer;
25
25
  private readonly idGen;
26
- /** Id de l'hôte câblé en `aria-labelledby` : préserve un id fourni par le consommateur, sinon en génère un. */
26
+ /**
27
+ * Id de l'hôte câblé en `aria-labelledby` : préserve un id fourni par le consommateur, sinon en génère un.
28
+ * @default `host.id` ?? `dialogRef.config.ariaLabelledBy` ?? `kt-dialog-title-<généré>`
29
+ */
27
30
  readonly id: string;
28
31
  constructor();
29
32
  static ɵfac: i0.ɵɵFactoryDeclaration<KtDialogTitle, never>;
@@ -50,7 +53,10 @@ declare class KtDialogDescription implements OnInit, OnDestroy {
50
53
  private readonly host;
51
54
  private readonly renderer;
52
55
  private readonly idGen;
53
- /** Id de l'hôte câblé en `aria-describedby` : préserve un id fourni par le consommateur, sinon en génère un. */
56
+ /**
57
+ * Id de l'hôte câblé en `aria-describedby` : préserve un id fourni par le consommateur, sinon en génère un.
58
+ * @default `host.id` ?? `dialogRef.config.ariaDescribedBy` ?? `kt-dialog-desc-<généré>`
59
+ */
54
60
  readonly id: string;
55
61
  constructor();
56
62
  ngOnInit(): void;
@@ -190,12 +196,28 @@ declare class KtDialogSheetHandle {
190
196
  * Pour focaliser un élément précis à l'ouverture (ex. éviter un bouton destructeur),
191
197
  * passez `autoFocus: '[ktDialogFocusInitial]'` dans la config d'ouverture et posez la
192
198
  * directive `ktDialogFocusInitial` sur la cible.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * // valeur de base, généralement consommée via provideKtDialogDefaults()
203
+ * provideKtDialogDefaults({ ...KT_DIALOG_AAA_DEFAULTS });
204
+ * ```
193
205
  */
194
206
  declare const KT_DIALOG_AAA_DEFAULTS: DialogConfig;
195
207
  /**
196
208
  * Enregistre les valeurs par défaut AAA du dialog au niveau application.
197
209
  * À ajouter aux `providers` de `app.config.ts`. `overrides` permet d'ajuster sans
198
210
  * tout réécrire (ex. `provideKtDialogDefaults({ maxWidth: '40rem' })`).
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * // app.config.ts
215
+ * export const appConfig: ApplicationConfig = {
216
+ * providers: [provideKtDialogDefaults({ maxWidth: '40rem' })],
217
+ * };
218
+ * ```
219
+ * @param overrides Surcharges partielles fusionnées par-dessus `KT_DIALOG_AAA_DEFAULTS`.
220
+ * @returns Un `Provider` pour le token `DEFAULT_DIALOG_CONFIG`.
199
221
  */
200
222
  declare function provideKtDialogDefaults(overrides?: Partial<DialogConfig>): Provider;
201
223
  /**
@@ -215,58 +237,134 @@ type KtDialogPresentation = 'centered' | 'fullscreen' | 'sheet' | 'centered-full
215
237
  * `centered-*`, l'appelant fournit `compact` (= `KtViewport.isCompact()`, largeur seule) — centré
216
238
  * sur desktop, plein écran / sheet sur écran compact. Fonction pure (testable sans DOM).
217
239
  * Appelée par `injectKtDialogOpener` à chaque ouverture ; exportée pour un usage direct éventuel.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * resolveKtDialogPanelClass('sheet'); // ['kt-dialog', 'kt-dialog--sheet']
244
+ * resolveKtDialogPanelClass('centered-sheet', true); // bottom-sheet sur écran compact
245
+ * ```
246
+ * @param presentation Présentation choisie par le dev (responsive comprise). Défaut `'centered'`.
247
+ * @param compact `true` quand l'écran est compact (= `KtViewport.isCompact()`), pour résoudre les variantes `centered-*`. Défaut `false`.
248
+ * @returns La liste des classes CSS de la présentation concrète résolue.
218
249
  */
219
250
  declare function resolveKtDialogPanelClass(presentation?: KtDialogPresentation, compact?: boolean): string[];
220
251
 
221
252
  /**
222
- * Sucre typé pour récupérer les données injectées dans un composant de dialogue (`DIALOG_DATA`).
223
- * À appeler en contexte d'injection (ex. initialiseur de champ).
253
+ * ⚠️ API BAS-NIVEAU n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par
254
+ * {@link defineKtDialog} et son `injectData()` (qui lie le type des données à l'ouvreur).
224
255
  *
225
- * @example
226
- * ```ts
227
- * interface RenameData { currentName: string; }
228
- *
229
- * @Component({ … })
230
- * export class RenameDialog {
231
- * protected readonly data = injectKtDialogData<RenameData>();
232
- * // this.data.currentName → string
233
- * }
234
- * ```
256
+ * Sucre typé pour récupérer les données injectées dans un composant de dialogue (`DIALOG_DATA`).
257
+ * Le type `T` est affirmé ICI indépendamment de l'ouvreur : rien ne garantit qu'il corresponde au
258
+ * type passé à `injectKtDialogOpener` risque de divergence silencieuse. À réserver à un cas où
259
+ * `defineKtDialog` ne convient pas.
235
260
  */
236
261
  declare function injectKtDialogData<T>(): T;
237
262
  /** Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation`. */
238
- type OpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & {
263
+ type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & {
239
264
  /** Présentation du dialog (cf. `KtDialogPresentation`) — choisie par le dev. Résolue à CHAQUE
240
265
  ouverture : les variantes responsive lisent le signal d'écran compact. Défaut : `'centered'`.
241
266
  Combinée à un éventuel `panelClass` additionnel. */
242
267
  presentation?: KtDialogPresentation;
243
268
  };
244
269
  /**
245
- * Crée un ouvreur de dialog **typé et centralisé**, en contexte d'injection.
246
- * Le contrat (composant + type de `data` + type de résultat + config par défaut) est défini
247
- * UNE fois ; l'ouvreur renvoyé est une closure appelable ensuite n'importe dans la classe
248
- * (handlers compris), 100 % typée, sans nouvel `inject`.
270
+ * ⚠️ API BAS-NIVEAU n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par
271
+ * {@link defineKtDialog} puis son `injectOpener(...)` : il fixe données + résultat une seule fois et
272
+ * les partage avec `injectData()`/`injectRef()`. N'appelez `injectKtDialogOpener` directement que
273
+ * dans un cas avancé le contrat groupé de `defineKtDialog` ne convient pas.
274
+ *
275
+ * Crée un ouvreur de dialog typé en contexte d'injection : le contrat (composant + type de `data` +
276
+ * type de résultat + config par défaut) est figé via les génériques `<Composant, Data, Résultat>`
277
+ * (qu'il faut répéter — d'où la préférence pour `defineKtDialog`). L'ouvreur renvoyé est une closure
278
+ * appelable n'importe où dans la classe, 100 % typée, sans nouvel `inject`.
249
279
  *
250
280
  * Conserve le `ViewContainerRef` du contexte appelant (le dialog hérite donc de l'arbre logique
251
281
  * d'injection), reste testable (TestBed fournit `Dialog`) et sans état global (SSR-safe).
252
282
  *
283
+ * @param component Composant à monter dans le dialog.
284
+ * @param baseConfig Config d'ouverture par défaut (sans `data`), enrichie de `presentation` ; fusionnée à chaque ouverture.
285
+ * @returns Une closure d'ouverture typée : `() => DialogRef` (sans data) ou `(data, config?) => DialogRef` (avec data).
286
+ * @see {@link defineKtDialog} — la façon recommandée d'obtenir cet ouvreur.
287
+ */
288
+ declare function injectKtDialogOpener<C, R = unknown>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<void, R, C>): () => DialogRef<R, C>;
289
+ declare function injectKtDialogOpener<C, D, R = unknown>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;
290
+ /**
291
+ * Contrat de dialog typé renvoyé par `defineKtDialog` : les trois accès (données, référence,
292
+ * ouvreur) dérivent des MÊMES génériques `D`/`R`, déclarés une seule fois — impossible donc que
293
+ * le type des données ou du résultat diverge entre le composant et l'ouvreur.
294
+ *
295
+ * @template D Type des données injectées (`void` si aucune).
296
+ * @template R Type du résultat renvoyé à la fermeture.
297
+ */
298
+ interface KtDialogContract<D, R> {
299
+ /** Données injectées (à appeler en contexte d'injection DANS le composant de dialog). */
300
+ injectData(): D;
301
+ /** Référence typée du dialog : `close()` n'accepte QUE le résultat `R` (sûreté de fermeture). */
302
+ injectRef(): DialogRef<R>;
303
+ /** Ouvreur typé CO-LOCALISÉ pour ce composant (cf. `injectKtDialogOpener`). */
304
+ injectOpener<C>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;
305
+ }
306
+ /**
307
+ * ✅ STRATÉGIE PAR DÉFAUT pour implémenter un dialog `@ktortu/aaa`. Toute nouvelle dialog DOIT être
308
+ * écrite ainsi. N'utilisez `injectKtDialogData` / `injectKtDialogOpener` directement QUE dans un cas
309
+ * avancé non couvert ici.
310
+ *
311
+ * Définit le contrat typé du dialog (données `D` + résultat `R`) en UN SEUL endroit, co-localisé avec
312
+ * le composant. Renvoie trois accès liés aux mêmes types — `injectData()` (données), `injectRef()`
313
+ * (référence dont `close()` n'accepte que `R`) et `injectOpener()` (ouvreur) — d'où l'impossibilité
314
+ * d'une divergence de type entre composant et ouvreur.
315
+ *
316
+ * Recette à copier pour CHAQUE dialog :
317
+ * 1. `interface XxxData { … }` (ou `void` si aucune donnée) ;
318
+ * 2. `const xxxDialog = defineKtDialog<XxxData, Résultat>();` ;
319
+ * 3. dans le composant : `injectData()` pour lire la donnée, `injectRef()` pour fermer avec résultat ;
320
+ * 4. `export const injectXxxDialog = () => xxxDialog.injectOpener(XxxDialog);` (co-localisé) ;
321
+ * 5. côté consommateur : `private readonly openXxx = injectXxxDialog();` (initialiseur de champ).
322
+ *
323
+ * Convention de fermeture : annuler / fermer SANS résultat via la directive `[ktDialogClose]`
324
+ * (→ `undefined`) ; renvoyer un résultat via `ref.close(résultat)` (typé `R`). Passer un résultat par
325
+ * `[ktDialogClose]="x"` reste possible mais N'EST PAS typé (la directive ignore `R`).
326
+ *
253
327
  * @example
254
- * // co-localisé avec le composant
255
- * export const injectRenameDialog = () =>
256
- * injectKtDialogOpener<RenameDialog, RenameData, string>(RenameDialog, { autoFocus: '[ktDialogFocusInitial]' });
328
+ * ```ts
329
+ * // ─── rename-dialog.ts : composant + contrat + ouvreur, co-localisés ───
330
+ * export interface RenameData { currentName: string; }
257
331
  *
258
- * // dans un composant/service consommateur
259
- * private readonly openRename = injectRenameDialog();
260
- * rename() { this.openRename({ currentName: 'X' }).closed.subscribe(n => { n: string | undefined }); }
332
+ * const renameDialog = defineKtDialog<RenameData, string>(); // D et R déclarés UNE seule fois
333
+ *
334
+ * @Component({
335
+ * imports: [KtButton, KtDialogImports],
336
+ * template: `
337
+ * <h2 ktDialogTitle>Renommer</h2>
338
+ * <footer ktDialogActions>
339
+ * <button ktButton ktDialogClose>Annuler</button> // ferme sans résultat (undefined)
340
+ * <button ktButton (click)="submit()">Renommer</button> // ferme avec résultat typé
341
+ * </footer>`,
342
+ * })
343
+ * export class RenameDialog {
344
+ * protected readonly data = renameDialog.injectData(); // RenameData garanti
345
+ * private readonly ref = renameDialog.injectRef(); // DialogRef<string>
346
+ * protected submit() { this.ref.close('nouveau-nom'); } // close(result?: string) — typé
347
+ * }
348
+ *
349
+ * export const injectRenameDialog = () => renameDialog.injectOpener(RenameDialog);
350
+ *
351
+ * // ─── consommateur ───
352
+ * private readonly openRename = injectRenameDialog(); // initialiseur de champ = contexte d'injection
353
+ * rename() {
354
+ * this.openRename({ currentName: 'X' }).closed.subscribe(name => {
355
+ * // name: string | undefined
356
+ * });
357
+ * }
358
+ * ```
261
359
  */
262
- declare function injectKtDialogOpener<C, R = unknown>(component: ComponentType<C>, baseConfig?: OpenerConfig<void, R, C>): () => DialogRef<R, C>;
263
- declare function injectKtDialogOpener<C, D, R = unknown>(component: ComponentType<C>, baseConfig?: OpenerConfig<D, R, C>): (data: D, config?: OpenerConfig<D, R, C>) => DialogRef<R, C>;
360
+ declare function defineKtDialog<D = void, R = unknown>(): KtDialogContract<D, R>;
264
361
 
265
362
  declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
266
363
  private readonly dialogRef;
267
364
  private readonly elementRef;
268
365
  private readonly host;
269
366
  private readonly platformId;
367
+ private readonly destroyRef;
270
368
  protected readonly isClosing: i0.WritableSignal<boolean>;
271
369
  constructor();
272
370
  ngOnInit(): void;
@@ -278,9 +376,9 @@ declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
278
376
 
279
377
  /**
280
378
  * Import ergonomique de toute la famille dialog en une fois :
281
- * `imports: [KT_DIALOG]` au lieu d'énumérer chaque directive structurelle.
379
+ * `imports: [KtDialogImports]` au lieu d'énumérer chaque directive structurelle.
282
380
  */
283
- declare const KT_DIALOG: readonly [typeof KtDialogHeader, typeof KtDialogTitle, typeof KtDialogDescription, typeof KtDialogContent, typeof KtDialogActions, typeof KtDialogClose, typeof KtDialogFocusInitial, typeof KtDialogSheetHandle];
381
+ declare const KtDialogImports: readonly [typeof KtDialogHeader, typeof KtDialogTitle, typeof KtDialogDescription, typeof KtDialogContent, typeof KtDialogActions, typeof KtDialogClose, typeof KtDialogFocusInitial, typeof KtDialogSheetHandle];
284
382
 
285
- export { KT_DIALOG, KT_DIALOG_AAA_DEFAULTS, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogSheetHandle, KtDialogTitle, injectKtDialogData, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
286
- export type { KtDialogPresentation };
383
+ export { KT_DIALOG_AAA_DEFAULTS, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, defineKtDialog, injectKtDialogData, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
384
+ export type { KtDialogContract, KtDialogOpenerConfig, KtDialogPresentation };