@ktortu/aaa 0.1.0-beta.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -7
- package/cdk/styles/tabs.css +100 -21
- package/fesm2022/ktortu-aaa-button.mjs +18 -11
- package/fesm2022/ktortu-aaa-button.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-card.mjs +29 -4
- package/fesm2022/ktortu-aaa-card.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-cdk.mjs +58 -15
- package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-dialog.mjs +69 -12
- package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-forms.mjs +455 -260
- package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-i18n.mjs +114 -0
- package/fesm2022/ktortu-aaa-i18n.mjs.map +1 -0
- package/fesm2022/ktortu-aaa-menu.mjs +38 -13
- package/fesm2022/ktortu-aaa-menu.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tabs.mjs +319 -42
- package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs +3 -2
- package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
- package/fesm2022/ktortu-aaa.mjs +1 -0
- package/fesm2022/ktortu-aaa.mjs.map +1 -1
- package/forms/radio/radio-group.css +3 -3
- package/forms/styles/field-box.css +150 -2
- package/forms/styles/tokens.css +3 -0
- package/menu/menu.css +8 -4
- package/package.json +5 -1
- package/types/ktortu-aaa-button.d.ts +22 -8
- package/types/ktortu-aaa-card.d.ts +24 -4
- package/types/ktortu-aaa-cdk.d.ts +38 -0
- package/types/ktortu-aaa-dialog.d.ts +45 -9
- package/types/ktortu-aaa-forms.d.ts +336 -149
- package/types/ktortu-aaa-i18n.d.ts +74 -0
- package/types/ktortu-aaa-menu.d.ts +15 -8
- package/types/ktortu-aaa-tabs.d.ts +130 -13
- package/types/ktortu-aaa-tooltip.d.ts +5 -0
- package/types/ktortu-aaa.d.ts +1 -0
|
@@ -1,79 +1,356 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, afterRenderEffect, Directive } from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, DOCUMENT, DestroyRef, signal, computed, afterRenderEffect, afterNextRender, Directive, InjectionToken, contentChild, input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { TabList } from '@angular/aria/tabs';
|
|
4
|
+
import { KtButton } from '@ktortu/aaa/button';
|
|
4
5
|
|
|
6
|
+
const EMPTY_METRICS = { canStart: false, canEnd: false, overflowing: false, vertical: false };
|
|
7
|
+
/** Tolérance d'1px : arrondis sub-pixel, zoom navigateur. */
|
|
8
|
+
const EPS = 1;
|
|
9
|
+
/** Fraction de la zone visible parcourue par un « page » de pagination (chevauchement d'un onglet). */
|
|
10
|
+
const PAGE_RATIO = 0.8;
|
|
5
11
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
12
|
+
* Pilote le **débordement** d'une liste d'onglets `@angular/aria/tabs` (cf. tabs.css). Deux rôles :
|
|
13
|
+
*
|
|
14
|
+
* 1. **Scroll-into-view** : amène l'onglet sélectionné dans la vue au montage et lors d'un changement
|
|
15
|
+
* de sélection programmatique (ce que le CSS seul ne fait pas), en respectant `prefers-reduced-motion`.
|
|
16
|
+
* 2. **Pagination** : expose un état réactif (`canScrollStart()`, `canScrollEnd()`, `overflowing()`,
|
|
17
|
+
* `orientation()`) et une méthode `scrollByPage()`, pour brancher des boutons chevrons (cf. le
|
|
18
|
+
* composant clé-en-main `KtTabScrollerPager`, ou des boutons custom via `exportAs: 'ktTabScroller'`).
|
|
10
19
|
*
|
|
11
20
|
* Opt-in, à poser sur `[ngTabList]` :
|
|
12
21
|
*
|
|
13
22
|
* @example
|
|
14
23
|
* ```html
|
|
15
|
-
* <ul ngTabList
|
|
24
|
+
* <ul ngTabList ktTabScroller #s="ktTabScroller" [(selectedTab)]="tab"> … </ul>
|
|
25
|
+
* <button (click)="s.scrollByPage('start')" [disabled]="!s.canScrollStart()">‹</button>
|
|
16
26
|
* ```
|
|
17
|
-
*
|
|
18
|
-
* Intégrée réactivement avec `@angular/aria/tabs` via son `ModelSignal` `selectedTab`.
|
|
19
27
|
*/
|
|
20
|
-
class
|
|
28
|
+
class KtTabScroller {
|
|
21
29
|
list = inject(ElementRef).nativeElement;
|
|
22
30
|
tabList = inject(TabList);
|
|
31
|
+
doc = inject(DOCUMENT);
|
|
32
|
+
destroyRef = inject(DestroyRef);
|
|
33
|
+
/** Préférence « réduire les animations », lue à chaud (absente possible en SSR/jsdom). */
|
|
34
|
+
reducedMotion = this.doc.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)');
|
|
35
|
+
/**
|
|
36
|
+
* Métriques de débordement. Mises à jour UNIQUEMENT depuis des callbacks navigateur
|
|
37
|
+
* (`afterNextRender`, `scroll`, `ResizeObserver`, `MutationObserver`) — jamais depuis le corps
|
|
38
|
+
* d'un effet réactif, pour rester conforme (pas d'écriture de signal dans un effet).
|
|
39
|
+
*/
|
|
40
|
+
metrics = signal(EMPTY_METRICS, /* @ts-ignore */
|
|
41
|
+
...(ngDevMode ? [{ debugName: "metrics" }] : /* istanbul ignore next */ []));
|
|
42
|
+
/** Reste-t-il du contenu hors-champ côté début (à brancher sur le bouton « précédent ») ? */
|
|
43
|
+
canScrollStart = computed(() => this.metrics().canStart, /* @ts-ignore */
|
|
44
|
+
...(ngDevMode ? [{ debugName: "canScrollStart" }] : /* istanbul ignore next */ []));
|
|
45
|
+
/** Reste-t-il du contenu hors-champ côté fin (à brancher sur le bouton « suivant ») ? */
|
|
46
|
+
canScrollEnd = computed(() => this.metrics().canEnd, /* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [{ debugName: "canScrollEnd" }] : /* istanbul ignore next */ []));
|
|
48
|
+
/** La liste déborde-t-elle ? (utile pour masquer toute la barre de pagination). */
|
|
49
|
+
overflowing = computed(() => this.metrics().overflowing, /* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [{ debugName: "overflowing" }] : /* istanbul ignore next */ []));
|
|
51
|
+
/** Axe courant, dérivé de l'orientation `@angular/aria`. */
|
|
52
|
+
orientation = computed(() => this.metrics().vertical ? 'vertical' : 'horizontal', /* @ts-ignore */
|
|
53
|
+
...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
23
54
|
constructor() {
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
afterRenderEffect(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
55
|
+
// 1. Scroll-into-view (phasé : mesure en `earlyRead`, scroll en `write`, pas de reflow forcé).
|
|
56
|
+
// Le `scrollTo` émet un événement `scroll` → remeasure via le listener (aucun `set` ici).
|
|
57
|
+
afterRenderEffect({
|
|
58
|
+
earlyRead: () => this.computeScrollTarget(),
|
|
59
|
+
write: (target) => {
|
|
60
|
+
const t = target();
|
|
61
|
+
if (!t)
|
|
62
|
+
return;
|
|
63
|
+
this.list.scrollTo({ [t.axis]: t.value, behavior: this.scrollBehavior() });
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
// 2. Mesure initiale + observateurs (browser-only ; `afterNextRender` ne tourne pas en SSR).
|
|
67
|
+
afterNextRender(() => {
|
|
68
|
+
const view = this.doc.defaultView;
|
|
69
|
+
if (!view)
|
|
70
|
+
return;
|
|
71
|
+
this.remeasure();
|
|
72
|
+
const onScroll = () => this.remeasure();
|
|
73
|
+
this.list.addEventListener('scroll', onScroll, { passive: true });
|
|
74
|
+
// ResizeObserver : viewport ET contenu (les onglets qui changent de largeur). Référencé en
|
|
75
|
+
// global (jamais instancié en SSR puisque dans `afterNextRender`).
|
|
76
|
+
const ro = new ResizeObserver(() => this.remeasure());
|
|
77
|
+
const observeAll = () => {
|
|
78
|
+
ro.disconnect();
|
|
79
|
+
ro.observe(this.list);
|
|
80
|
+
for (const child of Array.from(this.list.children))
|
|
81
|
+
ro.observe(child);
|
|
82
|
+
};
|
|
83
|
+
observeAll();
|
|
84
|
+
// MutationObserver : onglets ajoutés/retirés (@for) → re-observer + remeasure.
|
|
85
|
+
const mo = new MutationObserver(() => {
|
|
86
|
+
observeAll();
|
|
87
|
+
this.remeasure();
|
|
88
|
+
});
|
|
89
|
+
mo.observe(this.list, { childList: true });
|
|
90
|
+
this.destroyRef.onDestroy(() => {
|
|
91
|
+
this.list.removeEventListener('scroll', onScroll);
|
|
92
|
+
ro.disconnect();
|
|
93
|
+
mo.disconnect();
|
|
94
|
+
});
|
|
31
95
|
});
|
|
32
96
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Fait défiler d'environ une « page » (≈ {@link PAGE_RATIO} de la zone visible) vers le début ou la
|
|
99
|
+
* fin. `behavior` respecte `prefers-reduced-motion`. Le navigateur sature au min/max ; les boutons
|
|
100
|
+
* câblés sont `disabled` aux extrémités, donc l'appel n'a pas lieu à vide.
|
|
101
|
+
*/
|
|
102
|
+
scrollByPage(dir) {
|
|
103
|
+
const el = this.list;
|
|
104
|
+
const sign = dir === 'end' ? 1 : -1;
|
|
105
|
+
if (this.metrics().vertical) {
|
|
106
|
+
el.scrollBy({ top: sign * el.clientHeight * PAGE_RATIO, behavior: this.scrollBehavior() });
|
|
36
107
|
return;
|
|
108
|
+
}
|
|
109
|
+
// RTL : le sens d'écriture inverse le signe de `scrollLeft`.
|
|
110
|
+
const rtlSign = this.isRtl() ? -1 : 1;
|
|
111
|
+
el.scrollBy({ left: sign * rtlSign * el.clientWidth * PAGE_RATIO, behavior: this.scrollBehavior() });
|
|
112
|
+
}
|
|
113
|
+
/** Met à jour le signal de métriques. Appelé depuis des callbacks navigateur (jamais un effet). */
|
|
114
|
+
remeasure() {
|
|
115
|
+
this.metrics.set(this.measure());
|
|
116
|
+
}
|
|
117
|
+
/** Mesure le débordement (lecture pure de géométrie, n'écrit rien). */
|
|
118
|
+
measure() {
|
|
119
|
+
const el = this.list;
|
|
120
|
+
const vertical = this.isVertical();
|
|
121
|
+
if (vertical) {
|
|
122
|
+
const { scrollTop, scrollHeight, clientHeight } = el;
|
|
123
|
+
const max = scrollHeight - clientHeight;
|
|
124
|
+
return { vertical: true, overflowing: max > EPS, canStart: scrollTop > EPS, canEnd: scrollTop < max - EPS };
|
|
125
|
+
}
|
|
126
|
+
const { scrollLeft, scrollWidth, clientWidth } = el;
|
|
127
|
+
const max = scrollWidth - clientWidth;
|
|
128
|
+
const rtl = this.isRtl();
|
|
129
|
+
// Distances logiques indépendantes du signe de `scrollLeft` (négatif en RTL sur les navigateurs récents).
|
|
130
|
+
const fromStart = rtl ? -scrollLeft : scrollLeft;
|
|
131
|
+
const fromEnd = max - Math.abs(scrollLeft);
|
|
132
|
+
return { vertical: false, overflowing: max > EPS, canStart: fromStart > EPS, canEnd: fromEnd > EPS };
|
|
133
|
+
}
|
|
134
|
+
isVertical() {
|
|
135
|
+
return (this.list.getAttribute('aria-orientation') === 'vertical' || this.list.getAttribute('orientation') === 'vertical');
|
|
136
|
+
}
|
|
137
|
+
isRtl() {
|
|
138
|
+
return this.doc.defaultView?.getComputedStyle(this.list).direction === 'rtl';
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* `auto` si l'utilisateur a demandé à réduire les animations (WCAG 2.3.3 AAA), `smooth` sinon.
|
|
142
|
+
* Passer un `behavior` explicite à `scrollTo`/`scrollBy` écrase la propriété CSS `scroll-behavior`,
|
|
143
|
+
* d'où la nécessité de répliquer ici la décision que le CSS prend via `prefers-reduced-motion`.
|
|
144
|
+
*/
|
|
145
|
+
scrollBehavior() {
|
|
146
|
+
return this.reducedMotion?.matches ? 'auto' : 'smooth';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Calcule l'offset à atteindre pour amener l'onglet actif dans la vue, ou `null` s'il est déjà
|
|
150
|
+
* visible (ou s'il n'y a aucun onglet sélectionné). Lit `selectedTab()` → dépendance réactive.
|
|
151
|
+
*/
|
|
152
|
+
computeScrollTarget() {
|
|
153
|
+
const selected = this.tabList.findTab(this.tabList.selectedTab())?.element;
|
|
154
|
+
if (!selected)
|
|
155
|
+
return null;
|
|
37
156
|
const container = this.list;
|
|
38
|
-
|
|
39
|
-
if (isVertical) {
|
|
157
|
+
if (this.isVertical()) {
|
|
40
158
|
const selectedTop = selected.offsetTop;
|
|
41
159
|
const selectedBottom = selectedTop + selected.offsetHeight;
|
|
42
160
|
const containerTop = container.scrollTop;
|
|
43
161
|
const containerBottom = containerTop + container.clientHeight;
|
|
44
|
-
if (selectedTop < containerTop)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
const selectedLeft = selected.offsetLeft;
|
|
53
|
-
const selectedRight = selectedLeft + selected.offsetWidth;
|
|
54
|
-
const containerLeft = container.scrollLeft;
|
|
55
|
-
const containerRight = containerLeft + container.clientWidth;
|
|
56
|
-
if (selectedLeft < containerLeft) {
|
|
57
|
-
container.scrollTo({ left: selectedLeft, behavior: 'smooth' });
|
|
58
|
-
}
|
|
59
|
-
else if (selectedRight > containerRight) {
|
|
60
|
-
container.scrollTo({ left: selectedRight - container.clientWidth, behavior: 'smooth' });
|
|
61
|
-
}
|
|
162
|
+
if (selectedTop < containerTop)
|
|
163
|
+
return { axis: 'top', value: selectedTop };
|
|
164
|
+
if (selectedBottom > containerBottom)
|
|
165
|
+
return { axis: 'top', value: selectedBottom - container.clientHeight };
|
|
166
|
+
return null;
|
|
62
167
|
}
|
|
168
|
+
const selectedLeft = selected.offsetLeft;
|
|
169
|
+
const selectedRight = selectedLeft + selected.offsetWidth;
|
|
170
|
+
const containerLeft = container.scrollLeft;
|
|
171
|
+
const containerRight = containerLeft + container.clientWidth;
|
|
172
|
+
if (selectedLeft < containerLeft)
|
|
173
|
+
return { axis: 'left', value: selectedLeft };
|
|
174
|
+
if (selectedRight > containerRight)
|
|
175
|
+
return { axis: 'left', value: selectedRight - container.clientWidth };
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScroller, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
179
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtTabScroller, isStandalone: true, selector: "[ngTabList][ktTabScroller]", host: { properties: { "attr.data-kt-tab-scroller": "\"\"" } }, exportAs: ["ktTabScroller"], ngImport: i0 });
|
|
180
|
+
}
|
|
181
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScroller, decorators: [{
|
|
182
|
+
type: Directive,
|
|
183
|
+
args: [{
|
|
184
|
+
selector: '[ngTabList][ktTabScroller]',
|
|
185
|
+
exportAs: 'ktTabScroller',
|
|
186
|
+
host: {
|
|
187
|
+
// Marqueur CSS : pagination réactive active → la scrollbar native est masquée (cf. tabs.css).
|
|
188
|
+
'[attr.data-kt-tab-scroller]': '""',
|
|
189
|
+
},
|
|
190
|
+
}]
|
|
191
|
+
}], ctorParameters: () => [] });
|
|
192
|
+
|
|
193
|
+
const KT_TABS_CONFIG = new InjectionToken('KT_TABS_CONFIG');
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Composant clé-en-main : enveloppe une liste d'onglets `@angular/aria/tabs` débordante de deux
|
|
197
|
+
* **chevrons de pagination** accessibles (style Material). Il ne contient aucune logique propre :
|
|
198
|
+
* il lit l'état réactif de la directive headless {@link KtTabScroller} (à poser sur le `ngTabList`
|
|
199
|
+
* projeté) et câble deux boutons {@link KtButton}.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```html
|
|
203
|
+
* <kt-tab-scroller>
|
|
204
|
+
* <ul ngTabList ktTabScroller [(selectedTab)]="tab">
|
|
205
|
+
* @for (t of tabs; track t) { <li ngTab [value]="t">…</li> }
|
|
206
|
+
* </ul>
|
|
207
|
+
* </kt-tab-scroller>
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
class KtTabScrollerPager {
|
|
211
|
+
host = inject(ElementRef).nativeElement;
|
|
212
|
+
doc = inject(DOCUMENT);
|
|
213
|
+
/** Défauts d'app (provider global `KT_TABS_CONFIG`) ; les inputs ci-dessous priment dessus. */
|
|
214
|
+
config = inject(KT_TABS_CONFIG, { optional: true });
|
|
215
|
+
/** La directive headless posée sur le `ngTabList` projeté (`descendants` car dans le viewport). */
|
|
216
|
+
scroller = contentChild.required(KtTabScroller, { descendants: true });
|
|
217
|
+
/** Sens de lecture (figé au montage : le RTL inverse les chevrons gauche/droite). */
|
|
218
|
+
dir = signal('ltr', /* @ts-ignore */
|
|
219
|
+
...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ []));
|
|
220
|
+
startIcon = computed(() => {
|
|
221
|
+
if (this.scroller().orientation() === 'vertical')
|
|
222
|
+
return 'expand_less';
|
|
223
|
+
return this.dir() === 'rtl' ? 'chevron_right' : 'chevron_left';
|
|
224
|
+
}, /* @ts-ignore */
|
|
225
|
+
...(ngDevMode ? [{ debugName: "startIcon" }] : /* istanbul ignore next */ []));
|
|
226
|
+
endIcon = computed(() => {
|
|
227
|
+
if (this.scroller().orientation() === 'vertical')
|
|
228
|
+
return 'expand_more';
|
|
229
|
+
return this.dir() === 'rtl' ? 'chevron_left' : 'chevron_right';
|
|
230
|
+
}, /* @ts-ignore */
|
|
231
|
+
...(ngDevMode ? [{ debugName: "endIcon" }] : /* istanbul ignore next */ []));
|
|
232
|
+
/**
|
|
233
|
+
* Noms accessibles des chevrons (`aria-label`). Résolution `input ?? KT_TABS_CONFIG ?? défaut`,
|
|
234
|
+
* comme partout dans la lib (cf. `KT_FIELD_CONFIG`/`KT_CHIPS_CONFIG`). Défauts en anglais : lib
|
|
235
|
+
* neutre i18n, les textes sont fournis par le consommateur (provider global ou binding).
|
|
236
|
+
*/
|
|
237
|
+
/**
|
|
238
|
+
* `aria-label` du chevron « onglets précédents ».
|
|
239
|
+
* @default config.previousLabel ?? 'Previous tabs'
|
|
240
|
+
*/
|
|
241
|
+
previousLabel = input(this.config?.previousLabel ?? 'Previous tabs', /* @ts-ignore */
|
|
242
|
+
...(ngDevMode ? [{ debugName: "previousLabel" }] : /* istanbul ignore next */ []));
|
|
243
|
+
/**
|
|
244
|
+
* `aria-label` du chevron « onglets suivants ».
|
|
245
|
+
* @default config.nextLabel ?? 'Next tabs'
|
|
246
|
+
*/
|
|
247
|
+
nextLabel = input(this.config?.nextLabel ?? 'Next tabs', /* @ts-ignore */
|
|
248
|
+
...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
|
|
249
|
+
constructor() {
|
|
250
|
+
afterNextRender(() => {
|
|
251
|
+
if (this.doc.defaultView?.getComputedStyle(this.host).direction === 'rtl')
|
|
252
|
+
this.dir.set('rtl');
|
|
253
|
+
});
|
|
63
254
|
}
|
|
255
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScrollerPager, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
256
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.1", type: KtTabScrollerPager, isStandalone: true, selector: "kt-tab-scroller", inputs: { previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-orientation": "scroller().orientation()", "attr.data-overflowing": "scroller().overflowing() ? \"\" : null" } }, queries: [{ propertyName: "scroller", first: true, predicate: KtTabScroller, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
257
|
+
<button
|
|
258
|
+
ktButton
|
|
259
|
+
type="button"
|
|
260
|
+
mode="text"
|
|
261
|
+
iconOnly
|
|
262
|
+
class="kt-tab-scroller__chevron kt-tab-scroller__chevron--start"
|
|
263
|
+
[icon]="startIcon()"
|
|
264
|
+
[ariaLabel]="previousLabel()"
|
|
265
|
+
[disabled]="!scroller().canScrollStart()"
|
|
266
|
+
(click)="scroller().scrollByPage('start')"
|
|
267
|
+
></button>
|
|
268
|
+
|
|
269
|
+
<div class="kt-tab-scroller__viewport">
|
|
270
|
+
<ng-content select="[ngTabList]" />
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<button
|
|
274
|
+
ktButton
|
|
275
|
+
type="button"
|
|
276
|
+
mode="text"
|
|
277
|
+
iconOnly
|
|
278
|
+
class="kt-tab-scroller__chevron kt-tab-scroller__chevron--end"
|
|
279
|
+
[icon]="endIcon()"
|
|
280
|
+
[ariaLabel]="nextLabel()"
|
|
281
|
+
[disabled]="!scroller().canScrollEnd()"
|
|
282
|
+
(click)="scroller().scrollByPage('end')"
|
|
283
|
+
></button>
|
|
284
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: KtButton, selector: "button[ktButton], a[ktButton]", inputs: ["mode", "color", "size", "fullWidth", "iconOnly", "ariaLabel", "type", "loading", "icon", "iconPosition", "disabled", "disabledInteractive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
285
|
+
}
|
|
286
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScrollerPager, decorators: [{
|
|
287
|
+
type: Component,
|
|
288
|
+
args: [{
|
|
289
|
+
selector: 'kt-tab-scroller',
|
|
290
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
291
|
+
imports: [KtButton],
|
|
292
|
+
host: {
|
|
293
|
+
'[attr.data-orientation]': 'scroller().orientation()',
|
|
294
|
+
'[attr.data-overflowing]': 'scroller().overflowing() ? "" : null',
|
|
295
|
+
},
|
|
296
|
+
template: `
|
|
297
|
+
<button
|
|
298
|
+
ktButton
|
|
299
|
+
type="button"
|
|
300
|
+
mode="text"
|
|
301
|
+
iconOnly
|
|
302
|
+
class="kt-tab-scroller__chevron kt-tab-scroller__chevron--start"
|
|
303
|
+
[icon]="startIcon()"
|
|
304
|
+
[ariaLabel]="previousLabel()"
|
|
305
|
+
[disabled]="!scroller().canScrollStart()"
|
|
306
|
+
(click)="scroller().scrollByPage('start')"
|
|
307
|
+
></button>
|
|
308
|
+
|
|
309
|
+
<div class="kt-tab-scroller__viewport">
|
|
310
|
+
<ng-content select="[ngTabList]" />
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<button
|
|
314
|
+
ktButton
|
|
315
|
+
type="button"
|
|
316
|
+
mode="text"
|
|
317
|
+
iconOnly
|
|
318
|
+
class="kt-tab-scroller__chevron kt-tab-scroller__chevron--end"
|
|
319
|
+
[icon]="endIcon()"
|
|
320
|
+
[ariaLabel]="nextLabel()"
|
|
321
|
+
[disabled]="!scroller().canScrollEnd()"
|
|
322
|
+
(click)="scroller().scrollByPage('end')"
|
|
323
|
+
></button>
|
|
324
|
+
`,
|
|
325
|
+
}]
|
|
326
|
+
}], ctorParameters: () => [], propDecorators: { scroller: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtTabScroller), { ...{ descendants: true }, isSignal: true }] }], previousLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }] } });
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @deprecated Utilisez {@link KtTabScroller} (sélecteur `[ktTabScroller]`) : même défilement de
|
|
330
|
+
* l'onglet sélectionné dans la vue, plus la pagination par chevrons. `ktTabScroll` reste un **alias
|
|
331
|
+
* fonctionnel** (il applique `KtTabScroller` comme directive hôte) et sera retiré dans une version
|
|
332
|
+
* majeure ultérieure.
|
|
333
|
+
*
|
|
334
|
+
* Note : depuis cette version, une liste pilotée par `ktTabScroll`/`ktTabScroller` masque sa
|
|
335
|
+
* scrollbar native par défaut (les chevrons / ombres prennent le relais). Réafficher la barre via
|
|
336
|
+
* `--tab-scroller-scrollbar: thin`.
|
|
337
|
+
*/
|
|
338
|
+
class KtTabScroll {
|
|
64
339
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScroll, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
65
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtTabScroll, isStandalone: true, selector: "[ngTabList][ktTabScroll]", ngImport: i0 });
|
|
340
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtTabScroll, isStandalone: true, selector: "[ngTabList][ktTabScroll]", exportAs: ["ktTabScroll"], hostDirectives: [{ directive: KtTabScroller }], ngImport: i0 });
|
|
66
341
|
}
|
|
67
342
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTabScroll, decorators: [{
|
|
68
343
|
type: Directive,
|
|
69
344
|
args: [{
|
|
70
345
|
selector: '[ngTabList][ktTabScroll]',
|
|
346
|
+
exportAs: 'ktTabScroll',
|
|
347
|
+
hostDirectives: [KtTabScroller],
|
|
71
348
|
}]
|
|
72
|
-
}]
|
|
349
|
+
}] });
|
|
73
350
|
|
|
74
351
|
/**
|
|
75
352
|
* Generated bundle index. Do not edit.
|
|
76
353
|
*/
|
|
77
354
|
|
|
78
|
-
export { KtTabScroll };
|
|
355
|
+
export { KT_TABS_CONFIG, KtTabScroll, KtTabScroller, KtTabScrollerPager };
|
|
79
356
|
//# sourceMappingURL=ktortu-aaa-tabs.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktortu-aaa-tabs.mjs","sources":["../../../../projects/ktortu/aaa/tabs/tab-scroll.ts","../../../../projects/ktortu/aaa/tabs/ktortu-aaa-tabs.ts"],"sourcesContent":["import { Directive, ElementRef, afterRenderEffect, inject } from '@angular/core';\nimport { TabList } from '@angular/aria/tabs';\n\n/**\n * Amène l'onglet sélectionné dans la zone visible quand la liste d'onglets déborde et défile\n * (cf. tabs.css). Le focus clavier d'`@angular/aria` scrolle déjà l'onglet focalisé ; cette\n * directive couvre ce que le CSS seul ne peut pas faire de façon fiable : l'onglet actif\n * **hors-champ au montage** et lors d'un **changement de sélection programmatique**.\n *\n * Opt-in, à poser sur `[ngTabList]` :\n *\n * @example\n * ```html\n * <ul ngTabList ktTabScroll [(selectedTab)]=\"tab\"> … </ul>\n * ```\n *\n * Intégrée réactivement avec `@angular/aria/tabs` via son `ModelSignal` `selectedTab`.\n */\n@Directive({\n selector: '[ngTabList][ktTabScroll]',\n})\nexport class KtTabScroll {\n private readonly list = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly tabList = inject(TabList);\n\n constructor() {\n // afterRenderEffect est la primitive réactive d'Angular v22 conçue spécifiquement\n // pour exécuter des effets dépendant de signaux APRES la mise à jour complète du DOM et du layout.\n afterRenderEffect(() => {\n // Enregistrer la dépendance réactive sur le signal de sélection\n this.tabList.selectedTab();\n\n // Exécuter le scroll (le DOM est garanti stable et à jour)\n this.scrollSelectedIntoView();\n });\n }\n\n private scrollSelectedIntoView(): void {\n const selected = this.list.querySelector<HTMLElement>('[ngTab][aria-selected=\"true\"]');\n if (!selected) return;\n\n const container = this.list;\n const isVertical =\n container.getAttribute('aria-orientation') === 'vertical' || container.getAttribute('orientation') === 'vertical';\n\n if (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) {\n container.scrollTo({ top: selectedTop, behavior: 'smooth' });\n } else if (selectedBottom > containerBottom) {\n container.scrollTo({ top: selectedBottom - container.clientHeight, behavior: 'smooth' });\n }\n } else {\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) {\n container.scrollTo({ left: selectedLeft, behavior: 'smooth' });\n } else if (selectedRight > containerRight) {\n container.scrollTo({ left: selectedRight - container.clientWidth, behavior: 'smooth' });\n }\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAGA;;;;;;;;;;;;;;AAcG;MAIU,WAAW,CAAA;AACL,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC,CAAC,aAAa;AAChE,IAAA,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;AAE1C,IAAA,WAAA,GAAA;;;QAGE,iBAAiB,CAAC,MAAK;;AAErB,YAAA,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;;YAG1B,IAAI,CAAC,sBAAsB,EAAE;AAC/B,QAAA,CAAC,CAAC;IACJ;IAEQ,sBAAsB,GAAA;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAc,+BAA+B,CAAC;AACtF,QAAA,IAAI,CAAC,QAAQ;YAAE;AAEf,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI;AAC3B,QAAA,MAAM,UAAU,GACd,SAAS,CAAC,YAAY,CAAC,kBAAkB,CAAC,KAAK,UAAU,IAAI,SAAS,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,UAAU;QAEnH,IAAI,UAAU,EAAE;AACd,YAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS;AACtC,YAAA,MAAM,cAAc,GAAG,WAAW,GAAG,QAAQ,CAAC,YAAY;AAC1D,YAAA,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS;AACxC,YAAA,MAAM,eAAe,GAAG,YAAY,GAAG,SAAS,CAAC,YAAY;AAE7D,YAAA,IAAI,WAAW,GAAG,YAAY,EAAE;AAC9B,gBAAA,SAAS,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YAC9D;AAAO,iBAAA,IAAI,cAAc,GAAG,eAAe,EAAE;AAC3C,gBAAA,SAAS,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,cAAc,GAAG,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YAC1F;QACF;aAAO;AACL,YAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU;AACxC,YAAA,MAAM,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC,WAAW;AACzD,YAAA,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU;AAC1C,YAAA,MAAM,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC,WAAW;AAE5D,YAAA,IAAI,YAAY,GAAG,aAAa,EAAE;AAChC,gBAAA,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YAChE;AAAO,iBAAA,IAAI,aAAa,GAAG,cAAc,EAAE;AACzC,gBAAA,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YACzF;QACF;IACF;uGA/CW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAX,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAX,WAAW,EAAA,UAAA,EAAA,CAAA;kBAHvB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,0BAA0B;AACrC,iBAAA;;;ACpBD;;AAEG;;;;"}
|
|
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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"}
|
|
@@ -50,9 +50,10 @@ class KtTooltip {
|
|
|
50
50
|
hideDelay = input(this.config?.hideDelay ?? 100, /* @ts-ignore */
|
|
51
51
|
...(ngDevMode ? [{ debugName: "hideDelay" }] : /* istanbul ignore next */ []));
|
|
52
52
|
idGen = inject(KtIdGenerator);
|
|
53
|
-
uid = this.idGen.generateId();
|
|
53
|
+
uid = this.idGen.generateId('tooltip');
|
|
54
54
|
tooltipId = `kt-tooltip-${this.uid}`;
|
|
55
|
-
|
|
55
|
+
/** Id du noeud `role="tooltip"`. Public : sert aux liaisons d'accessibilité (`aria-describedby`) du déclencheur. */
|
|
56
|
+
idForA11y = this.tooltipId;
|
|
56
57
|
anchorName = `--kt-tooltip-anchor-${this.uid}`;
|
|
57
58
|
/** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).
|
|
58
59
|
Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */
|
|
@@ -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\nexport interface KtTooltipConfig {\n showDelay: number;\n hideDelay: number;\n position: KtTooltipPosition;\n}\n\nexport const KT_TOOLTIP_CONFIG = new InjectionToken<Partial<KtTooltipConfig>>('KT_TOOLTIP_CONFIG');\n\n/**\n * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.\n *\n * @example\n * ```ts\n * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]\n * ```\n */\nexport function provideKtTooltip(config: Partial<KtTooltipConfig>): Provider {\n return { provide: KT_TOOLTIP_CONFIG, useValue: config };\n}\n\n/**\n * Infobulle accessible posée sur n'importe quel élément focusable/survolable.\n * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme\n * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**\n * (un `role=\"tooltip\"` ne doit pas contenir de lien/bouton/champ).\n *\n * @example\n * ```html\n * <button ktTooltip=\"Enregistrer le brouillon\">Enregistrer</button>\n * <span ktTooltip=\"Aide\" tooltipPosition=\"right\" [showDelay]=\"300\">?</span>\n * ```\n */\n@Directive({\n selector: '[ktTooltip]',\n host: {\n '[attr.aria-describedby]': 'describedById()',\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusin)': 'show()',\n '(focusout)': 'hide()',\n '(keydown.escape)': 'onEscape($event)',\n },\n})\nexport class KtTooltip implements OnDestroy {\n private readonly config = inject(KT_TOOLTIP_CONFIG, { optional: true });\n private readonly doc = inject(DOCUMENT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly vcr = inject(ViewContainerRef);\n private readonly ngZone = inject(NgZone);\n private readonly platformId = inject(PLATFORM_ID);\n\n /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */\n readonly ktTooltip = input.required<string | TemplateRef<unknown>>();\n /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */\n readonly tooltipPosition = input<KtTooltipPosition>(this.config?.position ?? 'top');\n /** Désactive l'affichage de l'infobulle. @default false */\n readonly tooltipDisabled = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */\n readonly showDelay = input<number>(this.config?.showDelay ?? 150);\n /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */\n readonly hideDelay = input<number>(this.config?.hideDelay ?? 100);\n\n private readonly idGen = inject(KtIdGenerator);\n private readonly uid = this.idGen.generateId();\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n readonly idForA11y = this.tooltipId; // Rendu public pour les liaisons d'accessibilité (aria-describedby)\n private readonly anchorName = `--kt-tooltip-anchor-${this.uid}`;\n\n /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).\n Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */\n readonly isActive = computed(() => {\n if (this.tooltipDisabled()) return false;\n\n const content = this.ktTooltip();\n if (typeof content === 'string') return content.trim().length > 0;\n return true;\n });\n\n // Retourner null retire l'attribut (même astuce que aria-disabled dans button).\n // Corrigé : aria-describedby n'est présent sur le déclencheur que si le tooltip est affiché.\n protected describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null));\n\n private tip: HTMLElement | null = null;\n private view: EmbeddedViewRef<unknown> | null = null;\n private listeners: (() => void)[] = [];\n private showTimer: ReturnType<typeof setTimeout> | undefined;\n private hideTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly isShown = signal(false);\n private _supportsAnchor: boolean | null = null;\n private get supportsAnchor(): boolean {\n if (this._supportsAnchor === null) {\n this._supportsAnchor =\n isPlatformBrowser(this.platformId) &&\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('anchor-name: --x');\n }\n return this._supportsAnchor;\n }\n private fallbackListeners: (() => void)[] = [];\n private activeTemplate: TemplateRef<unknown> | null = null;\n private escListener: (() => void) | null = null;\n\n constructor() {\n // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés\n // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.\n if (isPlatformBrowser(this.platformId)) {\n this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);\n }\n\n // Gestion réactive du cycle de vie du DOM du Tooltip\n effect(() => {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Création lazy : uniquement si actif ET affiché\n if (!this.isActive() || !this.isShown()) {\n this.destroyTip();\n return;\n }\n\n const tip = this.ensureTip();\n this.registerEscapeListener();\n this.syncContent();\n\n try {\n tip.showPopover?.();\n } catch {\n // Ignorer si déjà ouvert ou non supporté\n }\n\n if (!this.supportsAnchor) {\n this.positionFallback();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroyTip();\n }\n\n protected show(): void {\n if (!this.isActive()) return;\n\n this.ngZone.runOutsideAngular(() => {\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n this.ngZone.run(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n });\n }, this.showDelay());\n });\n }\n\n protected hide(): void {\n this.ngZone.runOutsideAngular(() => {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => {\n this.ngZone.run(() => this.dismiss());\n }, this.hideDelay());\n });\n }\n\n protected onEscape(event: Event): void {\n if (!this.isShown()) return;\n\n // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.\n this.dismiss();\n event.stopPropagation();\n }\n\n private dismiss(): void {\n if (!this.isShown()) return;\n\n this.isShown.set(false);\n }\n\n private ensureTip(): HTMLElement {\n if (this.tip) return this.tip;\n\n const tip = this.renderer.createElement('div') as HTMLElement;\n this.renderer.setAttribute(tip, 'role', 'tooltip');\n this.renderer.setAttribute(tip, 'id', this.tooltipId);\n // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.\n this.renderer.setAttribute(tip, 'popover', 'manual');\n this.renderer.addClass(tip, 'kt-tooltip');\n // setProperty natif : indispensable pour une propriété CSS à tiret.\n tip.style.setProperty('position-anchor', this.anchorName);\n // Top-layer : ajouté au body, immunisé contre overflow/z-index.\n this.renderer.appendChild(this.doc.body, tip);\n\n // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.\n this.listeners.push(\n this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)),\n this.renderer.listen(tip, 'mouseleave', () => this.hide()),\n );\n\n this.tip = tip;\n return tip;\n }\n\n private registerEscapeListener(): void {\n if (this.escListener) return;\n this.escListener = this.renderer.listen('document', 'keydown.escape', (event: KeyboardEvent) => {\n if (this.isShown()) {\n this.dismiss();\n event.stopPropagation();\n }\n });\n }\n\n private syncContent(): void {\n if (!this.tip) return;\n\n this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());\n\n const content = this.ktTooltip();\n\n if (content instanceof TemplateRef) {\n if (this.activeTemplate === content) return;\n this.clearContent();\n this.activeTemplate = content;\n\n this.view = this.vcr.createEmbeddedView(content);\n this.view.detectChanges();\n for (const node of this.view.rootNodes) {\n this.renderer.appendChild(this.tip, node);\n }\n if (isDevMode()) {\n this.warnIfInteractive();\n }\n return;\n }\n\n this.clearContent();\n this.renderer.setProperty(this.tip, 'textContent', content);\n }\n\n private clearContent(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n this.activeTemplate = null;\n if (this.tip) {\n this.renderer.setProperty(this.tip, 'textContent', '');\n }\n }\n\n // Garde-fou a11y : un role=\"tooltip\" ne doit pas contenir d'éléments focusables.\n private warnIfInteractive(): void {\n if (!this.tip) return;\n\n const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');\n if (!interactive) return;\n\n console.warn(\n `[ktTooltip] Un role=\"tooltip\" ne doit pas contenir d'éléments interactifs ` +\n `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`,\n );\n }\n\n private destroyTip(): void {\n clearTimeout(this.showTimer);\n clearTimeout(this.hideTimer);\n\n for (const unlisten of this.listeners) unlisten();\n this.listeners = [];\n this.clearFallbackListeners();\n\n if (this.escListener) {\n this.escListener();\n this.escListener = null;\n }\n\n this.view?.destroy();\n this.view = null;\n this.activeTemplate = null;\n\n if (this.tip) {\n try {\n this.tip.hidePopover?.();\n } catch {\n // Ignorer si déjà fermé ou non supporté\n }\n this.tip.remove();\n this.tip = null;\n }\n\n if (this.isShown()) {\n this.isShown.set(false);\n }\n }\n\n private positionFallback(): void {\n if (!this.tip) return;\n const triggerEl = this.host.nativeElement;\n const triggerRect = triggerEl.getBoundingClientRect();\n const tooltipRect = this.tip.getBoundingClientRect();\n const position = this.tooltipPosition();\n const gap = 8;\n\n let top = 0;\n let left = 0;\n\n if (position === 'top') {\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'bottom') {\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'left') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n } else if (position === 'right') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n }\n\n const viewWidth = window.innerWidth;\n const viewHeight = window.innerHeight;\n\n if (left < 4) left = 4;\n if (left + tooltipRect.width > viewWidth - 4) {\n left = viewWidth - tooltipRect.width - 4;\n }\n if (top < 4) {\n if (position === 'top') {\n top = triggerRect.bottom + gap;\n } else {\n top = 4;\n }\n }\n if (top + tooltipRect.height > viewHeight - 4) {\n if (position === 'bottom') {\n top = triggerRect.top - tooltipRect.height - gap;\n } else {\n top = viewHeight - tooltipRect.height - 4;\n }\n }\n\n this.tip.style.position = 'fixed';\n this.tip.style.top = `${top}px`;\n this.tip.style.left = `${left}px`;\n this.tip.style.margin = '0';\n }\n\n private registerFallbackListeners(): void {\n this.clearFallbackListeners();\n if (this.supportsAnchor || !isPlatformBrowser(this.platformId)) return;\n\n this.ngZone.runOutsideAngular(() => {\n const onScrollOrResize = () => {\n this.positionFallback();\n };\n window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });\n window.addEventListener('resize', onScrollOrResize);\n\n this.fallbackListeners.push(\n () => window.removeEventListener('scroll', onScrollOrResize, { capture: true }),\n () => window.removeEventListener('resize', onScrollOrResize),\n );\n });\n }\n\n private clearFallbackListeners(): void {\n for (const remove of this.fallbackListeners) remove();\n this.fallbackListeners = [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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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 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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"}
|
package/fesm2022/ktortu-aaa.mjs
CHANGED
|
@@ -3,6 +3,7 @@ export * from '@ktortu/aaa/card';
|
|
|
3
3
|
export * from '@ktortu/aaa/cdk';
|
|
4
4
|
export * from '@ktortu/aaa/dialog';
|
|
5
5
|
export * from '@ktortu/aaa/forms';
|
|
6
|
+
export * from '@ktortu/aaa/i18n';
|
|
6
7
|
export * from '@ktortu/aaa/menu';
|
|
7
8
|
export * from '@ktortu/aaa/tabs';
|
|
8
9
|
export * from '@ktortu/aaa/tooltip';
|