@tociva/tailng-ui 0.11.0 → 0.13.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.
@@ -1,22 +1,785 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports$1) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./lib"), exports);
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, Component, output, signal, effect, TemplateRef, ViewChild, ContentChild, Directive, inject, HostListener, ElementRef, booleanAttribute, HostBinding, numberAttribute, contentChildren } from '@angular/core';
3
+ import { RouterLink } from '@angular/router';
4
+ import { TngFocusTrap } from '@tociva/tailng-cdk/a11y';
5
+ import * as i1 from '@angular/common';
6
+ import { CommonModule, NgTemplateOutlet } from '@angular/common';
7
+ import { TngConnectedOverlay, TngOverlayPanel, TngOverlayRef } from '@tociva/tailng-ui/popups-overlays';
8
+
9
+ class TngBreadcrumbs {
10
+ /** Items */
11
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
12
+ /** Optional Home crumb (prepended) */
13
+ home = input(null, ...(ngDevMode ? [{ debugName: "home" }] : []));
14
+ /** Separator text (if you later want icons, change template to project) */
15
+ separator = input('/', ...(ngDevMode ? [{ debugName: "separator" }] : []));
16
+ /** a11y label */
17
+ ariaLabel = input('Breadcrumb', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
18
+ /* =====================
19
+ * Klass inputs (Tailng style)
20
+ * ===================== */
21
+ rootKlass = input('flex items-center text-sm text-muted-foreground', ...(ngDevMode ? [{ debugName: "rootKlass" }] : []));
22
+ listKlass = input('flex items-center flex-wrap gap-1', ...(ngDevMode ? [{ debugName: "listKlass" }] : []));
23
+ itemKlass = input('inline-flex items-center', ...(ngDevMode ? [{ debugName: "itemKlass" }] : []));
24
+ linkKlass = input('text-primary hover:underline', ...(ngDevMode ? [{ debugName: "linkKlass" }] : []));
25
+ currentKlass = input('text-foreground font-medium', ...(ngDevMode ? [{ debugName: "currentKlass" }] : []));
26
+ disabledKlass = input('opacity-60 pointer-events-none', ...(ngDevMode ? [{ debugName: "disabledKlass" }] : []));
27
+ separatorKlass = input('mx-2 text-slate-400', ...(ngDevMode ? [{ debugName: "separatorKlass" }] : []));
28
+ /* =====================
29
+ * Derived
30
+ * ===================== */
31
+ resolvedItems = computed(() => {
32
+ const home = this.home();
33
+ const items = this.items() ?? [];
34
+ return home ? [home, ...items] : items;
35
+ }, ...(ngDevMode ? [{ debugName: "resolvedItems" }] : []));
36
+ currentIndex = computed(() => {
37
+ const items = this.resolvedItems();
38
+ const explicit = items.findIndex((x) => !!x.current);
39
+ return explicit >= 0 ? explicit : Math.max(0, items.length - 1);
40
+ }, ...(ngDevMode ? [{ debugName: "currentIndex" }] : []));
41
+ isCurrent(i) {
42
+ return i === this.currentIndex();
43
+ }
44
+ isClickable(item, i) {
45
+ if (item.disabled)
46
+ return false;
47
+ if (this.isCurrent(i))
48
+ return false;
49
+ return !!item.route || !!item.href;
50
+ }
51
+ itemClasses(item, i) {
52
+ const base = this.itemKlass();
53
+ const disabled = item.disabled ? ` ${this.disabledKlass()}` : '';
54
+ return `${base}${disabled}`.trim();
55
+ }
56
+ labelClasses(item, i) {
57
+ const isCurrent = this.isCurrent(i);
58
+ return (isCurrent ? this.currentKlass() : this.linkKlass()).trim();
59
+ }
60
+ relFor(item) {
61
+ if (!item.href)
62
+ return null;
63
+ if (item.rel)
64
+ return item.rel;
65
+ return item.target === '_blank' ? 'noopener noreferrer' : null;
66
+ }
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngBreadcrumbs, deps: [], target: i0.ɵɵFactoryTarget.Component });
68
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TngBreadcrumbs, isStandalone: true, selector: "tng-breadcrumbs", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, home: { classPropertyName: "home", publicName: "home", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, rootKlass: { classPropertyName: "rootKlass", publicName: "rootKlass", isSignal: true, isRequired: false, transformFunction: null }, listKlass: { classPropertyName: "listKlass", publicName: "listKlass", isSignal: true, isRequired: false, transformFunction: null }, itemKlass: { classPropertyName: "itemKlass", publicName: "itemKlass", isSignal: true, isRequired: false, transformFunction: null }, linkKlass: { classPropertyName: "linkKlass", publicName: "linkKlass", isSignal: true, isRequired: false, transformFunction: null }, currentKlass: { classPropertyName: "currentKlass", publicName: "currentKlass", isSignal: true, isRequired: false, transformFunction: null }, disabledKlass: { classPropertyName: "disabledKlass", publicName: "disabledKlass", isSignal: true, isRequired: false, transformFunction: null }, separatorKlass: { classPropertyName: "separatorKlass", publicName: "separatorKlass", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<nav [attr.aria-label]=\"ariaLabel()\" [class]=\"rootKlass()\">\n <ol [class]=\"listKlass()\">\n @for (item of resolvedItems(); track $index; let i = $index; let last = $last) {\n <li [class]=\"itemClasses(item, i)\">\n <!-- Internal route -->\n @if (item.route && isClickable(item, i)) {\n <a\n [routerLink]=\"item.route\"\n [class]=\"labelClasses(item, i)\"\n >\n {{ item.label }}\n </a>\n }\n <!-- External link -->\n @else if (item.href && isClickable(item, i)) {\n <a\n [href]=\"item.href\"\n [target]=\"item.target ?? null\"\n [attr.rel]=\"relFor(item)\"\n [class]=\"labelClasses(item, i)\"\n >\n {{ item.label }}\n </a>\n }\n <!-- Current/disabled/plain -->\n @else {\n <span\n [class]=\"labelClasses(item, i)\"\n [attr.aria-current]=\"isCurrent(i) ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n\n @if (!last) {\n <span [class]=\"separatorKlass()\">{{ separator() }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
69
+ }
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngBreadcrumbs, decorators: [{
71
+ type: Component,
72
+ args: [{ selector: 'tng-breadcrumbs', standalone: true, imports: [RouterLink], template: "<nav [attr.aria-label]=\"ariaLabel()\" [class]=\"rootKlass()\">\n <ol [class]=\"listKlass()\">\n @for (item of resolvedItems(); track $index; let i = $index; let last = $last) {\n <li [class]=\"itemClasses(item, i)\">\n <!-- Internal route -->\n @if (item.route && isClickable(item, i)) {\n <a\n [routerLink]=\"item.route\"\n [class]=\"labelClasses(item, i)\"\n >\n {{ item.label }}\n </a>\n }\n <!-- External link -->\n @else if (item.href && isClickable(item, i)) {\n <a\n [href]=\"item.href\"\n [target]=\"item.target ?? null\"\n [attr.rel]=\"relFor(item)\"\n [class]=\"labelClasses(item, i)\"\n >\n {{ item.label }}\n </a>\n }\n <!-- Current/disabled/plain -->\n @else {\n <span\n [class]=\"labelClasses(item, i)\"\n [attr.aria-current]=\"isCurrent(i) ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n\n @if (!last) {\n <span [class]=\"separatorKlass()\">{{ separator() }}</span>\n }\n </li>\n }\n </ol>\n</nav>\n" }]
73
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], home: [{ type: i0.Input, args: [{ isSignal: true, alias: "home", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], rootKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootKlass", required: false }] }], listKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "listKlass", required: false }] }], itemKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemKlass", required: false }] }], linkKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkKlass", required: false }] }], currentKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentKlass", required: false }] }], disabledKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledKlass", required: false }] }], separatorKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorKlass", required: false }] }] } });
74
+
75
+ class TngDrawer {
76
+ /* =====================
77
+ * Projected content
78
+ * ===================== */
79
+ drawerTpl;
80
+ anchorEl;
81
+ /* =====================
82
+ * Inputs / Outputs
83
+ * ===================== */
84
+ open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : []));
85
+ placement = input('left', ...(ngDevMode ? [{ debugName: "placement" }] : []));
86
+ closeOnBackdropClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdropClick" }] : []));
87
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
88
+ /** Focus trap (a11y) */
89
+ trapFocus = input(true, ...(ngDevMode ? [{ debugName: "trapFocus" }] : []));
90
+ restoreFocus = input(true, ...(ngDevMode ? [{ debugName: "restoreFocus" }] : []));
91
+ autoCapture = input(true, ...(ngDevMode ? [{ debugName: "autoCapture" }] : []));
92
+ deferCaptureElements = input(false, ...(ngDevMode ? [{ debugName: "deferCaptureElements" }] : []));
93
+ opened = output();
94
+ closed = output();
95
+ /* =====================
96
+ * Styling (klass-first)
97
+ * ===================== */
98
+ backdropKlass = input('fixed inset-0 bg-black/40 backdrop-blur-[1px]', ...(ngDevMode ? [{ debugName: "backdropKlass" }] : []));
99
+ panelKlass = input('bg-bg shadow-xl outline-none', ...(ngDevMode ? [{ debugName: "panelKlass" }] : []));
100
+ sizeKlass = input('w-80', ...(ngDevMode ? [{ debugName: "sizeKlass" }] : [])); // for left/right
101
+ heightKlass = input('h-80', ...(ngDevMode ? [{ debugName: "heightKlass" }] : [])); // for top/bottom
102
+ /* =====================
103
+ * Internal
104
+ * ===================== */
105
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
106
+ overlayPlacement = computed(() => {
107
+ switch (this.placement()) {
108
+ case 'left':
109
+ return 'bottom-start';
110
+ case 'right':
111
+ return 'bottom-end';
112
+ case 'top':
113
+ return 'top-start';
114
+ case 'bottom':
115
+ return 'bottom-start';
116
+ }
117
+ }, ...(ngDevMode ? [{ debugName: "overlayPlacement" }] : []));
118
+ slideClasses = computed(() => {
119
+ const base = 'fixed transition-transform duration-200 ease-in-out will-change-transform';
120
+ switch (this.placement()) {
121
+ case 'left':
122
+ return `${base} left-0 top-0 h-full ${this.isOpen() ? 'translate-x-0' : '-translate-x-full'}`;
123
+ case 'right':
124
+ return `${base} right-0 top-0 h-full ${this.isOpen() ? 'translate-x-0' : 'translate-x-full'}`;
125
+ case 'top':
126
+ return `${base} top-0 left-0 w-full ${this.isOpen() ? 'translate-y-0' : '-translate-y-full'}`;
127
+ case 'bottom':
128
+ return `${base} bottom-0 left-0 w-full ${this.isOpen() ? 'translate-y-0' : 'translate-y-full'}`;
129
+ }
130
+ }, ...(ngDevMode ? [{ debugName: "slideClasses" }] : []));
131
+ constructor() {
132
+ effect(() => {
133
+ if (this.open()) {
134
+ this.isOpen.set(true);
135
+ this.opened.emit();
136
+ }
137
+ else {
138
+ this.isOpen.set(false);
139
+ }
140
+ });
141
+ }
142
+ onOverlayClosed(reason) {
143
+ this.closed.emit(reason);
144
+ }
145
+ onBackdropClick() {
146
+ if (!this.closeOnBackdropClick())
147
+ return;
148
+ this.closed.emit('outside-click');
149
+ }
150
+ /** Keep escape handling scoped to drawer (instead of document listener) */
151
+ onPanelKeydown(ev) {
152
+ if (!this.open())
153
+ return;
154
+ if (!this.closeOnEscape())
155
+ return;
156
+ if (ev.defaultPrevented)
157
+ return;
158
+ if (ev.key === 'Escape') {
159
+ ev.preventDefault();
160
+ this.closed.emit('escape');
161
+ }
162
+ }
163
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngDrawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
164
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TngDrawer, isStandalone: true, selector: "tng-drawer", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, trapFocus: { classPropertyName: "trapFocus", publicName: "trapFocus", isSignal: true, isRequired: false, transformFunction: null }, restoreFocus: { classPropertyName: "restoreFocus", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, autoCapture: { classPropertyName: "autoCapture", publicName: "autoCapture", isSignal: true, isRequired: false, transformFunction: null }, deferCaptureElements: { classPropertyName: "deferCaptureElements", publicName: "deferCaptureElements", isSignal: true, isRequired: false, transformFunction: null }, backdropKlass: { classPropertyName: "backdropKlass", publicName: "backdropKlass", isSignal: true, isRequired: false, transformFunction: null }, panelKlass: { classPropertyName: "panelKlass", publicName: "panelKlass", isSignal: true, isRequired: false, transformFunction: null }, sizeKlass: { classPropertyName: "sizeKlass", publicName: "sizeKlass", isSignal: true, isRequired: false, transformFunction: null }, heightKlass: { classPropertyName: "heightKlass", publicName: "heightKlass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed" }, queries: [{ propertyName: "drawerTpl", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "anchorEl", first: true, predicate: ["anchorEl"], descendants: true, static: true }], ngImport: i0, template: "@if (open()) {\n <!-- Backdrop (below panel) -->\n <div\n [class]=\"backdropKlass()\"\n class=\"z-[1000]\"\n (click)=\"onBackdropClick()\"\n ></div>\n\n <!-- Drawer panel (above backdrop) -->\n <div\n [class]=\"slideClasses() + ' ' + panelKlass()\"\n class=\"z-[1001]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"onPanelKeydown($event)\"\n [tngFocusTrap]=\"open() && trapFocus()\"\n [restoreFocus]=\"restoreFocus()\"\n [autoCapture]=\"autoCapture()\"\n [deferCaptureElements]=\"deferCaptureElements()\"\n >\n <ng-content />\n </div>\n}\n", dependencies: [{ kind: "directive", type: TngFocusTrap, selector: "[tngFocusTrap]", inputs: ["tngFocusTrap", "deferCaptureElements", "autoCapture", "restoreFocus"] }] });
165
+ }
166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngDrawer, decorators: [{
167
+ type: Component,
168
+ args: [{ selector: 'tng-drawer', standalone: true, imports: [TngFocusTrap], template: "@if (open()) {\n <!-- Backdrop (below panel) -->\n <div\n [class]=\"backdropKlass()\"\n class=\"z-[1000]\"\n (click)=\"onBackdropClick()\"\n ></div>\n\n <!-- Drawer panel (above backdrop) -->\n <div\n [class]=\"slideClasses() + ' ' + panelKlass()\"\n class=\"z-[1001]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"onPanelKeydown($event)\"\n [tngFocusTrap]=\"open() && trapFocus()\"\n [restoreFocus]=\"restoreFocus()\"\n [autoCapture]=\"autoCapture()\"\n [deferCaptureElements]=\"deferCaptureElements()\"\n >\n <ng-content />\n </div>\n}\n" }]
169
+ }], ctorParameters: () => [], propDecorators: { drawerTpl: [{
170
+ type: ContentChild,
171
+ args: [TemplateRef, { descendants: true }]
172
+ }], anchorEl: [{
173
+ type: ViewChild,
174
+ args: ['anchorEl', { static: true }]
175
+ }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], closeOnBackdropClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdropClick", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], trapFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "trapFocus", required: false }] }], restoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], autoCapture: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoCapture", required: false }] }], deferCaptureElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "deferCaptureElements", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], backdropKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "backdropKlass", required: false }] }], panelKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelKlass", required: false }] }], sizeKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sizeKlass", required: false }] }], heightKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "heightKlass", required: false }] }] } });
176
+
177
+ class TngMenuTemplate {
178
+ tpl;
179
+ constructor(tpl) {
180
+ this.tpl = tpl;
181
+ }
182
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenuTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
183
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: TngMenuTemplate, isStandalone: true, selector: "ng-template[tngMenuTemplate]", ngImport: i0 });
184
+ }
185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenuTemplate, decorators: [{
186
+ type: Directive,
187
+ args: [{
188
+ selector: 'ng-template[tngMenuTemplate]',
189
+ standalone: true,
190
+ }]
191
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
192
+
193
+ // menu.component.ts
194
+ class TngMenu {
195
+ tplDir;
196
+ get menuTemplate() {
197
+ return this.tplDir?.tpl;
198
+ }
199
+ triggerEl;
200
+ // Modal mode (backdrop semantics)
201
+ modal = input(false, ...(ngDevMode ? [{ debugName: "modal" }] : []));
202
+ placement = input('bottom-start', ...(ngDevMode ? [{ debugName: "placement" }] : []));
203
+ offset = input(6, ...(ngDevMode ? [{ debugName: "offset" }] : []));
204
+ width = input('anchor', ...(ngDevMode ? [{ debugName: "width" }] : []));
205
+ closeOnOutsideClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnOutsideClick" }] : []));
206
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
207
+ closeOnItemClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnItemClick" }] : []));
208
+ rootKlass = input('relative inline-block', ...(ngDevMode ? [{ debugName: "rootKlass" }] : []));
209
+ triggerKlass = input('inline-flex', ...(ngDevMode ? [{ debugName: "triggerKlass" }] : []));
210
+ panelKlass = input('p-1', ...(ngDevMode ? [{ debugName: "panelKlass" }] : []));
211
+ backdropKlass = input('fixed inset-0 bg-black/40 z-[999]', ...(ngDevMode ? [{ debugName: "backdropKlass" }] : []));
212
+ opened = output();
213
+ closed = output();
214
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
215
+ // Simple stable id for aria-controls (unique enough per instance)
216
+ uid = Math.random().toString(36).slice(2);
217
+ menuId = computed(() => `tng-menu-${this.uid}`, ...(ngDevMode ? [{ debugName: "menuId" }] : []));
218
+ /** Modal forces predictable close behavior */
219
+ effectiveCloseOnOutsideClick = computed(() => this.modal() ? true : this.closeOnOutsideClick(), ...(ngDevMode ? [{ debugName: "effectiveCloseOnOutsideClick" }] : []));
220
+ effectiveCloseOnEscape = computed(() => this.modal() ? true : this.closeOnEscape(), ...(ngDevMode ? [{ debugName: "effectiveCloseOnEscape" }] : []));
221
+ open() {
222
+ this.isOpen.set(true);
223
+ }
224
+ onOverlayOpened() {
225
+ this.opened.emit();
226
+ }
227
+ close(reason) {
228
+ if (!this.isOpen())
229
+ return;
230
+ this.isOpen.set(false);
231
+ this.closed.emit(reason);
232
+ queueMicrotask(() => this.triggerEl?.nativeElement?.focus());
233
+ }
234
+ onOverlayOpenChange(open) {
235
+ if (open)
236
+ this.isOpen.set(true);
237
+ }
238
+ onOverlayClosed(reason) {
239
+ this.isOpen.set(false);
240
+ this.closed.emit(reason);
241
+ queueMicrotask(() => this.triggerEl?.nativeElement?.focus());
242
+ }
243
+ onTriggerClick() {
244
+ this.isOpen() ? this.close('programmatic') : this.open();
245
+ }
246
+ requestCloseOnSelection() {
247
+ if (!this.closeOnItemClick())
248
+ return;
249
+ this.close('selection');
250
+ }
251
+ onItemSelected() {
252
+ this.requestCloseOnSelection();
253
+ }
254
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
255
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TngMenu, isStandalone: true, selector: "tng-menu", inputs: { modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnItemClick: { classPropertyName: "closeOnItemClick", publicName: "closeOnItemClick", isSignal: true, isRequired: false, transformFunction: null }, rootKlass: { classPropertyName: "rootKlass", publicName: "rootKlass", isSignal: true, isRequired: false, transformFunction: null }, triggerKlass: { classPropertyName: "triggerKlass", publicName: "triggerKlass", isSignal: true, isRequired: false, transformFunction: null }, panelKlass: { classPropertyName: "panelKlass", publicName: "panelKlass", isSignal: true, isRequired: false, transformFunction: null }, backdropKlass: { classPropertyName: "backdropKlass", publicName: "backdropKlass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed" }, queries: [{ propertyName: "tplDir", first: true, predicate: TngMenuTemplate, descendants: true }], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, static: true }], ngImport: i0, template: "\n<div [class]=\"rootKlass()\">\n <!-- Trigger -->\n <button\n #triggerEl\n type=\"button\"\n [class]=\"triggerKlass()\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? menuId() : null\"\n (click)=\"onTriggerClick()\"\n >\n <ng-content select=\"[tngMenuTrigger]\"></ng-content>\n </button>\n\n <!-- Overlay -->\n <tng-overlay-ref\n #overlayRef=\"tngOverlayRef\"\n [open]=\"isOpen()\"\n (openChange)=\"onOverlayOpenChange($event)\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed($event)\"\n >\n <tng-connected-overlay\n [open]=\"overlayRef.isOpen()\"\n [anchor]=\"triggerEl\"\n [placement]=\"placement()\"\n [offset]=\"offset()\"\n [width]=\"width()\"\n [hasBackdrop]=\"modal()\"\n [backdropClass]=\"backdropKlass()\"\n [closeOnOutsideClick]=\"effectiveCloseOnOutsideClick()\"\n [closeOnEscape]=\"effectiveCloseOnEscape()\"\n [closeOnInsideClick]=\"false\"\n (closed)=\"overlayRef.close($event)\"\n\n >\n <tng-overlay-panel [klass]=\"panelKlass()\" [modal]=\"modal()\">\n <div [id]=\"menuId()\" role=\"menu\">\n @if (menuTemplate) {\n <ng-container [ngTemplateOutlet]=\"menuTemplate!\" />\n } @else {\n <ng-content select=\"[tngMenuContent]\"></ng-content>\n }\n </div>\n </tng-overlay-panel>\n </tng-connected-overlay>\n </tng-overlay-ref>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TngConnectedOverlay, selector: "tng-connected-overlay", inputs: ["open", "anchor", "placement", "offset", "width", "closeOnOutsideClick", "closeOnInsideClick", "closeOnEscape", "hasBackdrop", "backdropClass"], outputs: ["opened", "closed", "backdropClick"] }, { kind: "component", type: TngOverlayPanel, selector: "tng-overlay-panel", inputs: ["klass", "modal", "role", "ariaLabel", "ariaLabelledby", "ariaDescribedby", "restoreFocus", "autoCapture", "deferCaptureElements"] }, { kind: "component", type: TngOverlayRef, selector: "tng-overlay-ref", inputs: ["open"], outputs: ["openChange", "opened", "closed"], exportAs: ["tngOverlayRef"] }] });
256
+ }
257
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenu, decorators: [{
258
+ type: Component,
259
+ args: [{ selector: 'tng-menu', standalone: true, imports: [
260
+ CommonModule,
261
+ NgTemplateOutlet,
262
+ TngConnectedOverlay,
263
+ TngOverlayPanel,
264
+ TngOverlayRef,
265
+ ], template: "\n<div [class]=\"rootKlass()\">\n <!-- Trigger -->\n <button\n #triggerEl\n type=\"button\"\n [class]=\"triggerKlass()\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? menuId() : null\"\n (click)=\"onTriggerClick()\"\n >\n <ng-content select=\"[tngMenuTrigger]\"></ng-content>\n </button>\n\n <!-- Overlay -->\n <tng-overlay-ref\n #overlayRef=\"tngOverlayRef\"\n [open]=\"isOpen()\"\n (openChange)=\"onOverlayOpenChange($event)\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed($event)\"\n >\n <tng-connected-overlay\n [open]=\"overlayRef.isOpen()\"\n [anchor]=\"triggerEl\"\n [placement]=\"placement()\"\n [offset]=\"offset()\"\n [width]=\"width()\"\n [hasBackdrop]=\"modal()\"\n [backdropClass]=\"backdropKlass()\"\n [closeOnOutsideClick]=\"effectiveCloseOnOutsideClick()\"\n [closeOnEscape]=\"effectiveCloseOnEscape()\"\n [closeOnInsideClick]=\"false\"\n (closed)=\"overlayRef.close($event)\"\n\n >\n <tng-overlay-panel [klass]=\"panelKlass()\" [modal]=\"modal()\">\n <div [id]=\"menuId()\" role=\"menu\">\n @if (menuTemplate) {\n <ng-container [ngTemplateOutlet]=\"menuTemplate!\" />\n } @else {\n <ng-content select=\"[tngMenuContent]\"></ng-content>\n }\n </div>\n </tng-overlay-panel>\n </tng-connected-overlay>\n </tng-overlay-ref>\n</div>\n" }]
266
+ }], propDecorators: { tplDir: [{
267
+ type: ContentChild,
268
+ args: [TngMenuTemplate]
269
+ }], triggerEl: [{
270
+ type: ViewChild,
271
+ args: ['triggerEl', { static: true }]
272
+ }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], closeOnOutsideClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsideClick", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeOnItemClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnItemClick", required: false }] }], rootKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootKlass", required: false }] }], triggerKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerKlass", required: false }] }], panelKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelKlass", required: false }] }], backdropKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "backdropKlass", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
273
+
274
+ class TngMenuItem {
275
+ menu = inject(TngMenu, { optional: true });
276
+ onClick() {
277
+ this.menu?.requestCloseOnSelection();
278
+ }
279
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
280
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: TngMenuItem, isStandalone: true, selector: "[tngMenuItem]", host: { listeners: { "click": "onClick()" } }, ngImport: i0 });
281
+ }
282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngMenuItem, decorators: [{
283
+ type: Directive,
284
+ args: [{
285
+ selector: '[tngMenuItem]',
286
+ standalone: true,
287
+ }]
288
+ }], propDecorators: { onClick: [{
289
+ type: HostListener,
290
+ args: ['click']
291
+ }] } });
292
+
293
+ class TngPaginator {
294
+ /* =====================
295
+ * Inputs
296
+ * ===================== */
297
+ /** Total items count */
298
+ count = input(0, ...(ngDevMode ? [{ debugName: "count" }] : []));
299
+ /** Current page (1-based) */
300
+ page = input(1, ...(ngDevMode ? [{ debugName: "page" }] : []));
301
+ /** Items per page */
302
+ pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
303
+ /** Page size options */
304
+ pageSizeOptions = input([10, 20, 50, 100], ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : []));
305
+ /** Hide page size selector */
306
+ hidePageSize = input(false, ...(ngDevMode ? [{ debugName: "hidePageSize" }] : []));
307
+ /** Max visible page buttons (window size) */
308
+ maxPages = input(7, ...(ngDevMode ? [{ debugName: "maxPages" }] : []));
309
+ /* =====================
310
+ * Klass inputs (Tailng)
311
+ * ===================== */
312
+ rootKlass = input('flex flex-wrap items-center justify-between gap-3 text-sm', ...(ngDevMode ? [{ debugName: "rootKlass" }] : []));
313
+ leftKlass = input('text-muted-foreground', ...(ngDevMode ? [{ debugName: "leftKlass" }] : []));
314
+ rightKlass = input('flex flex-wrap items-center gap-2', ...(ngDevMode ? [{ debugName: "rightKlass" }] : []));
315
+ buttonKlass = input('rounded-md border border-border bg-bg px-2.5 py-1.5 text-sm hover:bg-slate-50 disabled:opacity-50 disabled:pointer-events-none', ...(ngDevMode ? [{ debugName: "buttonKlass" }] : []));
316
+ activePageKlass = input('bg-primary text-on-primary border-primary hover:bg-primary', ...(ngDevMode ? [{ debugName: "activePageKlass" }] : []));
317
+ pageKlass = input('rounded-md border border-border bg-bg px-2.5 py-1.5 text-sm hover:bg-slate-50', ...(ngDevMode ? [{ debugName: "pageKlass" }] : []));
318
+ selectKlass = input('rounded-md border border-border bg-bg px-2 py-1.5 text-sm', ...(ngDevMode ? [{ debugName: "selectKlass" }] : []));
319
+ separatorKlass = input('mx-2 text-slate-400', ...(ngDevMode ? [{ debugName: "separatorKlass" }] : []));
320
+ /* =====================
321
+ * Outputs
322
+ * ===================== */
323
+ pageChange = output();
324
+ pageSizeChange = output();
325
+ change = output();
326
+ /* =====================
327
+ * Derived
328
+ * ===================== */
329
+ totalPages = computed(() => {
330
+ const total = Math.max(0, this.count());
331
+ const size = Math.max(1, this.pageSize());
332
+ return Math.max(1, Math.ceil(total / size));
333
+ }, ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
334
+ clampedPage = computed(() => {
335
+ const p = this.page();
336
+ return Math.min(Math.max(1, p), this.totalPages());
337
+ }, ...(ngDevMode ? [{ debugName: "clampedPage" }] : []));
338
+ skip = computed(() => (this.clampedPage() - 1) * this.pageSize(), ...(ngDevMode ? [{ debugName: "skip" }] : []));
339
+ rangeStart = computed(() => {
340
+ const total = this.count();
341
+ if (total <= 0)
342
+ return 0;
343
+ return this.skip() + 1;
344
+ }, ...(ngDevMode ? [{ debugName: "rangeStart" }] : []));
345
+ rangeEnd = computed(() => {
346
+ const total = this.count();
347
+ if (total <= 0)
348
+ return 0;
349
+ return Math.min(total, this.skip() + this.pageSize());
350
+ }, ...(ngDevMode ? [{ debugName: "rangeEnd" }] : []));
351
+ pages = computed(() => {
352
+ const total = this.totalPages();
353
+ const max = Math.max(5, this.maxPages()); // keep sane min
354
+ const current = this.clampedPage();
355
+ if (total <= max) {
356
+ return Array.from({ length: total }, (_, i) => i + 1);
357
+ }
358
+ const half = Math.floor(max / 2);
359
+ let start = Math.max(1, current - half);
360
+ let end = Math.min(total, start + max - 1);
361
+ // adjust if we hit end
362
+ start = Math.max(1, end - max + 1);
363
+ const result = [];
364
+ if (start > 1) {
365
+ result.push(1);
366
+ if (start > 2)
367
+ result.push('…');
368
+ }
369
+ for (let p = start; p <= end; p++)
370
+ result.push(p);
371
+ if (end < total) {
372
+ if (end < total - 1)
373
+ result.push('…');
374
+ result.push(total);
375
+ }
376
+ return result;
377
+ }, ...(ngDevMode ? [{ debugName: "pages" }] : []));
378
+ /* =====================
379
+ * Actions
380
+ * ===================== */
381
+ emitChange(nextPage, nextSize) {
382
+ this.pageChange.emit(nextPage);
383
+ this.pageSizeChange.emit(nextSize);
384
+ this.change.emit({
385
+ page: nextPage,
386
+ pageSize: nextSize,
387
+ skip: (nextPage - 1) * nextSize,
388
+ });
389
+ }
390
+ goTo(page) {
391
+ const next = Math.min(Math.max(1, page), this.totalPages());
392
+ if (next === this.clampedPage())
393
+ return;
394
+ // keep size unchanged
395
+ this.pageChange.emit(next);
396
+ this.change.emit({ page: next, pageSize: this.pageSize(), skip: (next - 1) * this.pageSize() });
397
+ }
398
+ prev() {
399
+ this.goTo(this.clampedPage() - 1);
400
+ }
401
+ next() {
402
+ this.goTo(this.clampedPage() + 1);
403
+ }
404
+ first() {
405
+ this.goTo(1);
406
+ }
407
+ last() {
408
+ this.goTo(this.totalPages());
409
+ }
410
+ onPageSizeSelect(value) {
411
+ const size = Math.max(1, Number(value) || this.pageSize());
412
+ if (size === this.pageSize())
413
+ return;
414
+ // keep user near same position: recompute page from previous skip
415
+ const currentSkip = (this.clampedPage() - 1) * this.pageSize();
416
+ const nextPage = Math.floor(currentSkip / size) + 1;
417
+ this.emitChange(nextPage, size);
418
+ }
419
+ isActive(p) {
420
+ return p === this.clampedPage();
421
+ }
422
+ pageBtnClasses(p) {
423
+ const base = this.pageKlass();
424
+ const active = this.isActive(p) ? ` ${this.activePageKlass()}` : '';
425
+ return (base + active).trim();
426
+ }
427
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngPaginator, deps: [], target: i0.ɵɵFactoryTarget.Component });
428
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TngPaginator, isStandalone: true, selector: "tng-paginator", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, hidePageSize: { classPropertyName: "hidePageSize", publicName: "hidePageSize", isSignal: true, isRequired: false, transformFunction: null }, maxPages: { classPropertyName: "maxPages", publicName: "maxPages", isSignal: true, isRequired: false, transformFunction: null }, rootKlass: { classPropertyName: "rootKlass", publicName: "rootKlass", isSignal: true, isRequired: false, transformFunction: null }, leftKlass: { classPropertyName: "leftKlass", publicName: "leftKlass", isSignal: true, isRequired: false, transformFunction: null }, rightKlass: { classPropertyName: "rightKlass", publicName: "rightKlass", isSignal: true, isRequired: false, transformFunction: null }, buttonKlass: { classPropertyName: "buttonKlass", publicName: "buttonKlass", isSignal: true, isRequired: false, transformFunction: null }, activePageKlass: { classPropertyName: "activePageKlass", publicName: "activePageKlass", isSignal: true, isRequired: false, transformFunction: null }, pageKlass: { classPropertyName: "pageKlass", publicName: "pageKlass", isSignal: true, isRequired: false, transformFunction: null }, selectKlass: { classPropertyName: "selectKlass", publicName: "selectKlass", isSignal: true, isRequired: false, transformFunction: null }, separatorKlass: { classPropertyName: "separatorKlass", publicName: "separatorKlass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", change: "change" }, ngImport: i0, template: "<div [class]=\"rootKlass()\">\n <!-- Left: range -->\n <div [class]=\"leftKlass()\">\n @if (count() > 0) {\n Showing <span class=\"text-foreground\">{{ rangeStart() }}</span>\u2013<span class=\"text-foreground\">{{ rangeEnd() }}</span>\n of <span class=\"text-foreground\">{{ count() }}</span>\n } @else {\n Showing 0 of 0\n }\n </div>\n\n <!-- Right: controls -->\n <div [class]=\"rightKlass()\">\n @if (!hidePageSize()) {\n <div class=\"flex items-center gap-2\">\n <span class=\"text-xs text-muted-foreground\">Rows</span>\n <select\n [class]=\"selectKlass()\"\n [value]=\"pageSize()\"\n (change)=\"onPageSizeSelect($any($event.target).value)\"\n >\n @for (s of pageSizeOptions(); track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n }\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"first()\" [disabled]=\"clampedPage() <= 1\">\n \u00AB\n </button>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"prev()\" [disabled]=\"clampedPage() <= 1\">\n \u2039\n </button>\n\n <!-- Page numbers -->\n <div class=\"flex items-center gap-1\">\n @for (p of pages(); track $index) {\n @if (p === '\u2026') {\n <span class=\"px-2 text-muted-foreground\">\u2026</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageBtnClasses(p)\"\n (click)=\"goTo(p)\"\n [attr.aria-current]=\"isActive(p) ? 'page' : null\"\n >\n {{ p }}\n </button>\n }\n }\n </div>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"next()\" [disabled]=\"clampedPage() >= totalPages()\">\n \u203A\n </button>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"last()\" [disabled]=\"clampedPage() >= totalPages()\">\n \u00BB\n </button>\n </div>\n</div>\n" });
429
+ }
430
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngPaginator, decorators: [{
431
+ type: Component,
432
+ args: [{ selector: 'tng-paginator', standalone: true, template: "<div [class]=\"rootKlass()\">\n <!-- Left: range -->\n <div [class]=\"leftKlass()\">\n @if (count() > 0) {\n Showing <span class=\"text-foreground\">{{ rangeStart() }}</span>\u2013<span class=\"text-foreground\">{{ rangeEnd() }}</span>\n of <span class=\"text-foreground\">{{ count() }}</span>\n } @else {\n Showing 0 of 0\n }\n </div>\n\n <!-- Right: controls -->\n <div [class]=\"rightKlass()\">\n @if (!hidePageSize()) {\n <div class=\"flex items-center gap-2\">\n <span class=\"text-xs text-muted-foreground\">Rows</span>\n <select\n [class]=\"selectKlass()\"\n [value]=\"pageSize()\"\n (change)=\"onPageSizeSelect($any($event.target).value)\"\n >\n @for (s of pageSizeOptions(); track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n }\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"first()\" [disabled]=\"clampedPage() <= 1\">\n \u00AB\n </button>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"prev()\" [disabled]=\"clampedPage() <= 1\">\n \u2039\n </button>\n\n <!-- Page numbers -->\n <div class=\"flex items-center gap-1\">\n @for (p of pages(); track $index) {\n @if (p === '\u2026') {\n <span class=\"px-2 text-muted-foreground\">\u2026</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageBtnClasses(p)\"\n (click)=\"goTo(p)\"\n [attr.aria-current]=\"isActive(p) ? 'page' : null\"\n >\n {{ p }}\n </button>\n }\n }\n </div>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"next()\" [disabled]=\"clampedPage() >= totalPages()\">\n \u203A\n </button>\n\n <button type=\"button\" [class]=\"buttonKlass()\" (click)=\"last()\" [disabled]=\"clampedPage() >= totalPages()\">\n \u00BB\n </button>\n </div>\n</div>\n" }]
433
+ }], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], hidePageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidePageSize", required: false }] }], maxPages: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPages", required: false }] }], rootKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootKlass", required: false }] }], leftKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftKlass", required: false }] }], rightKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rightKlass", required: false }] }], buttonKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonKlass", required: false }] }], activePageKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "activePageKlass", required: false }] }], pageKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageKlass", required: false }] }], selectKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectKlass", required: false }] }], separatorKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorKlass", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], pageSizeChange: [{ type: i0.Output, args: ["pageSizeChange"] }], change: [{ type: i0.Output, args: ["change"] }] } });
434
+
435
+ class TngSidenav {
436
+ /* =====================
437
+ * State
438
+ * ===================== */
439
+ collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : []));
440
+ /* =====================
441
+ * Tailwind class inputs
442
+ * ===================== */
443
+ rootKlass = input('group h-full bg-bg border-r border-border flex flex-col ' +
444
+ 'transition-[width] duration-200 ease-in-out will-change-[width]', ...(ngDevMode ? [{ debugName: "rootKlass" }] : []));
445
+ expandedKlass = input('w-64', ...(ngDevMode ? [{ debugName: "expandedKlass" }] : []));
446
+ collapsedKlass = input('w-16', ...(ngDevMode ? [{ debugName: "collapsedKlass" }] : []));
447
+ contentKlass = input('flex-1 overflow-auto', ...(ngDevMode ? [{ debugName: "contentKlass" }] : []));
448
+ footerKlass = input('border-t border-border', ...(ngDevMode ? [{ debugName: "footerKlass" }] : []));
449
+ /* =====================
450
+ * Computed
451
+ * ===================== */
452
+ classes = computed(() => [this.rootKlass(), this.collapsed() ? this.collapsedKlass() : this.expandedKlass()].join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : []));
453
+ /**
454
+ * Expose state as attribute for Tailwind selectors:
455
+ * `data-[collapsed=true]:...`
456
+ */
457
+ dataCollapsed = computed(() => (this.collapsed() ? 'true' : 'false'), ...(ngDevMode ? [{ debugName: "dataCollapsed" }] : []));
458
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenav, deps: [], target: i0.ɵɵFactoryTarget.Component });
459
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: TngSidenav, isStandalone: true, selector: "tng-sidenav", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, rootKlass: { classPropertyName: "rootKlass", publicName: "rootKlass", isSignal: true, isRequired: false, transformFunction: null }, expandedKlass: { classPropertyName: "expandedKlass", publicName: "expandedKlass", isSignal: true, isRequired: false, transformFunction: null }, collapsedKlass: { classPropertyName: "collapsedKlass", publicName: "collapsedKlass", isSignal: true, isRequired: false, transformFunction: null }, contentKlass: { classPropertyName: "contentKlass", publicName: "contentKlass", isSignal: true, isRequired: false, transformFunction: null }, footerKlass: { classPropertyName: "footerKlass", publicName: "footerKlass", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<nav\n [class]=\"classes()\"\n [attr.data-collapsed]=\"dataCollapsed()\"\n aria-label=\"Primary navigation\"\n>\n <!-- Header slot -->\n <div class=\"shrink-0\">\n <ng-content select=\"[tngSidenavHeader]\"></ng-content>\n </div>\n\n <!-- Main navigation -->\n <div [class]=\"contentKlass()\">\n <ng-content></ng-content>\n </div>\n\n <!-- Footer slot -->\n <div [class]=\"footerKlass()\">\n <ng-content select=\"[tngSidenavFooter]\"></ng-content>\n </div>\n</nav>\n" });
460
+ }
461
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenav, decorators: [{
462
+ type: Component,
463
+ args: [{ selector: 'tng-sidenav', standalone: true, template: "<nav\n [class]=\"classes()\"\n [attr.data-collapsed]=\"dataCollapsed()\"\n aria-label=\"Primary navigation\"\n>\n <!-- Header slot -->\n <div class=\"shrink-0\">\n <ng-content select=\"[tngSidenavHeader]\"></ng-content>\n </div>\n\n <!-- Main navigation -->\n <div [class]=\"contentKlass()\">\n <ng-content></ng-content>\n </div>\n\n <!-- Footer slot -->\n <div [class]=\"footerKlass()\">\n <ng-content select=\"[tngSidenavFooter]\"></ng-content>\n </div>\n</nav>\n" }]
464
+ }], propDecorators: { collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], rootKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootKlass", required: false }] }], expandedKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedKlass", required: false }] }], collapsedKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedKlass", required: false }] }], contentKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentKlass", required: false }] }], footerKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerKlass", required: false }] }] } });
465
+
466
+ class TngSidenavHeaderSlot {
467
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenavHeaderSlot, deps: [], target: i0.ɵɵFactoryTarget.Directive });
468
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: TngSidenavHeaderSlot, isStandalone: true, selector: "[tngSidenavHeader]", ngImport: i0 });
469
+ }
470
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenavHeaderSlot, decorators: [{
471
+ type: Directive,
472
+ args: [{ selector: '[tngSidenavHeader]', standalone: true }]
473
+ }] });
474
+ class TngSidenavFooterSlot {
475
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenavFooterSlot, deps: [], target: i0.ɵɵFactoryTarget.Directive });
476
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: TngSidenavFooterSlot, isStandalone: true, selector: "[tngSidenavFooter]", ngImport: i0 });
477
+ }
478
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngSidenavFooterSlot, decorators: [{
479
+ type: Directive,
480
+ args: [{ selector: '[tngSidenavFooter]', standalone: true }]
481
+ }] });
482
+
483
+ class TngStep {
484
+ stepper = inject(TngStepper);
485
+ el = inject((ElementRef));
486
+ /* =====================
487
+ * Inputs
488
+ * ===================== */
489
+ /** Optional label (you can also project content) */
490
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
491
+ /** Disable this step */
492
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
493
+ /** Mark as complete (used by linear mode to allow forward navigation) */
494
+ complete = input(false, { ...(ngDevMode ? { debugName: "complete" } : {}), transform: booleanAttribute });
495
+ /* =====================
496
+ * Klass hooks
497
+ * ===================== */
498
+ stepKlass = input('inline-flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium border border-transparent', ...(ngDevMode ? [{ debugName: "stepKlass" }] : []));
499
+ activeKlass = input('bg-primary text-on-primary', ...(ngDevMode ? [{ debugName: "activeKlass" }] : []));
500
+ inactiveKlass = input('bg-bg text-muted-foreground hover:text-foreground hover:bg-slate-50', ...(ngDevMode ? [{ debugName: "inactiveKlass" }] : []));
501
+ disabledKlass = input('opacity-50 cursor-not-allowed', ...(ngDevMode ? [{ debugName: "disabledKlass" }] : []));
502
+ /* =====================
503
+ * Internal
504
+ * ===================== */
505
+ focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : []));
506
+ isComplete() {
507
+ return this.complete();
508
+ }
509
+ isFocused() {
510
+ return this.focused();
511
+ }
512
+ focus() {
513
+ this.el.nativeElement.focus();
514
+ }
515
+ /* =====================
516
+ * Host bindings
517
+ * ===================== */
518
+ role = 'tab';
519
+ get tabindex() {
520
+ // roving tabindex: active is focusable by default, others -1
521
+ return this.stepper.isActive(this.index()) ? 0 : -1;
522
+ }
523
+ get selected() {
524
+ return this.stepper.isActive(this.index());
525
+ }
526
+ get ariaDisabled() {
527
+ return this.disabled() ? 'true' : null;
528
+ }
529
+ get klass() {
530
+ if (this.disabled())
531
+ return `${this.stepKlass()} ${this.disabledKlass()}`.trim();
532
+ return this.stepper.isActive(this.index())
533
+ ? `${this.stepKlass()} ${this.activeKlass()}`.trim()
534
+ : `${this.stepKlass()} ${this.inactiveKlass()}`.trim();
535
+ }
536
+ /* =====================
537
+ * Index resolution
538
+ * ===================== */
539
+ index = computed(() => {
540
+ const steps = this.stepper.steps();
541
+ return steps.indexOf(this);
542
+ }, ...(ngDevMode ? [{ debugName: "index" }] : []));
543
+ /* =====================
544
+ * Events
545
+ * ===================== */
546
+ onClick() {
547
+ if (this.disabled())
548
+ return;
549
+ this.stepper.setIndex(this.index());
550
+ }
551
+ onFocus() {
552
+ this.focused.set(true);
553
+ }
554
+ onBlur() {
555
+ this.focused.set(false);
556
+ }
557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStep, deps: [], target: i0.ɵɵFactoryTarget.Component });
558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: TngStep, isStandalone: true, selector: "tng-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, complete: { classPropertyName: "complete", publicName: "complete", isSignal: true, isRequired: false, transformFunction: null }, stepKlass: { classPropertyName: "stepKlass", publicName: "stepKlass", isSignal: true, isRequired: false, transformFunction: null }, activeKlass: { classPropertyName: "activeKlass", publicName: "activeKlass", isSignal: true, isRequired: false, transformFunction: null }, inactiveKlass: { classPropertyName: "inactiveKlass", publicName: "inactiveKlass", isSignal: true, isRequired: false, transformFunction: null }, disabledKlass: { classPropertyName: "disabledKlass", publicName: "disabledKlass", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick()", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "attr.role": "this.role", "attr.tabindex": "this.tabindex", "attr.aria-selected": "this.selected", "attr.aria-disabled": "this.ariaDisabled", "class": "this.klass" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
559
+ }
560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStep, decorators: [{
561
+ type: Component,
562
+ args: [{
563
+ selector: 'tng-step',
564
+ standalone: true,
565
+ template: `<ng-content />`,
566
+ }]
567
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], complete: [{ type: i0.Input, args: [{ isSignal: true, alias: "complete", required: false }] }], stepKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepKlass", required: false }] }], activeKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKlass", required: false }] }], inactiveKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "inactiveKlass", required: false }] }], disabledKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledKlass", required: false }] }], role: [{
568
+ type: HostBinding,
569
+ args: ['attr.role']
570
+ }], tabindex: [{
571
+ type: HostBinding,
572
+ args: ['attr.tabindex']
573
+ }], selected: [{
574
+ type: HostBinding,
575
+ args: ['attr.aria-selected']
576
+ }], ariaDisabled: [{
577
+ type: HostBinding,
578
+ args: ['attr.aria-disabled']
579
+ }], klass: [{
580
+ type: HostBinding,
581
+ args: ['class']
582
+ }], onClick: [{
583
+ type: HostListener,
584
+ args: ['click']
585
+ }], onFocus: [{
586
+ type: HostListener,
587
+ args: ['focus']
588
+ }], onBlur: [{
589
+ type: HostListener,
590
+ args: ['blur']
591
+ }] } });
592
+
593
+ class TngStepper {
594
+ /* =====================
595
+ * Inputs
596
+ * ===================== */
597
+ /**
598
+ * Controlled active index.
599
+ * If not null, stepper behaves controlled.
600
+ * NOTE: No transform here (Angular typing limitation with null initial).
601
+ */
602
+ activeIndex = input(null, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
603
+ /** Uncontrolled initial index */
604
+ defaultIndex = input(0, { ...(ngDevMode ? { debugName: "defaultIndex" } : {}), transform: numberAttribute });
605
+ /** Linear mode: prevent jumping forward beyond completed steps */
606
+ linear = input(false, { ...(ngDevMode ? { debugName: "linear" } : {}), transform: booleanAttribute });
607
+ /** Orientation */
608
+ orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
609
+ /* =====================
610
+ * Outputs
611
+ * ===================== */
612
+ activeIndexChange = output();
613
+ /* =====================
614
+ * Klass hooks
615
+ * ===================== */
616
+ rootKlass = input('w-full', ...(ngDevMode ? [{ debugName: "rootKlass" }] : []));
617
+ headerKlass = input('flex gap-2', ...(ngDevMode ? [{ debugName: "headerKlass" }] : []));
618
+ headerVerticalKlass = input('flex flex-col gap-2', ...(ngDevMode ? [{ debugName: "headerVerticalKlass" }] : []));
619
+ panelWrapKlass = input('pt-4', ...(ngDevMode ? [{ debugName: "panelWrapKlass" }] : []));
620
+ /* =====================
621
+ * Children
622
+ * ===================== */
623
+ steps = contentChildren(TngStep, { ...(ngDevMode ? { debugName: "steps" } : {}), descendants: true });
624
+ /* =====================
625
+ * State
626
+ * ===================== */
627
+ _index = signal(0, ...(ngDevMode ? [{ debugName: "_index" }] : []));
628
+ index = this._index.asReadonly();
629
+ constructor() {
630
+ // Controlled/uncontrolled sync
631
+ effect(() => {
632
+ const steps = this.steps(); // track for clamping
633
+ const n = steps.length;
634
+ const controlled = this.activeIndex();
635
+ if (controlled !== null) {
636
+ this._index.set(this.clamp(Number(controlled), n));
637
+ return;
638
+ }
639
+ // uncontrolled init (only when nothing set yet)
640
+ const current = this._index();
641
+ if (current === 0 && this.defaultIndex() !== 0) {
642
+ this._index.set(this.clamp(this.defaultIndex(), n));
643
+ }
644
+ else {
645
+ // always keep clamped if steps count changes
646
+ this._index.set(this.clamp(current, n));
647
+ }
648
+ });
649
+ }
650
+ /* =====================
651
+ * Public API
652
+ * ===================== */
653
+ setIndex(next) {
654
+ const clamped = this.clamp(next, this.steps().length);
655
+ if (!this.canActivate(clamped))
656
+ return;
657
+ this._index.set(clamped);
658
+ this.activeIndexChange.emit(clamped);
659
+ }
660
+ next() {
661
+ this.setIndex(this._index() + 1);
662
+ }
663
+ prev() {
664
+ this.setIndex(this._index() - 1);
665
+ }
666
+ isActive(i) {
667
+ return this._index() === i;
668
+ }
669
+ /* =====================
670
+ * Keyboard navigation (roving focus)
671
+ * ===================== */
672
+ onKeydown(ev) {
673
+ const steps = this.steps();
674
+ if (!steps.length)
675
+ return;
676
+ const key = ev.key;
677
+ const horizontal = this.orientation() === 'horizontal';
678
+ const prevKey = horizontal ? 'ArrowLeft' : 'ArrowUp';
679
+ const nextKey = horizontal ? 'ArrowRight' : 'ArrowDown';
680
+ if (key === prevKey) {
681
+ ev.preventDefault();
682
+ this.focusStep(this._index() - 1);
683
+ return;
684
+ }
685
+ if (key === nextKey) {
686
+ ev.preventDefault();
687
+ this.focusStep(this._index() + 1);
688
+ return;
689
+ }
690
+ if (key === 'Home') {
691
+ ev.preventDefault();
692
+ this.focusStep(0);
693
+ return;
694
+ }
695
+ if (key === 'End') {
696
+ ev.preventDefault();
697
+ this.focusStep(steps.length - 1);
698
+ return;
699
+ }
700
+ if (key === 'Enter' || key === ' ') {
701
+ const focusedIndex = steps.findIndex((s) => s.isFocused());
702
+ if (focusedIndex >= 0) {
703
+ ev.preventDefault();
704
+ this.setIndex(focusedIndex);
705
+ }
706
+ }
707
+ }
708
+ focusStep(i) {
709
+ const steps = this.steps();
710
+ const clamped = this.clamp(i, steps.length);
711
+ steps[clamped]?.focus();
712
+ }
713
+ /* =====================
714
+ * Rules
715
+ * ===================== */
716
+ clamp(i, n) {
717
+ if (n <= 0)
718
+ return 0;
719
+ if (!Number.isFinite(i))
720
+ return 0;
721
+ return Math.max(0, Math.min(n - 1, i));
722
+ }
723
+ canActivate(target) {
724
+ const steps = this.steps();
725
+ const current = this._index();
726
+ if (!this.linear())
727
+ return true;
728
+ if (target <= current)
729
+ return true;
730
+ for (let i = 0; i < target; i++) {
731
+ const s = steps[i];
732
+ if (!s)
733
+ return false;
734
+ if (!s.isComplete())
735
+ return false;
736
+ }
737
+ return true;
738
+ }
739
+ /* =====================
740
+ * Computed
741
+ * ===================== */
742
+ headerResolvedKlass = computed(() => this.orientation() === 'vertical' ? this.headerVerticalKlass() : this.headerKlass(), ...(ngDevMode ? [{ debugName: "headerResolvedKlass" }] : []));
743
+ orientationAttr = computed(() => this.orientation() === 'vertical' ? 'vertical' : 'horizontal', ...(ngDevMode ? [{ debugName: "orientationAttr" }] : []));
744
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
745
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.6", type: TngStepper, isStandalone: true, selector: "tng-stepper", inputs: { activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null }, defaultIndex: { classPropertyName: "defaultIndex", publicName: "defaultIndex", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, rootKlass: { classPropertyName: "rootKlass", publicName: "rootKlass", isSignal: true, isRequired: false, transformFunction: null }, headerKlass: { classPropertyName: "headerKlass", publicName: "headerKlass", isSignal: true, isRequired: false, transformFunction: null }, headerVerticalKlass: { classPropertyName: "headerVerticalKlass", publicName: "headerVerticalKlass", isSignal: true, isRequired: false, transformFunction: null }, panelWrapKlass: { classPropertyName: "panelWrapKlass", publicName: "panelWrapKlass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndexChange: "activeIndexChange" }, queries: [{ propertyName: "steps", predicate: TngStep, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"rootKlass()\">\n <!-- Step headers -->\n <div\n role=\"tablist\"\n [attr.aria-orientation]=\"orientationAttr()\"\n [class]=\"headerResolvedKlass()\"\n (keydown)=\"onKeydown($event)\"\n >\n <ng-content select=\"tng-step\"></ng-content>\n </div>\n\n <!-- Panels -->\n <div [class]=\"panelWrapKlass()\">\n <ng-content select=\"tng-step-panel\"></ng-content>\n </div>\n</div>\n" });
746
+ }
747
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStepper, decorators: [{
748
+ type: Component,
749
+ args: [{ selector: 'tng-stepper', standalone: true, template: "<div [class]=\"rootKlass()\">\n <!-- Step headers -->\n <div\n role=\"tablist\"\n [attr.aria-orientation]=\"orientationAttr()\"\n [class]=\"headerResolvedKlass()\"\n (keydown)=\"onKeydown($event)\"\n >\n <ng-content select=\"tng-step\"></ng-content>\n </div>\n\n <!-- Panels -->\n <div [class]=\"panelWrapKlass()\">\n <ng-content select=\"tng-step-panel\"></ng-content>\n </div>\n</div>\n" }]
750
+ }], ctorParameters: () => [], propDecorators: { activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }], defaultIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultIndex", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], activeIndexChange: [{ type: i0.Output, args: ["activeIndexChange"] }], rootKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootKlass", required: false }] }], headerKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerKlass", required: false }] }], headerVerticalKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerVerticalKlass", required: false }] }], panelWrapKlass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWrapKlass", required: false }] }], steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TngStep), { ...{ descendants: true }, isSignal: true }] }] } });
751
+
752
+ class TngStepPanel {
753
+ stepper = inject(TngStepper);
754
+ /** Panel index this content belongs to */
755
+ index = input.required(...(ngDevMode ? [{ debugName: "index" }] : []));
756
+ role = 'tabpanel';
757
+ get hidden() {
758
+ return !this.stepper.isActive(this.index());
759
+ }
760
+ // Optional: you can use this for debugging or conditional content
761
+ isActive = computed(() => this.stepper.isActive(this.index()), ...(ngDevMode ? [{ debugName: "isActive" }] : []));
762
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStepPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
763
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: TngStepPanel, isStandalone: true, selector: "tng-step-panel", inputs: { index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.role": "this.role", "hidden": "this.hidden" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
764
+ }
765
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TngStepPanel, decorators: [{
766
+ type: Component,
767
+ args: [{
768
+ selector: 'tng-step-panel',
769
+ standalone: true,
770
+ template: `<ng-content />`,
771
+ }]
772
+ }], propDecorators: { index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: true }] }], role: [{
773
+ type: HostBinding,
774
+ args: ['attr.role']
775
+ }], hidden: [{
776
+ type: HostBinding,
777
+ args: ['hidden']
778
+ }] } });
18
779
 
19
780
  /**
20
781
  * Generated bundle index. Do not edit.
21
782
  */
783
+
784
+ export { TngBreadcrumbs, TngDrawer, TngMenu, TngMenuItem, TngMenuTemplate, TngPaginator, TngSidenav, TngSidenavFooterSlot, TngSidenavHeaderSlot, TngStep, TngStepPanel, TngStepper };
22
785
  //# sourceMappingURL=tociva-tailng-ui-navigation.mjs.map