@ojiepermana/angular 0.1.1 → 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -249
- package/fesm2022/ojiepermana-angular-chart.mjs +3714 -0
- package/fesm2022/ojiepermana-angular-chart.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-component.mjs +3463 -0
- package/fesm2022/ojiepermana-angular-component.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-layout.mjs +276 -408
- package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-navigation.mjs +2198 -404
- package/fesm2022/ojiepermana-angular-navigation.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular-theme.mjs +381 -1
- package/fesm2022/ojiepermana-angular-theme.mjs.map +1 -1
- package/fesm2022/ojiepermana-angular.mjs +15 -1
- package/fesm2022/ojiepermana-angular.mjs.map +1 -1
- package/package.json +49 -36
- package/theme/styles/etos.css +38 -0
- package/theme/styles/index.css +32 -8
- package/theme/styles/themes/brand/etos/color.css +21 -0
- package/theme/styles/themes/brand/etos/style.css +50 -0
- package/theme/styles/themes/library/_components.css +63 -0
- package/theme/styles/themes/library/_layers.css +15 -0
- package/theme/styles/themes/library/_material-overrides.css +254 -0
- package/theme/styles/themes/library/_tokens.css +54 -0
- package/theme/styles/themes/library/color/amber.css +18 -0
- package/theme/styles/themes/library/color/blue.css +23 -0
- package/theme/styles/themes/library/color/green.css +18 -0
- package/theme/styles/themes/library/color/index.css +9 -0
- package/theme/styles/themes/library/color/purple.css +18 -0
- package/theme/styles/themes/library/color/red.css +18 -0
- package/theme/styles/themes/library/style/brutal.css +47 -0
- package/theme/styles/themes/library/style/default.css +51 -0
- package/theme/styles/themes/library/style/index.css +8 -0
- package/theme/styles/themes/library/style/sharp.css +47 -0
- package/theme/styles/themes/library/style/soft.css +47 -0
- package/theme/styles/themes/mode/dark.css +20 -0
- package/theme/styles/themes/mode/index.css +6 -0
- package/theme/styles/themes/mode/light.css +24 -0
- package/theme/styles/themes/taildwind.css +109 -0
- package/types/ojiepermana-angular-chart.d.ts +1094 -0
- package/types/ojiepermana-angular-component.d.ts +1174 -0
- package/types/ojiepermana-angular-layout.d.ts +123 -76
- package/types/ojiepermana-angular-navigation.d.ts +256 -116
- package/types/ojiepermana-angular-theme.d.ts +170 -1
- package/types/ojiepermana-angular.d.ts +2 -1
- package/fesm2022/ojiepermana-angular-internal.mjs +0 -489
- package/fesm2022/ojiepermana-angular-internal.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs +0 -721
- package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-navigation-vertical.mjs +0 -1647
- package/fesm2022/ojiepermana-angular-navigation-vertical.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-shell.mjs +0 -19
- package/fesm2022/ojiepermana-angular-shell.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-theme-component.mjs +0 -235
- package/fesm2022/ojiepermana-angular-theme-component.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-theme-directive.mjs +0 -29
- package/fesm2022/ojiepermana-angular-theme-directive.mjs.map +0 -1
- package/fesm2022/ojiepermana-angular-theme-service.mjs +0 -241
- package/fesm2022/ojiepermana-angular-theme-service.mjs.map +0 -1
- package/layout/README.md +0 -144
- package/layout/src/component/horizontal/horizontal.css +0 -130
- package/layout/src/component/vertical/vertical.css +0 -75
- package/layout/src/layout.css +0 -16
- package/navigation/README.md +0 -301
- package/navigation/horizontal/README.md +0 -49
- package/shell/README.md +0 -41
- package/styles/index.css +0 -2
- package/styles/resets.css +0 -22
- package/theme/README.md +0 -379
- package/theme/styles/adapters/material-ui/index.css +0 -205
- package/theme/styles/modes/dark.css +0 -84
- package/theme/styles/presets/colors/blue.css +0 -45
- package/theme/styles/presets/colors/brand.css +0 -52
- package/theme/styles/presets/colors/cyan.css +0 -45
- package/theme/styles/presets/colors/green.css +0 -45
- package/theme/styles/presets/colors/index.css +0 -7
- package/theme/styles/presets/colors/orange.css +0 -45
- package/theme/styles/presets/colors/purple.css +0 -45
- package/theme/styles/presets/colors/red.css +0 -45
- package/theme/styles/presets/styles/flat.css +0 -61
- package/theme/styles/presets/styles/glass.css +0 -28
- package/theme/styles/presets/styles/index.css +0 -2
- package/theme/styles/roles/index.css +0 -67
- package/theme/styles/tokens/foundation.css +0 -136
- package/theme/styles/tokens/semantic.css +0 -87
- package/theme/styles/utilities/index.css +0 -88
- package/types/ojiepermana-angular-internal.d.ts +0 -90
- package/types/ojiepermana-angular-navigation-horizontal.d.ts +0 -81
- package/types/ojiepermana-angular-navigation-vertical.d.ts +0 -262
- package/types/ojiepermana-angular-shell.d.ts +0 -14
- package/types/ojiepermana-angular-theme-component.d.ts +0 -46
- package/types/ojiepermana-angular-theme-directive.d.ts +0 -10
- package/types/ojiepermana-angular-theme-service.d.ts +0 -68
- /package/{navigation/vertical → chart}/README.md +0 -0
|
@@ -1,472 +1,2266 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { inject, DestroyRef, signal, computed, Injectable, PLATFORM_ID, input, ChangeDetectionStrategy, Component, ViewContainerRef, viewChild, effect, ElementRef } from '@angular/core';
|
|
3
|
+
import { Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router';
|
|
4
|
+
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { filter, map } from 'rxjs/operators';
|
|
6
|
+
import { DOCUMENT, isPlatformBrowser, NgClass, NgTemplateOutlet } from '@angular/common';
|
|
7
|
+
import { MatTooltip } from '@angular/material/tooltip';
|
|
8
|
+
import { clsx } from 'clsx';
|
|
9
|
+
import { twMerge } from 'tailwind-merge';
|
|
10
|
+
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
11
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
12
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
13
|
+
import { FocusTrapFactory } from '@angular/cdk/a11y';
|
|
14
|
+
import { merge } from 'rxjs';
|
|
4
15
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/** Default registry key used when no id is specified. */
|
|
17
|
+
const DEFAULT_NAVIGATION_ID = 'main';
|
|
18
|
+
/**
|
|
19
|
+
* Signal-based global state untuk navigation (sidebar/topbar).
|
|
20
|
+
*
|
|
21
|
+
* Items disimpan dalam registry ber-key. Key default adalah `'main'`.
|
|
22
|
+
* Komponen `ui-sidebar` / `ui-topbar` memilih registry via input `navigationId`.
|
|
23
|
+
*/
|
|
24
|
+
class NavigationService {
|
|
25
|
+
router = inject(Router);
|
|
26
|
+
destroyRef = inject(DestroyRef);
|
|
27
|
+
/** Internal version counter — incremented on every registry mutation. */
|
|
28
|
+
_version = signal(0, ...(ngDevMode ? [{ debugName: "_version" }] : /* istanbul ignore next */ []));
|
|
29
|
+
/** Internal map of registered navigation trees. */
|
|
30
|
+
_registry = new Map();
|
|
31
|
+
/**
|
|
32
|
+
* Backward-compatible accessor — returns items for the default (`'main'`) key.
|
|
33
|
+
* Prefer `getItems(id)` when working with named registries.
|
|
34
|
+
*/
|
|
35
|
+
items = computed(() => this.getItems(DEFAULT_NAVIGATION_ID)(), ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
36
|
+
/** Sidebar collapsed (default ↔ thin) toggle untuk desktop. */
|
|
37
|
+
collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
38
|
+
/** Sheet drawer terbuka di mobile. */
|
|
39
|
+
mobileOpen = signal(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
|
|
40
|
+
/** Set id grup / collapsable yang sedang terbuka. */
|
|
41
|
+
openGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "openGroups" }] : /* istanbul ignore next */ []));
|
|
42
|
+
/** URL aktif terakhir. Update otomatis dari Router `NavigationEnd`. */
|
|
43
|
+
activeUrl = signal(this.router.url, ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
|
|
44
|
+
/** Trail id item yang sedang match dengan URL aktif (across ALL registries). */
|
|
45
|
+
activeTrail = computed(() => {
|
|
46
|
+
this._version(); // track changes
|
|
47
|
+
const url = this.activeUrl();
|
|
48
|
+
const trail = new Set();
|
|
49
|
+
const walk = (list, ancestors) => {
|
|
50
|
+
let matched = false;
|
|
51
|
+
for (const item of list) {
|
|
52
|
+
const id = item.id;
|
|
53
|
+
const link = 'link' in item ? item.link : undefined;
|
|
54
|
+
let selfMatch = false;
|
|
55
|
+
if (link) {
|
|
56
|
+
selfMatch = url === link || url.startsWith(link + '/') || url.startsWith(link + '?');
|
|
57
|
+
}
|
|
58
|
+
const children = 'children' in item ? (item.children ?? []) : [];
|
|
59
|
+
const nextAncestors = id ? [...ancestors, id] : ancestors;
|
|
60
|
+
const childMatch = children.length > 0 && walk(children, nextAncestors);
|
|
61
|
+
if (selfMatch || childMatch) {
|
|
62
|
+
if (id)
|
|
63
|
+
trail.add(id);
|
|
64
|
+
for (const a of ancestors)
|
|
65
|
+
trail.add(a);
|
|
66
|
+
matched = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return matched;
|
|
70
|
+
};
|
|
71
|
+
for (const items of this._registry.values()) {
|
|
72
|
+
walk(items, []);
|
|
73
|
+
}
|
|
74
|
+
return trail;
|
|
75
|
+
}, ...(ngDevMode ? [{ debugName: "activeTrail" }] : /* istanbul ignore next */ []));
|
|
76
|
+
constructor() {
|
|
77
|
+
this.router.events
|
|
78
|
+
.pipe(filter((e) => e instanceof NavigationEnd), takeUntilDestroyed(this.destroyRef))
|
|
79
|
+
.subscribe((e) => this.activeUrl.set(e.urlAfterRedirects));
|
|
17
80
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function isVerticalNavigationAppearance$1(value) {
|
|
23
|
-
return value === 'default' || value === 'collapsible';
|
|
24
|
-
}
|
|
25
|
-
function normalizeHorizontalVariant(value) {
|
|
26
|
-
if (typeof value === 'undefined' || isHorizontalNavigationVariant$1(value)) {
|
|
27
|
-
return value ?? DEFAULT_NG_NAVIGATION_CONFIG.defaultHorizontalVariant;
|
|
81
|
+
registerItems(idOrItems, maybeItems) {
|
|
82
|
+
const [id, items] = typeof idOrItems === 'string' ? [idOrItems, maybeItems] : [DEFAULT_NAVIGATION_ID, idOrItems];
|
|
83
|
+
this._registry.set(id, items);
|
|
84
|
+
this._version.update((v) => v + 1);
|
|
28
85
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (typeof value === 'undefined' || isVerticalNavigationAppearance$1(value)) {
|
|
34
|
-
return value ?? DEFAULT_NG_NAVIGATION_CONFIG.defaultVerticalVariant;
|
|
86
|
+
/** Remove a named registry entry. */
|
|
87
|
+
removeItems(id) {
|
|
88
|
+
this._registry.delete(id);
|
|
89
|
+
this._version.update((v) => v + 1);
|
|
35
90
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
function provideNgNavigation(config = {}) {
|
|
47
|
-
return makeEnvironmentProviders([{ provide: NG_NAVIGATION_CONFIG, useValue: normalizeNavigationConfig(config) }]);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function getNavigationItemAction(item) {
|
|
51
|
-
return isNavigationRoutableItem(item) ? item.action : undefined;
|
|
52
|
-
}
|
|
53
|
-
function getNavigationItemVisibilityHandler(item) {
|
|
54
|
-
return item.isHidden;
|
|
55
|
-
}
|
|
56
|
-
function isNavigationItemHidden(item) {
|
|
57
|
-
return !!getNavigationItemVisibilityHandler(item)?.(item);
|
|
58
|
-
}
|
|
59
|
-
function shouldRenderNavigationItem(item) {
|
|
60
|
-
return !isNavigationItemHidden(item);
|
|
61
|
-
}
|
|
62
|
-
function hasNavigationChildren(item) {
|
|
63
|
-
return Array.isArray(item.children) && item.children.length > 0;
|
|
64
|
-
}
|
|
65
|
-
function getNavigationChildren(item) {
|
|
66
|
-
return Array.isArray(item.children) ? item.children : [];
|
|
67
|
-
}
|
|
68
|
-
function isNavigationRoutableItem(item) {
|
|
69
|
-
return item.type === 'basic' || item.type === 'aside' || item.type === 'collapsable';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
class NavigationStorageAdapter {
|
|
73
|
-
config;
|
|
74
|
-
constructor(config) {
|
|
75
|
-
this.config = config;
|
|
91
|
+
/**
|
|
92
|
+
* Computed yang mengembalikan items untuk key tertentu.
|
|
93
|
+
* Reactive terhadap perubahan registry.
|
|
94
|
+
*/
|
|
95
|
+
getItems(id) {
|
|
96
|
+
return computed(() => {
|
|
97
|
+
this._version(); // track changes
|
|
98
|
+
return this._registry.get(id) ?? [];
|
|
99
|
+
});
|
|
76
100
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
this.config.storage.removeItem(this.key(axis));
|
|
82
|
-
this.config.storage.removeItem(this.legacyKey(axis));
|
|
101
|
+
/** Toggle sidebar collapsed (default ↔ thin). */
|
|
102
|
+
toggleCollapsed() {
|
|
103
|
+
this.collapsed.update((v) => !v);
|
|
83
104
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
this.config.storage.setItem(this.key(axis), value);
|
|
89
|
-
this.config.storage.removeItem(this.legacyKey(axis));
|
|
105
|
+
setCollapsed(value) {
|
|
106
|
+
this.collapsed.set(value);
|
|
90
107
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return fallback;
|
|
94
|
-
}
|
|
95
|
-
const storedValue = this.config.storage.getItem(this.key(axis));
|
|
96
|
-
if (storedValue && isValid(storedValue)) {
|
|
97
|
-
return storedValue;
|
|
98
|
-
}
|
|
99
|
-
const legacyValue = this.config.storage.getItem(this.legacyKey(axis));
|
|
100
|
-
if (legacyValue && isValid(legacyValue)) {
|
|
101
|
-
this.config.storage.setItem(this.key(axis), legacyValue);
|
|
102
|
-
this.config.storage.removeItem(this.legacyKey(axis));
|
|
103
|
-
return legacyValue;
|
|
104
|
-
}
|
|
105
|
-
return fallback;
|
|
108
|
+
openMobile() {
|
|
109
|
+
this.mobileOpen.set(true);
|
|
106
110
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (storedValue !== null) {
|
|
113
|
-
return storedValue;
|
|
114
|
-
}
|
|
115
|
-
const legacyValue = this.config.storage.getItem(this.legacyKey(axis));
|
|
116
|
-
if (legacyValue !== null) {
|
|
117
|
-
this.config.storage.setItem(this.key(axis), legacyValue);
|
|
118
|
-
this.config.storage.removeItem(this.legacyKey(axis));
|
|
119
|
-
return legacyValue;
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
111
|
+
closeMobile() {
|
|
112
|
+
this.mobileOpen.set(false);
|
|
113
|
+
}
|
|
114
|
+
toggleMobile() {
|
|
115
|
+
this.mobileOpen.update((v) => !v);
|
|
122
116
|
}
|
|
123
|
-
|
|
124
|
-
return this.
|
|
117
|
+
isGroupOpen(id) {
|
|
118
|
+
return this.openGroups().has(id);
|
|
125
119
|
}
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
toggleGroup(id) {
|
|
121
|
+
const next = new Set(this.openGroups());
|
|
122
|
+
if (next.has(id))
|
|
123
|
+
next.delete(id);
|
|
124
|
+
else
|
|
125
|
+
next.add(id);
|
|
126
|
+
this.openGroups.set(next);
|
|
128
127
|
}
|
|
128
|
+
setGroupOpen(id, open) {
|
|
129
|
+
const next = new Set(this.openGroups());
|
|
130
|
+
if (open)
|
|
131
|
+
next.add(id);
|
|
132
|
+
else
|
|
133
|
+
next.delete(id);
|
|
134
|
+
this.openGroups.set(next);
|
|
135
|
+
}
|
|
136
|
+
/** Apakah id termasuk dalam active trail saat ini. */
|
|
137
|
+
isActive(id) {
|
|
138
|
+
return !!id && this.activeTrail().has(id);
|
|
139
|
+
}
|
|
140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: NavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
141
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: NavigationService, providedIn: 'root' });
|
|
129
142
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: NavigationService, decorators: [{
|
|
144
|
+
type: Injectable,
|
|
145
|
+
args: [{ providedIn: 'root' }]
|
|
146
|
+
}], ctorParameters: () => [] });
|
|
147
|
+
|
|
148
|
+
const MATERIAL_SYMBOLS_FONT_ATTR = 'data-ui-nav-icon-font';
|
|
149
|
+
const MATERIAL_SYMBOLS_FONT_ID = 'material-symbols-outlined';
|
|
150
|
+
const MATERIAL_SYMBOLS_FONT_HREF = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0';
|
|
151
|
+
/**
|
|
152
|
+
* Material Symbols icon renderer.
|
|
153
|
+
* Menyuntikkan stylesheet font sekali saat dipakai agar consumer tidak perlu
|
|
154
|
+
* menambahkan `<link>` manual di `index.html`.
|
|
155
|
+
*/
|
|
156
|
+
class UiNavIconComponent {
|
|
157
|
+
doc = inject(DOCUMENT);
|
|
158
|
+
platformId = inject(PLATFORM_ID);
|
|
159
|
+
name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
160
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
161
|
+
size = input(null, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
162
|
+
fontVariationSettings = '"FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24';
|
|
163
|
+
constructor() {
|
|
164
|
+
this.ensureFontStylesheet();
|
|
165
|
+
}
|
|
166
|
+
classes = computed(() => {
|
|
167
|
+
const base = 'material-symbols-outlined inline-flex items-center justify-center leading-none select-none';
|
|
168
|
+
const extra = this.class();
|
|
169
|
+
return extra ? `${base} ${extra}` : base;
|
|
170
|
+
}, ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
171
|
+
ensureFontStylesheet() {
|
|
172
|
+
if (!isPlatformBrowser(this.platformId) || !this.doc.head)
|
|
173
|
+
return;
|
|
174
|
+
const existing = this.doc.head.querySelector(`link[${MATERIAL_SYMBOLS_FONT_ATTR}="${MATERIAL_SYMBOLS_FONT_ID}"]`);
|
|
175
|
+
if (existing)
|
|
176
|
+
return;
|
|
177
|
+
const link = this.doc.createElement('link');
|
|
178
|
+
link.rel = 'stylesheet';
|
|
179
|
+
link.href = MATERIAL_SYMBOLS_FONT_HREF;
|
|
180
|
+
link.setAttribute(MATERIAL_SYMBOLS_FONT_ATTR, MATERIAL_SYMBOLS_FONT_ID);
|
|
181
|
+
this.doc.head.appendChild(link);
|
|
182
|
+
}
|
|
183
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UiNavIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
184
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: UiNavIconComponent, isStandalone: true, selector: "ui-nav-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true", "translate": "no" }, properties: { "class": "classes()", "style.font-size.px": "size()", "style.font-variation-settings": "fontVariationSettings" } }, ngImport: i0, template: `{{ name() }}`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
139
185
|
}
|
|
140
|
-
|
|
141
|
-
|
|
186
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UiNavIconComponent, decorators: [{
|
|
187
|
+
type: Component,
|
|
188
|
+
args: [{
|
|
189
|
+
selector: 'ui-nav-icon',
|
|
190
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
191
|
+
host: {
|
|
192
|
+
'[class]': 'classes()',
|
|
193
|
+
'[style.font-size.px]': 'size()',
|
|
194
|
+
'[style.font-variation-settings]': 'fontVariationSettings',
|
|
195
|
+
'aria-hidden': 'true',
|
|
196
|
+
translate: 'no',
|
|
197
|
+
},
|
|
198
|
+
template: `{{ name() }}`,
|
|
199
|
+
}]
|
|
200
|
+
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
201
|
+
|
|
202
|
+
/** Concatenate and dedupe Tailwind class names. */
|
|
203
|
+
function cn(...inputs) {
|
|
204
|
+
return twMerge(clsx(inputs));
|
|
142
205
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Recursive navigation item renderer (vertical context).
|
|
209
|
+
*
|
|
210
|
+
* Menerima item polymorphic dan delegasi ke template sesuai `type`.
|
|
211
|
+
* Mega dirender sebagai group biasa saat muncul di konteks vertical.
|
|
212
|
+
*/
|
|
213
|
+
class UiNavItemComponent {
|
|
214
|
+
nav = inject(NavigationService);
|
|
215
|
+
cn = cn;
|
|
216
|
+
item = input.required(...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
|
|
217
|
+
level = input(0, ...(ngDevMode ? [{ debugName: "level" }] : /* istanbul ignore next */ []));
|
|
218
|
+
/** Compact / icon-only rendering (sidebar `thin`). */
|
|
219
|
+
compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
|
|
220
|
+
exactMatch = {
|
|
221
|
+
exact: true,
|
|
222
|
+
paths: 'exact',
|
|
223
|
+
queryParams: 'exact',
|
|
224
|
+
fragment: 'exact',
|
|
225
|
+
matrixParams: 'exact',
|
|
226
|
+
};
|
|
227
|
+
inexactMatch = {
|
|
228
|
+
paths: 'subset',
|
|
229
|
+
queryParams: 'subset',
|
|
230
|
+
fragment: 'ignored',
|
|
231
|
+
matrixParams: 'ignored',
|
|
232
|
+
};
|
|
233
|
+
type = computed(() => this.item().type, ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
234
|
+
groupItem = computed(() => this.item(), ...(ngDevMode ? [{ debugName: "groupItem" }] : /* istanbul ignore next */ []));
|
|
235
|
+
collapsableItem = computed(() => this.item(), ...(ngDevMode ? [{ debugName: "collapsableItem" }] : /* istanbul ignore next */ []));
|
|
236
|
+
megaItem = computed(() => this.item(), ...(ngDevMode ? [{ debugName: "megaItem" }] : /* istanbul ignore next */ []));
|
|
237
|
+
asideItem = computed(() => this.item(), ...(ngDevMode ? [{ debugName: "asideItem" }] : /* istanbul ignore next */ []));
|
|
238
|
+
basicItem = computed(() => this.item(), ...(ngDevMode ? [{ debugName: "basicItem" }] : /* istanbul ignore next */ []));
|
|
239
|
+
headingId = computed(() => {
|
|
240
|
+
const id = this.item().id ?? '';
|
|
241
|
+
return `nav-group-${id}`;
|
|
242
|
+
}, ...(ngDevMode ? [{ debugName: "headingId" }] : /* istanbul ignore next */ []));
|
|
243
|
+
isGroupOpen() {
|
|
244
|
+
const id = this.item().id;
|
|
245
|
+
if (!id)
|
|
246
|
+
return false;
|
|
247
|
+
// auto-open when any descendant is active
|
|
248
|
+
if (this.nav.isActive(id) && 'children' in this.item())
|
|
249
|
+
return true;
|
|
250
|
+
return this.nav.isGroupOpen(id);
|
|
146
251
|
}
|
|
147
|
-
|
|
148
|
-
return
|
|
252
|
+
isTrailActive() {
|
|
253
|
+
return this.nav.isActive(this.item().id);
|
|
149
254
|
}
|
|
150
|
-
|
|
151
|
-
|
|
255
|
+
toggleGroup() {
|
|
256
|
+
const id = this.item().id;
|
|
257
|
+
if (id)
|
|
258
|
+
this.nav.toggleGroup(id);
|
|
152
259
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
function parseExpandedItemIds(value) {
|
|
159
|
-
if (value === null) {
|
|
160
|
-
return [];
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
const parsed = JSON.parse(value);
|
|
164
|
-
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== 'string')) {
|
|
165
|
-
return null;
|
|
260
|
+
runAction() {
|
|
261
|
+
const item = this.item();
|
|
262
|
+
if ('action' in item && typeof item.action === 'function') {
|
|
263
|
+
item.action(item);
|
|
166
264
|
}
|
|
167
|
-
return normalizeExpandedItemIds(parsed);
|
|
168
265
|
}
|
|
169
|
-
|
|
170
|
-
|
|
266
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UiNavItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
267
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: UiNavItemComponent, isStandalone: true, selector: "ui-nav-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
268
|
+
@switch (type()) {
|
|
269
|
+
@case ('divider') {
|
|
270
|
+
<hr class="my-2 border-t border-border" role="separator" />
|
|
271
|
+
}
|
|
272
|
+
@case ('spacer') {
|
|
273
|
+
<div class="flex-1"></div>
|
|
274
|
+
}
|
|
275
|
+
@case ('group') {
|
|
276
|
+
<div class="p-3" role="group" [attr.aria-labelledby]="headingId()">
|
|
277
|
+
@if (!compact()) {
|
|
278
|
+
<div class="sticky top-0 z-10 bg-background py-3 text-muted-foreground">
|
|
279
|
+
<div [id]="headingId()" [class]="cn('ui-nav-heading text-muted-foreground', item().classes?.title)">
|
|
280
|
+
{{ item().title }}
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
}
|
|
284
|
+
<div class="flex flex-col gap-0.5">
|
|
285
|
+
@for (child of groupItem().children; track child.id) {
|
|
286
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="compact()" />
|
|
287
|
+
}
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
}
|
|
291
|
+
@case ('collapsable') {
|
|
292
|
+
@let id = collapsableItem().id ?? '';
|
|
293
|
+
@let open = isGroupOpen();
|
|
294
|
+
<button
|
|
295
|
+
type="button"
|
|
296
|
+
[class]="
|
|
297
|
+
cn(
|
|
298
|
+
'ui-nav-text group/ni flex w-full items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
299
|
+
isTrailActive() && 'text-primary',
|
|
300
|
+
item().classes?.wrapper
|
|
301
|
+
)
|
|
302
|
+
"
|
|
303
|
+
[attr.aria-expanded]="open"
|
|
304
|
+
[attr.aria-controls]="id + '-panel'"
|
|
305
|
+
[disabled]="collapsableItem().disabled || null"
|
|
306
|
+
[matTooltip]="compact() ? (collapsableItem().title ?? '') : ''"
|
|
307
|
+
matTooltipPosition="right"
|
|
308
|
+
[matTooltipDisabled]="!compact()"
|
|
309
|
+
(click)="toggleGroup()">
|
|
310
|
+
@if (collapsableItem().icon) {
|
|
311
|
+
<ui-nav-icon [name]="collapsableItem().icon!" [size]="18" [class]="item().classes?.icon ?? ''" />
|
|
312
|
+
}
|
|
313
|
+
@if (!compact()) {
|
|
314
|
+
<span [class]="cn('flex-1 truncate text-left', item().classes?.title)">
|
|
315
|
+
{{ collapsableItem().title }}
|
|
316
|
+
</span>
|
|
317
|
+
@if (collapsableItem().badge; as badge) {
|
|
318
|
+
<span [class]="badge.classes ?? 'ui-nav-badge ml-auto'">{{ badge.title }}</span>
|
|
319
|
+
}
|
|
320
|
+
<ui-nav-icon
|
|
321
|
+
[name]="'chevron_right'"
|
|
322
|
+
[size]="18"
|
|
323
|
+
[class]="cn('transition-transform duration-200', open && 'rotate-90')" />
|
|
324
|
+
}
|
|
325
|
+
</button>
|
|
326
|
+
@if (!compact() && open) {
|
|
327
|
+
<div [id]="id + '-panel'" role="region" class="ml-3 mt-0.5 flex flex-col gap-0.5 border-l border-border pl-3">
|
|
328
|
+
@for (child of collapsableItem().children; track child.id) {
|
|
329
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="false" />
|
|
330
|
+
}
|
|
331
|
+
</div>
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
@case ('mega') {
|
|
335
|
+
<!-- Mega direndahkan ke group saat berada di sidebar vertical. -->
|
|
336
|
+
<div class="mt-4 py-3 first:mt-0" role="group">
|
|
337
|
+
@if (!compact()) {
|
|
338
|
+
<div class="ui-nav-heading sticky top-0 z-10 bg-background px-3 pb-1 text-muted-foreground">
|
|
339
|
+
{{ item().title }}
|
|
340
|
+
</div>
|
|
341
|
+
}
|
|
342
|
+
<div class="flex flex-col gap-0.5">
|
|
343
|
+
@for (child of megaItem().children; track child.id) {
|
|
344
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="compact()" />
|
|
345
|
+
}
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
}
|
|
349
|
+
@case ('aside') {
|
|
350
|
+
<a
|
|
351
|
+
[class]="
|
|
352
|
+
cn(
|
|
353
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary',
|
|
354
|
+
item().classes?.wrapper
|
|
355
|
+
)
|
|
356
|
+
"
|
|
357
|
+
routerLinkActive="text-primary"
|
|
358
|
+
#rla="routerLinkActive"
|
|
359
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
360
|
+
[routerLink]="asideItem().link"
|
|
361
|
+
[queryParams]="asideItem().queryParams"
|
|
362
|
+
[fragment]="asideItem().fragment ?? undefined"
|
|
363
|
+
[target]="asideItem().target ?? undefined"
|
|
364
|
+
[matTooltip]="compact() ? (asideItem().title ?? '') : ''"
|
|
365
|
+
matTooltipPosition="right"
|
|
366
|
+
[matTooltipDisabled]="!compact()">
|
|
367
|
+
@if (asideItem().icon) {
|
|
368
|
+
<ui-nav-icon [name]="asideItem().icon!" [size]="18" />
|
|
369
|
+
}
|
|
370
|
+
@if (!compact()) {
|
|
371
|
+
<span class="flex-1 truncate">{{ asideItem().title }}</span>
|
|
372
|
+
}
|
|
373
|
+
</a>
|
|
374
|
+
}
|
|
375
|
+
@default {
|
|
376
|
+
<!-- basic -->
|
|
377
|
+
@if (basicItem().link && !basicItem().externalLink) {
|
|
378
|
+
<a
|
|
379
|
+
[class]="
|
|
380
|
+
cn(
|
|
381
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary aria-disabled:pointer-events-none aria-disabled:opacity-50',
|
|
382
|
+
item().classes?.wrapper
|
|
383
|
+
)
|
|
384
|
+
"
|
|
385
|
+
routerLinkActive="text-primary"
|
|
386
|
+
#rla="routerLinkActive"
|
|
387
|
+
[routerLinkActiveOptions]="
|
|
388
|
+
basicItem().isActiveMatchOptions ?? (basicItem().exactMatch ? exactMatch : inexactMatch)
|
|
389
|
+
"
|
|
390
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
391
|
+
[attr.aria-disabled]="basicItem().disabled || null"
|
|
392
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
393
|
+
matTooltipPosition="right"
|
|
394
|
+
[matTooltipDisabled]="!compact()"
|
|
395
|
+
[routerLink]="basicItem().link"
|
|
396
|
+
[queryParams]="basicItem().queryParams"
|
|
397
|
+
[queryParamsHandling]="basicItem().queryParamsHandling ?? null"
|
|
398
|
+
[fragment]="basicItem().fragment ?? undefined"
|
|
399
|
+
[preserveFragment]="basicItem().preserveFragment ?? false"
|
|
400
|
+
[target]="basicItem().target ?? undefined"
|
|
401
|
+
(click)="runAction()">
|
|
402
|
+
@if (basicItem().icon) {
|
|
403
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" [class]="item().classes?.icon ?? ''" />
|
|
404
|
+
}
|
|
405
|
+
@if (!compact()) {
|
|
406
|
+
<span [class]="cn('flex-1 truncate', item().classes?.title)">{{ basicItem().title }}</span>
|
|
407
|
+
@if (basicItem().badge; as badge) {
|
|
408
|
+
<span [class]="badge.classes ?? 'ui-nav-badge ml-auto'">{{ badge.title }}</span>
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
</a>
|
|
412
|
+
} @else if (basicItem().link && basicItem().externalLink) {
|
|
413
|
+
<a
|
|
414
|
+
[class]="
|
|
415
|
+
cn(
|
|
416
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
417
|
+
item().classes?.wrapper
|
|
418
|
+
)
|
|
419
|
+
"
|
|
420
|
+
[attr.href]="basicItem().link"
|
|
421
|
+
[attr.target]="basicItem().target ?? '_blank'"
|
|
422
|
+
rel="noopener noreferrer"
|
|
423
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
424
|
+
matTooltipPosition="right"
|
|
425
|
+
[matTooltipDisabled]="!compact()">
|
|
426
|
+
@if (basicItem().icon) {
|
|
427
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" />
|
|
428
|
+
}
|
|
429
|
+
@if (!compact()) {
|
|
430
|
+
<span class="flex-1 truncate">{{ basicItem().title }}</span>
|
|
431
|
+
}
|
|
432
|
+
</a>
|
|
433
|
+
} @else {
|
|
434
|
+
<button
|
|
435
|
+
type="button"
|
|
436
|
+
[class]="
|
|
437
|
+
cn(
|
|
438
|
+
'ui-nav-text flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
|
439
|
+
item().classes?.wrapper
|
|
440
|
+
)
|
|
441
|
+
"
|
|
442
|
+
[disabled]="basicItem().disabled || null"
|
|
443
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
444
|
+
matTooltipPosition="right"
|
|
445
|
+
[matTooltipDisabled]="!compact()"
|
|
446
|
+
(click)="runAction()">
|
|
447
|
+
@if (basicItem().icon) {
|
|
448
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" />
|
|
449
|
+
}
|
|
450
|
+
@if (!compact()) {
|
|
451
|
+
<span class="flex-1 truncate">{{ basicItem().title }}</span>
|
|
452
|
+
}
|
|
453
|
+
</button>
|
|
454
|
+
}
|
|
455
|
+
}
|
|
171
456
|
}
|
|
457
|
+
`, isInline: true, dependencies: [{ kind: "component", type: UiNavItemComponent, selector: "ui-nav-item", inputs: ["item", "level", "compact"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: UiNavIconComponent, selector: "ui-nav-icon", inputs: ["name", "class", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
172
458
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
459
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: UiNavItemComponent, decorators: [{
|
|
460
|
+
type: Component,
|
|
461
|
+
args: [{
|
|
462
|
+
selector: 'ui-nav-item',
|
|
463
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
464
|
+
imports: [RouterLink, RouterLinkActive, MatTooltip, UiNavIconComponent],
|
|
465
|
+
template: `
|
|
466
|
+
@switch (type()) {
|
|
467
|
+
@case ('divider') {
|
|
468
|
+
<hr class="my-2 border-t border-border" role="separator" />
|
|
469
|
+
}
|
|
470
|
+
@case ('spacer') {
|
|
471
|
+
<div class="flex-1"></div>
|
|
472
|
+
}
|
|
473
|
+
@case ('group') {
|
|
474
|
+
<div class="p-3" role="group" [attr.aria-labelledby]="headingId()">
|
|
475
|
+
@if (!compact()) {
|
|
476
|
+
<div class="sticky top-0 z-10 bg-background py-3 text-muted-foreground">
|
|
477
|
+
<div [id]="headingId()" [class]="cn('ui-nav-heading text-muted-foreground', item().classes?.title)">
|
|
478
|
+
{{ item().title }}
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
}
|
|
482
|
+
<div class="flex flex-col gap-0.5">
|
|
483
|
+
@for (child of groupItem().children; track child.id) {
|
|
484
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="compact()" />
|
|
485
|
+
}
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
}
|
|
489
|
+
@case ('collapsable') {
|
|
490
|
+
@let id = collapsableItem().id ?? '';
|
|
491
|
+
@let open = isGroupOpen();
|
|
492
|
+
<button
|
|
493
|
+
type="button"
|
|
494
|
+
[class]="
|
|
495
|
+
cn(
|
|
496
|
+
'ui-nav-text group/ni flex w-full items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
497
|
+
isTrailActive() && 'text-primary',
|
|
498
|
+
item().classes?.wrapper
|
|
499
|
+
)
|
|
500
|
+
"
|
|
501
|
+
[attr.aria-expanded]="open"
|
|
502
|
+
[attr.aria-controls]="id + '-panel'"
|
|
503
|
+
[disabled]="collapsableItem().disabled || null"
|
|
504
|
+
[matTooltip]="compact() ? (collapsableItem().title ?? '') : ''"
|
|
505
|
+
matTooltipPosition="right"
|
|
506
|
+
[matTooltipDisabled]="!compact()"
|
|
507
|
+
(click)="toggleGroup()">
|
|
508
|
+
@if (collapsableItem().icon) {
|
|
509
|
+
<ui-nav-icon [name]="collapsableItem().icon!" [size]="18" [class]="item().classes?.icon ?? ''" />
|
|
510
|
+
}
|
|
511
|
+
@if (!compact()) {
|
|
512
|
+
<span [class]="cn('flex-1 truncate text-left', item().classes?.title)">
|
|
513
|
+
{{ collapsableItem().title }}
|
|
514
|
+
</span>
|
|
515
|
+
@if (collapsableItem().badge; as badge) {
|
|
516
|
+
<span [class]="badge.classes ?? 'ui-nav-badge ml-auto'">{{ badge.title }}</span>
|
|
183
517
|
}
|
|
184
|
-
|
|
185
|
-
|
|
518
|
+
<ui-nav-icon
|
|
519
|
+
[name]="'chevron_right'"
|
|
520
|
+
[size]="18"
|
|
521
|
+
[class]="cn('transition-transform duration-200', open && 'rotate-90')" />
|
|
522
|
+
}
|
|
523
|
+
</button>
|
|
524
|
+
@if (!compact() && open) {
|
|
525
|
+
<div [id]="id + '-panel'" role="region" class="ml-3 mt-0.5 flex flex-col gap-0.5 border-l border-border pl-3">
|
|
526
|
+
@for (child of collapsableItem().children; track child.id) {
|
|
527
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="false" />
|
|
186
528
|
}
|
|
529
|
+
</div>
|
|
187
530
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
531
|
+
}
|
|
532
|
+
@case ('mega') {
|
|
533
|
+
<!-- Mega direndahkan ke group saat berada di sidebar vertical. -->
|
|
534
|
+
<div class="mt-4 py-3 first:mt-0" role="group">
|
|
535
|
+
@if (!compact()) {
|
|
536
|
+
<div class="ui-nav-heading sticky top-0 z-10 bg-background px-3 pb-1 text-muted-foreground">
|
|
537
|
+
{{ item().title }}
|
|
538
|
+
</div>
|
|
539
|
+
}
|
|
540
|
+
<div class="flex flex-col gap-0.5">
|
|
541
|
+
@for (child of megaItem().children; track child.id) {
|
|
542
|
+
<ui-nav-item [item]="child" [level]="level() + 1" [compact]="compact()" />
|
|
543
|
+
}
|
|
544
|
+
</div>
|
|
545
|
+
</div>
|
|
546
|
+
}
|
|
547
|
+
@case ('aside') {
|
|
548
|
+
<a
|
|
549
|
+
[class]="
|
|
550
|
+
cn(
|
|
551
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary',
|
|
552
|
+
item().classes?.wrapper
|
|
553
|
+
)
|
|
554
|
+
"
|
|
555
|
+
routerLinkActive="text-primary"
|
|
556
|
+
#rla="routerLinkActive"
|
|
557
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
558
|
+
[routerLink]="asideItem().link"
|
|
559
|
+
[queryParams]="asideItem().queryParams"
|
|
560
|
+
[fragment]="asideItem().fragment ?? undefined"
|
|
561
|
+
[target]="asideItem().target ?? undefined"
|
|
562
|
+
[matTooltip]="compact() ? (asideItem().title ?? '') : ''"
|
|
563
|
+
matTooltipPosition="right"
|
|
564
|
+
[matTooltipDisabled]="!compact()">
|
|
565
|
+
@if (asideItem().icon) {
|
|
566
|
+
<ui-nav-icon [name]="asideItem().icon!" [size]="18" />
|
|
567
|
+
}
|
|
568
|
+
@if (!compact()) {
|
|
569
|
+
<span class="flex-1 truncate">{{ asideItem().title }}</span>
|
|
570
|
+
}
|
|
571
|
+
</a>
|
|
572
|
+
}
|
|
573
|
+
@default {
|
|
574
|
+
<!-- basic -->
|
|
575
|
+
@if (basicItem().link && !basicItem().externalLink) {
|
|
576
|
+
<a
|
|
577
|
+
[class]="
|
|
578
|
+
cn(
|
|
579
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary aria-disabled:pointer-events-none aria-disabled:opacity-50',
|
|
580
|
+
item().classes?.wrapper
|
|
581
|
+
)
|
|
582
|
+
"
|
|
583
|
+
routerLinkActive="text-primary"
|
|
584
|
+
#rla="routerLinkActive"
|
|
585
|
+
[routerLinkActiveOptions]="
|
|
586
|
+
basicItem().isActiveMatchOptions ?? (basicItem().exactMatch ? exactMatch : inexactMatch)
|
|
587
|
+
"
|
|
588
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
589
|
+
[attr.aria-disabled]="basicItem().disabled || null"
|
|
590
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
591
|
+
matTooltipPosition="right"
|
|
592
|
+
[matTooltipDisabled]="!compact()"
|
|
593
|
+
[routerLink]="basicItem().link"
|
|
594
|
+
[queryParams]="basicItem().queryParams"
|
|
595
|
+
[queryParamsHandling]="basicItem().queryParamsHandling ?? null"
|
|
596
|
+
[fragment]="basicItem().fragment ?? undefined"
|
|
597
|
+
[preserveFragment]="basicItem().preserveFragment ?? false"
|
|
598
|
+
[target]="basicItem().target ?? undefined"
|
|
599
|
+
(click)="runAction()">
|
|
600
|
+
@if (basicItem().icon) {
|
|
601
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" [class]="item().classes?.icon ?? ''" />
|
|
602
|
+
}
|
|
603
|
+
@if (!compact()) {
|
|
604
|
+
<span [class]="cn('flex-1 truncate', item().classes?.title)">{{ basicItem().title }}</span>
|
|
605
|
+
@if (basicItem().badge; as badge) {
|
|
606
|
+
<span [class]="badge.classes ?? 'ui-nav-badge ml-auto'">{{ badge.title }}</span>
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
</a>
|
|
610
|
+
} @else if (basicItem().link && basicItem().externalLink) {
|
|
611
|
+
<a
|
|
612
|
+
[class]="
|
|
613
|
+
cn(
|
|
614
|
+
'ui-nav-text flex items-center gap-3 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
615
|
+
item().classes?.wrapper
|
|
616
|
+
)
|
|
617
|
+
"
|
|
618
|
+
[attr.href]="basicItem().link"
|
|
619
|
+
[attr.target]="basicItem().target ?? '_blank'"
|
|
620
|
+
rel="noopener noreferrer"
|
|
621
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
622
|
+
matTooltipPosition="right"
|
|
623
|
+
[matTooltipDisabled]="!compact()">
|
|
624
|
+
@if (basicItem().icon) {
|
|
625
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" />
|
|
626
|
+
}
|
|
627
|
+
@if (!compact()) {
|
|
628
|
+
<span class="flex-1 truncate">{{ basicItem().title }}</span>
|
|
629
|
+
}
|
|
630
|
+
</a>
|
|
631
|
+
} @else {
|
|
632
|
+
<button
|
|
633
|
+
type="button"
|
|
634
|
+
[class]="
|
|
635
|
+
cn(
|
|
636
|
+
'ui-nav-text flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
|
637
|
+
item().classes?.wrapper
|
|
638
|
+
)
|
|
639
|
+
"
|
|
640
|
+
[disabled]="basicItem().disabled || null"
|
|
641
|
+
[matTooltip]="compact() ? (basicItem().title ?? '') : ''"
|
|
642
|
+
matTooltipPosition="right"
|
|
643
|
+
[matTooltipDisabled]="!compact()"
|
|
644
|
+
(click)="runAction()">
|
|
645
|
+
@if (basicItem().icon) {
|
|
646
|
+
<ui-nav-icon [name]="basicItem().icon!" [size]="18" />
|
|
647
|
+
}
|
|
648
|
+
@if (!compact()) {
|
|
649
|
+
<span class="flex-1 truncate">{{ basicItem().title }}</span>
|
|
650
|
+
}
|
|
651
|
+
</button>
|
|
223
652
|
}
|
|
224
|
-
|
|
225
|
-
this._activeItemId.set(normalizedId);
|
|
653
|
+
}
|
|
226
654
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
655
|
+
`,
|
|
656
|
+
}]
|
|
657
|
+
}], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }] } });
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Vertical navigation (sidebar) — shadcn-styled.
|
|
661
|
+
*
|
|
662
|
+
* Variants:
|
|
663
|
+
* - `default`: 17.5rem, label + icon
|
|
664
|
+
* - `thin`: 4rem icon-only; hover memunculkan overlay expand (tidak push konten)
|
|
665
|
+
*
|
|
666
|
+
* Mobile (`< md`): saat `autoMobile=true` (default), host desktop disembunyikan
|
|
667
|
+
* dan konten dirender lewat CDK Overlay drawer dengan focus trap. State buka
|
|
668
|
+
* dikontrol lewat `NavigationService.mobileOpen`.
|
|
669
|
+
*/
|
|
670
|
+
class SidebarComponent {
|
|
671
|
+
nav = inject(NavigationService);
|
|
672
|
+
bp = inject(BreakpointObserver);
|
|
673
|
+
overlay = inject(Overlay);
|
|
674
|
+
vcr = inject(ViewContainerRef);
|
|
675
|
+
focusTrapFactory = inject(FocusTrapFactory);
|
|
676
|
+
doc = inject(DOCUMENT);
|
|
677
|
+
destroyRef = inject(DestroyRef);
|
|
678
|
+
items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
679
|
+
/** Registry key di `NavigationService`. Default `'main'`. */
|
|
680
|
+
navigationId = input(DEFAULT_NAVIGATION_ID, ...(ngDevMode ? [{ debugName: "navigationId" }] : /* istanbul ignore next */ []));
|
|
681
|
+
appearance = input('default', ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
682
|
+
position = input('left', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
683
|
+
ariaLabel = input('Primary', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
684
|
+
header = input(true, ...(ngDevMode ? [{ debugName: "header" }] : /* istanbul ignore next */ []));
|
|
685
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
686
|
+
/** Auto switch ke CDK overlay drawer saat viewport `< md`. */
|
|
687
|
+
autoMobile = input(true, ...(ngDevMode ? [{ debugName: "autoMobile" }] : /* istanbul ignore next */ []));
|
|
688
|
+
/** Auto-register `items` ke `NavigationService` agar `activeTrail` bekerja. */
|
|
689
|
+
autoRegister = input(true, ...(ngDevMode ? [{ debugName: "autoRegister" }] : /* istanbul ignore next */ []));
|
|
690
|
+
/** Resolved items: input jika disediakan, fallback ke registry NavigationService. */
|
|
691
|
+
resolvedItems = computed(() => {
|
|
692
|
+
const explicit = this.items();
|
|
693
|
+
return explicit.length > 0 ? explicit : this.nav.getItems(this.navigationId())();
|
|
694
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedItems" }] : /* istanbul ignore next */ []));
|
|
695
|
+
hovered = signal(false, ...(ngDevMode ? [{ debugName: "hovered" }] : /* istanbul ignore next */ []));
|
|
696
|
+
drawerTpl = viewChild.required('drawerTpl');
|
|
697
|
+
drawerRef = null;
|
|
698
|
+
focusTrap = null;
|
|
699
|
+
previouslyFocused = null;
|
|
700
|
+
/** True saat viewport `< md` (767.98px). */
|
|
701
|
+
isMobileMedia = toSignal(this.bp.observe('(max-width: 767.98px)').pipe(map((s) => s.matches)), {
|
|
702
|
+
initialValue: false,
|
|
703
|
+
});
|
|
704
|
+
isMobile = computed(() => this.autoMobile() && this.isMobileMedia(), ...(ngDevMode ? [{ debugName: "isMobile" }] : /* istanbul ignore next */ []));
|
|
705
|
+
isExpanded = computed(() => this.appearance() === 'default' || this.hovered(), ...(ngDevMode ? [{ debugName: "isExpanded" }] : /* istanbul ignore next */ []));
|
|
706
|
+
isCompact = computed(() => !this.isMobile() && this.appearance() === 'thin' && !this.hovered(), ...(ngDevMode ? [{ debugName: "isCompact" }] : /* istanbul ignore next */ []));
|
|
707
|
+
constructor() {
|
|
708
|
+
// Auto-register items ke service untuk active trail (hanya jika input non-kosong).
|
|
709
|
+
effect(() => {
|
|
710
|
+
const explicit = this.items();
|
|
711
|
+
if (this.autoRegister() && explicit.length > 0)
|
|
712
|
+
this.nav.registerItems(this.navigationId(), explicit);
|
|
713
|
+
});
|
|
714
|
+
// Kelola overlay drawer berdasarkan mobileOpen + isMobile.
|
|
715
|
+
effect(() => {
|
|
716
|
+
const open = this.nav.mobileOpen();
|
|
717
|
+
const mobile = this.isMobile();
|
|
718
|
+
if (mobile && open)
|
|
719
|
+
this.openDrawer();
|
|
720
|
+
else
|
|
721
|
+
this.closeDrawer();
|
|
722
|
+
});
|
|
723
|
+
this.destroyRef.onDestroy(() => this.closeDrawer());
|
|
230
724
|
}
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
725
|
+
hostClasses = computed(() => {
|
|
726
|
+
const base = ['relative flex shrink-0 bg-background text-foreground', 'transition-[width] duration-200 ease-out'];
|
|
727
|
+
const appearance = this.appearance();
|
|
728
|
+
if (appearance === 'thin')
|
|
729
|
+
base.push('w-16');
|
|
730
|
+
else
|
|
731
|
+
base.push('[width:17.5rem]');
|
|
732
|
+
if (this.position() === 'right')
|
|
733
|
+
base.push('border-l');
|
|
734
|
+
else
|
|
735
|
+
base.push('border-r');
|
|
736
|
+
base.push('border-border');
|
|
737
|
+
return [...base, this.class()].join(' ');
|
|
738
|
+
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
739
|
+
innerClasses = computed(() => {
|
|
740
|
+
const overlayActive = this.appearance() === 'thin' && this.hovered();
|
|
741
|
+
const base = ['flex h-full flex-col transition-[width] duration-200 ease-out'];
|
|
742
|
+
if (overlayActive) {
|
|
743
|
+
base.push('absolute inset-y-0 z-30 bg-background shadow-xl [width:17.5rem]', this.position() === 'right' ? 'right-0 border-l border-border' : 'left-0 border-r border-border');
|
|
236
744
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
expandItem(id) {
|
|
241
|
-
const normalizedId = id.trim();
|
|
242
|
-
if (!normalizedId || this._expandedItemIds().includes(normalizedId)) {
|
|
243
|
-
return;
|
|
745
|
+
else {
|
|
746
|
+
base.push('w-full');
|
|
244
747
|
}
|
|
245
|
-
|
|
748
|
+
return base.join(' ');
|
|
749
|
+
}, ...(ngDevMode ? [{ debugName: "innerClasses" }] : /* istanbul ignore next */ []));
|
|
750
|
+
onHoverEnter() {
|
|
751
|
+
if (this.appearance() === 'thin' && !this.isMobile())
|
|
752
|
+
this.hovered.set(true);
|
|
246
753
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
this.setExpandedItemIds(this._expandedItemIds().filter((expandedId) => expandedId !== normalizedId));
|
|
754
|
+
onHoverLeave() {
|
|
755
|
+
if (this.appearance() === 'thin')
|
|
756
|
+
this.hovered.set(false);
|
|
253
757
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
758
|
+
/** Touch fallback: tap pada strip thin (ketika belum expanded) untuk expand. */
|
|
759
|
+
onHostClick(event) {
|
|
760
|
+
if (this.appearance() !== 'thin' || this.isMobile())
|
|
257
761
|
return;
|
|
258
|
-
|
|
259
|
-
if (this._expandedItemIds().includes(normalizedId)) {
|
|
260
|
-
this.collapseItem(normalizedId);
|
|
762
|
+
if (this.hovered())
|
|
261
763
|
return;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
this.
|
|
267
|
-
this._expandedItemIds.set([]);
|
|
268
|
-
}
|
|
269
|
-
reset() {
|
|
270
|
-
this.storage.clear('horizontal-variant');
|
|
271
|
-
this._horizontalVariant.set(this.config.defaultHorizontalVariant);
|
|
272
|
-
this.storage.clear('vertical-appearance');
|
|
273
|
-
this._verticalAppearance.set(this.config.defaultVerticalVariant);
|
|
274
|
-
this.clearActiveItem();
|
|
275
|
-
this.clearExpandedItems();
|
|
276
|
-
}
|
|
277
|
-
syncWithNavigation(navigation) {
|
|
278
|
-
const { allIds, expandableIds } = collectNavigationMetadata(navigation);
|
|
279
|
-
const activeItemId = this._activeItemId();
|
|
280
|
-
if (activeItemId && !allIds.has(activeItemId)) {
|
|
281
|
-
this.clearActiveItem();
|
|
282
|
-
}
|
|
283
|
-
const filteredExpandedIds = this._expandedItemIds().filter((id) => expandableIds.has(id));
|
|
284
|
-
if (filteredExpandedIds.length !== this._expandedItemIds().length) {
|
|
285
|
-
this.setExpandedItemIds(filteredExpandedIds);
|
|
286
|
-
}
|
|
764
|
+
const target = event.target;
|
|
765
|
+
// Biarkan klik pada control interaktif terus propagate (tidak intercept).
|
|
766
|
+
if (target && target.closest('a,button,[role="menuitem"]'))
|
|
767
|
+
return;
|
|
768
|
+
this.hovered.set(true);
|
|
287
769
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
770
|
+
openDrawer() {
|
|
771
|
+
if (this.drawerRef)
|
|
772
|
+
return;
|
|
773
|
+
const side = this.position();
|
|
774
|
+
const pos = this.overlay.position().global().top('0');
|
|
775
|
+
if (side === 'right')
|
|
776
|
+
pos.right('0');
|
|
777
|
+
else
|
|
778
|
+
pos.left('0');
|
|
779
|
+
this.drawerRef = this.overlay.create({
|
|
780
|
+
positionStrategy: pos,
|
|
781
|
+
height: '100vh',
|
|
782
|
+
hasBackdrop: true,
|
|
783
|
+
backdropClass: 'cdk-overlay-dark-backdrop',
|
|
784
|
+
scrollStrategy: this.overlay.scrollStrategies.block(),
|
|
785
|
+
panelClass: ['ui-sidebar-drawer'],
|
|
786
|
+
});
|
|
787
|
+
const portal = new TemplatePortal(this.drawerTpl(), this.vcr);
|
|
788
|
+
const viewRef = this.drawerRef.attach(portal);
|
|
789
|
+
viewRef.detectChanges();
|
|
790
|
+
const root = this.drawerRef.overlayElement;
|
|
791
|
+
this.focusTrap = this.focusTrapFactory.create(root);
|
|
792
|
+
this.previouslyFocused = this.doc.activeElement;
|
|
793
|
+
queueMicrotask(() => this.focusTrap?.focusInitialElementWhenReady());
|
|
794
|
+
this.drawerRef
|
|
795
|
+
.backdropClick()
|
|
796
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
797
|
+
.subscribe(() => this.nav.closeMobile());
|
|
798
|
+
this.drawerRef
|
|
799
|
+
.keydownEvents()
|
|
800
|
+
.pipe(filter((e) => e.key === 'Escape'), takeUntilDestroyed(this.destroyRef))
|
|
801
|
+
.subscribe(() => this.nav.closeMobile());
|
|
304
802
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
readVerticalAppearance() {
|
|
316
|
-
const storedValue = this.storage.readValue('vertical-appearance');
|
|
317
|
-
const normalizedValue = normalizeVerticalNavigationAppearance(storedValue);
|
|
318
|
-
if (normalizedValue) {
|
|
319
|
-
if (storedValue !== normalizedValue) {
|
|
320
|
-
this.storage.persist('vertical-appearance', normalizedValue);
|
|
321
|
-
}
|
|
322
|
-
return normalizedValue;
|
|
323
|
-
}
|
|
324
|
-
if (storedValue !== null) {
|
|
325
|
-
this.storage.clear('vertical-appearance');
|
|
326
|
-
}
|
|
327
|
-
return this.config.defaultVerticalVariant;
|
|
803
|
+
closeDrawer() {
|
|
804
|
+
if (!this.drawerRef)
|
|
805
|
+
return;
|
|
806
|
+
this.focusTrap?.destroy();
|
|
807
|
+
this.focusTrap = null;
|
|
808
|
+
this.drawerRef.dispose();
|
|
809
|
+
this.drawerRef = null;
|
|
810
|
+
this.previouslyFocused?.focus?.();
|
|
811
|
+
this.previouslyFocused = null;
|
|
328
812
|
}
|
|
329
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
330
|
-
static
|
|
813
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
814
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: SidebarComponent, isStandalone: true, selector: "ui-sidebar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, navigationId: { classPropertyName: "navigationId", publicName: "navigationId", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, autoMobile: { classPropertyName: "autoMobile", publicName: "autoMobile", isSignal: true, isRequired: false, transformFunction: null }, autoRegister: { classPropertyName: "autoRegister", publicName: "autoRegister", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, listeners: { "mouseenter": "onHoverEnter()", "mouseleave": "onHoverLeave()", "focusin": "onHoverEnter()", "click": "onHostClick($event)" }, properties: { "attr.aria-label": "ariaLabel()", "class": "hostClasses()", "attr.data-appearance": "appearance()", "attr.data-position": "position()", "attr.data-expanded": "isExpanded()", "hidden": "isMobile()" } }, viewQueries: [{ propertyName: "drawerTpl", first: true, predicate: ["drawerTpl"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
815
|
+
<div [class]="innerClasses()">
|
|
816
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
817
|
+
</div>
|
|
818
|
+
|
|
819
|
+
<ng-template #body>
|
|
820
|
+
@if (header()) {
|
|
821
|
+
<div class="flex h-12 items-center gap-2 border-b border-border px-3">
|
|
822
|
+
<ng-content select="[ui-sidebar-header]" />
|
|
823
|
+
</div>
|
|
824
|
+
}
|
|
825
|
+
<nav class="flex-1 overflow-y-auto overflow-x-hidden">
|
|
826
|
+
@for (item of resolvedItems(); track item.id) {
|
|
827
|
+
<ui-nav-item [item]="item" [compact]="isCompact()" />
|
|
828
|
+
}
|
|
829
|
+
</nav>
|
|
830
|
+
<div class="border-t border-border h-12">
|
|
831
|
+
<ng-content select="[ui-sidebar-footer]" />
|
|
832
|
+
</div>
|
|
833
|
+
</ng-template>
|
|
834
|
+
|
|
835
|
+
<ng-template #drawerTpl>
|
|
836
|
+
<div
|
|
837
|
+
role="dialog"
|
|
838
|
+
aria-modal="true"
|
|
839
|
+
[attr.aria-label]="ariaLabel()"
|
|
840
|
+
class="flex h-full w-72 max-w-[85vw] flex-col bg-background text-foreground shadow-xl"
|
|
841
|
+
[ngClass]="position() === 'right' ? 'border-l border-border' : 'border-r border-border'">
|
|
842
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
843
|
+
</div>
|
|
844
|
+
</ng-template>
|
|
845
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: UiNavItemComponent, selector: "ui-nav-item", inputs: ["item", "level", "compact"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
331
846
|
}
|
|
332
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
333
|
-
type:
|
|
334
|
-
args: [{
|
|
335
|
-
|
|
847
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
848
|
+
type: Component,
|
|
849
|
+
args: [{
|
|
850
|
+
selector: 'ui-sidebar',
|
|
851
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
852
|
+
imports: [NgClass, NgTemplateOutlet, UiNavItemComponent],
|
|
853
|
+
host: {
|
|
854
|
+
role: 'navigation',
|
|
855
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
856
|
+
'[class]': 'hostClasses()',
|
|
857
|
+
'[attr.data-appearance]': 'appearance()',
|
|
858
|
+
'[attr.data-position]': 'position()',
|
|
859
|
+
'[attr.data-expanded]': 'isExpanded()',
|
|
860
|
+
'[hidden]': 'isMobile()',
|
|
861
|
+
'(mouseenter)': 'onHoverEnter()',
|
|
862
|
+
'(mouseleave)': 'onHoverLeave()',
|
|
863
|
+
'(focusin)': 'onHoverEnter()',
|
|
864
|
+
'(click)': 'onHostClick($event)',
|
|
865
|
+
},
|
|
866
|
+
template: `
|
|
867
|
+
<div [class]="innerClasses()">
|
|
868
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
869
|
+
</div>
|
|
870
|
+
|
|
871
|
+
<ng-template #body>
|
|
872
|
+
@if (header()) {
|
|
873
|
+
<div class="flex h-12 items-center gap-2 border-b border-border px-3">
|
|
874
|
+
<ng-content select="[ui-sidebar-header]" />
|
|
875
|
+
</div>
|
|
876
|
+
}
|
|
877
|
+
<nav class="flex-1 overflow-y-auto overflow-x-hidden">
|
|
878
|
+
@for (item of resolvedItems(); track item.id) {
|
|
879
|
+
<ui-nav-item [item]="item" [compact]="isCompact()" />
|
|
880
|
+
}
|
|
881
|
+
</nav>
|
|
882
|
+
<div class="border-t border-border h-12">
|
|
883
|
+
<ng-content select="[ui-sidebar-footer]" />
|
|
884
|
+
</div>
|
|
885
|
+
</ng-template>
|
|
886
|
+
|
|
887
|
+
<ng-template #drawerTpl>
|
|
888
|
+
<div
|
|
889
|
+
role="dialog"
|
|
890
|
+
aria-modal="true"
|
|
891
|
+
[attr.aria-label]="ariaLabel()"
|
|
892
|
+
class="flex h-full w-72 max-w-[85vw] flex-col bg-background text-foreground shadow-xl"
|
|
893
|
+
[ngClass]="position() === 'right' ? 'border-l border-border' : 'border-r border-border'">
|
|
894
|
+
<ng-container [ngTemplateOutlet]="body" />
|
|
895
|
+
</div>
|
|
896
|
+
</ng-template>
|
|
897
|
+
`,
|
|
898
|
+
}]
|
|
899
|
+
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], navigationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationId", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], autoMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoMobile", required: false }] }], autoRegister: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoRegister", required: false }] }], drawerTpl: [{ type: i0.ViewChild, args: ['drawerTpl', { isSignal: true }] }] } });
|
|
336
900
|
|
|
337
901
|
/**
|
|
338
|
-
*
|
|
902
|
+
* Horizontal navigation (topbar) — shadcn-styled.
|
|
339
903
|
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
* 3. Utility functions untuk navigation operations
|
|
904
|
+
* Variants:
|
|
905
|
+
* - `default`: horizontal list; item `collapsable` buka dropdown
|
|
906
|
+
* - `megamenu`: item `mega` buka panel full-width multi-kolom
|
|
344
907
|
*/
|
|
345
|
-
class
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
908
|
+
class TopbarComponent {
|
|
909
|
+
nav = inject(NavigationService);
|
|
910
|
+
overlay = inject(Overlay);
|
|
911
|
+
vcr = inject(ViewContainerRef);
|
|
912
|
+
host = inject(ElementRef);
|
|
913
|
+
destroyRef = inject(DestroyRef);
|
|
914
|
+
items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
915
|
+
/** Registry key di `NavigationService`. Default `'main'`. */
|
|
916
|
+
navigationId = input(DEFAULT_NAVIGATION_ID, ...(ngDevMode ? [{ debugName: "navigationId" }] : /* istanbul ignore next */ []));
|
|
917
|
+
appearance = input('default', ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
918
|
+
ariaLabel = input('Primary', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
919
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
920
|
+
/** Auto-register `items` ke `NavigationService` agar `activeTrail` bekerja. */
|
|
921
|
+
autoRegister = input(true, ...(ngDevMode ? [{ debugName: "autoRegister" }] : /* istanbul ignore next */ []));
|
|
922
|
+
/** Tampilkan hamburger di `< md` yang men-toggle mobile drawer sidebar. */
|
|
923
|
+
showHamburger = input(true, ...(ngDevMode ? [{ debugName: "showHamburger" }] : /* istanbul ignore next */ []));
|
|
924
|
+
hamburgerLabel = input('Open navigation', ...(ngDevMode ? [{ debugName: "hamburgerLabel" }] : /* istanbul ignore next */ []));
|
|
925
|
+
/** Resolved items: input jika disediakan, fallback ke registry NavigationService. */
|
|
926
|
+
resolvedItems = computed(() => {
|
|
927
|
+
const explicit = this.items();
|
|
928
|
+
return explicit.length > 0 ? explicit : this.nav.getItems(this.navigationId())();
|
|
929
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedItems" }] : /* istanbul ignore next */ []));
|
|
930
|
+
openId = signal(null, ...(ngDevMode ? [{ debugName: "openId" }] : /* istanbul ignore next */ []));
|
|
931
|
+
active = null;
|
|
932
|
+
dropdownTpl = viewChild.required('dropdownTpl');
|
|
933
|
+
megaTpl = viewChild.required('megaTpl');
|
|
934
|
+
constructor() {
|
|
935
|
+
effect(() => {
|
|
936
|
+
const explicit = this.items();
|
|
937
|
+
if (this.autoRegister() && explicit.length > 0)
|
|
938
|
+
this.nav.registerItems(this.navigationId(), explicit);
|
|
939
|
+
});
|
|
940
|
+
this.destroyRef.onDestroy(() => this.closeAll());
|
|
359
941
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
942
|
+
hostClasses = computed(() => {
|
|
943
|
+
return [
|
|
944
|
+
'sticky top-0 z-20 flex w-full items-center border-b border-border bg-background text-foreground',
|
|
945
|
+
this.class(),
|
|
946
|
+
].join(' ');
|
|
947
|
+
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
948
|
+
asBasic(i) {
|
|
949
|
+
return i;
|
|
365
950
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
this._navigation.set([]);
|
|
374
|
-
this.clearActiveItem();
|
|
375
|
-
this.clearExpandedItems();
|
|
951
|
+
asCollapsable(i) {
|
|
952
|
+
return i;
|
|
953
|
+
}
|
|
954
|
+
asGroup(i) {
|
|
955
|
+
return i;
|
|
376
956
|
}
|
|
377
|
-
|
|
378
|
-
|
|
957
|
+
asMega(i) {
|
|
958
|
+
return i;
|
|
379
959
|
}
|
|
380
|
-
|
|
381
|
-
this.
|
|
960
|
+
isItemActive(id) {
|
|
961
|
+
return this.nav.isActive(id);
|
|
382
962
|
}
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
963
|
+
megaColsClass(columns) {
|
|
964
|
+
const c = Math.min(Math.max(columns ?? 4, 1), 6);
|
|
965
|
+
switch (c) {
|
|
966
|
+
case 1:
|
|
967
|
+
return 'grid-cols-1';
|
|
968
|
+
case 2:
|
|
969
|
+
return 'md:grid-cols-2';
|
|
970
|
+
case 3:
|
|
971
|
+
return 'md:grid-cols-3';
|
|
972
|
+
case 5:
|
|
973
|
+
return 'md:grid-cols-5';
|
|
974
|
+
case 6:
|
|
975
|
+
return 'md:grid-cols-6';
|
|
976
|
+
default:
|
|
977
|
+
return 'md:grid-cols-4';
|
|
387
978
|
}
|
|
388
|
-
return this.getItem(activeItemId, navigation);
|
|
389
979
|
}
|
|
390
|
-
|
|
391
|
-
this.
|
|
980
|
+
toggleDropdown(trigger, item) {
|
|
981
|
+
if (this.openId() === item.id)
|
|
982
|
+
this.closeAll();
|
|
983
|
+
else
|
|
984
|
+
this.openDropdown(trigger, item);
|
|
392
985
|
}
|
|
393
|
-
|
|
394
|
-
this.
|
|
986
|
+
openDropdown(trigger, item) {
|
|
987
|
+
if (this.openId() === item.id)
|
|
988
|
+
return;
|
|
989
|
+
this.closeAll();
|
|
990
|
+
this.attach(trigger, item, this.dropdownTpl(), /*fullWidth*/ false);
|
|
395
991
|
}
|
|
396
|
-
|
|
397
|
-
this.
|
|
992
|
+
toggleMega(trigger, item) {
|
|
993
|
+
if (this.openId() === item.id)
|
|
994
|
+
this.closeAll();
|
|
995
|
+
else
|
|
996
|
+
this.openMega(trigger, item);
|
|
398
997
|
}
|
|
399
|
-
|
|
400
|
-
|
|
998
|
+
openMega(trigger, item) {
|
|
999
|
+
if (this.openId() === item.id)
|
|
1000
|
+
return;
|
|
1001
|
+
this.closeAll();
|
|
1002
|
+
this.attach(trigger, item, this.megaTpl(), /*fullWidth*/ true);
|
|
401
1003
|
}
|
|
402
|
-
|
|
403
|
-
this.
|
|
1004
|
+
attach(trigger, item, tpl, fullWidth) {
|
|
1005
|
+
const strategy = this.overlay
|
|
1006
|
+
.position()
|
|
1007
|
+
.flexibleConnectedTo(trigger)
|
|
1008
|
+
.withFlexibleDimensions(false)
|
|
1009
|
+
.withPush(false)
|
|
1010
|
+
.withPositions(fullWidth
|
|
1011
|
+
? [
|
|
1012
|
+
{
|
|
1013
|
+
originX: 'center',
|
|
1014
|
+
originY: 'bottom',
|
|
1015
|
+
overlayX: 'center',
|
|
1016
|
+
overlayY: 'top',
|
|
1017
|
+
offsetY: 4,
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
originX: 'center',
|
|
1021
|
+
originY: 'top',
|
|
1022
|
+
overlayX: 'center',
|
|
1023
|
+
overlayY: 'bottom',
|
|
1024
|
+
offsetY: -4,
|
|
1025
|
+
},
|
|
1026
|
+
]
|
|
1027
|
+
: [
|
|
1028
|
+
{
|
|
1029
|
+
originX: 'start',
|
|
1030
|
+
originY: 'bottom',
|
|
1031
|
+
overlayX: 'start',
|
|
1032
|
+
overlayY: 'top',
|
|
1033
|
+
offsetY: 4,
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
originX: 'start',
|
|
1037
|
+
originY: 'top',
|
|
1038
|
+
overlayX: 'start',
|
|
1039
|
+
overlayY: 'bottom',
|
|
1040
|
+
offsetY: -4,
|
|
1041
|
+
},
|
|
1042
|
+
]);
|
|
1043
|
+
const ref = this.overlay.create({
|
|
1044
|
+
positionStrategy: strategy,
|
|
1045
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
1046
|
+
hasBackdrop: true,
|
|
1047
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
1048
|
+
panelClass: fullWidth ? ['ui-mega-panel'] : ['ui-dropdown-panel'],
|
|
1049
|
+
width: fullWidth ? '100vw' : undefined,
|
|
1050
|
+
maxWidth: fullWidth ? '100vw' : undefined,
|
|
1051
|
+
});
|
|
1052
|
+
const portal = new TemplatePortal(tpl, this.vcr, { $implicit: item });
|
|
1053
|
+
ref.attach(portal);
|
|
1054
|
+
this.active = { ref, id: item.id ?? '' };
|
|
1055
|
+
this.openId.set(item.id ?? null);
|
|
1056
|
+
merge(ref.backdropClick(), ref.keydownEvents().pipe(filter((e) => e.key === 'Escape')))
|
|
1057
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1058
|
+
.subscribe(() => {
|
|
1059
|
+
this.closeAll();
|
|
1060
|
+
trigger.focus();
|
|
1061
|
+
});
|
|
404
1062
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
*/
|
|
410
|
-
getFlatNavigation(navigation, flatNavigation = []) {
|
|
411
|
-
for (const item of navigation) {
|
|
412
|
-
if (item.type === 'basic') {
|
|
413
|
-
flatNavigation.push(item);
|
|
414
|
-
}
|
|
415
|
-
if (hasNavigationChildren(item)) {
|
|
416
|
-
this.getFlatNavigation(getNavigationChildren(item), flatNavigation);
|
|
417
|
-
}
|
|
1063
|
+
closeAll() {
|
|
1064
|
+
if (this.active) {
|
|
1065
|
+
this.active.ref.dispose();
|
|
1066
|
+
this.active = null;
|
|
418
1067
|
}
|
|
419
|
-
|
|
1068
|
+
this.openId.set(null);
|
|
420
1069
|
}
|
|
421
|
-
/**
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
1070
|
+
/** Menubar keyboard navigation: ArrowLeft/Right antar trigger, Home/End, ArrowDown fokus panel. */
|
|
1071
|
+
onMenubarKeydown(event) {
|
|
1072
|
+
const key = event.key;
|
|
1073
|
+
const root = this.host.nativeElement;
|
|
1074
|
+
const triggers = Array.from(root.querySelectorAll('ul[role="menubar"] [role="menuitem"]')).filter((el) => !el.hasAttribute('disabled'));
|
|
1075
|
+
if (triggers.length === 0)
|
|
1076
|
+
return;
|
|
1077
|
+
const currentIndex = triggers.indexOf(document.activeElement);
|
|
1078
|
+
if (key === 'ArrowDown' && currentIndex !== -1) {
|
|
1079
|
+
event.preventDefault();
|
|
1080
|
+
// Jika open, fokus item pertama panel; jika belum, focus tetap (panel akan dibuka via click/mouseenter).
|
|
1081
|
+
queueMicrotask(() => this.focusFirstInPanel());
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
if (key !== 'ArrowLeft' && key !== 'ArrowRight' && key !== 'Home' && key !== 'End')
|
|
1085
|
+
return;
|
|
1086
|
+
let nextIndex = currentIndex;
|
|
1087
|
+
if (key === 'ArrowRight')
|
|
1088
|
+
nextIndex = (currentIndex + 1 + triggers.length) % triggers.length;
|
|
1089
|
+
else if (key === 'ArrowLeft')
|
|
1090
|
+
nextIndex = (currentIndex - 1 + triggers.length) % triggers.length;
|
|
1091
|
+
else if (key === 'Home')
|
|
1092
|
+
nextIndex = 0;
|
|
1093
|
+
else if (key === 'End')
|
|
1094
|
+
nextIndex = triggers.length - 1;
|
|
1095
|
+
if (nextIndex !== currentIndex && triggers[nextIndex]) {
|
|
1096
|
+
event.preventDefault();
|
|
1097
|
+
triggers[nextIndex].focus();
|
|
436
1098
|
}
|
|
437
|
-
return null;
|
|
438
1099
|
}
|
|
439
|
-
/**
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
1100
|
+
/** Arrow-key navigation dalam dropdown/mega panel. */
|
|
1101
|
+
onPanelKeydown(event) {
|
|
1102
|
+
const key = event.key;
|
|
1103
|
+
if (key !== 'ArrowDown' &&
|
|
1104
|
+
key !== 'ArrowUp' &&
|
|
1105
|
+
key !== 'ArrowLeft' &&
|
|
1106
|
+
key !== 'ArrowRight' &&
|
|
1107
|
+
key !== 'Home' &&
|
|
1108
|
+
key !== 'End')
|
|
1109
|
+
return;
|
|
1110
|
+
const panel = this.active?.ref.overlayElement;
|
|
1111
|
+
if (!panel)
|
|
1112
|
+
return;
|
|
1113
|
+
const items = this.collectPanelFocusables(panel);
|
|
1114
|
+
if (items.length === 0)
|
|
1115
|
+
return;
|
|
1116
|
+
const currentIndex = items.indexOf(document.activeElement);
|
|
1117
|
+
let nextIndex = currentIndex;
|
|
1118
|
+
if (key === 'ArrowDown' || key === 'ArrowRight')
|
|
1119
|
+
nextIndex = (currentIndex + 1 + items.length) % items.length;
|
|
1120
|
+
else if (key === 'ArrowUp' || key === 'ArrowLeft')
|
|
1121
|
+
nextIndex = (currentIndex - 1 + items.length) % items.length;
|
|
1122
|
+
else if (key === 'Home')
|
|
1123
|
+
nextIndex = 0;
|
|
1124
|
+
else if (key === 'End')
|
|
1125
|
+
nextIndex = items.length - 1;
|
|
1126
|
+
if (nextIndex !== currentIndex && items[nextIndex]) {
|
|
1127
|
+
event.preventDefault();
|
|
1128
|
+
items[nextIndex].focus();
|
|
454
1129
|
}
|
|
455
|
-
return null;
|
|
456
1130
|
}
|
|
457
|
-
|
|
458
|
-
|
|
1131
|
+
collectPanelFocusables(root) {
|
|
1132
|
+
return Array.from(root.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((el) => el.offsetParent !== null || el.getClientRects().length > 0);
|
|
1133
|
+
}
|
|
1134
|
+
focusFirstInPanel() {
|
|
1135
|
+
const panel = this.active?.ref.overlayElement;
|
|
1136
|
+
if (!panel)
|
|
1137
|
+
return;
|
|
1138
|
+
const items = this.collectPanelFocusables(panel);
|
|
1139
|
+
items[0]?.focus();
|
|
1140
|
+
}
|
|
1141
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TopbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1142
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: TopbarComponent, isStandalone: true, selector: "ui-topbar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, navigationId: { classPropertyName: "navigationId", publicName: "navigationId", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, autoRegister: { classPropertyName: "autoRegister", publicName: "autoRegister", isSignal: true, isRequired: false, transformFunction: null }, showHamburger: { classPropertyName: "showHamburger", publicName: "showHamburger", isSignal: true, isRequired: false, transformFunction: null }, hamburgerLabel: { classPropertyName: "hamburgerLabel", publicName: "hamburgerLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel()", "class": "hostClasses()", "attr.data-appearance": "appearance()" } }, viewQueries: [{ propertyName: "dropdownTpl", first: true, predicate: ["dropdownTpl"], descendants: true, isSignal: true }, { propertyName: "megaTpl", first: true, predicate: ["megaTpl"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1143
|
+
<div class="flex h-14 w-full items-center gap-3 px-3">
|
|
1144
|
+
<div data-ui-topbar-slot="start" class="flex shrink-0 items-center gap-2">
|
|
1145
|
+
@if (showHamburger()) {
|
|
1146
|
+
<button
|
|
1147
|
+
type="button"
|
|
1148
|
+
class="inline-flex h-9 w-9 items-center justify-center rounded-md text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring md:hidden"
|
|
1149
|
+
[attr.aria-label]="hamburgerLabel()"
|
|
1150
|
+
[attr.aria-expanded]="nav.mobileOpen()"
|
|
1151
|
+
(click)="nav.toggleMobile()">
|
|
1152
|
+
<ui-nav-icon name="menu" [size]="18" />
|
|
1153
|
+
</button>
|
|
1154
|
+
}
|
|
1155
|
+
<ng-content select="[ui-topbar-start]" />
|
|
1156
|
+
</div>
|
|
1157
|
+
|
|
1158
|
+
<div data-ui-topbar-slot="nav" class="flex min-w-0 flex-1 items-center justify-center">
|
|
1159
|
+
<ul
|
|
1160
|
+
class="flex min-w-0 flex-1 items-center justify-center gap-1"
|
|
1161
|
+
role="menubar"
|
|
1162
|
+
(keydown)="onMenubarKeydown($event)">
|
|
1163
|
+
@for (item of resolvedItems(); track item.id) {
|
|
1164
|
+
<li role="none" class="relative">
|
|
1165
|
+
@switch (item.type) {
|
|
1166
|
+
@case ('basic') {
|
|
1167
|
+
@let basic = asBasic(item);
|
|
1168
|
+
<a
|
|
1169
|
+
role="menuitem"
|
|
1170
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary"
|
|
1171
|
+
[routerLink]="basic.link"
|
|
1172
|
+
routerLinkActive
|
|
1173
|
+
#rla="routerLinkActive"
|
|
1174
|
+
[class.text-primary]="rla.isActive"
|
|
1175
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
1176
|
+
[target]="basic.target ?? undefined">
|
|
1177
|
+
@if (basic.icon) {
|
|
1178
|
+
<ui-nav-icon [name]="basic.icon" [size]="18" />
|
|
1179
|
+
}
|
|
1180
|
+
<span>{{ basic.title }}</span>
|
|
1181
|
+
</a>
|
|
1182
|
+
}
|
|
1183
|
+
@case ('collapsable') {
|
|
1184
|
+
@let col = asCollapsable(item);
|
|
1185
|
+
<button
|
|
1186
|
+
#trigger
|
|
1187
|
+
type="button"
|
|
1188
|
+
role="menuitem"
|
|
1189
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1190
|
+
[class.text-primary]="isItemActive(col.id)"
|
|
1191
|
+
[attr.aria-expanded]="openId() === col.id"
|
|
1192
|
+
[attr.aria-haspopup]="'menu'"
|
|
1193
|
+
(click)="toggleDropdown(trigger, item)"
|
|
1194
|
+
(mouseenter)="openDropdown(trigger, item)">
|
|
1195
|
+
@if (col.icon) {
|
|
1196
|
+
<ui-nav-icon [name]="col.icon" [size]="18" />
|
|
1197
|
+
}
|
|
1198
|
+
<span>{{ col.title }}</span>
|
|
1199
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1200
|
+
</button>
|
|
1201
|
+
}
|
|
1202
|
+
@case ('group') {
|
|
1203
|
+
@let group = asGroup(item);
|
|
1204
|
+
<button
|
|
1205
|
+
#trigger
|
|
1206
|
+
type="button"
|
|
1207
|
+
role="menuitem"
|
|
1208
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1209
|
+
[class.text-primary]="isItemActive(group.id)"
|
|
1210
|
+
[attr.aria-expanded]="openId() === group.id"
|
|
1211
|
+
[attr.aria-haspopup]="'menu'"
|
|
1212
|
+
(click)="toggleDropdown(trigger, item)"
|
|
1213
|
+
(mouseenter)="openDropdown(trigger, item)">
|
|
1214
|
+
@if (group.icon) {
|
|
1215
|
+
<ui-nav-icon [name]="group.icon" [size]="18" />
|
|
1216
|
+
}
|
|
1217
|
+
<span>{{ group.title }}</span>
|
|
1218
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1219
|
+
</button>
|
|
1220
|
+
}
|
|
1221
|
+
@case ('mega') {
|
|
1222
|
+
@let mega = asMega(item);
|
|
1223
|
+
<button
|
|
1224
|
+
#trigger
|
|
1225
|
+
type="button"
|
|
1226
|
+
role="menuitem"
|
|
1227
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1228
|
+
[class.text-primary]="isItemActive(mega.id)"
|
|
1229
|
+
[attr.aria-expanded]="openId() === mega.id"
|
|
1230
|
+
[attr.aria-haspopup]="'menu'"
|
|
1231
|
+
(click)="toggleMega(trigger, item)"
|
|
1232
|
+
(mouseenter)="openMega(trigger, item)">
|
|
1233
|
+
@if (mega.icon) {
|
|
1234
|
+
<ui-nav-icon [name]="mega.icon" [size]="18" />
|
|
1235
|
+
}
|
|
1236
|
+
<span>{{ mega.title }}</span>
|
|
1237
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1238
|
+
</button>
|
|
1239
|
+
}
|
|
1240
|
+
@default {
|
|
1241
|
+
<span class="ui-nav-heading px-3 py-2 text-muted-foreground">
|
|
1242
|
+
{{ item.title }}
|
|
1243
|
+
</span>
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
</li>
|
|
1247
|
+
}
|
|
1248
|
+
</ul>
|
|
1249
|
+
</div>
|
|
1250
|
+
|
|
1251
|
+
<div data-ui-topbar-slot="end" class="flex shrink-0 items-center justify-end gap-2">
|
|
1252
|
+
<ng-content select="[ui-topbar-end]" />
|
|
1253
|
+
</div>
|
|
1254
|
+
</div>
|
|
1255
|
+
|
|
1256
|
+
<!-- Dropdown template -->
|
|
1257
|
+
<ng-template #dropdownTpl let-item>
|
|
1258
|
+
<div
|
|
1259
|
+
role="menu"
|
|
1260
|
+
class="min-w-56 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md"
|
|
1261
|
+
(keydown)="onPanelKeydown($event)">
|
|
1262
|
+
@for (child of item.children; track child.id) {
|
|
1263
|
+
<ui-nav-item [item]="child" />
|
|
1264
|
+
}
|
|
1265
|
+
</div>
|
|
1266
|
+
</ng-template>
|
|
1267
|
+
|
|
1268
|
+
<!-- Mega panel template -->
|
|
1269
|
+
<ng-template #megaTpl let-item>
|
|
1270
|
+
<div
|
|
1271
|
+
role="menu"
|
|
1272
|
+
class="w-screen max-w-[min(90vw,72rem)] rounded-md border border-border bg-popover p-6 text-popover-foreground shadow-lg"
|
|
1273
|
+
(keydown)="onPanelKeydown($event)">
|
|
1274
|
+
<div class="grid gap-6" [ngClass]="megaColsClass(item.columns)">
|
|
1275
|
+
@for (col of item.children; track col.id) {
|
|
1276
|
+
<div>
|
|
1277
|
+
<div class="ui-nav-heading mb-2 text-muted-foreground">
|
|
1278
|
+
{{ col.title }}
|
|
1279
|
+
</div>
|
|
1280
|
+
<div class="flex flex-col gap-0.5">
|
|
1281
|
+
@for (leaf of col.children ?? []; track leaf.id) {
|
|
1282
|
+
<ui-nav-item [item]="leaf" />
|
|
1283
|
+
}
|
|
1284
|
+
</div>
|
|
1285
|
+
</div>
|
|
1286
|
+
}
|
|
1287
|
+
</div>
|
|
1288
|
+
</div>
|
|
1289
|
+
</ng-template>
|
|
1290
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: UiNavIconComponent, selector: "ui-nav-icon", inputs: ["name", "class", "size"] }, { kind: "component", type: UiNavItemComponent, selector: "ui-nav-item", inputs: ["item", "level", "compact"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
459
1291
|
}
|
|
460
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
461
|
-
type:
|
|
462
|
-
args: [{
|
|
463
|
-
|
|
1292
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TopbarComponent, decorators: [{
|
|
1293
|
+
type: Component,
|
|
1294
|
+
args: [{
|
|
1295
|
+
selector: 'ui-topbar',
|
|
1296
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1297
|
+
imports: [NgClass, RouterLink, RouterLinkActive, UiNavIconComponent, UiNavItemComponent],
|
|
1298
|
+
host: {
|
|
1299
|
+
role: 'navigation',
|
|
1300
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
1301
|
+
'[class]': 'hostClasses()',
|
|
1302
|
+
'[attr.data-appearance]': 'appearance()',
|
|
1303
|
+
},
|
|
1304
|
+
template: `
|
|
1305
|
+
<div class="flex h-14 w-full items-center gap-3 px-3">
|
|
1306
|
+
<div data-ui-topbar-slot="start" class="flex shrink-0 items-center gap-2">
|
|
1307
|
+
@if (showHamburger()) {
|
|
1308
|
+
<button
|
|
1309
|
+
type="button"
|
|
1310
|
+
class="inline-flex h-9 w-9 items-center justify-center rounded-md text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring md:hidden"
|
|
1311
|
+
[attr.aria-label]="hamburgerLabel()"
|
|
1312
|
+
[attr.aria-expanded]="nav.mobileOpen()"
|
|
1313
|
+
(click)="nav.toggleMobile()">
|
|
1314
|
+
<ui-nav-icon name="menu" [size]="18" />
|
|
1315
|
+
</button>
|
|
1316
|
+
}
|
|
1317
|
+
<ng-content select="[ui-topbar-start]" />
|
|
1318
|
+
</div>
|
|
1319
|
+
|
|
1320
|
+
<div data-ui-topbar-slot="nav" class="flex min-w-0 flex-1 items-center justify-center">
|
|
1321
|
+
<ul
|
|
1322
|
+
class="flex min-w-0 flex-1 items-center justify-center gap-1"
|
|
1323
|
+
role="menubar"
|
|
1324
|
+
(keydown)="onMenubarKeydown($event)">
|
|
1325
|
+
@for (item of resolvedItems(); track item.id) {
|
|
1326
|
+
<li role="none" class="relative">
|
|
1327
|
+
@switch (item.type) {
|
|
1328
|
+
@case ('basic') {
|
|
1329
|
+
@let basic = asBasic(item);
|
|
1330
|
+
<a
|
|
1331
|
+
role="menuitem"
|
|
1332
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-primary"
|
|
1333
|
+
[routerLink]="basic.link"
|
|
1334
|
+
routerLinkActive
|
|
1335
|
+
#rla="routerLinkActive"
|
|
1336
|
+
[class.text-primary]="rla.isActive"
|
|
1337
|
+
[attr.aria-current]="rla.isActive ? 'page' : null"
|
|
1338
|
+
[target]="basic.target ?? undefined">
|
|
1339
|
+
@if (basic.icon) {
|
|
1340
|
+
<ui-nav-icon [name]="basic.icon" [size]="18" />
|
|
1341
|
+
}
|
|
1342
|
+
<span>{{ basic.title }}</span>
|
|
1343
|
+
</a>
|
|
1344
|
+
}
|
|
1345
|
+
@case ('collapsable') {
|
|
1346
|
+
@let col = asCollapsable(item);
|
|
1347
|
+
<button
|
|
1348
|
+
#trigger
|
|
1349
|
+
type="button"
|
|
1350
|
+
role="menuitem"
|
|
1351
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1352
|
+
[class.text-primary]="isItemActive(col.id)"
|
|
1353
|
+
[attr.aria-expanded]="openId() === col.id"
|
|
1354
|
+
[attr.aria-haspopup]="'menu'"
|
|
1355
|
+
(click)="toggleDropdown(trigger, item)"
|
|
1356
|
+
(mouseenter)="openDropdown(trigger, item)">
|
|
1357
|
+
@if (col.icon) {
|
|
1358
|
+
<ui-nav-icon [name]="col.icon" [size]="18" />
|
|
1359
|
+
}
|
|
1360
|
+
<span>{{ col.title }}</span>
|
|
1361
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1362
|
+
</button>
|
|
1363
|
+
}
|
|
1364
|
+
@case ('group') {
|
|
1365
|
+
@let group = asGroup(item);
|
|
1366
|
+
<button
|
|
1367
|
+
#trigger
|
|
1368
|
+
type="button"
|
|
1369
|
+
role="menuitem"
|
|
1370
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1371
|
+
[class.text-primary]="isItemActive(group.id)"
|
|
1372
|
+
[attr.aria-expanded]="openId() === group.id"
|
|
1373
|
+
[attr.aria-haspopup]="'menu'"
|
|
1374
|
+
(click)="toggleDropdown(trigger, item)"
|
|
1375
|
+
(mouseenter)="openDropdown(trigger, item)">
|
|
1376
|
+
@if (group.icon) {
|
|
1377
|
+
<ui-nav-icon [name]="group.icon" [size]="18" />
|
|
1378
|
+
}
|
|
1379
|
+
<span>{{ group.title }}</span>
|
|
1380
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1381
|
+
</button>
|
|
1382
|
+
}
|
|
1383
|
+
@case ('mega') {
|
|
1384
|
+
@let mega = asMega(item);
|
|
1385
|
+
<button
|
|
1386
|
+
#trigger
|
|
1387
|
+
type="button"
|
|
1388
|
+
role="menuitem"
|
|
1389
|
+
class="ui-nav-text inline-flex items-center gap-2 rounded-md px-3 py-2 text-foreground/80 hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1390
|
+
[class.text-primary]="isItemActive(mega.id)"
|
|
1391
|
+
[attr.aria-expanded]="openId() === mega.id"
|
|
1392
|
+
[attr.aria-haspopup]="'menu'"
|
|
1393
|
+
(click)="toggleMega(trigger, item)"
|
|
1394
|
+
(mouseenter)="openMega(trigger, item)">
|
|
1395
|
+
@if (mega.icon) {
|
|
1396
|
+
<ui-nav-icon [name]="mega.icon" [size]="18" />
|
|
1397
|
+
}
|
|
1398
|
+
<span>{{ mega.title }}</span>
|
|
1399
|
+
<ui-nav-icon name="expand_more" [size]="18" />
|
|
1400
|
+
</button>
|
|
1401
|
+
}
|
|
1402
|
+
@default {
|
|
1403
|
+
<span class="ui-nav-heading px-3 py-2 text-muted-foreground">
|
|
1404
|
+
{{ item.title }}
|
|
1405
|
+
</span>
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
</li>
|
|
1409
|
+
}
|
|
1410
|
+
</ul>
|
|
1411
|
+
</div>
|
|
1412
|
+
|
|
1413
|
+
<div data-ui-topbar-slot="end" class="flex shrink-0 items-center justify-end gap-2">
|
|
1414
|
+
<ng-content select="[ui-topbar-end]" />
|
|
1415
|
+
</div>
|
|
1416
|
+
</div>
|
|
464
1417
|
|
|
465
|
-
|
|
1418
|
+
<!-- Dropdown template -->
|
|
1419
|
+
<ng-template #dropdownTpl let-item>
|
|
1420
|
+
<div
|
|
1421
|
+
role="menu"
|
|
1422
|
+
class="min-w-56 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md"
|
|
1423
|
+
(keydown)="onPanelKeydown($event)">
|
|
1424
|
+
@for (child of item.children; track child.id) {
|
|
1425
|
+
<ui-nav-item [item]="child" />
|
|
1426
|
+
}
|
|
1427
|
+
</div>
|
|
1428
|
+
</ng-template>
|
|
1429
|
+
|
|
1430
|
+
<!-- Mega panel template -->
|
|
1431
|
+
<ng-template #megaTpl let-item>
|
|
1432
|
+
<div
|
|
1433
|
+
role="menu"
|
|
1434
|
+
class="w-screen max-w-[min(90vw,72rem)] rounded-md border border-border bg-popover p-6 text-popover-foreground shadow-lg"
|
|
1435
|
+
(keydown)="onPanelKeydown($event)">
|
|
1436
|
+
<div class="grid gap-6" [ngClass]="megaColsClass(item.columns)">
|
|
1437
|
+
@for (col of item.children; track col.id) {
|
|
1438
|
+
<div>
|
|
1439
|
+
<div class="ui-nav-heading mb-2 text-muted-foreground">
|
|
1440
|
+
{{ col.title }}
|
|
1441
|
+
</div>
|
|
1442
|
+
<div class="flex flex-col gap-0.5">
|
|
1443
|
+
@for (leaf of col.children ?? []; track leaf.id) {
|
|
1444
|
+
<ui-nav-item [item]="leaf" />
|
|
1445
|
+
}
|
|
1446
|
+
</div>
|
|
1447
|
+
</div>
|
|
1448
|
+
}
|
|
1449
|
+
</div>
|
|
1450
|
+
</div>
|
|
1451
|
+
</ng-template>
|
|
1452
|
+
`,
|
|
1453
|
+
}]
|
|
1454
|
+
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], navigationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationId", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], autoRegister: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoRegister", required: false }] }], showHamburger: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHamburger", required: false }] }], hamburgerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hamburgerLabel", required: false }] }], dropdownTpl: [{ type: i0.ViewChild, args: ['dropdownTpl', { isSignal: true }] }], megaTpl: [{ type: i0.ViewChild, args: ['megaTpl', { isSignal: true }] }] } });
|
|
1455
|
+
|
|
1456
|
+
const DemoNavigationData = [
|
|
1457
|
+
{
|
|
1458
|
+
id: 'documentation',
|
|
1459
|
+
title: 'Documentation',
|
|
1460
|
+
subtitle: 'Guides and getting started resources',
|
|
1461
|
+
type: 'group',
|
|
1462
|
+
icon: 'menu_book',
|
|
1463
|
+
children: [
|
|
1464
|
+
{
|
|
1465
|
+
id: 'documentation-introduction',
|
|
1466
|
+
title: 'Introduction',
|
|
1467
|
+
type: 'basic',
|
|
1468
|
+
icon: 'menu_book',
|
|
1469
|
+
link: '/docs/introduction',
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
id: 'documentation-installation',
|
|
1473
|
+
title: 'Installation',
|
|
1474
|
+
type: 'basic',
|
|
1475
|
+
icon: 'download',
|
|
1476
|
+
link: '/docs/installation',
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
id: 'documentation-getting-started',
|
|
1480
|
+
title: 'Getting started',
|
|
1481
|
+
type: 'basic',
|
|
1482
|
+
icon: 'rocket_launch',
|
|
1483
|
+
link: '/docs/getting-started',
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
id: 'documentation-upgrade-guide',
|
|
1487
|
+
title: 'Upgrade Guide',
|
|
1488
|
+
type: 'basic',
|
|
1489
|
+
icon: 'arrow_circle_up',
|
|
1490
|
+
link: '/docs/upgrade-guide',
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
id: 'documentation-changelog',
|
|
1494
|
+
title: 'Changelog',
|
|
1495
|
+
type: 'basic',
|
|
1496
|
+
icon: 'history',
|
|
1497
|
+
link: '/docs/changelog',
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
id: 'documentation-icon-lucide',
|
|
1501
|
+
title: 'Lucide Icons',
|
|
1502
|
+
type: 'basic',
|
|
1503
|
+
icon: 'star',
|
|
1504
|
+
link: '/lucide-icons',
|
|
1505
|
+
badge: {
|
|
1506
|
+
title: 'Demo',
|
|
1507
|
+
classes: 'ml-2 px-2 py-0.5 rounded-full text-xs bg-blue-500 text-white',
|
|
1508
|
+
},
|
|
1509
|
+
},
|
|
1510
|
+
],
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
id: 'user-interface',
|
|
1514
|
+
title: 'User Interface',
|
|
1515
|
+
subtitle: 'Components and design elements',
|
|
1516
|
+
type: 'group',
|
|
1517
|
+
icon: 'dashboard',
|
|
1518
|
+
children: [
|
|
1519
|
+
{
|
|
1520
|
+
id: 'user-interface-material-components',
|
|
1521
|
+
title: 'Material Components',
|
|
1522
|
+
type: 'collapsable',
|
|
1523
|
+
icon: 'deployed_code',
|
|
1524
|
+
children: [
|
|
1525
|
+
{
|
|
1526
|
+
id: 'user-interface-material-components-inputs-forms',
|
|
1527
|
+
title: 'Inputs & Forms',
|
|
1528
|
+
type: 'collapsable',
|
|
1529
|
+
icon: 'input',
|
|
1530
|
+
children: [
|
|
1531
|
+
{
|
|
1532
|
+
id: 'user-interface-material-components-inputs-forms-autocomplete',
|
|
1533
|
+
title: 'Autocomplete',
|
|
1534
|
+
type: 'basic',
|
|
1535
|
+
icon: 'search',
|
|
1536
|
+
link: '/ui/material/autocomplete',
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
id: 'user-interface-material-components-inputs-forms-checkbox',
|
|
1540
|
+
title: 'Checkbox',
|
|
1541
|
+
type: 'basic',
|
|
1542
|
+
icon: 'check_box',
|
|
1543
|
+
link: '/ui/material/checkbox',
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
id: 'user-interface-material-components-inputs-forms-datepicker',
|
|
1547
|
+
title: 'Datepicker',
|
|
1548
|
+
type: 'basic',
|
|
1549
|
+
icon: 'calendar_today',
|
|
1550
|
+
link: '/ui/material/datepicker',
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
id: 'user-interface-material-components-inputs-forms-form-field',
|
|
1554
|
+
title: 'Form field',
|
|
1555
|
+
type: 'basic',
|
|
1556
|
+
icon: 'text_fields',
|
|
1557
|
+
link: '/ui/material/form-field',
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
id: 'user-interface-material-components-inputs-forms-input',
|
|
1561
|
+
title: 'Input',
|
|
1562
|
+
type: 'basic',
|
|
1563
|
+
icon: 'text_fields',
|
|
1564
|
+
link: '/ui/material/input',
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
id: 'user-interface-material-components-inputs-forms-radio-button',
|
|
1568
|
+
title: 'Radio button',
|
|
1569
|
+
type: 'basic',
|
|
1570
|
+
icon: 'radio_button_checked',
|
|
1571
|
+
link: '/ui/material/radio',
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
id: 'user-interface-material-components-inputs-forms-select',
|
|
1575
|
+
title: 'Select',
|
|
1576
|
+
type: 'basic',
|
|
1577
|
+
icon: 'expand_more',
|
|
1578
|
+
link: '/ui/material/select',
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
id: 'user-interface-material-components-inputs-forms-slider',
|
|
1582
|
+
title: 'Slider',
|
|
1583
|
+
type: 'basic',
|
|
1584
|
+
icon: 'tune',
|
|
1585
|
+
link: '/ui/material/slider',
|
|
1586
|
+
},
|
|
1587
|
+
{
|
|
1588
|
+
id: 'user-interface-material-components-inputs-forms-slide-toggle',
|
|
1589
|
+
title: 'Slide toggle',
|
|
1590
|
+
type: 'basic',
|
|
1591
|
+
icon: 'toggle_on',
|
|
1592
|
+
link: '/ui/material/slide-toggle',
|
|
1593
|
+
},
|
|
1594
|
+
],
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
id: 'user-interface-material-components-buttons-actions',
|
|
1598
|
+
title: 'Buttons & Actions',
|
|
1599
|
+
type: 'collapsable',
|
|
1600
|
+
icon: 'ads_click',
|
|
1601
|
+
children: [
|
|
1602
|
+
{
|
|
1603
|
+
id: 'user-interface-material-components-buttons-actions-button',
|
|
1604
|
+
title: 'Button',
|
|
1605
|
+
type: 'basic',
|
|
1606
|
+
icon: 'crop_square',
|
|
1607
|
+
link: '/ui/material/button',
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
id: 'user-interface-material-components-buttons-actions-button-toggle',
|
|
1611
|
+
title: 'Button toggle',
|
|
1612
|
+
type: 'basic',
|
|
1613
|
+
icon: 'view_column',
|
|
1614
|
+
link: '/ui/material/button-toggle',
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
id: 'user-interface-material-components-buttons-actions-chips',
|
|
1618
|
+
title: 'Chips',
|
|
1619
|
+
type: 'basic',
|
|
1620
|
+
icon: 'label',
|
|
1621
|
+
link: '/ui/material/chips',
|
|
1622
|
+
badge: {
|
|
1623
|
+
title: 'New',
|
|
1624
|
+
classes: 'ml-2 px-2 py-0.5 rounded-full text-xs bg-green-500 text-white',
|
|
1625
|
+
},
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
id: 'user-interface-material-components-buttons-actions-menu',
|
|
1629
|
+
title: 'Menu',
|
|
1630
|
+
type: 'basic',
|
|
1631
|
+
icon: 'menu',
|
|
1632
|
+
link: '/ui/material/menu',
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
id: 'user-interface-material-components-buttons-actions-ripples',
|
|
1636
|
+
title: 'Ripples',
|
|
1637
|
+
type: 'basic',
|
|
1638
|
+
icon: 'waves',
|
|
1639
|
+
link: '/ui/material/ripples',
|
|
1640
|
+
},
|
|
1641
|
+
],
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
id: 'user-interface-material-components-layout-containers',
|
|
1645
|
+
title: 'Layout & Containers',
|
|
1646
|
+
type: 'collapsable',
|
|
1647
|
+
icon: 'dashboard',
|
|
1648
|
+
children: [
|
|
1649
|
+
{
|
|
1650
|
+
id: 'user-interface-material-components-layout-containers-card',
|
|
1651
|
+
title: 'Card',
|
|
1652
|
+
type: 'basic',
|
|
1653
|
+
icon: 'credit_card',
|
|
1654
|
+
link: '/ui/material/card',
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
id: 'user-interface-material-components-layout-containers-divider',
|
|
1658
|
+
title: 'Divider',
|
|
1659
|
+
type: 'basic',
|
|
1660
|
+
icon: 'remove',
|
|
1661
|
+
link: '/ui/material/divider',
|
|
1662
|
+
},
|
|
1663
|
+
{
|
|
1664
|
+
id: 'user-interface-material-components-layout-containers-expansion-panel',
|
|
1665
|
+
title: 'Expansion Panel',
|
|
1666
|
+
type: 'basic',
|
|
1667
|
+
icon: 'expand_more',
|
|
1668
|
+
link: '/ui/material/expansion',
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
id: 'user-interface-material-components-layout-containers-grid-list',
|
|
1672
|
+
title: 'Grid list',
|
|
1673
|
+
type: 'basic',
|
|
1674
|
+
icon: 'grid_view',
|
|
1675
|
+
link: '/ui/material/grid-list',
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
id: 'user-interface-material-components-layout-containers-list',
|
|
1679
|
+
title: 'List',
|
|
1680
|
+
type: 'basic',
|
|
1681
|
+
icon: 'list',
|
|
1682
|
+
link: '/ui/material/list',
|
|
1683
|
+
},
|
|
1684
|
+
{
|
|
1685
|
+
id: 'user-interface-material-components-layout-containers-sidenav',
|
|
1686
|
+
title: 'Sidenav',
|
|
1687
|
+
type: 'basic',
|
|
1688
|
+
icon: 'view_sidebar',
|
|
1689
|
+
link: '/ui/material/sidenav',
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
id: 'user-interface-material-components-layout-containers-tabs',
|
|
1693
|
+
title: 'Tabs',
|
|
1694
|
+
type: 'basic',
|
|
1695
|
+
icon: 'tab',
|
|
1696
|
+
link: '/ui/material/tabs',
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
id: 'user-interface-material-components-layout-containers-toolbar',
|
|
1700
|
+
title: 'Toolbar',
|
|
1701
|
+
type: 'basic',
|
|
1702
|
+
icon: 'build',
|
|
1703
|
+
link: '/ui/material/toolbar',
|
|
1704
|
+
},
|
|
1705
|
+
],
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
id: 'user-interface-material-components-data-display',
|
|
1709
|
+
title: 'Data & Display',
|
|
1710
|
+
type: 'collapsable',
|
|
1711
|
+
icon: 'bar_chart',
|
|
1712
|
+
children: [
|
|
1713
|
+
{
|
|
1714
|
+
id: 'user-interface-material-components-data-display-badge',
|
|
1715
|
+
title: 'Badge',
|
|
1716
|
+
type: 'basic',
|
|
1717
|
+
icon: 'verified',
|
|
1718
|
+
link: '/ui/material/badge',
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
id: 'user-interface-material-components-data-display-icon',
|
|
1722
|
+
title: 'Icon',
|
|
1723
|
+
type: 'basic',
|
|
1724
|
+
icon: 'star',
|
|
1725
|
+
link: '/ui/material/icon',
|
|
1726
|
+
},
|
|
1727
|
+
{
|
|
1728
|
+
id: 'user-interface-material-components-data-display-paginator',
|
|
1729
|
+
title: 'Paginator',
|
|
1730
|
+
type: 'basic',
|
|
1731
|
+
icon: 'first_page',
|
|
1732
|
+
link: '/ui/material/paginator',
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
id: 'user-interface-material-components-data-display-progress-bar',
|
|
1736
|
+
title: 'Progress bar',
|
|
1737
|
+
type: 'basic',
|
|
1738
|
+
icon: 'hourglass_empty',
|
|
1739
|
+
link: '/ui/material/progress-bar',
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
id: 'user-interface-material-components-data-display-progress-spinner',
|
|
1743
|
+
title: 'Progress spinner',
|
|
1744
|
+
type: 'basic',
|
|
1745
|
+
icon: 'progress_activity',
|
|
1746
|
+
link: '/ui/material/progress-spinner',
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
id: 'user-interface-material-components-data-display-sort',
|
|
1750
|
+
title: 'Sort header',
|
|
1751
|
+
type: 'basic',
|
|
1752
|
+
icon: 'swap_vert',
|
|
1753
|
+
link: '/ui/material/sort',
|
|
1754
|
+
},
|
|
1755
|
+
{
|
|
1756
|
+
id: 'user-interface-material-components-data-display-table',
|
|
1757
|
+
title: 'Table',
|
|
1758
|
+
type: 'basic',
|
|
1759
|
+
icon: 'table_chart',
|
|
1760
|
+
link: '/ui/material/table',
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
id: 'user-interface-material-components-data-display-tree',
|
|
1764
|
+
title: 'Tree',
|
|
1765
|
+
type: 'basic',
|
|
1766
|
+
icon: 'hub',
|
|
1767
|
+
link: '/ui/material/tree',
|
|
1768
|
+
},
|
|
1769
|
+
],
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
id: 'user-interface-material-components-overlays-modals',
|
|
1773
|
+
title: 'Overlays & Modals',
|
|
1774
|
+
type: 'collapsable',
|
|
1775
|
+
icon: 'layers',
|
|
1776
|
+
children: [
|
|
1777
|
+
{
|
|
1778
|
+
id: 'user-interface-material-components-overlays-modals-bottom-sheet',
|
|
1779
|
+
title: 'Bottom Sheet',
|
|
1780
|
+
type: 'basic',
|
|
1781
|
+
icon: 'south',
|
|
1782
|
+
link: '/ui/material/bottom-sheet',
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
id: 'user-interface-material-components-overlays-modals-dialog',
|
|
1786
|
+
title: 'Dialog',
|
|
1787
|
+
type: 'basic',
|
|
1788
|
+
icon: 'chat',
|
|
1789
|
+
link: '/ui/material/dialog',
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
id: 'user-interface-material-components-overlays-modals-snack-bar',
|
|
1793
|
+
title: 'Snack-bar',
|
|
1794
|
+
type: 'basic',
|
|
1795
|
+
icon: 'notifications',
|
|
1796
|
+
link: '/ui/material/snack-bar',
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
id: 'user-interface-material-components-overlays-modals-tooltip',
|
|
1800
|
+
title: 'Tooltip',
|
|
1801
|
+
type: 'basic',
|
|
1802
|
+
icon: 'help',
|
|
1803
|
+
link: '/ui/material/tooltip',
|
|
1804
|
+
},
|
|
1805
|
+
],
|
|
1806
|
+
},
|
|
1807
|
+
{
|
|
1808
|
+
id: 'user-interface-material-components-navigation-stepper',
|
|
1809
|
+
title: 'Navigation & Steps',
|
|
1810
|
+
type: 'collapsable',
|
|
1811
|
+
icon: 'account_tree',
|
|
1812
|
+
children: [
|
|
1813
|
+
{
|
|
1814
|
+
id: 'user-interface-material-components-navigation-stepper-stepper',
|
|
1815
|
+
title: 'Stepper',
|
|
1816
|
+
type: 'basic',
|
|
1817
|
+
icon: 'account_tree',
|
|
1818
|
+
link: '/ui/material/stepper',
|
|
1819
|
+
},
|
|
1820
|
+
],
|
|
1821
|
+
},
|
|
1822
|
+
],
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
id: 'user-interface-angular-cdk',
|
|
1826
|
+
title: 'Angular CDK',
|
|
1827
|
+
type: 'collapsable',
|
|
1828
|
+
icon: 'widgets',
|
|
1829
|
+
children: [
|
|
1830
|
+
{
|
|
1831
|
+
id: 'user-interface-angular-cdk-accessibility-navigation',
|
|
1832
|
+
title: 'Accessibility & Navigation',
|
|
1833
|
+
type: 'collapsable',
|
|
1834
|
+
icon: 'accessibility',
|
|
1835
|
+
children: [
|
|
1836
|
+
{
|
|
1837
|
+
id: 'user-interface-angular-cdk-accessibility-navigation-a11y',
|
|
1838
|
+
title: 'Accessibility',
|
|
1839
|
+
type: 'basic',
|
|
1840
|
+
icon: 'accessibility',
|
|
1841
|
+
link: '/ui/cdk/a11y',
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
id: 'user-interface-angular-cdk-accessibility-navigation-focus-trap',
|
|
1845
|
+
title: 'Focus Trap',
|
|
1846
|
+
type: 'basic',
|
|
1847
|
+
icon: 'center_focus_strong',
|
|
1848
|
+
link: '/ui/cdk/focus-trap',
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
id: 'user-interface-angular-cdk-accessibility-navigation-live-announcer',
|
|
1852
|
+
title: 'Live Announcer',
|
|
1853
|
+
type: 'basic',
|
|
1854
|
+
icon: 'campaign',
|
|
1855
|
+
link: '/ui/cdk/live-announcer',
|
|
1856
|
+
},
|
|
1857
|
+
{
|
|
1858
|
+
id: 'user-interface-angular-cdk-accessibility-navigation-listbox',
|
|
1859
|
+
title: 'Listbox',
|
|
1860
|
+
type: 'basic',
|
|
1861
|
+
icon: 'list',
|
|
1862
|
+
link: '/ui/cdk/listbox',
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
id: 'user-interface-angular-cdk-accessibility-navigation-menu-cdk',
|
|
1866
|
+
title: 'Menu',
|
|
1867
|
+
type: 'basic',
|
|
1868
|
+
icon: 'menu',
|
|
1869
|
+
link: '/ui/cdk/menu',
|
|
1870
|
+
},
|
|
1871
|
+
],
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
id: 'user-interface-angular-cdk-layout-positioning',
|
|
1875
|
+
title: 'Layout & Positioning',
|
|
1876
|
+
type: 'collapsable',
|
|
1877
|
+
icon: 'dashboard',
|
|
1878
|
+
children: [
|
|
1879
|
+
{
|
|
1880
|
+
id: 'user-interface-angular-cdk-layout-positioning-layout',
|
|
1881
|
+
title: 'Layout',
|
|
1882
|
+
type: 'basic',
|
|
1883
|
+
icon: 'dashboard',
|
|
1884
|
+
link: '/ui/cdk/layout',
|
|
1885
|
+
},
|
|
1886
|
+
{
|
|
1887
|
+
id: 'user-interface-angular-cdk-layout-positioning-overlay',
|
|
1888
|
+
title: 'Overlay',
|
|
1889
|
+
type: 'basic',
|
|
1890
|
+
icon: 'layers',
|
|
1891
|
+
link: '/ui/cdk/overlay',
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
id: 'user-interface-angular-cdk-layout-positioning-portal',
|
|
1895
|
+
title: 'Portal',
|
|
1896
|
+
type: 'basic',
|
|
1897
|
+
icon: 'radio_button_checked',
|
|
1898
|
+
link: '/ui/cdk/portal',
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
id: 'user-interface-angular-cdk-layout-positioning-scrolling',
|
|
1902
|
+
title: 'Scrolling',
|
|
1903
|
+
type: 'basic',
|
|
1904
|
+
icon: 'unfold_more',
|
|
1905
|
+
link: '/ui/cdk/scrolling',
|
|
1906
|
+
},
|
|
1907
|
+
{
|
|
1908
|
+
id: 'user-interface-angular-cdk-layout-positioning-virtual-scrolling',
|
|
1909
|
+
title: 'Virtual Scrolling',
|
|
1910
|
+
type: 'basic',
|
|
1911
|
+
icon: 'view_agenda',
|
|
1912
|
+
link: '/ui/cdk/virtual-scrolling',
|
|
1913
|
+
},
|
|
1914
|
+
],
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
id: 'user-interface-angular-cdk-interaction-behavior',
|
|
1918
|
+
title: 'Interaction & Behavior',
|
|
1919
|
+
type: 'collapsable',
|
|
1920
|
+
icon: 'pan_tool',
|
|
1921
|
+
children: [
|
|
1922
|
+
{
|
|
1923
|
+
id: 'user-interface-angular-cdk-interaction-behavior-drag-drop',
|
|
1924
|
+
title: 'Drag and Drop',
|
|
1925
|
+
type: 'basic',
|
|
1926
|
+
icon: 'open_with',
|
|
1927
|
+
link: '/ui/cdk/drag-drop',
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
id: 'user-interface-angular-cdk-interaction-behavior-observers',
|
|
1931
|
+
title: 'Observers',
|
|
1932
|
+
type: 'basic',
|
|
1933
|
+
icon: 'visibility',
|
|
1934
|
+
link: '/ui/cdk/observers',
|
|
1935
|
+
},
|
|
1936
|
+
{
|
|
1937
|
+
id: 'user-interface-angular-cdk-interaction-behavior-platform',
|
|
1938
|
+
title: 'Platform',
|
|
1939
|
+
type: 'basic',
|
|
1940
|
+
icon: 'devices',
|
|
1941
|
+
link: '/ui/cdk/platform',
|
|
1942
|
+
},
|
|
1943
|
+
{
|
|
1944
|
+
id: 'user-interface-angular-cdk-interaction-behavior-stepper-cdk',
|
|
1945
|
+
title: 'Stepper',
|
|
1946
|
+
type: 'basic',
|
|
1947
|
+
icon: 'account_tree',
|
|
1948
|
+
link: '/ui/cdk/stepper',
|
|
1949
|
+
},
|
|
1950
|
+
],
|
|
1951
|
+
},
|
|
1952
|
+
{
|
|
1953
|
+
id: 'user-interface-angular-cdk-forms-data',
|
|
1954
|
+
title: 'Forms & Data',
|
|
1955
|
+
type: 'collapsable',
|
|
1956
|
+
icon: 'storage',
|
|
1957
|
+
children: [
|
|
1958
|
+
{
|
|
1959
|
+
id: 'user-interface-angular-cdk-forms-data-accordion',
|
|
1960
|
+
title: 'Accordion',
|
|
1961
|
+
type: 'basic',
|
|
1962
|
+
icon: 'expand_more',
|
|
1963
|
+
link: '/ui/cdk/accordion',
|
|
1964
|
+
},
|
|
1965
|
+
{
|
|
1966
|
+
id: 'user-interface-angular-cdk-forms-data-table-cdk',
|
|
1967
|
+
title: 'Table',
|
|
1968
|
+
type: 'basic',
|
|
1969
|
+
icon: 'table_chart',
|
|
1970
|
+
link: '/ui/cdk/table',
|
|
1971
|
+
},
|
|
1972
|
+
{
|
|
1973
|
+
id: 'user-interface-angular-cdk-forms-data-tree-cdk',
|
|
1974
|
+
title: 'Tree',
|
|
1975
|
+
type: 'basic',
|
|
1976
|
+
icon: 'hub',
|
|
1977
|
+
link: '/ui/cdk/tree',
|
|
1978
|
+
},
|
|
1979
|
+
],
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
id: 'user-interface-angular-cdk-utilities-helpers',
|
|
1983
|
+
title: 'Utilities & Helpers',
|
|
1984
|
+
type: 'collapsable',
|
|
1985
|
+
icon: 'build',
|
|
1986
|
+
children: [
|
|
1987
|
+
{
|
|
1988
|
+
id: 'user-interface-angular-cdk-utilities-helpers-bidi',
|
|
1989
|
+
title: 'Bidirectionality',
|
|
1990
|
+
type: 'basic',
|
|
1991
|
+
icon: 'swap_horiz',
|
|
1992
|
+
link: '/ui/cdk/bidi',
|
|
1993
|
+
},
|
|
1994
|
+
{
|
|
1995
|
+
id: 'user-interface-angular-cdk-utilities-helpers-clipboard',
|
|
1996
|
+
title: 'Clipboard',
|
|
1997
|
+
type: 'basic',
|
|
1998
|
+
icon: 'content_paste',
|
|
1999
|
+
link: '/ui/cdk/clipboard',
|
|
2000
|
+
},
|
|
2001
|
+
{
|
|
2002
|
+
id: 'user-interface-angular-cdk-utilities-helpers-coercion',
|
|
2003
|
+
title: 'Coercion',
|
|
2004
|
+
type: 'basic',
|
|
2005
|
+
icon: 'shuffle',
|
|
2006
|
+
link: '/ui/cdk/coercion',
|
|
2007
|
+
},
|
|
2008
|
+
{
|
|
2009
|
+
id: 'user-interface-angular-cdk-utilities-helpers-collections',
|
|
2010
|
+
title: 'Collections',
|
|
2011
|
+
type: 'basic',
|
|
2012
|
+
icon: 'folder',
|
|
2013
|
+
link: '/ui/cdk/collections',
|
|
2014
|
+
},
|
|
2015
|
+
{
|
|
2016
|
+
id: 'user-interface-angular-cdk-utilities-helpers-keycodes',
|
|
2017
|
+
title: 'Keycodes',
|
|
2018
|
+
type: 'basic',
|
|
2019
|
+
icon: 'keyboard',
|
|
2020
|
+
link: '/ui/cdk/keycodes',
|
|
2021
|
+
},
|
|
2022
|
+
],
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
id: 'user-interface-angular-cdk-testing-tools',
|
|
2026
|
+
title: 'Testing Tools',
|
|
2027
|
+
type: 'collapsable',
|
|
2028
|
+
icon: 'bug_report',
|
|
2029
|
+
children: [
|
|
2030
|
+
{
|
|
2031
|
+
id: 'user-interface-angular-cdk-testing-tools-component-harnesses',
|
|
2032
|
+
title: 'Component Harnesses',
|
|
2033
|
+
type: 'basic',
|
|
2034
|
+
icon: 'science',
|
|
2035
|
+
link: '/ui/cdk/testing',
|
|
2036
|
+
},
|
|
2037
|
+
{
|
|
2038
|
+
id: 'user-interface-angular-cdk-testing-tools-test-harnesses',
|
|
2039
|
+
title: 'Test Harnesses',
|
|
2040
|
+
type: 'basic',
|
|
2041
|
+
icon: 'science',
|
|
2042
|
+
link: '/ui/cdk/test-harnesses',
|
|
2043
|
+
},
|
|
2044
|
+
],
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
id: 'user-interface-angular-cdk-advanced-feature',
|
|
2048
|
+
title: 'Advanced feature',
|
|
2049
|
+
type: 'collapsable',
|
|
2050
|
+
icon: 'settings',
|
|
2051
|
+
children: [
|
|
2052
|
+
{
|
|
2053
|
+
id: 'user-interface-angular-cdk-advanced-feature-dialog-cdk',
|
|
2054
|
+
title: 'Dialog',
|
|
2055
|
+
type: 'basic',
|
|
2056
|
+
icon: 'chat',
|
|
2057
|
+
link: '/ui/cdk/dialog',
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
id: 'user-interface-angular-cdk-advanced-feature-text-field',
|
|
2061
|
+
title: 'Text Field',
|
|
2062
|
+
type: 'basic',
|
|
2063
|
+
icon: 'text_fields',
|
|
2064
|
+
link: '/ui/cdk/text-field',
|
|
2065
|
+
},
|
|
2066
|
+
],
|
|
2067
|
+
},
|
|
2068
|
+
],
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
id: 'user-interface-tailwind',
|
|
2072
|
+
title: 'Tailwind CSS',
|
|
2073
|
+
type: 'collapsable',
|
|
2074
|
+
icon: 'air',
|
|
2075
|
+
children: [
|
|
2076
|
+
{
|
|
2077
|
+
id: 'user-interface-tailwind-css-heading',
|
|
2078
|
+
title: 'Heading',
|
|
2079
|
+
type: 'basic',
|
|
2080
|
+
icon: 'text_fields',
|
|
2081
|
+
link: '/ui/tailwind/heading',
|
|
2082
|
+
},
|
|
2083
|
+
{
|
|
2084
|
+
id: 'user-interface-tailwind-data-display',
|
|
2085
|
+
title: 'Data Display',
|
|
2086
|
+
type: 'basic',
|
|
2087
|
+
icon: 'bar_chart',
|
|
2088
|
+
link: '/ui/tailwind/data-display',
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
id: 'user-interface-tailwind-list',
|
|
2092
|
+
title: 'List',
|
|
2093
|
+
type: 'basic',
|
|
2094
|
+
icon: 'list',
|
|
2095
|
+
link: '/ui/tailwind/list',
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
id: 'user-interface-tailwind-form',
|
|
2099
|
+
title: 'Form',
|
|
2100
|
+
type: 'basic',
|
|
2101
|
+
icon: 'dynamic_form',
|
|
2102
|
+
link: '/ui/tailwind/form',
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
id: 'user-interface-tailwind-feedback',
|
|
2106
|
+
title: 'Feedback',
|
|
2107
|
+
type: 'basic',
|
|
2108
|
+
icon: 'report',
|
|
2109
|
+
link: '/ui/tailwind/feedback',
|
|
2110
|
+
},
|
|
2111
|
+
],
|
|
2112
|
+
},
|
|
2113
|
+
],
|
|
2114
|
+
},
|
|
2115
|
+
{
|
|
2116
|
+
id: 'feature',
|
|
2117
|
+
title: 'Features',
|
|
2118
|
+
subtitle: 'Advanced functionality and customization options',
|
|
2119
|
+
type: 'group',
|
|
2120
|
+
icon: 'settings',
|
|
2121
|
+
children: [
|
|
2122
|
+
{
|
|
2123
|
+
id: 'feature-theme',
|
|
2124
|
+
title: 'Themes',
|
|
2125
|
+
type: 'collapsable',
|
|
2126
|
+
icon: 'palette',
|
|
2127
|
+
children: [
|
|
2128
|
+
{
|
|
2129
|
+
id: 'feature-theme-dark-mode',
|
|
2130
|
+
title: 'Dark Mode',
|
|
2131
|
+
type: 'basic',
|
|
2132
|
+
icon: 'dark_mode',
|
|
2133
|
+
link: '/feature/theme/dark-mode',
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
id: 'feature-theme-color',
|
|
2137
|
+
title: 'Color Schemes',
|
|
2138
|
+
type: 'basic',
|
|
2139
|
+
icon: 'palette',
|
|
2140
|
+
link: '/feature/theme/color-schemes',
|
|
2141
|
+
badge: {
|
|
2142
|
+
title: 'Beta',
|
|
2143
|
+
classes: 'ml-2 px-2 py-0.5 rounded-full text-xs bg-yellow-500 text-white',
|
|
2144
|
+
},
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
id: 'feature-layout',
|
|
2148
|
+
title: 'Layout',
|
|
2149
|
+
type: 'collapsable',
|
|
2150
|
+
icon: 'dashboard',
|
|
2151
|
+
children: [
|
|
2152
|
+
{
|
|
2153
|
+
id: 'feature-layout-apps',
|
|
2154
|
+
title: 'Application',
|
|
2155
|
+
type: 'collapsable',
|
|
2156
|
+
icon: 'web',
|
|
2157
|
+
children: [
|
|
2158
|
+
{
|
|
2159
|
+
id: 'feature-layout-apps-vertical',
|
|
2160
|
+
title: 'Vertical',
|
|
2161
|
+
type: 'basic',
|
|
2162
|
+
icon: 'view_sidebar',
|
|
2163
|
+
link: '/feature/layout/application/vertical',
|
|
2164
|
+
},
|
|
2165
|
+
{
|
|
2166
|
+
id: 'feature-layout-apps-horizontal',
|
|
2167
|
+
title: 'Horizontal',
|
|
2168
|
+
type: 'basic',
|
|
2169
|
+
icon: 'view_column',
|
|
2170
|
+
link: '/feature/layout/application/horizontal',
|
|
2171
|
+
},
|
|
2172
|
+
],
|
|
2173
|
+
},
|
|
2174
|
+
{
|
|
2175
|
+
id: 'feature-layout-page',
|
|
2176
|
+
title: 'Pages',
|
|
2177
|
+
type: 'collapsable',
|
|
2178
|
+
icon: 'description',
|
|
2179
|
+
children: [
|
|
2180
|
+
{
|
|
2181
|
+
id: 'feature-layout-page-page',
|
|
2182
|
+
title: 'Page',
|
|
2183
|
+
type: 'basic',
|
|
2184
|
+
icon: 'description',
|
|
2185
|
+
link: '/feature/layout/page/page',
|
|
2186
|
+
},
|
|
2187
|
+
{
|
|
2188
|
+
id: 'feature-layout-page-content',
|
|
2189
|
+
title: 'Content',
|
|
2190
|
+
type: 'basic',
|
|
2191
|
+
icon: 'description',
|
|
2192
|
+
link: '/feature/layout/page/content',
|
|
2193
|
+
},
|
|
2194
|
+
],
|
|
2195
|
+
},
|
|
2196
|
+
],
|
|
2197
|
+
},
|
|
2198
|
+
],
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
id: 'feature-navigation',
|
|
2202
|
+
title: 'Navigation',
|
|
2203
|
+
type: 'collapsable',
|
|
2204
|
+
icon: 'navigation',
|
|
2205
|
+
children: [
|
|
2206
|
+
{
|
|
2207
|
+
id: 'feature-navigation-horizontal-navigation',
|
|
2208
|
+
title: 'Horizontal ',
|
|
2209
|
+
type: 'basic',
|
|
2210
|
+
icon: 'view_column',
|
|
2211
|
+
link: '/feature/navigation/horizontal',
|
|
2212
|
+
},
|
|
2213
|
+
{
|
|
2214
|
+
id: 'feature-navigation-vertical-navigation',
|
|
2215
|
+
title: 'Vertical ',
|
|
2216
|
+
type: 'collapsable',
|
|
2217
|
+
icon: 'view_agenda',
|
|
2218
|
+
children: [
|
|
2219
|
+
{
|
|
2220
|
+
id: 'feature-navigation-vertical-navigation-default',
|
|
2221
|
+
title: 'Default',
|
|
2222
|
+
type: 'basic',
|
|
2223
|
+
icon: 'view_agenda',
|
|
2224
|
+
link: '/feature/navigation/vertical/default',
|
|
2225
|
+
},
|
|
2226
|
+
{
|
|
2227
|
+
id: 'feature-navigation-vertical-navigation-thin',
|
|
2228
|
+
title: 'Thin',
|
|
2229
|
+
type: 'basic',
|
|
2230
|
+
icon: 'view_agenda',
|
|
2231
|
+
link: '/feature/navigation/vertical/thin',
|
|
2232
|
+
},
|
|
2233
|
+
{
|
|
2234
|
+
id: 'feature-navigation-vertical-navigation-compact',
|
|
2235
|
+
title: 'Compact',
|
|
2236
|
+
type: 'basic',
|
|
2237
|
+
icon: 'view_agenda',
|
|
2238
|
+
link: '/feature/navigation/vertical/compact',
|
|
2239
|
+
},
|
|
2240
|
+
{
|
|
2241
|
+
id: 'feature-navigation-vertical-navigation-dense',
|
|
2242
|
+
title: 'Dense',
|
|
2243
|
+
type: 'basic',
|
|
2244
|
+
icon: 'view_agenda',
|
|
2245
|
+
link: '/feature/navigation/vertical/dense',
|
|
2246
|
+
},
|
|
2247
|
+
],
|
|
2248
|
+
},
|
|
2249
|
+
],
|
|
2250
|
+
},
|
|
2251
|
+
],
|
|
2252
|
+
},
|
|
2253
|
+
];
|
|
2254
|
+
|
|
2255
|
+
/*
|
|
2256
|
+
* Public API Surface of @ojiepermana/angular/navigation
|
|
2257
|
+
*/
|
|
2258
|
+
// Core
|
|
2259
|
+
const NAVIGATION_VERSION = '0.0.1';
|
|
466
2260
|
|
|
467
2261
|
/**
|
|
468
2262
|
* Generated bundle index. Do not edit.
|
|
469
2263
|
*/
|
|
470
2264
|
|
|
471
|
-
export {
|
|
2265
|
+
export { DEFAULT_NAVIGATION_ID, DemoNavigationData, NAVIGATION_VERSION, NavigationService, SidebarComponent, TopbarComponent, UiNavIconComponent, UiNavItemComponent };
|
|
472
2266
|
//# sourceMappingURL=ojiepermana-angular-navigation.mjs.map
|