@ojiepermana/angular-navigation 22.0.43 → 22.0.45

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,4022 +1 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, TemplateRef, Directive, DestroyRef, signal, computed, effect, InjectionToken, input, model, output, contentChild, isDevMode, forwardRef, ChangeDetectionStrategy, Component, ElementRef, Injector, afterNextRender, booleanAttribute, ViewContainerRef } from '@angular/core';
3
- import { cn } from '@ojiepermana/angular-component/utils';
4
- import { NavigationService } from '@ojiepermana/angular-navigation/service';
5
- import { IconComponent } from '@ojiepermana/angular-component/icon';
6
- import { RouterLink, RouterLinkActive } from '@angular/router';
7
- import { NgTemplateOutlet } from '@angular/common';
8
-
9
- class NavigationIconDirective {
10
- template = inject(TemplateRef);
11
- static ngTemplateContextGuard(_directive, context) {
12
- return true;
13
- }
14
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
15
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.3", type: NavigationIconDirective, isStandalone: true, selector: "ng-template[NavigationIcon]", ngImport: i0 });
16
- }
17
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationIconDirective, decorators: [{
18
- type: Directive,
19
- args: [{
20
- selector: 'ng-template[NavigationIcon]',
21
- }]
22
- }] });
23
-
24
- function normalizeType(type, hasChildren) {
25
- if (type === 'divider' || type === 'spacer' || type === 'group' || type === 'mega') {
26
- return type;
27
- }
28
- if (type === 'collapsible' || type === 'collapsable') {
29
- return 'collapsible';
30
- }
31
- if (type === 'aside' && hasChildren) {
32
- return 'collapsible';
33
- }
34
- if (!type && hasChildren) {
35
- return 'collapsible';
36
- }
37
- return 'item';
38
- }
39
- function toKeyPart(value) {
40
- return value
41
- .toLowerCase()
42
- .replace(/[^a-z0-9_-]+/g, '-')
43
- .replace(/^-+|-+$/g, '');
44
- }
45
- function itemFallbackKey(item, index) {
46
- return (toKeyPart(item.title ?? item.link?.toString() ?? item.href ?? `item-${index}`) ||
47
- `item-${index}`);
48
- }
49
- function normalizeItem(item, index, path) {
50
- if (item.isHidden?.(item)) {
51
- return null;
52
- }
53
- const children = (item.children ?? [])
54
- .map((child, childIndex) => normalizeItem(child, childIndex, `${path}-${childIndex}`))
55
- .filter((child) => child !== null);
56
- const hasChildren = children.length > 0;
57
- const key = item.id ?? `${path}-${itemFallbackKey(item, index)}`;
58
- return {
59
- ...item,
60
- key,
61
- stateId: item.id ?? key,
62
- panelId: `nav-panel-${toKeyPart(key) || index}`,
63
- type: normalizeType(item.type, hasChildren),
64
- source: item,
65
- children,
66
- };
67
- }
68
- function normalizeUiNavItems(items) {
69
- return items
70
- .map((item, index) => normalizeItem(item, index, `nav-${index}`))
71
- .filter((item) => item !== null);
72
- }
73
-
74
- function injectNavigationController(inputs) {
75
- const nav = inject(NavigationService);
76
- const destroyRef = inject(DestroyRef);
77
- // Token unik per instance <Navigation> untuk validasi keunikan id di NavigationService.
78
- const owner = {};
79
- const registeredState = signal(null, /* @ts-ignore */
80
- ...(ngDevMode ? [{ debugName: "registeredState" }] : /* istanbul ignore next */ []));
81
- let previousRegisteredId = null;
82
- const normalizedNavId = computed(() => normalizeId(inputs.navId()), /* @ts-ignore */
83
- ...(ngDevMode ? [{ debugName: "normalizedNavId" }] : /* istanbul ignore next */ []));
84
- const collapsedPreference = computed(() => inputs.collapsed() ?? (inputs.compact() ? true : null), /* @ts-ignore */
85
- ...(ngDevMode ? [{ debugName: "collapsedPreference" }] : /* istanbul ignore next */ []));
86
- const normalizedItems = computed(() => normalizeUiNavItems(inputs.data()), /* @ts-ignore */
87
- ...(ngDevMode ? [{ debugName: "normalizedItems" }] : /* istanbul ignore next */ []));
88
- const fallbackState = computed(() => ({
89
- id: normalizedNavId(),
90
- orientation: inputs.orientation(),
91
- type: fallbackType(inputs.orientation(), inputs.type()),
92
- position: inputs.position() ?? (inputs.orientation() === 'horizontal' ? 'top' : 'left'),
93
- collapsed: collapsedPreference() ?? false,
94
- dockbarMode: inputs.dockbarMode() ?? 'sticky',
95
- }), /* @ts-ignore */
96
- ...(ngDevMode ? [{ debugName: "fallbackState" }] : /* istanbul ignore next */ []));
97
- const resolvedState = computed(() => nav.currentState(normalizedNavId()) ?? registeredState() ?? fallbackState(), /* @ts-ignore */
98
- ...(ngDevMode ? [{ debugName: "resolvedState" }] : /* istanbul ignore next */ []));
99
- const activeIdSet = computed(() => {
100
- const ids = inputs.activeIds();
101
- if (!ids) {
102
- return new Set();
103
- }
104
- return ids instanceof Set ? new Set(ids) : new Set(ids);
105
- }, /* @ts-ignore */
106
- ...(ngDevMode ? [{ debugName: "activeIdSet" }] : /* istanbul ignore next */ []));
107
- effect(() => {
108
- if (!inputs.enabled()) {
109
- return;
110
- }
111
- const nextState = nav.register({
112
- id: normalizedNavId(),
113
- orientation: inputs.orientation(),
114
- type: inputs.type(),
115
- position: inputs.position(),
116
- collapsed: collapsedPreference(),
117
- dockbarMode: inputs.dockbarMode(),
118
- }, owner);
119
- if (previousRegisteredId && previousRegisteredId !== nextState.id) {
120
- nav.unregister(previousRegisteredId, owner);
121
- }
122
- previousRegisteredId = nextState.id;
123
- registeredState.set(nextState);
124
- });
125
- destroyRef.onDestroy(() => {
126
- if (previousRegisteredId) {
127
- nav.unregister(previousRegisteredId, owner);
128
- }
129
- });
130
- return {
131
- normalizedNavId,
132
- normalizedItems,
133
- resolvedState,
134
- activeIdSet,
135
- toggleCollapsed: () => nav.toggleCollapsed(normalizedNavId()),
136
- };
137
- }
138
- function normalizeId(value) {
139
- return value.trim() || 'default';
140
- }
141
- function fallbackType(orientation, type) {
142
- if (orientation === 'vertical' && (type === 'sidebar' || type === 'dockbar')) {
143
- return type;
144
- }
145
- if (orientation === 'horizontal' && (type === 'navbar' || type === 'flyout')) {
146
- return type;
147
- }
148
- return orientation === 'horizontal' ? 'navbar' : 'sidebar';
149
- }
150
-
151
- const NAVIGATION_SHELL = new InjectionToken('NAVIGATION_SHELL');
152
-
153
- /**
154
- * Container navigasi deklaratif. Type ditentukan oleh komponen anak:
155
- *
156
- * ```html
157
- * <Navigation id="main" [data]="items">
158
- * <NavigationSidebar>
159
- * <NavigationHeader>…</NavigationHeader>
160
- * <NavigationContent />
161
- * <NavigationFooter>…</NavigationFooter>
162
- * </NavigationSidebar>
163
- * </Navigation>
164
- * ```
165
- *
166
- * Header dan footer opsional; `NavigationContent` selalu dirender oleh
167
- * type (default otomatis bila tidak diproyeksikan).
168
- */
169
- class NavigationContainerComponent {
170
- navId = input('default', { ...(ngDevMode ? { debugName: "navId" } : /* istanbul ignore next */ {}), alias: 'id' });
171
- data = input([], /* @ts-ignore */
172
- ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
173
- ariaLabel = input('Primary navigation', /* @ts-ignore */
174
- ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
175
- compact = input(false, /* @ts-ignore */
176
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
177
- collapseTree = input('stairs', { ...(ngDevMode ? { debugName: "collapseTree" } : /* istanbul ignore next */ {}), alias: 'collapse-tree' });
178
- class = input('', /* @ts-ignore */
179
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
180
- itemClass = input('', /* @ts-ignore */
181
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
182
- /** Kelas Tailwind untuk container `<li>` group horizontal (flyout tab / navbar group). */
183
- groupClass = input('', { ...(ngDevMode ? { debugName: "groupClass" } : /* istanbul ignore next */ {}), alias: 'nav-group-class' });
184
- activeIds = input(null, /* @ts-ignore */
185
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
186
- activeUrl = input(null, /* @ts-ignore */
187
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
188
- openedIds = model([], /* @ts-ignore */
189
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
190
- itemSelected = output();
191
- nav = inject(NavigationService);
192
- destroyRef = inject(DestroyRef);
193
- hoverPreviewExpanded = signal(false, /* @ts-ignore */
194
- ...(ngDevMode ? [{ debugName: "hoverPreviewExpanded" }] : /* istanbul ignore next */ []));
195
- /** Konfigurasi type aktif yang didaftarkan wrapper anak (sidebar/dockbar/navbar/flyout). */
196
- typeConfig = signal(null, /* @ts-ignore */
197
- ...(ngDevMode ? [{ debugName: "typeConfig" }] : /* istanbul ignore next */ []));
198
- orientationPreference = computed(() => this.typeConfig()?.orientation ?? 'vertical', /* @ts-ignore */
199
- ...(ngDevMode ? [{ debugName: "orientationPreference" }] : /* istanbul ignore next */ []));
200
- typePreference = computed(() => this.typeConfig()?.type ?? null, /* @ts-ignore */
201
- ...(ngDevMode ? [{ debugName: "typePreference" }] : /* istanbul ignore next */ []));
202
- positionPreference = computed(() => this.typeConfig()?.position?.() ?? null, /* @ts-ignore */
203
- ...(ngDevMode ? [{ debugName: "positionPreference" }] : /* istanbul ignore next */ []));
204
- collapsedPreference = computed(() => this.typeConfig()?.collapsed?.() ?? null, /* @ts-ignore */
205
- ...(ngDevMode ? [{ debugName: "collapsedPreference" }] : /* istanbul ignore next */ []));
206
- dockbarModePreference = computed(() => this.typeConfig()?.dockbarMode?.() ?? null, /* @ts-ignore */
207
- ...(ngDevMode ? [{ debugName: "dockbarModePreference" }] : /* istanbul ignore next */ []));
208
- sidebarCollapse = computed(() => this.typeConfig()?.sidebarCollapse?.() ?? false, /* @ts-ignore */
209
- ...(ngDevMode ? [{ debugName: "sidebarCollapse" }] : /* istanbul ignore next */ []));
210
- previewExpanded = computed(() => this.typeConfig()?.previewExpanded?.() ?? false, /* @ts-ignore */
211
- ...(ngDevMode ? [{ debugName: "previewExpanded" }] : /* istanbul ignore next */ []));
212
- typeStyle = computed(() => this.typeConfig()?.typeStyle?.() ?? 'flat', /* @ts-ignore */
213
- ...(ngDevMode ? [{ debugName: "typeStyle" }] : /* istanbul ignore next */ []));
214
- flyoutLabel = computed(() => this.typeConfig()?.flyoutLabel?.() ?? 'Menu', /* @ts-ignore */
215
- ...(ngDevMode ? [{ debugName: "flyoutLabel" }] : /* istanbul ignore next */ []));
216
- flyoutIcon = computed(() => this.typeConfig()?.flyoutIcon?.() ?? null, /* @ts-ignore */
217
- ...(ngDevMode ? [{ debugName: "flyoutIcon" }] : /* istanbul ignore next */ []));
218
- flyoutIconOnly = computed(() => this.typeConfig()?.flyoutIconOnly?.() ?? false, /* @ts-ignore */
219
- ...(ngDevMode ? [{ debugName: "flyoutIconOnly" }] : /* istanbul ignore next */ []));
220
- flyoutIconPosition = computed(() => this.typeConfig()?.flyoutIconPosition?.() ?? 'start', /* @ts-ignore */
221
- ...(ngDevMode ? [{ debugName: "flyoutIconPosition" }] : /* istanbul ignore next */ []));
222
- flyoutTriggerVariant = computed(() => this.typeConfig()?.flyoutTriggerVariant?.() ?? 'button', /* @ts-ignore */
223
- ...(ngDevMode ? [{ debugName: "flyoutTriggerVariant" }] : /* istanbul ignore next */ []));
224
- flyoutTriggerFloating = computed(() => this.typeConfig()?.flyoutTriggerFloating?.() ?? false, /* @ts-ignore */
225
- ...(ngDevMode ? [{ debugName: "flyoutTriggerFloating" }] : /* istanbul ignore next */ []));
226
- flyoutTriggerClass = computed(() => this.typeConfig()?.flyoutTriggerClass?.() ?? '', /* @ts-ignore */
227
- ...(ngDevMode ? [{ debugName: "flyoutTriggerClass" }] : /* istanbul ignore next */ []));
228
- controller = injectNavigationController({
229
- navId: this.navId,
230
- data: this.data,
231
- orientation: this.orientationPreference,
232
- type: this.typePreference,
233
- position: this.positionPreference,
234
- collapsed: this.collapsedPreference,
235
- dockbarMode: this.dockbarModePreference,
236
- compact: this.compact,
237
- activeIds: this.activeIds,
238
- enabled: computed(() => this.typeConfig() !== null),
239
- });
240
- iconTemplate = contentChild(NavigationIconDirective, /* @ts-ignore */
241
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
242
- normalizedItems = this.controller.normalizedItems;
243
- resolvedState = this.controller.resolvedState;
244
- activeIdSet = this.controller.activeIdSet;
245
- previewRailExpanded = computed(() => {
246
- const state = this.resolvedState();
247
- if (state.orientation !== 'vertical' || state.type !== 'sidebar' || !state.collapsed) {
248
- return false;
249
- }
250
- return this.previewExpanded() || (this.sidebarCollapse() && this.hoverPreviewExpanded());
251
- }, /* @ts-ignore */
252
- ...(ngDevMode ? [{ debugName: "previewRailExpanded" }] : /* istanbul ignore next */ []));
253
- previewRailOffset = computed(() => (this.previewRailExpanded() ? '15rem' : '0px'), /* @ts-ignore */
254
- ...(ngDevMode ? [{ debugName: "previewRailOffset" }] : /* istanbul ignore next */ []));
255
- displayState = computed(() => {
256
- const state = this.resolvedState();
257
- if (state.type === 'dockbar') {
258
- return { ...state, collapsed: true };
259
- }
260
- return this.previewRailExpanded() ? { ...state, collapsed: false } : state;
261
- }, /* @ts-ignore */
262
- ...(ngDevMode ? [{ debugName: "displayState" }] : /* istanbul ignore next */ []));
263
- dockbarAsideOpen = computed(() => {
264
- const state = this.resolvedState();
265
- if (state.type !== 'dockbar' || state.dockbarMode !== 'sticky') {
266
- return false;
267
- }
268
- return (this.nav.resolveDockbarGroup(state.id, this.normalizedItems(), state.dockbarMode, this.activeIdSet(), this.activeUrl()) !== null);
269
- }, /* @ts-ignore */
270
- ...(ngDevMode ? [{ debugName: "dockbarAsideOpen" }] : /* istanbul ignore next */ []));
271
- collapseEnabled = computed(() => {
272
- const state = this.resolvedState();
273
- return this.sidebarCollapse() && state.orientation === 'vertical' && state.type === 'sidebar';
274
- }, /* @ts-ignore */
275
- ...(ngDevMode ? [{ debugName: "collapseEnabled" }] : /* istanbul ignore next */ []));
276
- /** Kelas shell yang dipakai host komponen type (eks `div` shell internal). */
277
- shellClasses = computed(() => cn('flex h-full min-h-0 transition-[width,box-shadow,transform] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none', this.resolvedState().orientation === 'horizontal'
278
- ? 'flex-row items-stretch overflow-visible'
279
- : this.resolvedState().type === 'dockbar'
280
- ? 'flex-col overflow-visible'
281
- : 'flex-col overflow-hidden', this.resolvedState().type === 'dockbar' && [
282
- 'w-16 shrink-0',
283
- this.resolvedState().position === 'right' && 'ml-auto',
284
- ], this.resolvedState().position === 'right' ? 'origin-right' : 'origin-left', this.previewRailExpanded() && [
285
- 'absolute inset-y-0 z-20 w-76 overflow-hidden bg-background shadow-xl',
286
- this.resolvedState().position === 'right'
287
- ? 'right-0 border-l border-[hsl(var(--border)/var(--opacity-70))]'
288
- : 'left-0 border-r border-[hsl(var(--border)/var(--opacity-70))]',
289
- ]), /* @ts-ignore */
290
- ...(ngDevMode ? [{ debugName: "shellClasses" }] : /* istanbul ignore next */ []));
291
- state = this.resolvedState;
292
- hostClasses = computed(() => cn('relative block min-h-0 text-foreground transition-[width] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none', this.resolvedState().orientation === 'horizontal'
293
- ? 'h-full w-full'
294
- : this.resolvedState().type === 'dockbar'
295
- ? this.dockbarAsideOpen()
296
- ? 'w-76'
297
- : 'w-16'
298
- : this.resolvedState().collapsed
299
- ? 'w-16'
300
- : 'w-76', this.resolvedState().orientation === 'horizontal' ||
301
- this.resolvedState().type === 'dockbar' ||
302
- this.previewRailExpanded()
303
- ? 'overflow-visible'
304
- : 'overflow-hidden', this.class()), /* @ts-ignore */
305
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
306
- constructor() {
307
- // Publikasikan data ke registry by id agar surface lain (mis. apps-launcher di `Page`)
308
- // bisa membaca nav by id tanpa mendaftarkan ulang `<Navigation>` dengan id yang sama.
309
- effect(() => this.nav.publishData(this.navId(), this.data()));
310
- this.destroyRef.onDestroy(() => this.nav.clearData(this.navId()));
311
- }
312
- /**
313
- * Dipanggil komponen type saat dibuat. Satu `<Navigation>` hanya boleh
314
- * memuat satu type hidup — pendaftaran ganda dianggap salah konfigurasi.
315
- */
316
- registerType(config) {
317
- if (this.typeConfig() !== null && isDevMode()) {
318
- throw new Error('[Navigation] Hanya satu type (<NavigationSidebar>/<NavigationDockbar>/<NavigationNavbar>/<NavigationFlyout>) yang boleh hidup dalam satu <Navigation>.');
319
- }
320
- this.typeConfig.set(config);
321
- }
322
- unregisterType(config) {
323
- if (this.typeConfig() === config) {
324
- this.typeConfig.set(null);
325
- }
326
- }
327
- toggleCollapsed() {
328
- this.controller.toggleCollapsed();
329
- }
330
- setHoverPreview(value) {
331
- this.hoverPreviewExpanded.set(this.sidebarCollapse() ? value : false);
332
- }
333
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
334
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.3", type: NavigationContainerComponent, isStandalone: true, selector: "Navigation", inputs: { navId: { classPropertyName: "navId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapse-tree", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, groupClass: { classPropertyName: "groupClass", publicName: "nav-group-class", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIds: "openedIdsChange", itemSelected: "itemSelected" }, host: { attributes: { "role": "navigation" }, listeners: { "mouseenter": "setHoverPreview(true)", "mouseleave": "setHoverPreview(false)" }, properties: { "class": "hostClasses()", "attr.aria-label": "ariaLabel() || null", "attr.data-navigation-id": "resolvedState().id", "attr.data-orientation": "resolvedState().orientation", "attr.data-type": "resolvedState().type", "attr.data-type-style": "typeStyle()", "attr.data-position": "resolvedState().position", "attr.data-collapse-tree": "collapseTree()", "attr.data-preview-expanded": "previewRailExpanded() ? \"true\" : null" } }, providers: [
335
- { provide: NAVIGATION_SHELL, useExisting: forwardRef(() => NavigationContainerComponent) },
336
- ], queries: [{ propertyName: "iconTemplate", first: true, predicate: NavigationIconDirective, descendants: true, isSignal: true }], ngImport: i0, template: ` <ng-content /> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
337
- }
338
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationContainerComponent, decorators: [{
339
- type: Component,
340
- args: [{
341
- selector: 'Navigation',
342
- changeDetection: ChangeDetectionStrategy.OnPush,
343
- providers: [
344
- { provide: NAVIGATION_SHELL, useExisting: forwardRef(() => NavigationContainerComponent) },
345
- ],
346
- host: {
347
- '[class]': 'hostClasses()',
348
- role: 'navigation',
349
- '[attr.aria-label]': 'ariaLabel() || null',
350
- '[attr.data-navigation-id]': 'resolvedState().id',
351
- '[attr.data-orientation]': 'resolvedState().orientation',
352
- '[attr.data-type]': 'resolvedState().type',
353
- '[attr.data-type-style]': 'typeStyle()',
354
- '[attr.data-position]': 'resolvedState().position',
355
- '[attr.data-collapse-tree]': 'collapseTree()',
356
- '[attr.data-preview-expanded]': 'previewRailExpanded() ? "true" : null',
357
- '(mouseenter)': 'setHoverPreview(true)',
358
- '(mouseleave)': 'setHoverPreview(false)',
359
- },
360
- template: ` <ng-content /> `,
361
- }]
362
- }], ctorParameters: () => [], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapse-tree", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-group-class", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }, { type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], iconTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationIconDirective), { isSignal: true }] }] } });
363
-
364
- class NavigationItemContentComponent {
365
- nav = inject(NavigationService);
366
- item = input.required(/* @ts-ignore */
367
- ...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
368
- active = input(false, /* @ts-ignore */
369
- ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
370
- compact = input(false, /* @ts-ignore */
371
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
372
- orientation = input('vertical', /* @ts-ignore */
373
- ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
374
- level = input(0, /* @ts-ignore */
375
- ...(ngDevMode ? [{ debugName: "level" }] : /* istanbul ignore next */ []));
376
- collapseTree = input('stairs', /* @ts-ignore */
377
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
378
- iconTemplate = input(undefined, /* @ts-ignore */
379
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
380
- iconSlotClasses = computed(() => cn('relative z-10 inline-flex shrink-0 items-center justify-center transition-[border-color,background-color,color,box-shadow] duration-200', this.orientation() === 'vertical'
381
- ? this.compact()
382
- ? 'h-8 w-8 rounded-full border'
383
- : 'h-7 w-7 rounded-full border'
384
- : 'h-5 w-5 rounded-full border border-transparent', this.usesStraightVerticalSurface() && 'overflow-hidden bg-background/85 backdrop-blur-sm border-transparent', this.active() && !this.usesStraightVerticalSurface() ? 'border-primary text-current' : 'border-transparent', this.active() && this.usesStraightVerticalSurface() && 'text-current', this.compact() && 'mx-auto'), /* @ts-ignore */
385
- ...(ngDevMode ? [{ debugName: "iconSlotClasses" }] : /* istanbul ignore next */ []));
386
- titleClasses = computed(() => cn('block truncate', this.active() && 'font-semibold text-foreground', this.item().classes?.title), /* @ts-ignore */
387
- ...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
388
- showSubtitle = computed(() => !!this.item().subtitle && !(this.orientation() === 'horizontal' && this.level() === 0), /* @ts-ignore */
389
- ...(ngDevMode ? [{ debugName: "showSubtitle" }] : /* istanbul ignore next */ []));
390
- subtitleClasses = computed(() => cn('block truncate text-xs font-normal text-muted-foreground', this.item().classes?.subtitle), /* @ts-ignore */
391
- ...(ngDevMode ? [{ debugName: "subtitleClasses" }] : /* istanbul ignore next */ []));
392
- compactFallbackClasses = computed(() => cn('inline-flex h-5 min-w-5 items-center justify-center text-xs font-semibold uppercase'), /* @ts-ignore */
393
- ...(ngDevMode ? [{ debugName: "compactFallbackClasses" }] : /* istanbul ignore next */ []));
394
- defaultBadgeClasses = computed(() => cn('nav-badge ml-auto inline-flex h-5 shrink-0 items-center rounded-full px-2', this.active() ? 'bg-background text-foreground' : 'bg-muted text-muted-foreground'), /* @ts-ignore */
395
- ...(ngDevMode ? [{ debugName: "defaultBadgeClasses" }] : /* istanbul ignore next */ []));
396
- defaultIconSize = computed(() => (this.usesStraightVerticalSurface() ? 18 : 16), /* @ts-ignore */
397
- ...(ngDevMode ? [{ debugName: "defaultIconSize" }] : /* istanbul ignore next */ []));
398
- defaultIconClasses = computed(() => cn('text-current', this.item().classes?.icon), /* @ts-ignore */
399
- ...(ngDevMode ? [{ debugName: "defaultIconClasses" }] : /* istanbul ignore next */ []));
400
- iconContext = computed(() => this.nav.iconContext(this.item(), this.active(), this.level(), this.orientation()), /* @ts-ignore */
401
- ...(ngDevMode ? [{ debugName: "iconContext" }] : /* istanbul ignore next */ []));
402
- compactFallback() {
403
- return this.nav.compactFallback(this.item());
404
- }
405
- usesStraightVerticalSurface() {
406
- return this.orientation() === 'vertical' && !this.compact() && this.collapseTree() === 'straight';
407
- }
408
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationItemContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
409
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationItemContentComponent, isStandalone: true, selector: "NavigationItemContent", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
410
- @if (item().icon; as iconName) {
411
- <span data-navigation-icon-slot="true" [class]="iconSlotClasses()">
412
- @if (iconTemplate(); as customIcon) {
413
- <ng-container [ngTemplateOutlet]="customIcon.template" [ngTemplateOutletContext]="iconContext()" />
414
- } @else {
415
- <Icon [name]="iconName" [class]="defaultIconClasses()" [size]="defaultIconSize()" />
416
- }
417
- </span>
418
- }
419
-
420
- @if (!compact()) {
421
- <span class="min-w-0 flex-1">
422
- <span [class]="titleClasses()">{{ item().title }}</span>
423
- @if (showSubtitle()) {
424
- <span [class]="subtitleClasses()">{{ item().subtitle }}</span>
425
- }
426
- </span>
427
-
428
- @if (item().badge; as badge) {
429
- <span [class]="badge.classes ?? defaultBadgeClasses()">{{ badge.title }}</span>
430
- }
431
- }
432
-
433
- @if (compact() && !item().icon) {
434
- <span aria-hidden="true" [class]="compactFallbackClasses()">{{ compactFallback() }}</span>
435
- }
436
- `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
437
- }
438
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationItemContentComponent, decorators: [{
439
- type: Component,
440
- args: [{
441
- selector: 'NavigationItemContent',
442
- changeDetection: ChangeDetectionStrategy.OnPush,
443
- imports: [NgTemplateOutlet, IconComponent],
444
- host: {
445
- class: 'contents',
446
- },
447
- template: `
448
- @if (item().icon; as iconName) {
449
- <span data-navigation-icon-slot="true" [class]="iconSlotClasses()">
450
- @if (iconTemplate(); as customIcon) {
451
- <ng-container [ngTemplateOutlet]="customIcon.template" [ngTemplateOutletContext]="iconContext()" />
452
- } @else {
453
- <Icon [name]="iconName" [class]="defaultIconClasses()" [size]="defaultIconSize()" />
454
- }
455
- </span>
456
- }
457
-
458
- @if (!compact()) {
459
- <span class="min-w-0 flex-1">
460
- <span [class]="titleClasses()">{{ item().title }}</span>
461
- @if (showSubtitle()) {
462
- <span [class]="subtitleClasses()">{{ item().subtitle }}</span>
463
- }
464
- </span>
465
-
466
- @if (item().badge; as badge) {
467
- <span [class]="badge.classes ?? defaultBadgeClasses()">{{ badge.title }}</span>
468
- }
469
- }
470
-
471
- @if (compact() && !item().icon) {
472
- <span aria-hidden="true" [class]="compactFallbackClasses()">{{ compactFallback() }}</span>
473
- }
474
- `,
475
- }]
476
- }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }] } });
477
-
478
- class NavigationItemComponent {
479
- nav = inject(NavigationService);
480
- navId = input('default', /* @ts-ignore */
481
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
482
- item = input.required(/* @ts-ignore */
483
- ...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
484
- level = input(0, /* @ts-ignore */
485
- ...(ngDevMode ? [{ debugName: "level" }] : /* istanbul ignore next */ []));
486
- orientation = input('vertical', /* @ts-ignore */
487
- ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
488
- compact = input(false, /* @ts-ignore */
489
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
490
- itemClass = input('', /* @ts-ignore */
491
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
492
- activeIds = input(new Set(), /* @ts-ignore */
493
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
494
- activeUrl = input(null, /* @ts-ignore */
495
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
496
- iconTemplate = input(undefined, /* @ts-ignore */
497
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
498
- collapseTree = input('stairs', /* @ts-ignore */
499
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
500
- straightRail = input(false, /* @ts-ignore */
501
- ...(ngDevMode ? [{ debugName: "straightRail" }] : /* istanbul ignore next */ []));
502
- straightRailActive = input(false, /* @ts-ignore */
503
- ...(ngDevMode ? [{ debugName: "straightRailActive" }] : /* istanbul ignore next */ []));
504
- firstInBranch = input(false, /* @ts-ignore */
505
- ...(ngDevMode ? [{ debugName: "firstInBranch" }] : /* istanbul ignore next */ []));
506
- lastInBranch = input(false, /* @ts-ignore */
507
- ...(ngDevMode ? [{ debugName: "lastInBranch" }] : /* istanbul ignore next */ []));
508
- openedIds = input([], /* @ts-ignore */
509
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
510
- openedIdsChange = output();
511
- itemSelected = output();
512
- openedIdSet = computed(() => new Set(this.openedIds()), /* @ts-ignore */
513
- ...(ngDevMode ? [{ debugName: "openedIdSet" }] : /* istanbul ignore next */ []));
514
- isHorizontalRoot = computed(() => this.orientation() === 'horizontal' && this.level() === 0, /* @ts-ignore */
515
- ...(ngDevMode ? [{ debugName: "isHorizontalRoot" }] : /* istanbul ignore next */ []));
516
- isActive = computed(() => this.nav.isItemActive(this.item(), this.activeIds(), this.activeUrl()), /* @ts-ignore */
517
- ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
518
- showChildren = computed(() => !this.compact() && this.isOpen(), /* @ts-ignore */
519
- ...(ngDevMode ? [{ debugName: "showChildren" }] : /* istanbul ignore next */ []));
520
- hostClasses = computed(() => {
521
- if (this.item().type === 'divider') {
522
- return this.dividerClasses();
523
- }
524
- if (this.item().type === 'spacer') {
525
- return 'flex-1';
526
- }
527
- if (this.item().type === 'group' || this.item().type === 'mega') {
528
- return this.groupContainerClasses();
529
- }
530
- return this.itemContainerClasses();
531
- }, /* @ts-ignore */
532
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
533
- hostRole = computed(() => {
534
- if (this.item().type === 'divider') {
535
- return 'separator';
536
- }
537
- return this.orientation() === 'horizontal' ? 'none' : null;
538
- }, /* @ts-ignore */
539
- ...(ngDevMode ? [{ debugName: "hostRole" }] : /* istanbul ignore next */ []));
540
- headingId = computed(() => `${this.item().panelId}-heading`, /* @ts-ignore */
541
- ...(ngDevMode ? [{ debugName: "headingId" }] : /* istanbul ignore next */ []));
542
- isRouterItem() {
543
- return this.nav.isRouterItem(this.item());
544
- }
545
- hrefFor() {
546
- return this.nav.hrefFor(this.item());
547
- }
548
- relFor() {
549
- return this.nav.relFor(this.item());
550
- }
551
- routerLinkActiveOptions() {
552
- return this.nav.routerLinkActiveOptions(this.item());
553
- }
554
- itemRole() {
555
- return this.nav.itemRole(this.orientation(), this.level());
556
- }
557
- compactLabel() {
558
- return this.nav.compactLabel(this.item(), this.compact());
559
- }
560
- titleFor() {
561
- return this.nav.titleFor(this.item(), this.compact());
562
- }
563
- isOpen() {
564
- return this.openedIdSet().has(this.item().stateId) || this.openedIdSet().has(this.item().key) || this.isActive();
565
- }
566
- toggleOpen() {
567
- if (this.item().disabled) {
568
- return;
569
- }
570
- const next = new Set(this.openedIds());
571
- if (next.has(this.item().stateId)) {
572
- next.delete(this.item().stateId);
573
- }
574
- else {
575
- next.add(this.item().stateId);
576
- }
577
- this.openedIdsChange.emit([...next]);
578
- }
579
- selectItem(event) {
580
- if (this.item().disabled) {
581
- event.preventDefault();
582
- event.stopPropagation();
583
- return;
584
- }
585
- this.item().action?.(this.item().source);
586
- this.itemSelected.emit({
587
- item: this.item().source,
588
- key: this.item().key,
589
- type: this.item().type,
590
- link: this.item().link,
591
- external: !!this.hrefFor(),
592
- });
593
- this.nav.closePanel(this.navId());
594
- this.nav.closeDrawer(this.navId());
595
- }
596
- leafClasses(active) {
597
- return cn('NavigationItem nav-text group/nav inline-flex min-w-0 items-center rounded-md font-medium transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', this.orientation() === 'horizontal' && this.level() === 0 ? 'h-9 px-3 py-2' : 'w-full px-3 py-1.5 text-left', this.orientation() === 'horizontal' && this.level() === 0 ? 'gap-3' : 'gap-1.5', this.compact() && 'h-10 w-10 justify-center gap-0 px-0 text-center', this.interactiveStateClasses(active), this.item().disabled && 'pointer-events-none opacity-50', this.item().classes?.wrapper, this.itemClass());
598
- }
599
- triggerClasses(active) {
600
- return cn('nav-trigger nav-text group/nav inline-flex min-w-0 items-center rounded-md font-medium transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', this.orientation() === 'horizontal' && this.level() === 0 ? 'h-9 px-3 py-2' : 'w-full px-3 py-1.5 text-left', this.orientation() === 'horizontal' && this.level() === 0 ? 'gap-3' : 'gap-1.5', this.compact() && 'h-10 w-10 justify-center gap-0 px-0 text-center', this.interactiveStateClasses(active), this.item().classes?.wrapper, this.itemClass());
601
- }
602
- interactiveStateClasses(active) {
603
- const showsNestedActiveConnector = active &&
604
- this.orientation() === 'vertical' &&
605
- !this.compact() &&
606
- this.level() > 1 &&
607
- this.collapseTree() === 'stairs';
608
- if (this.orientation() === 'vertical' && !this.compact()) {
609
- return cn('relative isolate', "before:pointer-events-none before:absolute before:inset-y-0 before:left-2 before:right-2 before:-z-10 before:rounded-md before:border before:border-transparent before:bg-transparent before:transition-colors before:duration-200 before:content-['']", showsNestedActiveConnector &&
610
- "after:pointer-events-none after:absolute after:-left-2 after:top-1/2 after:-z-10 after:h-px after:w-5 after:-translate-y-1/2 after:rounded-full after:bg-current/25 after:content-['']", active
611
- ? 'font-semibold text-foreground hover:before:border-primary'
612
- : 'text-foreground/80 hover:text-accent-foreground hover:before:border-primary hover:before:bg-accent');
613
- }
614
- return active ? 'font-semibold text-foreground' : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground';
615
- }
616
- chevronClasses() {
617
- return cn('ml-auto shrink-0 self-center transition-transform duration-200', this.isOpen() && 'rotate-90');
618
- }
619
- itemContainerClasses() {
620
- return cn(this.orientation() === 'horizontal' && this.level() === 0 ? 'relative' : 'w-full', this.compact() && 'flex justify-center', this.straightRailClasses());
621
- }
622
- groupContainerClasses() {
623
- return cn('w-full', this.level() > 0 && 'pt-2');
624
- }
625
- dividerClasses() {
626
- return cn(this.orientation() === 'horizontal' && this.level() === 0 ? 'mx-1 h-5 w-px' : 'my-2 w-full px-2');
627
- }
628
- groupHeadingClasses() {
629
- return cn('nav-heading px-3 py-2 text-muted-foreground', this.item().classes?.title);
630
- }
631
- childListClasses() {
632
- const isGroupedBranch = this.item().type === 'group' || this.item().type === 'mega';
633
- const usesStairsTree = this.collapseTree() === 'stairs';
634
- return cn('flex list-none flex-col gap-0.5 p-0', !this.compact() && 'mt-0.5', this.level() >= 0 &&
635
- !this.compact() &&
636
- !isGroupedBranch &&
637
- usesStairsTree &&
638
- cn("relative ml-[1.625rem] pl-2 before:absolute before:-top-2 before:bottom-0 before:left-0 before:w-px before:-translate-x-1/2 before:rounded-full before:content-['']", this.isActive() ? 'before:bg-current/25' : 'before:bg-border'));
639
- }
640
- showStraightRailForChildren() {
641
- return (!this.compact() &&
642
- this.collapseTree() === 'straight' &&
643
- this.item().type !== 'group' &&
644
- this.item().type !== 'mega');
645
- }
646
- straightRailClasses() {
647
- if (!this.straightRail() || this.orientation() !== 'vertical' || this.compact()) {
648
- return '';
649
- }
650
- return cn('relative', "before:pointer-events-none before:absolute before:left-[1.625rem] before:w-0 before:-z-10 before:border-l before:border-dotted before:content-['']", this.straightRailActive() ? 'before:border-primary/50' : 'before:border-border/50', this.firstInBranch() ? 'before:-top-9' : 'before:-top-0.5', this.lastInBranch() ? 'before:bottom-[calc(100%-1.25rem)]' : 'before:-bottom-0.5');
651
- }
652
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
653
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationItemComponent, isStandalone: true, selector: "li[NavigationItem]", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, straightRail: { classPropertyName: "straightRail", publicName: "straightRail", isSignal: true, isRequired: false, transformFunction: null }, straightRailActive: { classPropertyName: "straightRailActive", publicName: "straightRailActive", isSignal: true, isRequired: false, transformFunction: null }, firstInBranch: { classPropertyName: "firstInBranch", publicName: "firstInBranch", isSignal: true, isRequired: false, transformFunction: null }, lastInBranch: { classPropertyName: "lastInBranch", publicName: "lastInBranch", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { properties: { "class": "hostClasses()", "attr.role": "hostRole()", "attr.data-navigation-item-key": "item().key", "attr.aria-hidden": "item().type === \"spacer\" ? \"true\" : null" } }, ngImport: i0, template: `
654
- @switch (item().type) {
655
- @case ('divider') {
656
- <span class="block h-px w-full bg-border"></span>
657
- }
658
-
659
- @case ('spacer') {}
660
-
661
- @case ('group') {
662
- @if (!compact() && item().title) {
663
- <div [id]="headingId()" [class]="groupHeadingClasses()">{{ item().title }}</div>
664
- }
665
-
666
- <ul [class]="childListClasses()" role="group" [attr.aria-labelledby]="item().title ? headingId() : null">
667
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
668
- <li
669
- NavigationItem
670
- [navId]="navId()"
671
- [item]="child"
672
- [level]="level() + 1"
673
- [orientation]="orientation()"
674
- [compact]="compact()"
675
- [itemClass]="itemClass()"
676
- [activeIds]="activeIds()"
677
- [activeUrl]="activeUrl()"
678
- [iconTemplate]="iconTemplate()"
679
- [collapseTree]="collapseTree()"
680
- [straightRail]="showStraightRailForChildren()"
681
- [straightRailActive]="isActive()"
682
- [firstInBranch]="isFirst"
683
- [lastInBranch]="isLast"
684
- [openedIds]="openedIds()"
685
- (openedIdsChange)="openedIdsChange.emit($event)"
686
- (itemSelected)="itemSelected.emit($event)"></li>
687
- }
688
- </ul>
689
- }
690
-
691
- @case ('collapsible') {
692
- <button
693
- type="button"
694
- [class]="triggerClasses(isActive())"
695
- [attr.aria-expanded]="isOpen()"
696
- [attr.aria-controls]="item().panelId"
697
- [attr.aria-label]="compactLabel()"
698
- [attr.title]="titleFor()"
699
- [disabled]="item().disabled || null"
700
- (click)="toggleOpen()">
701
- <NavigationItemContent
702
- [item]="item()"
703
- [active]="isActive()"
704
- [compact]="compact()"
705
- [orientation]="orientation()"
706
- [level]="level()"
707
- [collapseTree]="collapseTree()"
708
- [iconTemplate]="iconTemplate()" />
709
-
710
- @if (!compact()) {
711
- <Icon name="chevron_right" [size]="16" [class]="chevronClasses()" />
712
- }
713
- </button>
714
-
715
- @if (showChildren()) {
716
- <ul [id]="item().panelId" [class]="childListClasses()" role="group">
717
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
718
- <li
719
- NavigationItem
720
- [navId]="navId()"
721
- [item]="child"
722
- [level]="level() + 1"
723
- [orientation]="orientation()"
724
- [compact]="false"
725
- [itemClass]="itemClass()"
726
- [activeIds]="activeIds()"
727
- [activeUrl]="activeUrl()"
728
- [iconTemplate]="iconTemplate()"
729
- [collapseTree]="collapseTree()"
730
- [straightRail]="showStraightRailForChildren()"
731
- [straightRailActive]="isActive()"
732
- [firstInBranch]="isFirst"
733
- [lastInBranch]="isLast"
734
- [openedIds]="openedIds()"
735
- (openedIdsChange)="openedIdsChange.emit($event)"
736
- (itemSelected)="itemSelected.emit($event)"></li>
737
- }
738
- </ul>
739
- }
740
- }
741
-
742
- @case ('mega') {
743
- @if (!compact() && item().title) {
744
- <div [id]="headingId()" [class]="groupHeadingClasses()">{{ item().title }}</div>
745
- }
746
-
747
- <ul [class]="childListClasses()" role="group" [attr.aria-labelledby]="item().title ? headingId() : null">
748
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
749
- <li
750
- NavigationItem
751
- [navId]="navId()"
752
- [item]="child"
753
- [level]="level() + 1"
754
- [orientation]="orientation()"
755
- [compact]="compact()"
756
- [itemClass]="itemClass()"
757
- [activeIds]="activeIds()"
758
- [activeUrl]="activeUrl()"
759
- [iconTemplate]="iconTemplate()"
760
- [collapseTree]="collapseTree()"
761
- [straightRail]="showStraightRailForChildren()"
762
- [straightRailActive]="isActive()"
763
- [firstInBranch]="isFirst"
764
- [lastInBranch]="isLast"
765
- [openedIds]="openedIds()"
766
- (openedIdsChange)="openedIdsChange.emit($event)"
767
- (itemSelected)="itemSelected.emit($event)"></li>
768
- }
769
- </ul>
770
- }
771
-
772
- @default {
773
- @if (isRouterItem()) {
774
- <a
775
- [class]="leafClasses(routerActive.isActive || isActive())"
776
- [routerLink]="item().link ?? null"
777
- [queryParams]="item().queryParams ?? null"
778
- [queryParamsHandling]="item().queryParamsHandling ?? null"
779
- [fragment]="item().fragment ?? undefined"
780
- [preserveFragment]="item().preserveFragment ?? false"
781
- [target]="item().target ?? undefined"
782
- routerLinkActive
783
- #routerActive="routerLinkActive"
784
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
785
- [attr.aria-current]="routerActive.isActive || isActive() ? 'page' : null"
786
- [attr.aria-disabled]="item().disabled || null"
787
- [attr.aria-label]="compactLabel()"
788
- [attr.title]="titleFor()"
789
- [attr.role]="itemRole()"
790
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
791
- (click)="selectItem($event)">
792
- <NavigationItemContent
793
- [item]="item()"
794
- [active]="routerActive.isActive || isActive()"
795
- [compact]="compact()"
796
- [orientation]="orientation()"
797
- [level]="level()"
798
- [collapseTree]="collapseTree()"
799
- [iconTemplate]="iconTemplate()" />
800
- </a>
801
- } @else if (hrefFor()) {
802
- <a
803
- [class]="leafClasses(isActive())"
804
- [attr.href]="hrefFor()"
805
- [attr.target]="item().target ?? (item().externalLink ? '_blank' : null)"
806
- [attr.rel]="relFor()"
807
- [attr.aria-current]="isActive() ? 'page' : null"
808
- [attr.aria-disabled]="item().disabled || null"
809
- [attr.aria-label]="compactLabel()"
810
- [attr.title]="titleFor()"
811
- [attr.role]="itemRole()"
812
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
813
- (click)="selectItem($event)">
814
- <NavigationItemContent
815
- [item]="item()"
816
- [active]="isActive()"
817
- [compact]="compact()"
818
- [orientation]="orientation()"
819
- [level]="level()"
820
- [collapseTree]="collapseTree()"
821
- [iconTemplate]="iconTemplate()" />
822
- </a>
823
- } @else {
824
- <button
825
- type="button"
826
- [class]="leafClasses(isActive())"
827
- [disabled]="item().disabled || null"
828
- [attr.aria-current]="isActive() ? 'page' : null"
829
- [attr.aria-label]="compactLabel()"
830
- [attr.title]="titleFor()"
831
- [attr.role]="itemRole()"
832
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
833
- (click)="selectItem($event)">
834
- <NavigationItemContent
835
- [item]="item()"
836
- [active]="isActive()"
837
- [compact]="compact()"
838
- [orientation]="orientation()"
839
- [level]="level()"
840
- [collapseTree]="collapseTree()"
841
- [iconTemplate]="iconTemplate()" />
842
- </button>
843
- }
844
- }
845
- }
846
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationItemContentComponent, selector: "NavigationItemContent", inputs: ["item", "active", "compact", "orientation", "level", "collapseTree", "iconTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
847
- }
848
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationItemComponent, decorators: [{
849
- type: Component,
850
- args: [{
851
- selector: 'li[NavigationItem]',
852
- changeDetection: ChangeDetectionStrategy.OnPush,
853
- imports: [RouterLink, RouterLinkActive, IconComponent, NavigationItemContentComponent],
854
- host: {
855
- '[class]': 'hostClasses()',
856
- '[attr.role]': 'hostRole()',
857
- '[attr.data-navigation-item-key]': 'item().key',
858
- '[attr.aria-hidden]': 'item().type === "spacer" ? "true" : null',
859
- },
860
- template: `
861
- @switch (item().type) {
862
- @case ('divider') {
863
- <span class="block h-px w-full bg-border"></span>
864
- }
865
-
866
- @case ('spacer') {}
867
-
868
- @case ('group') {
869
- @if (!compact() && item().title) {
870
- <div [id]="headingId()" [class]="groupHeadingClasses()">{{ item().title }}</div>
871
- }
872
-
873
- <ul [class]="childListClasses()" role="group" [attr.aria-labelledby]="item().title ? headingId() : null">
874
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
875
- <li
876
- NavigationItem
877
- [navId]="navId()"
878
- [item]="child"
879
- [level]="level() + 1"
880
- [orientation]="orientation()"
881
- [compact]="compact()"
882
- [itemClass]="itemClass()"
883
- [activeIds]="activeIds()"
884
- [activeUrl]="activeUrl()"
885
- [iconTemplate]="iconTemplate()"
886
- [collapseTree]="collapseTree()"
887
- [straightRail]="showStraightRailForChildren()"
888
- [straightRailActive]="isActive()"
889
- [firstInBranch]="isFirst"
890
- [lastInBranch]="isLast"
891
- [openedIds]="openedIds()"
892
- (openedIdsChange)="openedIdsChange.emit($event)"
893
- (itemSelected)="itemSelected.emit($event)"></li>
894
- }
895
- </ul>
896
- }
897
-
898
- @case ('collapsible') {
899
- <button
900
- type="button"
901
- [class]="triggerClasses(isActive())"
902
- [attr.aria-expanded]="isOpen()"
903
- [attr.aria-controls]="item().panelId"
904
- [attr.aria-label]="compactLabel()"
905
- [attr.title]="titleFor()"
906
- [disabled]="item().disabled || null"
907
- (click)="toggleOpen()">
908
- <NavigationItemContent
909
- [item]="item()"
910
- [active]="isActive()"
911
- [compact]="compact()"
912
- [orientation]="orientation()"
913
- [level]="level()"
914
- [collapseTree]="collapseTree()"
915
- [iconTemplate]="iconTemplate()" />
916
-
917
- @if (!compact()) {
918
- <Icon name="chevron_right" [size]="16" [class]="chevronClasses()" />
919
- }
920
- </button>
921
-
922
- @if (showChildren()) {
923
- <ul [id]="item().panelId" [class]="childListClasses()" role="group">
924
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
925
- <li
926
- NavigationItem
927
- [navId]="navId()"
928
- [item]="child"
929
- [level]="level() + 1"
930
- [orientation]="orientation()"
931
- [compact]="false"
932
- [itemClass]="itemClass()"
933
- [activeIds]="activeIds()"
934
- [activeUrl]="activeUrl()"
935
- [iconTemplate]="iconTemplate()"
936
- [collapseTree]="collapseTree()"
937
- [straightRail]="showStraightRailForChildren()"
938
- [straightRailActive]="isActive()"
939
- [firstInBranch]="isFirst"
940
- [lastInBranch]="isLast"
941
- [openedIds]="openedIds()"
942
- (openedIdsChange)="openedIdsChange.emit($event)"
943
- (itemSelected)="itemSelected.emit($event)"></li>
944
- }
945
- </ul>
946
- }
947
- }
948
-
949
- @case ('mega') {
950
- @if (!compact() && item().title) {
951
- <div [id]="headingId()" [class]="groupHeadingClasses()">{{ item().title }}</div>
952
- }
953
-
954
- <ul [class]="childListClasses()" role="group" [attr.aria-labelledby]="item().title ? headingId() : null">
955
- @for (child of item().children; track child.key; let isFirst = $first; let isLast = $last) {
956
- <li
957
- NavigationItem
958
- [navId]="navId()"
959
- [item]="child"
960
- [level]="level() + 1"
961
- [orientation]="orientation()"
962
- [compact]="compact()"
963
- [itemClass]="itemClass()"
964
- [activeIds]="activeIds()"
965
- [activeUrl]="activeUrl()"
966
- [iconTemplate]="iconTemplate()"
967
- [collapseTree]="collapseTree()"
968
- [straightRail]="showStraightRailForChildren()"
969
- [straightRailActive]="isActive()"
970
- [firstInBranch]="isFirst"
971
- [lastInBranch]="isLast"
972
- [openedIds]="openedIds()"
973
- (openedIdsChange)="openedIdsChange.emit($event)"
974
- (itemSelected)="itemSelected.emit($event)"></li>
975
- }
976
- </ul>
977
- }
978
-
979
- @default {
980
- @if (isRouterItem()) {
981
- <a
982
- [class]="leafClasses(routerActive.isActive || isActive())"
983
- [routerLink]="item().link ?? null"
984
- [queryParams]="item().queryParams ?? null"
985
- [queryParamsHandling]="item().queryParamsHandling ?? null"
986
- [fragment]="item().fragment ?? undefined"
987
- [preserveFragment]="item().preserveFragment ?? false"
988
- [target]="item().target ?? undefined"
989
- routerLinkActive
990
- #routerActive="routerLinkActive"
991
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
992
- [attr.aria-current]="routerActive.isActive || isActive() ? 'page' : null"
993
- [attr.aria-disabled]="item().disabled || null"
994
- [attr.aria-label]="compactLabel()"
995
- [attr.title]="titleFor()"
996
- [attr.role]="itemRole()"
997
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
998
- (click)="selectItem($event)">
999
- <NavigationItemContent
1000
- [item]="item()"
1001
- [active]="routerActive.isActive || isActive()"
1002
- [compact]="compact()"
1003
- [orientation]="orientation()"
1004
- [level]="level()"
1005
- [collapseTree]="collapseTree()"
1006
- [iconTemplate]="iconTemplate()" />
1007
- </a>
1008
- } @else if (hrefFor()) {
1009
- <a
1010
- [class]="leafClasses(isActive())"
1011
- [attr.href]="hrefFor()"
1012
- [attr.target]="item().target ?? (item().externalLink ? '_blank' : null)"
1013
- [attr.rel]="relFor()"
1014
- [attr.aria-current]="isActive() ? 'page' : null"
1015
- [attr.aria-disabled]="item().disabled || null"
1016
- [attr.aria-label]="compactLabel()"
1017
- [attr.title]="titleFor()"
1018
- [attr.role]="itemRole()"
1019
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
1020
- (click)="selectItem($event)">
1021
- <NavigationItemContent
1022
- [item]="item()"
1023
- [active]="isActive()"
1024
- [compact]="compact()"
1025
- [orientation]="orientation()"
1026
- [level]="level()"
1027
- [collapseTree]="collapseTree()"
1028
- [iconTemplate]="iconTemplate()" />
1029
- </a>
1030
- } @else {
1031
- <button
1032
- type="button"
1033
- [class]="leafClasses(isActive())"
1034
- [disabled]="item().disabled || null"
1035
- [attr.aria-current]="isActive() ? 'page' : null"
1036
- [attr.aria-label]="compactLabel()"
1037
- [attr.title]="titleFor()"
1038
- [attr.role]="itemRole()"
1039
- [attr.data-navigation-root-item]="isHorizontalRoot() ? 'true' : null"
1040
- (click)="selectItem($event)">
1041
- <NavigationItemContent
1042
- [item]="item()"
1043
- [active]="isActive()"
1044
- [compact]="compact()"
1045
- [orientation]="orientation()"
1046
- [level]="level()"
1047
- [collapseTree]="collapseTree()"
1048
- [iconTemplate]="iconTemplate()" />
1049
- </button>
1050
- }
1051
- }
1052
- }
1053
- `,
1054
- }]
1055
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], straightRail: [{ type: i0.Input, args: [{ isSignal: true, alias: "straightRail", required: false }] }], straightRailActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "straightRailActive", required: false }] }], firstInBranch: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstInBranch", required: false }] }], lastInBranch: [{ type: i0.Input, args: [{ isSignal: true, alias: "lastInBranch", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1056
-
1057
- class NavigationListComponent {
1058
- navId = input('default', /* @ts-ignore */
1059
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
1060
- items = input([], /* @ts-ignore */
1061
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1062
- collapsed = input(false, /* @ts-ignore */
1063
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
1064
- compact = input(false, /* @ts-ignore */
1065
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
1066
- position = input('left', /* @ts-ignore */
1067
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
1068
- itemClass = input('', /* @ts-ignore */
1069
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
1070
- activeIds = input(new Set(), /* @ts-ignore */
1071
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
1072
- activeUrl = input(null, /* @ts-ignore */
1073
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
1074
- iconTemplate = input(undefined, /* @ts-ignore */
1075
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
1076
- collapseTree = input('stairs', /* @ts-ignore */
1077
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
1078
- openedIds = input([], /* @ts-ignore */
1079
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
1080
- openedIdsChange = output();
1081
- itemSelected = output();
1082
- isCollapsed = computed(() => this.collapsed() || this.compact(), /* @ts-ignore */
1083
- ...(ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []));
1084
- hostClasses = computed(() => cn('block', this.position() === 'right' && 'items-end text-right'), /* @ts-ignore */
1085
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1086
- listClasses = computed(() => this.isCollapsed()
1087
- ? cn('flex list-none flex-col items-center gap-0.5 p-0')
1088
- : cn('flex list-none flex-col gap-0.5 p-0', this.position() === 'right' && 'items-end'), /* @ts-ignore */
1089
- ...(ngDevMode ? [{ debugName: "listClasses" }] : /* istanbul ignore next */ []));
1090
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1091
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationListComponent, isStandalone: true, selector: "NavigationList", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { properties: { "class": "hostClasses()", "attr.data-position": "position()" } }, ngImport: i0, template: `
1092
- <ul [class]="listClasses()" role="list">
1093
- @for (item of items(); track item.key) {
1094
- <li
1095
- NavigationItem
1096
- [navId]="navId()"
1097
- [item]="item"
1098
- [level]="0"
1099
- [orientation]="'vertical'"
1100
- [compact]="isCollapsed()"
1101
- [itemClass]="itemClass()"
1102
- [activeIds]="activeIds()"
1103
- [activeUrl]="activeUrl()"
1104
- [iconTemplate]="iconTemplate()"
1105
- [collapseTree]="collapseTree()"
1106
- [openedIds]="openedIds()"
1107
- (openedIdsChange)="openedIdsChange.emit($event)"
1108
- (itemSelected)="itemSelected.emit($event)"></li>
1109
- }
1110
- </ul>
1111
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1112
- }
1113
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationListComponent, decorators: [{
1114
- type: Component,
1115
- args: [{
1116
- selector: 'NavigationList',
1117
- changeDetection: ChangeDetectionStrategy.OnPush,
1118
- imports: [NavigationItemComponent],
1119
- host: {
1120
- '[class]': 'hostClasses()',
1121
- '[attr.data-position]': 'position()',
1122
- },
1123
- template: `
1124
- <ul [class]="listClasses()" role="list">
1125
- @for (item of items(); track item.key) {
1126
- <li
1127
- NavigationItem
1128
- [navId]="navId()"
1129
- [item]="item"
1130
- [level]="0"
1131
- [orientation]="'vertical'"
1132
- [compact]="isCollapsed()"
1133
- [itemClass]="itemClass()"
1134
- [activeIds]="activeIds()"
1135
- [activeUrl]="activeUrl()"
1136
- [iconTemplate]="iconTemplate()"
1137
- [collapseTree]="collapseTree()"
1138
- [openedIds]="openedIds()"
1139
- (openedIdsChange)="openedIdsChange.emit($event)"
1140
- (itemSelected)="itemSelected.emit($event)"></li>
1141
- }
1142
- </ul>
1143
- `,
1144
- }]
1145
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1146
-
1147
- class NavigationDockbarMenuComponent {
1148
- nav = inject(NavigationService);
1149
- host = inject(ElementRef);
1150
- injector = inject(Injector);
1151
- navId = input('default', /* @ts-ignore */
1152
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
1153
- items = input([], /* @ts-ignore */
1154
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1155
- mode = input('sticky', /* @ts-ignore */
1156
- ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
1157
- position = input('left', /* @ts-ignore */
1158
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
1159
- itemClass = input('', /* @ts-ignore */
1160
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
1161
- activeIds = input(new Set(), /* @ts-ignore */
1162
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
1163
- activeUrl = input(null, /* @ts-ignore */
1164
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
1165
- iconTemplate = input(undefined, /* @ts-ignore */
1166
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
1167
- collapseTree = input('stairs', /* @ts-ignore */
1168
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
1169
- openedIds = input([], /* @ts-ignore */
1170
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
1171
- openedIdsChange = output();
1172
- itemSelected = output();
1173
- isDrawerMode = computed(() => this.mode() === 'drawer', /* @ts-ignore */
1174
- ...(ngDevMode ? [{ debugName: "isDrawerMode" }] : /* istanbul ignore next */ []));
1175
- asideId = computed(() => `nav-dockbar-${this.safeId(this.navId())}`, /* @ts-ignore */
1176
- ...(ngDevMode ? [{ debugName: "asideId" }] : /* istanbul ignore next */ []));
1177
- asideHeadingId = computed(() => `${this.asideId()}-heading`, /* @ts-ignore */
1178
- ...(ngDevMode ? [{ debugName: "asideHeadingId" }] : /* istanbul ignore next */ []));
1179
- openGroup = computed(() => this.nav.resolveDockbarGroup(this.navId(), this.items(), this.mode(), this.activeIds(), this.activeUrl()), /* @ts-ignore */
1180
- ...(ngDevMode ? [{ debugName: "openGroup" }] : /* istanbul ignore next */ []));
1181
- hostClasses = computed(() => cn('block w-16'), /* @ts-ignore */
1182
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1183
- railClasses = computed(() => cn('flex w-full list-none flex-col items-center gap-0.5 p-2',
1184
- // Mode drawer: rail tetap di atas backdrop (z-40) agar user bisa langsung
1185
- // berpindah group lain tanpa menutup drawer lebih dulu.
1186
- this.isDrawerMode() && this.openGroup() !== null && 'relative z-50'), /* @ts-ignore */
1187
- ...(ngDevMode ? [{ debugName: "railClasses" }] : /* istanbul ignore next */ []));
1188
- asideClasses = computed(() => cn('absolute inset-y-0 flex w-60 flex-col bg-background',
1189
- // Border only on the CONTENT-facing edge. The dockbar rail already draws the
1190
- // rail-facing separator, so a rail-facing border here would double up
1191
- // (right of the mini-dock + left of the aside).
1192
- this.position() === 'right'
1193
- ? 'right-16 border-l border-[hsl(var(--border)/var(--opacity-70))]'
1194
- : 'left-16 border-r border-[hsl(var(--border)/var(--opacity-70))]', this.isDrawerMode() && 'z-50 shadow-xl'), /* @ts-ignore */
1195
- ...(ngDevMode ? [{ debugName: "asideClasses" }] : /* istanbul ignore next */ []));
1196
- /**
1197
- * Offset backdrop agar kolom navigasi (rail + header/footer) benar-benar bebas
1198
- * overlay — dockbar dan aside drawer berada di level yang sama di atas backdrop.
1199
- * `null` berarti pengukuran tidak tersedia (mis. jsdom) dan backdrop jatuh ke
1200
- * `inset-0` penuh seperti sebelumnya.
1201
- */
1202
- backdropInset = signal({
1203
- left: null,
1204
- right: null,
1205
- }, /* @ts-ignore */
1206
- ...(ngDevMode ? [{ debugName: "backdropInset" }] : /* istanbul ignore next */ []));
1207
- onWindowResize() {
1208
- if (this.isDrawerMode() && this.openGroup() !== null) {
1209
- this.measureBackdropInset();
1210
- }
1211
- }
1212
- measureBackdropInset() {
1213
- const navEl = this.host.nativeElement.closest('[data-navigation-id]') ?? this.host.nativeElement;
1214
- const rect = navEl.getBoundingClientRect();
1215
- const viewportWidth = this.host.nativeElement.ownerDocument?.defaultView?.innerWidth ?? 0;
1216
- if (rect.width <= 0 || viewportWidth <= 0) {
1217
- this.backdropInset.set({ left: null, right: null });
1218
- return;
1219
- }
1220
- // Containing block backdrop `fixed` bisa bergeser dari viewport (ancestor dengan
1221
- // filter/contain). Koreksi origin dihitung dari posisi aktual backdrop terhadap
1222
- // style left/right yang sedang berlaku — konvergen dalam satu langkah re-measure.
1223
- const backdrop = this.host.nativeElement.querySelector('[data-navigation-dockbar-backdrop="true"]');
1224
- const backdropRect = backdrop?.getBoundingClientRect() ?? null;
1225
- let originLeft = 0;
1226
- let originRight = viewportWidth;
1227
- if (backdrop && backdropRect && backdropRect.width > 0) {
1228
- originLeft = backdropRect.left - this.parsePx(backdrop.style.left);
1229
- originRight = backdropRect.right + this.parsePx(backdrop.style.right);
1230
- }
1231
- if (this.position() === 'right') {
1232
- this.backdropInset.set({ left: null, right: Math.max(originRight - rect.left, 0) });
1233
- return;
1234
- }
1235
- this.backdropInset.set({ left: Math.max(rect.right - originLeft, 0), right: null });
1236
- }
1237
- parsePx(value) {
1238
- const parsed = Number.parseFloat(value);
1239
- return Number.isFinite(parsed) ? parsed : 0;
1240
- }
1241
- isGroupOpen(entry) {
1242
- return this.openGroup()?.key === entry.key;
1243
- }
1244
- isGroupActive(entry) {
1245
- return this.nav.isItemActive(entry, this.activeIds(), this.activeUrl());
1246
- }
1247
- triggerClasses(entry) {
1248
- return cn('nav-text group/nav inline-flex h-10 w-10 items-center justify-center rounded-md font-medium transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', this.isGroupOpen(entry)
1249
- ? 'bg-accent text-accent-foreground'
1250
- : this.isGroupActive(entry)
1251
- ? 'font-semibold text-foreground'
1252
- : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground', entry.classes?.wrapper, this.itemClass());
1253
- }
1254
- toggleGroup(entry) {
1255
- const wasOpen = this.isGroupOpen(entry);
1256
- if (!wasOpen && this.isDrawerMode()) {
1257
- this.measureBackdropInset();
1258
- }
1259
- this.nav.togglePanel(this.navId(), entry);
1260
- if (!this.isDrawerMode()) {
1261
- return;
1262
- }
1263
- if (wasOpen) {
1264
- this.afterRender(() => this.focusTrigger(entry.key));
1265
- return;
1266
- }
1267
- this.afterRender(() => {
1268
- // Ukur ulang setelah render: geometri kolom bisa bergeser saat panel terbuka.
1269
- this.measureBackdropInset();
1270
- this.focusFirstAsideItem();
1271
- });
1272
- }
1273
- closeAside() {
1274
- const openKey = this.openGroup()?.key ?? null;
1275
- this.nav.closePanel(this.navId());
1276
- if (openKey !== null) {
1277
- this.afterRender(() => this.focusTrigger(openKey));
1278
- }
1279
- }
1280
- onEscape(event) {
1281
- if (!this.isDrawerMode() || this.openGroup() === null) {
1282
- return;
1283
- }
1284
- event.preventDefault();
1285
- this.closeAside();
1286
- }
1287
- afterRender(callback) {
1288
- afterNextRender({ read: callback }, { injector: this.injector });
1289
- }
1290
- focusFirstAsideItem() {
1291
- const aside = this.host.nativeElement.querySelector(`#${this.asideId()}`);
1292
- const focusable = aside?.querySelector('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])');
1293
- focusable?.focus();
1294
- }
1295
- focusTrigger(key) {
1296
- const trigger = this.host.nativeElement.querySelector(`[data-navigation-dockbar-trigger="true"][data-navigation-item-key="${key}"]`);
1297
- trigger?.focus();
1298
- }
1299
- safeId(value) {
1300
- const normalized = value
1301
- .trim()
1302
- .toLowerCase()
1303
- .replace(/[^a-z0-9_-]+/g, '-');
1304
- return normalized || 'default';
1305
- }
1306
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationDockbarMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1307
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationDockbarMenuComponent, isStandalone: true, selector: "NavigationDockbarMenu", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { listeners: { "keydown.escape": "onEscape($event)", "window:resize": "onWindowResize()" }, properties: { "class": "hostClasses()", "attr.data-mode": "mode()", "attr.data-position": "position()" } }, ngImport: i0, template: `
1308
- <ul [class]="railClasses()" role="list">
1309
- @for (entry of items(); track entry.key) {
1310
- @if (entry.children.length > 0) {
1311
- <li class="flex w-full justify-center">
1312
- <button
1313
- type="button"
1314
- data-navigation-dockbar-trigger="true"
1315
- [class]="triggerClasses(entry)"
1316
- [attr.aria-expanded]="isGroupOpen(entry)"
1317
- [attr.aria-controls]="asideId()"
1318
- [attr.aria-label]="entry.tooltip ?? entry.title ?? null"
1319
- [attr.title]="entry.tooltip ?? entry.title ?? null"
1320
- [attr.data-navigation-item-key]="entry.key"
1321
- [disabled]="entry.disabled || null"
1322
- (click)="toggleGroup(entry)">
1323
- <NavigationItemContent
1324
- [item]="entry"
1325
- [active]="isGroupActive(entry)"
1326
- [compact]="true"
1327
- orientation="vertical"
1328
- [level]="0"
1329
- [collapseTree]="collapseTree()"
1330
- [iconTemplate]="iconTemplate()" />
1331
- </button>
1332
- </li>
1333
- } @else {
1334
- <li
1335
- NavigationItem
1336
- [navId]="navId()"
1337
- [item]="entry"
1338
- [level]="0"
1339
- orientation="vertical"
1340
- [compact]="true"
1341
- [itemClass]="itemClass()"
1342
- [activeIds]="activeIds()"
1343
- [activeUrl]="activeUrl()"
1344
- [iconTemplate]="iconTemplate()"
1345
- [collapseTree]="collapseTree()"
1346
- [openedIds]="openedIds()"
1347
- (openedIdsChange)="openedIdsChange.emit($event)"
1348
- (itemSelected)="itemSelected.emit($event)"></li>
1349
- }
1350
- }
1351
- </ul>
1352
-
1353
- @if (openGroup(); as group) {
1354
- @if (isDrawerMode()) {
1355
- <div
1356
- class="fixed inset-0 z-40 bg-[hsl(var(--overlay-backdrop-strong))]"
1357
- data-navigation-dockbar-backdrop="true"
1358
- aria-hidden="true"
1359
- [style.left.px]="backdropInset().left"
1360
- [style.right.px]="backdropInset().right"
1361
- (click)="closeAside()"></div>
1362
- }
1363
-
1364
- <!-- Drawer non-modal: rail tetap interaktif di atas backdrop, jadi tanpa aria-modal. -->
1365
- <aside
1366
- [id]="asideId()"
1367
- [class]="asideClasses()"
1368
- data-navigation-dockbar-aside="true"
1369
- [attr.role]="isDrawerMode() ? 'dialog' : null"
1370
- [attr.aria-labelledby]="asideHeadingId()">
1371
- <header
1372
- class="flex h-12 shrink-0 items-center gap-2 border-b border-[hsl(var(--border)/var(--opacity-70))] px-4">
1373
- <div class="min-w-0 flex-1">
1374
- <h2 [id]="asideHeadingId()" class="truncate text-sm font-semibold leading-tight text-foreground">
1375
- {{ group.title }}
1376
- </h2>
1377
- @if (group.subtitle) {
1378
- <p class="truncate text-xs leading-tight text-muted-foreground">{{ group.subtitle }}</p>
1379
- }
1380
- </div>
1381
-
1382
- @if (isDrawerMode()) {
1383
- <button
1384
- type="button"
1385
- class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-foreground/80 transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1386
- data-navigation-dockbar-close="true"
1387
- aria-label="Close navigation panel"
1388
- (click)="closeAside()">
1389
- <Icon name="close" [size]="16" />
1390
- </button>
1391
- }
1392
- </header>
1393
-
1394
- <div class="min-h-0 flex-1 overflow-y-auto px-2 py-3" data-navigation-dockbar-aside-scroll="true">
1395
- <NavigationList
1396
- [navId]="navId()"
1397
- [items]="group.children"
1398
- [collapsed]="false"
1399
- position="left"
1400
- [itemClass]="itemClass()"
1401
- [activeIds]="activeIds()"
1402
- [activeUrl]="activeUrl()"
1403
- [iconTemplate]="iconTemplate()"
1404
- [collapseTree]="collapseTree()"
1405
- [openedIds]="openedIds()"
1406
- (openedIdsChange)="openedIdsChange.emit($event)"
1407
- (itemSelected)="itemSelected.emit($event)" />
1408
- </div>
1409
- </aside>
1410
- }
1411
- `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationItemContentComponent, selector: "NavigationItemContent", inputs: ["item", "active", "compact", "orientation", "level", "collapseTree", "iconTemplate"] }, { kind: "component", type: NavigationListComponent, selector: "NavigationList", inputs: ["navId", "items", "collapsed", "compact", "position", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1412
- }
1413
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationDockbarMenuComponent, decorators: [{
1414
- type: Component,
1415
- args: [{
1416
- selector: 'NavigationDockbarMenu',
1417
- changeDetection: ChangeDetectionStrategy.OnPush,
1418
- imports: [IconComponent, NavigationItemComponent, NavigationItemContentComponent, NavigationListComponent],
1419
- host: {
1420
- '[class]': 'hostClasses()',
1421
- '[attr.data-mode]': 'mode()',
1422
- '[attr.data-position]': 'position()',
1423
- '(keydown.escape)': 'onEscape($event)',
1424
- '(window:resize)': 'onWindowResize()',
1425
- },
1426
- template: `
1427
- <ul [class]="railClasses()" role="list">
1428
- @for (entry of items(); track entry.key) {
1429
- @if (entry.children.length > 0) {
1430
- <li class="flex w-full justify-center">
1431
- <button
1432
- type="button"
1433
- data-navigation-dockbar-trigger="true"
1434
- [class]="triggerClasses(entry)"
1435
- [attr.aria-expanded]="isGroupOpen(entry)"
1436
- [attr.aria-controls]="asideId()"
1437
- [attr.aria-label]="entry.tooltip ?? entry.title ?? null"
1438
- [attr.title]="entry.tooltip ?? entry.title ?? null"
1439
- [attr.data-navigation-item-key]="entry.key"
1440
- [disabled]="entry.disabled || null"
1441
- (click)="toggleGroup(entry)">
1442
- <NavigationItemContent
1443
- [item]="entry"
1444
- [active]="isGroupActive(entry)"
1445
- [compact]="true"
1446
- orientation="vertical"
1447
- [level]="0"
1448
- [collapseTree]="collapseTree()"
1449
- [iconTemplate]="iconTemplate()" />
1450
- </button>
1451
- </li>
1452
- } @else {
1453
- <li
1454
- NavigationItem
1455
- [navId]="navId()"
1456
- [item]="entry"
1457
- [level]="0"
1458
- orientation="vertical"
1459
- [compact]="true"
1460
- [itemClass]="itemClass()"
1461
- [activeIds]="activeIds()"
1462
- [activeUrl]="activeUrl()"
1463
- [iconTemplate]="iconTemplate()"
1464
- [collapseTree]="collapseTree()"
1465
- [openedIds]="openedIds()"
1466
- (openedIdsChange)="openedIdsChange.emit($event)"
1467
- (itemSelected)="itemSelected.emit($event)"></li>
1468
- }
1469
- }
1470
- </ul>
1471
-
1472
- @if (openGroup(); as group) {
1473
- @if (isDrawerMode()) {
1474
- <div
1475
- class="fixed inset-0 z-40 bg-[hsl(var(--overlay-backdrop-strong))]"
1476
- data-navigation-dockbar-backdrop="true"
1477
- aria-hidden="true"
1478
- [style.left.px]="backdropInset().left"
1479
- [style.right.px]="backdropInset().right"
1480
- (click)="closeAside()"></div>
1481
- }
1482
-
1483
- <!-- Drawer non-modal: rail tetap interaktif di atas backdrop, jadi tanpa aria-modal. -->
1484
- <aside
1485
- [id]="asideId()"
1486
- [class]="asideClasses()"
1487
- data-navigation-dockbar-aside="true"
1488
- [attr.role]="isDrawerMode() ? 'dialog' : null"
1489
- [attr.aria-labelledby]="asideHeadingId()">
1490
- <header
1491
- class="flex h-12 shrink-0 items-center gap-2 border-b border-[hsl(var(--border)/var(--opacity-70))] px-4">
1492
- <div class="min-w-0 flex-1">
1493
- <h2 [id]="asideHeadingId()" class="truncate text-sm font-semibold leading-tight text-foreground">
1494
- {{ group.title }}
1495
- </h2>
1496
- @if (group.subtitle) {
1497
- <p class="truncate text-xs leading-tight text-muted-foreground">{{ group.subtitle }}</p>
1498
- }
1499
- </div>
1500
-
1501
- @if (isDrawerMode()) {
1502
- <button
1503
- type="button"
1504
- class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-foreground/80 transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1505
- data-navigation-dockbar-close="true"
1506
- aria-label="Close navigation panel"
1507
- (click)="closeAside()">
1508
- <Icon name="close" [size]="16" />
1509
- </button>
1510
- }
1511
- </header>
1512
-
1513
- <div class="min-h-0 flex-1 overflow-y-auto px-2 py-3" data-navigation-dockbar-aside-scroll="true">
1514
- <NavigationList
1515
- [navId]="navId()"
1516
- [items]="group.children"
1517
- [collapsed]="false"
1518
- position="left"
1519
- [itemClass]="itemClass()"
1520
- [activeIds]="activeIds()"
1521
- [activeUrl]="activeUrl()"
1522
- [iconTemplate]="iconTemplate()"
1523
- [collapseTree]="collapseTree()"
1524
- [openedIds]="openedIds()"
1525
- (openedIdsChange)="openedIdsChange.emit($event)"
1526
- (itemSelected)="itemSelected.emit($event)" />
1527
- </div>
1528
- </aside>
1529
- }
1530
- `,
1531
- }]
1532
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1533
-
1534
- /**
1535
- * Grid entry ala flyout: children sebuah branch dirender sebagai entry
1536
- * icon-box + title/subtitle dalam grid responsif (1/sm:2/md:3/lg:4, dibatasi
1537
- * `columns`); entry ber-children tampil terbuka secara default dengan collapse
1538
- * vertical yang icon-nya sejajar satu garis dengan icon induk. Dipakai oleh
1539
- * flyout dan panel mega navbar.
1540
- */
1541
- class NavigationEntryGridComponent {
1542
- nav = inject(NavigationService);
1543
- navId = input('default', /* @ts-ignore */
1544
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
1545
- branch = input.required(/* @ts-ignore */
1546
- ...(ngDevMode ? [{ debugName: "branch" }] : /* istanbul ignore next */ []));
1547
- typeStyle = input('flat', /* @ts-ignore */
1548
- ...(ngDevMode ? [{ debugName: "typeStyle" }] : /* istanbul ignore next */ []));
1549
- itemClass = input('', /* @ts-ignore */
1550
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
1551
- activeIds = input(new Set(), /* @ts-ignore */
1552
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
1553
- activeUrl = input(null, /* @ts-ignore */
1554
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
1555
- iconTemplate = input(undefined, /* @ts-ignore */
1556
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
1557
- collapseTree = input('stairs', /* @ts-ignore */
1558
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
1559
- openedIds = input([], /* @ts-ignore */
1560
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
1561
- openedIdsChange = output();
1562
- itemSelected = output();
1563
- isBorderRail = computed(() => this.typeStyle() === 'border-rail', /* @ts-ignore */
1564
- ...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
1565
- /** Kelas tambahan untuk NavigationItem bersarang saat style border-rail aktif. */
1566
- navItemClass = computed(() => cn(this.itemClass(), this.isBorderRail() && 'rounded-none hover:bg-transparent hover:text-primary'), /* @ts-ignore */
1567
- ...(ngDevMode ? [{ debugName: "navItemClass" }] : /* istanbul ignore next */ []));
1568
- /**
1569
- * Entry ber-children tampil TERBUKA secara default; set ini hanya menyimpan
1570
- * entry yang sengaja di-collapse pengguna. Instance grid dibuat ulang setiap
1571
- * panel dibuka sehingga state kembali terbuka semua.
1572
- */
1573
- collapsedEntryKeys = signal(new Set(), /* @ts-ignore */
1574
- ...(ngDevMode ? [{ debugName: "collapsedEntryKeys" }] : /* istanbul ignore next */ []));
1575
- isItemActive(item) {
1576
- return this.nav.isItemActive(item, this.activeIds(), this.activeUrl());
1577
- }
1578
- isEntryOpen(item) {
1579
- return !this.collapsedEntryKeys().has(item.stateId);
1580
- }
1581
- toggleEntry(item) {
1582
- if (item.disabled) {
1583
- return;
1584
- }
1585
- const next = new Set(this.collapsedEntryKeys());
1586
- if (next.has(item.stateId)) {
1587
- next.delete(item.stateId);
1588
- }
1589
- else {
1590
- next.add(item.stateId);
1591
- }
1592
- this.collapsedEntryKeys.set(next);
1593
- }
1594
- selectEntry(item, event) {
1595
- if (item.disabled) {
1596
- event.preventDefault();
1597
- event.stopPropagation();
1598
- return;
1599
- }
1600
- item.action?.(item.source);
1601
- this.itemSelected.emit({
1602
- item: item.source,
1603
- key: item.key,
1604
- type: item.type,
1605
- link: item.link,
1606
- external: !!this.nav.hrefFor(item),
1607
- });
1608
- this.nav.closePanel(this.navId());
1609
- this.nav.closeDrawer(this.navId());
1610
- }
1611
- isRouterItem(item) {
1612
- return this.nav.isRouterItem(item);
1613
- }
1614
- hrefFor(item) {
1615
- return this.nav.hrefFor(item);
1616
- }
1617
- relFor(item) {
1618
- return this.nav.relFor(item);
1619
- }
1620
- routerLinkActiveOptions(item) {
1621
- return this.nav.routerLinkActiveOptions(item);
1622
- }
1623
- iconContext(item, active) {
1624
- return this.nav.iconContext(item, active, 1, 'horizontal');
1625
- }
1626
- fallbackInitials(item) {
1627
- return this.nav.compactFallback(item);
1628
- }
1629
- contentGridClasses(branch) {
1630
- // Skala responsif: mobile 1, sm 2, md 3, lg ke atas 4; `columns` membatasi maksimumnya.
1631
- const columns = Math.min(Math.max(branch.columns ?? 4, 1), 4);
1632
- return cn('m-0 grid list-none grid-cols-1 gap-1 p-0', columns >= 2 && 'sm:grid-cols-2', columns >= 3 && 'md:grid-cols-3', columns >= 4 && 'lg:grid-cols-4');
1633
- }
1634
- entryClasses(item, active) {
1635
- return cn('group/nav nav-text flex w-full items-center gap-3 px-3 py-2.5 text-left transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', this.isBorderRail()
1636
- ? cn('rounded-none', active ? 'text-primary' : 'text-foreground hover:text-primary')
1637
- : cn('rounded-lg', active
1638
- ? 'bg-accent text-accent-foreground'
1639
- : 'text-foreground hover:bg-accent hover:text-accent-foreground'), item.disabled && 'pointer-events-none opacity-50', item.classes?.wrapper, this.itemClass());
1640
- }
1641
- entryIconClasses(active) {
1642
- if (this.isBorderRail()) {
1643
- // Kotak icon polos; bingkai digambar oleh rail line yang menjorok melewati sudut.
1644
- return cn('relative flex h-10 w-10 shrink-0 items-center justify-center self-center text-foreground transition-colors group-hover/nav:text-primary', active && 'text-primary');
1645
- }
1646
- return cn('relative flex h-10 w-10 shrink-0 items-center justify-center self-center rounded-lg border bg-background text-foreground shadow-sm transition-colors', active ? 'border-primary text-primary' : 'border-[hsl(var(--border)/var(--opacity-70))]');
1647
- }
1648
- entryIconGlyphClasses(item) {
1649
- return cn('text-current', item.classes?.icon);
1650
- }
1651
- entryTitleClasses(item, active) {
1652
- return cn('block truncate font-medium', this.isBorderRail() ? 'text-current' : 'text-foreground', active && 'font-semibold', item.classes?.title);
1653
- }
1654
- entrySubtitleClasses(item) {
1655
- return cn('mt-0.5 block truncate text-xs text-muted-foreground', item.classes?.subtitle);
1656
- }
1657
- entryChevronClasses(item) {
1658
- return cn('shrink-0 self-center text-muted-foreground transition-transform duration-200', this.isEntryOpen(item) && 'rotate-90');
1659
- }
1660
- nestedListClasses() {
1661
- // Children sejajar satu garis vertical dengan icon induk: rail digambar lewat pseudo-element
1662
- // di x = 32px (px-3 entry + setengah icon box w-10); pl-2.5 membuat icon child (px-3 + slot
1663
- // w-5) ber-center tepat di garis yang sama.
1664
- return cn("relative mt-1 flex list-none flex-col gap-0.5 p-0 pl-2.5 before:pointer-events-none before:absolute before:inset-y-0 before:left-8 before:w-0 before:border-l before:content-['']", this.isBorderRail()
1665
- ? 'before:border-dashed before:border-border/40'
1666
- : 'before:border-[hsl(var(--border)/var(--opacity-60))]');
1667
- }
1668
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationEntryGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1669
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationEntryGridComponent, isStandalone: true, selector: "NavigationEntryGrid", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, branch: { classPropertyName: "branch", publicName: "branch", isSignal: true, isRequired: true, transformFunction: null }, typeStyle: { classPropertyName: "typeStyle", publicName: "typeStyle", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { classAttribute: "contents" }, ngImport: i0, template: `
1670
- @let branchItem = branch();
1671
-
1672
- <div
1673
- role="group"
1674
- [id]="branchItem.panelId"
1675
- [attr.aria-label]="branchItem.title || null"
1676
- [attr.data-navigation-flyout-content]="branchItem.key"
1677
- class="p-2 md:p-3">
1678
- <ul role="none" [class]="contentGridClasses(branchItem)">
1679
- @for (child of branchItem.children; track child.key) {
1680
- @switch (child.type) {
1681
- @case ('divider') {
1682
- <li role="separator" class="col-span-full my-1 h-px bg-border"></li>
1683
- }
1684
- @case ('spacer') {}
1685
- @default {
1686
- @if (child.children.length > 0) {
1687
- <li role="none" class="min-w-0" [attr.data-navigation-item-key]="child.key">
1688
- <button
1689
- type="button"
1690
- role="menuitem"
1691
- data-navigation-flyout-entry="true"
1692
- [class]="entryClasses(child, isItemActive(child))"
1693
- [attr.aria-expanded]="isEntryOpen(child)"
1694
- [attr.aria-controls]="child.panelId"
1695
- [disabled]="child.disabled || null"
1696
- (click)="toggleEntry(child)">
1697
- <ng-container
1698
- [ngTemplateOutlet]="entryContent"
1699
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1700
- <Icon name="chevron_right" [size]="16" [class]="entryChevronClasses(child)" />
1701
- </button>
1702
-
1703
- @if (isEntryOpen(child)) {
1704
- <ul [id]="child.panelId" role="none" [class]="nestedListClasses()">
1705
- @for (nested of child.children; track nested.key) {
1706
- <li
1707
- NavigationItem
1708
- [navId]="navId()"
1709
- [item]="nested"
1710
- [level]="2"
1711
- [orientation]="'horizontal'"
1712
- [compact]="false"
1713
- [itemClass]="navItemClass()"
1714
- [activeIds]="activeIds()"
1715
- [activeUrl]="activeUrl()"
1716
- [iconTemplate]="iconTemplate()"
1717
- [collapseTree]="collapseTree()"
1718
- [openedIds]="openedIds()"
1719
- (openedIdsChange)="openedIdsChange.emit($event)"
1720
- (itemSelected)="itemSelected.emit($event)"></li>
1721
- }
1722
- </ul>
1723
- }
1724
- </li>
1725
- } @else {
1726
- <li role="none" class="min-w-0" [attr.data-navigation-item-key]="child.key">
1727
- @if (isRouterItem(child)) {
1728
- <a
1729
- role="menuitem"
1730
- data-navigation-flyout-entry="true"
1731
- [class]="entryClasses(child, routerActive.isActive || isItemActive(child))"
1732
- [routerLink]="child.link ?? null"
1733
- [queryParams]="child.queryParams ?? null"
1734
- [queryParamsHandling]="child.queryParamsHandling ?? null"
1735
- [fragment]="child.fragment ?? undefined"
1736
- [preserveFragment]="child.preserveFragment ?? false"
1737
- [target]="child.target ?? undefined"
1738
- routerLinkActive
1739
- #routerActive="routerLinkActive"
1740
- [routerLinkActiveOptions]="routerLinkActiveOptions(child)"
1741
- [attr.aria-current]="routerActive.isActive || isItemActive(child) ? 'page' : null"
1742
- [attr.aria-disabled]="child.disabled || null"
1743
- (click)="selectEntry(child, $event)">
1744
- <ng-container
1745
- [ngTemplateOutlet]="entryContent"
1746
- [ngTemplateOutletContext]="{
1747
- $implicit: child,
1748
- active: routerActive.isActive || isItemActive(child),
1749
- }" />
1750
- </a>
1751
- } @else if (hrefFor(child)) {
1752
- <a
1753
- role="menuitem"
1754
- data-navigation-flyout-entry="true"
1755
- [class]="entryClasses(child, isItemActive(child))"
1756
- [attr.href]="hrefFor(child)"
1757
- [attr.target]="child.target ?? (child.externalLink ? '_blank' : null)"
1758
- [attr.rel]="relFor(child)"
1759
- [attr.aria-current]="isItemActive(child) ? 'page' : null"
1760
- [attr.aria-disabled]="child.disabled || null"
1761
- (click)="selectEntry(child, $event)">
1762
- <ng-container
1763
- [ngTemplateOutlet]="entryContent"
1764
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1765
- </a>
1766
- } @else {
1767
- <button
1768
- type="button"
1769
- role="menuitem"
1770
- data-navigation-flyout-entry="true"
1771
- [class]="entryClasses(child, isItemActive(child))"
1772
- [disabled]="child.disabled || null"
1773
- [attr.aria-current]="isItemActive(child) ? 'page' : null"
1774
- (click)="selectEntry(child, $event)">
1775
- <ng-container
1776
- [ngTemplateOutlet]="entryContent"
1777
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1778
- </button>
1779
- }
1780
- </li>
1781
- }
1782
- }
1783
- }
1784
- }
1785
- </ul>
1786
- </div>
1787
-
1788
- <ng-template #entryContent let-child let-active="active">
1789
- <span [class]="entryIconClasses(active)">
1790
- @if (isBorderRail()) {
1791
- <span
1792
- aria-hidden="true"
1793
- data-navigation-icon-rail="top"
1794
- class="pointer-events-none absolute -inset-x-1.5 top-0 h-px bg-border/50"></span>
1795
- <span
1796
- aria-hidden="true"
1797
- data-navigation-icon-rail="bottom"
1798
- class="pointer-events-none absolute -inset-x-1.5 bottom-0 h-px bg-border/50"></span>
1799
- <span
1800
- aria-hidden="true"
1801
- data-navigation-icon-rail="left"
1802
- class="pointer-events-none absolute -inset-y-1.5 left-0 w-px bg-border/50"></span>
1803
- <span
1804
- aria-hidden="true"
1805
- data-navigation-icon-rail="right"
1806
- class="pointer-events-none absolute -inset-y-1.5 right-0 w-px bg-border/50"></span>
1807
- <span
1808
- aria-hidden="true"
1809
- data-navigation-icon-rail="center-horizontal"
1810
- class="pointer-events-none absolute -inset-x-1.5 top-1/2 border-t border-dashed border-border/40"></span>
1811
- <span
1812
- aria-hidden="true"
1813
- data-navigation-icon-rail="center-vertical"
1814
- class="pointer-events-none absolute -inset-y-1.5 left-1/2 border-l border-dashed border-border/40"></span>
1815
- }
1816
-
1817
- @if (child.icon) {
1818
- @if (iconTemplate(); as customIcon) {
1819
- <ng-container
1820
- [ngTemplateOutlet]="customIcon.template"
1821
- [ngTemplateOutletContext]="iconContext(child, active)" />
1822
- } @else {
1823
- <Icon [name]="child.icon" [size]="18" [class]="entryIconGlyphClasses(child)" />
1824
- }
1825
- } @else {
1826
- <span aria-hidden="true" class="text-xs font-semibold uppercase">{{ fallbackInitials(child) }}</span>
1827
- }
1828
- </span>
1829
-
1830
- <span class="min-w-0 flex-1">
1831
- <span [class]="entryTitleClasses(child, active)">{{ child.title }}</span>
1832
- @if (child.subtitle) {
1833
- <span [class]="entrySubtitleClasses(child)">{{ child.subtitle }}</span>
1834
- }
1835
- </span>
1836
-
1837
- @if (child.badge; as badge) {
1838
- <span
1839
- [class]="
1840
- badge.classes ??
1841
- 'nav-badge inline-flex h-5 shrink-0 items-center self-center rounded-full bg-muted px-2 text-muted-foreground'
1842
- "
1843
- >{{ badge.title }}</span
1844
- >
1845
- }
1846
- </ng-template>
1847
- `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1848
- }
1849
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationEntryGridComponent, decorators: [{
1850
- type: Component,
1851
- args: [{
1852
- selector: 'NavigationEntryGrid',
1853
- changeDetection: ChangeDetectionStrategy.OnPush,
1854
- imports: [NgTemplateOutlet, RouterLink, RouterLinkActive, IconComponent, NavigationItemComponent],
1855
- host: {
1856
- class: 'contents',
1857
- },
1858
- template: `
1859
- @let branchItem = branch();
1860
-
1861
- <div
1862
- role="group"
1863
- [id]="branchItem.panelId"
1864
- [attr.aria-label]="branchItem.title || null"
1865
- [attr.data-navigation-flyout-content]="branchItem.key"
1866
- class="p-2 md:p-3">
1867
- <ul role="none" [class]="contentGridClasses(branchItem)">
1868
- @for (child of branchItem.children; track child.key) {
1869
- @switch (child.type) {
1870
- @case ('divider') {
1871
- <li role="separator" class="col-span-full my-1 h-px bg-border"></li>
1872
- }
1873
- @case ('spacer') {}
1874
- @default {
1875
- @if (child.children.length > 0) {
1876
- <li role="none" class="min-w-0" [attr.data-navigation-item-key]="child.key">
1877
- <button
1878
- type="button"
1879
- role="menuitem"
1880
- data-navigation-flyout-entry="true"
1881
- [class]="entryClasses(child, isItemActive(child))"
1882
- [attr.aria-expanded]="isEntryOpen(child)"
1883
- [attr.aria-controls]="child.panelId"
1884
- [disabled]="child.disabled || null"
1885
- (click)="toggleEntry(child)">
1886
- <ng-container
1887
- [ngTemplateOutlet]="entryContent"
1888
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1889
- <Icon name="chevron_right" [size]="16" [class]="entryChevronClasses(child)" />
1890
- </button>
1891
-
1892
- @if (isEntryOpen(child)) {
1893
- <ul [id]="child.panelId" role="none" [class]="nestedListClasses()">
1894
- @for (nested of child.children; track nested.key) {
1895
- <li
1896
- NavigationItem
1897
- [navId]="navId()"
1898
- [item]="nested"
1899
- [level]="2"
1900
- [orientation]="'horizontal'"
1901
- [compact]="false"
1902
- [itemClass]="navItemClass()"
1903
- [activeIds]="activeIds()"
1904
- [activeUrl]="activeUrl()"
1905
- [iconTemplate]="iconTemplate()"
1906
- [collapseTree]="collapseTree()"
1907
- [openedIds]="openedIds()"
1908
- (openedIdsChange)="openedIdsChange.emit($event)"
1909
- (itemSelected)="itemSelected.emit($event)"></li>
1910
- }
1911
- </ul>
1912
- }
1913
- </li>
1914
- } @else {
1915
- <li role="none" class="min-w-0" [attr.data-navigation-item-key]="child.key">
1916
- @if (isRouterItem(child)) {
1917
- <a
1918
- role="menuitem"
1919
- data-navigation-flyout-entry="true"
1920
- [class]="entryClasses(child, routerActive.isActive || isItemActive(child))"
1921
- [routerLink]="child.link ?? null"
1922
- [queryParams]="child.queryParams ?? null"
1923
- [queryParamsHandling]="child.queryParamsHandling ?? null"
1924
- [fragment]="child.fragment ?? undefined"
1925
- [preserveFragment]="child.preserveFragment ?? false"
1926
- [target]="child.target ?? undefined"
1927
- routerLinkActive
1928
- #routerActive="routerLinkActive"
1929
- [routerLinkActiveOptions]="routerLinkActiveOptions(child)"
1930
- [attr.aria-current]="routerActive.isActive || isItemActive(child) ? 'page' : null"
1931
- [attr.aria-disabled]="child.disabled || null"
1932
- (click)="selectEntry(child, $event)">
1933
- <ng-container
1934
- [ngTemplateOutlet]="entryContent"
1935
- [ngTemplateOutletContext]="{
1936
- $implicit: child,
1937
- active: routerActive.isActive || isItemActive(child),
1938
- }" />
1939
- </a>
1940
- } @else if (hrefFor(child)) {
1941
- <a
1942
- role="menuitem"
1943
- data-navigation-flyout-entry="true"
1944
- [class]="entryClasses(child, isItemActive(child))"
1945
- [attr.href]="hrefFor(child)"
1946
- [attr.target]="child.target ?? (child.externalLink ? '_blank' : null)"
1947
- [attr.rel]="relFor(child)"
1948
- [attr.aria-current]="isItemActive(child) ? 'page' : null"
1949
- [attr.aria-disabled]="child.disabled || null"
1950
- (click)="selectEntry(child, $event)">
1951
- <ng-container
1952
- [ngTemplateOutlet]="entryContent"
1953
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1954
- </a>
1955
- } @else {
1956
- <button
1957
- type="button"
1958
- role="menuitem"
1959
- data-navigation-flyout-entry="true"
1960
- [class]="entryClasses(child, isItemActive(child))"
1961
- [disabled]="child.disabled || null"
1962
- [attr.aria-current]="isItemActive(child) ? 'page' : null"
1963
- (click)="selectEntry(child, $event)">
1964
- <ng-container
1965
- [ngTemplateOutlet]="entryContent"
1966
- [ngTemplateOutletContext]="{ $implicit: child, active: isItemActive(child) }" />
1967
- </button>
1968
- }
1969
- </li>
1970
- }
1971
- }
1972
- }
1973
- }
1974
- </ul>
1975
- </div>
1976
-
1977
- <ng-template #entryContent let-child let-active="active">
1978
- <span [class]="entryIconClasses(active)">
1979
- @if (isBorderRail()) {
1980
- <span
1981
- aria-hidden="true"
1982
- data-navigation-icon-rail="top"
1983
- class="pointer-events-none absolute -inset-x-1.5 top-0 h-px bg-border/50"></span>
1984
- <span
1985
- aria-hidden="true"
1986
- data-navigation-icon-rail="bottom"
1987
- class="pointer-events-none absolute -inset-x-1.5 bottom-0 h-px bg-border/50"></span>
1988
- <span
1989
- aria-hidden="true"
1990
- data-navigation-icon-rail="left"
1991
- class="pointer-events-none absolute -inset-y-1.5 left-0 w-px bg-border/50"></span>
1992
- <span
1993
- aria-hidden="true"
1994
- data-navigation-icon-rail="right"
1995
- class="pointer-events-none absolute -inset-y-1.5 right-0 w-px bg-border/50"></span>
1996
- <span
1997
- aria-hidden="true"
1998
- data-navigation-icon-rail="center-horizontal"
1999
- class="pointer-events-none absolute -inset-x-1.5 top-1/2 border-t border-dashed border-border/40"></span>
2000
- <span
2001
- aria-hidden="true"
2002
- data-navigation-icon-rail="center-vertical"
2003
- class="pointer-events-none absolute -inset-y-1.5 left-1/2 border-l border-dashed border-border/40"></span>
2004
- }
2005
-
2006
- @if (child.icon) {
2007
- @if (iconTemplate(); as customIcon) {
2008
- <ng-container
2009
- [ngTemplateOutlet]="customIcon.template"
2010
- [ngTemplateOutletContext]="iconContext(child, active)" />
2011
- } @else {
2012
- <Icon [name]="child.icon" [size]="18" [class]="entryIconGlyphClasses(child)" />
2013
- }
2014
- } @else {
2015
- <span aria-hidden="true" class="text-xs font-semibold uppercase">{{ fallbackInitials(child) }}</span>
2016
- }
2017
- </span>
2018
-
2019
- <span class="min-w-0 flex-1">
2020
- <span [class]="entryTitleClasses(child, active)">{{ child.title }}</span>
2021
- @if (child.subtitle) {
2022
- <span [class]="entrySubtitleClasses(child)">{{ child.subtitle }}</span>
2023
- }
2024
- </span>
2025
-
2026
- @if (child.badge; as badge) {
2027
- <span
2028
- [class]="
2029
- badge.classes ??
2030
- 'nav-badge inline-flex h-5 shrink-0 items-center self-center rounded-full bg-muted px-2 text-muted-foreground'
2031
- "
2032
- >{{ badge.title }}</span
2033
- >
2034
- }
2035
- </ng-template>
2036
- `,
2037
- }]
2038
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], branch: [{ type: i0.Input, args: [{ isSignal: true, alias: "branch", required: true }] }], typeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeStyle", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
2039
-
2040
- class NavigationFlyoutMenuComponent {
2041
- nav = inject(NavigationService);
2042
- host = inject(ElementRef);
2043
- navId = input('default', /* @ts-ignore */
2044
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
2045
- items = input([], /* @ts-ignore */
2046
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
2047
- label = input('Menu', /* @ts-ignore */
2048
- ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2049
- /** Nama Material Symbols untuk trigger; `null` = label saja (mode normal). */
2050
- icon = input(null, /* @ts-ignore */
2051
- ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
2052
- /** Trigger hanya ikon — label tetap diumumkan via aria-label/title. */
2053
- iconOnly = input(false, /* @ts-ignore */
2054
- ...(ngDevMode ? [{ debugName: "iconOnly" }] : /* istanbul ignore next */ []));
2055
- /** Penempatan ikon relatif label: `start` (default) atau `end`. */
2056
- iconPosition = input('start', /* @ts-ignore */
2057
- ...(ngDevMode ? [{ debugName: "iconPosition" }] : /* istanbul ignore next */ []));
2058
- /** Bentuk visual tombol trigger: `button` (pil) | `link` | `plain` (ghost). */
2059
- variant = input('button', /* @ts-ignore */
2060
- ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2061
- /** Trigger mengambang (`fixed`) — host menjadi popover lepas, panel menempel ke trigger. */
2062
- floating = input(false, /* @ts-ignore */
2063
- ...(ngDevMode ? [{ debugName: "floating" }] : /* istanbul ignore next */ []));
2064
- /** Kelas Tailwind untuk host trigger (posisi pojok floating / styling wrapper in-flow). */
2065
- triggerClass = input('', /* @ts-ignore */
2066
- ...(ngDevMode ? [{ debugName: "triggerClass" }] : /* istanbul ignore next */ []));
2067
- /** `bottom` = bar berada di bawah konten; panel menempel sisi bawah container dan tumbuh ke atas. */
2068
- position = input('top', /* @ts-ignore */
2069
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
2070
- typeStyle = input('flat', /* @ts-ignore */
2071
- ...(ngDevMode ? [{ debugName: "typeStyle" }] : /* istanbul ignore next */ []));
2072
- compact = input(false, /* @ts-ignore */
2073
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
2074
- itemClass = input('', /* @ts-ignore */
2075
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
2076
- /** Kelas Tailwind untuk container `<li>` tiap tab group (mengatur tinggi/border/padding container). */
2077
- groupClass = input('', /* @ts-ignore */
2078
- ...(ngDevMode ? [{ debugName: "groupClass" }] : /* istanbul ignore next */ []));
2079
- activeIds = input(new Set(), /* @ts-ignore */
2080
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
2081
- activeUrl = input(null, /* @ts-ignore */
2082
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
2083
- iconTemplate = input(undefined, /* @ts-ignore */
2084
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
2085
- collapseTree = input('stairs', /* @ts-ignore */
2086
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
2087
- openedIds = input([], /* @ts-ignore */
2088
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
2089
- openedIdsChange = output();
2090
- itemSelected = output();
2091
- panelId = computed(() => `nav-flyout-${this.navId()}`, /* @ts-ignore */
2092
- ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
2093
- isBorderRail = computed(() => this.typeStyle() === 'border-rail', /* @ts-ignore */
2094
- ...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
2095
- isBottom = computed(() => this.position() === 'bottom', /* @ts-ignore */
2096
- ...(ngDevMode ? [{ debugName: "isBottom" }] : /* istanbul ignore next */ []));
2097
- /** Compact (mobile) selalu icon-only; selain itu mengikuti input `iconOnly`. */
2098
- showIconOnly = computed(() => this.compact() || this.iconOnly(), /* @ts-ignore */
2099
- ...(ngDevMode ? [{ debugName: "showIconOnly" }] : /* istanbul ignore next */ []));
2100
- triggerIcon = computed(() => this.icon() ?? (this.showIconOnly() ? 'menu' : null), /* @ts-ignore */
2101
- ...(ngDevMode ? [{ debugName: "triggerIcon" }] : /* istanbul ignore next */ []));
2102
- /** Kelas tambahan untuk NavigationItem di dalam flyout saat style border-rail aktif. */
2103
- navItemClass = computed(() =>
2104
- // h-8 menjaga leaf di row tetap muat dalam tinggi 48px (py-2 + 32px) agar
2105
- // border bawah row tidak terdorong melewati posisi rail layout.
2106
- cn(this.itemClass(), this.isBorderRail() && 'h-8 rounded-none hover:bg-transparent hover:text-primary'), /* @ts-ignore */
2107
- ...(ngDevMode ? [{ debugName: "navItemClass" }] : /* istanbul ignore next */ []));
2108
- branches = computed(() => this.items().filter((item) => item.children.length > 0), /* @ts-ignore */
2109
- ...(ngDevMode ? [{ debugName: "branches" }] : /* istanbul ignore next */ []));
2110
- activeBranch = computed(() => {
2111
- const key = this.nav.currentPanelKey(this.navId());
2112
- return this.branches().find((branch) => branch.key === key) ?? null;
2113
- }, /* @ts-ignore */
2114
- ...(ngDevMode ? [{ debugName: "activeBranch" }] : /* istanbul ignore next */ []));
2115
- /**
2116
- * Floating: sisi popover relatif trigger — `true` = rata kanan (buka ke kiri, untuk trigger di
2117
- * pojok kanan), `false` = rata kiri (buka ke kanan). Diukur dari posisi trigger saat dibuka.
2118
- */
2119
- floatingAlignEnd = signal(true, /* @ts-ignore */
2120
- ...(ngDevMode ? [{ debugName: "floatingAlignEnd" }] : /* istanbul ignore next */ []));
2121
- /**
2122
- * Offset panel terhadap host agar panel menimpa penuh container parent dari
2123
- * `Navigation` (lebar sama persis; posisi atas di mode top, posisi bawah di
2124
- * mode bottom). `null` berarti pengukuran tidak tersedia (mis. SSR/jsdom)
2125
- * dan panel jatuh ke lebar host sendiri.
2126
- */
2127
- panelPlacement = signal(null, /* @ts-ignore */
2128
- ...(ngDevMode ? [{ debugName: "panelPlacement" }] : /* istanbul ignore next */ []));
2129
- panelWrapperClasses = computed(() => {
2130
- if (this.floating()) {
2131
- // Floating: popover menempel ke trigger — atas/bawah ikut nav-position; sisi kiri/kanan
2132
- // ikut posisi trigger (floatingAlignEnd) agar tidak keluar layar saat trigger di pojok kiri.
2133
- return cn('absolute z-50 w-[min(22rem,85vw)] max-w-[85vw]', this.floatingAlignEnd() ? 'right-0' : 'left-0', this.isBottom() ? 'bottom-full mb-2' : 'top-full mt-2');
2134
- }
2135
- // Default: panel menutupi (overlay) container bar persis — posisi & lebar ikut container.
2136
- return cn('absolute z-50', !this.panelPlacement() && cn('inset-x-0', this.isBottom() ? 'bottom-0' : 'top-0'));
2137
- }, /* @ts-ignore */
2138
- ...(ngDevMode ? [{ debugName: "panelWrapperClasses" }] : /* istanbul ignore next */ []));
2139
- /**
2140
- * Mode bottom membalik urutan visual: grid entri di atas, bar di bawah (dekat bar trigger).
2141
- * `min-h-0 flex-1` membuat menu mengisi penuh panel card (yang di-clip) sehingga ROW 2
2142
- * bisa jadi satu-satunya area scroll.
2143
- */
2144
- menuClasses = computed(() => cn('flex min-h-0 flex-1', this.isBottom() ? 'flex-col-reverse' : 'flex-col'), /* @ts-ignore */
2145
- ...(ngDevMode ? [{ debugName: "menuClasses" }] : /* istanbul ignore next */ []));
2146
- /**
2147
- * ROW 1 = bar flyout: satu baris horizontal seperti bar navbar —
2148
- * Header (kiri) · menu item (tengah, flex-1) · Footer (kanan). `shrink-0` membuatnya DIAM
2149
- * (tidak ikut scroll) — hanya ROW 2 (grid child) yang punya area scroll sendiri.
2150
- * Border memisahkan bar dari ROW 2 di sisi yang menjauh dari bar (bawah di mode top).
2151
- */
2152
- barRowClasses = computed(() => cn('flex shrink-0 items-center gap-2 bg-popover px-2 md:px-3', this.isBorderRail()
2153
- ? cn('min-h-12 border-border', this.isBottom() ? 'border-t-[1.5px]' : 'border-b-[1.5px]')
2154
- : cn('min-h-[3.25rem] border-[hsl(var(--border)/var(--opacity-60))]', this.isBottom() ? 'border-t' : 'border-b')), /* @ts-ignore */
2155
- ...(ngDevMode ? [{ debugName: "barRowClasses" }] : /* istanbul ignore next */ []));
2156
- /**
2157
- * ROW 2 = HANYA area ini yang scroll: children dari nav item aktif. `min-h-0 flex-1`
2158
- * membatasi tingginya ke sisa ruang panel lalu `overflow-y-auto` men-scroll isinya —
2159
- * bar ROW 1 & kontainer panel sendiri tetap diam.
2160
- */
2161
- scrollRegionClasses = computed(() => cn('min-h-0 flex-1 overflow-x-hidden overflow-y-auto overscroll-contain'), /* @ts-ignore */
2162
- ...(ngDevMode ? [{ debugName: "scrollRegionClasses" }] : /* istanbul ignore next */ []));
2163
- isOpen() {
2164
- return this.nav.isDrawerOpen(this.navId());
2165
- }
2166
- onWindowResize() {
2167
- if (this.isOpen()) {
2168
- this.measurePanelPlacement();
2169
- }
2170
- }
2171
- measurePanelPlacement() {
2172
- // Floating: panel anchored ke trigger via CSS, bukan overlay container. Pilih sisi popover
2173
- // (kanan→buka kiri / kiri→buka kanan) dari posisi trigger agar tidak keluar layar.
2174
- if (this.floating()) {
2175
- const triggerEl = this.host.nativeElement.querySelector('[data-navigation-flyout-trigger="true"]');
2176
- const rect = triggerEl?.getBoundingClientRect();
2177
- if (rect && typeof window !== 'undefined' && window.innerWidth > 0) {
2178
- this.floatingAlignEnd.set(rect.left + rect.width / 2 > window.innerWidth / 2);
2179
- }
2180
- this.panelPlacement.set(null);
2181
- return;
2182
- }
2183
- const hostEl = this.host.nativeElement;
2184
- const navEl = hostEl.closest('[data-navigation-id]');
2185
- let container = navEl?.parentElement ?? hostEl.parentElement;
2186
- // Wrapper display:contents punya rect kosong — naik terus sampai container yang punya box visual.
2187
- while (container && container.getBoundingClientRect().width <= 0 && container.parentElement) {
2188
- container = container.parentElement;
2189
- }
2190
- const containerRect = (container ?? hostEl).getBoundingClientRect();
2191
- const hostRect = hostEl.getBoundingClientRect();
2192
- if (containerRect.width <= 0) {
2193
- this.panelPlacement.set(null);
2194
- return;
2195
- }
2196
- this.panelPlacement.set({
2197
- left: containerRect.left - hostRect.left,
2198
- top: containerRect.top - hostRect.top,
2199
- bottom: hostRect.bottom - containerRect.bottom,
2200
- width: containerRect.width,
2201
- });
2202
- }
2203
- toggleFlyout() {
2204
- if (this.isOpen()) {
2205
- this.closeFlyout(false);
2206
- return;
2207
- }
2208
- this.measurePanelPlacement();
2209
- this.nav.openDrawer(this.navId());
2210
- const current = this.nav.currentPanelKey(this.navId());
2211
- const branches = this.branches();
2212
- if (!branches.some((branch) => branch.key === current)) {
2213
- const first = branches.find((branch) => !branch.disabled) ?? branches[0];
2214
- if (first) {
2215
- this.nav.openPanel(this.navId(), first);
2216
- }
2217
- }
2218
- queueMicrotask(() => this.focusFirstPanelItem());
2219
- }
2220
- closeFlyout(restoreFocus) {
2221
- this.nav.closeDrawer(this.navId());
2222
- if (restoreFocus) {
2223
- queueMicrotask(() => this.focusTrigger());
2224
- }
2225
- }
2226
- onEscape(event) {
2227
- if (!this.isOpen()) {
2228
- return;
2229
- }
2230
- event.preventDefault();
2231
- this.closeFlyout(true);
2232
- }
2233
- onDocumentClick(event) {
2234
- if (!this.isOpen()) {
2235
- return;
2236
- }
2237
- const target = event.target;
2238
- if (target && !this.host.nativeElement.contains(target)) {
2239
- this.closeFlyout(false);
2240
- }
2241
- }
2242
- isItemActive(item) {
2243
- return this.nav.isItemActive(item, this.activeIds(), this.activeUrl());
2244
- }
2245
- isBranchOpen(item) {
2246
- return this.nav.isPanelOpen(this.navId(), item);
2247
- }
2248
- openBranch(item) {
2249
- this.nav.openPanel(this.navId(), item);
2250
- }
2251
- /**
2252
- * Host trigger+panel. Default `relative block w-full` (mengalir di dalam bar/div). Saat
2253
- * `floating`, jadi `fixed` (mengambang) — default pojok kanan-atas, override via `triggerClass`.
2254
- */
2255
- hostClasses = computed(() => this.floating()
2256
- ? cn('fixed z-50 block w-max', this.triggerClass() || 'right-6 top-6')
2257
- : cn('relative block w-full', this.triggerClass()), /* @ts-ignore */
2258
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2259
- /** Bentuk visual trigger: `button` (pil), `link` (tautan), atau `plain` (ghost); + ikon/teks. */
2260
- triggerClasses() {
2261
- const iconOnly = this.showIconOnly();
2262
- const base = 'nav-trigger group/nav inline-flex min-w-0 items-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring';
2263
- if (this.variant() === 'link') {
2264
- return cn(base, 'nav-text underline-offset-4 hover:underline',
2265
- // Icon-only tetap punya target ≥ 36px (WCAG 2.5.8) walau tanpa chrome tautan.
2266
- iconOnly ? 'h-9 w-9 justify-center gap-0' : 'gap-1.5', this.isOpen() ? 'text-primary underline' : 'text-primary/90 hover:text-primary', this.itemClass());
2267
- }
2268
- if (this.variant() === 'plain') {
2269
- return cn(base, 'gap-2 rounded-md nav-text', iconOnly ? 'h-9 w-9 justify-center' : 'h-9 px-3 py-2', this.isOpen()
2270
- ? 'bg-accent text-accent-foreground'
2271
- : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground', this.itemClass());
2272
- }
2273
- // button (pil, default)
2274
- return cn(base, 'h-10 gap-2 rounded-full border border-[hsl(var(--border)/var(--opacity-60))] bg-background px-4 py-2 nav-text shadow-sm', iconOnly && 'w-10 justify-center gap-0 px-0', this.isBorderRail()
2275
- ? this.isOpen()
2276
- ? 'text-primary'
2277
- : 'text-foreground/80 hover:text-primary'
2278
- : this.isOpen()
2279
- ? 'bg-accent text-accent-foreground'
2280
- : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground', this.itemClass());
2281
- }
2282
- panelCardClasses() {
2283
- if (this.floating()) {
2284
- // Floating: kartu popover mandiri (rounded penuh + border + shadow), tinggi dibatasi & di-clip;
2285
- // hanya ROW 2 (children) yang scroll.
2286
- return cn('relative flex flex-col rounded-xl border border-[hsl(var(--border)/var(--opacity-70))] bg-popover text-popover-foreground shadow-2xl', 'max-h-[min(28rem,70vh)] overflow-hidden');
2287
- }
2288
- // Border-rail: panel menutup tepat content-box frame layout, jadi garis
2289
- // sisi bar memakai border frame (rail) itu sendiri — panel cukup menggambar
2290
- // border 1.5px senada rail pada sisi yang menjauh dari bar agar sambungan
2291
- // tetap lurus (bawah di mode top, atas di mode bottom).
2292
- return cn('relative flex flex-col bg-popover text-popover-foreground shadow-2xl',
2293
- // Batasi tinggi panel ke viewport lalu CLIP — bukan scroll. Hanya ROW 2 (children, lihat
2294
- // scrollRegionClasses) yang scroll; bar ROW 1 & kontainer panel sendiri tetap diam.
2295
- 'max-h-[calc(100dvh-5rem)] overflow-hidden', this.isBorderRail()
2296
- ? cn('rounded-none border-border', this.isBottom() ? 'border-t-[1.5px]' : 'border-b-[1.5px]')
2297
- : 'rounded-[var(--layout-frame-radius)] border border-[hsl(var(--border)/var(--opacity-70))]');
2298
- }
2299
- rowClasses() {
2300
- // Menu item = bagian tengah ROW 1: isi ruang antara Footer & Header (flex-1) lalu
2301
- // di-center seperti menubar navbar. Saat jumlah/lebar item melebihi band, band ini
2302
- // scroll horizontal (overflow-x-auto) agar tidak ada item ter-clip & takterjangkau
2303
- // (panel card meng-clip overflow-x). Tinggi & border bar ditangani barRowClasses().
2304
- return cn('m-0 flex min-w-0 flex-1 list-none items-center justify-center gap-1 overflow-x-auto overscroll-x-contain py-2');
2305
- }
2306
- /**
2307
- * Container `<li>` tab group. Basis `flex -my-2 self-stretch` membuat tab setinggi
2308
- * penuh row (lihat tabClasses); consumer dapat menimpa/menambah lewat `nav-group-class`
2309
- * (global) atau `item.classes.container` (per-group) untuk fleksibilitas.
2310
- */
2311
- groupContainerClasses(item) {
2312
- return cn('flex -my-2 self-stretch', this.groupClass(), item.classes?.container);
2313
- }
2314
- tabClasses(item) {
2315
- return cn(
2316
- // Tinggi tab group mengikuti tinggi penuh row (parent). Wrapper <li> memakai
2317
- // `-my-2 self-stretch` untuk membatalkan `py-2` row; tombol `h-full` mengisi penuh
2318
- // sehingga sisinya rata dengan border row — sudut pada sisi border dibuat siku
2319
- // agar menyambung (bawah di mode top, atas di mode bottom).
2320
- 'nav-trigger nav-text group/nav inline-flex h-full min-h-9 min-w-0 items-center gap-2 rounded-md px-3 font-medium transition-colors', this.isBottom() ? 'rounded-t-none' : 'rounded-b-none', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', this.isBorderRail()
2321
- ? this.isBranchOpen(item) || this.isItemActive(item)
2322
- ? 'rounded-none text-primary'
2323
- : 'rounded-none text-foreground/80 hover:text-primary'
2324
- : this.isBranchOpen(item)
2325
- ? 'bg-accent text-accent-foreground'
2326
- : this.isItemActive(item)
2327
- ? 'font-semibold text-foreground hover:bg-accent hover:text-accent-foreground'
2328
- : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground', item.classes?.wrapper, this.itemClass());
2329
- }
2330
- tabChevronClasses(item) {
2331
- return cn('shrink-0 self-center text-current transition-transform duration-200', this.isBranchOpen(item) && 'rotate-90');
2332
- }
2333
- onRowKeydown(event) {
2334
- if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft' && event.key !== 'ArrowDown') {
2335
- return;
2336
- }
2337
- const rowItems = Array.from(this.host.nativeElement.querySelectorAll('[data-navigation-flyout-row="true"] [role="menuitem"]'));
2338
- const currentIndex = rowItems.indexOf(document.activeElement);
2339
- if (currentIndex === -1) {
2340
- return;
2341
- }
2342
- event.preventDefault();
2343
- if (event.key === 'ArrowDown') {
2344
- const entry = this.host.nativeElement.querySelector('[data-navigation-flyout-content] [role="menuitem"]');
2345
- entry?.focus();
2346
- return;
2347
- }
2348
- const direction = event.key === 'ArrowRight' ? 1 : -1;
2349
- rowItems[(currentIndex + direction + rowItems.length) % rowItems.length]?.focus();
2350
- }
2351
- focusFirstPanelItem() {
2352
- const panel = this.host.nativeElement.querySelector('[data-navigation-flyout-panel="true"]');
2353
- if (!panel) {
2354
- return;
2355
- }
2356
- // Fokus awal ke menu item ROW 1 (lalu grid ROW 2) — BUKAN kontrol Header/Footer yang
2357
- // juga ada di bar (mis. tombol logout). querySelector mengembalikan match pertama dalam
2358
- // urutan DOM, dan Header/Footer bisa mendahului menu, jadi lingkup ke baris menu dulu.
2359
- const target = panel.querySelector('[data-navigation-flyout-row="true"] [role="menuitem"], [data-navigation-flyout-row="true"] a[href]') ?? panel.querySelector('[role="menuitem"], a[href]');
2360
- target?.focus();
2361
- }
2362
- focusTrigger() {
2363
- this.host.nativeElement
2364
- .querySelector('[data-navigation-flyout-trigger="true"]')
2365
- ?.focus();
2366
- }
2367
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFlyoutMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2368
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationFlyoutMenuComponent, isStandalone: true, selector: "NavigationFlyoutMenu", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "iconPosition", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, floating: { classPropertyName: "floating", publicName: "floating", isSignal: true, isRequired: false, transformFunction: null }, triggerClass: { classPropertyName: "triggerClass", publicName: "triggerClass", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, typeStyle: { classPropertyName: "typeStyle", publicName: "typeStyle", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { listeners: { "keydown.escape": "onEscape($event)", "document:click": "onDocumentClick($event)", "window:resize": "onWindowResize()" }, properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
2369
- <button
2370
- type="button"
2371
- data-navigation-flyout-trigger="true"
2372
- [class]="triggerClasses()"
2373
- aria-haspopup="menu"
2374
- [attr.aria-expanded]="isOpen()"
2375
- [attr.aria-controls]="isOpen() ? panelId() : null"
2376
- [attr.aria-label]="showIconOnly() ? label() : null"
2377
- [attr.title]="showIconOnly() ? label() : null"
2378
- (click)="toggleFlyout()"
2379
- >
2380
- @if (showIconOnly()) {
2381
- <Icon [name]="triggerIcon() ?? 'menu'" [size]="18" class="text-current" />
2382
- } @else {
2383
- @if (iconPosition() === 'start' && triggerIcon(); as iconName) {
2384
- <Icon [name]="iconName" [size]="18" class="shrink-0 text-current" />
2385
- }
2386
-
2387
- <span class="truncate">{{ label() }}</span>
2388
-
2389
- @if (iconPosition() === 'end' && triggerIcon(); as iconName) {
2390
- <Icon [name]="iconName" [size]="18" class="shrink-0 text-current" />
2391
- }
2392
- }
2393
- </button>
2394
-
2395
- @if (isOpen()) {
2396
- <div
2397
- [id]="panelId()"
2398
- data-navigation-flyout-panel="true"
2399
- [class]="panelWrapperClasses()"
2400
- [style.left.px]="floating() ? null : panelPlacement()?.left"
2401
- [style.top.px]="floating() || isBottom() ? null : panelPlacement()?.top"
2402
- [style.bottom.px]="!floating() && isBottom() ? panelPlacement()?.bottom : null"
2403
- [style.width.px]="floating() ? null : panelPlacement()?.width"
2404
- >
2405
- <div [class]="panelCardClasses()">
2406
- <div role="menu" [class]="menuClasses()" [attr.aria-label]="label()">
2407
- <!-- ROW 1 = bar (sticky, menutup bar trigger), struktur seperti bar navbar:
2408
- Header (kiri) | menu item (tengah) | Footer (kanan). Hanya ROW 2 (grid child)
2409
- di bawah bar yang ikut scroll. -->
2410
- <div data-navigation-flyout-bar="true" [class]="barRowClasses()">
2411
- <ng-content select="NavigationHeader" />
2412
-
2413
- <ul
2414
- role="none"
2415
- data-navigation-flyout-row="true"
2416
- [class]="rowClasses()"
2417
- (keydown)="onRowKeydown($event)"
2418
- >
2419
- @for (item of items(); track item.key) {
2420
- @switch (item.type) {
2421
- @case ('divider') {
2422
- <li role="separator" class="mx-1 h-5 w-px bg-border"></li>
2423
- }
2424
- @case ('spacer') {
2425
- <li role="none" aria-hidden="true" class="flex-1"></li>
2426
- }
2427
- @default {
2428
- @if (item.children.length > 0) {
2429
- <li
2430
- role="none"
2431
- [class]="groupContainerClasses(item)"
2432
- [attr.data-navigation-item-key]="item.key"
2433
- >
2434
- <button
2435
- type="button"
2436
- role="menuitem"
2437
- data-navigation-flyout-tab="true"
2438
- [class]="tabClasses(item)"
2439
- [attr.aria-expanded]="isBranchOpen(item)"
2440
- [attr.aria-controls]="item.panelId"
2441
- [disabled]="item.disabled || null"
2442
- (click)="openBranch(item)"
2443
- >
2444
- <NavigationItemContent
2445
- [item]="item"
2446
- [active]="isItemActive(item)"
2447
- [compact]="false"
2448
- [orientation]="'horizontal'"
2449
- [level]="0"
2450
- [iconTemplate]="iconTemplate()"
2451
- />
2452
- <Icon
2453
- name="chevron_right"
2454
- [size]="16"
2455
- [class]="tabChevronClasses(item)"
2456
- />
2457
- </button>
2458
- </li>
2459
- } @else {
2460
- <li
2461
- NavigationItem
2462
- [navId]="navId()"
2463
- [item]="item"
2464
- [level]="0"
2465
- [orientation]="'horizontal'"
2466
- [compact]="false"
2467
- [itemClass]="navItemClass()"
2468
- [activeIds]="activeIds()"
2469
- [activeUrl]="activeUrl()"
2470
- [iconTemplate]="iconTemplate()"
2471
- [collapseTree]="collapseTree()"
2472
- [openedIds]="openedIds()"
2473
- (openedIdsChange)="openedIdsChange.emit($event)"
2474
- (itemSelected)="itemSelected.emit($event)"
2475
- ></li>
2476
- }
2477
- }
2478
- }
2479
- }
2480
- </ul>
2481
-
2482
- <ng-content select="NavigationFooter" />
2483
- </div>
2484
-
2485
- <!-- ROW 2 = child dari menu item aktif; HANYA area ini yang men-scroll. -->
2486
- <div data-navigation-flyout-scroll="true" [class]="scrollRegionClasses()">
2487
- @if (activeBranch(); as branch) {
2488
- <NavigationEntryGrid
2489
- [navId]="navId()"
2490
- [branch]="branch"
2491
- [typeStyle]="typeStyle()"
2492
- [itemClass]="itemClass()"
2493
- [activeIds]="activeIds()"
2494
- [activeUrl]="activeUrl()"
2495
- [iconTemplate]="iconTemplate()"
2496
- [collapseTree]="collapseTree()"
2497
- [openedIds]="openedIds()"
2498
- (openedIdsChange)="openedIdsChange.emit($event)"
2499
- (itemSelected)="itemSelected.emit($event)"
2500
- />
2501
- }
2502
- </div>
2503
- </div>
2504
- </div>
2505
- </div>
2506
- }
2507
- `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationEntryGridComponent, selector: "NavigationEntryGrid", inputs: ["navId", "branch", "typeStyle", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationItemContentComponent, selector: "NavigationItemContent", inputs: ["item", "active", "compact", "orientation", "level", "collapseTree", "iconTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2508
- }
2509
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFlyoutMenuComponent, decorators: [{
2510
- type: Component,
2511
- args: [{
2512
- selector: 'NavigationFlyoutMenu',
2513
- changeDetection: ChangeDetectionStrategy.OnPush,
2514
- imports: [
2515
- IconComponent,
2516
- NavigationEntryGridComponent,
2517
- NavigationItemComponent,
2518
- NavigationItemContentComponent,
2519
- ],
2520
- host: {
2521
- '[class]': 'hostClasses()',
2522
- '(keydown.escape)': 'onEscape($event)',
2523
- '(document:click)': 'onDocumentClick($event)',
2524
- '(window:resize)': 'onWindowResize()',
2525
- },
2526
- template: `
2527
- <button
2528
- type="button"
2529
- data-navigation-flyout-trigger="true"
2530
- [class]="triggerClasses()"
2531
- aria-haspopup="menu"
2532
- [attr.aria-expanded]="isOpen()"
2533
- [attr.aria-controls]="isOpen() ? panelId() : null"
2534
- [attr.aria-label]="showIconOnly() ? label() : null"
2535
- [attr.title]="showIconOnly() ? label() : null"
2536
- (click)="toggleFlyout()"
2537
- >
2538
- @if (showIconOnly()) {
2539
- <Icon [name]="triggerIcon() ?? 'menu'" [size]="18" class="text-current" />
2540
- } @else {
2541
- @if (iconPosition() === 'start' && triggerIcon(); as iconName) {
2542
- <Icon [name]="iconName" [size]="18" class="shrink-0 text-current" />
2543
- }
2544
-
2545
- <span class="truncate">{{ label() }}</span>
2546
-
2547
- @if (iconPosition() === 'end' && triggerIcon(); as iconName) {
2548
- <Icon [name]="iconName" [size]="18" class="shrink-0 text-current" />
2549
- }
2550
- }
2551
- </button>
2552
-
2553
- @if (isOpen()) {
2554
- <div
2555
- [id]="panelId()"
2556
- data-navigation-flyout-panel="true"
2557
- [class]="panelWrapperClasses()"
2558
- [style.left.px]="floating() ? null : panelPlacement()?.left"
2559
- [style.top.px]="floating() || isBottom() ? null : panelPlacement()?.top"
2560
- [style.bottom.px]="!floating() && isBottom() ? panelPlacement()?.bottom : null"
2561
- [style.width.px]="floating() ? null : panelPlacement()?.width"
2562
- >
2563
- <div [class]="panelCardClasses()">
2564
- <div role="menu" [class]="menuClasses()" [attr.aria-label]="label()">
2565
- <!-- ROW 1 = bar (sticky, menutup bar trigger), struktur seperti bar navbar:
2566
- Header (kiri) | menu item (tengah) | Footer (kanan). Hanya ROW 2 (grid child)
2567
- di bawah bar yang ikut scroll. -->
2568
- <div data-navigation-flyout-bar="true" [class]="barRowClasses()">
2569
- <ng-content select="NavigationHeader" />
2570
-
2571
- <ul
2572
- role="none"
2573
- data-navigation-flyout-row="true"
2574
- [class]="rowClasses()"
2575
- (keydown)="onRowKeydown($event)"
2576
- >
2577
- @for (item of items(); track item.key) {
2578
- @switch (item.type) {
2579
- @case ('divider') {
2580
- <li role="separator" class="mx-1 h-5 w-px bg-border"></li>
2581
- }
2582
- @case ('spacer') {
2583
- <li role="none" aria-hidden="true" class="flex-1"></li>
2584
- }
2585
- @default {
2586
- @if (item.children.length > 0) {
2587
- <li
2588
- role="none"
2589
- [class]="groupContainerClasses(item)"
2590
- [attr.data-navigation-item-key]="item.key"
2591
- >
2592
- <button
2593
- type="button"
2594
- role="menuitem"
2595
- data-navigation-flyout-tab="true"
2596
- [class]="tabClasses(item)"
2597
- [attr.aria-expanded]="isBranchOpen(item)"
2598
- [attr.aria-controls]="item.panelId"
2599
- [disabled]="item.disabled || null"
2600
- (click)="openBranch(item)"
2601
- >
2602
- <NavigationItemContent
2603
- [item]="item"
2604
- [active]="isItemActive(item)"
2605
- [compact]="false"
2606
- [orientation]="'horizontal'"
2607
- [level]="0"
2608
- [iconTemplate]="iconTemplate()"
2609
- />
2610
- <Icon
2611
- name="chevron_right"
2612
- [size]="16"
2613
- [class]="tabChevronClasses(item)"
2614
- />
2615
- </button>
2616
- </li>
2617
- } @else {
2618
- <li
2619
- NavigationItem
2620
- [navId]="navId()"
2621
- [item]="item"
2622
- [level]="0"
2623
- [orientation]="'horizontal'"
2624
- [compact]="false"
2625
- [itemClass]="navItemClass()"
2626
- [activeIds]="activeIds()"
2627
- [activeUrl]="activeUrl()"
2628
- [iconTemplate]="iconTemplate()"
2629
- [collapseTree]="collapseTree()"
2630
- [openedIds]="openedIds()"
2631
- (openedIdsChange)="openedIdsChange.emit($event)"
2632
- (itemSelected)="itemSelected.emit($event)"
2633
- ></li>
2634
- }
2635
- }
2636
- }
2637
- }
2638
- </ul>
2639
-
2640
- <ng-content select="NavigationFooter" />
2641
- </div>
2642
-
2643
- <!-- ROW 2 = child dari menu item aktif; HANYA area ini yang men-scroll. -->
2644
- <div data-navigation-flyout-scroll="true" [class]="scrollRegionClasses()">
2645
- @if (activeBranch(); as branch) {
2646
- <NavigationEntryGrid
2647
- [navId]="navId()"
2648
- [branch]="branch"
2649
- [typeStyle]="typeStyle()"
2650
- [itemClass]="itemClass()"
2651
- [activeIds]="activeIds()"
2652
- [activeUrl]="activeUrl()"
2653
- [iconTemplate]="iconTemplate()"
2654
- [collapseTree]="collapseTree()"
2655
- [openedIds]="openedIds()"
2656
- (openedIdsChange)="openedIdsChange.emit($event)"
2657
- (itemSelected)="itemSelected.emit($event)"
2658
- />
2659
- }
2660
- </div>
2661
- </div>
2662
- </div>
2663
- </div>
2664
- }
2665
- `,
2666
- }]
2667
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], floating: [{ type: i0.Input, args: [{ isSignal: true, alias: "floating", required: false }] }], triggerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerClass", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], typeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeStyle", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
2668
-
2669
- class NavigationHorizontalComponent {
2670
- nav = inject(NavigationService);
2671
- host = inject(ElementRef);
2672
- navId = input('default', /* @ts-ignore */
2673
- ...(ngDevMode ? [{ debugName: "navId" }] : /* istanbul ignore next */ []));
2674
- items = input([], /* @ts-ignore */
2675
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
2676
- /** Posisi bar terhadap konten: `bottom` membuka panel ke atas; selain itu ke bawah. */
2677
- position = input('top', /* @ts-ignore */
2678
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
2679
- typeStyle = input('flat', /* @ts-ignore */
2680
- ...(ngDevMode ? [{ debugName: "typeStyle" }] : /* istanbul ignore next */ []));
2681
- compact = input(false, /* @ts-ignore */
2682
- ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
2683
- itemClass = input('', /* @ts-ignore */
2684
- ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
2685
- /** Kelas Tailwind untuk container `<li>` group navbar. */
2686
- groupClass = input('', /* @ts-ignore */
2687
- ...(ngDevMode ? [{ debugName: "groupClass" }] : /* istanbul ignore next */ []));
2688
- activeIds = input(new Set(), /* @ts-ignore */
2689
- ...(ngDevMode ? [{ debugName: "activeIds" }] : /* istanbul ignore next */ []));
2690
- activeUrl = input(null, /* @ts-ignore */
2691
- ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
2692
- iconTemplate = input(undefined, /* @ts-ignore */
2693
- ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
2694
- collapseTree = input('stairs', /* @ts-ignore */
2695
- ...(ngDevMode ? [{ debugName: "collapseTree" }] : /* istanbul ignore next */ []));
2696
- openedIds = input([], /* @ts-ignore */
2697
- ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
2698
- openedIdsChange = output();
2699
- itemSelected = output();
2700
- isBorderRail = computed(() => this.typeStyle() === 'border-rail', /* @ts-ignore */
2701
- ...(ngDevMode ? [{ debugName: "isBorderRail" }] : /* istanbul ignore next */ []));
2702
- isBottom = computed(() => this.position() === 'bottom', /* @ts-ignore */
2703
- ...(ngDevMode ? [{ debugName: "isBottom" }] : /* istanbul ignore next */ []));
2704
- /** Kelas tambahan untuk NavigationItem leaf di row saat style border-rail aktif. */
2705
- navItemClass = computed(() => cn(this.itemClass(), this.isBorderRail() && 'rounded-none hover:bg-transparent hover:text-primary'), /* @ts-ignore */
2706
- ...(ngDevMode ? [{ debugName: "navItemClass" }] : /* istanbul ignore next */ []));
2707
- listClasses = computed(() => cn('flex h-full min-w-0 items-center justify-center gap-1 list-none p-0'), /* @ts-ignore */
2708
- ...(ngDevMode ? [{ debugName: "listClasses" }] : /* istanbul ignore next */ []));
2709
- isItemActive(item) {
2710
- return this.nav.isItemActive(item, this.activeIds(), this.activeUrl());
2711
- }
2712
- isPanelOpen(item) {
2713
- return this.nav.isPanelOpen(this.navId(), item);
2714
- }
2715
- togglePanel(item) {
2716
- if (!this.isPanelOpen(item)) {
2717
- this.measurePanelPlacement();
2718
- }
2719
- this.nav.togglePanel(this.navId(), item);
2720
- }
2721
- onWindowResize() {
2722
- if (this.nav.currentPanelKey(this.navId())) {
2723
- this.measurePanelPlacement();
2724
- }
2725
- }
2726
- /** Klik di luar menubar/panel menutup panel mega yang sedang terbuka. */
2727
- onDocumentClick(event) {
2728
- if (!this.nav.currentPanelKey(this.navId())) {
2729
- return;
2730
- }
2731
- const target = event.target;
2732
- if (target && !this.host.nativeElement.contains(target)) {
2733
- this.nav.closePanel(this.navId());
2734
- }
2735
- }
2736
- /**
2737
- * Lebar & posisi kiri panel mengikuti container parent dari `Navigation`
2738
- * (wrapper display:contents dilewati). `null` = pengukuran tak tersedia dan
2739
- * panel jatuh ke lebar host (inset-x-0).
2740
- */
2741
- panelPlacement = signal(null, /* @ts-ignore */
2742
- ...(ngDevMode ? [{ debugName: "panelPlacement" }] : /* istanbul ignore next */ []));
2743
- measurePanelPlacement() {
2744
- const hostEl = this.host.nativeElement;
2745
- const navEl = hostEl.closest('[data-navigation-id]');
2746
- let container = navEl?.parentElement ?? hostEl.parentElement;
2747
- while (container && container.getBoundingClientRect().width <= 0 && container.parentElement) {
2748
- container = container.parentElement;
2749
- }
2750
- const containerRect = (container ?? hostEl).getBoundingClientRect();
2751
- const hostRect = hostEl.getBoundingClientRect();
2752
- if (containerRect.width <= 0) {
2753
- this.panelPlacement.set(null);
2754
- return;
2755
- }
2756
- this.panelPlacement.set({
2757
- left: containerRect.left - hostRect.left,
2758
- width: containerRect.width,
2759
- });
2760
- }
2761
- compactLabel(item) {
2762
- return this.nav.compactLabel(item, this.compact());
2763
- }
2764
- titleFor(item) {
2765
- return this.nav.titleFor(item, this.compact());
2766
- }
2767
- /** Container `<li>` group navbar; consumer atur lewat `nav-group-class` atau `item.classes.container`. */
2768
- groupContainerClasses(item) {
2769
- return cn(this.groupClass(), item.classes?.container);
2770
- }
2771
- triggerClasses(item) {
2772
- return cn('nav-trigger nav-text group/nav inline-flex min-w-0 items-center gap-3 rounded-md font-medium transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', 'h-9 px-3 py-2', this.compact() && 'w-10 justify-center px-0', this.isBorderRail()
2773
- ? this.isPanelOpen(item) || this.isItemActive(item)
2774
- ? 'rounded-none text-primary'
2775
- : 'rounded-none text-foreground/80 hover:text-primary'
2776
- : this.isItemActive(item)
2777
- ? 'bg-accent text-accent-foreground'
2778
- : 'text-foreground/80 hover:bg-accent hover:text-accent-foreground', item.classes?.wrapper, this.itemClass());
2779
- }
2780
- chevronClasses(item) {
2781
- return cn('ml-auto shrink-0 self-center transition-transform duration-200', this.isPanelOpen(item) && 'rotate-90');
2782
- }
2783
- panelClasses() {
2784
- // Panel mega selebar container parent, menempel rapat tanpa gap pada sisi bar:
2785
- // nav-position top membuka ke bawah (sisi atas siku), bottom membuka ke atas
2786
- // (sisi bawah siku) sehingga sambungan border selalu menyatu dengan bar.
2787
- // Border-rail: sisi kiri/kanan panel dibiarkan ditangani rail vertikal dari
2788
- // layout; panel hanya menggambar border atas & bawah 1.5px senada rail.
2789
- // Panel dibiarkan pada tepi bawah bar (`top-full`) tanpa offset, sehingga border
2790
- // atasnya sejajar dengan border-bottom bar (mis. yang dipasang consumer).
2791
- return cn('absolute z-50 bg-popover text-popover-foreground shadow-lg',
2792
- // Batasi tinggi ke viewport (dikurangi area bar) lalu scroll vertikal supaya
2793
- // menu dengan item banyak tetap bisa diakses tanpa keluar layar.
2794
- 'max-h-[calc(100dvh-5rem)] overflow-x-hidden overflow-y-auto overscroll-contain', this.isBottom() ? 'bottom-full' : 'top-full', !this.panelPlacement() && 'inset-x-0', this.isBorderRail()
2795
- ? 'rounded-none border-y-[1.5px] border-border'
2796
- : cn('rounded-xl border border-[hsl(var(--border)/var(--opacity-70))]', this.isBottom() ? 'rounded-b-none' : 'rounded-t-none'));
2797
- }
2798
- onKeydown(event) {
2799
- if (event.key === 'Escape') {
2800
- const panelKey = this.nav.currentPanelKey(this.navId());
2801
- this.nav.closePanel(this.navId());
2802
- this.focusOpenPanelTrigger(panelKey);
2803
- return;
2804
- }
2805
- const rootItems = this.rootFocusItems();
2806
- if (rootItems.length === 0) {
2807
- return;
2808
- }
2809
- const currentIndex = rootItems.indexOf(document.activeElement);
2810
- if (currentIndex === -1) {
2811
- return;
2812
- }
2813
- // ArrowDown membuka panel di posisi top; ArrowUp di posisi bottom (panel di atas bar).
2814
- if (event.key === (this.isBottom() ? 'ArrowUp' : 'ArrowDown')) {
2815
- const currentItem = rootItems[currentIndex];
2816
- if (currentItem.getAttribute('aria-haspopup') === 'menu') {
2817
- event.preventDefault();
2818
- currentItem.click();
2819
- queueMicrotask(() => this.focusFirstPanelItem(this.nav.currentPanelKey(this.navId())));
2820
- }
2821
- return;
2822
- }
2823
- if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
2824
- event.preventDefault();
2825
- const direction = event.key === 'ArrowRight' ? 1 : -1;
2826
- const nextIndex = (currentIndex + direction + rootItems.length) % rootItems.length;
2827
- rootItems[nextIndex]?.focus();
2828
- }
2829
- }
2830
- onPanelKeydown(event) {
2831
- if (event.key !== 'Escape') {
2832
- return;
2833
- }
2834
- event.preventDefault();
2835
- const panelKey = this.nav.currentPanelKey(this.navId());
2836
- this.nav.closePanel(this.navId());
2837
- this.focusOpenPanelTrigger(panelKey);
2838
- }
2839
- rootFocusItems() {
2840
- return Array.from(this.host.nativeElement.querySelectorAll('[data-navigation-root-item="true"]'));
2841
- }
2842
- focusOpenPanelTrigger(panelKey) {
2843
- if (!panelKey) {
2844
- return;
2845
- }
2846
- const trigger = this.host.nativeElement.querySelector(`[data-navigation-item-key="${panelKey}"] [data-navigation-root-item="true"]`);
2847
- trigger?.focus();
2848
- }
2849
- focusFirstPanelItem(panelKey) {
2850
- if (!panelKey) {
2851
- return;
2852
- }
2853
- const panel = this.host.nativeElement.querySelector(`[data-navigation-panel="${panelKey}"]`);
2854
- const item = panel?.querySelector('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])');
2855
- item?.focus();
2856
- }
2857
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHorizontalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2858
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationHorizontalComponent, isStandalone: true, selector: "NavigationHorizontal", inputs: { navId: { classPropertyName: "navId", publicName: "navId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, typeStyle: { classPropertyName: "typeStyle", publicName: "typeStyle", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", isSignal: true, isRequired: false, transformFunction: null }, activeIds: { classPropertyName: "activeIds", publicName: "activeIds", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseTree: { classPropertyName: "collapseTree", publicName: "collapseTree", isSignal: true, isRequired: false, transformFunction: null }, openedIds: { classPropertyName: "openedIds", publicName: "openedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedIdsChange: "openedIdsChange", itemSelected: "itemSelected" }, host: { listeners: { "window:resize": "onWindowResize()", "document:click": "onDocumentClick($event)" }, classAttribute: "relative block h-full w-full" }, ngImport: i0, template: `
2859
- <ul [class]="listClasses()" role="menubar" (keydown)="onKeydown($event)">
2860
- @for (item of items(); track item.key) {
2861
- @switch (item.type) {
2862
- @case ('group') {
2863
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2864
- }
2865
- @case ('collapsible') {
2866
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2867
- }
2868
- @case ('mega') {
2869
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2870
- }
2871
- @default {
2872
- <li
2873
- NavigationItem
2874
- [navId]="navId()"
2875
- [item]="item"
2876
- [level]="0"
2877
- [orientation]="'horizontal'"
2878
- [compact]="compact()"
2879
- [itemClass]="navItemClass()"
2880
- [activeIds]="activeIds()"
2881
- [activeUrl]="activeUrl()"
2882
- [iconTemplate]="iconTemplate()"
2883
- [collapseTree]="collapseTree()"
2884
- [openedIds]="openedIds()"
2885
- (openedIdsChange)="openedIdsChange.emit($event)"
2886
- (itemSelected)="itemSelected.emit($event)"></li>
2887
- }
2888
- }
2889
- }
2890
- </ul>
2891
-
2892
- <ng-template #branchTemplate let-item>
2893
- <li role="none" [class]="groupContainerClasses(item)" [attr.data-navigation-item-key]="item.key">
2894
- <button
2895
- type="button"
2896
- role="menuitem"
2897
- data-navigation-root-item="true"
2898
- [class]="triggerClasses(item)"
2899
- [attr.aria-expanded]="isPanelOpen(item)"
2900
- [attr.aria-controls]="item.panelId"
2901
- [attr.aria-haspopup]="'menu'"
2902
- [attr.aria-label]="compactLabel(item)"
2903
- [attr.title]="titleFor(item)"
2904
- [disabled]="item.disabled || null"
2905
- (click)="togglePanel(item)">
2906
- <NavigationItemContent
2907
- [item]="item"
2908
- [active]="isItemActive(item)"
2909
- [compact]="compact()"
2910
- [orientation]="'horizontal'"
2911
- [level]="0"
2912
- [iconTemplate]="iconTemplate()" />
2913
- <Icon name="chevron_right" [size]="16" [class]="chevronClasses(item)" />
2914
- </button>
2915
-
2916
- @if (isPanelOpen(item)) {
2917
- <div
2918
- [id]="item.panelId"
2919
- role="menu"
2920
- [class]="panelClasses()"
2921
- [style.left.px]="panelPlacement()?.left"
2922
- [style.width.px]="panelPlacement()?.width"
2923
- [attr.data-navigation-panel]="item.key"
2924
- (keydown)="onPanelKeydown($event)">
2925
- <NavigationEntryGrid
2926
- [navId]="navId()"
2927
- [branch]="item"
2928
- [typeStyle]="typeStyle()"
2929
- [itemClass]="itemClass()"
2930
- [activeIds]="activeIds()"
2931
- [activeUrl]="activeUrl()"
2932
- [iconTemplate]="iconTemplate()"
2933
- [collapseTree]="collapseTree()"
2934
- [openedIds]="openedIds()"
2935
- (openedIdsChange)="openedIdsChange.emit($event)"
2936
- (itemSelected)="itemSelected.emit($event)" />
2937
- </div>
2938
- }
2939
- </li>
2940
- </ng-template>
2941
- `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: NavigationEntryGridComponent, selector: "NavigationEntryGrid", inputs: ["navId", "branch", "typeStyle", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationItemComponent, selector: "li[NavigationItem]", inputs: ["navId", "item", "level", "orientation", "compact", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "straightRail", "straightRailActive", "firstInBranch", "lastInBranch", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationItemContentComponent, selector: "NavigationItemContent", inputs: ["item", "active", "compact", "orientation", "level", "collapseTree", "iconTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2942
- }
2943
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHorizontalComponent, decorators: [{
2944
- type: Component,
2945
- args: [{
2946
- selector: 'NavigationHorizontal',
2947
- changeDetection: ChangeDetectionStrategy.OnPush,
2948
- imports: [
2949
- NgTemplateOutlet,
2950
- IconComponent,
2951
- NavigationEntryGridComponent,
2952
- NavigationItemComponent,
2953
- NavigationItemContentComponent,
2954
- ],
2955
- host: {
2956
- class: 'relative block h-full w-full',
2957
- '(window:resize)': 'onWindowResize()',
2958
- '(document:click)': 'onDocumentClick($event)',
2959
- },
2960
- template: `
2961
- <ul [class]="listClasses()" role="menubar" (keydown)="onKeydown($event)">
2962
- @for (item of items(); track item.key) {
2963
- @switch (item.type) {
2964
- @case ('group') {
2965
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2966
- }
2967
- @case ('collapsible') {
2968
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2969
- }
2970
- @case ('mega') {
2971
- <ng-container [ngTemplateOutlet]="branchTemplate" [ngTemplateOutletContext]="{ $implicit: item }" />
2972
- }
2973
- @default {
2974
- <li
2975
- NavigationItem
2976
- [navId]="navId()"
2977
- [item]="item"
2978
- [level]="0"
2979
- [orientation]="'horizontal'"
2980
- [compact]="compact()"
2981
- [itemClass]="navItemClass()"
2982
- [activeIds]="activeIds()"
2983
- [activeUrl]="activeUrl()"
2984
- [iconTemplate]="iconTemplate()"
2985
- [collapseTree]="collapseTree()"
2986
- [openedIds]="openedIds()"
2987
- (openedIdsChange)="openedIdsChange.emit($event)"
2988
- (itemSelected)="itemSelected.emit($event)"></li>
2989
- }
2990
- }
2991
- }
2992
- </ul>
2993
-
2994
- <ng-template #branchTemplate let-item>
2995
- <li role="none" [class]="groupContainerClasses(item)" [attr.data-navigation-item-key]="item.key">
2996
- <button
2997
- type="button"
2998
- role="menuitem"
2999
- data-navigation-root-item="true"
3000
- [class]="triggerClasses(item)"
3001
- [attr.aria-expanded]="isPanelOpen(item)"
3002
- [attr.aria-controls]="item.panelId"
3003
- [attr.aria-haspopup]="'menu'"
3004
- [attr.aria-label]="compactLabel(item)"
3005
- [attr.title]="titleFor(item)"
3006
- [disabled]="item.disabled || null"
3007
- (click)="togglePanel(item)">
3008
- <NavigationItemContent
3009
- [item]="item"
3010
- [active]="isItemActive(item)"
3011
- [compact]="compact()"
3012
- [orientation]="'horizontal'"
3013
- [level]="0"
3014
- [iconTemplate]="iconTemplate()" />
3015
- <Icon name="chevron_right" [size]="16" [class]="chevronClasses(item)" />
3016
- </button>
3017
-
3018
- @if (isPanelOpen(item)) {
3019
- <div
3020
- [id]="item.panelId"
3021
- role="menu"
3022
- [class]="panelClasses()"
3023
- [style.left.px]="panelPlacement()?.left"
3024
- [style.width.px]="panelPlacement()?.width"
3025
- [attr.data-navigation-panel]="item.key"
3026
- (keydown)="onPanelKeydown($event)">
3027
- <NavigationEntryGrid
3028
- [navId]="navId()"
3029
- [branch]="item"
3030
- [typeStyle]="typeStyle()"
3031
- [itemClass]="itemClass()"
3032
- [activeIds]="activeIds()"
3033
- [activeUrl]="activeUrl()"
3034
- [iconTemplate]="iconTemplate()"
3035
- [collapseTree]="collapseTree()"
3036
- [openedIds]="openedIds()"
3037
- (openedIdsChange)="openedIdsChange.emit($event)"
3038
- (itemSelected)="itemSelected.emit($event)" />
3039
- </div>
3040
- }
3041
- </li>
3042
- </ng-template>
3043
- `,
3044
- }]
3045
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navId", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], typeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeStyle", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupClass", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTree", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }], openedIdsChange: [{ type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
3046
-
3047
- /**
3048
- * Area konten navigasi: merender daftar item sesuai type aktif dari
3049
- * `<Navigation>` induk. Selalu hadir di setiap type — komponen type
3050
- * merender default-nya bila consumer tidak memproyeksikan `<NavigationContent />`.
3051
- */
3052
- class NavigationContentComponent {
3053
- container = inject(NavigationContainerComponent);
3054
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3055
- hostClasses = computed(() => cn('min-h-0 flex-1', this.container.displayState().orientation === 'horizontal'
3056
- ? 'flex h-full min-w-0 items-stretch justify-center overflow-visible'
3057
- : 'block overflow-y-auto overflow-x-hidden py-2', this.class()), /* @ts-ignore */
3058
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3059
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3060
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationContentComponent, isStandalone: true, selector: "NavigationContent", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
3061
- @let navState = container.displayState();
3062
-
3063
- @if (navState.orientation === 'horizontal' && navState.type === 'flyout') {
3064
- <NavigationFlyoutMenu
3065
- [navId]="navState.id"
3066
- [items]="container.normalizedItems()"
3067
- [label]="container.flyoutLabel()"
3068
- [icon]="container.flyoutIcon()"
3069
- [iconOnly]="container.flyoutIconOnly()"
3070
- [iconPosition]="container.flyoutIconPosition()"
3071
- [variant]="container.flyoutTriggerVariant()"
3072
- [floating]="container.flyoutTriggerFloating()"
3073
- [triggerClass]="container.flyoutTriggerClass()"
3074
- [position]="navState.position"
3075
- [typeStyle]="container.typeStyle()"
3076
- [compact]="container.compact()"
3077
- [itemClass]="container.itemClass()"
3078
- [groupClass]="container.groupClass()"
3079
- [activeIds]="container.activeIdSet()"
3080
- [activeUrl]="container.activeUrl()"
3081
- [iconTemplate]="container.iconTemplate()"
3082
- [collapseTree]="container.collapseTree()"
3083
- [openedIds]="container.openedIds()"
3084
- (openedIdsChange)="container.openedIds.set($event)"
3085
- (itemSelected)="container.itemSelected.emit($event)"
3086
- >
3087
- <ng-content select="NavigationHeader" ngProjectAs="NavigationHeader" />
3088
- <ng-content select="NavigationFooter" ngProjectAs="NavigationFooter" />
3089
- </NavigationFlyoutMenu>
3090
- } @else if (navState.orientation === 'horizontal') {
3091
- <NavigationHorizontal
3092
- [navId]="navState.id"
3093
- [items]="container.normalizedItems()"
3094
- [position]="navState.position"
3095
- [typeStyle]="container.typeStyle()"
3096
- [compact]="container.compact()"
3097
- [itemClass]="container.itemClass()"
3098
- [groupClass]="container.groupClass()"
3099
- [activeIds]="container.activeIdSet()"
3100
- [activeUrl]="container.activeUrl()"
3101
- [iconTemplate]="container.iconTemplate()"
3102
- [collapseTree]="container.collapseTree()"
3103
- [openedIds]="container.openedIds()"
3104
- (openedIdsChange)="container.openedIds.set($event)"
3105
- (itemSelected)="container.itemSelected.emit($event)"
3106
- />
3107
- } @else if (navState.type === 'dockbar') {
3108
- <NavigationDockbarMenu
3109
- [navId]="navState.id"
3110
- [items]="container.normalizedItems()"
3111
- [mode]="navState.dockbarMode"
3112
- [position]="navState.position"
3113
- [itemClass]="container.itemClass()"
3114
- [activeIds]="container.activeIdSet()"
3115
- [activeUrl]="container.activeUrl()"
3116
- [iconTemplate]="container.iconTemplate()"
3117
- [collapseTree]="container.collapseTree()"
3118
- [openedIds]="container.openedIds()"
3119
- (openedIdsChange)="container.openedIds.set($event)"
3120
- (itemSelected)="container.itemSelected.emit($event)"
3121
- />
3122
- } @else {
3123
- <NavigationList
3124
- [navId]="navState.id"
3125
- [items]="container.normalizedItems()"
3126
- [collapsed]="navState.collapsed"
3127
- [position]="navState.position"
3128
- [itemClass]="container.itemClass()"
3129
- [activeIds]="container.activeIdSet()"
3130
- [activeUrl]="container.activeUrl()"
3131
- [iconTemplate]="container.iconTemplate()"
3132
- [collapseTree]="container.collapseTree()"
3133
- [openedIds]="container.openedIds()"
3134
- (openedIdsChange)="container.openedIds.set($event)"
3135
- (itemSelected)="container.itemSelected.emit($event)"
3136
- />
3137
- }
3138
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationDockbarMenuComponent, selector: "NavigationDockbarMenu", inputs: ["navId", "items", "mode", "position", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationFlyoutMenuComponent, selector: "NavigationFlyoutMenu", inputs: ["navId", "items", "label", "icon", "iconOnly", "iconPosition", "variant", "floating", "triggerClass", "position", "typeStyle", "compact", "itemClass", "groupClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationHorizontalComponent, selector: "NavigationHorizontal", inputs: ["navId", "items", "position", "typeStyle", "compact", "itemClass", "groupClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }, { kind: "component", type: NavigationListComponent, selector: "NavigationList", inputs: ["navId", "items", "collapsed", "compact", "position", "itemClass", "activeIds", "activeUrl", "iconTemplate", "collapseTree", "openedIds"], outputs: ["openedIdsChange", "itemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3139
- }
3140
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationContentComponent, decorators: [{
3141
- type: Component,
3142
- args: [{
3143
- selector: 'NavigationContent',
3144
- changeDetection: ChangeDetectionStrategy.OnPush,
3145
- imports: [
3146
- NavigationDockbarMenuComponent,
3147
- NavigationFlyoutMenuComponent,
3148
- NavigationHorizontalComponent,
3149
- NavigationListComponent,
3150
- ],
3151
- host: {
3152
- '[class]': 'hostClasses()',
3153
- },
3154
- template: `
3155
- @let navState = container.displayState();
3156
-
3157
- @if (navState.orientation === 'horizontal' && navState.type === 'flyout') {
3158
- <NavigationFlyoutMenu
3159
- [navId]="navState.id"
3160
- [items]="container.normalizedItems()"
3161
- [label]="container.flyoutLabel()"
3162
- [icon]="container.flyoutIcon()"
3163
- [iconOnly]="container.flyoutIconOnly()"
3164
- [iconPosition]="container.flyoutIconPosition()"
3165
- [variant]="container.flyoutTriggerVariant()"
3166
- [floating]="container.flyoutTriggerFloating()"
3167
- [triggerClass]="container.flyoutTriggerClass()"
3168
- [position]="navState.position"
3169
- [typeStyle]="container.typeStyle()"
3170
- [compact]="container.compact()"
3171
- [itemClass]="container.itemClass()"
3172
- [groupClass]="container.groupClass()"
3173
- [activeIds]="container.activeIdSet()"
3174
- [activeUrl]="container.activeUrl()"
3175
- [iconTemplate]="container.iconTemplate()"
3176
- [collapseTree]="container.collapseTree()"
3177
- [openedIds]="container.openedIds()"
3178
- (openedIdsChange)="container.openedIds.set($event)"
3179
- (itemSelected)="container.itemSelected.emit($event)"
3180
- >
3181
- <ng-content select="NavigationHeader" ngProjectAs="NavigationHeader" />
3182
- <ng-content select="NavigationFooter" ngProjectAs="NavigationFooter" />
3183
- </NavigationFlyoutMenu>
3184
- } @else if (navState.orientation === 'horizontal') {
3185
- <NavigationHorizontal
3186
- [navId]="navState.id"
3187
- [items]="container.normalizedItems()"
3188
- [position]="navState.position"
3189
- [typeStyle]="container.typeStyle()"
3190
- [compact]="container.compact()"
3191
- [itemClass]="container.itemClass()"
3192
- [groupClass]="container.groupClass()"
3193
- [activeIds]="container.activeIdSet()"
3194
- [activeUrl]="container.activeUrl()"
3195
- [iconTemplate]="container.iconTemplate()"
3196
- [collapseTree]="container.collapseTree()"
3197
- [openedIds]="container.openedIds()"
3198
- (openedIdsChange)="container.openedIds.set($event)"
3199
- (itemSelected)="container.itemSelected.emit($event)"
3200
- />
3201
- } @else if (navState.type === 'dockbar') {
3202
- <NavigationDockbarMenu
3203
- [navId]="navState.id"
3204
- [items]="container.normalizedItems()"
3205
- [mode]="navState.dockbarMode"
3206
- [position]="navState.position"
3207
- [itemClass]="container.itemClass()"
3208
- [activeIds]="container.activeIdSet()"
3209
- [activeUrl]="container.activeUrl()"
3210
- [iconTemplate]="container.iconTemplate()"
3211
- [collapseTree]="container.collapseTree()"
3212
- [openedIds]="container.openedIds()"
3213
- (openedIdsChange)="container.openedIds.set($event)"
3214
- (itemSelected)="container.itemSelected.emit($event)"
3215
- />
3216
- } @else {
3217
- <NavigationList
3218
- [navId]="navState.id"
3219
- [items]="container.normalizedItems()"
3220
- [collapsed]="navState.collapsed"
3221
- [position]="navState.position"
3222
- [itemClass]="container.itemClass()"
3223
- [activeIds]="container.activeIdSet()"
3224
- [activeUrl]="container.activeUrl()"
3225
- [iconTemplate]="container.iconTemplate()"
3226
- [collapseTree]="container.collapseTree()"
3227
- [openedIds]="container.openedIds()"
3228
- (openedIdsChange)="container.openedIds.set($event)"
3229
- (itemSelected)="container.itemSelected.emit($event)"
3230
- />
3231
- }
3232
- `,
3233
- }]
3234
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3235
-
3236
- class NavigationFooterComponent {
3237
- shell = inject(NAVIGATION_SHELL, { optional: true });
3238
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3239
- isHorizontal = computed(() => this.shell?.displayState().orientation === 'horizontal', /* @ts-ignore */
3240
- ...(ngDevMode ? [{ debugName: "isHorizontal" }] : /* istanbul ignore next */ []));
3241
- hostClasses = computed(() => cn(this.isHorizontal()
3242
- ? 'relative z-10 block h-full w-auto shrink-0'
3243
- : 'sticky bottom-0 z-10 block h-12 shrink-0 border-t border-[hsl(var(--border)/var(--opacity-70))]', this.class()), /* @ts-ignore */
3244
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3245
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3246
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.3", type: NavigationFooterComponent, isStandalone: true, selector: "NavigationFooter", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
3247
- <div class="flex h-full min-w-0 items-center gap-3">
3248
- <ng-content />
3249
- </div>
3250
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
3251
- }
3252
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterComponent, decorators: [{
3253
- type: Component,
3254
- args: [{
3255
- selector: 'NavigationFooter',
3256
- changeDetection: ChangeDetectionStrategy.OnPush,
3257
- host: {
3258
- '[class]': 'hostClasses()',
3259
- },
3260
- template: `
3261
- <div class="flex h-full min-w-0 items-center gap-3">
3262
- <ng-content />
3263
- </div>
3264
- `,
3265
- }]
3266
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3267
-
3268
- class NavigationHeaderComponent {
3269
- shell = inject(NAVIGATION_SHELL);
3270
- toggle = input(false, /* @ts-ignore */
3271
- ...(ngDevMode ? [{ debugName: "toggle" }] : /* istanbul ignore next */ []));
3272
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3273
- collapsed = computed(() => this.shell.state().collapsed, /* @ts-ignore */
3274
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3275
- displayCollapsed = computed(() => this.shell.displayState().collapsed, /* @ts-ignore */
3276
- ...(ngDevMode ? [{ debugName: "displayCollapsed" }] : /* istanbul ignore next */ []));
3277
- isHorizontal = computed(() => this.shell.displayState().orientation === 'horizontal', /* @ts-ignore */
3278
- ...(ngDevMode ? [{ debugName: "isHorizontal" }] : /* istanbul ignore next */ []));
3279
- showToggle = computed(() => {
3280
- if (this.isHorizontal()) {
3281
- return false;
3282
- }
3283
- return this.toggle() || (this.shell.collapseEnabled() && !this.displayCollapsed());
3284
- }, /* @ts-ignore */
3285
- ...(ngDevMode ? [{ debugName: "showToggle" }] : /* istanbul ignore next */ []));
3286
- toggleAriaLabel = computed(() => this.collapsed() ? 'Expand navigation' : 'Collapse navigation', /* @ts-ignore */
3287
- ...(ngDevMode ? [{ debugName: "toggleAriaLabel" }] : /* istanbul ignore next */ []));
3288
- toggleIconName = computed(() => this.collapsed() ? 'left_panel_open' : 'left_panel_close', /* @ts-ignore */
3289
- ...(ngDevMode ? [{ debugName: "toggleIconName" }] : /* istanbul ignore next */ []));
3290
- /**
3291
- * Baris isi header. Saat collapsed/dockbar (vertical) isi (inisial/ikon) dipusatkan di tengah
3292
- * rail agar simetris dengan ikon nav-item di bawahnya (yang juga center di rail); selain itu kiri
3293
- * dengan padding `px-3`.
3294
- */
3295
- rowClasses = computed(() => cn('flex h-full items-center', !this.isHorizontal() && this.displayCollapsed() ? 'justify-center' : 'gap-3 px-3'), /* @ts-ignore */
3296
- ...(ngDevMode ? [{ debugName: "rowClasses" }] : /* istanbul ignore next */ []));
3297
- contentClasses = computed(() => {
3298
- if (this.isHorizontal()) {
3299
- return 'flex min-w-0 items-center gap-3';
3300
- }
3301
- // Collapsed/dockbar: inisial center (tanpa `flex-1` yang membuatnya rata kiri).
3302
- return this.displayCollapsed()
3303
- ? 'flex min-w-0 items-center justify-center'
3304
- : 'flex min-w-0 flex-1 items-center gap-3';
3305
- }, /* @ts-ignore */
3306
- ...(ngDevMode ? [{ debugName: "contentClasses" }] : /* istanbul ignore next */ []));
3307
- hostClasses = computed(() => cn(this.isHorizontal()
3308
- ? 'relative z-10 block h-full w-auto shrink-0'
3309
- : 'sticky top-0 z-10 block h-12 shrink-0 border-b border-[hsl(var(--border)/var(--opacity-70))]', this.class()), /* @ts-ignore */
3310
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3311
- toggleCollapsed() {
3312
- this.shell.toggleCollapsed();
3313
- }
3314
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3315
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationHeaderComponent, isStandalone: true, selector: "NavigationHeader", inputs: { toggle: { classPropertyName: "toggle", publicName: "toggle", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.data-collapsed": "displayCollapsed()" } }, ngImport: i0, template: `
3316
- <div [class]="rowClasses()">
3317
- <div [class]="contentClasses()">
3318
- <ng-content />
3319
- </div>
3320
-
3321
- @if (showToggle()) {
3322
- <button
3323
- type="button"
3324
- class="inline-flex h-8 w-8 shrink-0 items-center justify-center bg-transparent text-foreground/80 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
3325
- [attr.aria-label]="toggleAriaLabel()"
3326
- [attr.title]="toggleAriaLabel()"
3327
- data-navigation-header-toggle="true"
3328
- (click)="toggleCollapsed()"
3329
- >
3330
- <Icon data-navigation-header-toggle-icon="true" [name]="toggleIconName()" [size]="18" />
3331
- </button>
3332
- }
3333
- </div>
3334
- `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3335
- }
3336
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderComponent, decorators: [{
3337
- type: Component,
3338
- args: [{
3339
- selector: 'NavigationHeader',
3340
- changeDetection: ChangeDetectionStrategy.OnPush,
3341
- imports: [IconComponent],
3342
- host: {
3343
- '[class]': 'hostClasses()',
3344
- '[attr.data-collapsed]': 'displayCollapsed()',
3345
- },
3346
- template: `
3347
- <div [class]="rowClasses()">
3348
- <div [class]="contentClasses()">
3349
- <ng-content />
3350
- </div>
3351
-
3352
- @if (showToggle()) {
3353
- <button
3354
- type="button"
3355
- class="inline-flex h-8 w-8 shrink-0 items-center justify-center bg-transparent text-foreground/80 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
3356
- [attr.aria-label]="toggleAriaLabel()"
3357
- [attr.title]="toggleAriaLabel()"
3358
- data-navigation-header-toggle="true"
3359
- (click)="toggleCollapsed()"
3360
- >
3361
- <Icon data-navigation-header-toggle-icon="true" [name]="toggleIconName()" [size]="18" />
3362
- </button>
3363
- }
3364
- </div>
3365
- `,
3366
- }]
3367
- }], propDecorators: { toggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggle", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3368
-
3369
- /**
3370
- * Type sidebar vertikal untuk `<Navigation>`. Slot `NavigationHeader` dan
3371
- * `NavigationFooter` opsional; `NavigationContent` selalu dirender (default
3372
- * otomatis bila tidak diproyeksikan).
3373
- */
3374
- class NavigationSidebarComponent {
3375
- container = inject(NavigationContainerComponent);
3376
- destroyRef = inject(DestroyRef);
3377
- position = input(null, /* @ts-ignore */
3378
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
3379
- collapsed = input(null, /* @ts-ignore */
3380
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3381
- collapse = input(false, { ...(ngDevMode ? { debugName: "collapse" } : /* istanbul ignore next */ {}), alias: 'nav-sidebar-collapse', transform: booleanAttribute });
3382
- previewExpanded = input(false, /* @ts-ignore */
3383
- ...(ngDevMode ? [{ debugName: "previewExpanded" }] : /* istanbul ignore next */ []));
3384
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3385
- headerSlot = contentChild(NavigationHeaderComponent, /* @ts-ignore */
3386
- ...(ngDevMode ? [{ debugName: "headerSlot" }] : /* istanbul ignore next */ []));
3387
- contentSlot = contentChild(NavigationContentComponent, /* @ts-ignore */
3388
- ...(ngDevMode ? [{ debugName: "contentSlot" }] : /* istanbul ignore next */ []));
3389
- footerSlot = contentChild(NavigationFooterComponent, /* @ts-ignore */
3390
- ...(ngDevMode ? [{ debugName: "footerSlot" }] : /* istanbul ignore next */ []));
3391
- hostClasses = computed(() => cn(this.container.shellClasses(), this.class()), /* @ts-ignore */
3392
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3393
- constructor() {
3394
- const config = {
3395
- orientation: 'vertical',
3396
- type: 'sidebar',
3397
- position: this.position,
3398
- collapsed: this.collapsed,
3399
- sidebarCollapse: this.collapse,
3400
- previewExpanded: this.previewExpanded,
3401
- };
3402
- this.container.registerType(config);
3403
- this.destroyRef.onDestroy(() => this.container.unregisterType(config));
3404
- }
3405
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3406
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationSidebarComponent, isStandalone: true, selector: "NavigationSidebar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, collapse: { classPropertyName: "collapse", publicName: "nav-sidebar-collapse", isSignal: true, isRequired: false, transformFunction: null }, previewExpanded: { classPropertyName: "previewExpanded", publicName: "previewExpanded", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "headerSlot", first: true, predicate: NavigationHeaderComponent, descendants: true, isSignal: true }, { propertyName: "contentSlot", first: true, predicate: NavigationContentComponent, descendants: true, isSignal: true }, { propertyName: "footerSlot", first: true, predicate: NavigationFooterComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
3407
- @if (headerSlot()) {
3408
- <ng-content select="NavigationHeader" />
3409
- }
3410
-
3411
- @if (contentSlot()) {
3412
- <ng-content select="NavigationContent" />
3413
- } @else {
3414
- <NavigationContent />
3415
- }
3416
-
3417
- @if (footerSlot()) {
3418
- <ng-content select="NavigationFooter" />
3419
- }
3420
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationContentComponent, selector: "NavigationContent", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3421
- }
3422
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationSidebarComponent, decorators: [{
3423
- type: Component,
3424
- args: [{
3425
- selector: 'NavigationSidebar',
3426
- changeDetection: ChangeDetectionStrategy.OnPush,
3427
- imports: [NavigationContentComponent],
3428
- host: {
3429
- '[class]': 'hostClasses()',
3430
- },
3431
- template: `
3432
- @if (headerSlot()) {
3433
- <ng-content select="NavigationHeader" />
3434
- }
3435
-
3436
- @if (contentSlot()) {
3437
- <ng-content select="NavigationContent" />
3438
- } @else {
3439
- <NavigationContent />
3440
- }
3441
-
3442
- @if (footerSlot()) {
3443
- <ng-content select="NavigationFooter" />
3444
- }
3445
- `,
3446
- }]
3447
- }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], collapse: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-sidebar-collapse", required: false }] }], previewExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewExpanded", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], headerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationHeaderComponent), { isSignal: true }] }], contentSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationContentComponent), { isSignal: true }] }], footerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationFooterComponent), { isSignal: true }] }] } });
3448
-
3449
- /**
3450
- * Type dockbar vertikal (rail ikon + aside) untuk `<Navigation>`. Slot
3451
- * `NavigationHeader` dan `NavigationFooter` opsional; `NavigationContent`
3452
- * selalu dirender (default otomatis bila tidak diproyeksikan).
3453
- */
3454
- class NavigationDockbarComponent {
3455
- container = inject(NavigationContainerComponent);
3456
- destroyRef = inject(DestroyRef);
3457
- mode = input(null, /* @ts-ignore */
3458
- ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
3459
- position = input(null, /* @ts-ignore */
3460
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
3461
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3462
- headerSlot = contentChild(NavigationHeaderComponent, /* @ts-ignore */
3463
- ...(ngDevMode ? [{ debugName: "headerSlot" }] : /* istanbul ignore next */ []));
3464
- contentSlot = contentChild(NavigationContentComponent, /* @ts-ignore */
3465
- ...(ngDevMode ? [{ debugName: "contentSlot" }] : /* istanbul ignore next */ []));
3466
- footerSlot = contentChild(NavigationFooterComponent, /* @ts-ignore */
3467
- ...(ngDevMode ? [{ debugName: "footerSlot" }] : /* istanbul ignore next */ []));
3468
- hostClasses = computed(() => cn(this.container.shellClasses(), this.class()), /* @ts-ignore */
3469
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3470
- constructor() {
3471
- const config = {
3472
- orientation: 'vertical',
3473
- type: 'dockbar',
3474
- position: this.position,
3475
- dockbarMode: this.mode,
3476
- };
3477
- this.container.registerType(config);
3478
- this.destroyRef.onDestroy(() => this.container.unregisterType(config));
3479
- }
3480
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationDockbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3481
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationDockbarComponent, isStandalone: true, selector: "NavigationDockbar", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "headerSlot", first: true, predicate: NavigationHeaderComponent, descendants: true, isSignal: true }, { propertyName: "contentSlot", first: true, predicate: NavigationContentComponent, descendants: true, isSignal: true }, { propertyName: "footerSlot", first: true, predicate: NavigationFooterComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
3482
- @if (headerSlot()) {
3483
- <ng-content select="NavigationHeader" />
3484
- }
3485
-
3486
- @if (contentSlot()) {
3487
- <ng-content select="NavigationContent" />
3488
- } @else {
3489
- <NavigationContent />
3490
- }
3491
-
3492
- @if (footerSlot()) {
3493
- <ng-content select="NavigationFooter" />
3494
- }
3495
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationContentComponent, selector: "NavigationContent", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3496
- }
3497
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationDockbarComponent, decorators: [{
3498
- type: Component,
3499
- args: [{
3500
- selector: 'NavigationDockbar',
3501
- changeDetection: ChangeDetectionStrategy.OnPush,
3502
- imports: [NavigationContentComponent],
3503
- host: {
3504
- '[class]': 'hostClasses()',
3505
- },
3506
- template: `
3507
- @if (headerSlot()) {
3508
- <ng-content select="NavigationHeader" />
3509
- }
3510
-
3511
- @if (contentSlot()) {
3512
- <ng-content select="NavigationContent" />
3513
- } @else {
3514
- <NavigationContent />
3515
- }
3516
-
3517
- @if (footerSlot()) {
3518
- <ng-content select="NavigationFooter" />
3519
- }
3520
- `,
3521
- }]
3522
- }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], headerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationHeaderComponent), { isSignal: true }] }], contentSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationContentComponent), { isSignal: true }] }], footerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationFooterComponent), { isSignal: true }] }] } });
3523
-
3524
- /**
3525
- * Type navbar horizontal untuk `<Navigation>`. Slot `NavigationHeader`
3526
- * dan `NavigationFooter` opsional; `NavigationContent` selalu dirender
3527
- * (default otomatis bila tidak diproyeksikan).
3528
- */
3529
- class NavigationNavbarComponent {
3530
- container = inject(NavigationContainerComponent);
3531
- destroyRef = inject(DestroyRef);
3532
- /** Posisi bar terhadap konten layout: `top` (default) atau `bottom` — panel grid membuka ke arah sebaliknya. */
3533
- position = input(null, { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'nav-position' });
3534
- typeStyle = input('flat', { ...(ngDevMode ? { debugName: "typeStyle" } : /* istanbul ignore next */ {}), alias: 'nav-appearance' });
3535
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3536
- headerSlot = contentChild(NavigationHeaderComponent, /* @ts-ignore */
3537
- ...(ngDevMode ? [{ debugName: "headerSlot" }] : /* istanbul ignore next */ []));
3538
- contentSlot = contentChild(NavigationContentComponent, /* @ts-ignore */
3539
- ...(ngDevMode ? [{ debugName: "contentSlot" }] : /* istanbul ignore next */ []));
3540
- footerSlot = contentChild(NavigationFooterComponent, /* @ts-ignore */
3541
- ...(ngDevMode ? [{ debugName: "footerSlot" }] : /* istanbul ignore next */ []));
3542
- hostClasses = computed(() => cn(this.container.shellClasses(), this.class()), /* @ts-ignore */
3543
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3544
- constructor() {
3545
- const config = {
3546
- orientation: 'horizontal',
3547
- type: 'navbar',
3548
- position: this.position,
3549
- typeStyle: this.typeStyle,
3550
- };
3551
- this.container.registerType(config);
3552
- this.destroyRef.onDestroy(() => this.container.unregisterType(config));
3553
- }
3554
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationNavbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3555
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationNavbarComponent, isStandalone: true, selector: "NavigationNavbar", inputs: { position: { classPropertyName: "position", publicName: "nav-position", isSignal: true, isRequired: false, transformFunction: null }, typeStyle: { classPropertyName: "typeStyle", publicName: "nav-appearance", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "headerSlot", first: true, predicate: NavigationHeaderComponent, descendants: true, isSignal: true }, { propertyName: "contentSlot", first: true, predicate: NavigationContentComponent, descendants: true, isSignal: true }, { propertyName: "footerSlot", first: true, predicate: NavigationFooterComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
3556
- @if (headerSlot()) {
3557
- <ng-content select="NavigationHeader" />
3558
- }
3559
-
3560
- @if (contentSlot()) {
3561
- <ng-content select="NavigationContent" />
3562
- } @else {
3563
- <NavigationContent />
3564
- }
3565
-
3566
- @if (footerSlot()) {
3567
- <ng-content select="NavigationFooter" />
3568
- }
3569
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationContentComponent, selector: "NavigationContent", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3570
- }
3571
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationNavbarComponent, decorators: [{
3572
- type: Component,
3573
- args: [{
3574
- selector: 'NavigationNavbar',
3575
- changeDetection: ChangeDetectionStrategy.OnPush,
3576
- imports: [NavigationContentComponent],
3577
- host: {
3578
- '[class]': 'hostClasses()',
3579
- },
3580
- template: `
3581
- @if (headerSlot()) {
3582
- <ng-content select="NavigationHeader" />
3583
- }
3584
-
3585
- @if (contentSlot()) {
3586
- <ng-content select="NavigationContent" />
3587
- } @else {
3588
- <NavigationContent />
3589
- }
3590
-
3591
- @if (footerSlot()) {
3592
- <ng-content select="NavigationFooter" />
3593
- }
3594
- `,
3595
- }]
3596
- }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-position", required: false }] }], typeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-appearance", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], headerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationHeaderComponent), { isSignal: true }] }], contentSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationContentComponent), { isSignal: true }] }], footerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationFooterComponent), { isSignal: true }] }] } });
3597
-
3598
- /**
3599
- * Type flyout horizontal (trigger + panel menu) untuk `<Navigation>`.
3600
- * Slot `NavigationHeader` dan `NavigationFooter` opsional; `NavigationContent`
3601
- * selalu dirender (default otomatis bila tidak diproyeksikan).
3602
- */
3603
- class NavigationFlyoutComponent {
3604
- container = inject(NavigationContainerComponent);
3605
- destroyRef = inject(DestroyRef);
3606
- label = input('Menu', /* @ts-ignore */
3607
- ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
3608
- /** Nama Material Symbols untuk trigger (mis. `apps`, `menu`); `null` = label saja. */
3609
- icon = input(null, /* @ts-ignore */
3610
- ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
3611
- /** Trigger hanya menampilkan ikon; label tetap dipakai sebagai aria-label/title. */
3612
- iconOnly = input(false, { ...(ngDevMode ? { debugName: "iconOnly" } : /* istanbul ignore next */ {}), alias: 'icon-only', transform: booleanAttribute });
3613
- /** Penempatan ikon relatif terhadap label: `start` (default) atau `end`. */
3614
- iconPosition = input('start', { ...(ngDevMode ? { debugName: "iconPosition" } : /* istanbul ignore next */ {}), alias: 'icon-position' });
3615
- /** Bentuk visual tombol trigger: `button` (pil, default) | `link` | `plain` (ghost). */
3616
- triggerVariant = input('button', { ...(ngDevMode ? { debugName: "triggerVariant" } : /* istanbul ignore next */ {}), alias: 'trigger-variant' });
3617
- /**
3618
- * Trigger mengambang (`fixed`) alih-alih mengalir di dalam bar/div. Default pojok kanan-atas;
3619
- * pakai `trigger-class` untuk pindah pojok (mis. `bottom-6 right-6 top-auto`).
3620
- *
3621
- * Catatan: `position: fixed` ber-anchor ke viewport HANYA bila tak ada ancestor pembentuk
3622
- * containing block. Di dalam `<Layout>` (frame-nya memakai `backdrop-blur`), trigger ber-anchor
3623
- * ke kotak konten frame (bukan viewport sebenarnya) dan bisa ter-clip oleh frame `overflow-hidden`.
3624
- * Untuk floating sebenar-viewport, tempatkan `<Navigation>` flyout di luar frame `<Layout>`.
3625
- */
3626
- triggerFloating = input(false, { ...(ngDevMode ? { debugName: "triggerFloating" } : /* istanbul ignore next */ {}), alias: 'trigger-floating',
3627
- transform: booleanAttribute });
3628
- /** Kelas Tailwind untuk host trigger (posisi pojok floating / styling wrapper saat in-flow). */
3629
- triggerClass = input('', { ...(ngDevMode ? { debugName: "triggerClass" } : /* istanbul ignore next */ {}), alias: 'trigger-class' });
3630
- /** Posisi bar terhadap konten layout: `top` (default) atau `bottom` — panel membuka ke arah sebaliknya. */
3631
- position = input(null, { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'nav-position' });
3632
- typeStyle = input('flat', { ...(ngDevMode ? { debugName: "typeStyle" } : /* istanbul ignore next */ {}), alias: 'nav-appearance' });
3633
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3634
- hostClasses = computed(() => cn(this.container.shellClasses(), this.class()), /* @ts-ignore */
3635
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3636
- constructor() {
3637
- const config = {
3638
- orientation: 'horizontal',
3639
- type: 'flyout',
3640
- position: this.position,
3641
- flyoutLabel: this.label,
3642
- flyoutIcon: this.icon,
3643
- flyoutIconOnly: this.iconOnly,
3644
- flyoutIconPosition: this.iconPosition,
3645
- flyoutTriggerVariant: this.triggerVariant,
3646
- flyoutTriggerFloating: this.triggerFloating,
3647
- flyoutTriggerClass: this.triggerClass,
3648
- typeStyle: this.typeStyle,
3649
- };
3650
- this.container.registerType(config);
3651
- this.destroyRef.onDestroy(() => this.container.unregisterType(config));
3652
- }
3653
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFlyoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3654
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.3", type: NavigationFlyoutComponent, isStandalone: true, selector: "NavigationFlyout", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "icon-only", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "icon-position", isSignal: true, isRequired: false, transformFunction: null }, triggerVariant: { classPropertyName: "triggerVariant", publicName: "trigger-variant", isSignal: true, isRequired: false, transformFunction: null }, triggerFloating: { classPropertyName: "triggerFloating", publicName: "trigger-floating", isSignal: true, isRequired: false, transformFunction: null }, triggerClass: { classPropertyName: "triggerClass", publicName: "trigger-class", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "nav-position", isSignal: true, isRequired: false, transformFunction: null }, typeStyle: { classPropertyName: "typeStyle", publicName: "nav-appearance", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
3655
- <!-- Bar hanya berisi trigger (dari NavigationContent → FlyoutMenu); NavigationHeader &
3656
- NavigationFooter di-re-project ke DALAM panel flyout saat dibuka. Urutan dibaca dari sisi
3657
- bar ke arah luar: header (menempel bar, sticky) → menu → footer (ujung jauh). Mode top:
3658
- brand atas, logout bawah; mode bottom: cerminannya (brand bawah dekat bar, logout atas). -->
3659
- <NavigationContent>
3660
- <ng-content select="NavigationHeader" ngProjectAs="NavigationHeader" />
3661
- <ng-content select="NavigationFooter" ngProjectAs="NavigationFooter" />
3662
- </NavigationContent>
3663
- `, isInline: true, dependencies: [{ kind: "component", type: NavigationContentComponent, selector: "NavigationContent", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3664
- }
3665
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFlyoutComponent, decorators: [{
3666
- type: Component,
3667
- args: [{
3668
- selector: 'NavigationFlyout',
3669
- changeDetection: ChangeDetectionStrategy.OnPush,
3670
- imports: [NavigationContentComponent],
3671
- host: {
3672
- '[class]': 'hostClasses()',
3673
- },
3674
- template: `
3675
- <!-- Bar hanya berisi trigger (dari NavigationContent → FlyoutMenu); NavigationHeader &
3676
- NavigationFooter di-re-project ke DALAM panel flyout saat dibuka. Urutan dibaca dari sisi
3677
- bar ke arah luar: header (menempel bar, sticky) → menu → footer (ujung jauh). Mode top:
3678
- brand atas, logout bawah; mode bottom: cerminannya (brand bawah dekat bar, logout atas). -->
3679
- <NavigationContent>
3680
- <ng-content select="NavigationHeader" ngProjectAs="NavigationHeader" />
3681
- <ng-content select="NavigationFooter" ngProjectAs="NavigationFooter" />
3682
- </NavigationContent>
3683
- `,
3684
- }]
3685
- }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon-only", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon-position", required: false }] }], triggerVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger-variant", required: false }] }], triggerFloating: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger-floating", required: false }] }], triggerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger-class", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-position", required: false }] }], typeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-appearance", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3686
-
3687
- /**
3688
- * Tampilan compact aktif saat sidebar collapsible sedang collapsed, atau saat
3689
- * type dockbar aktif — rail dockbar selalu selebar ikon (`w-16`) sehingga
3690
- * konten expanded tidak pernah muat.
3691
- */
3692
- function isCompactDisplay(shell) {
3693
- const state = shell.displayState();
3694
- if (state.orientation !== 'vertical') {
3695
- return false;
3696
- }
3697
- if (state.type === 'dockbar') {
3698
- return true;
3699
- }
3700
- return shell.collapseEnabled() && state.collapsed;
3701
- }
3702
- class NavigationCollapseRootDirective {
3703
- shell = inject(NAVIGATION_SHELL);
3704
- collapseEnabled = computed(() => {
3705
- const state = this.shell.displayState();
3706
- return state.orientation === 'vertical' && (this.shell.collapseEnabled() || state.type === 'dockbar');
3707
- }, /* @ts-ignore */
3708
- ...(ngDevMode ? [{ debugName: "collapseEnabled" }] : /* istanbul ignore next */ []));
3709
- displayCollapsed = computed(() => isCompactDisplay(this.shell), /* @ts-ignore */
3710
- ...(ngDevMode ? [{ debugName: "displayCollapsed" }] : /* istanbul ignore next */ []));
3711
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationCollapseRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3712
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.3", type: NavigationCollapseRootDirective, isStandalone: true, selector: "[NavigationCollapseRoot]", host: { properties: { "class.w-full": "collapseEnabled()", "class.justify-center": "displayCollapsed()" } }, ngImport: i0 });
3713
- }
3714
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationCollapseRootDirective, decorators: [{
3715
- type: Directive,
3716
- args: [{
3717
- selector: '[NavigationCollapseRoot]',
3718
- host: {
3719
- '[class.w-full]': 'collapseEnabled()',
3720
- '[class.justify-center]': 'displayCollapsed()',
3721
- },
3722
- }]
3723
- }] });
3724
- class NavigationCollapseExpandedDirective {
3725
- shell = inject(NAVIGATION_SHELL);
3726
- templateRef = inject((TemplateRef));
3727
- viewContainer = inject(ViewContainerRef);
3728
- hasView = false;
3729
- shouldRender = computed(() => !isCompactDisplay(this.shell), /* @ts-ignore */
3730
- ...(ngDevMode ? [{ debugName: "shouldRender" }] : /* istanbul ignore next */ []));
3731
- constructor() {
3732
- effect(() => {
3733
- if (this.shouldRender()) {
3734
- if (!this.hasView) {
3735
- this.viewContainer.createEmbeddedView(this.templateRef);
3736
- this.hasView = true;
3737
- }
3738
- return;
3739
- }
3740
- if (this.hasView) {
3741
- this.viewContainer.clear();
3742
- this.hasView = false;
3743
- }
3744
- });
3745
- }
3746
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationCollapseExpandedDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3747
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.3", type: NavigationCollapseExpandedDirective, isStandalone: true, selector: "[NavigationCollapseExpanded]", ngImport: i0 });
3748
- }
3749
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationCollapseExpandedDirective, decorators: [{
3750
- type: Directive,
3751
- args: [{
3752
- selector: '[NavigationCollapseExpanded]',
3753
- }]
3754
- }], ctorParameters: () => [] });
3755
-
3756
- /**
3757
- * Slot aksi di sisi kanan `NavigationFooter`. Selalu didorong ke kanan (`ml-auto`),
3758
- * rata tengah vertikal, dengan jarak antar-child otomatis (`gap`). Isi bebas dengan
3759
- * ikon, button, atau teks — mis. tombol logout.
3760
- *
3761
- * Otomatis disembunyikan saat sidebar vertical sedang collapsed (rail icon-only)
3762
- * agar tidak overflow; konsisten dengan `NavigationFooterTitle`.
3763
- */
3764
- class NavigationFooterActionComponent {
3765
- shell = inject(NAVIGATION_SHELL, { optional: true });
3766
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3767
- collapsed = computed(() => {
3768
- const state = this.shell?.displayState();
3769
- return state ? state.orientation === 'vertical' && state.collapsed : false;
3770
- }, /* @ts-ignore */
3771
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3772
- hostClasses = computed(() => cn(this.collapsed() ? 'hidden' : 'ml-auto flex shrink-0 items-center gap-1', this.class()), /* @ts-ignore */
3773
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3774
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3775
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.3", type: NavigationFooterActionComponent, isStandalone: true, selector: "NavigationFooterAction", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
3776
- }
3777
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterActionComponent, decorators: [{
3778
- type: Component,
3779
- args: [{
3780
- selector: 'NavigationFooterAction',
3781
- changeDetection: ChangeDetectionStrategy.OnPush,
3782
- host: {
3783
- '[class]': 'hostClasses()',
3784
- },
3785
- template: `<ng-content />`,
3786
- }]
3787
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3788
-
3789
- /**
3790
- * Turunkan inisial ringkas dari sebuah nama untuk avatar fallback.
3791
- *
3792
- * "Ojie Permana" → "OP"
3793
- * "Ojiepermana" → "OJ"
3794
- * "" → ""
3795
- *
3796
- * Mengambil huruf depan kata pertama dan kata terakhir; bila hanya satu kata,
3797
- * memakai dua huruf pertamanya.
3798
- */
3799
- function deriveNavigationInitials(name) {
3800
- const parts = name.trim().split(/\s+/).filter(Boolean);
3801
- if (parts.length === 0) {
3802
- return '';
3803
- }
3804
- const first = parts[0] ?? '';
3805
- if (parts.length === 1) {
3806
- return first.slice(0, 2).toUpperCase();
3807
- }
3808
- const last = parts[parts.length - 1] ?? '';
3809
- return (first.charAt(0) + last.charAt(0)).toUpperCase();
3810
- }
3811
-
3812
- /**
3813
- * Blok avatar/inisial untuk slot `NavigationFooter` (profil user). Sama seperti
3814
- * `NavigationHeaderInitial` tetapi default-nya bulat (rounded-full) sesuai
3815
- * konvensi avatar user. Consumer cukup memberi `name`; inisial diturunkan
3816
- * otomatis. Beri `src` untuk foto, `icon` untuk material symbol, atau `initials`
3817
- * untuk override.
3818
- *
3819
- * Tetap tampil saat sidebar collapsed; pasangannya `NavigationFooterTitle` yang
3820
- * menyembunyikan diri.
3821
- */
3822
- class NavigationFooterInitialComponent {
3823
- name = input('', /* @ts-ignore */
3824
- ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
3825
- src = input(null, /* @ts-ignore */
3826
- ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
3827
- initials = input(null, /* @ts-ignore */
3828
- ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
3829
- icon = input(null, /* @ts-ignore */
3830
- ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
3831
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3832
- resolvedInitials = computed(() => this.initials()?.slice(0, 2).toUpperCase() || deriveNavigationInitials(this.name()), /* @ts-ignore */
3833
- ...(ngDevMode ? [{ debugName: "resolvedInitials" }] : /* istanbul ignore next */ []));
3834
- hostClasses = computed(() => cn('inline-flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary/10 text-primary', this.class()), /* @ts-ignore */
3835
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3836
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterInitialComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3837
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationFooterInitialComponent, isStandalone: true, selector: "NavigationFooterInitial", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.role": "name() ? 'img' : null", "attr.aria-label": "name() || null" } }, ngImport: i0, template: `
3838
- @if (src(); as source) {
3839
- <img [src]="source" alt="" class="h-full w-full rounded-[inherit] object-cover" />
3840
- } @else if (icon(); as glyph) {
3841
- <Icon [name]="glyph" [size]="18" />
3842
- } @else {
3843
- <span class="text-xs font-semibold leading-none">{{ resolvedInitials() }}</span>
3844
- }
3845
- `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3846
- }
3847
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterInitialComponent, decorators: [{
3848
- type: Component,
3849
- args: [{
3850
- selector: 'NavigationFooterInitial',
3851
- changeDetection: ChangeDetectionStrategy.OnPush,
3852
- imports: [IconComponent],
3853
- host: {
3854
- '[class]': 'hostClasses()',
3855
- '[attr.role]': "name() ? 'img' : null",
3856
- '[attr.aria-label]': 'name() || null',
3857
- },
3858
- template: `
3859
- @if (src(); as source) {
3860
- <img [src]="source" alt="" class="h-full w-full rounded-[inherit] object-cover" />
3861
- } @else if (icon(); as glyph) {
3862
- <Icon [name]="glyph" [size]="18" />
3863
- } @else {
3864
- <span class="text-xs font-semibold leading-none">{{ resolvedInitials() }}</span>
3865
- }
3866
- `,
3867
- }]
3868
- }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3869
-
3870
- /**
3871
- * Judul + subjudul untuk slot `NavigationFooter` (mis. nama + email user).
3872
- * Otomatis disembunyikan saat sidebar vertical sedang collapsed (rail icon-only)
3873
- * dengan membaca `NAVIGATION_SHELL`.
3874
- */
3875
- class NavigationFooterTitleComponent {
3876
- shell = inject(NAVIGATION_SHELL, { optional: true });
3877
- title = input('', /* @ts-ignore */
3878
- ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
3879
- subtitle = input(null, /* @ts-ignore */
3880
- ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
3881
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3882
- collapsed = computed(() => {
3883
- const state = this.shell?.displayState();
3884
- return state ? state.orientation === 'vertical' && state.collapsed : false;
3885
- }, /* @ts-ignore */
3886
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3887
- hostClasses = computed(() => cn(this.collapsed() ? 'hidden' : 'flex min-w-0 flex-col justify-center', this.class()), /* @ts-ignore */
3888
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3889
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3890
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationFooterTitleComponent, isStandalone: true, selector: "NavigationFooterTitle", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.data-collapsed": "collapsed()" } }, ngImport: i0, template: `
3891
- <span class="block truncate text-sm font-semibold leading-tight text-foreground">{{ title() }}</span>
3892
- @if (subtitle(); as sub) {
3893
- <span class="block truncate text-xs leading-tight text-muted-foreground">{{ sub }}</span>
3894
- }
3895
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
3896
- }
3897
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationFooterTitleComponent, decorators: [{
3898
- type: Component,
3899
- args: [{
3900
- selector: 'NavigationFooterTitle',
3901
- changeDetection: ChangeDetectionStrategy.OnPush,
3902
- host: {
3903
- '[class]': 'hostClasses()',
3904
- '[attr.data-collapsed]': 'collapsed()',
3905
- },
3906
- template: `
3907
- <span class="block truncate text-sm font-semibold leading-tight text-foreground">{{ title() }}</span>
3908
- @if (subtitle(); as sub) {
3909
- <span class="block truncate text-xs leading-tight text-muted-foreground">{{ sub }}</span>
3910
- }
3911
- `,
3912
- }]
3913
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3914
-
3915
- /**
3916
- * Blok avatar/inisial untuk slot `NavigationHeader` (brand/logo). Consumer cukup
3917
- * memberi `name`; inisial diturunkan otomatis ("Ojie Permana" → "OP"). Beri `src`
3918
- * untuk gambar, `icon` (material symbol) sebagai ganti inisial, atau `initials`
3919
- * untuk override manual.
3920
- *
3921
- * Selalu tampil baik saat sidebar expanded maupun collapsed karena ukurannya muat
3922
- * di rail icon-only — pasangannya, `NavigationHeaderTitle`, yang menyembunyikan
3923
- * diri saat collapsed.
3924
- */
3925
- class NavigationHeaderInitialComponent {
3926
- name = input('', /* @ts-ignore */
3927
- ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
3928
- src = input(null, /* @ts-ignore */
3929
- ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
3930
- initials = input(null, /* @ts-ignore */
3931
- ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
3932
- icon = input(null, /* @ts-ignore */
3933
- ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
3934
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3935
- resolvedInitials = computed(() => this.initials()?.slice(0, 2).toUpperCase() || deriveNavigationInitials(this.name()), /* @ts-ignore */
3936
- ...(ngDevMode ? [{ debugName: "resolvedInitials" }] : /* istanbul ignore next */ []));
3937
- hostClasses = computed(() => cn('inline-flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-md bg-primary/10 text-primary', this.class()), /* @ts-ignore */
3938
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3939
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderInitialComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3940
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationHeaderInitialComponent, isStandalone: true, selector: "NavigationHeaderInitial", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.role": "name() ? 'img' : null", "attr.aria-label": "name() || null" } }, ngImport: i0, template: `
3941
- @if (src(); as source) {
3942
- <img [src]="source" alt="" class="h-full w-full rounded-[inherit] object-cover" />
3943
- } @else if (icon(); as glyph) {
3944
- <Icon [name]="glyph" [size]="18" />
3945
- } @else {
3946
- <span class="text-xs font-semibold leading-none">{{ resolvedInitials() }}</span>
3947
- }
3948
- `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "Icon", inputs: ["name", "class", "size", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3949
- }
3950
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderInitialComponent, decorators: [{
3951
- type: Component,
3952
- args: [{
3953
- selector: 'NavigationHeaderInitial',
3954
- changeDetection: ChangeDetectionStrategy.OnPush,
3955
- imports: [IconComponent],
3956
- host: {
3957
- '[class]': 'hostClasses()',
3958
- '[attr.role]': "name() ? 'img' : null",
3959
- '[attr.aria-label]': 'name() || null',
3960
- },
3961
- template: `
3962
- @if (src(); as source) {
3963
- <img [src]="source" alt="" class="h-full w-full rounded-[inherit] object-cover" />
3964
- } @else if (icon(); as glyph) {
3965
- <Icon [name]="glyph" [size]="18" />
3966
- } @else {
3967
- <span class="text-xs font-semibold leading-none">{{ resolvedInitials() }}</span>
3968
- }
3969
- `,
3970
- }]
3971
- }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3972
-
3973
- /**
3974
- * Judul + subjudul untuk slot `NavigationHeader`. Otomatis disembunyikan saat
3975
- * sidebar vertical sedang collapsed (rail icon-only) dengan membaca
3976
- * `NAVIGATION_SHELL` — consumer tidak perlu mengelola state collapse sendiri.
3977
- */
3978
- class NavigationHeaderTitleComponent {
3979
- shell = inject(NAVIGATION_SHELL, { optional: true });
3980
- title = input('', /* @ts-ignore */
3981
- ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
3982
- subtitle = input(null, /* @ts-ignore */
3983
- ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
3984
- class = input('', { ...(ngDevMode ? { debugName: "class" } : /* istanbul ignore next */ {}), alias: 'class' });
3985
- collapsed = computed(() => {
3986
- const state = this.shell?.displayState();
3987
- return state ? state.orientation === 'vertical' && state.collapsed : false;
3988
- }, /* @ts-ignore */
3989
- ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3990
- hostClasses = computed(() => cn(this.collapsed() ? 'hidden' : 'flex min-w-0 flex-col justify-center', this.class()), /* @ts-ignore */
3991
- ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3992
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3993
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.3", type: NavigationHeaderTitleComponent, isStandalone: true, selector: "NavigationHeaderTitle", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.data-collapsed": "collapsed()" } }, ngImport: i0, template: `
3994
- <span class="block truncate text-sm font-semibold leading-tight text-foreground">{{ title() }}</span>
3995
- @if (subtitle(); as sub) {
3996
- <span class="block truncate text-xs leading-tight text-muted-foreground">{{ sub }}</span>
3997
- }
3998
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
3999
- }
4000
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImport: i0, type: NavigationHeaderTitleComponent, decorators: [{
4001
- type: Component,
4002
- args: [{
4003
- selector: 'NavigationHeaderTitle',
4004
- changeDetection: ChangeDetectionStrategy.OnPush,
4005
- host: {
4006
- '[class]': 'hostClasses()',
4007
- '[attr.data-collapsed]': 'collapsed()',
4008
- },
4009
- template: `
4010
- <span class="block truncate text-sm font-semibold leading-tight text-foreground">{{ title() }}</span>
4011
- @if (subtitle(); as sub) {
4012
- <span class="block truncate text-xs leading-tight text-muted-foreground">{{ sub }}</span>
4013
- }
4014
- `,
4015
- }]
4016
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
4017
-
4018
- /**
4019
- * Generated bundle index. Do not edit.
4020
- */
4021
-
4022
- export { NavigationCollapseExpandedDirective, NavigationCollapseRootDirective, NavigationContainerComponent, NavigationContentComponent, NavigationDockbarComponent, NavigationFlyoutComponent, NavigationFooterActionComponent, NavigationFooterComponent, NavigationFooterInitialComponent, NavigationFooterTitleComponent, NavigationHeaderComponent, NavigationHeaderInitialComponent, NavigationHeaderTitleComponent, NavigationIconDirective, NavigationNavbarComponent, NavigationSidebarComponent, deriveNavigationInitials, normalizeUiNavItems };
1
+ export { c as NavigationCollapseExpandedDirective, d as NavigationCollapseRootDirective, e as NavigationContainerComponent, f as NavigationContentComponent, g as NavigationDockbarComponent, h as NavigationFlyoutComponent, i as NavigationFooterActionComponent, j as NavigationFooterComponent, k as NavigationFooterInitialComponent, l as NavigationFooterTitleComponent, m as NavigationHeaderComponent, n as NavigationHeaderInitialComponent, o as NavigationHeaderTitleComponent, p as NavigationIconDirective, q as NavigationNavbarComponent, r as NavigationSidebarComponent, s as deriveNavigationInitials, t as normalizeUiNavItems } from './ojiepermana-angular-navigation-ojiepermana-angular-navigation-SlMGlTuA.mjs';