@ktortu/aaa 0.1.0-beta.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +23 -7
  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 +58 -15
  8. package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
  9. package/fesm2022/ktortu-aaa-dialog.mjs +69 -12
  10. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
  11. package/fesm2022/ktortu-aaa-forms.mjs +455 -260
  12. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
  13. package/fesm2022/ktortu-aaa-i18n.mjs +114 -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-tabs.mjs +319 -42
  18. package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
  19. package/fesm2022/ktortu-aaa-tooltip.mjs +3 -2
  20. package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
  21. package/fesm2022/ktortu-aaa.mjs +1 -0
  22. package/fesm2022/ktortu-aaa.mjs.map +1 -1
  23. package/forms/radio/radio-group.css +3 -3
  24. package/forms/styles/field-box.css +150 -2
  25. package/forms/styles/tokens.css +3 -0
  26. package/menu/menu.css +8 -4
  27. package/package.json +5 -1
  28. package/types/ktortu-aaa-button.d.ts +22 -8
  29. package/types/ktortu-aaa-card.d.ts +24 -4
  30. package/types/ktortu-aaa-cdk.d.ts +38 -0
  31. package/types/ktortu-aaa-dialog.d.ts +45 -9
  32. package/types/ktortu-aaa-forms.d.ts +336 -149
  33. package/types/ktortu-aaa-i18n.d.ts +74 -0
  34. package/types/ktortu-aaa-menu.d.ts +15 -8
  35. package/types/ktortu-aaa-tabs.d.ts +130 -13
  36. package/types/ktortu-aaa-tooltip.d.ts +5 -0
  37. package/types/ktortu-aaa.d.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
1
+ {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -24,9 +24,9 @@
24
24
  /* Disposition des options : pilotable par token (colonne par défaut, ligne possible). */
25
25
  .kt-radio-group__options {
26
26
  display: flex;
27
- flex-direction: var(--radio-group-direction, column);
27
+ flex-direction: var(--radio-group-direction, row);
28
28
  flex-wrap: wrap;
29
- gap: var(--radio-group-gap, 0.25rem);
29
+ gap: var(--radio-group-gap, 1rem);
30
30
  }
31
31
 
32
32
  .kt-radio-group__hint {
@@ -52,4 +52,4 @@
52
52
  animation: none;
53
53
  }
54
54
  }
55
- }
55
+ }
@@ -1,9 +1,22 @@
1
1
  @layer kt-aaa.components {
2
- /* Boîte de contrôle partagée par les champs simples (TextField, NumberField).
2
+ /* Boîte de contrôle partagée par les champs simples (TextField, NumberField) et la famille
3
+ Temporal (Date/Time/DateTime/YearMonth/Instant), qui réutilise la même `.kt-field-box`.
3
4
  Globale + classes namespacées : partagée entre plusieurs composants, donc non scopable. */
4
5
  kt-text-field,
5
- kt-number-field {
6
+ kt-text-area,
7
+ kt-number-field,
8
+ kt-date-field,
9
+ kt-time-field,
10
+ kt-date-time-field,
11
+ kt-year-month-field,
12
+ kt-instant-field,
13
+ kt-select,
14
+ kt-multi-select {
6
15
  display: block;
16
+ /* Largeur pilotable d'un coup via --field-width. Défaut `auto` : remplit le conteneur en
17
+ contexte bloc (formulaire), se dimensionne au contenu en flex. Surcharger sur :root ou un
18
+ conteneur pour fixer tous les champs (ex. --field-width: 320px). */
19
+ width: var(--field-width, auto);
7
20
  }
8
21
 
9
22
  .kt-field-box {
@@ -168,4 +181,139 @@
168
181
  field-sizing: content;
169
182
  resize: vertical;
170
183
  }
184
+
185
+ /* =========================================================================
186
+ Apparence OUTLINE (opt-in via [appearance]="'outline'" ou KT_FIELD_CONFIG).
187
+ Label flottant qui se loge dans la bordure haute de la boîte (façon Material).
188
+ Rendu GLOBAL (et non dans field.css scopé) car il référence .kt-field-box*,
189
+ contenu PROJETÉ depuis le composant de champ — inatteignable en CSS scopé.
190
+ L'apparence par défaut (fill) n'est jamais touchée.
191
+ ========================================================================= */
192
+ kt-field[data-appearance='outline'] {
193
+ position: relative;
194
+ margin-top: 0.5rem; /* espace pour le label une fois flotté au-dessus de la bordure */
195
+ }
196
+
197
+ /* Le header (label + aide) recouvre la boîte sans réserver de hauteur en flux. */
198
+ kt-field[data-appearance='outline'] .kt-field__header {
199
+ position: absolute;
200
+ inset: 0 0 auto 0;
201
+ height: var(--field-min-height, 44px);
202
+ margin: 0;
203
+ padding-inline: var(--field-padding-x, 0.75rem);
204
+ z-index: 1;
205
+ pointer-events: none; /* la boîte/l'input dessous restent cliquables */
206
+ }
207
+
208
+ /* Label au repos = position « placeholder » (centré verticalement dans la boîte). */
209
+ kt-field[data-appearance='outline'] .kt-field__label {
210
+ position: absolute;
211
+ inset-inline-start: var(--field-padding-x, 0.75rem);
212
+ top: 50%;
213
+ transform: translateY(-50%);
214
+ transform-origin: left center;
215
+ max-width: calc(100% - 2 * var(--field-padding-x, 0.75rem));
216
+ overflow: hidden;
217
+ white-space: nowrap;
218
+ text-overflow: ellipsis;
219
+ background: transparent;
220
+ padding-inline: 0.25rem;
221
+ font-size: var(--field-font-size, 1rem);
222
+ font-weight: 400;
223
+ color: var(--field-hint-color, #5f6368);
224
+ transition: transform 0.15s ease, color 0.15s ease;
225
+ }
226
+
227
+ /* RTL : `transform-origin` n'accepte pas de mot-clé logique → on bascule l'origine de la mise à
228
+ l'échelle vers le bord de départ (droite en RTL) pour rester aligné sur `inset-inline-start`. */
229
+ [dir='rtl'] kt-field[data-appearance='outline'] .kt-field__label {
230
+ transform-origin: right center;
231
+ }
232
+
233
+ /* Bouton d'aide : recliquable et calé à droite du header. */
234
+ kt-field[data-appearance='outline'] .kt-field__help {
235
+ margin-inline-start: auto;
236
+ pointer-events: auto;
237
+ }
238
+
239
+ /* Label flotté — DEUX règles séparées à dessein (dégradation gracieuse) : la 1re (focus / always)
240
+ reste valide même si le moteur ne supporte pas `:has()`. Une seule pseudo-classe inconnue dans une
241
+ liste de sélecteurs invaliderait TOUTE la liste → le label ne flotterait jamais, focus compris.
242
+ La 2nde ajoute les cas qui exigent `:has()` (input rempli, select `[data-filled]`). Les inputs
243
+ date/heure n'ayant pas de placeholder CSS, `:not(:placeholder-shown)` les garde flottés en permanence. */
244
+ kt-field[data-appearance='outline'][data-float-label='always'] .kt-field__label,
245
+ kt-field[data-appearance='outline']:focus-within .kt-field__label {
246
+ transform: translateY(-50%) translateY(calc(var(--field-min-height, 44px) / -2)) scale(0.75);
247
+ color: var(--field-label-color, inherit);
248
+ /* Fond du label flotté : masque la ligne d'outline sous le label. Défaut : fond PLEIN du champ.
249
+ Le consommateur peut poser un gradient (ex. `linear-gradient(transparent 50%, var(--field-bg) 50%)`)
250
+ via le token --field-label-float-bg. */
251
+ background: var(--field-label-float-bg, var(--field-bg, #fff));
252
+ }
253
+ kt-field[data-appearance='outline']:has(.kt-field-box[data-filled]) .kt-field__label,
254
+ kt-field[data-appearance='outline']:has(.kt-field-box__input:not(:placeholder-shown)) .kt-field__label {
255
+ transform: translateY(-50%) translateY(calc(var(--field-min-height, 44px) / -2)) scale(0.75);
256
+ color: var(--field-label-color, inherit);
257
+ background: var(--field-label-float-bg, var(--field-bg, #fff));
258
+ }
259
+
260
+ /* Bordure de l'outline : token dédié (état de repos). Surcharge possible indépendamment du
261
+ mode `fill`. Les états hover/focus/invalid gardent leurs propres tokens (réaffirmés ici
262
+ pour rester prioritaires sur la règle de repos). */
263
+ kt-field[data-appearance='outline'] .kt-field-box {
264
+ border-color: var(--field-outline-border-color, var(--field-border-color, #c4c7c5));
265
+ }
266
+ kt-field[data-appearance='outline'] .kt-field-box:hover {
267
+ border-color: var(--field-border-color-hover, #5f6368);
268
+ }
269
+ kt-field[data-appearance='outline'] .kt-field-box:focus-within {
270
+ border-color: var(--field-border-color-focus, #0b57d0);
271
+ }
272
+ kt-field[data-appearance='outline'] .kt-field-box[data-invalid] {
273
+ border-color: var(--field-error-color, #b3261e);
274
+ }
275
+
276
+ /* En outline AUTO, le label flottant tient lieu de placeholder au repos : on masque le placeholder
277
+ propre du select (sinon doublon avec le label en position « placeholder »). En ALWAYS, le label
278
+ est déjà en haut → on laisse le placeholder du select s'afficher. */
279
+ kt-field[data-appearance='outline']:not([data-float-label='always']) .kt-select__placeholder {
280
+ visibility: hidden;
281
+ }
282
+
283
+ /* En outline, le placeholder natif ne s'affiche QUE lorsque le label flotte : au repos le label
284
+ tient lieu de placeholder (sinon les deux se superposeraient). Masqué par défaut, révélé au
285
+ focus ou en floatLabel='always'. (Quand le champ est rempli, le navigateur ne le rend pas.) */
286
+ kt-field[data-appearance='outline'] .kt-field-box__input::placeholder {
287
+ color: transparent;
288
+ }
289
+ kt-field[data-appearance='outline']:focus-within .kt-field-box__input::placeholder,
290
+ kt-field[data-appearance='outline'][data-float-label='always'] .kt-field-box__input::placeholder {
291
+ color: var(--field-placeholder-color, var(--field-hint-color, #5f6368));
292
+ }
293
+
294
+ /* Accent au focus / état d'erreur. */
295
+ kt-field[data-appearance='outline']:focus-within .kt-field__label {
296
+ color: var(--field-border-color-focus, #0b57d0);
297
+ }
298
+ kt-field[data-appearance='outline']:has(.kt-field-box[data-invalid]) .kt-field__label {
299
+ color: var(--field-error-color, #b3261e);
300
+ }
301
+
302
+ @media (prefers-reduced-motion: reduce) {
303
+ kt-field[data-appearance='outline'] .kt-field__label {
304
+ transition: none;
305
+ }
306
+ }
307
+
308
+ /* Contraste forcé (Windows High Contrast) : le fond du label flotté masque la bordure ; un gradient
309
+ custom `--field-label-float-bg` serait ignoré → on force une couleur système opaque pour garantir
310
+ le « notch ». Au repos le label est transparent (non listé), donc rien à forcer. */
311
+ @media (forced-colors: active) {
312
+ kt-field[data-appearance='outline'][data-float-label='always'] .kt-field__label,
313
+ kt-field[data-appearance='outline']:focus-within .kt-field__label,
314
+ kt-field[data-appearance='outline']:has(.kt-field-box[data-filled]) .kt-field__label,
315
+ kt-field[data-appearance='outline']:has(.kt-field-box__input:not(:placeholder-shown)) .kt-field__label {
316
+ background: Canvas;
317
+ }
318
+ }
171
319
  }
@@ -35,6 +35,9 @@
35
35
  --field-padding-y: 0.5rem;
36
36
  --field-gap: 0.375rem;
37
37
  --field-control-gap: 0.5rem;
38
+ /* Largeur du champ : un seul réglage pilote tous les champs. Défaut `auto` (remplit le
39
+ conteneur en bloc, se dimensionne au contenu en flex). Ex. global : --field-width: 320px. */
40
+ --field-width: auto;
38
41
 
39
42
  /* Typo */
40
43
  --field-font-size: var(--kt-control-font);
package/menu/menu.css CHANGED
@@ -42,8 +42,11 @@
42
42
  [ktMenu] {
43
43
  position: fixed;
44
44
  inset: auto;
45
- inset-block-start: anchor(block-end);
46
- inset-inline-start: anchor(inline-start);
45
+ /* Dropdown sous le déclencheur, aligné sur son bord inline-start. On utilise `position-area`
46
+ et NON la fonction `anchor()` : `anchor()` résout mal une ancre imbriquée dans un sous-arbre
47
+ déjà ancré → les sous-menus s'EMPILENT dès le 3ᵉ niveau. `position-area` cascade correctement
48
+ à n'importe quelle profondeur (validé Chrome 125+ / Firefox 147+ / Safari 26+). */
49
+ position-area: block-end span-inline-end;
47
50
  margin-block-start: var(--kt-menu-offset, 0.25rem);
48
51
  /* Bascule de côté / au-dessus si le bas/droite manque de place. */
49
52
  position-try-fallbacks:
@@ -61,8 +64,9 @@
61
64
  --_submenu-offset: calc(
62
65
  var(--kt-menu-padding, 0.25rem) + var(--kt-menu-border-width, 1px) + var(--kt-menu-submenu-gap, 0.375rem)
63
66
  );
64
- inset-block-start: anchor(block-start);
65
- inset-inline-start: anchor(inline-end);
67
+ /* À l'inline-end de l'item parent, aligné sur son haut. `position-area` (et non `anchor()`)
68
+ pour cascader correctement à toute profondeur — cf. note sur le menu racine ci-dessus. */
69
+ position-area: inline-end span-block-end;
66
70
  margin-block-start: 0;
67
71
  margin-inline-start: var(--_submenu-offset);
68
72
  position-try-fallbacks:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktortu/aaa",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.9.0",
4
4
  "description": "Bibliothèque de composants Angular headless + thémés par tokens CSS.",
5
5
  "keywords": [
6
6
  "angular",
@@ -77,6 +77,10 @@
77
77
  "types": "./types/ktortu-aaa-forms.d.ts",
78
78
  "default": "./fesm2022/ktortu-aaa-forms.mjs"
79
79
  },
80
+ "./i18n": {
81
+ "types": "./types/ktortu-aaa-i18n.d.ts",
82
+ "default": "./fesm2022/ktortu-aaa-i18n.mjs"
83
+ },
80
84
  "./menu": {
81
85
  "types": "./types/ktortu-aaa-menu.d.ts",
82
86
  "default": "./fesm2022/ktortu-aaa-menu.mjs"
@@ -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,6 +237,15 @@ 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
 
@@ -235,7 +266,7 @@ declare function resolveKtDialogPanelClass(presentation?: KtDialogPresentation,
235
266
  */
236
267
  declare function injectKtDialogData<T>(): T;
237
268
  /** 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'> & {
269
+ type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & {
239
270
  /** Présentation du dialog (cf. `KtDialogPresentation`) — choisie par le dev. Résolue à CHAQUE
240
271
  ouverture : les variantes responsive lisent le signal d'écran compact. Défaut : `'centered'`.
241
272
  Combinée à un éventuel `panelClass` additionnel. */
@@ -258,15 +289,20 @@ type OpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & {
258
289
  * // dans un composant/service consommateur
259
290
  * private readonly openRename = injectRenameDialog();
260
291
  * rename() { this.openRename({ currentName: 'X' }).closed.subscribe(n => { n: string | undefined }); }
292
+ *
293
+ * @param component Composant à monter dans le dialog.
294
+ * @param baseConfig Config d'ouverture par défaut (sans `data`), enrichie de `presentation` ; fusionnée à chaque ouverture.
295
+ * @returns Une closure d'ouverture typée : `() => DialogRef` (sans data) ou `(data, config?) => DialogRef` (avec data).
261
296
  */
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>;
297
+ declare function injectKtDialogOpener<C, R = unknown>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<void, R, C>): () => DialogRef<R, C>;
298
+ 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>;
264
299
 
265
300
  declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
266
301
  private readonly dialogRef;
267
302
  private readonly elementRef;
268
303
  private readonly host;
269
304
  private readonly platformId;
305
+ private readonly destroyRef;
270
306
  protected readonly isClosing: i0.WritableSignal<boolean>;
271
307
  constructor();
272
308
  ngOnInit(): void;
@@ -278,9 +314,9 @@ declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
278
314
 
279
315
  /**
280
316
  * Import ergonomique de toute la famille dialog en une fois :
281
- * `imports: [KT_DIALOG]` au lieu d'énumérer chaque directive structurelle.
317
+ * `imports: [KtDialogImports]` au lieu d'énumérer chaque directive structurelle.
282
318
  */
283
- declare const KT_DIALOG: readonly [typeof KtDialogHeader, typeof KtDialogTitle, typeof KtDialogDescription, typeof KtDialogContent, typeof KtDialogActions, typeof KtDialogClose, typeof KtDialogFocusInitial, typeof KtDialogSheetHandle];
319
+ declare const KtDialogImports: readonly [typeof KtDialogHeader, typeof KtDialogTitle, typeof KtDialogDescription, typeof KtDialogContent, typeof KtDialogActions, typeof KtDialogClose, typeof KtDialogFocusInitial, typeof KtDialogSheetHandle];
284
320
 
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 };
321
+ export { KT_DIALOG_AAA_DEFAULTS, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, injectKtDialogData, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
322
+ export type { KtDialogOpenerConfig, KtDialogPresentation };