@ktortu/aaa 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/button/button.css +82 -0
- package/fesm2022/ktortu-aaa-button.mjs +57 -9
- package/fesm2022/ktortu-aaa-button.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-dialog.mjs +6 -4
- package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-forms.mjs +4 -1
- package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-layout.mjs +8 -1
- package/fesm2022/ktortu-aaa-layout.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-menu.mjs +9 -7
- package/fesm2022/ktortu-aaa-menu.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-snackbar.mjs +6 -2
- package/fesm2022/ktortu-aaa-snackbar.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tabs.mjs +36 -1
- package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ktortu-aaa-button.d.ts +27 -2
- package/types/ktortu-aaa-forms.d.ts +3 -0
- package/types/ktortu-aaa-layout.d.ts +1 -0
- package/types/ktortu-aaa-menu.d.ts +1 -1
- package/types/ktortu-aaa-snackbar.d.ts +1 -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. */\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
|
+
{"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 const selectedRect = selected.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n\n // En environnement réel de rendu (navigateur), getBoundingClientRect est géométriquement\n // universel (indépendant du signe de scrollLeft, de RTL/LTR et des arrondis subpixel).\n // En jsdom (tests unitaires sans layout), les rectangles sont à 0 -> repli sur offsetLeft/Top.\n const hasLayout =\n selectedRect.width > 0 || selectedRect.height > 0 || selectedRect.left !== 0 || selectedRect.top !== 0;\n\n if (hasLayout) {\n if (this.isVertical()) {\n if (selectedRect.top < containerRect.top) {\n return { axis: 'top', value: container.scrollTop + (selectedRect.top - containerRect.top) };\n }\n if (selectedRect.bottom > containerRect.bottom) {\n return { axis: 'top', value: container.scrollTop + (selectedRect.bottom - containerRect.bottom) };\n }\n return null;\n }\n\n if (selectedRect.left < containerRect.left) {\n return { axis: 'left', value: container.scrollLeft + (selectedRect.left - containerRect.left) };\n }\n if (selectedRect.right > containerRect.right) {\n return { axis: 'left', value: container.scrollLeft + (selectedRect.right - containerRect.right) };\n }\n return null;\n }\n\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 if (this.isRtl()) {\n const selectedStart = container.scrollWidth - (selected.offsetLeft + selected.offsetWidth);\n const selectedEnd = container.scrollWidth - selected.offsetLeft;\n const containerStart = -container.scrollLeft;\n const containerEnd = containerStart + container.clientWidth;\n\n if (selectedStart < containerStart) return { axis: 'left', value: -selectedStart };\n if (selectedEnd > containerEnd) return { axis: 'left', value: -(selectedEnd - container.clientWidth) };\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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"}
|
package/package.json
CHANGED
|
@@ -59,6 +59,8 @@ declare class KtButton implements AfterViewInit {
|
|
|
59
59
|
readonly fullWidth: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
60
60
|
/** Bouton carré sans texte ; impose un nom accessible via `ariaLabel`. @default false */
|
|
61
61
|
readonly iconOnly: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
62
|
+
/** Bascule automatiquement le bouton en icône seule sous le seuil compact (600px). @default false */
|
|
63
|
+
readonly collapseCompact: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
62
64
|
/** Nom accessible. **Obligatoire si `iconOnly`** ; à défaut, l'`aria-label` natif est préservé. @default undefined */
|
|
63
65
|
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
64
66
|
/** Attribut HTML natif (comportement formulaire), distinct de `mode`. @default 'button' */
|
|
@@ -67,6 +69,12 @@ declare class KtButton implements AfterViewInit {
|
|
|
67
69
|
readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
68
70
|
/** Nom de l'icône (rendu via CSS `data-icon`). @default undefined */
|
|
69
71
|
readonly icon: _angular_core.InputSignal<string | undefined>;
|
|
72
|
+
/**
|
|
73
|
+
* Nom de l'icône spécifique au mode compact (`iconOnly` ou `collapseCompact`).
|
|
74
|
+
* Permet d'avoir un bouton avec texte seul sur grand écran et une icône dédiée sur petit écran.
|
|
75
|
+
* @default undefined
|
|
76
|
+
*/
|
|
77
|
+
readonly compactIcon: _angular_core.InputSignal<string | undefined>;
|
|
70
78
|
/** Position de l'icône relative au texte. @default 'start' */
|
|
71
79
|
readonly iconPosition: _angular_core.InputSignal<"start" | "end">;
|
|
72
80
|
/** Désactive le bouton. @default false */
|
|
@@ -79,8 +87,25 @@ declare class KtButton implements AfterViewInit {
|
|
|
79
87
|
ngAfterViewInit(): void;
|
|
80
88
|
protected haltDisabledEvents(event: Event): void;
|
|
81
89
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtButton, never>;
|
|
82
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KtButton, "button[ktButton], a[ktButton]", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "disabledInteractive": { "alias": "disabledInteractive"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
90
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KtButton, "button[ktButton], a[ktButton]", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "collapseCompact": { "alias": "collapseCompact"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "compactIcon": { "alias": "compactIcon"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "disabledInteractive": { "alias": "disabledInteractive"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Libellé textuel pour un bouton `[ktButton]`.
|
|
95
|
+
* Permet de masquer visuellement le texte de façon accessible (WCAG 4.1.2 / 2.5.3)
|
|
96
|
+
* lorsque le bouton bascule en mode compact / icône seule (`iconOnly` ou `collapseCompact`).
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```html
|
|
100
|
+
* <button ktButton icon="download" collapseCompact>
|
|
101
|
+
* <span ktButtonLabel>Télécharger</span>
|
|
102
|
+
* </button>
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
declare class KtButtonLabel {
|
|
106
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtButtonLabel, never>;
|
|
107
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KtButtonLabel, "[ktButtonLabel], .kt-button-label", never, {}, {}, never, never, true, never>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { KT_BUTTON_CONFIG, KtButton, KtButtonLabel, provideKtButton };
|
|
86
111
|
export type { KtButtonColor, KtButtonConfig, KtButtonMode, KtButtonSize };
|
|
@@ -1460,6 +1460,9 @@ declare class KtMultiSelect<T, V = T> extends KtBaseSelect<T, V> implements Form
|
|
|
1460
1460
|
protected readonly triggerText: _angular_core.Signal<string>;
|
|
1461
1461
|
/** Valeur brute transmise au ngListbox sous-jacent (tableau de clés). */
|
|
1462
1462
|
protected readonly listboxValue: _angular_core.Signal<unknown[]>;
|
|
1463
|
+
/** Affiche le bouton « effacer » (×) sur le champ dès qu'une valeur est présente (`clearable`).
|
|
1464
|
+
Basé sur `value()` et non `selectedOptions()` : des clés orphelines (options retirées des données)
|
|
1465
|
+
restent effaçables (aligné sur `KtSelect`). */
|
|
1463
1466
|
protected readonly showClear: _angular_core.Signal<boolean>;
|
|
1464
1467
|
/** Le popup utilise la structure « panneau dialog » (champ de filtre et/ou barre d'actions). */
|
|
1465
1468
|
protected readonly dialogMode: _angular_core.Signal<boolean>;
|
|
@@ -64,6 +64,7 @@ declare class KtSidenavComponent {
|
|
|
64
64
|
protected readonly isHidden: _angular_core.Signal<boolean>;
|
|
65
65
|
private readonly trapFocus;
|
|
66
66
|
constructor();
|
|
67
|
+
protected onEscape(event: Event): void;
|
|
67
68
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KtSidenavComponent, never>;
|
|
68
69
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KtSidenavComponent, "kt-sidenav", never, {}, {}, never, ["*"], true, [{ directive: typeof i1.CdkTrapFocus; inputs: {}; outputs: {}; }]>;
|
|
69
70
|
}
|
|
@@ -50,7 +50,7 @@ declare class KtMenu {
|
|
|
50
50
|
declare class KtMenuItem {
|
|
51
51
|
private readonly ariaItem;
|
|
52
52
|
private readonly platformId;
|
|
53
|
-
protected anchorName: string | undefined
|
|
53
|
+
protected readonly anchorName: i0.WritableSignal<string | undefined>;
|
|
54
54
|
private readonly idGen;
|
|
55
55
|
constructor();
|
|
56
56
|
static ɵfac: i0.ɵɵFactoryDeclaration<KtMenuItem, never>;
|
|
@@ -176,6 +176,7 @@ declare class KtSnackbar implements OnDestroy {
|
|
|
176
176
|
/** File FIFO : `queue[0]` est la snackbar affichée dès qu'elle est attachée. */
|
|
177
177
|
private readonly queue;
|
|
178
178
|
private active;
|
|
179
|
+
private isExiting;
|
|
179
180
|
private escapeRegistered;
|
|
180
181
|
/**
|
|
181
182
|
* Ouvre une snackbar affichant `message`. Les `options` priment sur `KT_SNACKBAR_CONFIG`, qui
|