@ktortu/aaa 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/button/button-tokens.css +152 -0
  4. package/button/button.css +319 -0
  5. package/card/card-tokens.css +49 -0
  6. package/card/card.css +200 -0
  7. package/cdk/styles/foundation.css +83 -0
  8. package/cdk/styles/tabs.css +276 -0
  9. package/dialog/dialog.css +350 -0
  10. package/fesm2022/ktortu-aaa-button.mjs +128 -0
  11. package/fesm2022/ktortu-aaa-button.mjs.map +1 -0
  12. package/fesm2022/ktortu-aaa-card.mjs +209 -0
  13. package/fesm2022/ktortu-aaa-card.mjs.map +1 -0
  14. package/fesm2022/ktortu-aaa-cdk.mjs +183 -0
  15. package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -0
  16. package/fesm2022/ktortu-aaa-dialog.mjs +512 -0
  17. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -0
  18. package/fesm2022/ktortu-aaa-forms.mjs +3215 -0
  19. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -0
  20. package/fesm2022/ktortu-aaa-menu.mjs +315 -0
  21. package/fesm2022/ktortu-aaa-menu.mjs.map +1 -0
  22. package/fesm2022/ktortu-aaa-tabs.mjs +79 -0
  23. package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -0
  24. package/fesm2022/ktortu-aaa-tooltip.mjs +356 -0
  25. package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -0
  26. package/fesm2022/ktortu-aaa.mjs +17 -0
  27. package/fesm2022/ktortu-aaa.mjs.map +1 -0
  28. package/forms/checkbox/checkbox-group.css +55 -0
  29. package/forms/checkbox/checkbox.css +216 -0
  30. package/forms/chips/chip-list.css +70 -0
  31. package/forms/chips/chip.css +92 -0
  32. package/forms/chips/tokens.css +102 -0
  33. package/forms/field/field.css +87 -0
  34. package/forms/multi-select/multi-select.css +136 -0
  35. package/forms/radio/radio-group.css +55 -0
  36. package/forms/radio/radio.css +165 -0
  37. package/forms/styles/field-box.css +171 -0
  38. package/forms/styles/select-panel.css +464 -0
  39. package/forms/styles/tokens.css +67 -0
  40. package/forms/switch/switch.css +188 -0
  41. package/menu/menu-tokens.css +58 -0
  42. package/menu/menu.css +224 -0
  43. package/package.json +96 -0
  44. package/styles/button.css +6 -0
  45. package/styles/card.css +6 -0
  46. package/styles/dialog.css +6 -0
  47. package/styles/forms.css +13 -0
  48. package/styles/foundation.css +7 -0
  49. package/styles/menu.css +6 -0
  50. package/styles/styles.css +24 -0
  51. package/styles/tabs.css +5 -0
  52. package/styles/tooltip.css +5 -0
  53. package/themes/theme-ant.css +44 -0
  54. package/themes/theme-architecte.css +83 -0
  55. package/themes/theme-aurora.css +97 -0
  56. package/themes/theme-bootstrap.css +46 -0
  57. package/themes/theme-carbon.css +49 -0
  58. package/themes/theme-catppuccin.css +66 -0
  59. package/themes/theme-cyberpunk.css +211 -0
  60. package/themes/theme-fluent.css +45 -0
  61. package/themes/theme-material-you.css +74 -0
  62. package/themes/theme-material.css +48 -0
  63. package/themes/theme-primer.css +46 -0
  64. package/themes/theme-vegetal.css +78 -0
  65. package/tooltip/tooltip.css +129 -0
  66. package/types/ktortu-aaa-button.d.ts +70 -0
  67. package/types/ktortu-aaa-card.d.ts +143 -0
  68. package/types/ktortu-aaa-cdk.d.ts +110 -0
  69. package/types/ktortu-aaa-dialog.d.ts +286 -0
  70. package/types/ktortu-aaa-forms.d.ts +1574 -0
  71. package/types/ktortu-aaa-menu.d.ts +171 -0
  72. package/types/ktortu-aaa-tabs.d.ts +27 -0
  73. package/types/ktortu-aaa-tooltip.d.ts +90 -0
  74. package/types/ktortu-aaa.d.ts +8 -0
@@ -0,0 +1,356 @@
1
+ import { DOCUMENT, isPlatformBrowser } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { InjectionToken, inject, ElementRef, Renderer2, ViewContainerRef, NgZone, PLATFORM_ID, input, booleanAttribute, computed, signal, effect, TemplateRef, isDevMode, Directive } from '@angular/core';
4
+ import { KtIdGenerator } from '@ktortu/aaa/cdk';
5
+
6
+ const KT_TOOLTIP_CONFIG = new InjectionToken('KT_TOOLTIP_CONFIG');
7
+ /**
8
+ * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]
13
+ * ```
14
+ */
15
+ function provideKtTooltip(config) {
16
+ return { provide: KT_TOOLTIP_CONFIG, useValue: config };
17
+ }
18
+ /**
19
+ * Infobulle accessible posée sur n'importe quel élément focusable/survolable.
20
+ * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme
21
+ * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**
22
+ * (un `role="tooltip"` ne doit pas contenir de lien/bouton/champ).
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <button ktTooltip="Enregistrer le brouillon">Enregistrer</button>
27
+ * <span ktTooltip="Aide" tooltipPosition="right" [showDelay]="300">?</span>
28
+ * ```
29
+ */
30
+ class KtTooltip {
31
+ config = inject(KT_TOOLTIP_CONFIG, { optional: true });
32
+ doc = inject(DOCUMENT);
33
+ host = inject(ElementRef);
34
+ renderer = inject(Renderer2);
35
+ vcr = inject(ViewContainerRef);
36
+ ngZone = inject(NgZone);
37
+ platformId = inject(PLATFORM_ID);
38
+ /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */
39
+ ktTooltip = input.required(/* @ts-ignore */
40
+ ...(ngDevMode ? [{ debugName: "ktTooltip" }] : /* istanbul ignore next */ []));
41
+ /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */
42
+ tooltipPosition = input(this.config?.position ?? 'top', /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "tooltipPosition" }] : /* istanbul ignore next */ []));
44
+ /** Désactive l'affichage de l'infobulle. @default false */
45
+ tooltipDisabled = input(false, { ...(ngDevMode ? { debugName: "tooltipDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
46
+ /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */
47
+ showDelay = input(this.config?.showDelay ?? 150, /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "showDelay" }] : /* istanbul ignore next */ []));
49
+ /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */
50
+ hideDelay = input(this.config?.hideDelay ?? 100, /* @ts-ignore */
51
+ ...(ngDevMode ? [{ debugName: "hideDelay" }] : /* istanbul ignore next */ []));
52
+ idGen = inject(KtIdGenerator);
53
+ uid = this.idGen.generateId();
54
+ tooltipId = `kt-tooltip-${this.uid}`;
55
+ idForA11y = this.tooltipId; // Rendu public pour les liaisons d'accessibilité (aria-describedby)
56
+ anchorName = `--kt-tooltip-anchor-${this.uid}`;
57
+ /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).
58
+ Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */
59
+ isActive = computed(() => {
60
+ if (this.tooltipDisabled())
61
+ return false;
62
+ const content = this.ktTooltip();
63
+ if (typeof content === 'string')
64
+ return content.trim().length > 0;
65
+ return true;
66
+ }, /* @ts-ignore */
67
+ ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
68
+ // Retourner null retire l'attribut (même astuce que aria-disabled dans button).
69
+ // Corrigé : aria-describedby n'est présent sur le déclencheur que si le tooltip est affiché.
70
+ describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null), /* @ts-ignore */
71
+ ...(ngDevMode ? [{ debugName: "describedById" }] : /* istanbul ignore next */ []));
72
+ tip = null;
73
+ view = null;
74
+ listeners = [];
75
+ showTimer;
76
+ hideTimer;
77
+ isShown = signal(false, /* @ts-ignore */
78
+ ...(ngDevMode ? [{ debugName: "isShown" }] : /* istanbul ignore next */ []));
79
+ _supportsAnchor = null;
80
+ get supportsAnchor() {
81
+ if (this._supportsAnchor === null) {
82
+ this._supportsAnchor =
83
+ isPlatformBrowser(this.platformId) &&
84
+ typeof CSS !== 'undefined' &&
85
+ typeof CSS.supports === 'function' &&
86
+ CSS.supports('anchor-name: --x');
87
+ }
88
+ return this._supportsAnchor;
89
+ }
90
+ fallbackListeners = [];
91
+ activeTemplate = null;
92
+ escListener = null;
93
+ constructor() {
94
+ // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés
95
+ // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.
96
+ if (isPlatformBrowser(this.platformId)) {
97
+ this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);
98
+ }
99
+ // Gestion réactive du cycle de vie du DOM du Tooltip
100
+ effect(() => {
101
+ if (!isPlatformBrowser(this.platformId))
102
+ return;
103
+ // Création lazy : uniquement si actif ET affiché
104
+ if (!this.isActive() || !this.isShown()) {
105
+ this.destroyTip();
106
+ return;
107
+ }
108
+ const tip = this.ensureTip();
109
+ this.registerEscapeListener();
110
+ this.syncContent();
111
+ try {
112
+ tip.showPopover?.();
113
+ }
114
+ catch {
115
+ // Ignorer si déjà ouvert ou non supporté
116
+ }
117
+ if (!this.supportsAnchor) {
118
+ this.positionFallback();
119
+ }
120
+ });
121
+ }
122
+ ngOnDestroy() {
123
+ this.destroyTip();
124
+ }
125
+ show() {
126
+ if (!this.isActive())
127
+ return;
128
+ this.ngZone.runOutsideAngular(() => {
129
+ clearTimeout(this.hideTimer);
130
+ this.showTimer = setTimeout(() => {
131
+ this.ngZone.run(() => {
132
+ if (this.isShown())
133
+ return;
134
+ this.isShown.set(true);
135
+ if (!this.supportsAnchor) {
136
+ this.registerFallbackListeners();
137
+ }
138
+ });
139
+ }, this.showDelay());
140
+ });
141
+ }
142
+ hide() {
143
+ this.ngZone.runOutsideAngular(() => {
144
+ clearTimeout(this.showTimer);
145
+ this.hideTimer = setTimeout(() => {
146
+ this.ngZone.run(() => this.dismiss());
147
+ }, this.hideDelay());
148
+ });
149
+ }
150
+ onEscape(event) {
151
+ if (!this.isShown())
152
+ return;
153
+ // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.
154
+ this.dismiss();
155
+ event.stopPropagation();
156
+ }
157
+ dismiss() {
158
+ if (!this.isShown())
159
+ return;
160
+ this.isShown.set(false);
161
+ }
162
+ ensureTip() {
163
+ if (this.tip)
164
+ return this.tip;
165
+ const tip = this.renderer.createElement('div');
166
+ this.renderer.setAttribute(tip, 'role', 'tooltip');
167
+ this.renderer.setAttribute(tip, 'id', this.tooltipId);
168
+ // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.
169
+ this.renderer.setAttribute(tip, 'popover', 'manual');
170
+ this.renderer.addClass(tip, 'kt-tooltip');
171
+ // setProperty natif : indispensable pour une propriété CSS à tiret.
172
+ tip.style.setProperty('position-anchor', this.anchorName);
173
+ // Top-layer : ajouté au body, immunisé contre overflow/z-index.
174
+ this.renderer.appendChild(this.doc.body, tip);
175
+ // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.
176
+ this.listeners.push(this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)), this.renderer.listen(tip, 'mouseleave', () => this.hide()));
177
+ this.tip = tip;
178
+ return tip;
179
+ }
180
+ registerEscapeListener() {
181
+ if (this.escListener)
182
+ return;
183
+ this.escListener = this.renderer.listen('document', 'keydown.escape', (event) => {
184
+ if (this.isShown()) {
185
+ this.dismiss();
186
+ event.stopPropagation();
187
+ }
188
+ });
189
+ }
190
+ syncContent() {
191
+ if (!this.tip)
192
+ return;
193
+ this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());
194
+ const content = this.ktTooltip();
195
+ if (content instanceof TemplateRef) {
196
+ if (this.activeTemplate === content)
197
+ return;
198
+ this.clearContent();
199
+ this.activeTemplate = content;
200
+ this.view = this.vcr.createEmbeddedView(content);
201
+ this.view.detectChanges();
202
+ for (const node of this.view.rootNodes) {
203
+ this.renderer.appendChild(this.tip, node);
204
+ }
205
+ if (isDevMode()) {
206
+ this.warnIfInteractive();
207
+ }
208
+ return;
209
+ }
210
+ this.clearContent();
211
+ this.renderer.setProperty(this.tip, 'textContent', content);
212
+ }
213
+ clearContent() {
214
+ if (this.view) {
215
+ this.view.destroy();
216
+ this.view = null;
217
+ }
218
+ this.activeTemplate = null;
219
+ if (this.tip) {
220
+ this.renderer.setProperty(this.tip, 'textContent', '');
221
+ }
222
+ }
223
+ // Garde-fou a11y : un role="tooltip" ne doit pas contenir d'éléments focusables.
224
+ warnIfInteractive() {
225
+ if (!this.tip)
226
+ return;
227
+ const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');
228
+ if (!interactive)
229
+ return;
230
+ console.warn(`[ktTooltip] Un role="tooltip" ne doit pas contenir d'éléments interactifs ` +
231
+ `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`);
232
+ }
233
+ destroyTip() {
234
+ clearTimeout(this.showTimer);
235
+ clearTimeout(this.hideTimer);
236
+ for (const unlisten of this.listeners)
237
+ unlisten();
238
+ this.listeners = [];
239
+ this.clearFallbackListeners();
240
+ if (this.escListener) {
241
+ this.escListener();
242
+ this.escListener = null;
243
+ }
244
+ this.view?.destroy();
245
+ this.view = null;
246
+ this.activeTemplate = null;
247
+ if (this.tip) {
248
+ try {
249
+ this.tip.hidePopover?.();
250
+ }
251
+ catch {
252
+ // Ignorer si déjà fermé ou non supporté
253
+ }
254
+ this.tip.remove();
255
+ this.tip = null;
256
+ }
257
+ if (this.isShown()) {
258
+ this.isShown.set(false);
259
+ }
260
+ }
261
+ positionFallback() {
262
+ if (!this.tip)
263
+ return;
264
+ const triggerEl = this.host.nativeElement;
265
+ const triggerRect = triggerEl.getBoundingClientRect();
266
+ const tooltipRect = this.tip.getBoundingClientRect();
267
+ const position = this.tooltipPosition();
268
+ const gap = 8;
269
+ let top = 0;
270
+ let left = 0;
271
+ if (position === 'top') {
272
+ top = triggerRect.top - tooltipRect.height - gap;
273
+ left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
274
+ }
275
+ else if (position === 'bottom') {
276
+ top = triggerRect.bottom + gap;
277
+ left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
278
+ }
279
+ else if (position === 'left') {
280
+ top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
281
+ left = triggerRect.left - tooltipRect.width - gap;
282
+ }
283
+ else if (position === 'right') {
284
+ top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
285
+ left = triggerRect.right + gap;
286
+ }
287
+ const viewWidth = window.innerWidth;
288
+ const viewHeight = window.innerHeight;
289
+ if (left < 4)
290
+ left = 4;
291
+ if (left + tooltipRect.width > viewWidth - 4) {
292
+ left = viewWidth - tooltipRect.width - 4;
293
+ }
294
+ if (top < 4) {
295
+ if (position === 'top') {
296
+ top = triggerRect.bottom + gap;
297
+ }
298
+ else {
299
+ top = 4;
300
+ }
301
+ }
302
+ if (top + tooltipRect.height > viewHeight - 4) {
303
+ if (position === 'bottom') {
304
+ top = triggerRect.top - tooltipRect.height - gap;
305
+ }
306
+ else {
307
+ top = viewHeight - tooltipRect.height - 4;
308
+ }
309
+ }
310
+ this.tip.style.position = 'fixed';
311
+ this.tip.style.top = `${top}px`;
312
+ this.tip.style.left = `${left}px`;
313
+ this.tip.style.margin = '0';
314
+ }
315
+ registerFallbackListeners() {
316
+ this.clearFallbackListeners();
317
+ if (this.supportsAnchor || !isPlatformBrowser(this.platformId))
318
+ return;
319
+ this.ngZone.runOutsideAngular(() => {
320
+ const onScrollOrResize = () => {
321
+ this.positionFallback();
322
+ };
323
+ window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });
324
+ window.addEventListener('resize', onScrollOrResize);
325
+ this.fallbackListeners.push(() => window.removeEventListener('scroll', onScrollOrResize, { capture: true }), () => window.removeEventListener('resize', onScrollOrResize));
326
+ });
327
+ }
328
+ clearFallbackListeners() {
329
+ for (const remove of this.fallbackListeners)
330
+ remove();
331
+ this.fallbackListeners = [];
332
+ }
333
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
334
+ 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 });
335
+ }
336
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, decorators: [{
337
+ type: Directive,
338
+ args: [{
339
+ selector: '[ktTooltip]',
340
+ host: {
341
+ '[attr.aria-describedby]': 'describedById()',
342
+ '(mouseenter)': 'show()',
343
+ '(mouseleave)': 'hide()',
344
+ '(focusin)': 'show()',
345
+ '(focusout)': 'hide()',
346
+ '(keydown.escape)': 'onEscape($event)',
347
+ },
348
+ }]
349
+ }], ctorParameters: () => [], propDecorators: { ktTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "ktTooltip", required: true }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], tooltipDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDisabled", required: false }] }], showDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDelay", required: false }] }], hideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideDelay", required: false }] }] } });
350
+
351
+ /**
352
+ * Generated bundle index. Do not edit.
353
+ */
354
+
355
+ export { KT_TOOLTIP_CONFIG, KtTooltip, provideKtTooltip };
356
+ //# sourceMappingURL=ktortu-aaa-tooltip.mjs.map
@@ -0,0 +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 NgZone,\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\nexport interface KtTooltipConfig {\n showDelay: number;\n hideDelay: number;\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 ngZone = inject(NgZone);\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();\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n readonly idForA11y = this.tooltipId; // Rendu public pour les liaisons d'accessibilité (aria-describedby)\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 // Corrigé : aria-describedby n'est présent sur le déclencheur que si le tooltip est affiché.\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 this.ngZone.runOutsideAngular(() => {\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n this.ngZone.run(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n });\n }, this.showDelay());\n });\n }\n\n protected hide(): void {\n this.ngZone.runOutsideAngular(() => {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => {\n this.ngZone.run(() => this.dismiss());\n }, this.hideDelay());\n });\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 this.ngZone.runOutsideAngular(() => {\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\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":";;;;;MA+Ba,iBAAiB,GAAG,IAAI,cAAc,CAA2B,mBAAmB;AAEjG;;;;;;;AAOG;AACG,SAAU,gBAAgB,CAAC,MAAgC,EAAA;IAC/D,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE;AACzD;AAEA;;;;;;;;;;;AAWG;MAYU,SAAS,CAAA;IACH,MAAM,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACtD,IAAA,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC;AACtB,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC;AAC5B,IAAA,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC9B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;;IAGxC,SAAS,GAAG,KAAK,CAAC,QAAQ;kFAAiC;;IAE3D,eAAe,GAAG,KAAK,CAAoB,IAAI,CAAC,MAAM,EAAE,QAAQ,IAAI,KAAK;wFAAC;;IAE1E,eAAe,GAAG,KAAK,CAAmB,KAAK,uFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAEjF,SAAS,GAAG,KAAK,CAAS,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,GAAG;kFAAC;;IAExD,SAAS,GAAG,KAAK,CAAS,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,GAAG;kFAAC;AAEhD,IAAA,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC;AAC7B,IAAA,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;AAC7B,IAAA,SAAS,GAAG,CAAA,WAAA,EAAc,IAAI,CAAC,GAAG,EAAE;AAC5C,IAAA,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;AACnB,IAAA,UAAU,GAAG,CAAA,oBAAA,EAAuB,IAAI,CAAC,GAAG,EAAE;AAE/D;AACmG;AAC1F,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;QAChC,IAAI,IAAI,CAAC,eAAe,EAAE;AAAE,YAAA,OAAO,KAAK;AAExC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE;QAChC,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;AACjE,QAAA,OAAO,IAAI;IACb,CAAC;iFAAC;;;IAIQ,aAAa,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;sFAAC;IAE7F,GAAG,GAAuB,IAAI;IAC9B,IAAI,GAAoC,IAAI;IAC5C,SAAS,GAAmB,EAAE;AAC9B,IAAA,SAAS;AACT,IAAA,SAAS;IACA,OAAO,GAAG,MAAM,CAAC,KAAK;gFAAC;IAChC,eAAe,GAAmB,IAAI;AAC9C,IAAA,IAAY,cAAc,GAAA;AACxB,QAAA,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,EAAE;AACjC,YAAA,IAAI,CAAC,eAAe;AAClB,gBAAA,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;oBAClC,OAAO,GAAG,KAAK,WAAW;AAC1B,oBAAA,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU;AAClC,oBAAA,GAAG,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QACpC;QACA,OAAO,IAAI,CAAC,eAAe;IAC7B;IACQ,iBAAiB,GAAmB,EAAE;IACtC,cAAc,GAAgC,IAAI;IAClD,WAAW,GAAwB,IAAI;AAE/C,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;AACtC,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC;QAC3E;;QAGA,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;gBAAE;;AAGzC,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACvC,IAAI,CAAC,UAAU,EAAE;gBACjB;YACF;AAEA,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE;YAC5B,IAAI,CAAC,sBAAsB,EAAE;YAC7B,IAAI,CAAC,WAAW,EAAE;AAElB,YAAA,IAAI;AACF,gBAAA,GAAG,CAAC,WAAW,IAAI;YACrB;AAAE,YAAA,MAAM;;YAER;AAEA,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;gBACxB,IAAI,CAAC,gBAAgB,EAAE;YACzB;AACF,QAAA,CAAC,CAAC;IACJ;IAEA,WAAW,GAAA;QACT,IAAI,CAAC,UAAU,EAAE;IACnB;IAEU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAAE;AAEtB,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,YAAA,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5B,YAAA,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAK;AAC/B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;oBACnB,IAAI,IAAI,CAAC,OAAO,EAAE;wBAAE;AAEpB,oBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAEtB,oBAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;wBACxB,IAAI,CAAC,yBAAyB,EAAE;oBAClC;AACF,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AACtB,QAAA,CAAC,CAAC;IACJ;IAEU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,YAAA,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5B,YAAA,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAK;AAC/B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;AACvC,YAAA,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AACtB,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,QAAQ,CAAC,KAAY,EAAA;AAC7B,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE;;QAGrB,IAAI,CAAC,OAAO,EAAE;QACd,KAAK,CAAC,eAAe,EAAE;IACzB;IAEQ,OAAO,GAAA;AACb,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE;AAErB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;IACzB;IAEQ,SAAS,GAAA;QACf,IAAI,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC,GAAG;QAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAgB;QAC7D,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC;AAClD,QAAA,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;;QAErD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC;QACpD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;;QAEzC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,UAAU,CAAC;;AAEzD,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;;QAG7C,IAAI,CAAC,SAAS,CAAC,IAAI,CACjB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAC3E,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAC3D;AAED,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,OAAO,GAAG;IACZ;IAEQ,sBAAsB,GAAA;QAC5B,IAAI,IAAI,CAAC,WAAW;YAAE;AACtB,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,EAAE,CAAC,KAAoB,KAAI;AAC7F,YAAA,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,IAAI,CAAC,OAAO,EAAE;gBACd,KAAK,CAAC,eAAe,EAAE;YACzB;AACF,QAAA,CAAC,CAAC;IACJ;IAEQ,WAAW,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE;AAEf,QAAA,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;AAE7E,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE;AAEhC,QAAA,IAAI,OAAO,YAAY,WAAW,EAAE;AAClC,YAAA,IAAI,IAAI,CAAC,cAAc,KAAK,OAAO;gBAAE;YACrC,IAAI,CAAC,YAAY,EAAE;AACnB,YAAA,IAAI,CAAC,cAAc,GAAG,OAAO;YAE7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,OAAO,CAAC;AAChD,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACtC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;YAC3C;YACA,IAAI,SAAS,EAAE,EAAE;gBACf,IAAI,CAAC,iBAAiB,EAAE;YAC1B;YACA;QACF;QAEA,IAAI,CAAC,YAAY,EAAE;AACnB,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,CAAC;IAC7D;IAEQ,YAAY,GAAA;AAClB,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE;AACb,YAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AACnB,YAAA,IAAI,CAAC,IAAI,GAAG,IAAI;QAClB;AACA,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAC1B,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE;AACZ,YAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,CAAC;QACxD;IACF;;IAGQ,iBAAiB,GAAA;QACvB,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE;QAEf,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,sDAAsD,CAAC;AAClG,QAAA,IAAI,CAAC,WAAW;YAAE;QAElB,OAAO,CAAC,IAAI,CACV,CAAA,0EAAA,CAA4E;YAC1E,CAAA,EAAA,EAAK,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA,gDAAA,CAAkD,CAC5F;IACH;IAEQ,UAAU,GAAA;AAChB,QAAA,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5B,QAAA,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAE5B,QAAA,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;AAAE,YAAA,QAAQ,EAAE;AACjD,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;QACnB,IAAI,CAAC,sBAAsB,EAAE;AAE7B,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,IAAI,CAAC,WAAW,EAAE;AAClB,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;QACzB;AAEA,QAAA,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE;AACpB,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAE1B,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE;AACZ,YAAA,IAAI;AACF,gBAAA,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI;YAC1B;AAAE,YAAA,MAAM;;YAER;AACA,YAAA,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE;AACjB,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI;QACjB;AAEA,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;AAClB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;QACzB;IACF;IAEQ,gBAAgB,GAAA;QACtB,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE;AACf,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa;AACzC,QAAA,MAAM,WAAW,GAAG,SAAS,CAAC,qBAAqB,EAAE;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE;AACpD,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE;QACvC,MAAM,GAAG,GAAG,CAAC;QAEb,IAAI,GAAG,GAAG,CAAC;QACX,IAAI,IAAI,GAAG,CAAC;AAEZ,QAAA,IAAI,QAAQ,KAAK,KAAK,EAAE;YACtB,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,GAAG;AAChD,YAAA,IAAI,GAAG,WAAW,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,CAAC;QACvE;AAAO,aAAA,IAAI,QAAQ,KAAK,QAAQ,EAAE;AAChC,YAAA,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,GAAG;AAC9B,YAAA,IAAI,GAAG,WAAW,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,CAAC;QACvE;AAAO,aAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AAC9B,YAAA,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC;YACrE,IAAI,GAAG,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,KAAK,GAAG,GAAG;QACnD;AAAO,aAAA,IAAI,QAAQ,KAAK,OAAO,EAAE;AAC/B,YAAA,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC;AACrE,YAAA,IAAI,GAAG,WAAW,CAAC,KAAK,GAAG,GAAG;QAChC;AAEA,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU;AACnC,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW;QAErC,IAAI,IAAI,GAAG,CAAC;YAAE,IAAI,GAAG,CAAC;QACtB,IAAI,IAAI,GAAG,WAAW,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,EAAE;YAC5C,IAAI,GAAG,SAAS,GAAG,WAAW,CAAC,KAAK,GAAG,CAAC;QAC1C;AACA,QAAA,IAAI,GAAG,GAAG,CAAC,EAAE;AACX,YAAA,IAAI,QAAQ,KAAK,KAAK,EAAE;AACtB,gBAAA,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,GAAG;YAChC;iBAAO;gBACL,GAAG,GAAG,CAAC;YACT;QACF;QACA,IAAI,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,UAAU,GAAG,CAAC,EAAE;AAC7C,YAAA,IAAI,QAAQ,KAAK,QAAQ,EAAE;gBACzB,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,GAAG;YAClD;iBAAO;gBACL,GAAG,GAAG,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC;YAC3C;QACF;QAEA,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO;QACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAA,EAAG,GAAG,CAAA,EAAA,CAAI;QAC/B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAA,EAAG,IAAI,CAAA,EAAA,CAAI;QACjC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG;IAC7B;IAEQ,yBAAyB,GAAA;QAC/B,IAAI,CAAC,sBAAsB,EAAE;QAC7B,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE;AAEhE,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;YACjC,MAAM,gBAAgB,GAAG,MAAK;gBAC5B,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,CAAC;AACD,YAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACrF,YAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC;AAEnD,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CACzB,MAAM,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAC/E,MAAM,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAC7D;AACH,QAAA,CAAC,CAAC;IACJ;IAEQ,sBAAsB,GAAA;AAC5B,QAAA,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,iBAAiB;AAAE,YAAA,MAAM,EAAE;AACrD,QAAA,IAAI,CAAC,iBAAiB,GAAG,EAAE;IAC7B;uGA3UW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAT,SAAS,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,YAAA,EAAA,QAAA,EAAA,YAAA,EAAA,QAAA,EAAA,SAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,EAAA,UAAA,EAAA,EAAA,uBAAA,EAAA,iBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAT,SAAS,EAAA,UAAA,EAAA,CAAA;kBAXrB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,IAAI,EAAE;AACJ,wBAAA,yBAAyB,EAAE,iBAAiB;AAC5C,wBAAA,cAAc,EAAE,QAAQ;AACxB,wBAAA,cAAc,EAAE,QAAQ;AACxB,wBAAA,WAAW,EAAE,QAAQ;AACrB,wBAAA,YAAY,EAAE,QAAQ;AACtB,wBAAA,kBAAkB,EAAE,kBAAkB;AACvC,qBAAA;AACF,iBAAA;;;ACnED;;AAEG;;;;"}
@@ -0,0 +1,17 @@
1
+ export * from '@ktortu/aaa/button';
2
+ export * from '@ktortu/aaa/card';
3
+ export * from '@ktortu/aaa/cdk';
4
+ export * from '@ktortu/aaa/dialog';
5
+ export * from '@ktortu/aaa/forms';
6
+ export * from '@ktortu/aaa/menu';
7
+ export * from '@ktortu/aaa/tabs';
8
+ export * from '@ktortu/aaa/tooltip';
9
+
10
+ /*
11
+ * Public API Surface of @ktortu/aaa
12
+ */
13
+
14
+ /**
15
+ * Generated bundle index. Do not edit.
16
+ */
17
+ //# sourceMappingURL=ktortu-aaa.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -0,0 +1,55 @@
1
+ @layer kt-aaa.components {
2
+ :host {
3
+ display: block;
4
+ }
5
+
6
+ .kt-checkbox-group-field {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--field-gap, 0.375rem);
10
+ }
11
+
12
+ /* Légende du groupe (référencée par aria-labelledby — un groupe n'a pas un <label for> unique). */
13
+ .kt-checkbox-group__legend {
14
+ font-size: var(--field-label-font-size, 0.875rem);
15
+ font-weight: var(--field-label-weight, 500);
16
+ color: var(--field-label-color, inherit);
17
+ }
18
+
19
+ .kt-checkbox-group__required {
20
+ margin-inline-start: 0.125rem;
21
+ color: var(--field-required-color, var(--kt-danger, #8c1d18));
22
+ }
23
+
24
+ /* Disposition des options : pilotable par token (colonne par défaut, ligne possible). */
25
+ .kt-checkbox-group__options {
26
+ display: flex;
27
+ flex-direction: var(--checkbox-group-direction, column);
28
+ flex-wrap: wrap;
29
+ gap: var(--checkbox-group-gap, 0.25rem);
30
+ }
31
+
32
+ .kt-checkbox-group__hint {
33
+ margin: 0;
34
+ font-size: var(--field-hint-font-size, 0.8125rem);
35
+ color: var(--field-hint-color, #474747);
36
+ }
37
+
38
+ .kt-checkbox-group__error {
39
+ margin: 0;
40
+ display: flex;
41
+ flex-direction: column;
42
+ font-size: var(--field-hint-font-size, 0.8125rem);
43
+ color: var(--field-error-color, #8c1d18);
44
+ }
45
+
46
+ .kt-checkbox-group__error-message {
47
+ animation: var(--field-error-animation, none);
48
+ }
49
+
50
+ @media (prefers-reduced-motion: reduce) {
51
+ .kt-checkbox-group__error-message {
52
+ animation: none;
53
+ }
54
+ }
55
+ }