@cdevhub/ngx-tw 0.2.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/LICENSE +21 -0
- package/README.md +134 -0
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +108 -0
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-alert.mjs +240 -0
- package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +287 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +332 -0
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +452 -0
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-button.mjs +227 -0
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +417 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +232 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +4482 -0
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-card.mjs +157 -0
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +1454 -0
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +593 -0
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +228 -0
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +510 -0
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +1721 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +721 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-core.mjs +861 -0
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +1558 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +1833 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +693 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +331 -0
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +289 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +572 -0
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +36 -0
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +278 -0
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-input.mjs +355 -0
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-item.mjs +241 -0
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +433 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +691 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +678 -0
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +335 -0
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +708 -0
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +319 -0
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +1722 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-separator.mjs +115 -0
- package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +768 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +1147 -0
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +346 -0
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs +186 -0
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-split.mjs +1082 -0
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +579 -0
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +443 -0
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +391 -0
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +315 -0
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-table.mjs +994 -0
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +508 -0
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +147 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +178 -0
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +1344 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +1136 -0
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +1311 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +533 -0
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw.mjs +61 -0
- package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -0
- package/package.json +265 -0
- package/theme/_base.css +394 -0
- package/theme/_dark.css +510 -0
- package/theme/_high-contrast.css +290 -0
- package/theme/_semantic.css +317 -0
- package/theme/_typography.css +9 -0
- package/theme/index.css +54 -0
- package/types/cdevhub-ngx-tw-accordion.d.ts +48 -0
- package/types/cdevhub-ngx-tw-alert.d.ts +67 -0
- package/types/cdevhub-ngx-tw-avatar.d.ts +79 -0
- package/types/cdevhub-ngx-tw-badge.d.ts +94 -0
- package/types/cdevhub-ngx-tw-breadcrumbs.d.ts +227 -0
- package/types/cdevhub-ngx-tw-button.d.ts +74 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +200 -0
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +113 -0
- package/types/cdevhub-ngx-tw-calendar.d.ts +1704 -0
- package/types/cdevhub-ngx-tw-card.d.ts +48 -0
- package/types/cdevhub-ngx-tw-carousel.d.ts +406 -0
- package/types/cdevhub-ngx-tw-checkbox.d.ts +136 -0
- package/types/cdevhub-ngx-tw-code-block.d.ts +93 -0
- package/types/cdevhub-ngx-tw-collapsible.d.ts +151 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +389 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +215 -0
- package/types/cdevhub-ngx-tw-core.d.ts +719 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +317 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +313 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +303 -0
- package/types/cdevhub-ngx-tw-empty-state.d.ts +104 -0
- package/types/cdevhub-ngx-tw-flip-card.d.ts +95 -0
- package/types/cdevhub-ngx-tw-form-field.d.ts +210 -0
- package/types/cdevhub-ngx-tw-icon-lucide.d.ts +29 -0
- package/types/cdevhub-ngx-tw-icon.d.ts +134 -0
- package/types/cdevhub-ngx-tw-input.d.ts +110 -0
- package/types/cdevhub-ngx-tw-item.d.ts +70 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +99 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +305 -0
- package/types/cdevhub-ngx-tw-popover.d.ts +157 -0
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +100 -0
- package/types/cdevhub-ngx-tw-radio.d.ts +174 -0
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +66 -0
- package/types/cdevhub-ngx-tw-select.d.ts +384 -0
- package/types/cdevhub-ngx-tw-separator.d.ts +28 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +335 -0
- package/types/cdevhub-ngx-tw-skeleton.d.ts +52 -0
- package/types/cdevhub-ngx-tw-slider.d.ts +258 -0
- package/types/cdevhub-ngx-tw-sort.d.ts +136 -0
- package/types/cdevhub-ngx-tw-spinner.d.ts +50 -0
- package/types/cdevhub-ngx-tw-split.d.ts +265 -0
- package/types/cdevhub-ngx-tw-stat.d.ts +140 -0
- package/types/cdevhub-ngx-tw-stepper.d.ts +127 -0
- package/types/cdevhub-ngx-tw-switch.d.ts +88 -0
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +107 -0
- package/types/cdevhub-ngx-tw-table.d.ts +479 -0
- package/types/cdevhub-ngx-tw-tabs.d.ts +121 -0
- package/types/cdevhub-ngx-tw-textarea.d.ts +62 -0
- package/types/cdevhub-ngx-tw-theme.d.ts +106 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +303 -0
- package/types/cdevhub-ngx-tw-timeline.d.ts +278 -0
- package/types/cdevhub-ngx-tw-toast.d.ts +388 -0
- package/types/cdevhub-ngx-tw-tooltip.d.ts +95 -0
- package/types/cdevhub-ngx-tw.d.ts +49 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, TemplateRef, Directive, input, contentChild, viewChild, ChangeDetectionStrategy, Component, ElementRef, computed, model, output, DestroyRef, contentChildren, viewChildren, linkedSignal, signal, afterNextRender, effect, untracked } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import { LiveAnnouncer, FocusKeyManager } from '@angular/cdk/a11y';
|
|
5
|
+
import { tv } from 'tailwind-variants';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { tabTriggerVariants, getActiveTriggerClasses, getInactiveTriggerClasses } from '@cdevhub/ngx-tw/core';
|
|
8
|
+
|
|
9
|
+
// ── tv() config (component-local slots only — trigger config is shared) ──
|
|
10
|
+
const tabsLayoutVariants = tv({
|
|
11
|
+
slots: {
|
|
12
|
+
root: 'flex',
|
|
13
|
+
tablist: 'relative flex shrink-0',
|
|
14
|
+
tablistInner: 'flex overflow-x-auto',
|
|
15
|
+
panel: 'min-w-0 flex-1',
|
|
16
|
+
scrollButton: 'inline-flex items-center justify-center shrink-0 cursor-pointer transition-colors duration-normal motion-reduce:transition-none disabled:opacity-30 disabled:cursor-default hover:bg-surface-muted',
|
|
17
|
+
closeButton: 'inline-flex items-center justify-center rounded-md cursor-pointer transition-colors duration-normal motion-reduce:transition-none hover:bg-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',
|
|
18
|
+
},
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
underline: {
|
|
22
|
+
tablist: 'border-b border-border',
|
|
23
|
+
tablistInner: 'gap-0',
|
|
24
|
+
panel: 'pt-4',
|
|
25
|
+
},
|
|
26
|
+
enclosed: {
|
|
27
|
+
tablist: 'border-b border-border',
|
|
28
|
+
tablistInner: 'gap-0',
|
|
29
|
+
panel: 'pt-4',
|
|
30
|
+
},
|
|
31
|
+
pill: {
|
|
32
|
+
tablist: 'bg-surface-muted rounded-xl p-1',
|
|
33
|
+
tablistInner: 'gap-1',
|
|
34
|
+
panel: 'pt-4',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
// Square interactive-target scale: see CLAUDE.md "Icon Sizing".
|
|
38
|
+
size: {
|
|
39
|
+
xs: { scrollButton: 'size-5', closeButton: 'size-6' },
|
|
40
|
+
sm: { scrollButton: 'size-5', closeButton: 'size-7' },
|
|
41
|
+
md: { scrollButton: 'size-6', closeButton: 'size-8' },
|
|
42
|
+
lg: { scrollButton: 'size-7', closeButton: 'size-9' },
|
|
43
|
+
xl: { scrollButton: 'size-8', closeButton: 'size-9' },
|
|
44
|
+
},
|
|
45
|
+
orientation: {
|
|
46
|
+
horizontal: {
|
|
47
|
+
root: 'flex-col',
|
|
48
|
+
tablist: '',
|
|
49
|
+
tablistInner: 'flex-row',
|
|
50
|
+
},
|
|
51
|
+
vertical: {
|
|
52
|
+
root: 'flex-row',
|
|
53
|
+
tablistInner: 'flex-col overflow-y-auto overflow-x-hidden',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
compoundVariants: [
|
|
58
|
+
{
|
|
59
|
+
variant: 'underline',
|
|
60
|
+
orientation: 'vertical',
|
|
61
|
+
class: {
|
|
62
|
+
tablist: 'border-b-0 border-r border-border',
|
|
63
|
+
panel: 'pt-0 pl-4',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
variant: 'enclosed',
|
|
68
|
+
orientation: 'vertical',
|
|
69
|
+
class: {
|
|
70
|
+
tablist: 'border-b-0 border-r border-border',
|
|
71
|
+
panel: 'pt-0 pl-4',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
variant: 'pill',
|
|
76
|
+
orientation: 'vertical',
|
|
77
|
+
class: {
|
|
78
|
+
panel: 'pt-0 pl-4',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
defaultVariants: {
|
|
83
|
+
variant: 'underline',
|
|
84
|
+
size: 'md',
|
|
85
|
+
orientation: 'horizontal',
|
|
86
|
+
},
|
|
87
|
+
}, { twMerge: true });
|
|
88
|
+
// ── Per-variant/orientation trigger additions (vertical underline/enclosed
|
|
89
|
+
// re-route the active border axis, hence these compound overrides). ──
|
|
90
|
+
function getTriggerOrientationExtras(variant, orientation) {
|
|
91
|
+
if (orientation !== 'vertical')
|
|
92
|
+
return '';
|
|
93
|
+
switch (variant) {
|
|
94
|
+
case 'underline':
|
|
95
|
+
return 'border-b-0 -mb-0 border-r-2 border-transparent -mr-px';
|
|
96
|
+
case 'enclosed':
|
|
97
|
+
return '-mb-0 -mr-px';
|
|
98
|
+
case 'pill':
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ── Directives ──
|
|
103
|
+
class TabTriggerDirective {
|
|
104
|
+
templateRef = inject(TemplateRef);
|
|
105
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
106
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: TabTriggerDirective, isStandalone: true, selector: "ng-template[twTabTrigger]", ngImport: i0 });
|
|
107
|
+
}
|
|
108
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabTriggerDirective, decorators: [{
|
|
109
|
+
type: Directive,
|
|
110
|
+
args: [{ selector: 'ng-template[twTabTrigger]' }]
|
|
111
|
+
}] });
|
|
112
|
+
class TabContentDirective {
|
|
113
|
+
templateRef = inject(TemplateRef);
|
|
114
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
115
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: TabContentDirective, isStandalone: true, selector: "ng-template[twTabContent]", ngImport: i0 });
|
|
116
|
+
}
|
|
117
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabContentDirective, decorators: [{
|
|
118
|
+
type: Directive,
|
|
119
|
+
args: [{ selector: 'ng-template[twTabContent]' }]
|
|
120
|
+
}] });
|
|
121
|
+
// ── TabComponent ──
|
|
122
|
+
class TabComponent {
|
|
123
|
+
/** Unique identifier for this tab. Used to match the active tab value. */
|
|
124
|
+
value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
125
|
+
/** Plain text label shown in the trigger. Ignored when a custom trigger template is provided. */
|
|
126
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
127
|
+
/** When true, the tab cannot be selected and is skipped by keyboard navigation. Defaults to false. */
|
|
128
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
129
|
+
/** When true, a close button is rendered in the tab trigger. Defaults to false. */
|
|
130
|
+
closable = input(false, ...(ngDevMode ? [{ debugName: "closable" }] : /* istanbul ignore next */ []));
|
|
131
|
+
/** When true, the tab panel content is only instantiated when the tab becomes active for the first time. Defaults to false. */
|
|
132
|
+
lazy = input(false, ...(ngDevMode ? [{ debugName: "lazy" }] : /* istanbul ignore next */ []));
|
|
133
|
+
/** @internal Custom trigger template, if provided. */
|
|
134
|
+
triggerTemplate = contentChild(TabTriggerDirective, ...(ngDevMode ? [{ debugName: "triggerTemplate" }] : /* istanbul ignore next */ []));
|
|
135
|
+
/** @internal Custom content template, if provided via twTabContent. */
|
|
136
|
+
contentTemplate = contentChild(TabContentDirective, ...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
|
|
137
|
+
/** @internal Implicit content template wrapping ng-content. */
|
|
138
|
+
implicitContentTemplate = viewChild('implicitContent', ...(ngDevMode ? [{ debugName: "implicitContentTemplate" }] : /* istanbul ignore next */ []));
|
|
139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.14", type: TabComponent, isStandalone: true, selector: "tw-tab", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: none" }, queries: [{ propertyName: "triggerTemplate", first: true, predicate: TabTriggerDirective, descendants: true, isSignal: true }, { propertyName: "contentTemplate", first: true, predicate: TabContentDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "implicitContentTemplate", first: true, predicate: ["implicitContent"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
141
|
+
<ng-template #implicitContent>
|
|
142
|
+
<ng-content />
|
|
143
|
+
</ng-template>
|
|
144
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
145
|
+
}
|
|
146
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabComponent, decorators: [{
|
|
147
|
+
type: Component,
|
|
148
|
+
args: [{
|
|
149
|
+
selector: 'tw-tab',
|
|
150
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
151
|
+
template: `
|
|
152
|
+
<ng-template #implicitContent>
|
|
153
|
+
<ng-content />
|
|
154
|
+
</ng-template>
|
|
155
|
+
`,
|
|
156
|
+
host: {
|
|
157
|
+
'style': 'display: none',
|
|
158
|
+
},
|
|
159
|
+
}]
|
|
160
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], triggerTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TabTriggerDirective), { isSignal: true }] }], contentTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TabContentDirective), { isSignal: true }] }], implicitContentTemplate: [{ type: i0.ViewChild, args: ['implicitContent', { isSignal: true }] }] } });
|
|
161
|
+
// ── Tab trigger element wrapper ──
|
|
162
|
+
class TabTriggerElementDirective {
|
|
163
|
+
elementRef = inject((ElementRef));
|
|
164
|
+
isActive = input(false, ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
|
|
165
|
+
isDisabled = input(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
166
|
+
tabIndex = computed(() => this.isActive() ? 0 : -1, ...(ngDevMode ? [{ debugName: "tabIndex" }] : /* istanbul ignore next */ []));
|
|
167
|
+
focus() {
|
|
168
|
+
this.elementRef.nativeElement.focus();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* FocusableOption getter. NOTE: we cannot expose the `isDisabled` input
|
|
172
|
+
* signal directly — the signal function itself is always truthy, which would
|
|
173
|
+
* make FocusKeyManager treat every trigger as disabled. We resolve the
|
|
174
|
+
* signal here so the manager skips the right items.
|
|
175
|
+
*/
|
|
176
|
+
get disabled() {
|
|
177
|
+
return this.isDisabled();
|
|
178
|
+
}
|
|
179
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabTriggerElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
180
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: TabTriggerElementDirective, isStandalone: true, selector: "[twTabTriggerElement]", inputs: { isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.tabindex": "tabIndex()" } }, ngImport: i0 });
|
|
181
|
+
}
|
|
182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabTriggerElementDirective, decorators: [{
|
|
183
|
+
type: Directive,
|
|
184
|
+
args: [{
|
|
185
|
+
selector: '[twTabTriggerElement]',
|
|
186
|
+
host: {
|
|
187
|
+
'[attr.tabindex]': 'tabIndex()',
|
|
188
|
+
},
|
|
189
|
+
}]
|
|
190
|
+
}], propDecorators: { isActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "isActive", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }] } });
|
|
191
|
+
// ── TabsComponent ──
|
|
192
|
+
let nextId = 0;
|
|
193
|
+
class TabsComponent {
|
|
194
|
+
/** Controls the visual style of the tab strip. Defaults to 'underline'. */
|
|
195
|
+
variant = input('underline', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
196
|
+
/** Sets the semantic color for active tab indicators and highlights. Defaults to 'primary'. */
|
|
197
|
+
color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
198
|
+
/** Controls padding, font size, and icon size of tab triggers. Defaults to 'md'. */
|
|
199
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
200
|
+
/** Layout direction of the tab strip. Defaults to 'horizontal'. */
|
|
201
|
+
orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
202
|
+
/** When true, tab triggers stretch to fill the available width equally. Defaults to false. */
|
|
203
|
+
fitted = input(false, ...(ngDevMode ? [{ debugName: "fitted" }] : /* istanbul ignore next */ []));
|
|
204
|
+
/** The value of the currently active tab. Two-way bound. Updates when the user selects a tab. */
|
|
205
|
+
value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
206
|
+
/** Fires when a closable tab's close button is clicked. Payload is the tab's value. */
|
|
207
|
+
closed = output();
|
|
208
|
+
destroyRef = inject(DestroyRef);
|
|
209
|
+
liveAnnouncer = inject(LiveAnnouncer);
|
|
210
|
+
/** @internal */
|
|
211
|
+
tabs = contentChildren(TabComponent, ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
212
|
+
/** @internal */
|
|
213
|
+
triggerElements = viewChildren(TabTriggerElementDirective, ...(ngDevMode ? [{ debugName: "triggerElements" }] : /* istanbul ignore next */ []));
|
|
214
|
+
/** @internal */
|
|
215
|
+
tablistInnerRef = viewChild('tablistInner', ...(ngDevMode ? [{ debugName: "tablistInnerRef" }] : /* istanbul ignore next */ []));
|
|
216
|
+
componentId = `tw-tabs-${nextId++}`;
|
|
217
|
+
// ── Active tab tracking ──
|
|
218
|
+
activeValue = linkedSignal(() => this.value(), ...(ngDevMode ? [{ debugName: "activeValue" }] : /* istanbul ignore next */ []));
|
|
219
|
+
// ── Lazy tab tracking — Set of tab values that have been activated at least once ──
|
|
220
|
+
activatedTabs = signal(new Set(), ...(ngDevMode ? [{ debugName: "activatedTabs" }] : /* istanbul ignore next */ []));
|
|
221
|
+
// ── Scroll overflow signals ──
|
|
222
|
+
canScrollStart = signal(false, ...(ngDevMode ? [{ debugName: "canScrollStart" }] : /* istanbul ignore next */ []));
|
|
223
|
+
canScrollEnd = signal(false, ...(ngDevMode ? [{ debugName: "canScrollEnd" }] : /* istanbul ignore next */ []));
|
|
224
|
+
resizeObserver = null;
|
|
225
|
+
scrollCleanup = null;
|
|
226
|
+
// ── Variant classes ──
|
|
227
|
+
layoutResult = computed(() => tabsLayoutVariants({
|
|
228
|
+
variant: this.variant(),
|
|
229
|
+
size: this.size(),
|
|
230
|
+
orientation: this.orientation(),
|
|
231
|
+
}), ...(ngDevMode ? [{ debugName: "layoutResult" }] : /* istanbul ignore next */ []));
|
|
232
|
+
triggerResult = computed(() => tabTriggerVariants({
|
|
233
|
+
variant: this.variant(),
|
|
234
|
+
color: this.color(),
|
|
235
|
+
size: this.size(),
|
|
236
|
+
fitted: this.fitted(),
|
|
237
|
+
}), ...(ngDevMode ? [{ debugName: "triggerResult" }] : /* istanbul ignore next */ []));
|
|
238
|
+
rootClasses = computed(() => this.layoutResult().root(), ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
|
|
239
|
+
tablistClasses = computed(() => this.layoutResult().tablist(), ...(ngDevMode ? [{ debugName: "tablistClasses" }] : /* istanbul ignore next */ []));
|
|
240
|
+
tablistInnerClasses = computed(() => this.layoutResult().tablistInner(), ...(ngDevMode ? [{ debugName: "tablistInnerClasses" }] : /* istanbul ignore next */ []));
|
|
241
|
+
baseTriggerClasses = computed(() => this.triggerResult().trigger(), ...(ngDevMode ? [{ debugName: "baseTriggerClasses" }] : /* istanbul ignore next */ []));
|
|
242
|
+
panelClasses = computed(() => this.layoutResult().panel(), ...(ngDevMode ? [{ debugName: "panelClasses" }] : /* istanbul ignore next */ []));
|
|
243
|
+
scrollButtonClasses = computed(() => this.layoutResult().scrollButton(), ...(ngDevMode ? [{ debugName: "scrollButtonClasses" }] : /* istanbul ignore next */ []));
|
|
244
|
+
closeButtonClasses = computed(() => this.layoutResult().closeButton(), ...(ngDevMode ? [{ debugName: "closeButtonClasses" }] : /* istanbul ignore next */ []));
|
|
245
|
+
// ── Per-trigger active/inactive class computation ──
|
|
246
|
+
/** @internal Get combined trigger classes for a given tab. */
|
|
247
|
+
getTriggerClasses(_tabValue, isActive) {
|
|
248
|
+
const base = this.baseTriggerClasses();
|
|
249
|
+
const orientationExtras = getTriggerOrientationExtras(this.variant(), this.orientation());
|
|
250
|
+
const state = isActive
|
|
251
|
+
? getActiveTriggerClasses(this.variant(), this.color(), this.orientation())
|
|
252
|
+
: getInactiveTriggerClasses(this.variant());
|
|
253
|
+
return twMerge(base, orientationExtras, state);
|
|
254
|
+
}
|
|
255
|
+
// ── ID generation ──
|
|
256
|
+
getTabId(tabValue) {
|
|
257
|
+
return `${this.componentId}-tab-${tabValue}`;
|
|
258
|
+
}
|
|
259
|
+
getPanelId(tabValue) {
|
|
260
|
+
return `${this.componentId}-panel-${tabValue}`;
|
|
261
|
+
}
|
|
262
|
+
// ── Tab visibility ──
|
|
263
|
+
isTabActive(tabValue) {
|
|
264
|
+
return this.activeValue() === tabValue;
|
|
265
|
+
}
|
|
266
|
+
shouldRenderPanel(tab) {
|
|
267
|
+
const value = tab.value();
|
|
268
|
+
if (!tab.lazy()) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
// Lazy: render only if it has been activated at least once
|
|
272
|
+
return this.activatedTabs().has(value);
|
|
273
|
+
}
|
|
274
|
+
// ── Selection ──
|
|
275
|
+
selectTab(tab) {
|
|
276
|
+
if (tab.disabled())
|
|
277
|
+
return;
|
|
278
|
+
const val = tab.value();
|
|
279
|
+
this.activeValue.set(val);
|
|
280
|
+
this.value.set(val);
|
|
281
|
+
// Mark as activated for lazy tabs
|
|
282
|
+
this.activatedTabs.update(set => {
|
|
283
|
+
const next = new Set(set);
|
|
284
|
+
next.add(val);
|
|
285
|
+
return next;
|
|
286
|
+
});
|
|
287
|
+
// Announce to screen readers
|
|
288
|
+
const tabsArr = this.tabs();
|
|
289
|
+
const idx = tabsArr.findIndex(t => t.value() === val);
|
|
290
|
+
this.liveAnnouncer.announce(`${tab.label() || val} tab, ${idx + 1} of ${tabsArr.length}`);
|
|
291
|
+
}
|
|
292
|
+
closeTab(tab, event) {
|
|
293
|
+
event.stopPropagation();
|
|
294
|
+
if (event instanceof KeyboardEvent) {
|
|
295
|
+
event.preventDefault();
|
|
296
|
+
}
|
|
297
|
+
const val = tab.value();
|
|
298
|
+
this.closed.emit(val);
|
|
299
|
+
// If closing the active tab, activate nearest enabled sibling
|
|
300
|
+
if (this.isTabActive(val)) {
|
|
301
|
+
const tabsArr = this.tabs();
|
|
302
|
+
const idx = tabsArr.findIndex(t => t.value() === val);
|
|
303
|
+
const next = this.findNearestEnabledTab(tabsArr, idx);
|
|
304
|
+
if (next) {
|
|
305
|
+
this.selectTab(next);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
findNearestEnabledTab(tabs, fromIndex) {
|
|
310
|
+
// Search forward first, then backward
|
|
311
|
+
for (let i = fromIndex + 1; i < tabs.length; i++) {
|
|
312
|
+
if (!tabs[i].disabled())
|
|
313
|
+
return tabs[i];
|
|
314
|
+
}
|
|
315
|
+
for (let i = fromIndex - 1; i >= 0; i--) {
|
|
316
|
+
if (!tabs[i].disabled())
|
|
317
|
+
return tabs[i];
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
// ── Keyboard navigation (CDK FocusKeyManager) ──
|
|
322
|
+
keyManager = null;
|
|
323
|
+
/**
|
|
324
|
+
* @internal Handles keyboard navigation. The manager handles Arrow/Home/End;
|
|
325
|
+
* we layer Enter/Space to select the focused tab (the wrapper is a `<div role="tab">`
|
|
326
|
+
* so we lose the native button activation) and Delete to close a closable tab.
|
|
327
|
+
*/
|
|
328
|
+
onKeydown(event) {
|
|
329
|
+
if (!this.keyManager)
|
|
330
|
+
return;
|
|
331
|
+
const triggers = this.triggerElements();
|
|
332
|
+
if (triggers.length === 0)
|
|
333
|
+
return;
|
|
334
|
+
// Sync active item with the trigger DOM-focused by the user. We accept
|
|
335
|
+
// either `event.target` (which works under shadow DOM) or the currently
|
|
336
|
+
// active tab's index as a safety net (e.g. when the event was dispatched
|
|
337
|
+
// on the tablist container itself, not a trigger).
|
|
338
|
+
const focusedIdx = triggers.findIndex(t => t.elementRef.nativeElement === event.target);
|
|
339
|
+
const activeIdx = focusedIdx >= 0
|
|
340
|
+
? focusedIdx
|
|
341
|
+
: this.tabs().findIndex(t => t.value() === this.activeValue());
|
|
342
|
+
if (activeIdx >= 0 && activeIdx !== this.keyManager.activeItemIndex) {
|
|
343
|
+
this.keyManager.setActiveItem(activeIdx);
|
|
344
|
+
}
|
|
345
|
+
// Enter / Space select the focused tab (we no longer get this for free
|
|
346
|
+
// because the trigger is a div, not a button — see DOM restructure below).
|
|
347
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
348
|
+
if (focusedIdx >= 0) {
|
|
349
|
+
event.preventDefault();
|
|
350
|
+
this.selectTab(this.tabs()[focusedIdx]);
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// Delete on a closable tab dismisses it (APG-recommended). Keyboard users
|
|
355
|
+
// who don't want to traverse to the close button can dismiss inline.
|
|
356
|
+
if (event.key === 'Delete' && focusedIdx >= 0) {
|
|
357
|
+
const tab = this.tabs()[focusedIdx];
|
|
358
|
+
if (tab.closable() && !tab.disabled()) {
|
|
359
|
+
event.preventDefault();
|
|
360
|
+
this.closeTab(tab, event);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Let the manager handle arrow/home/end navigation.
|
|
365
|
+
const before = this.keyManager.activeItemIndex;
|
|
366
|
+
this.keyManager.onKeydown(event);
|
|
367
|
+
const after = this.keyManager.activeItemIndex;
|
|
368
|
+
if (after !== null && after !== before && after >= 0) {
|
|
369
|
+
// Automatic activation pattern (APG): selection follows focus.
|
|
370
|
+
this.selectTab(this.tabs()[after]);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// ── Scrolling ──
|
|
374
|
+
scrollStart() {
|
|
375
|
+
const el = this.tablistInnerRef()?.nativeElement;
|
|
376
|
+
if (!el)
|
|
377
|
+
return;
|
|
378
|
+
const isVertical = this.orientation() === 'vertical';
|
|
379
|
+
if (isVertical) {
|
|
380
|
+
el.scrollBy({ top: -120, behavior: 'smooth' });
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
el.scrollBy({ left: -120, behavior: 'smooth' });
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
scrollEnd() {
|
|
387
|
+
const el = this.tablistInnerRef()?.nativeElement;
|
|
388
|
+
if (!el)
|
|
389
|
+
return;
|
|
390
|
+
const isVertical = this.orientation() === 'vertical';
|
|
391
|
+
if (isVertical) {
|
|
392
|
+
el.scrollBy({ top: 120, behavior: 'smooth' });
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
el.scrollBy({ left: 120, behavior: 'smooth' });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
updateScrollState() {
|
|
399
|
+
const el = this.tablistInnerRef()?.nativeElement;
|
|
400
|
+
if (!el)
|
|
401
|
+
return;
|
|
402
|
+
const isVertical = this.orientation() === 'vertical';
|
|
403
|
+
if (isVertical) {
|
|
404
|
+
this.canScrollStart.set(el.scrollTop > 0);
|
|
405
|
+
this.canScrollEnd.set(el.scrollTop + el.clientHeight < el.scrollHeight - 1);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
this.canScrollStart.set(el.scrollLeft > 0);
|
|
409
|
+
this.canScrollEnd.set(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
ngAfterViewInit() {
|
|
413
|
+
this.initializeActiveTab();
|
|
414
|
+
}
|
|
415
|
+
constructor() {
|
|
416
|
+
afterNextRender(() => {
|
|
417
|
+
this.setupScrollDetection();
|
|
418
|
+
});
|
|
419
|
+
// Rebuild FocusKeyManager whenever triggers or orientation change.
|
|
420
|
+
effect((onCleanup) => {
|
|
421
|
+
const triggers = this.triggerElements();
|
|
422
|
+
const orientation = this.orientation();
|
|
423
|
+
if (triggers.length === 0) {
|
|
424
|
+
this.keyManager = null;
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const manager = new FocusKeyManager(triggers)
|
|
428
|
+
.withWrap()
|
|
429
|
+
.withHomeAndEnd();
|
|
430
|
+
if (orientation === 'vertical') {
|
|
431
|
+
manager.withVerticalOrientation();
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
manager.withHorizontalOrientation('ltr');
|
|
435
|
+
}
|
|
436
|
+
this.keyManager = manager;
|
|
437
|
+
// Initialise the manager's active index to the active tab so the first
|
|
438
|
+
// arrow press moves from the active item, not from -1.
|
|
439
|
+
untracked(() => {
|
|
440
|
+
const activeVal = this.activeValue();
|
|
441
|
+
const tabs = this.tabs();
|
|
442
|
+
const idx = tabs.findIndex(t => t.value() === activeVal);
|
|
443
|
+
if (idx >= 0) {
|
|
444
|
+
manager.setActiveItem(idx);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
onCleanup(() => {
|
|
448
|
+
manager.destroy();
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
this.destroyRef.onDestroy(() => {
|
|
452
|
+
this.resizeObserver?.disconnect();
|
|
453
|
+
this.scrollCleanup?.();
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
initializeActiveTab() {
|
|
457
|
+
// If no value was provided, default to the first enabled tab
|
|
458
|
+
if (!this.activeValue()) {
|
|
459
|
+
const first = this.tabs().find(t => !t.disabled());
|
|
460
|
+
if (first) {
|
|
461
|
+
this.activeValue.set(first.value());
|
|
462
|
+
this.value.set(first.value());
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
// Mark the initial active tab as activated (for lazy tracking)
|
|
466
|
+
const val = this.activeValue();
|
|
467
|
+
if (val) {
|
|
468
|
+
this.activatedTabs.update(set => {
|
|
469
|
+
const next = new Set(set);
|
|
470
|
+
next.add(val);
|
|
471
|
+
return next;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
setupScrollDetection() {
|
|
476
|
+
const el = this.tablistInnerRef()?.nativeElement;
|
|
477
|
+
if (!el)
|
|
478
|
+
return;
|
|
479
|
+
// Initial check
|
|
480
|
+
this.updateScrollState();
|
|
481
|
+
// ResizeObserver for container size changes
|
|
482
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
483
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
484
|
+
this.updateScrollState();
|
|
485
|
+
});
|
|
486
|
+
this.resizeObserver.observe(el);
|
|
487
|
+
}
|
|
488
|
+
// Scroll event for scroll position changes
|
|
489
|
+
const onScroll = () => this.updateScrollState();
|
|
490
|
+
el.addEventListener('scroll', onScroll, { passive: true });
|
|
491
|
+
this.scrollCleanup = () => el.removeEventListener('scroll', onScroll);
|
|
492
|
+
}
|
|
493
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
494
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: TabsComponent, isStandalone: true, selector: "tw-tabs", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, fitted: { classPropertyName: "fitted", publicName: "fitted", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", closed: "closed" }, host: { properties: { "class": "rootClasses()" } }, queries: [{ propertyName: "tabs", predicate: TabComponent, isSignal: true }], viewQueries: [{ propertyName: "triggerElements", predicate: TabTriggerElementDirective, descendants: true, isSignal: true }, { propertyName: "tablistInnerRef", first: true, predicate: ["tablistInner"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Tablist container -->\n<div\n [class]=\"tablistClasses()\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientation()\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Scroll start button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollStart()\"\n (click)=\"scrollStart()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n\n <!-- Scrollable trigger strip -->\n <div #tablistInner [class]=\"tablistInnerClasses()\" style=\"scrollbar-width: none\">\n @for (tab of tabs(); track tab.value()) {\n <!-- Trigger is rendered as <div role=\"tab\"> (not <button>) so the close\n affordance can be a native <button> child without nesting interactive\n content (invalid HTML). Activation is wired explicitly via (click)\n and the parent tablist (keydown.enter / keydown.space). -->\n <div\n role=\"tab\"\n twTabTriggerElement\n [isActive]=\"isTabActive(tab.value())\"\n [isDisabled]=\"tab.disabled()\"\n [id]=\"getTabId(tab.value())\"\n [attr.aria-selected]=\"isTabActive(tab.value())\"\n [attr.aria-controls]=\"getPanelId(tab.value())\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [class]=\"getTriggerClasses(tab.value(), isTabActive(tab.value()))\"\n [class.opacity-50]=\"tab.disabled()\"\n [class.pointer-events-none]=\"tab.disabled()\"\n (click)=\"selectTab(tab)\"\n >\n <!-- Custom trigger template or default label -->\n @if (tab.triggerTemplate(); as triggerDir) {\n <ng-container\n [ngTemplateOutlet]=\"triggerDir.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: { active: isTabActive(tab.value()), disabled: tab.disabled(), value: tab.value() } }\"\n />\n } @else {\n {{ tab.label() }}\n }\n\n <!-- Close affordance \u2014 native <button> so it is keyboard-focusable.\n Valid because the trigger is a <div role=\"tab\">, not a button. -->\n @if (tab.closable() && !tab.disabled()) {\n <button\n type=\"button\"\n [attr.aria-label]=\"'Close ' + (tab.label() || tab.value())\"\n [class]=\"closeButtonClasses()\"\n (click)=\"closeTab(tab, $event)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path d=\"M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z\"/>\n </svg>\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Scroll end button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollEnd()\"\n (click)=\"scrollEnd()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n</div>\n\n<!-- Tab panels -->\n@for (tab of tabs(); track tab.value()) {\n @if (shouldRenderPanel(tab)) {\n <div\n role=\"tabpanel\"\n [id]=\"getPanelId(tab.value())\"\n [attr.aria-labelledby]=\"getTabId(tab.value())\"\n [class]=\"panelClasses()\"\n [hidden]=\"!isTabActive(tab.value())\"\n tabindex=\"0\"\n >\n @if (tab.contentTemplate(); as contentDir) {\n <ng-container [ngTemplateOutlet]=\"contentDir.templateRef\" />\n } @else if (tab.implicitContentTemplate(); as implicitTpl) {\n <ng-container [ngTemplateOutlet]=\"implicitTpl\" />\n }\n </div>\n }\n}\n\n<!-- Hidden projection slot for tw-tab children -->\n<div style=\"display: none\">\n <ng-content />\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TabTriggerElementDirective, selector: "[twTabTriggerElement]", inputs: ["isActive", "isDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
495
|
+
}
|
|
496
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TabsComponent, decorators: [{
|
|
497
|
+
type: Component,
|
|
498
|
+
args: [{ selector: 'tw-tabs', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, TabTriggerElementDirective], host: {
|
|
499
|
+
'[class]': 'rootClasses()',
|
|
500
|
+
}, template: "<!-- Tablist container -->\n<div\n [class]=\"tablistClasses()\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientation()\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Scroll start button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollStart()\"\n (click)=\"scrollStart()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n\n <!-- Scrollable trigger strip -->\n <div #tablistInner [class]=\"tablistInnerClasses()\" style=\"scrollbar-width: none\">\n @for (tab of tabs(); track tab.value()) {\n <!-- Trigger is rendered as <div role=\"tab\"> (not <button>) so the close\n affordance can be a native <button> child without nesting interactive\n content (invalid HTML). Activation is wired explicitly via (click)\n and the parent tablist (keydown.enter / keydown.space). -->\n <div\n role=\"tab\"\n twTabTriggerElement\n [isActive]=\"isTabActive(tab.value())\"\n [isDisabled]=\"tab.disabled()\"\n [id]=\"getTabId(tab.value())\"\n [attr.aria-selected]=\"isTabActive(tab.value())\"\n [attr.aria-controls]=\"getPanelId(tab.value())\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [class]=\"getTriggerClasses(tab.value(), isTabActive(tab.value()))\"\n [class.opacity-50]=\"tab.disabled()\"\n [class.pointer-events-none]=\"tab.disabled()\"\n (click)=\"selectTab(tab)\"\n >\n <!-- Custom trigger template or default label -->\n @if (tab.triggerTemplate(); as triggerDir) {\n <ng-container\n [ngTemplateOutlet]=\"triggerDir.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: { active: isTabActive(tab.value()), disabled: tab.disabled(), value: tab.value() } }\"\n />\n } @else {\n {{ tab.label() }}\n }\n\n <!-- Close affordance \u2014 native <button> so it is keyboard-focusable.\n Valid because the trigger is a <div role=\"tab\">, not a button. -->\n @if (tab.closable() && !tab.disabled()) {\n <button\n type=\"button\"\n [attr.aria-label]=\"'Close ' + (tab.label() || tab.value())\"\n [class]=\"closeButtonClasses()\"\n (click)=\"closeTab(tab, $event)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path d=\"M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z\"/>\n </svg>\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Scroll end button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollEnd()\"\n (click)=\"scrollEnd()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n</div>\n\n<!-- Tab panels -->\n@for (tab of tabs(); track tab.value()) {\n @if (shouldRenderPanel(tab)) {\n <div\n role=\"tabpanel\"\n [id]=\"getPanelId(tab.value())\"\n [attr.aria-labelledby]=\"getTabId(tab.value())\"\n [class]=\"panelClasses()\"\n [hidden]=\"!isTabActive(tab.value())\"\n tabindex=\"0\"\n >\n @if (tab.contentTemplate(); as contentDir) {\n <ng-container [ngTemplateOutlet]=\"contentDir.templateRef\" />\n } @else if (tab.implicitContentTemplate(); as implicitTpl) {\n <ng-container [ngTemplateOutlet]=\"implicitTpl\" />\n }\n </div>\n }\n}\n\n<!-- Hidden projection slot for tw-tab children -->\n<div style=\"display: none\">\n <ng-content />\n</div>\n" }]
|
|
501
|
+
}], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], fitted: [{ type: i0.Input, args: [{ isSignal: true, alias: "fitted", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TabComponent), { isSignal: true }] }], triggerElements: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => TabTriggerElementDirective), { isSignal: true }] }], tablistInnerRef: [{ type: i0.ViewChild, args: ['tablistInner', { isSignal: true }] }] } });
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Generated bundle index. Do not edit.
|
|
505
|
+
*/
|
|
506
|
+
|
|
507
|
+
export { TabComponent, TabContentDirective, TabTriggerDirective, TabsComponent };
|
|
508
|
+
//# sourceMappingURL=cdevhub-ngx-tw-tabs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-tabs.mjs","sources":["../../../projects/ngx-tw/tabs/tabs.ts","../../../projects/ngx-tw/tabs/tabs.html","../../../projects/ngx-tw/tabs/cdevhub-ngx-tw-tabs.ts"],"sourcesContent":["import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n contentChildren,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n linkedSignal,\n model,\n output,\n signal,\n TemplateRef,\n untracked,\n viewChild,\n viewChildren,\n type AfterViewInit,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { FocusableOption, FocusKeyManager, LiveAnnouncer } from '@angular/cdk/a11y';\nimport { tv } from 'tailwind-variants';\nimport { twMerge } from 'tailwind-merge';\nimport {\n getActiveTriggerClasses,\n getInactiveTriggerClasses,\n tabTriggerVariants,\n type TabTriggerVariant,\n type TwColor,\n type TwSize,\n} from '@cdevhub/ngx-tw/core';\n\n/** Visual style of the tab strip. */\nexport type TabsVariant = TabTriggerVariant;\n\n// ── tv() config (component-local slots only — trigger config is shared) ──\n\nconst tabsLayoutVariants = tv(\n {\n slots: {\n root: 'flex',\n tablist: 'relative flex shrink-0',\n tablistInner: 'flex overflow-x-auto',\n panel: 'min-w-0 flex-1',\n scrollButton:\n 'inline-flex items-center justify-center shrink-0 cursor-pointer transition-colors duration-normal motion-reduce:transition-none disabled:opacity-30 disabled:cursor-default hover:bg-surface-muted',\n closeButton:\n 'inline-flex items-center justify-center rounded-md cursor-pointer transition-colors duration-normal motion-reduce:transition-none hover:bg-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',\n },\n variants: {\n variant: {\n underline: {\n tablist: 'border-b border-border',\n tablistInner: 'gap-0',\n panel: 'pt-4',\n },\n enclosed: {\n tablist: 'border-b border-border',\n tablistInner: 'gap-0',\n panel: 'pt-4',\n },\n pill: {\n tablist: 'bg-surface-muted rounded-xl p-1',\n tablistInner: 'gap-1',\n panel: 'pt-4',\n },\n },\n // Square interactive-target scale: see CLAUDE.md \"Icon Sizing\".\n size: {\n xs: { scrollButton: 'size-5', closeButton: 'size-6' },\n sm: { scrollButton: 'size-5', closeButton: 'size-7' },\n md: { scrollButton: 'size-6', closeButton: 'size-8' },\n lg: { scrollButton: 'size-7', closeButton: 'size-9' },\n xl: { scrollButton: 'size-8', closeButton: 'size-9' },\n },\n orientation: {\n horizontal: {\n root: 'flex-col',\n tablist: '',\n tablistInner: 'flex-row',\n },\n vertical: {\n root: 'flex-row',\n tablistInner: 'flex-col overflow-y-auto overflow-x-hidden',\n },\n },\n },\n compoundVariants: [\n {\n variant: 'underline',\n orientation: 'vertical',\n class: {\n tablist: 'border-b-0 border-r border-border',\n panel: 'pt-0 pl-4',\n },\n },\n {\n variant: 'enclosed',\n orientation: 'vertical',\n class: {\n tablist: 'border-b-0 border-r border-border',\n panel: 'pt-0 pl-4',\n },\n },\n {\n variant: 'pill',\n orientation: 'vertical',\n class: {\n panel: 'pt-0 pl-4',\n },\n },\n ],\n defaultVariants: {\n variant: 'underline',\n size: 'md',\n orientation: 'horizontal',\n },\n },\n { twMerge: true },\n);\n\n// ── Per-variant/orientation trigger additions (vertical underline/enclosed\n// re-route the active border axis, hence these compound overrides). ──\n\nfunction getTriggerOrientationExtras(\n variant: TabsVariant,\n orientation: 'horizontal' | 'vertical',\n): string {\n if (orientation !== 'vertical') return '';\n switch (variant) {\n case 'underline':\n return 'border-b-0 -mb-0 border-r-2 border-transparent -mr-px';\n case 'enclosed':\n return '-mb-0 -mr-px';\n case 'pill':\n return '';\n }\n}\n\n// ── Directives ──\n\n@Directive({ selector: 'ng-template[twTabTrigger]' })\nexport class TabTriggerDirective {\n readonly templateRef = inject(TemplateRef);\n}\n\n@Directive({ selector: 'ng-template[twTabContent]' })\nexport class TabContentDirective {\n readonly templateRef = inject(TemplateRef);\n}\n\n// ── TabComponent ──\n\n@Component({\n selector: 'tw-tab',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <ng-template #implicitContent>\n <ng-content />\n </ng-template>\n `,\n host: {\n 'style': 'display: none',\n },\n})\nexport class TabComponent {\n /** Unique identifier for this tab. Used to match the active tab value. */\n readonly value = input.required<string>();\n\n /** Plain text label shown in the trigger. Ignored when a custom trigger template is provided. */\n readonly label = input('');\n\n /** When true, the tab cannot be selected and is skipped by keyboard navigation. Defaults to false. */\n readonly disabled = input(false);\n\n /** When true, a close button is rendered in the tab trigger. Defaults to false. */\n readonly closable = input(false);\n\n /** When true, the tab panel content is only instantiated when the tab becomes active for the first time. Defaults to false. */\n readonly lazy = input(false);\n\n /** @internal Custom trigger template, if provided. */\n readonly triggerTemplate = contentChild(TabTriggerDirective);\n\n /** @internal Custom content template, if provided via twTabContent. */\n readonly contentTemplate = contentChild(TabContentDirective);\n\n /** @internal Implicit content template wrapping ng-content. */\n readonly implicitContentTemplate = viewChild<TemplateRef<unknown>>('implicitContent');\n}\n\n// ── Tab trigger element wrapper ──\n\n@Directive({\n selector: '[twTabTriggerElement]',\n host: {\n '[attr.tabindex]': 'tabIndex()',\n },\n})\nexport class TabTriggerElementDirective implements FocusableOption {\n readonly elementRef = inject(ElementRef<HTMLElement>);\n\n readonly isActive = input(false);\n readonly isDisabled = input(false);\n\n readonly tabIndex = computed(() => this.isActive() ? 0 : -1);\n\n focus(): void {\n this.elementRef.nativeElement.focus();\n }\n\n /**\n * FocusableOption getter. NOTE: we cannot expose the `isDisabled` input\n * signal directly — the signal function itself is always truthy, which would\n * make FocusKeyManager treat every trigger as disabled. We resolve the\n * signal here so the manager skips the right items.\n */\n get disabled(): boolean {\n return this.isDisabled();\n }\n}\n\n// ── TabsComponent ──\n\nlet nextId = 0;\n\n@Component({\n selector: 'tw-tabs',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgTemplateOutlet, TabTriggerElementDirective],\n templateUrl: './tabs.html',\n host: {\n '[class]': 'rootClasses()',\n },\n})\nexport class TabsComponent implements AfterViewInit {\n /** Controls the visual style of the tab strip. Defaults to 'underline'. */\n readonly variant = input<TabsVariant>('underline');\n\n /** Sets the semantic color for active tab indicators and highlights. Defaults to 'primary'. */\n readonly color = input<TwColor>('primary');\n\n /** Controls padding, font size, and icon size of tab triggers. Defaults to 'md'. */\n readonly size = input<TwSize>('md');\n\n /** Layout direction of the tab strip. Defaults to 'horizontal'. */\n readonly orientation = input<'horizontal' | 'vertical'>('horizontal');\n\n /** When true, tab triggers stretch to fill the available width equally. Defaults to false. */\n readonly fitted = input(false);\n\n /** The value of the currently active tab. Two-way bound. Updates when the user selects a tab. */\n readonly value = model<string>('');\n\n /** Fires when a closable tab's close button is clicked. Payload is the tab's value. */\n readonly closed = output<string>();\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly liveAnnouncer = inject(LiveAnnouncer);\n\n /** @internal */\n readonly tabs = contentChildren(TabComponent);\n\n /** @internal */\n readonly triggerElements = viewChildren(TabTriggerElementDirective);\n\n /** @internal */\n readonly tablistInnerRef = viewChild<ElementRef<HTMLElement>>('tablistInner');\n\n private readonly componentId = `tw-tabs-${nextId++}`;\n\n // ── Active tab tracking ──\n\n readonly activeValue = linkedSignal(() => this.value());\n\n // ── Lazy tab tracking — Set of tab values that have been activated at least once ──\n readonly activatedTabs = signal(new Set<string>());\n\n // ── Scroll overflow signals ──\n readonly canScrollStart = signal(false);\n readonly canScrollEnd = signal(false);\n\n private resizeObserver: ResizeObserver | null = null;\n private scrollCleanup: (() => void) | null = null;\n\n // ── Variant classes ──\n\n private readonly layoutResult = computed(() =>\n tabsLayoutVariants({\n variant: this.variant(),\n size: this.size(),\n orientation: this.orientation(),\n }),\n );\n\n private readonly triggerResult = computed(() =>\n tabTriggerVariants({\n variant: this.variant(),\n color: this.color(),\n size: this.size(),\n fitted: this.fitted(),\n }),\n );\n\n readonly rootClasses = computed(() => this.layoutResult().root());\n readonly tablistClasses = computed(() => this.layoutResult().tablist());\n readonly tablistInnerClasses = computed(() => this.layoutResult().tablistInner());\n readonly baseTriggerClasses = computed(() => this.triggerResult().trigger());\n readonly panelClasses = computed(() => this.layoutResult().panel());\n readonly scrollButtonClasses = computed(() => this.layoutResult().scrollButton());\n readonly closeButtonClasses = computed(() => this.layoutResult().closeButton());\n\n // ── Per-trigger active/inactive class computation ──\n\n /** @internal Get combined trigger classes for a given tab. */\n getTriggerClasses(_tabValue: string, isActive: boolean): string {\n const base = this.baseTriggerClasses();\n const orientationExtras = getTriggerOrientationExtras(this.variant(), this.orientation());\n const state = isActive\n ? getActiveTriggerClasses(this.variant(), this.color(), this.orientation())\n : getInactiveTriggerClasses(this.variant());\n return twMerge(base, orientationExtras, state);\n }\n\n // ── ID generation ──\n getTabId(tabValue: string): string {\n return `${this.componentId}-tab-${tabValue}`;\n }\n\n getPanelId(tabValue: string): string {\n return `${this.componentId}-panel-${tabValue}`;\n }\n\n // ── Tab visibility ──\n\n isTabActive(tabValue: string): boolean {\n return this.activeValue() === tabValue;\n }\n\n shouldRenderPanel(tab: TabComponent): boolean {\n const value = tab.value();\n if (!tab.lazy()) {\n return true;\n }\n // Lazy: render only if it has been activated at least once\n return this.activatedTabs().has(value);\n }\n\n // ── Selection ──\n\n selectTab(tab: TabComponent): void {\n if (tab.disabled()) return;\n const val = tab.value();\n this.activeValue.set(val);\n this.value.set(val);\n\n // Mark as activated for lazy tabs\n this.activatedTabs.update(set => {\n const next = new Set(set);\n next.add(val);\n return next;\n });\n\n // Announce to screen readers\n const tabsArr = this.tabs();\n const idx = tabsArr.findIndex(t => t.value() === val);\n this.liveAnnouncer.announce(\n `${tab.label() || val} tab, ${idx + 1} of ${tabsArr.length}`,\n );\n }\n\n closeTab(tab: TabComponent, event: Event): void {\n event.stopPropagation();\n if (event instanceof KeyboardEvent) {\n event.preventDefault();\n }\n const val = tab.value();\n this.closed.emit(val);\n\n // If closing the active tab, activate nearest enabled sibling\n if (this.isTabActive(val)) {\n const tabsArr = this.tabs();\n const idx = tabsArr.findIndex(t => t.value() === val);\n const next = this.findNearestEnabledTab(tabsArr, idx);\n if (next) {\n this.selectTab(next);\n }\n }\n }\n\n private findNearestEnabledTab(tabs: readonly TabComponent[], fromIndex: number): TabComponent | null {\n // Search forward first, then backward\n for (let i = fromIndex + 1; i < tabs.length; i++) {\n if (!tabs[i].disabled()) return tabs[i];\n }\n for (let i = fromIndex - 1; i >= 0; i--) {\n if (!tabs[i].disabled()) return tabs[i];\n }\n return null;\n }\n\n // ── Keyboard navigation (CDK FocusKeyManager) ──\n\n private keyManager: FocusKeyManager<TabTriggerElementDirective> | null = null;\n\n /**\n * @internal Handles keyboard navigation. The manager handles Arrow/Home/End;\n * we layer Enter/Space to select the focused tab (the wrapper is a `<div role=\"tab\">`\n * so we lose the native button activation) and Delete to close a closable tab.\n */\n onKeydown(event: KeyboardEvent): void {\n if (!this.keyManager) return;\n const triggers = this.triggerElements();\n if (triggers.length === 0) return;\n\n // Sync active item with the trigger DOM-focused by the user. We accept\n // either `event.target` (which works under shadow DOM) or the currently\n // active tab's index as a safety net (e.g. when the event was dispatched\n // on the tablist container itself, not a trigger).\n const focusedIdx = triggers.findIndex(\n t => t.elementRef.nativeElement === event.target,\n );\n const activeIdx = focusedIdx >= 0\n ? focusedIdx\n : this.tabs().findIndex(t => t.value() === this.activeValue());\n if (activeIdx >= 0 && activeIdx !== this.keyManager.activeItemIndex) {\n this.keyManager.setActiveItem(activeIdx);\n }\n\n // Enter / Space select the focused tab (we no longer get this for free\n // because the trigger is a div, not a button — see DOM restructure below).\n if (event.key === 'Enter' || event.key === ' ') {\n if (focusedIdx >= 0) {\n event.preventDefault();\n this.selectTab(this.tabs()[focusedIdx]);\n }\n return;\n }\n\n // Delete on a closable tab dismisses it (APG-recommended). Keyboard users\n // who don't want to traverse to the close button can dismiss inline.\n if (event.key === 'Delete' && focusedIdx >= 0) {\n const tab = this.tabs()[focusedIdx];\n if (tab.closable() && !tab.disabled()) {\n event.preventDefault();\n this.closeTab(tab, event);\n return;\n }\n }\n\n // Let the manager handle arrow/home/end navigation.\n const before = this.keyManager.activeItemIndex;\n this.keyManager.onKeydown(event);\n const after = this.keyManager.activeItemIndex;\n if (after !== null && after !== before && after >= 0) {\n // Automatic activation pattern (APG): selection follows focus.\n this.selectTab(this.tabs()[after]);\n }\n }\n\n // ── Scrolling ──\n\n scrollStart(): void {\n const el = this.tablistInnerRef()?.nativeElement;\n if (!el) return;\n const isVertical = this.orientation() === 'vertical';\n if (isVertical) {\n el.scrollBy({ top: -120, behavior: 'smooth' });\n } else {\n el.scrollBy({ left: -120, behavior: 'smooth' });\n }\n }\n\n scrollEnd(): void {\n const el = this.tablistInnerRef()?.nativeElement;\n if (!el) return;\n const isVertical = this.orientation() === 'vertical';\n if (isVertical) {\n el.scrollBy({ top: 120, behavior: 'smooth' });\n } else {\n el.scrollBy({ left: 120, behavior: 'smooth' });\n }\n }\n\n private updateScrollState(): void {\n const el = this.tablistInnerRef()?.nativeElement;\n if (!el) return;\n\n const isVertical = this.orientation() === 'vertical';\n if (isVertical) {\n this.canScrollStart.set(el.scrollTop > 0);\n this.canScrollEnd.set(el.scrollTop + el.clientHeight < el.scrollHeight - 1);\n } else {\n this.canScrollStart.set(el.scrollLeft > 0);\n this.canScrollEnd.set(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);\n }\n }\n\n ngAfterViewInit(): void {\n this.initializeActiveTab();\n }\n\n constructor() {\n afterNextRender(() => {\n this.setupScrollDetection();\n });\n\n // Rebuild FocusKeyManager whenever triggers or orientation change.\n effect((onCleanup) => {\n const triggers = this.triggerElements();\n const orientation = this.orientation();\n if (triggers.length === 0) {\n this.keyManager = null;\n return;\n }\n const manager = new FocusKeyManager(triggers)\n .withWrap()\n .withHomeAndEnd();\n if (orientation === 'vertical') {\n manager.withVerticalOrientation();\n } else {\n manager.withHorizontalOrientation('ltr');\n }\n this.keyManager = manager;\n\n // Initialise the manager's active index to the active tab so the first\n // arrow press moves from the active item, not from -1.\n untracked(() => {\n const activeVal = this.activeValue();\n const tabs = this.tabs();\n const idx = tabs.findIndex(t => t.value() === activeVal);\n if (idx >= 0) {\n manager.setActiveItem(idx);\n }\n });\n\n onCleanup(() => {\n manager.destroy();\n });\n });\n\n this.destroyRef.onDestroy(() => {\n this.resizeObserver?.disconnect();\n this.scrollCleanup?.();\n });\n }\n\n private initializeActiveTab(): void {\n // If no value was provided, default to the first enabled tab\n if (!this.activeValue()) {\n const first = this.tabs().find(t => !t.disabled());\n if (first) {\n this.activeValue.set(first.value());\n this.value.set(first.value());\n }\n }\n\n // Mark the initial active tab as activated (for lazy tracking)\n const val = this.activeValue();\n if (val) {\n this.activatedTabs.update(set => {\n const next = new Set(set);\n next.add(val);\n return next;\n });\n }\n }\n\n private setupScrollDetection(): void {\n const el = this.tablistInnerRef()?.nativeElement;\n if (!el) return;\n\n // Initial check\n this.updateScrollState();\n\n // ResizeObserver for container size changes\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => {\n this.updateScrollState();\n });\n this.resizeObserver.observe(el);\n }\n\n // Scroll event for scroll position changes\n const onScroll = () => this.updateScrollState();\n el.addEventListener('scroll', onScroll, { passive: true });\n this.scrollCleanup = () => el.removeEventListener('scroll', onScroll);\n }\n}\n","<!-- Tablist container -->\n<div\n [class]=\"tablistClasses()\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientation()\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Scroll start button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollStart()\"\n (click)=\"scrollStart()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n\n <!-- Scrollable trigger strip -->\n <div #tablistInner [class]=\"tablistInnerClasses()\" style=\"scrollbar-width: none\">\n @for (tab of tabs(); track tab.value()) {\n <!-- Trigger is rendered as <div role=\"tab\"> (not <button>) so the close\n affordance can be a native <button> child without nesting interactive\n content (invalid HTML). Activation is wired explicitly via (click)\n and the parent tablist (keydown.enter / keydown.space). -->\n <div\n role=\"tab\"\n twTabTriggerElement\n [isActive]=\"isTabActive(tab.value())\"\n [isDisabled]=\"tab.disabled()\"\n [id]=\"getTabId(tab.value())\"\n [attr.aria-selected]=\"isTabActive(tab.value())\"\n [attr.aria-controls]=\"getPanelId(tab.value())\"\n [attr.aria-disabled]=\"tab.disabled() || null\"\n [class]=\"getTriggerClasses(tab.value(), isTabActive(tab.value()))\"\n [class.opacity-50]=\"tab.disabled()\"\n [class.pointer-events-none]=\"tab.disabled()\"\n (click)=\"selectTab(tab)\"\n >\n <!-- Custom trigger template or default label -->\n @if (tab.triggerTemplate(); as triggerDir) {\n <ng-container\n [ngTemplateOutlet]=\"triggerDir.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: { active: isTabActive(tab.value()), disabled: tab.disabled(), value: tab.value() } }\"\n />\n } @else {\n {{ tab.label() }}\n }\n\n <!-- Close affordance — native <button> so it is keyboard-focusable.\n Valid because the trigger is a <div role=\"tab\">, not a button. -->\n @if (tab.closable() && !tab.disabled()) {\n <button\n type=\"button\"\n [attr.aria-label]=\"'Close ' + (tab.label() || tab.value())\"\n [class]=\"closeButtonClasses()\"\n (click)=\"closeTab(tab, $event)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path d=\"M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z\"/>\n </svg>\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Scroll end button (horizontal only) -->\n @if (orientation() === 'horizontal' && (canScrollStart() || canScrollEnd())) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"scrollButtonClasses()\"\n [disabled]=\"!canScrollEnd()\"\n (click)=\"scrollEnd()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-4 shrink-0\">\n <path fill-rule=\"evenodd\" d=\"M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n }\n</div>\n\n<!-- Tab panels -->\n@for (tab of tabs(); track tab.value()) {\n @if (shouldRenderPanel(tab)) {\n <div\n role=\"tabpanel\"\n [id]=\"getPanelId(tab.value())\"\n [attr.aria-labelledby]=\"getTabId(tab.value())\"\n [class]=\"panelClasses()\"\n [hidden]=\"!isTabActive(tab.value())\"\n tabindex=\"0\"\n >\n @if (tab.contentTemplate(); as contentDir) {\n <ng-container [ngTemplateOutlet]=\"contentDir.templateRef\" />\n } @else if (tab.implicitContentTemplate(); as implicitTpl) {\n <ng-container [ngTemplateOutlet]=\"implicitTpl\" />\n }\n </div>\n }\n}\n\n<!-- Hidden projection slot for tw-tab children -->\n<div style=\"display: none\">\n <ng-content />\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|