@ktortu/aaa 0.9.8 → 0.10.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.
@@ -5,6 +5,7 @@ export * from '@ktortu/aaa/dialog';
5
5
  export * from '@ktortu/aaa/disclosure';
6
6
  export * from '@ktortu/aaa/forms';
7
7
  export * from '@ktortu/aaa/i18n';
8
+ export * from '@ktortu/aaa/icon';
8
9
  export * from '@ktortu/aaa/menu';
9
10
  export * from '@ktortu/aaa/snackbar';
10
11
  export * from '@ktortu/aaa/tabs';
@@ -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/disclosure';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/snackbar';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\nexport * from '@ktortu/aaa/progress-bar';\nexport * from '@ktortu/aaa/layout';\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/disclosure';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/icon';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/snackbar';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\nexport * from '@ktortu/aaa/progress-bar';\nexport * from '@ktortu/aaa/layout';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -87,7 +87,7 @@
87
87
  color: inherit;
88
88
  font: inherit;
89
89
  caret-color: var(--field-caret-color, auto); /* bascule (thème terminal, etc.) */
90
- padding-inline-end: 0.5rem;
90
+ padding-inline-end: var(--field-input-padding-end, 0.5rem);
91
91
  }
92
92
 
93
93
  .kt-field-box__input:disabled {
@@ -95,6 +95,16 @@
95
95
  color: color-mix(in srgb, currentColor 50%, transparent);
96
96
  }
97
97
 
98
+ /* Types temporels natifs (date/time/datetime-local/month) : l'indicateur natif de sélecteur
99
+ (calendrier/horloge) vit à la FIN de l'input et gère déjà son propre espacement. Le respir de
100
+ fin « texte » ne protège ici aucune saisie libre : il ne ferait que repousser ce picto vers
101
+ l'intérieur (renfoncement de 1.25rem = box 0.75 + input 0.5, incohérent avec les champs texte).
102
+ On remet donc le token à 0 ; la gouttière commune reste le padding de la boîte (0.75rem). La
103
+ propriété consommatrice est LOGIQUE => l'indicateur bascule aussi côté départ en RTL. */
104
+ .kt-field-box__input:is([type='date'], [type='time'], [type='datetime-local'], [type='month']) {
105
+ --field-input-padding-end: 0;
106
+ }
107
+
98
108
  /* Datalist : masque la flèche déroulante native (Chromium) sur les champs texte/number. Le
99
109
  pseudo-élément étant partagé avec l'icône de picker des champs date/heure (qui peuvent eux
100
110
  aussi porter un `list`), on restreint aux types concernés pour ne pas masquer leur picker. */
@@ -35,6 +35,11 @@
35
35
  --field-padding-y: 0.5rem;
36
36
  --field-gap: 0.375rem;
37
37
  --field-control-gap: 0.5rem;
38
+ /* Respir de fin propre à l'input (texte/caret), distinct de la gouttière de la boîte
39
+ (--field-padding-x) et de l'écart entre contrôles (--field-control-gap). Neutralisé à 0 pour
40
+ les champs temporels natifs (cf. field-box.css : l'indicateur de picker gère son propre
41
+ espacement, ce respir ne ferait que le décaler vers l'intérieur). */
42
+ --field-input-padding-end: 0.5rem;
38
43
  /* Largeur du champ : un seul réglage pilote tous les champs. Défaut `auto` (remplit le
39
44
  conteneur en bloc, se dimensionne au contenu en flex). Ex. global : --field-width: 320px. */
40
45
  --field-width: auto;
@@ -143,6 +143,12 @@
143
143
  user-select: none;
144
144
  }
145
145
 
146
+ /* Label vide (ni texte ni contenu projeté — switch nommé via ariaLabel) : masqué pour ne pas
147
+ réserver l'écart flex de la rangée. Le label reste dans le DOM pour accueillir la projection. */
148
+ .kt-switch-label:empty {
149
+ display: none;
150
+ }
151
+
146
152
  .kt-switch-field--disabled .kt-switch-label {
147
153
  cursor: not-allowed;
148
154
  color: var(--field-hint-color, #5f6368);
package/icon/icon.css ADDED
@@ -0,0 +1,52 @@
1
+ @layer kt-aaa.components {
2
+ /* Styles de la primitive d'icône autonome [ktIcon]. Global : chargé via l'agrégat styles.css,
3
+ applicable partout où la directive est posée. Ciblé par la CLASSE `.kt-icon` (posée en dur sur
4
+ l'hôte par la directive) et NON par l'attribut de sélecteur : un binding `[ktIcon]="x"` ne reflète
5
+ aucun attribut dans le DOM, la classe reste le seul marqueur fiable. Leviers = BASCULES NON déclarées
6
+ (le fallback var() fait foi) : --kt-icon-font / --kt-icon-font-weight / --kt-icon-font-variation (posées
7
+ par la directive quand une police du registre est résolue, sinon cascade globale) + --kt-icon-size
8
+ (posée par [size]) + --kt-icon-overflow (bascule d'opt-out du rognage de la boîte ligature). */
9
+
10
+ .kt-icon {
11
+ display: inline-flex;
12
+ align-items: center;
13
+ justify-content: center;
14
+ flex: none;
15
+ /* Taille pilotée par --kt-icon-size (posée par [size]) ; défaut relatif au texte du contexte. */
16
+ font-size: var(--kt-icon-size, 1.25em);
17
+ line-height: 1;
18
+ /* Couleur héritée du texte courant (currentColor) : l'icône suit son contexte sans réglage. */
19
+ color: inherit;
20
+ /* Alignement propre au fil du texte (icône ↔ libellé adjacent). */
21
+ vertical-align: middle;
22
+ -webkit-font-smoothing: antialiased;
23
+ }
24
+
25
+ /* Rendu de la LIGATURE (nom → glyphe) via un pseudo-élément, comme Button/Field.
26
+ Police : --kt-icon-font (posée par la directive si police du registre résolue) > cascade globale
27
+ > Material Symbols Outlined. Un set NON-ligature (Font Awesome…) se projette dans l'hôte (ktIcon
28
+ vide) : aucun ::before n'est alors rendu. */
29
+ .kt-icon[data-icon]::before {
30
+ content: attr(data-icon);
31
+ font-family: var(--kt-icon-font, 'Material Symbols Outlined');
32
+ font-weight: var(--kt-icon-font-weight, normal);
33
+ font-style: normal;
34
+ font-size: 1em; /* = taille de l'hôte (--kt-icon-size) */
35
+ line-height: 1;
36
+ font-variation-settings: var(--kt-icon-font-variation, normal);
37
+ font-feature-settings: 'liga';
38
+ }
39
+
40
+ /* Boîte réservée (1 em, carrée) UNIQUEMENT en mode ligature : évite le décalage de mise en page au
41
+ chargement de la police et masque le clignotement du nom en clair (FOUT) tant que la police n'est
42
+ pas prête. `clip` + une petite marge tolèrent un léger débordement d'encre (polices tierces dont le
43
+ glyphe dépasse le cadratin) sans rogner, tout en bridant le texte de repli. Bascule d'opt-out via
44
+ --kt-icon-overflow (ex. `visible`). Non appliqué au mode projeté (contenu de largeur libre). */
45
+ .kt-icon[data-icon] {
46
+ inline-size: 1em;
47
+ block-size: 1em;
48
+ overflow: hidden; /* Fallback pour WebView < 90 */
49
+ overflow: var(--kt-icon-overflow, clip);
50
+ overflow-clip-margin: 0.15em;
51
+ }
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktortu/aaa",
3
- "version": "0.9.8",
3
+ "version": "0.10.0",
4
4
  "description": "Bibliothèque de composants Angular headless + thémés par tokens CSS.",
5
5
  "keywords": [
6
6
  "angular",
@@ -85,6 +85,10 @@
85
85
  "types": "./types/ktortu-aaa-i18n.d.ts",
86
86
  "default": "./fesm2022/ktortu-aaa-i18n.mjs"
87
87
  },
88
+ "./icon": {
89
+ "types": "./types/ktortu-aaa-icon.d.ts",
90
+ "default": "./fesm2022/ktortu-aaa-icon.mjs"
91
+ },
88
92
  "./layout": {
89
93
  "types": "./types/ktortu-aaa-layout.d.ts",
90
94
  "default": "./fesm2022/ktortu-aaa-layout.mjs"
@@ -0,0 +1,7 @@
1
+ @layer kt-aaa.tokens, kt-aaa.base, kt-aaa.components;
2
+
3
+ /* Icône autonome (directive ktIcon) : apparence pure (aucun token dédié — cf. les bascules
4
+ --kt-icon-font / --kt-icon-font-weight / --kt-icon-size du socle). Nécessite le socle
5
+ (@ktortu/aaa/foundation.css) et le chargement d'une police d'icônes côté application.
6
+ @import '@ktortu/aaa/icon.css'; */
7
+ @import '../icon/icon.css';
package/styles/styles.css CHANGED
@@ -15,6 +15,7 @@
15
15
  importez aussi '@angular/cdk/overlay-prebuilt.css'. */
16
16
 
17
17
  @import './foundation.css';
18
+ @import './icon.css';
18
19
  @import './tabs.css';
19
20
  @import './forms.css';
20
21
  @import './button.css';
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { OnInit, OnDestroy, Provider } from '@angular/core';
2
+ import { OnInit, OnDestroy, InjectionToken, Provider } from '@angular/core';
3
3
  import { DialogConfig, DialogRef, CdkDialogContainer } from '@angular/cdk/dialog';
4
4
  import { ComponentType } from '@angular/cdk/portal';
5
5
  import * as _ktortu_aaa_dialog from '@ktortu/aaa/dialog';
@@ -105,6 +105,10 @@ declare class KtDialogClose {
105
105
  * aria-labelledby). En usage simple — titre nu sans header — [ktDialogTitle] conserve son propre
106
106
  * padding : ce header n'est à utiliser que pour les en-têtes composés (icône, close top-right…).
107
107
  *
108
+ * ⚠️ Ne rend RIEN par lui-même — pas de bouton de fermeture implicite : c'est vous qui posez la
109
+ * croix (cf. exemple). En présentation `sheet`, l'option `sheetCloseButton` en rend une
110
+ * automatiquement, hors flux ; les deux ensemble feraient doublon (le conteneur avertit en dev).
111
+ *
108
112
  * @example
109
113
  * ```html
110
114
  * <header ktDialogHeader>
@@ -163,7 +167,7 @@ declare class KtDialogFocusInitial {
163
167
  }
164
168
  /**
165
169
  * @deprecated ADR-0005 — la poignée est désormais RENDUE AUTOMATIQUEMENT par `KtDialogContainer`
166
- * en présentation `sheet` (opt-out : panelClass additionnel `kt-dialog--no-handle`), et le
170
+ * en présentation `sheet` (opt-out : option typée `sheetHandle: false`), et le
167
171
  * drag-to-dismiss s'attrape sur TOUTE la surface de la sheet (scroll-snap natif). Cette
168
172
  * directive est INERTE et son hôte est masqué (évite une double poignée) : retirez-la de vos
169
173
  * templates. Sera supprimée dans une prochaine version majeure.
@@ -207,6 +211,63 @@ declare const KT_DIALOG_AAA_DEFAULTS: DialogConfig;
207
211
  * @returns Un `Provider` pour le token `DEFAULT_DIALOG_CONFIG`.
208
212
  */
209
213
  declare function provideKtDialogDefaults(overrides?: Partial<DialogConfig>): Provider;
214
+ /**
215
+ * Options MAISON du dialog (≠ {@link KT_DIALOG_AAA_DEFAULTS}, qui porte la config du CDK).
216
+ * Conforme à l'ADR-0003 : un token `KT_*_CONFIG` par entry-point, défauts anglais neutres,
217
+ * cascade `option d'ouverture ?? token ?? défaut`.
218
+ *
219
+ * Toutes les clés actuelles ne concernent que la présentation `sheet` (préfixe `sheet*`) : sur les
220
+ * présentations `centered` / `fullscreen`, la place d'un bouton de fermeture est un
221
+ * `[ktDialogHeader]`, où on le POSE soi-même, dans le flux. Un usage hors sheet déclenche un
222
+ * avertissement en mode dev.
223
+ */
224
+ interface KtDialogConfig {
225
+ /**
226
+ * Bouton de fermeture AUTO-RENDU en haut de la carte, en présentation `sheet`.
227
+ *
228
+ * Désactivé par défaut, pour une raison de COMPATIBILITÉ, pas d'ergonomie : `[ktDialogHeader]`
229
+ * ne rend aucune croix (c'est une simple rangée flex), mais un dialog qui en compose un y place
230
+ * généralement la sienne à la main. Activer l'option par défaut ferait donc apparaître une
231
+ * DEUXIÈME croix chez ces consommateurs-là sans qu'ils aient rien changé.
232
+ *
233
+ * Recommandé sur toute sheet qui ne pose pas déjà son propre bouton de fermeture en tête.
234
+ * @default false
235
+ */
236
+ sheetCloseButton: boolean;
237
+ /** Nom accessible du bouton de fermeture auto-rendu (WCAG 4.1.2). @default 'Close' */
238
+ sheetCloseLabel: string;
239
+ /** Poignée décorative auto-rendue en présentation `sheet` (ADR-0005). @default true */
240
+ sheetHandle: boolean;
241
+ }
242
+ /**
243
+ * Défauts effectifs des options maison du dialog. Objet `Required` figé : c'est la SOURCE des
244
+ * valeurs de repli, lue à la fois par l'ouvreur (résolution) et par le conteneur (fusion
245
+ * idempotente), et énumérée par la garde de complétude i18n.
246
+ */
247
+ declare const DEFAULT_KT_DIALOG_CONFIG: Required<KtDialogConfig>;
248
+ /**
249
+ * Token des options maison du dialog. Deux usages, un seul chemin de résolution :
250
+ * - **application** : fourni via {@link provideKtDialog} (valeur partielle) ;
251
+ * - **par ouverture** : `injectKtDialogOpener` REFOURNIT ce même token, déjà RÉSOLU, dans
252
+ * l'injecteur du conteneur (canal `container.providers` du CDK). Le conteneur fusionne
253
+ * toujours par-dessus {@link DEFAULT_KT_DIALOG_CONFIG} : l'opération est idempotente sur une
254
+ * valeur déjà résolue, et reste correcte si le conteneur est monté sans passer par l'ouvreur.
255
+ */
256
+ declare const KT_DIALOG_CONFIG: InjectionToken<Partial<KtDialogConfig>>;
257
+ /**
258
+ * Enregistre les options maison du dialog pour l'application (ou un sous-arbre).
259
+ * Complémentaire de {@link provideKtDialogDefaults}, qui porte la config du CDK : les deux
260
+ * coexistent et ne se recouvrent pas.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * // app.config.ts — bouton de fermeture sur toutes les bottom-sheets
265
+ * providers: [provideKtDialog({ sheetCloseButton: true })];
266
+ * ```
267
+ * @param config Options partielles fusionnées par-dessus `DEFAULT_KT_DIALOG_CONFIG`.
268
+ * @returns Un `Provider` pour le token `KT_DIALOG_CONFIG`.
269
+ */
270
+ declare function provideKtDialog(config: Partial<KtDialogConfig>): Provider;
210
271
  /**
211
272
  * Présentation du dialog, CHOISIE EXPLICITEMENT PAR LE DÉVELOPPEUR à l'ouverture (option
212
273
  * `presentation` de `injectKtDialogOpener`). Aucune bascule CSS automatique : le dev décide.
@@ -236,8 +297,11 @@ type KtDialogPresentation = 'centered' | 'fullscreen' | 'sheet' | 'centered-full
236
297
  */
237
298
  declare function resolveKtDialogPanelClass(presentation?: KtDialogPresentation, compact?: boolean): string[];
238
299
 
239
- /** Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation`. */
240
- type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & {
300
+ /**
301
+ * Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation` et
302
+ * des options maison de {@link KtDialogConfig} (surcharge par ouverture de `KT_DIALOG_CONFIG`).
303
+ */
304
+ type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> & Partial<KtDialogConfig> & {
241
305
  /** Présentation du dialog (cf. `KtDialogPresentation`) — choisie par le dev. Résolue à CHAQUE
242
306
  ouverture : les variantes responsive lisent le signal d'écran compact. Défaut : `'centered'`.
243
307
  Combinée à un éventuel `panelClass` additionnel. */
@@ -343,6 +407,11 @@ declare class KtDialogContainer extends CdkDialogContainer {
343
407
  private readonly platformId;
344
408
  private readonly destroyRef;
345
409
  private readonly bodyScrollLock;
410
+ /** Options maison RÉSOLUES. `injectKtDialogOpener` refournit `KT_DIALOG_CONFIG` déjà résolu dans
411
+ l'injecteur du conteneur : la fusion ci-dessous est alors un no-op. Elle reste indispensable
412
+ quand le conteneur est monté sans l'ouvreur (`dialog.open` brut), où le token remonte à
413
+ l'application et n'est que partiel. Un seul chemin de code, idempotent. */
414
+ protected readonly ktConfig: Required<KtDialogConfig>;
346
415
  protected readonly isClosing: i0.WritableSignal<boolean>;
347
416
  /** Armé quand l'ouverture a dépassé 50px : un repos à ~0 est alors forcément le snap « fermé ». */
348
417
  private sheetArmed;
@@ -355,9 +424,25 @@ declare class KtDialogContainer extends CdkDialogContainer {
355
424
  renomme ce membre, on dégrade proprement vers `null` au lieu de casser le rendu du conteneur. */
356
425
  protected get ariaLabelledBy(): string | null;
357
426
  constructor();
427
+ /** Garde-fous dev sur la config maison : usage hors sheet, double bouton de fermeture, opt-out
428
+ déprécié de la poignée. On AVERTIT sans jamais corriger en silence — un masquage automatique
429
+ dépendrait de l'ordre de rendu du portail et serait indébogable. */
430
+ private warnOnConfigMisuse;
358
431
  protected isSheet(): boolean;
359
- /** Poignée décorative auto-rendue en présentation sheet. Opt-out : panelClass `kt-dialog--no-handle`. */
432
+ /** panelClass d'opt-out historique de la poignée repli DÉPRÉCIÉ, remplacé par `sheetHandle`. */
433
+ private hasLegacyNoHandleClass;
434
+ /** Poignée décorative auto-rendue en présentation sheet (ADR-0005). Opt-out : option `sheetHandle`
435
+ (le panelClass historique reste honoré, en déprécié). */
360
436
  protected showSheetHandle(): boolean;
437
+ /** Bouton de fermeture auto-rendu : opt-in `sheetCloseButton`, et UNIQUEMENT en présentation sheet
438
+ (ailleurs, la croix se pose à la main dans un `[ktDialogHeader]` — cf. `KtDialogConfig`). */
439
+ protected showSheetClose(): boolean;
440
+ /** Clic sur le bouton de fermeture auto-rendu. Ne consulte VOLONTAIREMENT pas `disableClose` :
441
+ contrairement au tap-extérieur et à Échap (fermetures « par inadvertance » que `disableClose`
442
+ protège), ce bouton est une sortie EXPLICITEMENT demandée par le dev via `sheetCloseButton` —
443
+ le combiner à `disableClose` est le patron « une seule sortie contrôlée ». Le drapeau
444
+ `isClosing` garde l'idempotence face à un geste de glissement simultané. */
445
+ protected onSheetCloseClick(): void;
361
446
  /** Tap sur le spacer (zone extérieure à la carte) = fermeture, façon backdrop. Le conteneur
362
447
  captant désormais le tactile (pointer-events auto, requis pour le drag iOS), le clic ne
363
448
  traverse plus vers le backdrop CDK : on porte donc ICI la fermeture au tap-extérieur, en
@@ -531,5 +616,5 @@ declare class KtQuickDialog {
531
616
  static ɵprov: i0.ɵɵInjectableDeclaration<KtQuickDialog>;
532
617
  }
533
618
 
534
- export { KT_DIALOG_AAA_DEFAULTS, KtAlertDialog, KtConfirmDialog, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, KtQuickDialog, defineKtDialog, injectAlertDialog, injectConfirmDialog, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
535
- export type { KtAlertData, KtAlertDialogVariant, KtAlertOptions, KtConfirmConfig, KtConfirmResult, KtDecideConfig, KtDialogColor, KtDialogContract, KtDialogOpenerConfig, KtDialogPresentation };
619
+ export { DEFAULT_KT_DIALOG_CONFIG, KT_DIALOG_AAA_DEFAULTS, KT_DIALOG_CONFIG, KtAlertDialog, KtConfirmDialog, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, KtQuickDialog, defineKtDialog, injectAlertDialog, injectConfirmDialog, injectKtDialogOpener, provideKtDialog, provideKtDialogDefaults, resolveKtDialogPanelClass };
620
+ export type { KtAlertData, KtAlertDialogVariant, KtAlertOptions, KtConfirmConfig, KtConfirmResult, KtDecideConfig, KtDialogColor, KtDialogConfig, KtDialogContract, KtDialogOpenerConfig, KtDialogPresentation };
@@ -547,9 +547,19 @@ declare class KtPasswordField extends KtBaseInputField<string> implements FormVa
547
547
  * Permet d'activer ou désactiver une option avec effet immédiat.
548
548
  * Intégré aux Signal Forms de l'application via FormValueControl.
549
549
  *
550
+ * Libellé : `label` (texte) par défaut ; un contenu projeté le remplace pour les rendus riches
551
+ * (image + texte, spans empilés…). `ariaLabel` porte alors le nom accessible si le contenu projeté
552
+ * n'a pas de texte (WCAG 4.1.2). Même règle que `kt-checkbox` / `kt-radio`.
553
+ *
550
554
  * @example
551
555
  * ```html
556
+ * <!-- Simple -->
552
557
  * <kt-switch label="Notifications par e-mail" [(value)]="emailNotif" />
558
+ *
559
+ * <!-- Contenu projeté (image + texte) -->
560
+ * <kt-switch [(value)]="emailNotif">
561
+ * <img ngSrc="/assets/mail.png" width="20" height="20" alt="" /> Notifications par e-mail
562
+ * </kt-switch>
553
563
  * ```
554
564
  */
555
565
  declare class KtSwitch implements FormValueControl<boolean> {
@@ -574,7 +584,7 @@ declare class KtSwitch implements FormValueControl<boolean> {
574
584
  readonly name: _angular_core.InputSignal<string>;
575
585
  /** id imposé (sélecteurs de test stables) ; sinon auto-généré, anti-collision. @default undefined */
576
586
  readonly id: _angular_core.InputSignal<string | undefined>;
577
- /** Texte du libellé associé à la bascule. @default undefined */
587
+ /** Texte du libellé (remplacé visuellement par un contenu projeté). @default undefined */
578
588
  readonly label: _angular_core.InputSignal<string | undefined>;
579
589
  /** Texte d'aide affiché sous la bascule (masqué quand une erreur s'affiche). @default undefined */
580
590
  readonly hint: _angular_core.InputSignal<string | undefined>;
@@ -585,6 +595,7 @@ declare class KtSwitch implements FormValueControl<boolean> {
585
595
  /** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
586
596
  readonly showAllErrors: _angular_core.InputSignalWithTransform<boolean, unknown>;
587
597
  private readonly switchBtn;
598
+ private readonly el;
588
599
  private readonly errorResolver;
589
600
  private readonly idGen;
590
601
  private readonly uid;
@@ -605,7 +616,7 @@ declare class KtSwitch implements FormValueControl<boolean> {
605
616
  protected toggle(): void;
606
617
  protected onSpacebar(event: Event): void;
607
618
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtSwitch, never>;
608
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtSwitch, "kt-switch", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "pending": { "alias": "pending"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "errorMatcher": { "alias": "errorMatcher"; "required": false; "isSignal": true; }; "showAllErrors": { "alias": "showAllErrors"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
619
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtSwitch, "kt-switch", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "pending": { "alias": "pending"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "errorMatcher": { "alias": "errorMatcher"; "required": false; "isSignal": true; }; "showAllErrors": { "alias": "showAllErrors"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, ["*"], true, never>;
609
620
  }
610
621
 
611
622
  /**
@@ -2,6 +2,7 @@ import { EnvironmentProviders } from '@angular/core';
2
2
  import { KtFieldConfig, KtSelectConfigOptions, KtChipsConfig } from '@ktortu/aaa/forms';
3
3
  import { KtSnackbarConfig } from '@ktortu/aaa/snackbar';
4
4
  import { KtTabsConfig } from '@ktortu/aaa/tabs';
5
+ import { KtDialogConfig } from '@ktortu/aaa/dialog';
5
6
 
6
7
  /**
7
8
  * Agrégat de TOUS les libellés traduisibles de la lib, groupés par famille de composants.
@@ -23,6 +24,8 @@ interface KtTranslations {
23
24
  snackbar?: Partial<KtSnackbarConfig>;
24
25
  /** Libellés de la pagination des onglets → {@link KT_TABS_CONFIG}. */
25
26
  tabs?: Partial<KtTabsConfig>;
27
+ /** Libellés du dialog (`sheetCloseLabel`) → {@link KT_DIALOG_CONFIG}. */
28
+ dialog?: Partial<KtDialogConfig>;
26
29
  }
27
30
  /**
28
31
  * Enregistre, en un seul appel, les libellés fournis sur les tokens de config de la lib.
@@ -0,0 +1,158 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { InjectionToken, Provider } from '@angular/core';
3
+
4
+ /**
5
+ * Définition d'une police d'icônes **à ligatures** enregistrée dans le registre (cf.
6
+ * {@link KtIconConfig}). Le registre ne charge AUCUNE police : il se contente d'associer un alias
7
+ * court à la famille CSS réelle (à vous de charger le fichier de police, façon « apportez la vôtre »).
8
+ */
9
+ interface KtIconFont {
10
+ /** Famille de police CSS réelle (ex. `'Material Symbols Rounded'`). Valeur `font-family` brute :
11
+ si elle commence par un chiffre ou contient des caractères spéciaux, la citer vous-même. */
12
+ family: string;
13
+ /** Graisse par défaut de cette police (ex. `300` ou `'normal'`). @default hérité de `--kt-icon-font-weight` */
14
+ weight?: string | number;
15
+ /** `font-variation-settings` par défaut (polices variables, ex. `"'FILL' 0, 'wght' 300"`). @default `normal` */
16
+ variationSettings?: string;
17
+ }
18
+ /**
19
+ * Défauts applicables à toutes les icônes `[ktIcon]` (registre de polices + police par défaut),
20
+ * fournis via {@link provideKtIcon}. Fourni en `Partial` : on ne déclare que ce qu'on veut.
21
+ */
22
+ interface KtIconConfig {
23
+ /** Registre `alias → police`. L'alias est ensuite choisi sur la primitive via `[font]`. */
24
+ fonts: Record<string, KtIconFont>;
25
+ /** Alias utilisé quand aucune police n'est précisée sur la primitive (`[font]` absent). */
26
+ defaultFont: string;
27
+ }
28
+ /**
29
+ * Interface d'**enregistrement des alias de POLICE** à augmenter côté application pour typer l'input
30
+ * `[font]` et obtenir son **autocomplétion** dans les templates. Vide par défaut : sans augmentation,
31
+ * `[font]` accepte n'importe quelle chaîne (dégradation gracieuse, zéro config).
32
+ *
33
+ * Nommée `KtIconFontRegistry` (et non `KtIconRegistry`) à dessein : le nom générique reste réservé à
34
+ * un futur registre de **noms d'icônes** (SVG), qui bénéficiera du même mécanisme.
35
+ *
36
+ * @example Recette à source unique (le même objet type ET fournit le registre) :
37
+ * ```ts
38
+ * // app-icons.ts
39
+ * export const APP_ICON_FONTS = {
40
+ * material: { family: 'Material Symbols Outlined' },
41
+ * rounded: { family: 'Material Symbols Rounded', variationSettings: "'FILL' 0, 'wght' 300" },
42
+ * } as const;
43
+ *
44
+ * declare module '@ktortu/aaa/icon' {
45
+ * // Injecte les clés de APP_ICON_FONTS comme alias connus → autocomplétion de [font].
46
+ * // eslint-disable-next-line @typescript-eslint/no-empty-object-type
47
+ * interface KtIconFontRegistry extends Record<keyof typeof APP_ICON_FONTS, unknown> {}
48
+ * }
49
+ *
50
+ * // app.config.ts
51
+ * providers: [provideKtIcon({ fonts: APP_ICON_FONTS, defaultFont: 'material' })];
52
+ * ```
53
+ */
54
+ interface KtIconFontRegistry {
55
+ }
56
+ /**
57
+ * Alias de police connus : l'union des clés de {@link KtIconFontRegistry} une fois augmentée, sinon
58
+ * `string` (registre vide → chaîne libre). Le tuple `[…] extends […]` évite la distribution du
59
+ * conditionnel sur l'union.
60
+ */
61
+ type KtIconFontAlias = [keyof KtIconFontRegistry] extends [never] ? string : keyof KtIconFontRegistry;
62
+ declare const KT_ICON_CONFIG: InjectionToken<Partial<KtIconConfig>>;
63
+ /**
64
+ * Fournit un registre de polices d'icônes (alias → famille) et l'alias par défaut, pour un
65
+ * sous-arbre ou l'application entière. Combiné à l'augmentation de {@link KtIconFontRegistry}, il
66
+ * offre l'autocomplétion typée de l'input `[font]`.
67
+ *
68
+ * `defaultFont` est **contraint aux clés de `fonts`** passées dans le même appel : un typo devient
69
+ * une erreur de compilation (pas de repli silencieux de toutes les icônes sur la police globale).
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * providers: [
74
+ * provideKtIcon({
75
+ * fonts: {
76
+ * material: { family: 'Material Symbols Outlined' },
77
+ * rounded: { family: 'Material Symbols Rounded' },
78
+ * },
79
+ * defaultFont: 'material', // 'rouded' → erreur TS
80
+ * }),
81
+ * ];
82
+ * ```
83
+ */
84
+ declare function provideKtIcon<F extends Record<string, KtIconFont>>(config: {
85
+ fonts?: F;
86
+ defaultFont?: keyof F & string;
87
+ }): Provider;
88
+ /**
89
+ * Primitive d'icône **autonome** : pose une icône seule (en-tête, item de liste, badge d'état…),
90
+ * là où le bouton et les champs ne suffisent pas. Directive présentationnelle — **jamais focusable
91
+ * ni cliquable** (pour une icône cliquable, utilisez `ktButton iconOnly`).
92
+ *
93
+ * Sélecteur d'attribut `[ktIcon]` (camelCase) ; l'hôte reçoit la classe stable `.kt-icon` (cible du
94
+ * style et du harness). Ne pas confondre avec le slot de projection `[kt-icon]` (kebab) de
95
+ * `kt-nav-item`, qui est un autre mécanisme.
96
+ *
97
+ * Deux régimes, comme dans le reste de la lib :
98
+ * - **Ligature** (`[ktIcon]="nom"`) : le nom devient un glyphe via une police d'icônes à ligatures
99
+ * (défaut `--kt-icon-font` → Material Symbols Outlined). Choisissez une autre police enregistrée
100
+ * via `[font]`.
101
+ * - **Projection** (set à classes, ex. Font Awesome, ou SVG en ligne) : laissez `ktIcon` vide et
102
+ * projetez votre markup dans l'élément ; la primitive ne fait que l'habiller (taille, couleur
103
+ * héritée, alignement). Le contenu projeté **ne doit jamais être focusable** (l'hôte décoratif
104
+ * porte `aria-hidden` : un descendant focusable violerait WCAG 4.1.2).
105
+ *
106
+ * Accessibilité : **décorative par défaut** (`aria-hidden`). Fournissez `[ariaLabel]` (ou un
107
+ * `aria-label` natif) pour une icône **porteuse de sens** (bascule en `role="img"`).
108
+ *
109
+ * @example
110
+ * ```html
111
+ * <!-- Ligature autonome, taille et couleur héritées du contexte ; `fill` = version remplie -->
112
+ * <span ktIcon="home"></span>
113
+ * <span ktIcon="favorite" fill size="2rem" style="color: var(--kt-primary)"></span>
114
+ *
115
+ * <!-- Set à classes (Font Awesome) : projection, ktIcon reste vide -->
116
+ * <span ktIcon><i class="fa-solid fa-user"></i></span>
117
+ *
118
+ * <!-- Icône porteuse de sens (nommée pour les lecteurs d'écran) -->
119
+ * <span ktIcon="error" ariaLabel="Erreur" style="color: var(--kt-danger)"></span>
120
+ * ```
121
+ */
122
+ declare class KtIcon {
123
+ private readonly config;
124
+ private readonly auditEnabled;
125
+ private readonly platformId;
126
+ private readonly host;
127
+ private readonly nativeAriaLabel;
128
+ /** Nom de l'icône (ligature). Laisser vide pour projeter un set à classes / un SVG. @default '' */
129
+ readonly ktIcon: _angular_core.InputSignal<string>;
130
+ /** Alias de police d'icônes du registre (cf. {@link provideKtIcon}). @default `KtIconConfig.defaultFont` */
131
+ readonly font: _angular_core.InputSignal<string | undefined>;
132
+ /** Nom accessible : le fournir rend l'icône **porteuse de sens** (`role="img"`). Aligné sur `ktButton`.
133
+ @default undefined (icône décorative ; un `aria-label` natif reste toutefois préservé) */
134
+ readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
135
+ /** Taille de l'icône (longueur CSS, ex. `'24px'`, `'2rem'`, `'1.5em'`). @default `1.25em` (héritée du contexte) */
136
+ readonly size: _angular_core.InputSignal<string | undefined>;
137
+ /** Version **remplie** plutôt que contour, pour les polices variables à axe `FILL` (Material Symbols).
138
+ Force `FILL` à 1 en préservant les autres axes (graisse…) ; sans effet sur une police sans cet axe.
139
+ Nécessite une police chargée **avec l'axe FILL ajustable** (ex. Google Fonts :
140
+ `…Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200`).
141
+ @default false (contour) */
142
+ readonly fill: _angular_core.InputSignalWithTransform<boolean, unknown>;
143
+ /** Nom rendu en ligature : coupé, `null` si vide (aucun `::before`, laisse place à la projection). */
144
+ protected readonly renderedName: _angular_core.Signal<string | null>;
145
+ /** Libellé accessible résolu : input prioritaire, sinon `aria-label` natif préservé, sinon `null` (décorative). */
146
+ protected readonly accessibleLabel: _angular_core.Signal<string | null>;
147
+ /** Police résolue depuis le registre : alias explicite, sinon police par défaut du provider. */
148
+ private readonly resolvedFont;
149
+ protected readonly resolvedFamily: _angular_core.Signal<string | null>;
150
+ protected readonly resolvedWeight: _angular_core.Signal<string | null>;
151
+ protected readonly resolvedVariation: _angular_core.Signal<string | null>;
152
+ constructor();
153
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtIcon, never>;
154
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KtIcon, "[ktIcon]", never, { "ktIcon": { "alias": "ktIcon"; "required": false; "isSignal": true; }; "font": { "alias": "font"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fill": { "alias": "fill"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
155
+ }
156
+
157
+ export { KT_ICON_CONFIG, KtIcon, provideKtIcon };
158
+ export type { KtIconConfig, KtIconFont, KtIconFontAlias, KtIconFontRegistry };
@@ -77,11 +77,21 @@ declare class KtToolbarComponent {
77
77
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtToolbarComponent, "kt-toolbar", never, {}, {}, never, ["*"], true, never>;
78
78
  }
79
79
 
80
+ /**
81
+ * Item de navigation : projette une icône dans son slot dédié + un libellé.
82
+ *
83
+ * Le slot d'icône accepte :
84
+ * - la directive `[ktIcon]` (primitive d'icône `@ktortu/aaa/icon`), forme canonique.
85
+ * - l'attribut de projection `kt-icon` (historique/legacy).
86
+ *
87
+ * Note : la classe `.kt-icon` (posée à l'exécution par la directive) n'est PAS un critère de
88
+ * projection valable (ng-content matche la forme statique du template) — d'où le sélecteur d'attribut.
89
+ */
80
90
  declare class KtNavItemComponent {
81
91
  label: _angular_core.InputSignal<string>;
82
92
  protected readonly layout: KtLayoutService;
83
93
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtNavItemComponent, never>;
84
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtNavItemComponent, "kt-nav-item", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; }, {}, never, ["[kt-icon]", "*"], true, never>;
94
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtNavItemComponent, "kt-nav-item", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; }, {}, never, ["[ktIcon], [kt-icon]", "*"], true, never>;
85
95
  }
86
96
 
87
97
  /**
@@ -75,6 +75,22 @@ declare class KtTooltip implements OnDestroy {
75
75
  ngOnDestroy(): void;
76
76
  protected show(): void;
77
77
  protected hide(): void;
78
+ /**
79
+ * Fermeture immédiate à l'activation de la cible (clic souris, tap tactile, stylet).
80
+ * Dès que l'utilisateur AGIT sur l'élément (typiquement un bouton qui ouvre une bottom sheet ou un
81
+ * dialog), l'infobulle a fini son rôle : on la ferme sans attendre le hideDelay, et on purge un
82
+ * affichage en attente pour qu'il ne surgisse pas après coup.
83
+ *
84
+ * Sans ce déclencheur, une infobulle affichée au survol SURVIVAIT à l'ouverture d'un overlay : le
85
+ * pointeur reste sur la cible (aucun `mouseleave`) et un clic ne défocalise pas toujours (aucun
86
+ * `focusout` fiable, ex. Safari/Firefox macOS). Comme l'infobulle est un popover en top layer, elle
87
+ * flottait alors AU-DESSUS de l'overlay (lui empilé au z-index) — impossible à masquer autrement.
88
+ *
89
+ * `pointerdown` (et non `click`) car il précède l'ouverture de l'overlay et le déplacement de focus
90
+ * → zéro flash. On ne fait ni preventDefault ni stopPropagation : l'action native (clic) doit suivre
91
+ * son cours. Le cas clavier (Entrée/Espace) reste couvert par `focusout` quand l'overlay prend le focus.
92
+ */
93
+ protected onActivate(): void;
78
94
  protected onEscape(event: Event): void;
79
95
  private dismiss;
80
96
  private ensureTip;
@@ -5,6 +5,7 @@ export * from '@ktortu/aaa/dialog';
5
5
  export * from '@ktortu/aaa/disclosure';
6
6
  export * from '@ktortu/aaa/forms';
7
7
  export * from '@ktortu/aaa/i18n';
8
+ export * from '@ktortu/aaa/icon';
8
9
  export * from '@ktortu/aaa/menu';
9
10
  export * from '@ktortu/aaa/snackbar';
10
11
  export * from '@ktortu/aaa/tabs';