@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.
- package/README.md +40 -3
- package/dialog/dialog.css +85 -0
- package/fesm2022/ktortu-aaa-dialog.mjs +172 -13
- package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-forms.mjs +34 -23
- package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-i18n.mjs +7 -0
- package/fesm2022/ktortu-aaa-i18n.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-icon.mjs +174 -0
- package/fesm2022/ktortu-aaa-icon.mjs.map +1 -0
- package/fesm2022/ktortu-aaa-layout.mjs +12 -2
- package/fesm2022/ktortu-aaa-layout.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs +21 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
- package/fesm2022/ktortu-aaa.mjs +1 -0
- package/fesm2022/ktortu-aaa.mjs.map +1 -1
- package/forms/styles/field-box.css +11 -1
- package/forms/styles/tokens.css +5 -0
- package/forms/switch/switch.css +6 -0
- package/icon/icon.css +52 -0
- package/package.json +5 -1
- package/styles/icon.css +7 -0
- package/styles/styles.css +1 -0
- package/types/ktortu-aaa-dialog.d.ts +92 -7
- package/types/ktortu-aaa-forms.d.ts +13 -2
- package/types/ktortu-aaa-i18n.d.ts +3 -0
- package/types/ktortu-aaa-icon.d.ts +158 -0
- package/types/ktortu-aaa-layout.d.ts +11 -1
- package/types/ktortu-aaa-tooltip.d.ts +16 -0
- package/types/ktortu-aaa.d.ts +1 -0
|
@@ -2,6 +2,7 @@ import { makeEnvironmentProviders } from '@angular/core';
|
|
|
2
2
|
import { KT_FIELD_CONFIG, KT_SELECT_CONFIG, KT_CHIPS_CONFIG, ktErrorParam } from '@ktortu/aaa/forms';
|
|
3
3
|
import { KT_SNACKBAR_CONFIG } from '@ktortu/aaa/snackbar';
|
|
4
4
|
import { KT_TABS_CONFIG } from '@ktortu/aaa/tabs';
|
|
5
|
+
import { KT_DIALOG_CONFIG } from '@ktortu/aaa/dialog';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Enregistre, en un seul appel, les libellés fournis sur les tokens de config de la lib.
|
|
@@ -29,6 +30,8 @@ function provideKtTranslations(t) {
|
|
|
29
30
|
providers.push({ provide: KT_SNACKBAR_CONFIG, useValue: t.snackbar });
|
|
30
31
|
if (t.tabs)
|
|
31
32
|
providers.push({ provide: KT_TABS_CONFIG, useValue: t.tabs });
|
|
33
|
+
if (t.dialog)
|
|
34
|
+
providers.push({ provide: KT_DIALOG_CONFIG, useValue: t.dialog });
|
|
32
35
|
return makeEnvironmentProviders(providers);
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
@@ -52,6 +55,7 @@ function mergeKtTranslations(base, over) {
|
|
|
52
55
|
chips: { ...base.chips, ...over.chips },
|
|
53
56
|
snackbar: { ...base.snackbar, ...over.snackbar },
|
|
54
57
|
tabs: { ...base.tabs, ...over.tabs },
|
|
58
|
+
dialog: { ...base.dialog, ...over.dialog },
|
|
55
59
|
};
|
|
56
60
|
}
|
|
57
61
|
|
|
@@ -109,6 +113,9 @@ const KT_FR_TRANSLATIONS = {
|
|
|
109
113
|
previousLabel: 'Onglets précédents',
|
|
110
114
|
nextLabel: 'Onglets suivants',
|
|
111
115
|
},
|
|
116
|
+
dialog: {
|
|
117
|
+
sheetCloseLabel: 'Fermer',
|
|
118
|
+
},
|
|
112
119
|
};
|
|
113
120
|
/**
|
|
114
121
|
* Enregistre les libellés **français** par défaut sur toute la lib, en un seul appel.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktortu-aaa-i18n.mjs","sources":["../../../../projects/ktortu/aaa/i18n/translations.ts","../../../../projects/ktortu/aaa/i18n/fr.ts","../../../../projects/ktortu/aaa/i18n/ktortu-aaa-i18n.ts"],"sourcesContent":["import { EnvironmentProviders, Provider, makeEnvironmentProviders } from '@angular/core';\n\nimport { KT_FIELD_CONFIG, KT_CHIPS_CONFIG, KT_SELECT_CONFIG } from '@ktortu/aaa/forms';\nimport type { KtFieldConfig, KtChipsConfig, KtSelectConfigOptions } from '@ktortu/aaa/forms';\nimport { KT_SNACKBAR_CONFIG } from '@ktortu/aaa/snackbar';\nimport type { KtSnackbarConfig } from '@ktortu/aaa/snackbar';\nimport { KT_TABS_CONFIG } from '@ktortu/aaa/tabs';\nimport type { KtTabsConfig } from '@ktortu/aaa/tabs';\n\n/**\n * Agrégat de TOUS les libellés traduisibles de la lib, groupés par famille de composants.\n * Chaque clé reprend la config du token correspondant (`Partial` : tout est optionnel — on ne\n * fournit que ce qu'on veut traduire). C'est l'« interface de traduction » unique de la lib :\n * un point d'entrée pour brancher une langue d'un coup.\n *\n * @see provideKtTranslations pour enregistrer un jeu de libellés.\n * @see provideKtDefaultFR pour partir des libellés français.\n */\nexport interface KtTranslations {\n /** Libellés des champs (`clearLabel`, `helpLabel`) → {@link KT_FIELD_CONFIG}. */\n field?: Partial<KtFieldConfig>;\n /** Libellés des selects / multi-selects → {@link KT_SELECT_CONFIG}. */\n select?: Partial<KtSelectConfigOptions>;\n /** Libellés des listes de chips → {@link KT_CHIPS_CONFIG}. */\n chips?: Partial<KtChipsConfig>;\n /** Libellés de la snackbar (`closeLabel`) → {@link KT_SNACKBAR_CONFIG}. */\n snackbar?: Partial<KtSnackbarConfig>;\n /** Libellés de la pagination des onglets → {@link KT_TABS_CONFIG}. */\n tabs?: Partial<KtTabsConfig>;\n}\n\n/**\n * Enregistre, en un seul appel, les libellés fournis sur les tokens de config de la lib.\n * Base = défauts anglais de chaque composant ; seules les familles **présentes** dans `t` sont\n * fournies (les autres gardent leur défaut anglais et restent surchargeables ailleurs).\n *\n * À placer dans les `providers` de `app.config.ts` (ou de tout injecteur).\n *\n * @param t Libellés à fournir, groupés par famille ; seules les familles présentes sont enregistrées.\n * @returns Les `EnvironmentProviders` liant chaque famille présente à son token de config.\n * @example\n * ```ts\n * provideKtTranslations({ tabs: { nextLabel: 'Suivant', previousLabel: 'Précédent' } })\n * ```\n */\nexport function provideKtTranslations(t: KtTranslations): EnvironmentProviders {\n const providers: Provider[] = [];\n if (t.field) providers.push({ provide: KT_FIELD_CONFIG, useValue: t.field });\n if (t.select) providers.push({ provide: KT_SELECT_CONFIG, useValue: t.select });\n if (t.chips) providers.push({ provide: KT_CHIPS_CONFIG, useValue: t.chips });\n if (t.snackbar) providers.push({ provide: KT_SNACKBAR_CONFIG, useValue: t.snackbar });\n if (t.tabs) providers.push({ provide: KT_TABS_CONFIG, useValue: t.tabs });\n return makeEnvironmentProviders(providers);\n}\n\n/**\n * Fusion par famille de deux {@link KtTranslations} : `over` écrase `base`, clé par clé.\n * @param base Libellés de référence (ex. un dictionnaire de langue complet).\n * @param over Libellés prioritaires venant écraser `base`.\n * @returns Un nouveau {@link KtTranslations} fusionné, famille par famille.\n * @example mergeKtTranslations(KT_FR_TRANSLATIONS, { tabs: { nextLabel: 'Suivant' } })\n */\nexport function mergeKtTranslations(base: KtTranslations, over: KtTranslations): KtTranslations {\n return {\n // `errorMessages` est lui-même une map par `kind` : fusion PROFONDE pour qu'un override ponctuel\n // (ex. `provideKtDefaultFR({ field: { errorMessages: { required: '…' } } })`) ne fasse pas tomber\n // les autres messages de la langue de base.\n field: {\n ...base.field,\n ...over.field,\n errorMessages: { ...base.field?.errorMessages, ...over.field?.errorMessages },\n },\n select: { ...base.select, ...over.select },\n chips: { ...base.chips, ...over.chips },\n snackbar: { ...base.snackbar, ...over.snackbar },\n tabs: { ...base.tabs, ...over.tabs },\n };\n}\n","import { EnvironmentProviders } from '@angular/core';\n\nimport { ktErrorParam } from '@ktortu/aaa/forms';\nimport { KtTranslations, mergeKtTranslations, provideKtTranslations } from './translations';\n\n/**\n * Dictionnaire **français** complet de tous les libellés de la lib. Figé et réutilisable :\n * importable tel quel (ex. pour le composer avec d'autres réglages) ou via {@link provideKtDefaultFR}.\n * Les libellés à pluriels sont des fonctions, pour laisser la grammaire au consommateur.\n */\nexport const KT_FR_TRANSLATIONS: KtTranslations = {\n field: {\n clearLabel: 'Effacer',\n helpLabel: 'Aide',\n numberParseError: 'La valeur saisie doit être un nombre valide.',\n errorMessages: {\n required: 'Ce champ est requis.',\n email: 'Saisissez une adresse e-mail valide.',\n min: (e) => `Saisissez une valeur supérieure ou égale à ${ktErrorParam<number>(e, 'min')}.`,\n max: (e) => `Saisissez une valeur inférieure ou égale à ${ktErrorParam<number>(e, 'max')}.`,\n minLength: (e) => `Saisissez au moins ${ktErrorParam<number>(e, 'minLength')} caractères.`,\n maxLength: (e) => `Saisissez au plus ${ktErrorParam<number>(e, 'maxLength')} caractères.`,\n minDate: (e) => `Choisissez une date à partir du ${ktErrorParam<Date>(e, 'minDate').toLocaleDateString('fr')}.`,\n maxDate: (e) => `Choisissez une date jusqu'au ${ktErrorParam<Date>(e, 'maxDate').toLocaleDateString('fr')}.`,\n pattern: 'Le format saisi est invalide.',\n },\n },\n select: {\n emptyText: 'Aucune option',\n closeLabel: 'Fermer',\n filterLabel: 'Filtrer les options',\n // En français, 0 ET 1 prennent le singulier (≠ anglais où seul 1 est singulier).\n filterResultsText: (count) => (count <= 1 ? `${count} résultat` : `${count} résultats`),\n removeItemLabel: (itemLabel) => `Retirer ${itemLabel}`,\n selectedItemsLabel: (fieldLabel) =>\n fieldLabel ? `Éléments sélectionnés pour ${fieldLabel}` : 'Éléments sélectionnés',\n selectionSummaryText: (count) => (count <= 1 ? `${count} élément sélectionné` : `${count} éléments sélectionnés`),\n itemRemovedText: (itemLabel) => `${itemLabel} retiré`,\n selectionCountText: (count) => (count <= 1 ? `${count} sélectionné` : `${count} sélectionnés`),\n selectAllLabel: 'Tout sélectionner',\n clearAllLabel: 'Tout effacer',\n moreChipsLabel: (hiddenCount) => `+${hiddenCount} de plus`,\n lessChipsLabel: 'Afficher moins',\n truncatedResultsText: (max, total) =>\n `Affichage des ${max} premiers résultats sur ${total}. Affinez votre recherche pour en voir plus.`,\n truncatedResultsAnnouncement: (max, total) =>\n `${max} résultats affichés sur ${total}. Affinez votre recherche pour en voir plus.`,\n },\n chips: {\n removeItemLabel: (itemLabel) => `Retirer ${itemLabel}`,\n itemRemovedText: (itemLabel) => `${itemLabel} retiré`,\n moreLabel: (hiddenCount) => `+${hiddenCount} de plus`,\n lessLabel: 'Afficher moins',\n listLabel: 'Éléments sélectionnés',\n },\n snackbar: {\n closeLabel: 'Fermer',\n },\n tabs: {\n previousLabel: 'Onglets précédents',\n nextLabel: 'Onglets suivants',\n },\n};\n\n/**\n * Enregistre les libellés **français** par défaut sur toute la lib, en un seul appel.\n * `overrides` permet d'ajuster ponctuellement sans tout réécrire (fusion par famille,\n * cf. {@link mergeKtTranslations}). À placer dans les `providers` de `app.config.ts`.\n *\n * @param overrides Libellés à ajuster par-dessus le français (fusion par famille). Défaut : `{}`.\n * @returns Les `EnvironmentProviders` enregistrant le français (fusionné aux `overrides`).\n * @example\n * ```ts\n * // app.config.ts\n * providers: [\n * provideKtDefaultFR(), // tout en français\n * // ou en ajustant un libellé précis :\n * provideKtDefaultFR({ tabs: { nextLabel: 'Suivant' } }),\n * ]\n * ```\n */\nexport function provideKtDefaultFR(overrides: KtTranslations = {}): EnvironmentProviders {\n return provideKtTranslations(mergeKtTranslations(KT_FR_TRANSLATIONS, overrides));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ktortu-aaa-i18n.mjs","sources":["../../../../projects/ktortu/aaa/i18n/translations.ts","../../../../projects/ktortu/aaa/i18n/fr.ts","../../../../projects/ktortu/aaa/i18n/ktortu-aaa-i18n.ts"],"sourcesContent":["import { EnvironmentProviders, Provider, makeEnvironmentProviders } from '@angular/core';\n\nimport { KT_FIELD_CONFIG, KT_CHIPS_CONFIG, KT_SELECT_CONFIG } from '@ktortu/aaa/forms';\nimport type { KtFieldConfig, KtChipsConfig, KtSelectConfigOptions } from '@ktortu/aaa/forms';\nimport { KT_SNACKBAR_CONFIG } from '@ktortu/aaa/snackbar';\nimport type { KtSnackbarConfig } from '@ktortu/aaa/snackbar';\nimport { KT_TABS_CONFIG } from '@ktortu/aaa/tabs';\nimport type { KtTabsConfig } from '@ktortu/aaa/tabs';\nimport { KT_DIALOG_CONFIG } from '@ktortu/aaa/dialog';\nimport type { KtDialogConfig } from '@ktortu/aaa/dialog';\n\n/**\n * Agrégat de TOUS les libellés traduisibles de la lib, groupés par famille de composants.\n * Chaque clé reprend la config du token correspondant (`Partial` : tout est optionnel — on ne\n * fournit que ce qu'on veut traduire). C'est l'« interface de traduction » unique de la lib :\n * un point d'entrée pour brancher une langue d'un coup.\n *\n * @see provideKtTranslations pour enregistrer un jeu de libellés.\n * @see provideKtDefaultFR pour partir des libellés français.\n */\nexport interface KtTranslations {\n /** Libellés des champs (`clearLabel`, `helpLabel`) → {@link KT_FIELD_CONFIG}. */\n field?: Partial<KtFieldConfig>;\n /** Libellés des selects / multi-selects → {@link KT_SELECT_CONFIG}. */\n select?: Partial<KtSelectConfigOptions>;\n /** Libellés des listes de chips → {@link KT_CHIPS_CONFIG}. */\n chips?: Partial<KtChipsConfig>;\n /** Libellés de la snackbar (`closeLabel`) → {@link KT_SNACKBAR_CONFIG}. */\n snackbar?: Partial<KtSnackbarConfig>;\n /** Libellés de la pagination des onglets → {@link KT_TABS_CONFIG}. */\n tabs?: Partial<KtTabsConfig>;\n /** Libellés du dialog (`sheetCloseLabel`) → {@link KT_DIALOG_CONFIG}. */\n dialog?: Partial<KtDialogConfig>;\n}\n\n/**\n * Enregistre, en un seul appel, les libellés fournis sur les tokens de config de la lib.\n * Base = défauts anglais de chaque composant ; seules les familles **présentes** dans `t` sont\n * fournies (les autres gardent leur défaut anglais et restent surchargeables ailleurs).\n *\n * À placer dans les `providers` de `app.config.ts` (ou de tout injecteur).\n *\n * @param t Libellés à fournir, groupés par famille ; seules les familles présentes sont enregistrées.\n * @returns Les `EnvironmentProviders` liant chaque famille présente à son token de config.\n * @example\n * ```ts\n * provideKtTranslations({ tabs: { nextLabel: 'Suivant', previousLabel: 'Précédent' } })\n * ```\n */\nexport function provideKtTranslations(t: KtTranslations): EnvironmentProviders {\n const providers: Provider[] = [];\n if (t.field) providers.push({ provide: KT_FIELD_CONFIG, useValue: t.field });\n if (t.select) providers.push({ provide: KT_SELECT_CONFIG, useValue: t.select });\n if (t.chips) providers.push({ provide: KT_CHIPS_CONFIG, useValue: t.chips });\n if (t.snackbar) providers.push({ provide: KT_SNACKBAR_CONFIG, useValue: t.snackbar });\n if (t.tabs) providers.push({ provide: KT_TABS_CONFIG, useValue: t.tabs });\n if (t.dialog) providers.push({ provide: KT_DIALOG_CONFIG, useValue: t.dialog });\n return makeEnvironmentProviders(providers);\n}\n\n/**\n * Fusion par famille de deux {@link KtTranslations} : `over` écrase `base`, clé par clé.\n * @param base Libellés de référence (ex. un dictionnaire de langue complet).\n * @param over Libellés prioritaires venant écraser `base`.\n * @returns Un nouveau {@link KtTranslations} fusionné, famille par famille.\n * @example mergeKtTranslations(KT_FR_TRANSLATIONS, { tabs: { nextLabel: 'Suivant' } })\n */\nexport function mergeKtTranslations(base: KtTranslations, over: KtTranslations): KtTranslations {\n return {\n // `errorMessages` est lui-même une map par `kind` : fusion PROFONDE pour qu'un override ponctuel\n // (ex. `provideKtDefaultFR({ field: { errorMessages: { required: '…' } } })`) ne fasse pas tomber\n // les autres messages de la langue de base.\n field: {\n ...base.field,\n ...over.field,\n errorMessages: { ...base.field?.errorMessages, ...over.field?.errorMessages },\n },\n select: { ...base.select, ...over.select },\n chips: { ...base.chips, ...over.chips },\n snackbar: { ...base.snackbar, ...over.snackbar },\n tabs: { ...base.tabs, ...over.tabs },\n dialog: { ...base.dialog, ...over.dialog },\n };\n}\n","import { EnvironmentProviders } from '@angular/core';\n\nimport { ktErrorParam } from '@ktortu/aaa/forms';\nimport { KtTranslations, mergeKtTranslations, provideKtTranslations } from './translations';\n\n/**\n * Dictionnaire **français** complet de tous les libellés de la lib. Figé et réutilisable :\n * importable tel quel (ex. pour le composer avec d'autres réglages) ou via {@link provideKtDefaultFR}.\n * Les libellés à pluriels sont des fonctions, pour laisser la grammaire au consommateur.\n */\nexport const KT_FR_TRANSLATIONS: KtTranslations = {\n field: {\n clearLabel: 'Effacer',\n helpLabel: 'Aide',\n numberParseError: 'La valeur saisie doit être un nombre valide.',\n errorMessages: {\n required: 'Ce champ est requis.',\n email: 'Saisissez une adresse e-mail valide.',\n min: (e) => `Saisissez une valeur supérieure ou égale à ${ktErrorParam<number>(e, 'min')}.`,\n max: (e) => `Saisissez une valeur inférieure ou égale à ${ktErrorParam<number>(e, 'max')}.`,\n minLength: (e) => `Saisissez au moins ${ktErrorParam<number>(e, 'minLength')} caractères.`,\n maxLength: (e) => `Saisissez au plus ${ktErrorParam<number>(e, 'maxLength')} caractères.`,\n minDate: (e) => `Choisissez une date à partir du ${ktErrorParam<Date>(e, 'minDate').toLocaleDateString('fr')}.`,\n maxDate: (e) => `Choisissez une date jusqu'au ${ktErrorParam<Date>(e, 'maxDate').toLocaleDateString('fr')}.`,\n pattern: 'Le format saisi est invalide.',\n },\n },\n select: {\n emptyText: 'Aucune option',\n closeLabel: 'Fermer',\n filterLabel: 'Filtrer les options',\n // En français, 0 ET 1 prennent le singulier (≠ anglais où seul 1 est singulier).\n filterResultsText: (count) => (count <= 1 ? `${count} résultat` : `${count} résultats`),\n removeItemLabel: (itemLabel) => `Retirer ${itemLabel}`,\n selectedItemsLabel: (fieldLabel) =>\n fieldLabel ? `Éléments sélectionnés pour ${fieldLabel}` : 'Éléments sélectionnés',\n selectionSummaryText: (count) => (count <= 1 ? `${count} élément sélectionné` : `${count} éléments sélectionnés`),\n itemRemovedText: (itemLabel) => `${itemLabel} retiré`,\n selectionCountText: (count) => (count <= 1 ? `${count} sélectionné` : `${count} sélectionnés`),\n selectAllLabel: 'Tout sélectionner',\n clearAllLabel: 'Tout effacer',\n moreChipsLabel: (hiddenCount) => `+${hiddenCount} de plus`,\n lessChipsLabel: 'Afficher moins',\n truncatedResultsText: (max, total) =>\n `Affichage des ${max} premiers résultats sur ${total}. Affinez votre recherche pour en voir plus.`,\n truncatedResultsAnnouncement: (max, total) =>\n `${max} résultats affichés sur ${total}. Affinez votre recherche pour en voir plus.`,\n },\n chips: {\n removeItemLabel: (itemLabel) => `Retirer ${itemLabel}`,\n itemRemovedText: (itemLabel) => `${itemLabel} retiré`,\n moreLabel: (hiddenCount) => `+${hiddenCount} de plus`,\n lessLabel: 'Afficher moins',\n listLabel: 'Éléments sélectionnés',\n },\n snackbar: {\n closeLabel: 'Fermer',\n },\n tabs: {\n previousLabel: 'Onglets précédents',\n nextLabel: 'Onglets suivants',\n },\n dialog: {\n sheetCloseLabel: 'Fermer',\n },\n};\n\n/**\n * Enregistre les libellés **français** par défaut sur toute la lib, en un seul appel.\n * `overrides` permet d'ajuster ponctuellement sans tout réécrire (fusion par famille,\n * cf. {@link mergeKtTranslations}). À placer dans les `providers` de `app.config.ts`.\n *\n * @param overrides Libellés à ajuster par-dessus le français (fusion par famille). Défaut : `{}`.\n * @returns Les `EnvironmentProviders` enregistrant le français (fusionné aux `overrides`).\n * @example\n * ```ts\n * // app.config.ts\n * providers: [\n * provideKtDefaultFR(), // tout en français\n * // ou en ajustant un libellé précis :\n * provideKtDefaultFR({ tabs: { nextLabel: 'Suivant' } }),\n * ]\n * ```\n */\nexport function provideKtDefaultFR(overrides: KtTranslations = {}): EnvironmentProviders {\n return provideKtTranslations(mergeKtTranslations(KT_FR_TRANSLATIONS, overrides));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, PLATFORM_ID, ElementRef, input, booleanAttribute, computed, effect, Directive } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { KT_AUDIT_ENABLED } from '@ktortu/aaa/cdk';
|
|
5
|
+
|
|
6
|
+
const KT_ICON_CONFIG = new InjectionToken('KT_ICON_CONFIG');
|
|
7
|
+
/**
|
|
8
|
+
* Fournit un registre de polices d'icônes (alias → famille) et l'alias par défaut, pour un
|
|
9
|
+
* sous-arbre ou l'application entière. Combiné à l'augmentation de {@link KtIconFontRegistry}, il
|
|
10
|
+
* offre l'autocomplétion typée de l'input `[font]`.
|
|
11
|
+
*
|
|
12
|
+
* `defaultFont` est **contraint aux clés de `fonts`** passées dans le même appel : un typo devient
|
|
13
|
+
* une erreur de compilation (pas de repli silencieux de toutes les icônes sur la police globale).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* providers: [
|
|
18
|
+
* provideKtIcon({
|
|
19
|
+
* fonts: {
|
|
20
|
+
* material: { family: 'Material Symbols Outlined' },
|
|
21
|
+
* rounded: { family: 'Material Symbols Rounded' },
|
|
22
|
+
* },
|
|
23
|
+
* defaultFont: 'material', // 'rouded' → erreur TS
|
|
24
|
+
* }),
|
|
25
|
+
* ];
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function provideKtIcon(config) {
|
|
29
|
+
return { provide: KT_ICON_CONFIG, useValue: config };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Primitive d'icône **autonome** : pose une icône seule (en-tête, item de liste, badge d'état…),
|
|
33
|
+
* là où le bouton et les champs ne suffisent pas. Directive présentationnelle — **jamais focusable
|
|
34
|
+
* ni cliquable** (pour une icône cliquable, utilisez `ktButton iconOnly`).
|
|
35
|
+
*
|
|
36
|
+
* Sélecteur d'attribut `[ktIcon]` (camelCase) ; l'hôte reçoit la classe stable `.kt-icon` (cible du
|
|
37
|
+
* style et du harness). Ne pas confondre avec le slot de projection `[kt-icon]` (kebab) de
|
|
38
|
+
* `kt-nav-item`, qui est un autre mécanisme.
|
|
39
|
+
*
|
|
40
|
+
* Deux régimes, comme dans le reste de la lib :
|
|
41
|
+
* - **Ligature** (`[ktIcon]="nom"`) : le nom devient un glyphe via une police d'icônes à ligatures
|
|
42
|
+
* (défaut `--kt-icon-font` → Material Symbols Outlined). Choisissez une autre police enregistrée
|
|
43
|
+
* via `[font]`.
|
|
44
|
+
* - **Projection** (set à classes, ex. Font Awesome, ou SVG en ligne) : laissez `ktIcon` vide et
|
|
45
|
+
* projetez votre markup dans l'élément ; la primitive ne fait que l'habiller (taille, couleur
|
|
46
|
+
* héritée, alignement). Le contenu projeté **ne doit jamais être focusable** (l'hôte décoratif
|
|
47
|
+
* porte `aria-hidden` : un descendant focusable violerait WCAG 4.1.2).
|
|
48
|
+
*
|
|
49
|
+
* Accessibilité : **décorative par défaut** (`aria-hidden`). Fournissez `[ariaLabel]` (ou un
|
|
50
|
+
* `aria-label` natif) pour une icône **porteuse de sens** (bascule en `role="img"`).
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```html
|
|
54
|
+
* <!-- Ligature autonome, taille et couleur héritées du contexte ; `fill` = version remplie -->
|
|
55
|
+
* <span ktIcon="home"></span>
|
|
56
|
+
* <span ktIcon="favorite" fill size="2rem" style="color: var(--kt-primary)"></span>
|
|
57
|
+
*
|
|
58
|
+
* <!-- Set à classes (Font Awesome) : projection, ktIcon reste vide -->
|
|
59
|
+
* <span ktIcon><i class="fa-solid fa-user"></i></span>
|
|
60
|
+
*
|
|
61
|
+
* <!-- Icône porteuse de sens (nommée pour les lecteurs d'écran) -->
|
|
62
|
+
* <span ktIcon="error" ariaLabel="Erreur" style="color: var(--kt-danger)"></span>
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
class KtIcon {
|
|
66
|
+
config = inject(KT_ICON_CONFIG, { optional: true });
|
|
67
|
+
auditEnabled = inject(KT_AUDIT_ENABLED);
|
|
68
|
+
platformId = inject(PLATFORM_ID);
|
|
69
|
+
host = inject(ElementRef).nativeElement;
|
|
70
|
+
// aria-label natif posé par le consommateur, capté à la construction (préservé si l'input est absent).
|
|
71
|
+
nativeAriaLabel = this.host.getAttribute('aria-label');
|
|
72
|
+
/** Nom de l'icône (ligature). Laisser vide pour projeter un set à classes / un SVG. @default '' */
|
|
73
|
+
ktIcon = input('', /* @ts-ignore */
|
|
74
|
+
...(ngDevMode ? [{ debugName: "ktIcon" }] : /* istanbul ignore next */ []));
|
|
75
|
+
/** Alias de police d'icônes du registre (cf. {@link provideKtIcon}). @default `KtIconConfig.defaultFont` */
|
|
76
|
+
font = input(/* @ts-ignore */
|
|
77
|
+
...(ngDevMode ? [undefined, { debugName: "font" }] : /* istanbul ignore next */ []));
|
|
78
|
+
/** Nom accessible : le fournir rend l'icône **porteuse de sens** (`role="img"`). Aligné sur `ktButton`.
|
|
79
|
+
@default undefined (icône décorative ; un `aria-label` natif reste toutefois préservé) */
|
|
80
|
+
ariaLabel = input(/* @ts-ignore */
|
|
81
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
82
|
+
/** Taille de l'icône (longueur CSS, ex. `'24px'`, `'2rem'`, `'1.5em'`). @default `1.25em` (héritée du contexte) */
|
|
83
|
+
size = input(/* @ts-ignore */
|
|
84
|
+
...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
|
|
85
|
+
/** Version **remplie** plutôt que contour, pour les polices variables à axe `FILL` (Material Symbols).
|
|
86
|
+
Force `FILL` à 1 en préservant les autres axes (graisse…) ; sans effet sur une police sans cet axe.
|
|
87
|
+
Nécessite une police chargée **avec l'axe FILL ajustable** (ex. Google Fonts :
|
|
88
|
+
`…Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200`).
|
|
89
|
+
@default false (contour) */
|
|
90
|
+
fill = input(false, { ...(ngDevMode ? { debugName: "fill" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
91
|
+
/** Nom rendu en ligature : coupé, `null` si vide (aucun `::before`, laisse place à la projection). */
|
|
92
|
+
renderedName = computed(() => this.ktIcon()?.trim() || null, /* @ts-ignore */
|
|
93
|
+
...(ngDevMode ? [{ debugName: "renderedName" }] : /* istanbul ignore next */ []));
|
|
94
|
+
/** Libellé accessible résolu : input prioritaire, sinon `aria-label` natif préservé, sinon `null` (décorative). */
|
|
95
|
+
accessibleLabel = computed(() => this.ariaLabel()?.trim() || this.nativeAriaLabel || null, /* @ts-ignore */
|
|
96
|
+
...(ngDevMode ? [{ debugName: "accessibleLabel" }] : /* istanbul ignore next */ []));
|
|
97
|
+
/** Police résolue depuis le registre : alias explicite, sinon police par défaut du provider. */
|
|
98
|
+
resolvedFont = computed(() => {
|
|
99
|
+
const alias = this.font() ?? this.config?.defaultFont;
|
|
100
|
+
if (!alias)
|
|
101
|
+
return undefined;
|
|
102
|
+
return this.config?.fonts?.[alias];
|
|
103
|
+
}, /* @ts-ignore */
|
|
104
|
+
...(ngDevMode ? [{ debugName: "resolvedFont" }] : /* istanbul ignore next */ []));
|
|
105
|
+
resolvedFamily = computed(() => this.resolvedFont()?.family ?? null, /* @ts-ignore */
|
|
106
|
+
...(ngDevMode ? [{ debugName: "resolvedFamily" }] : /* istanbul ignore next */ []));
|
|
107
|
+
resolvedWeight = computed(() => {
|
|
108
|
+
const weight = this.resolvedFont()?.weight;
|
|
109
|
+
return weight == null ? null : String(weight);
|
|
110
|
+
}, /* @ts-ignore */
|
|
111
|
+
...(ngDevMode ? [{ debugName: "resolvedWeight" }] : /* istanbul ignore next */ []));
|
|
112
|
+
resolvedVariation = computed(() => {
|
|
113
|
+
const base = this.resolvedFont()?.variationSettings ?? null;
|
|
114
|
+
if (!this.fill())
|
|
115
|
+
return base;
|
|
116
|
+
// Rempli : on force l'axe FILL à 1. En cas d'axe dupliqué, la DERNIÈRE valeur prime (spec CSS
|
|
117
|
+
// Fonts) → on préserve les autres axes de la police du registre (graisse, GRAD, opsz…).
|
|
118
|
+
// ADR [fill] cross-navigateur : la spec CSS Fonts module 4 stipule que si un axe est
|
|
119
|
+
// dupliqué dans font-variation-settings, la dernière déclaration l'emporte.
|
|
120
|
+
// Cela fonctionne parfaitement sur Chromium. WebKit/Firefox pourraient théoriquement avoir
|
|
121
|
+
// des bugs historiques (bien que non constatés), le risque est assumé (dégradation = contour).
|
|
122
|
+
return base ? `${base}, 'FILL' 1` : `'FILL' 1`;
|
|
123
|
+
}, /* @ts-ignore */
|
|
124
|
+
...(ngDevMode ? [{ debugName: "resolvedVariation" }] : /* istanbul ignore next */ []));
|
|
125
|
+
constructor() {
|
|
126
|
+
// Garde-fou dev : un alias absent du registre (input [font] OU defaultFont) retombe silencieusement
|
|
127
|
+
// sur --kt-icon-font. On résout l'alias effectif pour aussi couvrir un defaultFont mal orthographié.
|
|
128
|
+
effect(() => {
|
|
129
|
+
if (!this.auditEnabled || !isPlatformBrowser(this.platformId))
|
|
130
|
+
return;
|
|
131
|
+
const alias = this.font() ?? this.config?.defaultFont;
|
|
132
|
+
if (alias && !this.config?.fonts?.[alias]) {
|
|
133
|
+
console.warn(`[ktIcon] police "${String(alias)}" absente du registre : ` +
|
|
134
|
+
'enregistrez-la via provideKtIcon({ fonts }) — repli sur --kt-icon-font.');
|
|
135
|
+
}
|
|
136
|
+
// Garde-fou dev opt-in projection focusable
|
|
137
|
+
if (!this.accessibleLabel()) {
|
|
138
|
+
const focusable = this.host.querySelector('a[href],button,input,select,textarea,[tabindex]:not([tabindex="-1"]),[contenteditable="true"]');
|
|
139
|
+
if (focusable) {
|
|
140
|
+
console.warn('[ktIcon] (WCAG 4.1.2) : icône décorative (aria-hidden) avec un enfant projeté focusable. Ajoutez ariaLabel ou retirez le focus.');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
146
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtIcon, isStandalone: true, selector: "[ktIcon]", inputs: { ktIcon: { classPropertyName: "ktIcon", publicName: "ktIcon", isSignal: true, isRequired: false, transformFunction: null }, font: { classPropertyName: "font", publicName: "font", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-icon": "renderedName()", "style.--kt-icon-font": "resolvedFamily()", "style.--kt-icon-font-weight": "resolvedWeight()", "style.--kt-icon-font-variation": "resolvedVariation()", "style.--kt-icon-size": "size() || null", "attr.role": "accessibleLabel() ? \"img\" : null", "attr.aria-label": "accessibleLabel()", "attr.aria-hidden": "accessibleLabel() ? null : \"true\"" }, classAttribute: "kt-icon" }, ngImport: i0 });
|
|
147
|
+
}
|
|
148
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtIcon, decorators: [{
|
|
149
|
+
type: Directive,
|
|
150
|
+
args: [{
|
|
151
|
+
selector: '[ktIcon]',
|
|
152
|
+
host: {
|
|
153
|
+
// Marqueur stable posé quel que soit le mode d'usage (`ktIcon="x"` OU `[ktIcon]="x"`) : un binding
|
|
154
|
+
// de propriété ne reflète AUCUN attribut dans le DOM, donc le CSS/harness ne peuvent pas cibler
|
|
155
|
+
// `[ktIcon]`. La classe, elle, est toujours présente → cible du style et du harness.
|
|
156
|
+
class: 'kt-icon',
|
|
157
|
+
'[attr.data-icon]': 'renderedName()',
|
|
158
|
+
'[style.--kt-icon-font]': 'resolvedFamily()',
|
|
159
|
+
'[style.--kt-icon-font-weight]': 'resolvedWeight()',
|
|
160
|
+
'[style.--kt-icon-font-variation]': 'resolvedVariation()',
|
|
161
|
+
'[style.--kt-icon-size]': 'size() || null',
|
|
162
|
+
'[attr.role]': 'accessibleLabel() ? "img" : null',
|
|
163
|
+
'[attr.aria-label]': 'accessibleLabel()',
|
|
164
|
+
'[attr.aria-hidden]': 'accessibleLabel() ? null : "true"',
|
|
165
|
+
},
|
|
166
|
+
}]
|
|
167
|
+
}], ctorParameters: () => [], propDecorators: { ktIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "ktIcon", required: false }] }], font: [{ type: i0.Input, args: [{ isSignal: true, alias: "font", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fill: [{ type: i0.Input, args: [{ isSignal: true, alias: "fill", required: false }] }] } });
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generated bundle index. Do not edit.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
export { KT_ICON_CONFIG, KtIcon, provideKtIcon };
|
|
174
|
+
//# sourceMappingURL=ktortu-aaa-icon.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ktortu-aaa-icon.mjs","sources":["../../../../projects/ktortu/aaa/icon/icon.ts","../../../../projects/ktortu/aaa/icon/ktortu-aaa-icon.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n InjectionToken,\n PLATFORM_ID,\n Provider,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { KT_AUDIT_ENABLED } from '@ktortu/aaa/cdk';\n\n/**\n * Définition d'une police d'icônes **à ligatures** enregistrée dans le registre (cf.\n * {@link KtIconConfig}). Le registre ne charge AUCUNE police : il se contente d'associer un alias\n * court à la famille CSS réelle (à vous de charger le fichier de police, façon « apportez la vôtre »).\n */\nexport interface KtIconFont {\n /** Famille de police CSS réelle (ex. `'Material Symbols Rounded'`). Valeur `font-family` brute :\n si elle commence par un chiffre ou contient des caractères spéciaux, la citer vous-même. */\n family: string;\n /** Graisse par défaut de cette police (ex. `300` ou `'normal'`). @default hérité de `--kt-icon-font-weight` */\n weight?: string | number;\n /** `font-variation-settings` par défaut (polices variables, ex. `\"'FILL' 0, 'wght' 300\"`). @default `normal` */\n variationSettings?: string;\n}\n\n/**\n * Défauts applicables à toutes les icônes `[ktIcon]` (registre de polices + police par défaut),\n * fournis via {@link provideKtIcon}. Fourni en `Partial` : on ne déclare que ce qu'on veut.\n */\nexport interface KtIconConfig {\n /** Registre `alias → police`. L'alias est ensuite choisi sur la primitive via `[font]`. */\n fonts: Record<string, KtIconFont>;\n /** Alias utilisé quand aucune police n'est précisée sur la primitive (`[font]` absent). */\n defaultFont: string;\n}\n\n/**\n * Interface d'**enregistrement des alias de POLICE** à augmenter côté application pour typer l'input\n * `[font]` et obtenir son **autocomplétion** dans les templates. Vide par défaut : sans augmentation,\n * `[font]` accepte n'importe quelle chaîne (dégradation gracieuse, zéro config).\n *\n * Nommée `KtIconFontRegistry` (et non `KtIconRegistry`) à dessein : le nom générique reste réservé à\n * un futur registre de **noms d'icônes** (SVG), qui bénéficiera du même mécanisme.\n *\n * @example Recette à source unique (le même objet type ET fournit le registre) :\n * ```ts\n * // app-icons.ts\n * export const APP_ICON_FONTS = {\n * material: { family: 'Material Symbols Outlined' },\n * rounded: { family: 'Material Symbols Rounded', variationSettings: \"'FILL' 0, 'wght' 300\" },\n * } as const;\n *\n * declare module '@ktortu/aaa/icon' {\n * // Injecte les clés de APP_ICON_FONTS comme alias connus → autocomplétion de [font].\n * // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n * interface KtIconFontRegistry extends Record<keyof typeof APP_ICON_FONTS, unknown> {}\n * }\n *\n * // app.config.ts\n * providers: [provideKtIcon({ fonts: APP_ICON_FONTS, defaultFont: 'material' })];\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- point d'extension à augmenter côté app.\nexport interface KtIconFontRegistry {}\n\n/**\n * Alias de police connus : l'union des clés de {@link KtIconFontRegistry} une fois augmentée, sinon\n * `string` (registre vide → chaîne libre). Le tuple `[…] extends […]` évite la distribution du\n * conditionnel sur l'union.\n */\nexport type KtIconFontAlias = [keyof KtIconFontRegistry] extends [never] ? string : keyof KtIconFontRegistry;\n\nexport const KT_ICON_CONFIG = new InjectionToken<Partial<KtIconConfig>>('KT_ICON_CONFIG');\n\n/**\n * Fournit un registre de polices d'icônes (alias → famille) et l'alias par défaut, pour un\n * sous-arbre ou l'application entière. Combiné à l'augmentation de {@link KtIconFontRegistry}, il\n * offre l'autocomplétion typée de l'input `[font]`.\n *\n * `defaultFont` est **contraint aux clés de `fonts`** passées dans le même appel : un typo devient\n * une erreur de compilation (pas de repli silencieux de toutes les icônes sur la police globale).\n *\n * @example\n * ```ts\n * providers: [\n * provideKtIcon({\n * fonts: {\n * material: { family: 'Material Symbols Outlined' },\n * rounded: { family: 'Material Symbols Rounded' },\n * },\n * defaultFont: 'material', // 'rouded' → erreur TS\n * }),\n * ];\n * ```\n */\nexport function provideKtIcon<F extends Record<string, KtIconFont>>(config: {\n fonts?: F;\n defaultFont?: keyof F & string;\n}): Provider {\n return { provide: KT_ICON_CONFIG, useValue: config };\n}\n\n/**\n * Primitive d'icône **autonome** : pose une icône seule (en-tête, item de liste, badge d'état…),\n * là où le bouton et les champs ne suffisent pas. Directive présentationnelle — **jamais focusable\n * ni cliquable** (pour une icône cliquable, utilisez `ktButton iconOnly`).\n *\n * Sélecteur d'attribut `[ktIcon]` (camelCase) ; l'hôte reçoit la classe stable `.kt-icon` (cible du\n * style et du harness). Ne pas confondre avec le slot de projection `[kt-icon]` (kebab) de\n * `kt-nav-item`, qui est un autre mécanisme.\n *\n * Deux régimes, comme dans le reste de la lib :\n * - **Ligature** (`[ktIcon]=\"nom\"`) : le nom devient un glyphe via une police d'icônes à ligatures\n * (défaut `--kt-icon-font` → Material Symbols Outlined). Choisissez une autre police enregistrée\n * via `[font]`.\n * - **Projection** (set à classes, ex. Font Awesome, ou SVG en ligne) : laissez `ktIcon` vide et\n * projetez votre markup dans l'élément ; la primitive ne fait que l'habiller (taille, couleur\n * héritée, alignement). Le contenu projeté **ne doit jamais être focusable** (l'hôte décoratif\n * porte `aria-hidden` : un descendant focusable violerait WCAG 4.1.2).\n *\n * Accessibilité : **décorative par défaut** (`aria-hidden`). Fournissez `[ariaLabel]` (ou un\n * `aria-label` natif) pour une icône **porteuse de sens** (bascule en `role=\"img\"`).\n *\n * @example\n * ```html\n * <!-- Ligature autonome, taille et couleur héritées du contexte ; `fill` = version remplie -->\n * <span ktIcon=\"home\"></span>\n * <span ktIcon=\"favorite\" fill size=\"2rem\" style=\"color: var(--kt-primary)\"></span>\n *\n * <!-- Set à classes (Font Awesome) : projection, ktIcon reste vide -->\n * <span ktIcon><i class=\"fa-solid fa-user\"></i></span>\n *\n * <!-- Icône porteuse de sens (nommée pour les lecteurs d'écran) -->\n * <span ktIcon=\"error\" ariaLabel=\"Erreur\" style=\"color: var(--kt-danger)\"></span>\n * ```\n */\n@Directive({\n selector: '[ktIcon]',\n host: {\n // Marqueur stable posé quel que soit le mode d'usage (`ktIcon=\"x\"` OU `[ktIcon]=\"x\"`) : un binding\n // de propriété ne reflète AUCUN attribut dans le DOM, donc le CSS/harness ne peuvent pas cibler\n // `[ktIcon]`. La classe, elle, est toujours présente → cible du style et du harness.\n class: 'kt-icon',\n '[attr.data-icon]': 'renderedName()',\n '[style.--kt-icon-font]': 'resolvedFamily()',\n '[style.--kt-icon-font-weight]': 'resolvedWeight()',\n '[style.--kt-icon-font-variation]': 'resolvedVariation()',\n '[style.--kt-icon-size]': 'size() || null',\n '[attr.role]': 'accessibleLabel() ? \"img\" : null',\n '[attr.aria-label]': 'accessibleLabel()',\n '[attr.aria-hidden]': 'accessibleLabel() ? null : \"true\"',\n },\n})\nexport class KtIcon {\n private readonly config = inject(KT_ICON_CONFIG, { optional: true });\n private readonly auditEnabled = inject(KT_AUDIT_ENABLED);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n // aria-label natif posé par le consommateur, capté à la construction (préservé si l'input est absent).\n private readonly nativeAriaLabel = this.host.getAttribute('aria-label');\n\n /** Nom de l'icône (ligature). Laisser vide pour projeter un set à classes / un SVG. @default '' */\n readonly ktIcon = input<string>('');\n\n /** Alias de police d'icônes du registre (cf. {@link provideKtIcon}). @default `KtIconConfig.defaultFont` */\n readonly font = input<KtIconFontAlias>();\n\n /** Nom accessible : le fournir rend l'icône **porteuse de sens** (`role=\"img\"`). Aligné sur `ktButton`.\n @default undefined (icône décorative ; un `aria-label` natif reste toutefois préservé) */\n readonly ariaLabel = input<string>();\n\n /** Taille de l'icône (longueur CSS, ex. `'24px'`, `'2rem'`, `'1.5em'`). @default `1.25em` (héritée du contexte) */\n readonly size = input<string>();\n\n /** Version **remplie** plutôt que contour, pour les polices variables à axe `FILL` (Material Symbols).\n Force `FILL` à 1 en préservant les autres axes (graisse…) ; sans effet sur une police sans cet axe.\n Nécessite une police chargée **avec l'axe FILL ajustable** (ex. Google Fonts :\n `…Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200`).\n @default false (contour) */\n readonly fill = input<boolean, unknown>(false, { transform: booleanAttribute });\n\n /** Nom rendu en ligature : coupé, `null` si vide (aucun `::before`, laisse place à la projection). */\n protected readonly renderedName = computed(() => this.ktIcon()?.trim() || null);\n\n /** Libellé accessible résolu : input prioritaire, sinon `aria-label` natif préservé, sinon `null` (décorative). */\n protected readonly accessibleLabel = computed(() => this.ariaLabel()?.trim() || this.nativeAriaLabel || null);\n\n /** Police résolue depuis le registre : alias explicite, sinon police par défaut du provider. */\n private readonly resolvedFont = computed<KtIconFont | undefined>(() => {\n const alias = this.font() ?? this.config?.defaultFont;\n if (!alias) return undefined;\n return this.config?.fonts?.[alias as string];\n });\n\n protected readonly resolvedFamily = computed(() => this.resolvedFont()?.family ?? null);\n protected readonly resolvedWeight = computed(() => {\n const weight = this.resolvedFont()?.weight;\n return weight == null ? null : String(weight);\n });\n protected readonly resolvedVariation = computed(() => {\n const base = this.resolvedFont()?.variationSettings ?? null;\n if (!this.fill()) return base;\n // Rempli : on force l'axe FILL à 1. En cas d'axe dupliqué, la DERNIÈRE valeur prime (spec CSS\n // Fonts) → on préserve les autres axes de la police du registre (graisse, GRAD, opsz…).\n // ADR [fill] cross-navigateur : la spec CSS Fonts module 4 stipule que si un axe est\n // dupliqué dans font-variation-settings, la dernière déclaration l'emporte.\n // Cela fonctionne parfaitement sur Chromium. WebKit/Firefox pourraient théoriquement avoir\n // des bugs historiques (bien que non constatés), le risque est assumé (dégradation = contour).\n return base ? `${base}, 'FILL' 1` : `'FILL' 1`;\n });\n\n constructor() {\n // Garde-fou dev : un alias absent du registre (input [font] OU defaultFont) retombe silencieusement\n // sur --kt-icon-font. On résout l'alias effectif pour aussi couvrir un defaultFont mal orthographié.\n effect(() => {\n if (!this.auditEnabled || !isPlatformBrowser(this.platformId)) return;\n const alias = this.font() ?? this.config?.defaultFont;\n if (alias && !this.config?.fonts?.[alias as string]) {\n console.warn(\n `[ktIcon] police \"${String(alias)}\" absente du registre : ` +\n 'enregistrez-la via provideKtIcon({ fonts }) — repli sur --kt-icon-font.',\n );\n }\n\n // Garde-fou dev opt-in projection focusable\n if (!this.accessibleLabel()) {\n const focusable = this.host.querySelector(\n 'a[href],button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"]),[contenteditable=\"true\"]',\n );\n if (focusable) {\n console.warn(\n '[ktIcon] (WCAG 4.1.2) : icône décorative (aria-hidden) avec un enfant projeté focusable. Ajoutez ariaLabel ou retirez le focus.',\n );\n }\n }\n });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -199,6 +199,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
199
199
|
}]
|
|
200
200
|
}] });
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Item de navigation : projette une icône dans son slot dédié + un libellé.
|
|
204
|
+
*
|
|
205
|
+
* Le slot d'icône accepte :
|
|
206
|
+
* - la directive `[ktIcon]` (primitive d'icône `@ktortu/aaa/icon`), forme canonique.
|
|
207
|
+
* - l'attribut de projection `kt-icon` (historique/legacy).
|
|
208
|
+
*
|
|
209
|
+
* Note : la classe `.kt-icon` (posée à l'exécution par la directive) n'est PAS un critère de
|
|
210
|
+
* projection valable (ng-content matche la forme statique du template) — d'où le sélecteur d'attribut.
|
|
211
|
+
*/
|
|
202
212
|
class KtNavItemComponent {
|
|
203
213
|
label = input.required(/* @ts-ignore */
|
|
204
214
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
@@ -206,7 +216,7 @@ class KtNavItemComponent {
|
|
|
206
216
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNavItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
207
217
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.1", type: KtNavItemComponent, isStandalone: true, selector: "kt-nav-item", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "kt-nav-item" }, ngImport: i0, template: `
|
|
208
218
|
<div class="kt-nav-item-icon">
|
|
209
|
-
<ng-content select="[kt-icon]"></ng-content>
|
|
219
|
+
<ng-content select="[ktIcon], [kt-icon]"></ng-content>
|
|
210
220
|
</div>
|
|
211
221
|
<div class="kt-nav-item-label">
|
|
212
222
|
{{ label() }}
|
|
@@ -225,7 +235,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
225
235
|
},
|
|
226
236
|
template: `
|
|
227
237
|
<div class="kt-nav-item-icon">
|
|
228
|
-
<ng-content select="[kt-icon]"></ng-content>
|
|
238
|
+
<ng-content select="[ktIcon], [kt-icon]"></ng-content>
|
|
229
239
|
</div>
|
|
230
240
|
<div class="kt-nav-item-label">
|
|
231
241
|
{{ label() }}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktortu-aaa-layout.mjs","sources":["../../../../projects/ktortu/aaa/layout/layout.service.ts","../../../../projects/ktortu/aaa/layout/layout.component.ts","../../../../projects/ktortu/aaa/layout/sidenav.component.ts","../../../../projects/ktortu/aaa/layout/toolbar.component.ts","../../../../projects/ktortu/aaa/layout/nav-item.component.ts","../../../../projects/ktortu/aaa/layout/sidenav-toggle.directive.ts","../../../../projects/ktortu/aaa/layout/ktortu-aaa-layout.ts"],"sourcesContent":["import { Injectable, computed, inject, InjectionToken, signal } from '@angular/core';\nimport { KtViewport } from '@ktortu/aaa/cdk';\n\n/** Mode d'état de la navigation latérale. */\nexport type KtSidenavState = 'expanded' | 'rail' | 'hidden';\n\nexport const KT_LAYOUT_DEFAULT_STATE = new InjectionToken<KtSidenavState>('KT_LAYOUT_DEFAULT_STATE', {\n providedIn: 'root',\n factory: () => 'expanded',\n});\n\n/**\n * Service global de gestion de la mise en page (Layout).\n * Gère l'état d'ouverture/fermeture de la barre latérale sur mobile et bureau,\n * ainsi que le comportement spécifique de \"rail\" sur bureau.\n *\n * NOTE: Ce service n'est pas \"providedIn: 'root'\". Le développeur doit le fournir\n * (via le tableau providers d'un composant parent ou de l'application) pour\n * maîtriser le scope (ex: avoir plusieurs layouts indépendants).\n */\n@Injectable()\nexport class KtLayoutService {\n private readonly viewport = inject(KtViewport);\n private readonly defaultState = inject(KT_LAYOUT_DEFAULT_STATE);\n\n /**\n * Comportement actif lors de la fermeture sur ordinateur (écran non mobile).\n * Renseigné généralement par le composant racine `KtLayoutComponent`.\n */\n readonly desktopCloseBehavior = signal<'hidden' | 'rail'>('hidden');\n\n private readonly _isDesktopOpen = signal<boolean>(this.defaultState !== 'rail' && this.defaultState !== 'hidden');\n private readonly _isMobileOpen = signal<boolean>(false);\n\n readonly isMobile = this.viewport.isMobile;\n readonly isRail = computed(\n () => !this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'rail',\n );\n readonly isExpanded = computed(() => !this.isMobile() && this._isDesktopOpen());\n readonly isHidden = computed(\n () =>\n (this.isMobile() && !this._isMobileOpen()) ||\n (!this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'hidden'),\n );\n readonly isMobileOpen = computed(() => this.isMobile() && this._isMobileOpen());\n\n toggle() {\n if (this.isMobile()) {\n this._isMobileOpen.update((v) => !v);\n } else {\n this._isDesktopOpen.update((v) => !v);\n }\n }\n\n open() {\n if (this.isMobile()) {\n this._isMobileOpen.set(true);\n } else {\n this._isDesktopOpen.set(true);\n }\n }\n\n close() {\n if (this.isMobile()) {\n this._isMobileOpen.set(false);\n } else {\n this._isDesktopOpen.set(false);\n }\n }\n}\n","import { Component, inject, effect, input } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant racine de l'application qui gère la structure de base (Sidebar, Toolbar, Contenu).\n * Configure dynamiquement le comportement du layout.\n */\n@Component({\n selector: 'kt-layout',\n standalone: true,\n host: {\n class: 'kt-layout-container',\n },\n template: `\n <ng-content select=\"kt-sidenav\"></ng-content>\n <div class=\"kt-layout-main-wrapper\">\n <ng-content select=\"kt-toolbar\"></ng-content>\n <main class=\"kt-layout-main\" [attr.aria-hidden]=\"layout.isMobileOpen()\">\n <ng-content></ng-content>\n </main>\n </div>\n <div\n class=\"kt-layout-backdrop\"\n [class.is-visible]=\"layout.isMobileOpen()\"\n aria-hidden=\"true\"\n (click)=\"layout.close()\"\n ></div>\n `,\n})\nexport class KtLayoutComponent {\n /**\n * Définit le comportement de la navigation latérale lors de sa fermeture sur bureau (écran large).\n * - `'hidden'` (défaut) : le menu est complètement masqué et retiré du flux visuel/a11y.\n * - `'rail'` : le menu est réduit à une fine barre verticale (mini-sidebar), permettant\n * d'afficher uniquement les icônes. Idéal si les liens possèdent des icônes explicites.\n */\n readonly desktopCloseBehavior = input<'hidden' | 'rail'>('hidden');\n protected readonly layout = inject(KtLayoutService);\n\n constructor() {\n effect(\n () => {\n this.layout.desktopCloseBehavior.set(this.desktopCloseBehavior());\n },\n { allowSignalWrites: true },\n );\n\n effect(\n () => {\n // Clean up mobile state when switching back to desktop\n if (!this.layout.isMobile() && this.layout.isMobileOpen()) {\n this.layout.close();\n }\n },\n { allowSignalWrites: true },\n );\n }\n}\n","import { Component, inject, computed, effect } from '@angular/core';\nimport { CdkTrapFocus } from '@angular/cdk/a11y';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant représentant le panneau latéral de navigation.\n * Se comporte comme un tiroir (drawer) superposé sur mobile, et comme un\n * menu latéral persistant (réductible ou masquable) sur ordinateur.\n */\n@Component({\n selector: 'kt-sidenav',\n standalone: true,\n imports: [CdkTrapFocus],\n host: {\n class: 'kt-sidenav',\n '[class.is-hidden]': 'isHidden()',\n '[class.is-rail]': 'layout.isRail()',\n '[class.is-mobile-open]': 'layout.isMobileOpen()',\n '[attr.aria-expanded]': 'layout.isExpanded()',\n '[attr.aria-hidden]': 'isHidden()',\n role: 'navigation',\n },\n hostDirectives: [CdkTrapFocus],\n template: `<ng-content></ng-content>`,\n})\nexport class KtSidenavComponent {\n protected readonly layout = inject(KtLayoutService);\n protected readonly isHidden = computed(() => this.layout.isHidden());\n private readonly trapFocus = inject(CdkTrapFocus);\n\n constructor() {\n effect(() => {\n this.trapFocus.autoCapture = this.layout.isMobileOpen();\n this.trapFocus.enabled = this.layout.isMobileOpen();\n });\n }\n}\n","import { Component } from '@angular/core';\n\n/**\n * Barre d'outils supérieure (Toolbar / Top app bar).\n * Se place généralement dans un `kt-layout`.\n */\n@Component({\n selector: 'kt-toolbar',\n standalone: true,\n host: {\n class: 'kt-toolbar',\n role: 'banner',\n },\n template: `<ng-content></ng-content>`,\n})\nexport class KtToolbarComponent {}\n","import { Component, input, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n@Component({\n selector: 'kt-nav-item',\n standalone: true,\n host: {\n class: 'kt-nav-item',\n },\n template: `\n <div class=\"kt-nav-item-icon\">\n <ng-content select=\"[kt-icon]\"></ng-content>\n </div>\n <div class=\"kt-nav-item-label\">\n {{ label() }}\n <ng-content></ng-content>\n </div>\n <!-- TODO: Add Tooltip component injection here conditionally based on layout.isRail() -->\n `,\n})\nexport class KtNavItemComponent {\n label = input.required<string>();\n protected readonly layout = inject(KtLayoutService);\n}\n","import { Directive, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Directive applicable sur n'importe quel élément (souvent un bouton) pour basculer\n * l'état d'ouverture du panneau latéral (Sidenav).\n *\n * Expose l'état du layout pour des utilisations dynamiques dans le template\n * (ex: changer l'icône selon l'état).\n *\n * @example\n * ```html\n * <button ktSidenavToggle #btn=\"ktSidenavToggle\" [icon]=\"btn.isRail() ? 'right' : 'left'\">\n * ```\n */\n@Directive({\n selector: '[ktSidenavToggle]',\n exportAs: 'ktSidenavToggle',\n standalone: true,\n host: {\n '(click)': 'onClick()',\n },\n})\nexport class KtSidenavToggleDirective {\n private readonly layout = inject(KtLayoutService);\n\n /** Indique si le menu est actuellement réduit en mode rail. */\n readonly isRail = this.layout.isRail;\n\n /** Indique si le menu est actuellement complètement étendu sur bureau. */\n readonly isExpanded = this.layout.isExpanded;\n\n /** Indique si le menu est totalement masqué. */\n readonly isHidden = this.layout.isHidden;\n\n /** Indique si le tiroir est actuellement ouvert par-dessus le contenu (mobile). */\n readonly isMobileOpen = this.layout.isMobileOpen;\n\n /** Indique si l'écran actuel est de taille compacte (mobile). */\n readonly isMobile = this.layout.isMobile;\n\n onClick() {\n this.layout.toggle();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ktortu-aaa-layout.mjs","sources":["../../../../projects/ktortu/aaa/layout/layout.service.ts","../../../../projects/ktortu/aaa/layout/layout.component.ts","../../../../projects/ktortu/aaa/layout/sidenav.component.ts","../../../../projects/ktortu/aaa/layout/toolbar.component.ts","../../../../projects/ktortu/aaa/layout/nav-item.component.ts","../../../../projects/ktortu/aaa/layout/sidenav-toggle.directive.ts","../../../../projects/ktortu/aaa/layout/ktortu-aaa-layout.ts"],"sourcesContent":["import { Injectable, computed, inject, InjectionToken, signal } from '@angular/core';\nimport { KtViewport } from '@ktortu/aaa/cdk';\n\n/** Mode d'état de la navigation latérale. */\nexport type KtSidenavState = 'expanded' | 'rail' | 'hidden';\n\nexport const KT_LAYOUT_DEFAULT_STATE = new InjectionToken<KtSidenavState>('KT_LAYOUT_DEFAULT_STATE', {\n providedIn: 'root',\n factory: () => 'expanded',\n});\n\n/**\n * Service global de gestion de la mise en page (Layout).\n * Gère l'état d'ouverture/fermeture de la barre latérale sur mobile et bureau,\n * ainsi que le comportement spécifique de \"rail\" sur bureau.\n *\n * NOTE: Ce service n'est pas \"providedIn: 'root'\". Le développeur doit le fournir\n * (via le tableau providers d'un composant parent ou de l'application) pour\n * maîtriser le scope (ex: avoir plusieurs layouts indépendants).\n */\n@Injectable()\nexport class KtLayoutService {\n private readonly viewport = inject(KtViewport);\n private readonly defaultState = inject(KT_LAYOUT_DEFAULT_STATE);\n\n /**\n * Comportement actif lors de la fermeture sur ordinateur (écran non mobile).\n * Renseigné généralement par le composant racine `KtLayoutComponent`.\n */\n readonly desktopCloseBehavior = signal<'hidden' | 'rail'>('hidden');\n\n private readonly _isDesktopOpen = signal<boolean>(this.defaultState !== 'rail' && this.defaultState !== 'hidden');\n private readonly _isMobileOpen = signal<boolean>(false);\n\n readonly isMobile = this.viewport.isMobile;\n readonly isRail = computed(\n () => !this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'rail',\n );\n readonly isExpanded = computed(() => !this.isMobile() && this._isDesktopOpen());\n readonly isHidden = computed(\n () =>\n (this.isMobile() && !this._isMobileOpen()) ||\n (!this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'hidden'),\n );\n readonly isMobileOpen = computed(() => this.isMobile() && this._isMobileOpen());\n\n toggle() {\n if (this.isMobile()) {\n this._isMobileOpen.update((v) => !v);\n } else {\n this._isDesktopOpen.update((v) => !v);\n }\n }\n\n open() {\n if (this.isMobile()) {\n this._isMobileOpen.set(true);\n } else {\n this._isDesktopOpen.set(true);\n }\n }\n\n close() {\n if (this.isMobile()) {\n this._isMobileOpen.set(false);\n } else {\n this._isDesktopOpen.set(false);\n }\n }\n}\n","import { Component, inject, effect, input } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant racine de l'application qui gère la structure de base (Sidebar, Toolbar, Contenu).\n * Configure dynamiquement le comportement du layout.\n */\n@Component({\n selector: 'kt-layout',\n standalone: true,\n host: {\n class: 'kt-layout-container',\n },\n template: `\n <ng-content select=\"kt-sidenav\"></ng-content>\n <div class=\"kt-layout-main-wrapper\">\n <ng-content select=\"kt-toolbar\"></ng-content>\n <main class=\"kt-layout-main\" [attr.aria-hidden]=\"layout.isMobileOpen()\">\n <ng-content></ng-content>\n </main>\n </div>\n <div\n class=\"kt-layout-backdrop\"\n [class.is-visible]=\"layout.isMobileOpen()\"\n aria-hidden=\"true\"\n (click)=\"layout.close()\"\n ></div>\n `,\n})\nexport class KtLayoutComponent {\n /**\n * Définit le comportement de la navigation latérale lors de sa fermeture sur bureau (écran large).\n * - `'hidden'` (défaut) : le menu est complètement masqué et retiré du flux visuel/a11y.\n * - `'rail'` : le menu est réduit à une fine barre verticale (mini-sidebar), permettant\n * d'afficher uniquement les icônes. Idéal si les liens possèdent des icônes explicites.\n */\n readonly desktopCloseBehavior = input<'hidden' | 'rail'>('hidden');\n protected readonly layout = inject(KtLayoutService);\n\n constructor() {\n effect(\n () => {\n this.layout.desktopCloseBehavior.set(this.desktopCloseBehavior());\n },\n { allowSignalWrites: true },\n );\n\n effect(\n () => {\n // Clean up mobile state when switching back to desktop\n if (!this.layout.isMobile() && this.layout.isMobileOpen()) {\n this.layout.close();\n }\n },\n { allowSignalWrites: true },\n );\n }\n}\n","import { Component, inject, computed, effect } from '@angular/core';\nimport { CdkTrapFocus } from '@angular/cdk/a11y';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant représentant le panneau latéral de navigation.\n * Se comporte comme un tiroir (drawer) superposé sur mobile, et comme un\n * menu latéral persistant (réductible ou masquable) sur ordinateur.\n */\n@Component({\n selector: 'kt-sidenav',\n standalone: true,\n imports: [CdkTrapFocus],\n host: {\n class: 'kt-sidenav',\n '[class.is-hidden]': 'isHidden()',\n '[class.is-rail]': 'layout.isRail()',\n '[class.is-mobile-open]': 'layout.isMobileOpen()',\n '[attr.aria-expanded]': 'layout.isExpanded()',\n '[attr.aria-hidden]': 'isHidden()',\n role: 'navigation',\n },\n hostDirectives: [CdkTrapFocus],\n template: `<ng-content></ng-content>`,\n})\nexport class KtSidenavComponent {\n protected readonly layout = inject(KtLayoutService);\n protected readonly isHidden = computed(() => this.layout.isHidden());\n private readonly trapFocus = inject(CdkTrapFocus);\n\n constructor() {\n effect(() => {\n this.trapFocus.autoCapture = this.layout.isMobileOpen();\n this.trapFocus.enabled = this.layout.isMobileOpen();\n });\n }\n}\n","import { Component } from '@angular/core';\n\n/**\n * Barre d'outils supérieure (Toolbar / Top app bar).\n * Se place généralement dans un `kt-layout`.\n */\n@Component({\n selector: 'kt-toolbar',\n standalone: true,\n host: {\n class: 'kt-toolbar',\n role: 'banner',\n },\n template: `<ng-content></ng-content>`,\n})\nexport class KtToolbarComponent {}\n","import { Component, input, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Item de navigation : projette une icône dans son slot dédié + un libellé.\n *\n * Le slot d'icône accepte :\n * - la directive `[ktIcon]` (primitive d'icône `@ktortu/aaa/icon`), forme canonique.\n * - l'attribut de projection `kt-icon` (historique/legacy).\n *\n * Note : la classe `.kt-icon` (posée à l'exécution par la directive) n'est PAS un critère de\n * projection valable (ng-content matche la forme statique du template) — d'où le sélecteur d'attribut.\n */\n@Component({\n selector: 'kt-nav-item',\n standalone: true,\n host: {\n class: 'kt-nav-item',\n },\n template: `\n <div class=\"kt-nav-item-icon\">\n <ng-content select=\"[ktIcon], [kt-icon]\"></ng-content>\n </div>\n <div class=\"kt-nav-item-label\">\n {{ label() }}\n <ng-content></ng-content>\n </div>\n <!-- TODO: Add Tooltip component injection here conditionally based on layout.isRail() -->\n `,\n})\nexport class KtNavItemComponent {\n label = input.required<string>();\n protected readonly layout = inject(KtLayoutService);\n}\n","import { Directive, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Directive applicable sur n'importe quel élément (souvent un bouton) pour basculer\n * l'état d'ouverture du panneau latéral (Sidenav).\n *\n * Expose l'état du layout pour des utilisations dynamiques dans le template\n * (ex: changer l'icône selon l'état).\n *\n * @example\n * ```html\n * <button ktSidenavToggle #btn=\"ktSidenavToggle\" [icon]=\"btn.isRail() ? 'right' : 'left'\">\n * ```\n */\n@Directive({\n selector: '[ktSidenavToggle]',\n exportAs: 'ktSidenavToggle',\n standalone: true,\n host: {\n '(click)': 'onClick()',\n },\n})\nexport class KtSidenavToggleDirective {\n private readonly layout = inject(KtLayoutService);\n\n /** Indique si le menu est actuellement réduit en mode rail. */\n readonly isRail = this.layout.isRail;\n\n /** Indique si le menu est actuellement complètement étendu sur bureau. */\n readonly isExpanded = this.layout.isExpanded;\n\n /** Indique si le menu est totalement masqué. */\n readonly isHidden = this.layout.isHidden;\n\n /** Indique si le tiroir est actuellement ouvert par-dessus le contenu (mobile). */\n readonly isMobileOpen = this.layout.isMobileOpen;\n\n /** Indique si l'écran actuel est de taille compacte (mobile). */\n readonly isMobile = this.layout.isMobile;\n\n onClick() {\n this.layout.toggle();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -140,6 +140,25 @@ class KtTooltip {
|
|
|
140
140
|
clearTimeout(this.showTimer);
|
|
141
141
|
this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Fermeture immédiate à l'activation de la cible (clic souris, tap tactile, stylet).
|
|
145
|
+
* Dès que l'utilisateur AGIT sur l'élément (typiquement un bouton qui ouvre une bottom sheet ou un
|
|
146
|
+
* dialog), l'infobulle a fini son rôle : on la ferme sans attendre le hideDelay, et on purge un
|
|
147
|
+
* affichage en attente pour qu'il ne surgisse pas après coup.
|
|
148
|
+
*
|
|
149
|
+
* Sans ce déclencheur, une infobulle affichée au survol SURVIVAIT à l'ouverture d'un overlay : le
|
|
150
|
+
* pointeur reste sur la cible (aucun `mouseleave`) et un clic ne défocalise pas toujours (aucun
|
|
151
|
+
* `focusout` fiable, ex. Safari/Firefox macOS). Comme l'infobulle est un popover en top layer, elle
|
|
152
|
+
* flottait alors AU-DESSUS de l'overlay (lui empilé au z-index) — impossible à masquer autrement.
|
|
153
|
+
*
|
|
154
|
+
* `pointerdown` (et non `click`) car il précède l'ouverture de l'overlay et le déplacement de focus
|
|
155
|
+
* → zéro flash. On ne fait ni preventDefault ni stopPropagation : l'action native (clic) doit suivre
|
|
156
|
+
* son cours. Le cas clavier (Entrée/Espace) reste couvert par `focusout` quand l'overlay prend le focus.
|
|
157
|
+
*/
|
|
158
|
+
onActivate() {
|
|
159
|
+
clearTimeout(this.showTimer);
|
|
160
|
+
this.dismiss();
|
|
161
|
+
}
|
|
143
162
|
onEscape(event) {
|
|
144
163
|
if (!this.isShown())
|
|
145
164
|
return;
|
|
@@ -322,7 +341,7 @@ class KtTooltip {
|
|
|
322
341
|
this.fallbackListeners = [];
|
|
323
342
|
}
|
|
324
343
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
325
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtTooltip, isStandalone: true, selector: "[ktTooltip]", inputs: { ktTooltip: { classPropertyName: "ktTooltip", publicName: "ktTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "hideDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focusin": "show()", "focusout": "hide()", "keydown.escape": "onEscape($event)" }, properties: { "attr.aria-describedby": "describedById()" } }, ngImport: i0 });
|
|
344
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtTooltip, isStandalone: true, selector: "[ktTooltip]", inputs: { ktTooltip: { classPropertyName: "ktTooltip", publicName: "ktTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "hideDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focusin": "show()", "focusout": "hide()", "pointerdown": "onActivate()", "keydown.escape": "onEscape($event)" }, properties: { "attr.aria-describedby": "describedById()" } }, ngImport: i0 });
|
|
326
345
|
}
|
|
327
346
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, decorators: [{
|
|
328
347
|
type: Directive,
|
|
@@ -334,6 +353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
334
353
|
'(mouseleave)': 'hide()',
|
|
335
354
|
'(focusin)': 'show()',
|
|
336
355
|
'(focusout)': 'hide()',
|
|
356
|
+
'(pointerdown)': 'onActivate()',
|
|
337
357
|
'(keydown.escape)': 'onEscape($event)',
|
|
338
358
|
},
|
|
339
359
|
}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktortu-aaa-tooltip.mjs","sources":["../../../../projects/ktortu/aaa/tooltip/tooltip.ts","../../../../projects/ktortu/aaa/tooltip/ktortu-aaa-tooltip.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n ElementRef,\n EmbeddedViewRef,\n InjectionToken,\n OnDestroy,\n Provider,\n Renderer2,\n TemplateRef,\n ViewContainerRef,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n isDevMode,\n signal,\n PLATFORM_ID,\n} from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\nexport type KtTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/** Défauts d'infobulle (délais, position) injectables via `provideKtTooltip` / `KT_TOOLTIP_CONFIG`. */\nexport interface KtTooltipConfig {\n /** Délai (ms) avant apparition au survol/focus. */\n showDelay: number;\n /** Délai (ms) avant masquage (laisse le temps d'atteindre l'infobulle, WCAG « hoverable »). */\n hideDelay: number;\n /** Position de l'infobulle autour de la cible. */\n position: KtTooltipPosition;\n}\n\nexport const KT_TOOLTIP_CONFIG = new InjectionToken<Partial<KtTooltipConfig>>('KT_TOOLTIP_CONFIG');\n\n/**\n * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.\n *\n * @example\n * ```ts\n * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]\n * ```\n */\nexport function provideKtTooltip(config: Partial<KtTooltipConfig>): Provider {\n return { provide: KT_TOOLTIP_CONFIG, useValue: config };\n}\n\n/**\n * Infobulle accessible posée sur n'importe quel élément focusable/survolable.\n * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme\n * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**\n * (un `role=\"tooltip\"` ne doit pas contenir de lien/bouton/champ).\n *\n * @example\n * ```html\n * <button ktTooltip=\"Enregistrer le brouillon\">Enregistrer</button>\n * <span ktTooltip=\"Aide\" tooltipPosition=\"right\" [showDelay]=\"300\">?</span>\n * ```\n */\n@Directive({\n selector: '[ktTooltip]',\n host: {\n '[attr.aria-describedby]': 'describedById()',\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusin)': 'show()',\n '(focusout)': 'hide()',\n '(keydown.escape)': 'onEscape($event)',\n },\n})\nexport class KtTooltip implements OnDestroy {\n private readonly config = inject(KT_TOOLTIP_CONFIG, { optional: true });\n private readonly doc = inject(DOCUMENT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly vcr = inject(ViewContainerRef);\n private readonly platformId = inject(PLATFORM_ID);\n\n /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */\n readonly ktTooltip = input.required<string | TemplateRef<unknown>>();\n /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */\n readonly tooltipPosition = input<KtTooltipPosition>(this.config?.position ?? 'top');\n /** Désactive l'affichage de l'infobulle. @default false */\n readonly tooltipDisabled = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */\n readonly showDelay = input<number>(this.config?.showDelay ?? 150);\n /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */\n readonly hideDelay = input<number>(this.config?.hideDelay ?? 100);\n\n private readonly idGen = inject(KtIdGenerator);\n private readonly uid = this.idGen.generateId('tooltip');\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n /** Id du noeud `role=\"tooltip\"`. Public : sert aux liaisons d'accessibilité (`aria-describedby`) du déclencheur. */\n readonly idForA11y = this.tooltipId;\n private readonly anchorName = `--kt-tooltip-anchor-${this.uid}`;\n\n /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).\n Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */\n readonly isActive = computed(() => {\n if (this.tooltipDisabled()) return false;\n\n const content = this.ktTooltip();\n if (typeof content === 'string') return content.trim().length > 0;\n return true;\n });\n\n // Retourner null retire l'attribut (même astuce que aria-disabled dans button).\n // aria-describedby n'est posé sur le déclencheur que lorsque le tooltip est affiché : sinon il\n // référencerait un nœud absent du DOM (création lazy), donnant une référence pendante aux AT.\n protected describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null));\n\n private tip: HTMLElement | null = null;\n private view: EmbeddedViewRef<unknown> | null = null;\n private listeners: (() => void)[] = [];\n private showTimer: ReturnType<typeof setTimeout> | undefined;\n private hideTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly isShown = signal(false);\n private _supportsAnchor: boolean | null = null;\n private get supportsAnchor(): boolean {\n if (this._supportsAnchor === null) {\n this._supportsAnchor =\n isPlatformBrowser(this.platformId) &&\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('anchor-name: --x');\n }\n return this._supportsAnchor;\n }\n private fallbackListeners: (() => void)[] = [];\n private activeTemplate: TemplateRef<unknown> | null = null;\n private escListener: (() => void) | null = null;\n\n constructor() {\n // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés\n // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.\n if (isPlatformBrowser(this.platformId)) {\n this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);\n }\n\n // Gestion réactive du cycle de vie du DOM du Tooltip\n effect(() => {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Création lazy : uniquement si actif ET affiché\n if (!this.isActive() || !this.isShown()) {\n this.destroyTip();\n return;\n }\n\n const tip = this.ensureTip();\n this.registerEscapeListener();\n this.syncContent();\n\n try {\n tip.showPopover?.();\n } catch {\n // Ignorer si déjà ouvert ou non supporté\n }\n\n if (!this.supportsAnchor) {\n this.positionFallback();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroyTip();\n }\n\n protected show(): void {\n if (!this.isActive()) return;\n\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n }, this.showDelay());\n }\n\n protected hide(): void {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());\n }\n\n protected onEscape(event: Event): void {\n if (!this.isShown()) return;\n\n // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.\n this.dismiss();\n event.stopPropagation();\n }\n\n private dismiss(): void {\n if (!this.isShown()) return;\n\n this.isShown.set(false);\n }\n\n private ensureTip(): HTMLElement {\n if (this.tip) return this.tip;\n\n const tip = this.renderer.createElement('div') as HTMLElement;\n this.renderer.setAttribute(tip, 'role', 'tooltip');\n this.renderer.setAttribute(tip, 'id', this.tooltipId);\n // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.\n this.renderer.setAttribute(tip, 'popover', 'manual');\n this.renderer.addClass(tip, 'kt-tooltip');\n // setProperty natif : indispensable pour une propriété CSS à tiret.\n tip.style.setProperty('position-anchor', this.anchorName);\n // Top-layer : ajouté au body, immunisé contre overflow/z-index.\n this.renderer.appendChild(this.doc.body, tip);\n\n // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.\n this.listeners.push(\n this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)),\n this.renderer.listen(tip, 'mouseleave', () => this.hide()),\n );\n\n this.tip = tip;\n return tip;\n }\n\n private registerEscapeListener(): void {\n if (this.escListener) return;\n this.escListener = this.renderer.listen('document', 'keydown.escape', (event: KeyboardEvent) => {\n if (this.isShown()) {\n this.dismiss();\n event.stopPropagation();\n }\n });\n }\n\n private syncContent(): void {\n if (!this.tip) return;\n\n this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());\n\n const content = this.ktTooltip();\n\n if (content instanceof TemplateRef) {\n if (this.activeTemplate === content) return;\n this.clearContent();\n this.activeTemplate = content;\n\n this.view = this.vcr.createEmbeddedView(content);\n this.view.detectChanges();\n for (const node of this.view.rootNodes) {\n this.renderer.appendChild(this.tip, node);\n }\n if (isDevMode()) {\n this.warnIfInteractive();\n }\n return;\n }\n\n this.clearContent();\n this.renderer.setProperty(this.tip, 'textContent', content);\n }\n\n private clearContent(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n this.activeTemplate = null;\n if (this.tip) {\n this.renderer.setProperty(this.tip, 'textContent', '');\n }\n }\n\n // Garde-fou a11y : un role=\"tooltip\" ne doit pas contenir d'éléments focusables.\n private warnIfInteractive(): void {\n if (!this.tip) return;\n\n const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');\n if (!interactive) return;\n\n console.warn(\n `[ktTooltip] Un role=\"tooltip\" ne doit pas contenir d'éléments interactifs ` +\n `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`,\n );\n }\n\n private destroyTip(): void {\n clearTimeout(this.showTimer);\n clearTimeout(this.hideTimer);\n\n for (const unlisten of this.listeners) unlisten();\n this.listeners = [];\n this.clearFallbackListeners();\n\n if (this.escListener) {\n this.escListener();\n this.escListener = null;\n }\n\n this.view?.destroy();\n this.view = null;\n this.activeTemplate = null;\n\n if (this.tip) {\n try {\n this.tip.hidePopover?.();\n } catch {\n // Ignorer si déjà fermé ou non supporté\n }\n this.tip.remove();\n this.tip = null;\n }\n\n if (this.isShown()) {\n this.isShown.set(false);\n }\n }\n\n private positionFallback(): void {\n if (!this.tip) return;\n const triggerEl = this.host.nativeElement;\n const triggerRect = triggerEl.getBoundingClientRect();\n const tooltipRect = this.tip.getBoundingClientRect();\n const position = this.tooltipPosition();\n const gap = 8;\n\n let top = 0;\n let left = 0;\n\n if (position === 'top') {\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'bottom') {\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'left') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n } else if (position === 'right') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n }\n\n const viewWidth = window.innerWidth;\n const viewHeight = window.innerHeight;\n\n if (left < 4) left = 4;\n if (left + tooltipRect.width > viewWidth - 4) {\n left = viewWidth - tooltipRect.width - 4;\n }\n if (top < 4) {\n if (position === 'top') {\n top = triggerRect.bottom + gap;\n } else {\n top = 4;\n }\n }\n if (top + tooltipRect.height > viewHeight - 4) {\n if (position === 'bottom') {\n top = triggerRect.top - tooltipRect.height - gap;\n } else {\n top = viewHeight - tooltipRect.height - 4;\n }\n }\n\n this.tip.style.position = 'fixed';\n this.tip.style.top = `${top}px`;\n this.tip.style.left = `${left}px`;\n this.tip.style.margin = '0';\n }\n\n private registerFallbackListeners(): void {\n this.clearFallbackListeners();\n if (this.supportsAnchor || !isPlatformBrowser(this.platformId)) return;\n\n const onScrollOrResize = () => {\n this.positionFallback();\n };\n window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });\n window.addEventListener('resize', onScrollOrResize);\n\n this.fallbackListeners.push(\n () => window.removeEventListener('scroll', onScrollOrResize, { capture: true }),\n () => window.removeEventListener('resize', onScrollOrResize),\n );\n }\n\n private clearFallbackListeners(): void {\n for (const remove of this.fallbackListeners) remove();\n this.fallbackListeners = [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ktortu-aaa-tooltip.mjs","sources":["../../../../projects/ktortu/aaa/tooltip/tooltip.ts","../../../../projects/ktortu/aaa/tooltip/ktortu-aaa-tooltip.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n ElementRef,\n EmbeddedViewRef,\n InjectionToken,\n OnDestroy,\n Provider,\n Renderer2,\n TemplateRef,\n ViewContainerRef,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n isDevMode,\n signal,\n PLATFORM_ID,\n} from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\nexport type KtTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/** Défauts d'infobulle (délais, position) injectables via `provideKtTooltip` / `KT_TOOLTIP_CONFIG`. */\nexport interface KtTooltipConfig {\n /** Délai (ms) avant apparition au survol/focus. */\n showDelay: number;\n /** Délai (ms) avant masquage (laisse le temps d'atteindre l'infobulle, WCAG « hoverable »). */\n hideDelay: number;\n /** Position de l'infobulle autour de la cible. */\n position: KtTooltipPosition;\n}\n\nexport const KT_TOOLTIP_CONFIG = new InjectionToken<Partial<KtTooltipConfig>>('KT_TOOLTIP_CONFIG');\n\n/**\n * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.\n *\n * @example\n * ```ts\n * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]\n * ```\n */\nexport function provideKtTooltip(config: Partial<KtTooltipConfig>): Provider {\n return { provide: KT_TOOLTIP_CONFIG, useValue: config };\n}\n\n/**\n * Infobulle accessible posée sur n'importe quel élément focusable/survolable.\n * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme\n * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**\n * (un `role=\"tooltip\"` ne doit pas contenir de lien/bouton/champ).\n *\n * @example\n * ```html\n * <button ktTooltip=\"Enregistrer le brouillon\">Enregistrer</button>\n * <span ktTooltip=\"Aide\" tooltipPosition=\"right\" [showDelay]=\"300\">?</span>\n * ```\n */\n@Directive({\n selector: '[ktTooltip]',\n host: {\n '[attr.aria-describedby]': 'describedById()',\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusin)': 'show()',\n '(focusout)': 'hide()',\n '(pointerdown)': 'onActivate()',\n '(keydown.escape)': 'onEscape($event)',\n },\n})\nexport class KtTooltip implements OnDestroy {\n private readonly config = inject(KT_TOOLTIP_CONFIG, { optional: true });\n private readonly doc = inject(DOCUMENT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly vcr = inject(ViewContainerRef);\n private readonly platformId = inject(PLATFORM_ID);\n\n /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */\n readonly ktTooltip = input.required<string | TemplateRef<unknown>>();\n /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */\n readonly tooltipPosition = input<KtTooltipPosition>(this.config?.position ?? 'top');\n /** Désactive l'affichage de l'infobulle. @default false */\n readonly tooltipDisabled = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */\n readonly showDelay = input<number>(this.config?.showDelay ?? 150);\n /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */\n readonly hideDelay = input<number>(this.config?.hideDelay ?? 100);\n\n private readonly idGen = inject(KtIdGenerator);\n private readonly uid = this.idGen.generateId('tooltip');\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n /** Id du noeud `role=\"tooltip\"`. Public : sert aux liaisons d'accessibilité (`aria-describedby`) du déclencheur. */\n readonly idForA11y = this.tooltipId;\n private readonly anchorName = `--kt-tooltip-anchor-${this.uid}`;\n\n /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).\n Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */\n readonly isActive = computed(() => {\n if (this.tooltipDisabled()) return false;\n\n const content = this.ktTooltip();\n if (typeof content === 'string') return content.trim().length > 0;\n return true;\n });\n\n // Retourner null retire l'attribut (même astuce que aria-disabled dans button).\n // aria-describedby n'est posé sur le déclencheur que lorsque le tooltip est affiché : sinon il\n // référencerait un nœud absent du DOM (création lazy), donnant une référence pendante aux AT.\n protected describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null));\n\n private tip: HTMLElement | null = null;\n private view: EmbeddedViewRef<unknown> | null = null;\n private listeners: (() => void)[] = [];\n private showTimer: ReturnType<typeof setTimeout> | undefined;\n private hideTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly isShown = signal(false);\n private _supportsAnchor: boolean | null = null;\n private get supportsAnchor(): boolean {\n if (this._supportsAnchor === null) {\n this._supportsAnchor =\n isPlatformBrowser(this.platformId) &&\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('anchor-name: --x');\n }\n return this._supportsAnchor;\n }\n private fallbackListeners: (() => void)[] = [];\n private activeTemplate: TemplateRef<unknown> | null = null;\n private escListener: (() => void) | null = null;\n\n constructor() {\n // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés\n // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.\n if (isPlatformBrowser(this.platformId)) {\n this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);\n }\n\n // Gestion réactive du cycle de vie du DOM du Tooltip\n effect(() => {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Création lazy : uniquement si actif ET affiché\n if (!this.isActive() || !this.isShown()) {\n this.destroyTip();\n return;\n }\n\n const tip = this.ensureTip();\n this.registerEscapeListener();\n this.syncContent();\n\n try {\n tip.showPopover?.();\n } catch {\n // Ignorer si déjà ouvert ou non supporté\n }\n\n if (!this.supportsAnchor) {\n this.positionFallback();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroyTip();\n }\n\n protected show(): void {\n if (!this.isActive()) return;\n\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n }, this.showDelay());\n }\n\n protected hide(): void {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());\n }\n\n /**\n * Fermeture immédiate à l'activation de la cible (clic souris, tap tactile, stylet).\n * Dès que l'utilisateur AGIT sur l'élément (typiquement un bouton qui ouvre une bottom sheet ou un\n * dialog), l'infobulle a fini son rôle : on la ferme sans attendre le hideDelay, et on purge un\n * affichage en attente pour qu'il ne surgisse pas après coup.\n *\n * Sans ce déclencheur, une infobulle affichée au survol SURVIVAIT à l'ouverture d'un overlay : le\n * pointeur reste sur la cible (aucun `mouseleave`) et un clic ne défocalise pas toujours (aucun\n * `focusout` fiable, ex. Safari/Firefox macOS). Comme l'infobulle est un popover en top layer, elle\n * flottait alors AU-DESSUS de l'overlay (lui empilé au z-index) — impossible à masquer autrement.\n *\n * `pointerdown` (et non `click`) car il précède l'ouverture de l'overlay et le déplacement de focus\n * → zéro flash. On ne fait ni preventDefault ni stopPropagation : l'action native (clic) doit suivre\n * son cours. Le cas clavier (Entrée/Espace) reste couvert par `focusout` quand l'overlay prend le focus.\n */\n protected onActivate(): void {\n clearTimeout(this.showTimer);\n this.dismiss();\n }\n\n protected onEscape(event: Event): void {\n if (!this.isShown()) return;\n\n // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.\n this.dismiss();\n event.stopPropagation();\n }\n\n private dismiss(): void {\n if (!this.isShown()) return;\n\n this.isShown.set(false);\n }\n\n private ensureTip(): HTMLElement {\n if (this.tip) return this.tip;\n\n const tip = this.renderer.createElement('div') as HTMLElement;\n this.renderer.setAttribute(tip, 'role', 'tooltip');\n this.renderer.setAttribute(tip, 'id', this.tooltipId);\n // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.\n this.renderer.setAttribute(tip, 'popover', 'manual');\n this.renderer.addClass(tip, 'kt-tooltip');\n // setProperty natif : indispensable pour une propriété CSS à tiret.\n tip.style.setProperty('position-anchor', this.anchorName);\n // Top-layer : ajouté au body, immunisé contre overflow/z-index.\n this.renderer.appendChild(this.doc.body, tip);\n\n // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.\n this.listeners.push(\n this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)),\n this.renderer.listen(tip, 'mouseleave', () => this.hide()),\n );\n\n this.tip = tip;\n return tip;\n }\n\n private registerEscapeListener(): void {\n if (this.escListener) return;\n this.escListener = this.renderer.listen('document', 'keydown.escape', (event: KeyboardEvent) => {\n if (this.isShown()) {\n this.dismiss();\n event.stopPropagation();\n }\n });\n }\n\n private syncContent(): void {\n if (!this.tip) return;\n\n this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());\n\n const content = this.ktTooltip();\n\n if (content instanceof TemplateRef) {\n if (this.activeTemplate === content) return;\n this.clearContent();\n this.activeTemplate = content;\n\n this.view = this.vcr.createEmbeddedView(content);\n this.view.detectChanges();\n for (const node of this.view.rootNodes) {\n this.renderer.appendChild(this.tip, node);\n }\n if (isDevMode()) {\n this.warnIfInteractive();\n }\n return;\n }\n\n this.clearContent();\n this.renderer.setProperty(this.tip, 'textContent', content);\n }\n\n private clearContent(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n this.activeTemplate = null;\n if (this.tip) {\n this.renderer.setProperty(this.tip, 'textContent', '');\n }\n }\n\n // Garde-fou a11y : un role=\"tooltip\" ne doit pas contenir d'éléments focusables.\n private warnIfInteractive(): void {\n if (!this.tip) return;\n\n const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');\n if (!interactive) return;\n\n console.warn(\n `[ktTooltip] Un role=\"tooltip\" ne doit pas contenir d'éléments interactifs ` +\n `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`,\n );\n }\n\n private destroyTip(): void {\n clearTimeout(this.showTimer);\n clearTimeout(this.hideTimer);\n\n for (const unlisten of this.listeners) unlisten();\n this.listeners = [];\n this.clearFallbackListeners();\n\n if (this.escListener) {\n this.escListener();\n this.escListener = null;\n }\n\n this.view?.destroy();\n this.view = null;\n this.activeTemplate = null;\n\n if (this.tip) {\n try {\n this.tip.hidePopover?.();\n } catch {\n // Ignorer si déjà fermé ou non supporté\n }\n this.tip.remove();\n this.tip = null;\n }\n\n if (this.isShown()) {\n this.isShown.set(false);\n }\n }\n\n private positionFallback(): void {\n if (!this.tip) return;\n const triggerEl = this.host.nativeElement;\n const triggerRect = triggerEl.getBoundingClientRect();\n const tooltipRect = this.tip.getBoundingClientRect();\n const position = this.tooltipPosition();\n const gap = 8;\n\n let top = 0;\n let left = 0;\n\n if (position === 'top') {\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'bottom') {\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'left') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n } else if (position === 'right') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n }\n\n const viewWidth = window.innerWidth;\n const viewHeight = window.innerHeight;\n\n if (left < 4) left = 4;\n if (left + tooltipRect.width > viewWidth - 4) {\n left = viewWidth - tooltipRect.width - 4;\n }\n if (top < 4) {\n if (position === 'top') {\n top = triggerRect.bottom + gap;\n } else {\n top = 4;\n }\n }\n if (top + tooltipRect.height > viewHeight - 4) {\n if (position === 'bottom') {\n top = triggerRect.top - tooltipRect.height - gap;\n } else {\n top = viewHeight - tooltipRect.height - 4;\n }\n }\n\n this.tip.style.position = 'fixed';\n this.tip.style.top = `${top}px`;\n this.tip.style.left = `${left}px`;\n this.tip.style.margin = '0';\n }\n\n private registerFallbackListeners(): void {\n this.clearFallbackListeners();\n if (this.supportsAnchor || !isPlatformBrowser(this.platformId)) return;\n\n const onScrollOrResize = () => {\n this.positionFallback();\n };\n window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });\n window.addEventListener('resize', onScrollOrResize);\n\n this.fallbackListeners.push(\n () => window.removeEventListener('scroll', onScrollOrResize, { capture: true }),\n () => window.removeEventListener('resize', onScrollOrResize),\n );\n }\n\n private clearFallbackListeners(): void {\n for (const remove of this.fallbackListeners) remove();\n this.fallbackListeners = [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|