@ktortu/aaa 0.9.0 → 0.9.2

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 (54) hide show
  1. package/README.md +5 -3
  2. package/fesm2022/ktortu-aaa-button.mjs +10 -2
  3. package/fesm2022/ktortu-aaa-button.mjs.map +1 -1
  4. package/fesm2022/ktortu-aaa-card.mjs +14 -5
  5. package/fesm2022/ktortu-aaa-card.mjs.map +1 -1
  6. package/fesm2022/ktortu-aaa-cdk.mjs +50 -2
  7. package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
  8. package/fesm2022/ktortu-aaa-dialog.mjs +80 -39
  9. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
  10. package/fesm2022/ktortu-aaa-disclosure.mjs +201 -0
  11. package/fesm2022/ktortu-aaa-disclosure.mjs.map +1 -0
  12. package/fesm2022/ktortu-aaa-forms.mjs +525 -149
  13. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
  14. package/fesm2022/ktortu-aaa-i18n.mjs +27 -2
  15. package/fesm2022/ktortu-aaa-i18n.mjs.map +1 -1
  16. package/fesm2022/ktortu-aaa-menu.mjs.map +1 -1
  17. package/fesm2022/ktortu-aaa-progress-bar.mjs +91 -0
  18. package/fesm2022/ktortu-aaa-progress-bar.mjs.map +1 -0
  19. package/fesm2022/ktortu-aaa-snackbar.mjs +478 -0
  20. package/fesm2022/ktortu-aaa-snackbar.mjs.map +1 -0
  21. package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
  22. package/fesm2022/ktortu-aaa-tooltip.mjs +20 -30
  23. package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
  24. package/fesm2022/ktortu-aaa.mjs +2 -0
  25. package/fesm2022/ktortu-aaa.mjs.map +1 -1
  26. package/forms/checkbox/checkbox-group.css +0 -8
  27. package/forms/chips/chip-list.css +5 -0
  28. package/forms/field/field.css +16 -0
  29. package/forms/radio/radio-group.css +1 -9
  30. package/forms/styles/field-box.css +14 -6
  31. package/forms/styles/field-pending.css +46 -0
  32. package/forms/styles/select-panel.css +4 -0
  33. package/package.json +13 -1
  34. package/progress-bar/progress-bar.css +127 -0
  35. package/snackbar/snackbar-tokens.css +53 -0
  36. package/snackbar/snackbar.css +175 -0
  37. package/styles/disclosure.css +6 -0
  38. package/styles/forms.css +1 -0
  39. package/styles/progress-bar.css +5 -0
  40. package/styles/snackbar.css +9 -0
  41. package/styles/styles.css +3 -0
  42. package/themes/theme-cyberpunk.css +11 -0
  43. package/tooltip/tooltip.css +1 -1
  44. package/types/ktortu-aaa-button.d.ts +2 -0
  45. package/types/ktortu-aaa-card.d.ts +3 -0
  46. package/types/ktortu-aaa-cdk.d.ts +27 -1
  47. package/types/ktortu-aaa-dialog.d.ts +89 -34
  48. package/types/ktortu-aaa-disclosure.d.ts +112 -0
  49. package/types/ktortu-aaa-forms.d.ts +238 -30
  50. package/types/ktortu-aaa-i18n.d.ts +3 -0
  51. package/types/ktortu-aaa-progress-bar.d.ts +27 -0
  52. package/types/ktortu-aaa-snackbar.d.ts +218 -0
  53. package/types/ktortu-aaa-tooltip.d.ts +0 -1
  54. package/types/ktortu-aaa.d.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ktortu-aaa-tabs.mjs","sources":["../../../../projects/ktortu/aaa/tabs/tab-scroller.ts","../../../../projects/ktortu/aaa/tabs/tabs-config.ts","../../../../projects/ktortu/aaa/tabs/tab-scroller-pager.ts","../../../../projects/ktortu/aaa/tabs/tab-scroll.ts","../../../../projects/ktortu/aaa/tabs/ktortu-aaa-tabs.ts"],"sourcesContent":["import {\n Directive,\n DOCUMENT,\n DestroyRef,\n ElementRef,\n afterNextRender,\n afterRenderEffect,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { TabList } from '@angular/aria/tabs';\n\n/** Cible de défilement calculée en phase de lecture, appliquée en phase d'écriture. */\ntype ScrollTarget = { axis: 'left' | 'top'; value: number };\n\n/** Métriques de débordement de la liste d'onglets, mesurées de façon impérative. */\ninterface ScrollMetrics {\n /** Reste-t-il du contenu hors-champ côté début (gauche en LTR / droite en RTL ; haut si vertical) ? */\n canStart: boolean;\n /** Reste-t-il du contenu hors-champ côté fin ? */\n canEnd: boolean;\n /** La liste déborde-t-elle (taille de défilement > taille visible) ? */\n overflowing: boolean;\n /** Axe courant. */\n vertical: boolean;\n}\n\nconst EMPTY_METRICS: ScrollMetrics = { canStart: false, canEnd: false, overflowing: false, vertical: false };\n\n/** Tolérance d'1px : arrondis sub-pixel, zoom navigateur. */\nconst EPS = 1;\n\n/** Fraction de la zone visible parcourue par un « page » de pagination (chevauchement d'un onglet). */\nconst PAGE_RATIO = 0.8;\n\n/**\n * Pilote le **débordement** d'une liste d'onglets `@angular/aria/tabs` (cf. tabs.css). Deux rôles :\n *\n * 1. **Scroll-into-view** : amène l'onglet sélectionné dans la vue au montage et lors d'un changement\n * de sélection programmatique (ce que le CSS seul ne fait pas), en respectant `prefers-reduced-motion`.\n * 2. **Pagination** : expose un état réactif (`canScrollStart()`, `canScrollEnd()`, `overflowing()`,\n * `orientation()`) et une méthode `scrollByPage()`, pour brancher des boutons chevrons (cf. le\n * composant clé-en-main `KtTabScrollerPager`, ou des boutons custom via `exportAs: 'ktTabScroller'`).\n *\n * Opt-in, à poser sur `[ngTabList]` :\n *\n * @example\n * ```html\n * <ul ngTabList ktTabScroller #s=\"ktTabScroller\" [(selectedTab)]=\"tab\"> … </ul>\n * <button (click)=\"s.scrollByPage('start')\" [disabled]=\"!s.canScrollStart()\">‹</button>\n * ```\n */\n@Directive({\n selector: '[ngTabList][ktTabScroller]',\n exportAs: 'ktTabScroller',\n host: {\n // Marqueur CSS : pagination réactive active → la scrollbar native est masquée (cf. tabs.css).\n '[attr.data-kt-tab-scroller]': '\"\"',\n },\n})\nexport class KtTabScroller {\n private readonly list = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly tabList = inject(TabList);\n private readonly doc = inject(DOCUMENT);\n private readonly destroyRef = inject(DestroyRef);\n /** Préférence « réduire les animations », lue à chaud (absente possible en SSR/jsdom). */\n private readonly reducedMotion = this.doc.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)');\n\n /**\n * Métriques de débordement. Mises à jour UNIQUEMENT depuis des callbacks navigateur\n * (`afterNextRender`, `scroll`, `ResizeObserver`, `MutationObserver`) — jamais depuis le corps\n * d'un effet réactif, pour rester conforme (pas d'écriture de signal dans un effet).\n */\n private readonly metrics = signal<ScrollMetrics>(EMPTY_METRICS);\n\n /** Reste-t-il du contenu hors-champ côté début (à brancher sur le bouton « précédent ») ? */\n readonly canScrollStart = computed(() => this.metrics().canStart);\n /** Reste-t-il du contenu hors-champ côté fin (à brancher sur le bouton « suivant ») ? */\n readonly canScrollEnd = computed(() => this.metrics().canEnd);\n /** La liste déborde-t-elle ? (utile pour masquer toute la barre de pagination). */\n readonly overflowing = computed(() => this.metrics().overflowing);\n /** Axe courant, dérivé de l'orientation `@angular/aria`. */\n readonly orientation = computed<'horizontal' | 'vertical'>(() =>\n this.metrics().vertical ? 'vertical' : 'horizontal',\n );\n\n constructor() {\n // 1. Scroll-into-view (phasé : mesure en `earlyRead`, scroll en `write`, pas de reflow forcé).\n // Le `scrollTo` émet un événement `scroll` → remeasure via le listener (aucun `set` ici).\n afterRenderEffect({\n earlyRead: () => this.computeScrollTarget(),\n write: (target) => {\n const t = target();\n if (!t) return;\n this.list.scrollTo({ [t.axis]: t.value, behavior: this.scrollBehavior() });\n },\n });\n\n // 2. Mesure initiale + observateurs (browser-only ; `afterNextRender` ne tourne pas en SSR).\n afterNextRender(() => {\n const view = this.doc.defaultView;\n if (!view) return;\n this.remeasure();\n\n const onScroll = () => this.remeasure();\n this.list.addEventListener('scroll', onScroll, { passive: true });\n\n // ResizeObserver : viewport ET contenu (les onglets qui changent de largeur). Référencé en\n // global (jamais instancié en SSR puisque dans `afterNextRender`).\n const ro = new ResizeObserver(() => this.remeasure());\n const observeAll = () => {\n ro.disconnect();\n ro.observe(this.list);\n for (const child of Array.from(this.list.children)) ro.observe(child);\n };\n observeAll();\n\n // MutationObserver : onglets ajoutés/retirés (@for) → re-observer + remeasure.\n const mo = new MutationObserver(() => {\n observeAll();\n this.remeasure();\n });\n mo.observe(this.list, { childList: true });\n\n this.destroyRef.onDestroy(() => {\n this.list.removeEventListener('scroll', onScroll);\n ro.disconnect();\n mo.disconnect();\n });\n });\n }\n\n /**\n * Fait défiler d'environ une « page » (≈ {@link PAGE_RATIO} de la zone visible) vers le début ou la\n * fin. `behavior` respecte `prefers-reduced-motion`. Le navigateur sature au min/max ; les boutons\n * câblés sont `disabled` aux extrémités, donc l'appel n'a pas lieu à vide.\n */\n scrollByPage(dir: 'start' | 'end'): void {\n const el = this.list;\n const sign = dir === 'end' ? 1 : -1;\n if (this.metrics().vertical) {\n el.scrollBy({ top: sign * el.clientHeight * PAGE_RATIO, behavior: this.scrollBehavior() });\n return;\n }\n // RTL : le sens d'écriture inverse le signe de `scrollLeft`.\n const rtlSign = this.isRtl() ? -1 : 1;\n el.scrollBy({ left: sign * rtlSign * el.clientWidth * PAGE_RATIO, behavior: this.scrollBehavior() });\n }\n\n /** Met à jour le signal de métriques. Appelé depuis des callbacks navigateur (jamais un effet). */\n private remeasure(): void {\n this.metrics.set(this.measure());\n }\n\n /** Mesure le débordement (lecture pure de géométrie, n'écrit rien). */\n private measure(): ScrollMetrics {\n const el = this.list;\n const vertical = this.isVertical();\n\n if (vertical) {\n const { scrollTop, scrollHeight, clientHeight } = el;\n const max = scrollHeight - clientHeight;\n return { vertical: true, overflowing: max > EPS, canStart: scrollTop > EPS, canEnd: scrollTop < max - EPS };\n }\n\n const { scrollLeft, scrollWidth, clientWidth } = el;\n const max = scrollWidth - clientWidth;\n const rtl = this.isRtl();\n // Distances logiques indépendantes du signe de `scrollLeft` (négatif en RTL sur les navigateurs récents).\n const fromStart = rtl ? -scrollLeft : scrollLeft;\n const fromEnd = max - Math.abs(scrollLeft);\n return { vertical: false, overflowing: max > EPS, canStart: fromStart > EPS, canEnd: fromEnd > EPS };\n }\n\n private isVertical(): boolean {\n return (\n this.list.getAttribute('aria-orientation') === 'vertical' || this.list.getAttribute('orientation') === 'vertical'\n );\n }\n\n private isRtl(): boolean {\n return this.doc.defaultView?.getComputedStyle(this.list).direction === 'rtl';\n }\n\n /**\n * `auto` si l'utilisateur a demandé à réduire les animations (WCAG 2.3.3 AAA), `smooth` sinon.\n * Passer un `behavior` explicite à `scrollTo`/`scrollBy` écrase la propriété CSS `scroll-behavior`,\n * d'où la nécessité de répliquer ici la décision que le CSS prend via `prefers-reduced-motion`.\n */\n private scrollBehavior(): ScrollBehavior {\n return this.reducedMotion?.matches ? 'auto' : 'smooth';\n }\n\n /**\n * Calcule l'offset à atteindre pour amener l'onglet actif dans la vue, ou `null` s'il est déjà\n * visible (ou s'il n'y a aucun onglet sélectionné). Lit `selectedTab()` → dépendance réactive.\n */\n private computeScrollTarget(): ScrollTarget | null {\n const selected = this.tabList.findTab(this.tabList.selectedTab())?.element;\n if (!selected) return null;\n\n const container = this.list;\n if (this.isVertical()) {\n const selectedTop = selected.offsetTop;\n const selectedBottom = selectedTop + selected.offsetHeight;\n const containerTop = container.scrollTop;\n const containerBottom = containerTop + container.clientHeight;\n\n if (selectedTop < containerTop) return { axis: 'top', value: selectedTop };\n if (selectedBottom > containerBottom) return { axis: 'top', value: selectedBottom - container.clientHeight };\n return null;\n }\n\n const selectedLeft = selected.offsetLeft;\n const selectedRight = selectedLeft + selected.offsetWidth;\n const containerLeft = container.scrollLeft;\n const containerRight = containerLeft + container.clientWidth;\n\n if (selectedLeft < containerLeft) return { axis: 'left', value: selectedLeft };\n if (selectedRight > containerRight) return { axis: 'left', value: selectedRight - container.clientWidth };\n return null;\n }\n}\n","import { InjectionToken } from '@angular/core';\n\n/** Défauts applicables à tous les `kt-tab-scroller` (surchargeables par instance via les inputs).\n Lib neutre i18n : les textes sont fournis par le consommateur (ici en une fois).\n Fourni en `Partial` : un consommateur n'override que ce qu'il veut.\n Calqué sur `KT_FIELD_CONFIG`/`KT_CHIPS_CONFIG`. */\nexport interface KtTabsConfig {\n /** `aria-label` du chevron de pagination « onglets précédents ». Défaut : `'Previous tabs'`. */\n previousLabel: string;\n /** `aria-label` du chevron de pagination « onglets suivants ». Défaut : `'Next tabs'`. */\n nextLabel: string;\n}\n\nexport const KT_TABS_CONFIG = new InjectionToken<Partial<KtTabsConfig>>('KT_TABS_CONFIG');\n","import {\n ChangeDetectionStrategy,\n Component,\n DOCUMENT,\n ElementRef,\n afterNextRender,\n computed,\n contentChild,\n inject,\n input,\n signal,\n} from '@angular/core';\n\nimport { KtButton } from '@ktortu/aaa/button';\nimport { KtTabScroller } from './tab-scroller';\nimport { KT_TABS_CONFIG } from './tabs-config';\n\n/**\n * Composant clé-en-main : enveloppe une liste d'onglets `@angular/aria/tabs` débordante de deux\n * **chevrons de pagination** accessibles (style Material). Il ne contient aucune logique propre :\n * il lit l'état réactif de la directive headless {@link KtTabScroller} (à poser sur le `ngTabList`\n * projeté) et câble deux boutons {@link KtButton}.\n *\n * @example\n * ```html\n * <kt-tab-scroller>\n * <ul ngTabList ktTabScroller [(selectedTab)]=\"tab\">\n * @for (t of tabs; track t) { <li ngTab [value]=\"t\">…</li> }\n * </ul>\n * </kt-tab-scroller>\n * ```\n */\n@Component({\n selector: 'kt-tab-scroller',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton],\n host: {\n '[attr.data-orientation]': 'scroller().orientation()',\n '[attr.data-overflowing]': 'scroller().overflowing() ? \"\" : null',\n },\n template: `\n <button\n ktButton\n type=\"button\"\n mode=\"text\"\n iconOnly\n class=\"kt-tab-scroller__chevron kt-tab-scroller__chevron--start\"\n [icon]=\"startIcon()\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"!scroller().canScrollStart()\"\n (click)=\"scroller().scrollByPage('start')\"\n ></button>\n\n <div class=\"kt-tab-scroller__viewport\">\n <ng-content select=\"[ngTabList]\" />\n </div>\n\n <button\n ktButton\n type=\"button\"\n mode=\"text\"\n iconOnly\n class=\"kt-tab-scroller__chevron kt-tab-scroller__chevron--end\"\n [icon]=\"endIcon()\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"!scroller().canScrollEnd()\"\n (click)=\"scroller().scrollByPage('end')\"\n ></button>\n `,\n})\nexport class KtTabScrollerPager {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly doc = inject(DOCUMENT);\n\n /** Défauts d'app (provider global `KT_TABS_CONFIG`) ; les inputs ci-dessous priment dessus. */\n private readonly config = inject(KT_TABS_CONFIG, { optional: true });\n\n /** La directive headless posée sur le `ngTabList` projeté (`descendants` car dans le viewport). */\n protected readonly scroller = contentChild.required(KtTabScroller, { descendants: true });\n\n /** Sens de lecture (figé au montage : le RTL inverse les chevrons gauche/droite). */\n private readonly dir = signal<'ltr' | 'rtl'>('ltr');\n\n protected readonly startIcon = computed(() => {\n if (this.scroller().orientation() === 'vertical') return 'expand_less';\n return this.dir() === 'rtl' ? 'chevron_right' : 'chevron_left';\n });\n protected readonly endIcon = computed(() => {\n if (this.scroller().orientation() === 'vertical') return 'expand_more';\n return this.dir() === 'rtl' ? 'chevron_left' : 'chevron_right';\n });\n\n /**\n * Noms accessibles des chevrons (`aria-label`). Résolution `input ?? KT_TABS_CONFIG ?? défaut`,\n * comme partout dans la lib (cf. `KT_FIELD_CONFIG`/`KT_CHIPS_CONFIG`). Défauts en anglais : lib\n * neutre i18n, les textes sont fournis par le consommateur (provider global ou binding).\n */\n /**\n * `aria-label` du chevron « onglets précédents ».\n * @default config.previousLabel ?? 'Previous tabs'\n */\n readonly previousLabel = input(this.config?.previousLabel ?? 'Previous tabs');\n /**\n * `aria-label` du chevron « onglets suivants ».\n * @default config.nextLabel ?? 'Next tabs'\n */\n readonly nextLabel = input(this.config?.nextLabel ?? 'Next tabs');\n\n constructor() {\n afterNextRender(() => {\n if (this.doc.defaultView?.getComputedStyle(this.host).direction === 'rtl') this.dir.set('rtl');\n });\n }\n}\n","import { Directive } from '@angular/core';\nimport { KtTabScroller } from './tab-scroller';\n\n/**\n * @deprecated Utilisez {@link KtTabScroller} (sélecteur `[ktTabScroller]`) : même défilement de\n * l'onglet sélectionné dans la vue, plus la pagination par chevrons. `ktTabScroll` reste un **alias\n * fonctionnel** (il applique `KtTabScroller` comme directive hôte) et sera retiré dans une version\n * majeure ultérieure.\n *\n * Note : depuis cette version, une liste pilotée par `ktTabScroll`/`ktTabScroller` masque sa\n * scrollbar native par défaut (les chevrons / ombres prennent le relais). Réafficher la barre via\n * `--tab-scroller-scrollbar: thin`.\n */\n@Directive({\n selector: '[ngTabList][ktTabScroll]',\n exportAs: 'ktTabScroll',\n hostDirectives: [KtTabScroller],\n})\nexport class KtTabScroll {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KtTabScroller"],"mappings":"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"}
1
+ {"version":3,"file":"ktortu-aaa-tabs.mjs","sources":["../../../../projects/ktortu/aaa/tabs/tab-scroller.ts","../../../../projects/ktortu/aaa/tabs/tabs-config.ts","../../../../projects/ktortu/aaa/tabs/tab-scroller-pager.ts","../../../../projects/ktortu/aaa/tabs/tab-scroll.ts","../../../../projects/ktortu/aaa/tabs/ktortu-aaa-tabs.ts"],"sourcesContent":["import {\n Directive,\n DOCUMENT,\n DestroyRef,\n ElementRef,\n afterNextRender,\n afterRenderEffect,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { TabList } from '@angular/aria/tabs';\n\n/** Cible de défilement calculée en phase de lecture, appliquée en phase d'écriture. */\ninterface ScrollTarget {\n axis: 'left' | 'top';\n value: number;\n}\n\n/** Métriques de débordement de la liste d'onglets, mesurées de façon impérative. */\ninterface ScrollMetrics {\n /** Reste-t-il du contenu hors-champ côté début (gauche en LTR / droite en RTL ; haut si vertical) ? */\n canStart: boolean;\n /** Reste-t-il du contenu hors-champ côté fin ? */\n canEnd: boolean;\n /** La liste déborde-t-elle (taille de défilement > taille visible) ? */\n overflowing: boolean;\n /** Axe courant. */\n vertical: boolean;\n}\n\nconst EMPTY_METRICS: ScrollMetrics = { canStart: false, canEnd: false, overflowing: false, vertical: false };\n\n/** Tolérance d'1px : arrondis sub-pixel, zoom navigateur. */\nconst EPS = 1;\n\n/** Fraction de la zone visible parcourue par un « page » de pagination (chevauchement d'un onglet). */\nconst PAGE_RATIO = 0.8;\n\n/**\n * Pilote le **débordement** d'une liste d'onglets `@angular/aria/tabs` (cf. tabs.css). Deux rôles :\n *\n * 1. **Scroll-into-view** : amène l'onglet sélectionné dans la vue au montage et lors d'un changement\n * de sélection programmatique (ce que le CSS seul ne fait pas), en respectant `prefers-reduced-motion`.\n * 2. **Pagination** : expose un état réactif (`canScrollStart()`, `canScrollEnd()`, `overflowing()`,\n * `orientation()`) et une méthode `scrollByPage()`, pour brancher des boutons chevrons (cf. le\n * composant clé-en-main `KtTabScrollerPager`, ou des boutons custom via `exportAs: 'ktTabScroller'`).\n *\n * Opt-in, à poser sur `[ngTabList]` :\n *\n * @example\n * ```html\n * <ul ngTabList ktTabScroller #s=\"ktTabScroller\" [(selectedTab)]=\"tab\"> … </ul>\n * <button (click)=\"s.scrollByPage('start')\" [disabled]=\"!s.canScrollStart()\">‹</button>\n * ```\n */\n@Directive({\n selector: '[ngTabList][ktTabScroller]',\n exportAs: 'ktTabScroller',\n host: {\n // Marqueur CSS : pagination réactive active → la scrollbar native est masquée (cf. tabs.css).\n '[attr.data-kt-tab-scroller]': '\"\"',\n },\n})\nexport class KtTabScroller {\n private readonly list = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly tabList = inject(TabList);\n private readonly doc = inject(DOCUMENT);\n private readonly destroyRef = inject(DestroyRef);\n /** Préférence « réduire les animations », lue à chaud (absente possible en SSR/jsdom). */\n private readonly reducedMotion = this.doc.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)');\n\n /**\n * Métriques de débordement. Mises à jour UNIQUEMENT depuis des callbacks navigateur\n * (`afterNextRender`, `scroll`, `ResizeObserver`, `MutationObserver`) — jamais depuis le corps\n * d'un effet réactif, pour rester conforme (pas d'écriture de signal dans un effet).\n */\n private readonly metrics = signal<ScrollMetrics>(EMPTY_METRICS);\n\n /** Reste-t-il du contenu hors-champ côté début (à brancher sur le bouton « précédent ») ? */\n readonly canScrollStart = computed(() => this.metrics().canStart);\n /** Reste-t-il du contenu hors-champ côté fin (à brancher sur le bouton « suivant ») ? */\n readonly canScrollEnd = computed(() => this.metrics().canEnd);\n /** La liste déborde-t-elle ? (utile pour masquer toute la barre de pagination). */\n readonly overflowing = computed(() => this.metrics().overflowing);\n /** Axe courant, dérivé de l'orientation `@angular/aria`. */\n readonly orientation = computed<'horizontal' | 'vertical'>(() =>\n this.metrics().vertical ? 'vertical' : 'horizontal',\n );\n\n constructor() {\n // 1. Scroll-into-view (phasé : mesure en `earlyRead`, scroll en `write`, pas de reflow forcé).\n // Le `scrollTo` émet un événement `scroll` → remeasure via le listener (aucun `set` ici).\n afterRenderEffect({\n earlyRead: () => this.computeScrollTarget(),\n write: (target) => {\n const t = target();\n if (!t) return;\n this.list.scrollTo({ [t.axis]: t.value, behavior: this.scrollBehavior() });\n },\n });\n\n // 2. Mesure initiale + observateurs (browser-only ; `afterNextRender` ne tourne pas en SSR).\n afterNextRender(() => {\n const view = this.doc.defaultView;\n if (!view) return;\n this.remeasure();\n\n const onScroll = () => this.remeasure();\n this.list.addEventListener('scroll', onScroll, { passive: true });\n\n // ResizeObserver : viewport ET contenu (les onglets qui changent de largeur). Référencé en\n // global (jamais instancié en SSR puisque dans `afterNextRender`).\n const ro = new ResizeObserver(() => this.remeasure());\n const observeAll = () => {\n ro.disconnect();\n ro.observe(this.list);\n for (const child of Array.from(this.list.children)) ro.observe(child);\n };\n observeAll();\n\n // MutationObserver : onglets ajoutés/retirés (@for) → re-observer + remeasure.\n const mo = new MutationObserver(() => {\n observeAll();\n this.remeasure();\n });\n mo.observe(this.list, { childList: true });\n\n this.destroyRef.onDestroy(() => {\n this.list.removeEventListener('scroll', onScroll);\n ro.disconnect();\n mo.disconnect();\n });\n });\n }\n\n /**\n * Fait défiler d'environ une « page » (≈ {@link PAGE_RATIO} de la zone visible) vers le début ou la\n * fin. `behavior` respecte `prefers-reduced-motion`. Le navigateur sature au min/max ; les boutons\n * câblés sont `disabled` aux extrémités, donc l'appel n'a pas lieu à vide.\n */\n scrollByPage(dir: 'start' | 'end'): void {\n const el = this.list;\n const sign = dir === 'end' ? 1 : -1;\n if (this.metrics().vertical) {\n el.scrollBy({ top: sign * el.clientHeight * PAGE_RATIO, behavior: this.scrollBehavior() });\n return;\n }\n // RTL : le sens d'écriture inverse le signe de `scrollLeft`.\n const rtlSign = this.isRtl() ? -1 : 1;\n el.scrollBy({ left: sign * rtlSign * el.clientWidth * PAGE_RATIO, behavior: this.scrollBehavior() });\n }\n\n /** Met à jour le signal de métriques. Appelé depuis des callbacks navigateur (jamais un effet). */\n private remeasure(): void {\n this.metrics.set(this.measure());\n }\n\n /** Mesure le débordement (lecture pure de géométrie, n'écrit rien). */\n private measure(): ScrollMetrics {\n const el = this.list;\n const vertical = this.isVertical();\n\n if (vertical) {\n const { scrollTop, scrollHeight, clientHeight } = el;\n const max = scrollHeight - clientHeight;\n return { vertical: true, overflowing: max > EPS, canStart: scrollTop > EPS, canEnd: scrollTop < max - EPS };\n }\n\n const { scrollLeft, scrollWidth, clientWidth } = el;\n const max = scrollWidth - clientWidth;\n const rtl = this.isRtl();\n // Distances logiques indépendantes du signe de `scrollLeft` (négatif en RTL sur les navigateurs récents).\n const fromStart = rtl ? -scrollLeft : scrollLeft;\n const fromEnd = max - Math.abs(scrollLeft);\n return { vertical: false, overflowing: max > EPS, canStart: fromStart > EPS, canEnd: fromEnd > EPS };\n }\n\n private isVertical(): boolean {\n return (\n this.list.getAttribute('aria-orientation') === 'vertical' || this.list.getAttribute('orientation') === 'vertical'\n );\n }\n\n private isRtl(): boolean {\n return this.doc.defaultView?.getComputedStyle(this.list).direction === 'rtl';\n }\n\n /**\n * `auto` si l'utilisateur a demandé à réduire les animations (WCAG 2.3.3 AAA), `smooth` sinon.\n * Passer un `behavior` explicite à `scrollTo`/`scrollBy` écrase la propriété CSS `scroll-behavior`,\n * d'où la nécessité de répliquer ici la décision que le CSS prend via `prefers-reduced-motion`.\n */\n private scrollBehavior(): ScrollBehavior {\n return this.reducedMotion?.matches ? 'auto' : 'smooth';\n }\n\n /**\n * Calcule l'offset à atteindre pour amener l'onglet actif dans la vue, ou `null` s'il est déjà\n * visible (ou s'il n'y a aucun onglet sélectionné). Lit `selectedTab()` → dépendance réactive.\n */\n private computeScrollTarget(): ScrollTarget | null {\n const selected = this.tabList.findTab(this.tabList.selectedTab())?.element;\n if (!selected) return null;\n\n const container = this.list;\n if (this.isVertical()) {\n const selectedTop = selected.offsetTop;\n const selectedBottom = selectedTop + selected.offsetHeight;\n const containerTop = container.scrollTop;\n const containerBottom = containerTop + container.clientHeight;\n\n if (selectedTop < containerTop) return { axis: 'top', value: selectedTop };\n if (selectedBottom > containerBottom) return { axis: 'top', value: selectedBottom - container.clientHeight };\n return null;\n }\n\n const selectedLeft = selected.offsetLeft;\n const selectedRight = selectedLeft + selected.offsetWidth;\n const containerLeft = container.scrollLeft;\n const containerRight = containerLeft + container.clientWidth;\n\n if (selectedLeft < containerLeft) return { axis: 'left', value: selectedLeft };\n if (selectedRight > containerRight) return { axis: 'left', value: selectedRight - container.clientWidth };\n return null;\n }\n}\n","import { InjectionToken } from '@angular/core';\n\n/** Défauts applicables à tous les `kt-tab-scroller` (surchargeables par instance via les inputs).\n Lib neutre i18n : les textes sont fournis par le consommateur (ici en une fois).\n Fourni en `Partial` : un consommateur n'override que ce qu'il veut.\n Calqué sur `KT_FIELD_CONFIG`/`KT_CHIPS_CONFIG`. */\nexport interface KtTabsConfig {\n /** `aria-label` du chevron de pagination « onglets précédents ». Défaut : `'Previous tabs'`. */\n previousLabel: string;\n /** `aria-label` du chevron de pagination « onglets suivants ». Défaut : `'Next tabs'`. */\n nextLabel: string;\n}\n\nexport const KT_TABS_CONFIG = new InjectionToken<Partial<KtTabsConfig>>('KT_TABS_CONFIG');\n","import {\n ChangeDetectionStrategy,\n Component,\n DOCUMENT,\n ElementRef,\n afterNextRender,\n computed,\n contentChild,\n inject,\n input,\n signal,\n} from '@angular/core';\n\nimport { KtButton } from '@ktortu/aaa/button';\nimport { KtTabScroller } from './tab-scroller';\nimport { KT_TABS_CONFIG } from './tabs-config';\n\n/**\n * Composant clé-en-main : enveloppe une liste d'onglets `@angular/aria/tabs` débordante de deux\n * **chevrons de pagination** accessibles (style Material). Il ne contient aucune logique propre :\n * il lit l'état réactif de la directive headless {@link KtTabScroller} (à poser sur le `ngTabList`\n * projeté) et câble deux boutons {@link KtButton}.\n *\n * @example\n * ```html\n * <kt-tab-scroller>\n * <ul ngTabList ktTabScroller [(selectedTab)]=\"tab\">\n * @for (t of tabs; track t) { <li ngTab [value]=\"t\">…</li> }\n * </ul>\n * </kt-tab-scroller>\n * ```\n */\n@Component({\n selector: 'kt-tab-scroller',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton],\n host: {\n '[attr.data-orientation]': 'scroller().orientation()',\n '[attr.data-overflowing]': 'scroller().overflowing() ? \"\" : null',\n },\n template: `\n <button\n ktButton\n type=\"button\"\n mode=\"text\"\n iconOnly\n class=\"kt-tab-scroller__chevron kt-tab-scroller__chevron--start\"\n [icon]=\"startIcon()\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"!scroller().canScrollStart()\"\n (click)=\"scroller().scrollByPage('start')\"\n ></button>\n\n <div class=\"kt-tab-scroller__viewport\">\n <ng-content select=\"[ngTabList]\" />\n </div>\n\n <button\n ktButton\n type=\"button\"\n mode=\"text\"\n iconOnly\n class=\"kt-tab-scroller__chevron kt-tab-scroller__chevron--end\"\n [icon]=\"endIcon()\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"!scroller().canScrollEnd()\"\n (click)=\"scroller().scrollByPage('end')\"\n ></button>\n `,\n})\nexport class KtTabScrollerPager {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly doc = inject(DOCUMENT);\n\n /** Défauts d'app (provider global `KT_TABS_CONFIG`) ; les inputs ci-dessous priment dessus. */\n private readonly config = inject(KT_TABS_CONFIG, { optional: true });\n\n /** La directive headless posée sur le `ngTabList` projeté (`descendants` car dans le viewport). */\n protected readonly scroller = contentChild.required(KtTabScroller, { descendants: true });\n\n /** Sens de lecture (figé au montage : le RTL inverse les chevrons gauche/droite). */\n private readonly dir = signal<'ltr' | 'rtl'>('ltr');\n\n protected readonly startIcon = computed(() => {\n if (this.scroller().orientation() === 'vertical') return 'expand_less';\n return this.dir() === 'rtl' ? 'chevron_right' : 'chevron_left';\n });\n protected readonly endIcon = computed(() => {\n if (this.scroller().orientation() === 'vertical') return 'expand_more';\n return this.dir() === 'rtl' ? 'chevron_left' : 'chevron_right';\n });\n\n /**\n * Noms accessibles des chevrons (`aria-label`). Résolution `input ?? KT_TABS_CONFIG ?? défaut`,\n * comme partout dans la lib (cf. `KT_FIELD_CONFIG`/`KT_CHIPS_CONFIG`). Défauts en anglais : lib\n * neutre i18n, les textes sont fournis par le consommateur (provider global ou binding).\n */\n /**\n * `aria-label` du chevron « onglets précédents ».\n * @default config.previousLabel ?? 'Previous tabs'\n */\n readonly previousLabel = input(this.config?.previousLabel ?? 'Previous tabs');\n /**\n * `aria-label` du chevron « onglets suivants ».\n * @default config.nextLabel ?? 'Next tabs'\n */\n readonly nextLabel = input(this.config?.nextLabel ?? 'Next tabs');\n\n constructor() {\n afterNextRender(() => {\n if (this.doc.defaultView?.getComputedStyle(this.host).direction === 'rtl') this.dir.set('rtl');\n });\n }\n}\n","import { Directive } from '@angular/core';\nimport { KtTabScroller } from './tab-scroller';\n\n/**\n * @deprecated Utilisez {@link KtTabScroller} (sélecteur `[ktTabScroller]`) : même défilement de\n * l'onglet sélectionné dans la vue, plus la pagination par chevrons. `ktTabScroll` reste un **alias\n * fonctionnel** (il applique `KtTabScroller` comme directive hôte) et sera retiré dans une version\n * majeure ultérieure.\n *\n * Note : depuis cette version, une liste pilotée par `ktTabScroll`/`ktTabScroller` masque sa\n * scrollbar native par défaut (les chevrons / ombres prennent le relais). Réafficher la barre via\n * `--tab-scroller-scrollbar: thin`.\n */\n@Directive({\n selector: '[ngTabList][ktTabScroll]',\n exportAs: 'ktTabScroll',\n hostDirectives: [KtTabScroller],\n})\nexport class KtTabScroll {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KtTabScroller"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { DOCUMENT, isPlatformBrowser } from '@angular/common';
2
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';
3
+ import { InjectionToken, inject, ElementRef, Renderer2, ViewContainerRef, PLATFORM_ID, input, booleanAttribute, computed, signal, effect, TemplateRef, isDevMode, Directive } from '@angular/core';
4
4
  import { KtIdGenerator } from '@ktortu/aaa/cdk';
5
5
 
6
6
  const KT_TOOLTIP_CONFIG = new InjectionToken('KT_TOOLTIP_CONFIG');
@@ -33,7 +33,6 @@ class KtTooltip {
33
33
  host = inject(ElementRef);
34
34
  renderer = inject(Renderer2);
35
35
  vcr = inject(ViewContainerRef);
36
- ngZone = inject(NgZone);
37
36
  platformId = inject(PLATFORM_ID);
38
37
  /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */
39
38
  ktTooltip = input.required(/* @ts-ignore */
@@ -67,7 +66,8 @@ class KtTooltip {
67
66
  }, /* @ts-ignore */
68
67
  ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
69
68
  // Retourner null retire l'attribut (même astuce que aria-disabled dans button).
70
- // Corrigé : aria-describedby n'est présent sur le déclencheur que si le tooltip est affiché.
69
+ // aria-describedby n'est posé sur le déclencheur que lorsque le tooltip est affiché : sinon il
70
+ // référencerait un nœud absent du DOM (création lazy), donnant une référence pendante aux AT.
71
71
  describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null), /* @ts-ignore */
72
72
  ...(ngDevMode ? [{ debugName: "describedById" }] : /* istanbul ignore next */ []));
73
73
  tip = null;
@@ -126,27 +126,19 @@ class KtTooltip {
126
126
  show() {
127
127
  if (!this.isActive())
128
128
  return;
129
- this.ngZone.runOutsideAngular(() => {
130
- clearTimeout(this.hideTimer);
131
- this.showTimer = setTimeout(() => {
132
- this.ngZone.run(() => {
133
- if (this.isShown())
134
- return;
135
- this.isShown.set(true);
136
- if (!this.supportsAnchor) {
137
- this.registerFallbackListeners();
138
- }
139
- });
140
- }, this.showDelay());
141
- });
129
+ clearTimeout(this.hideTimer);
130
+ this.showTimer = setTimeout(() => {
131
+ if (this.isShown())
132
+ return;
133
+ this.isShown.set(true);
134
+ if (!this.supportsAnchor) {
135
+ this.registerFallbackListeners();
136
+ }
137
+ }, this.showDelay());
142
138
  }
143
139
  hide() {
144
- this.ngZone.runOutsideAngular(() => {
145
- clearTimeout(this.showTimer);
146
- this.hideTimer = setTimeout(() => {
147
- this.ngZone.run(() => this.dismiss());
148
- }, this.hideDelay());
149
- });
140
+ clearTimeout(this.showTimer);
141
+ this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());
150
142
  }
151
143
  onEscape(event) {
152
144
  if (!this.isShown())
@@ -317,14 +309,12 @@ class KtTooltip {
317
309
  this.clearFallbackListeners();
318
310
  if (this.supportsAnchor || !isPlatformBrowser(this.platformId))
319
311
  return;
320
- this.ngZone.runOutsideAngular(() => {
321
- const onScrollOrResize = () => {
322
- this.positionFallback();
323
- };
324
- window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });
325
- window.addEventListener('resize', onScrollOrResize);
326
- this.fallbackListeners.push(() => window.removeEventListener('scroll', onScrollOrResize, { capture: true }), () => window.removeEventListener('resize', onScrollOrResize));
327
- });
312
+ const onScrollOrResize = () => {
313
+ this.positionFallback();
314
+ };
315
+ window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });
316
+ window.addEventListener('resize', onScrollOrResize);
317
+ this.fallbackListeners.push(() => window.removeEventListener('scroll', onScrollOrResize, { capture: true }), () => window.removeEventListener('resize', onScrollOrResize));
328
318
  }
329
319
  clearFallbackListeners() {
330
320
  for (const remove of this.fallbackListeners)
@@ -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 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\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 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('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 // 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":"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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 '(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":";;;;;MAkCa,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,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;IAC7B,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;AACtC,IAAA,SAAS,GAAG,CAAA,WAAA,EAAc,IAAI,CAAC,GAAG,EAAE;;AAE5C,IAAA,SAAS,GAAG,IAAI,CAAC,SAAS;AAClB,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;;;;IAKQ,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,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5B,QAAA,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAK;YAC/B,IAAI,IAAI,CAAC,OAAO,EAAE;gBAAE;AAEpB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAEtB,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;gBACxB,IAAI,CAAC,yBAAyB,EAAE;YAClC;AACF,QAAA,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACtB;IAEU,IAAI,GAAA;AACZ,QAAA,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5B,QAAA,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACrE;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;QAEhE,MAAM,gBAAgB,GAAG,MAAK;YAC5B,IAAI,CAAC,gBAAgB,EAAE;AACzB,QAAA,CAAC;AACD,QAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACrF,QAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC;AAEnD,QAAA,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;IACH;IAEQ,sBAAsB,GAAA;AAC5B,QAAA,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,iBAAiB;AAAE,YAAA,MAAM,EAAE;AACrD,QAAA,IAAI,CAAC,iBAAiB,GAAG,EAAE;IAC7B;uGAlUW,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;;;ACtED;;AAEG;;;;"}
@@ -5,8 +5,10 @@ export * from '@ktortu/aaa/dialog';
5
5
  export * from '@ktortu/aaa/forms';
6
6
  export * from '@ktortu/aaa/i18n';
7
7
  export * from '@ktortu/aaa/menu';
8
+ export * from '@ktortu/aaa/snackbar';
8
9
  export * from '@ktortu/aaa/tabs';
9
10
  export * from '@ktortu/aaa/tooltip';
11
+ export * from '@ktortu/aaa/progress-bar';
10
12
 
11
13
  /*
12
14
  * Public API Surface of @ktortu/aaa
@@ -1 +1 @@
1
- {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
1
+ {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/snackbar';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\nexport * from '@ktortu/aaa/progress-bar';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -21,14 +21,6 @@
21
21
  color: var(--field-required-color, var(--kt-danger, #8c1d18));
22
22
  }
23
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
24
  .kt-checkbox-group__hint {
33
25
  margin: 0;
34
26
  font-size: var(--field-hint-font-size, 0.8125rem);
@@ -52,6 +52,11 @@
52
52
  /* Texte réservé aux lecteurs d'écran (live region des retraits). */
53
53
  .kt-chip-list__status {
54
54
  position: absolute;
55
+ /* Ancrée au coin de l'hôte : sans `inset`, un `position: absolute` sans ancêtre positionné
56
+ retombe sur sa position STATIQUE (bas de la liste). Dans un conteneur scrollable, ce 1px
57
+ atterrit loin dans le document et crée une 2ᵉ barre de défilement fantôme. */
58
+ inset-block-start: 0;
59
+ inset-inline-start: 0;
55
60
  inline-size: 1px;
56
61
  block-size: 1px;
57
62
  padding: 0;
@@ -71,6 +71,22 @@
71
71
  color: var(--field-error-color, #8c1d18);
72
72
  }
73
73
 
74
+ /* Copie visually-hidden du texte d'aide : présente en permanence dans l'arbre d'accessibilité
75
+ (technique clip), contrairement à la bulle du tooltip créée à la volée → aria-describedby du
76
+ contrôle résout toujours sa cible (pas de référence pendante pour les lecteurs d'écran). */
77
+ .kt-field__help-description {
78
+ position: absolute;
79
+ inset-block-start: 0;
80
+ inset-inline-start: 0;
81
+ inline-size: 1px;
82
+ block-size: 1px;
83
+ padding: 0;
84
+ margin: -1px;
85
+ overflow: hidden;
86
+ clip-path: inset(50%);
87
+ white-space: nowrap;
88
+ }
89
+
74
90
  /* Apparition d'un message d'erreur : token de BASCULE (non déclaré => aucune animation).
75
91
  Sur le MESSAGE (inséré à l'invalidation) — PAS sur le conteneur, qui vit en permanence
76
92
  (région live). Keyframes de thème : transform/opacity/filter seulement (les spans sont
@@ -21,14 +21,6 @@
21
21
  color: var(--field-required-color, var(--kt-danger, #8c1d18));
22
22
  }
23
23
 
24
- /* Disposition des options : pilotable par token (colonne par défaut, ligne possible). */
25
- .kt-radio-group__options {
26
- display: flex;
27
- flex-direction: var(--radio-group-direction, row);
28
- flex-wrap: wrap;
29
- gap: var(--radio-group-gap, 1rem);
30
- }
31
-
32
24
  .kt-radio-group__hint {
33
25
  margin: 0;
34
26
  font-size: var(--field-hint-font-size, 0.8125rem);
@@ -52,4 +44,4 @@
52
44
  animation: none;
53
45
  }
54
46
  }
55
- }
47
+ }
@@ -3,6 +3,7 @@
3
3
  Temporal (Date/Time/DateTime/YearMonth/Instant), qui réutilise la même `.kt-field-box`.
4
4
  Globale + classes namespacées : partagée entre plusieurs composants, donc non scopable. */
5
5
  kt-text-field,
6
+ kt-password-field,
6
7
  kt-text-area,
7
8
  kt-number-field,
8
9
  kt-date-field,
@@ -131,12 +132,14 @@
131
132
 
132
133
  /* Le bouton « effacer » est une icône INTERNE de la lib : toujours Material Symbols,
133
134
  indépendante de --kt-icon-font (sinon un override consommateur casserait la croix). */
134
- .kt-field-box__clear .kt-field-box__icon {
135
+ .kt-field-box__clear .kt-field-box__icon,
136
+ .kt-field-box__toggle .kt-field-box__icon {
135
137
  font-family: 'Material Symbols Outlined';
136
138
  font-weight: normal;
137
139
  }
138
140
 
139
- .kt-field-box__clear {
141
+ .kt-field-box__clear,
142
+ .kt-field-box__toggle {
140
143
  display: inline-flex;
141
144
  align-items: center;
142
145
  justify-content: center;
@@ -151,7 +154,8 @@
151
154
  }
152
155
 
153
156
  /* Cible tactile AAA 44x44px étendue via un pseudo-élément transparent */
154
- .kt-field-box__clear::after {
157
+ .kt-field-box__clear::after,
158
+ .kt-field-box__toggle::after {
155
159
  content: '';
156
160
  position: absolute;
157
161
  top: 50%;
@@ -161,11 +165,13 @@
161
165
  height: 44px;
162
166
  }
163
167
 
164
- .kt-field-box__clear:hover {
168
+ .kt-field-box__clear:hover,
169
+ .kt-field-box__toggle:hover {
165
170
  color: var(--field-color, inherit);
166
171
  }
167
172
 
168
- .kt-field-box__clear:focus-visible {
173
+ .kt-field-box__clear:focus-visible,
174
+ .kt-field-box__toggle:focus-visible {
169
175
  outline: 2px solid var(--field-border-color-focus, #0b57d0);
170
176
  outline-offset: 1px;
171
177
  }
@@ -221,7 +227,9 @@
221
227
  font-size: var(--field-font-size, 1rem);
222
228
  font-weight: 400;
223
229
  color: var(--field-hint-color, #5f6368);
224
- transition: transform 0.15s ease, color 0.15s ease;
230
+ transition:
231
+ transform 0.15s ease,
232
+ color 0.15s ease;
225
233
  }
226
234
 
227
235
  /* RTL : `transform-origin` n'accepte pas de mot-clé logique → on bascule l'origine de la mise à
@@ -0,0 +1,46 @@
1
+ @layer kt-aaa.components {
2
+ /* Spinner « validation asynchrone en cours » par défaut.
3
+
4
+ 100 % CSS (pseudo-élément, aucun markup) et piloté par l'attribut `[data-pending]` posé par les
5
+ contrôles quand leur input `pending` est vrai (l'accessibilité passe par `aria-busy`, indépendant).
6
+
7
+ Entièrement surchargeable / suppressible côté consommateur :
8
+ - retailler/recolorer via les tokens `--field-spinner-*` ;
9
+ - supprimer : kt-text-field .kt-field-box[data-pending]::after { content: none; }
10
+ - remplacer par sa propre affordance (le hook `[data-pending]` reste disponible). */
11
+ @keyframes kt-field-spin {
12
+ to {
13
+ transform: rotate(1turn);
14
+ }
15
+ }
16
+
17
+ .kt-field-box[data-pending]::after,
18
+ .kt-switch-field[data-pending] .kt-switch-row::after,
19
+ .kt-checkbox-field[data-pending] .kt-checkbox::after,
20
+ .kt-radio-group-field[data-pending] .kt-radio-group__legend::after,
21
+ .kt-checkbox-group-field[data-pending] .kt-checkbox-group__legend::after {
22
+ content: '';
23
+ display: inline-block;
24
+ flex: none;
25
+ vertical-align: middle;
26
+ inline-size: var(--field-spinner-size, 1em);
27
+ block-size: var(--field-spinner-size, 1em);
28
+ margin-inline-start: var(--field-spinner-gap, 0.5rem);
29
+ border: var(--field-spinner-width, 2px) solid var(--field-spinner-track, currentColor);
30
+ border-top-color: var(--field-spinner-color, var(--field-border-color-focus, #1a73e8));
31
+ border-radius: 50%;
32
+ opacity: var(--field-spinner-opacity, 0.7);
33
+ animation: kt-field-spin var(--field-spinner-duration, 0.7s) linear infinite;
34
+ }
35
+
36
+ /* Respect de prefers-reduced-motion : on fige la rotation (le cercle reste visible comme indicateur). */
37
+ @media (prefers-reduced-motion: reduce) {
38
+ .kt-field-box[data-pending]::after,
39
+ .kt-switch-field[data-pending] .kt-switch-row::after,
40
+ .kt-checkbox-field[data-pending] .kt-checkbox::after,
41
+ .kt-radio-group-field[data-pending] .kt-radio-group__legend::after,
42
+ .kt-checkbox-group-field[data-pending] .kt-checkbox-group__legend::after {
43
+ animation: none;
44
+ }
45
+ }
46
+ }
@@ -178,6 +178,10 @@
178
178
  /* Texte réservé aux lecteurs d'écran (live region du nombre de résultats). */
179
179
  .kt-select__sr-only {
180
180
  position: absolute;
181
+ /* Ancrée au coin : sinon ce 1px `absolute` retombe sur sa position statique et, dans un
182
+ conteneur scrollable, étire le document → barre de défilement fantôme. */
183
+ inset-block-start: 0;
184
+ inset-inline-start: 0;
181
185
  inline-size: 1px;
182
186
  block-size: 1px;
183
187
  padding: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktortu/aaa",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Bibliothèque de composants Angular headless + thémés par tokens CSS.",
5
5
  "keywords": [
6
6
  "angular",
@@ -73,6 +73,10 @@
73
73
  "types": "./types/ktortu-aaa-dialog.d.ts",
74
74
  "default": "./fesm2022/ktortu-aaa-dialog.mjs"
75
75
  },
76
+ "./disclosure": {
77
+ "types": "./types/ktortu-aaa-disclosure.d.ts",
78
+ "default": "./fesm2022/ktortu-aaa-disclosure.mjs"
79
+ },
76
80
  "./forms": {
77
81
  "types": "./types/ktortu-aaa-forms.d.ts",
78
82
  "default": "./fesm2022/ktortu-aaa-forms.mjs"
@@ -85,6 +89,14 @@
85
89
  "types": "./types/ktortu-aaa-menu.d.ts",
86
90
  "default": "./fesm2022/ktortu-aaa-menu.mjs"
87
91
  },
92
+ "./progress-bar": {
93
+ "types": "./types/ktortu-aaa-progress-bar.d.ts",
94
+ "default": "./fesm2022/ktortu-aaa-progress-bar.mjs"
95
+ },
96
+ "./snackbar": {
97
+ "types": "./types/ktortu-aaa-snackbar.d.ts",
98
+ "default": "./fesm2022/ktortu-aaa-snackbar.mjs"
99
+ },
88
100
  "./tabs": {
89
101
  "types": "./types/ktortu-aaa-tabs.d.ts",
90
102
  "default": "./fesm2022/ktortu-aaa-tabs.mjs"