@ojiepermana/angular 0.0.3 → 0.1.1

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.
Files changed (41) hide show
  1. package/README.md +55 -9
  2. package/fesm2022/ojiepermana-angular-internal.mjs +433 -2
  3. package/fesm2022/ojiepermana-angular-internal.mjs.map +1 -1
  4. package/fesm2022/ojiepermana-angular-layout.mjs +52 -59
  5. package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -1
  6. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs +721 -0
  7. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs.map +1 -0
  8. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs +1647 -0
  9. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs.map +1 -0
  10. package/fesm2022/ojiepermana-angular-navigation.mjs +472 -0
  11. package/fesm2022/ojiepermana-angular-navigation.mjs.map +1 -0
  12. package/fesm2022/ojiepermana-angular-shell.mjs +6 -1
  13. package/fesm2022/ojiepermana-angular-shell.mjs.map +1 -1
  14. package/fesm2022/ojiepermana-angular-theme-component.mjs +12 -26
  15. package/fesm2022/ojiepermana-angular-theme-component.mjs.map +1 -1
  16. package/fesm2022/ojiepermana-angular-theme-service.mjs +2 -6
  17. package/fesm2022/ojiepermana-angular-theme-service.mjs.map +1 -1
  18. package/fesm2022/ojiepermana-angular.mjs.map +1 -1
  19. package/layout/README.md +3 -3
  20. package/{theme/styles/layout → layout/src/component/horizontal}/horizontal.css +39 -26
  21. package/{theme/styles/layout → layout/src/component/vertical}/vertical.css +10 -12
  22. package/{theme/styles/layout/index.css → layout/src/layout.css} +0 -3
  23. package/navigation/README.md +301 -0
  24. package/navigation/horizontal/README.md +49 -0
  25. package/navigation/vertical/README.md +0 -0
  26. package/package.json +13 -1
  27. package/shell/README.md +5 -1
  28. package/styles/index.css +1 -1
  29. package/theme/README.md +3 -6
  30. package/theme/styles/adapters/material-ui/index.css +1 -5
  31. package/theme/styles/presets/styles/flat.css +3 -6
  32. package/theme/styles/presets/styles/glass.css +1 -7
  33. package/theme/styles/presets/styles/index.css +1 -1
  34. package/theme/styles/roles/index.css +18 -0
  35. package/theme/styles/tokens/foundation.css +4 -7
  36. package/types/ojiepermana-angular-internal.d.ts +65 -1
  37. package/types/ojiepermana-angular-layout.d.ts +1 -1
  38. package/types/ojiepermana-angular-navigation-horizontal.d.ts +81 -0
  39. package/types/ojiepermana-angular-navigation-vertical.d.ts +262 -0
  40. package/types/ojiepermana-angular-navigation.d.ts +228 -0
  41. package/types/ojiepermana-angular-shell.d.ts +2 -0
@@ -0,0 +1,301 @@
1
+ # Navigation
2
+
3
+ Navigation for `@ojiepermana/angular` is split into three secondary entry points so consumers can import only the state helpers or component variants they need.
4
+
5
+ ## Entry Points
6
+
7
+ - `@ojiepermana/angular/navigation` exposes the navigation item model, utility helpers, `NavigationService`, and `NavigationPreferencesService`.
8
+ - `@ojiepermana/angular/navigation/vertical` exposes the vertical navigation container variants and vertical item components.
9
+ - `@ojiepermana/angular/navigation/horizontal` exposes the horizontal navigation variants and branch item component.
10
+
11
+ Do not import consumer code from `@ojiepermana/angular/internal` or from source file paths under this folder. Those paths are implementation details and are not part of the public contract.
12
+
13
+ ## Requirements
14
+
15
+ - Configure Angular Router before rendering the navigation components.
16
+ - Import `@ojiepermana/angular/styles/index.css` in the consuming application so the shared theme tokens are available.
17
+ - Use Lucide icon names or aliases in `NavigationItem.icon`. The navigation components resolve icons through `@lucide/angular`.
18
+
19
+ ## Source Layout
20
+
21
+ ```text
22
+ navigation/
23
+ ├── data/
24
+ │ └── demo-navigation.data.ts
25
+ ├── state/
26
+ │ ├── navigation.service.ts
27
+ │ ├── navigation.type.ts
28
+ │ └── navigation.utils.ts
29
+ ├── horizontal/
30
+ │ ├── core/
31
+ │ │ ├── horizontal-navigation.base.ts
32
+ │ │ └── horizontal-navigation.shared.ts
33
+ │ ├── default/
34
+ │ │ ├── default.ts
35
+ │ │ ├── default.css
36
+ │ │ └── README.md
37
+ │ ├── mega/
38
+ │ │ ├── mega.ts
39
+ │ │ ├── mega.css
40
+ │ │ └── README.md
41
+ │ └── types/
42
+ │ ├── index.ts
43
+ │ ├── branch.ts
44
+ │ └── branch/
45
+ │ ├── branch.ts
46
+ │ └── README.md
47
+ ├── shared/
48
+ │ ├── content/
49
+ │ └── tree/
50
+ └── vertical/
51
+ ├── core/
52
+ │ ├── vertical-navigation.base.ts
53
+ │ └── vertical-navigation.shared.ts
54
+ ├── default/
55
+ │ ├── default.ts
56
+ │ └── default.css
57
+ ├── collapsible/
58
+ │ └── collapsible.ts
59
+ └── types/
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ### 1. Define a navigation tree
65
+
66
+ ```ts
67
+ import { NavigationItem } from '@ojiepermana/angular/navigation';
68
+
69
+ export const appNavigation = [
70
+ {
71
+ id: 'dashboard',
72
+ title: 'Dashboard',
73
+ type: 'basic',
74
+ icon: 'layout-dashboard',
75
+ link: '/dashboard',
76
+ },
77
+ {
78
+ id: 'workspace',
79
+ title: 'Workspace',
80
+ type: 'collapsable',
81
+ icon: 'folders',
82
+ children: [
83
+ {
84
+ id: 'workspace-overview',
85
+ title: 'Overview',
86
+ type: 'basic',
87
+ link: '/workspace/overview',
88
+ },
89
+ {
90
+ id: 'workspace-settings',
91
+ title: 'Settings',
92
+ type: 'basic',
93
+ link: '/workspace/settings',
94
+ badge: {
95
+ title: 'Beta',
96
+ classes: 'bg-primary text-primary-foreground',
97
+ },
98
+ },
99
+ ],
100
+ },
101
+ ] satisfies NavigationItem[];
102
+ ```
103
+
104
+ ### 2. Render a vertical navigation
105
+
106
+ ```ts
107
+ import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
108
+ import { NavigationItem } from '@ojiepermana/angular/navigation';
109
+ import { VerticalNavigationDefaultComponent } from '@ojiepermana/angular/navigation/vertical';
110
+
111
+ import { appNavigation } from './app.navigation';
112
+
113
+ @Component({
114
+ selector: 'app-shell-navigation',
115
+ imports: [VerticalNavigationDefaultComponent],
116
+ template: `
117
+ <vertical-navigation [navigation]="navigation()" [opened]="true" mode="side" position="left"></vertical-navigation>
118
+ `,
119
+ changeDetection: ChangeDetectionStrategy.OnPush,
120
+ })
121
+ export class ShellNavigationComponent {
122
+ readonly navigation = signal<NavigationItem[]>(appNavigation);
123
+ }
124
+ ```
125
+
126
+ Vertical variants use these selectors:
127
+
128
+ - `<vertical-navigation>` for the default width and density.
129
+ - `<vertical-navigation-collapsible>` for the upcoming collapsible variant contract. It currently reuses the default layout.
130
+
131
+ All vertical variants share the same public API surface inherited from the base component, including `navigation`, `opened`, `mode`, `position`, `autoCollapse`, `inner`, `transparentOverlay`, and the `openedChanged` output.
132
+
133
+ ### 3. Render a horizontal navigation
134
+
135
+ ```ts
136
+ import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
137
+ import { NavigationItem } from '@ojiepermana/angular/navigation';
138
+ import { HorizontalNavigation } from '@ojiepermana/angular/navigation/horizontal';
139
+
140
+ import { appNavigation } from './app.navigation';
141
+
142
+ @Component({
143
+ selector: 'app-top-navigation',
144
+ imports: [HorizontalNavigation],
145
+ template: `
146
+ <horizontal-navigation [navigation]="navigation()" (itemClicked)="onItemClicked($event)"></horizontal-navigation>
147
+ `,
148
+ changeDetection: ChangeDetectionStrategy.OnPush,
149
+ })
150
+ export class TopNavigationComponent {
151
+ readonly navigation = signal<NavigationItem[]>(appNavigation);
152
+
153
+ onItemClicked(item: NavigationItem): void {
154
+ console.log('Navigation item clicked:', item.id);
155
+ }
156
+ }
157
+ ```
158
+
159
+ Horizontal variants use these selectors:
160
+
161
+ - `<horizontal-navigation>` for the default horizontal layout.
162
+ - `<horizontal-navigation-mega>` for a roomier mega-style horizontal layout.
163
+
164
+ ### 4. Optionally mirror the tree into `NavigationService`
165
+
166
+ `NavigationService` is useful when other parts of the application need lookup helpers, active item state, or expanded item state. Vertical navigation renders from its `navigation` input. Horizontal navigation renders from its `navigation` input first, and falls back to the service only when the input array is empty.
167
+
168
+ ```ts
169
+ import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
170
+ import { NavigationItem, NavigationService } from '@ojiepermana/angular/navigation';
171
+
172
+ import { appNavigation } from './app.navigation';
173
+
174
+ @Component({
175
+ selector: 'app-navigation-store',
176
+ template: '',
177
+ changeDetection: ChangeDetectionStrategy.OnPush,
178
+ })
179
+ export class NavigationStoreComponent {
180
+ private readonly navigationService = inject(NavigationService);
181
+ readonly navigation = signal<NavigationItem[]>(appNavigation);
182
+
183
+ ngOnInit(): void {
184
+ this.navigationService.storeNavigation(this.navigation());
185
+ }
186
+ }
187
+ ```
188
+
189
+ ## Navigation Item Model
190
+
191
+ Every tree node is a `NavigationItem`. The public union is split across these item types:
192
+
193
+ - `basic` is a leaf item that can route, open an external link, or run an `action` callback.
194
+ - `aside` is a routable branch rendered through the vertical aside panel pattern.
195
+ - `collapsable` is a branch that expands and collapses inline.
196
+ - `group` is a non-routable section label with children.
197
+ - `divider` renders a visual separator.
198
+ - `spacer` renders flexible empty space.
199
+
200
+ Shared fields available on most item types:
201
+
202
+ - `id`, `title`, `subtitle`, `tooltip`, `icon`, `disabled`, and `meta`.
203
+ - `classes.wrapper`, `classes.icon`, `classes.title`, and `classes.subtitle` for per-item styling hooks.
204
+ - `badge.title` and `badge.classes` for optional item badges.
205
+ - `isHidden` for conditional visibility.
206
+
207
+ Routable item fields available on `basic`, `aside`, and `collapsable`:
208
+
209
+ - `link`, `fragment`, `preserveFragment`, `queryParams`, and `queryParamsHandling`.
210
+ - `externalLink` and `target` for external navigation.
211
+ - `exactMatch` and `isActiveMatchOptions` for route activity matching.
212
+ - `action` for click callbacks.
213
+
214
+ ## Navigation Service
215
+
216
+ `NavigationService` is provided in root and exposes navigation state as signals plus a small lookup API.
217
+
218
+ Readonly state:
219
+
220
+ - `navigationItems`
221
+ - `activeItemId`
222
+ - `flatNavigation`
223
+ - `expandedItemIds`
224
+
225
+ Mutation and lookup methods:
226
+
227
+ - `storeNavigation()` and `deleteNavigation()`
228
+ - `setActiveItem()` and `clearActiveItem()`
229
+ - `expandItem()`, `collapseItem()`, `toggleItemExpanded()`, and `clearExpandedItems()`
230
+ - `getNavigation()`, `getActiveItem()`, `getFlatNavigation()`, `getItem()`, and `getItemParent()`
231
+
232
+ `activeItemId` and `expandedItemIds` now persist automatically through `NavigationPreferencesService`, while `NavigationService` stays focused on the navigation tree and lookup helpers.
233
+
234
+ ## Navigation Preferences Service
235
+
236
+ `NavigationPreferencesService` is provided in root and stores persisted navigation preferences separately from the navigation tree itself.
237
+
238
+ `provideNgNavigation()` configures the defaults that are used before any persisted browser state exists.
239
+
240
+ Readonly state:
241
+
242
+ - `horizontalVariant`
243
+ - `verticalAppearance`
244
+ - `activeItemId`
245
+ - `expandedItemIds`
246
+
247
+ Mutation methods:
248
+
249
+ - `setHorizontalVariant()`
250
+ - `setVerticalAppearance()`
251
+ - `setActiveItem()` and `clearActiveItem()`
252
+ - `setExpandedItemIds()`, `expandItem()`, `collapseItem()`, `toggleExpandedItem()`, and `clearExpandedItems()`
253
+ - `syncWithNavigation()` and `reset()`
254
+
255
+ Persisted flat localStorage keys:
256
+
257
+ - `navigation-horizontal-variant`
258
+ - `navigation-vertical-appearance`
259
+ - `navigation-active-item`
260
+ - `navigation-expanded-items`
261
+
262
+ Legacy `ng-navigation:v1:vertical-appearance`, `ng-navigation:v1:active-item`, and `ng-navigation:v1:expanded-items` entries migrate automatically when they are read.
263
+
264
+ Use `horizontalVariant()` to choose which horizontal variant component to render in the consumer app, and `verticalAppearance()` to choose which vertical variant component to render.
265
+
266
+ Default provider config fields:
267
+
268
+ - `defaultHorizontalVariant`
269
+ - `defaultVerticalVariant`
270
+
271
+ ## Styling Notes
272
+
273
+ - Pass Tailwind utility classes or other class names through the item `classes` and `badge.classes` fields when you need local visual overrides.
274
+ - Icons are resolved from Lucide. Use names such as `layout-dashboard`, `folders`, `settings-2`, or valid Lucide aliases.
275
+ - Active state depends on Angular Router. Use `exactMatch` or `isActiveMatchOptions` when the default subset matching is too broad.
276
+
277
+ ## Troubleshooting
278
+
279
+ ### Nothing renders
280
+
281
+ - Confirm the component receives a non-empty `navigation` input.
282
+ - If a horizontal navigation intentionally relies on service fallback, call `NavigationService.storeNavigation()` before it renders.
283
+ - Check whether `isHidden` returns `true` for the affected items.
284
+
285
+ ### Icons do not appear
286
+
287
+ - Use Lucide icon names or aliases, not Material icon names.
288
+ - Check the `icon` value on the affected item.
289
+
290
+ ### Active state is wrong
291
+
292
+ - Verify Router is configured and the application uses the expected route paths.
293
+ - Tune `exactMatch` or `isActiveMatchOptions` for the affected items.
294
+
295
+ ## Notes For Contributors
296
+
297
+ - Keep `@ojiepermana/angular/navigation` focused on the item model, helpers, and `NavigationService`.
298
+ - Keep navigation persistence and UI preferences in `NavigationPreferencesService` instead of storing the full navigation tree in browser storage.
299
+ - Keep render components in `@ojiepermana/angular/navigation/vertical` and `@ojiepermana/angular/navigation/horizontal`.
300
+ - Move shared implementation helpers behind `@ojiepermana/angular/internal` instead of reaching across entry point boundaries with relative imports.
301
+ - Treat `projects/library/navigation/shared` as a local compatibility layer for tests and source organization, not as consumer API.
@@ -0,0 +1,49 @@
1
+ # Horizontal Navigation
2
+
3
+ The horizontal entrypoint exposes shared top-bar navigation variants for `@ojiepermana/angular`.
4
+
5
+ ## Public Imports
6
+
7
+ ```ts
8
+ import { HorizontalNavigation, HorizontalNavigationMegaComponent } from '@ojiepermana/angular/navigation/horizontal';
9
+ ```
10
+
11
+ ## Variants
12
+
13
+ - `HorizontalNavigation` renders the default selector `<horizontal-navigation>`.
14
+ - `HorizontalNavigationMegaComponent` renders the mega selector `<horizontal-navigation-mega>`.
15
+
16
+ ## Source Layout
17
+
18
+ ```text
19
+ horizontal/
20
+ ├── core/
21
+ │ ├── horizontal-navigation.base.ts
22
+ │ └── horizontal-navigation.shared.ts
23
+ ├── default/
24
+ │ ├── default.ts
25
+ │ ├── default.css
26
+ │ └── README.md
27
+ ├── mega/
28
+ │ ├── mega.ts
29
+ │ ├── mega.css
30
+ │ └── README.md
31
+ ├── types/
32
+ │ ├── index.ts
33
+ │ ├── README.md
34
+ │ ├── branch.ts
35
+ │ └── branch/
36
+ │ ├── branch.ts
37
+ │ └── README.md
38
+ ├── horizontal.ts
39
+ ├── index.ts
40
+ ├── ng-package.json
41
+ └── public-api.ts
42
+ ```
43
+
44
+ ## Notes
45
+
46
+ - `core/` contains variant-agnostic logic and template composition.
47
+ - `default/` and `mega/` contain variant-specific components and styles.
48
+ - `types/` contains reusable branch rendering primitives shared by all horizontal variants.
49
+ - `horizontal.ts` remains a compatibility barrel that points to the default variant implementation.
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ojiepermana/angular",
3
- "version": "0.0.3",
3
+ "version": "0.1.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,6 +34,18 @@
34
34
  "types": "./types/ojiepermana-angular-layout.d.ts",
35
35
  "default": "./fesm2022/ojiepermana-angular-layout.mjs"
36
36
  },
37
+ "./navigation": {
38
+ "types": "./types/ojiepermana-angular-navigation.d.ts",
39
+ "default": "./fesm2022/ojiepermana-angular-navigation.mjs"
40
+ },
41
+ "./navigation/horizontal": {
42
+ "types": "./types/ojiepermana-angular-navigation-horizontal.d.ts",
43
+ "default": "./fesm2022/ojiepermana-angular-navigation-horizontal.mjs"
44
+ },
45
+ "./navigation/vertical": {
46
+ "types": "./types/ojiepermana-angular-navigation-vertical.d.ts",
47
+ "default": "./fesm2022/ojiepermana-angular-navigation-vertical.mjs"
48
+ },
37
49
  "./shell": {
38
50
  "types": "./types/ojiepermana-angular-shell.d.ts",
39
51
  "default": "./fesm2022/ojiepermana-angular-shell.mjs"
package/shell/README.md CHANGED
@@ -29,9 +29,13 @@ export const appConfig: ApplicationConfig = {
29
29
  defaultMode: 'vertical',
30
30
  defaultContainer: 'boxed',
31
31
  },
32
+ navigation: {
33
+ defaultHorizontalVariant: 'default',
34
+ defaultVerticalVariant: 'default',
35
+ },
32
36
  }),
33
37
  ],
34
38
  };
35
39
  ```
36
40
 
37
- `provideNgShell()` is a convenience wrapper over `provideNgTheme()` and `provideNgLayout()`. It does not introduce a separate runtime state layer.
41
+ `provideNgShell()` is a convenience wrapper over `provideNgTheme()`, `provideNgLayout()`, and `provideNgNavigation()`. It does not introduce a separate runtime state layer.
package/styles/index.css CHANGED
@@ -1,2 +1,2 @@
1
1
  @import '../theme/styles/index.css';
2
- @import '../theme/styles/layout/index.css';
2
+ @import '../layout/src/layout.css';
package/theme/README.md CHANGED
@@ -188,9 +188,9 @@ It imports the current structure in this order:
188
188
  - `utilities/index.css`
189
189
  - `adapters/material-ui/index.css`
190
190
 
191
- Layout selectors now live in `projects/library/layout/styles/index.css` inside this workspace.
191
+ Layout-wide selectors now live in `projects/library/layout/src/layout.css` inside this workspace.
192
192
 
193
- For applications that consume the published package, use the aggregate bundle at `projects/library/styles/index.css` in this workspace or `@ojiepermana/angular/styles/index.css` from the published package. The aggregate bundle imports theme first, then layout.
193
+ For applications that consume the published package, use the aggregate bundle at `projects/library/styles/index.css` in this workspace or `@ojiepermana/angular/styles/index.css` from the published package. The aggregate bundle imports theme first, then the layout-wide selectors. Horizontal and vertical shell CSS are loaded by their respective layout components.
194
194
 
195
195
  Application-level resets are intentionally opt-in. If a consumer wants them, import `projects/library/styles/resets.css` in this workspace or `@ojiepermana/angular/styles/resets.css` from the published package in addition to the aggregate bundle.
196
196
 
@@ -310,10 +310,7 @@ For a package consumer, use the published aggregate bundle instead:
310
310
 
311
311
  ```ts
312
312
  import { ChangeDetectionStrategy, Component } from '@angular/core';
313
- import {
314
- LayoutContainerSwitcherComponent,
315
- LayoutVerticalComponent,
316
- } from '@ojiepermana/angular/layout';
313
+ import { LayoutContainerSwitcherComponent, LayoutVerticalComponent } from '@ojiepermana/angular/layout';
317
314
  import {
318
315
  StyleSwitcherComponent,
319
316
  ColorPickerComponent,
@@ -28,11 +28,7 @@
28
28
  --mat-sys-on-surface: var(--container-foreground);
29
29
  --mat-sys-surface-container: var(--overlay-surface);
30
30
  --mat-sys-surface-container-high: var(--overlay-surface);
31
- --mat-sys-surface-container-highest: color-mix(
32
- in oklab,
33
- var(--overlay-surface) 90%,
34
- var(--muted)
35
- );
31
+ --mat-sys-surface-container-highest: color-mix(in oklab, var(--overlay-surface) 90%, var(--muted));
36
32
  --mat-sys-surface-variant: var(--data-header-surface);
37
33
  --mat-sys-on-surface-variant: var(--data-header-foreground);
38
34
  --mat-sys-inverse-surface: var(--inverse);
@@ -25,15 +25,13 @@
25
25
  --shell-foreground: var(--card-foreground);
26
26
  --shell-border: var(--border);
27
27
  --shell-shadow:
28
- rgb(0 0 0 / 0.14) 0 28px 70px, rgb(0 0 0 / 0.1) 0 14px 32px,
29
- oklab(0.263084 -0.00230259 0.0124794 / 0.1) 0 0 0 1px;
28
+ rgb(0 0 0 / 0.14) 0 28px 70px, rgb(0 0 0 / 0.1) 0 14px 32px, oklab(0.263084 -0.00230259 0.0124794 / 0.1) 0 0 0 1px;
30
29
  --shell-backdrop: var(--backdrop);
31
30
  --surface-elevated: var(--popover);
32
31
  --surface-elevated-foreground: var(--popover-foreground);
33
32
  --surface-elevated-border: oklab(0.263084 -0.00230259 0.0124794 / 0.2);
34
33
  --surface-elevated-shadow:
35
- rgb(0 0 0 / 0.12) 0 24px 52px, rgb(0 0 0 / 0.08) 0 10px 24px,
36
- oklab(0.263084 -0.00230259 0.0124794 / 0.1) 0 0 0 1px;
34
+ rgb(0 0 0 / 0.12) 0 24px 52px, rgb(0 0 0 / 0.08) 0 10px 24px, oklab(0.263084 -0.00230259 0.0124794 / 0.1) 0 0 0 1px;
37
35
  }
38
36
 
39
37
  .dark[data-theme-style='flat'] {
@@ -54,8 +52,7 @@
54
52
  --sidebar-primary-foreground: var(--foreground);
55
53
  --sidebar-accent: color-mix(in oklab, var(--theme-primary) 18%, var(--sidebar));
56
54
  --sidebar-accent-foreground: var(--foreground);
57
- --shell-shadow:
58
- rgb(0 0 0 / 0.44) 0 28px 70px, rgb(0 0 0 / 0.28) 0 14px 32px, rgb(235 231 222 / 0.08) 0 0 0 1px;
55
+ --shell-shadow: rgb(0 0 0 / 0.44) 0 28px 70px, rgb(0 0 0 / 0.28) 0 14px 32px, rgb(235 231 222 / 0.08) 0 0 0 1px;
59
56
  --surface-elevated: #2b2820;
60
57
  --surface-elevated-foreground: var(--foreground);
61
58
  --surface-elevated-border: rgb(235 231 222 / 0.12);
@@ -7,13 +7,7 @@
7
7
  ui-sans-serif,
8
8
  sans-serif
9
9
  );
10
- --typeface-brand: var(
11
- --theme-style-glass-brand-font,
12
- ui-rounded,
13
- 'Avenir Next',
14
- 'Segoe UI',
15
- sans-serif
16
- );
10
+ --typeface-brand: var(--theme-style-glass-brand-font, ui-rounded, 'Avenir Next', 'Segoe UI', sans-serif);
17
11
  --typeface-mono: var(
18
12
  --theme-style-glass-mono-font,
19
13
  'SFMono-Regular',
@@ -1,2 +1,2 @@
1
1
  @import './flat.css';
2
- @import './glass.css';
2
+ @import './glass.css';
@@ -3,6 +3,24 @@
3
3
  --nav-surface: color-mix(in oklab, var(--shell-surface) 92%, transparent);
4
4
  --nav-foreground: var(--shell-foreground);
5
5
  --nav-border: var(--shell-border);
6
+ --nav-font-family: var(--typeface-plain);
7
+ --nav-item-font-size: 0.875rem;
8
+ --nav-item-line-height: 1.25rem;
9
+ --nav-item-font-weight: 500;
10
+ --nav-item-active-font-weight: 600;
11
+ --nav-subtitle-font-size: 0.75rem;
12
+ --nav-subtitle-line-height: 1rem;
13
+ --nav-subtitle-font-weight: 400;
14
+ --nav-badge-font-size: 0.75rem;
15
+ --nav-badge-line-height: 1rem;
16
+ --nav-badge-font-weight: 600;
17
+ --nav-group-title-font-size: 0.75rem;
18
+ --nav-group-title-line-height: 1rem;
19
+ --nav-group-title-font-weight: 600;
20
+ --nav-group-title-letter-spacing: 0.08em;
21
+ --nav-group-subtitle-font-size: 0.75rem;
22
+ --nav-group-subtitle-line-height: 1rem;
23
+ --nav-group-subtitle-font-weight: 400;
6
24
  --nav-item-hover-surface: var(--tertiary-container);
7
25
  --nav-item-hover-foreground: var(--tertiary-container-foreground);
8
26
  --nav-item-active-surface: var(--secondary-container);
@@ -87,8 +87,7 @@
87
87
 
88
88
  /* Keep these radius tokens in :root as well so non-Tailwind consumers get the same values as @theme. */
89
89
  :root {
90
- --typeface-plain:
91
- ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
90
+ --typeface-plain: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
92
91
  --typeface-brand: var(--typeface-plain);
93
92
  --typeface-mono: 'SFMono-Regular', 'Cascadia Mono', 'Liberation Mono', ui-monospace, monospace;
94
93
  --radius: 0.75rem;
@@ -115,7 +114,7 @@
115
114
  --layout-shell-max-width: 100%;
116
115
  --layout-shell-padding: 0rem;
117
116
  --layout-shell-radius: 0rem;
118
- --layout-sidebar-width: 17rem;
117
+ --layout-sidebar-width: 280px;
119
118
  --layout-header-height: 3.75rem;
120
119
  --layout-header-display: grid;
121
120
  --layout-sidebar-display: flex;
@@ -131,9 +130,7 @@
131
130
  text-decoration-color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard),
132
131
  backdrop-filter var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard);
133
132
  --ngt-shell-transition:
134
- var(--ngt-chrome-transition),
135
- border-radius var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard);
133
+ var(--ngt-chrome-transition), border-radius var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard);
136
134
  --ngt-control-transition:
137
- var(--ngt-chrome-transition),
138
- transform var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard);
135
+ var(--ngt-chrome-transition), transform var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard);
139
136
  }
@@ -1,4 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+ import { LucideIcon } from '@lucide/angular';
4
+ import { NavigationItem } from '@ojiepermana/angular/navigation';
2
5
 
3
6
  declare const libraryLucideConfigProvider: _angular_core.Provider;
4
7
 
@@ -18,9 +21,70 @@ declare class LocalStorageStateAdapter<Axis extends string> {
18
21
  constructor(config: LocalStorageStateAdapterConfig<Axis>);
19
22
  clear(axis: Axis): void;
20
23
  persist(axis: Axis, value: string): void;
24
+ readValue(axis: Axis): string | null;
21
25
  read<T extends string>(axis: Axis, fallback: T, isValid: (value: string) => value is T): T;
22
26
  private key;
23
27
  private legacyKey;
24
28
  }
25
29
 
26
- export { LocalStorageStateAdapter, libraryLucideConfigProvider };
30
+ type NavigationItemContentVariant = 'horizontal' | 'vertical' | 'vertical-group';
31
+ declare class NavigationItemContent {
32
+ item: _angular_core.InputSignal<NavigationItem>;
33
+ level: _angular_core.InputSignal<number>;
34
+ variant: _angular_core.InputSignal<NavigationItemContentVariant>;
35
+ protected readonly resolvedIcon: _angular_core.Signal<LucideIcon | null>;
36
+ protected readonly horizontalIconClass: _angular_core.Signal<string | null>;
37
+ protected readonly verticalIconClass: _angular_core.Signal<string | null>;
38
+ protected readonly horizontalTitleClass: _angular_core.Signal<string | null>;
39
+ protected readonly titleClass: _angular_core.Signal<string | null>;
40
+ protected readonly subtitleClass: _angular_core.Signal<string | null>;
41
+ protected readonly horizontalBadgeClass: _angular_core.Signal<string | null>;
42
+ protected readonly verticalBadgeClass: _angular_core.Signal<string | null>;
43
+ protected readonly titleContainerClass: _angular_core.Signal<"kit-navigation-group-title" | "kit-navigation-item-title">;
44
+ protected readonly subtitleContainerClass: _angular_core.Signal<"kit-navigation-group-subtitle" | "kit-navigation-item-subtitle">;
45
+ private joinClasses;
46
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NavigationItemContent, never>;
47
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NavigationItemContent, "navigation-item-content", never, { "item": { "alias": "item"; "required": true; "isSignal": true; }; "level": { "alias": "level"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
48
+ }
49
+
50
+ type NavigationTreeTemplateData = Record<string, unknown>;
51
+ interface NavigationTreeItemContext {
52
+ $implicit: NavigationItem;
53
+ level: number;
54
+ parentKey: string;
55
+ isLast: boolean;
56
+ data: NavigationTreeTemplateData | null;
57
+ }
58
+ declare class NavigationTreeOutlet {
59
+ items: _angular_core.InputSignal<NavigationItem[]>;
60
+ level: _angular_core.InputSignal<number>;
61
+ parentKey: _angular_core.InputSignal<string>;
62
+ data: _angular_core.InputSignal<NavigationTreeTemplateData | null>;
63
+ branchTemplate: _angular_core.InputSignal<TemplateRef<NavigationTreeItemContext>>;
64
+ leafTemplate: _angular_core.InputSignal<TemplateRef<NavigationTreeItemContext>>;
65
+ groupTemplate: _angular_core.InputSignal<TemplateRef<NavigationTreeItemContext>>;
66
+ dividerTemplate: _angular_core.InputSignal<TemplateRef<NavigationTreeItemContext> | null>;
67
+ spacerTemplate: _angular_core.InputSignal<TemplateRef<NavigationTreeItemContext> | null>;
68
+ trackByFn: _angular_core.InputSignal<(index: number, item: NavigationItem) => string | number | undefined>;
69
+ shouldRenderItemFn: _angular_core.InputSignal<(item: NavigationItem) => boolean>;
70
+ hasChildrenFn: _angular_core.InputSignal<(item: NavigationItem) => boolean>;
71
+ resolveParentKeyFn: _angular_core.InputSignal<(parentKey: string, item: NavigationItem) => string>;
72
+ trackItem(index: number, item: NavigationItem): string | number | undefined;
73
+ shouldRender(item: NavigationItem): boolean;
74
+ hasChildren(item: NavigationItem): boolean;
75
+ resolveParentKey(parentKey: string, item: NavigationItem): string;
76
+ templateContext(item: NavigationItem, isLast: boolean): NavigationTreeItemContext;
77
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NavigationTreeOutlet, never>;
78
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NavigationTreeOutlet, "navigation-tree-outlet", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "level": { "alias": "level"; "required": false; "isSignal": true; }; "parentKey": { "alias": "parentKey"; "required": false; "isSignal": true; }; "data": { "alias": "data"; "required": false; "isSignal": true; }; "branchTemplate": { "alias": "branchTemplate"; "required": true; "isSignal": true; }; "leafTemplate": { "alias": "leafTemplate"; "required": true; "isSignal": true; }; "groupTemplate": { "alias": "groupTemplate"; "required": true; "isSignal": true; }; "dividerTemplate": { "alias": "dividerTemplate"; "required": false; "isSignal": true; }; "spacerTemplate": { "alias": "spacerTemplate"; "required": false; "isSignal": true; }; "trackByFn": { "alias": "trackByFn"; "required": false; "isSignal": true; }; "shouldRenderItemFn": { "alias": "shouldRenderItemFn"; "required": false; "isSignal": true; }; "hasChildrenFn": { "alias": "hasChildrenFn"; "required": false; "isSignal": true; }; "resolveParentKeyFn": { "alias": "resolveParentKeyFn"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
79
+ }
80
+
81
+ type NavigationExpandedItemsByParent = Record<string, string>;
82
+ declare function trackNavigationTreeItem(index: number, item: NavigationItem): string | number | undefined;
83
+ declare function getNavigationTreePathKey(parentKey: string, item: NavigationItem): string;
84
+ declare function isNavigationTreeItemExpanded(expandedByParent: NavigationExpandedItemsByParent, parentKey: string, item: NavigationItem): boolean;
85
+ declare function toggleNavigationTreeItemExpanded(expandedByParent: NavigationExpandedItemsByParent, parentKey: string, item: NavigationItem): NavigationExpandedItemsByParent;
86
+ declare function hasActiveNavigationDescendant(item: NavigationItem, isItemActive: (item: NavigationItem) => boolean): boolean;
87
+ declare function isNavigationTreeDescendant(parent: NavigationItem, item: NavigationItem): boolean;
88
+
89
+ export { LocalStorageStateAdapter, NavigationItemContent, NavigationTreeOutlet, getNavigationTreePathKey, hasActiveNavigationDescendant, isNavigationTreeDescendant, isNavigationTreeItemExpanded, libraryLucideConfigProvider, toggleNavigationTreeItemExpanded, trackNavigationTreeItem };
90
+ export type { NavigationExpandedItemsByParent, NavigationTreeItemContext, NavigationTreeTemplateData };
@@ -43,7 +43,7 @@ declare class LayoutHostDirective {
43
43
 
44
44
  declare class LayoutHorizontalComponent {
45
45
  static ɵfac: i0.ɵɵFactoryDeclaration<LayoutHorizontalComponent, never>;
46
- static ɵcmp: i0.ɵɵComponentDeclaration<LayoutHorizontalComponent, "horizontal", never, {}, {}, never, ["[headerBrand]", "[headerNavigation]", "[headerActions]"], true, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<LayoutHorizontalComponent, "horizontal", never, {}, {}, never, ["[brand]", "[navigation]", "[action]"], true, never>;
47
47
  }
48
48
 
49
49
  declare class LayoutVerticalComponent {