@ojiepermana/angular-navigation 22.0.35 → 22.0.41

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.
@@ -4,6 +4,8 @@ import { inject, signal, computed, isDevMode, Service } from '@angular/core';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { Router, NavigationEnd } from '@angular/router';
6
6
 
7
+ /** Referensi stabil untuk id yang belum punya data terdaftar (hindari array baru tiap evaluasi). */
8
+ const EMPTY_NAV_DATA = Object.freeze([]);
7
9
  const DEFAULT_NAV_ID = 'default';
8
10
  const PERSISTED_NAV_ID = 'main';
9
11
  const DEFAULT_VERTICAL_TYPE = 'sidebar';
@@ -26,6 +28,9 @@ class NavigationService {
26
28
  ...(ngDevMode ? [{ debugName: "openPanelKeys" }] : /* istanbul ignore next */ []));
27
29
  drawerOpenState = signal({}, /* @ts-ignore */
28
30
  ...(ngDevMode ? [{ debugName: "drawerOpenState" }] : /* istanbul ignore next */ []));
31
+ /** Data mentah per id, dipublikasikan oleh `<Navigation>` agar surface lain (mis. apps-launcher di `Page`) bisa membaca nav by id tanpa mendaftarkan ulang id yang sama. */
32
+ dataById = signal({}, /* @ts-ignore */
33
+ ...(ngDevMode ? [{ debugName: "dataById" }] : /* istanbul ignore next */ []));
29
34
  /** id navigasi → token owner instance, untuk menjaga setiap id hanya dipakai satu <Navigation> hidup. */
30
35
  idOwners = new Map();
31
36
  openPanelKey = computed(() => this.openPanelKeys()[DEFAULT_NAV_ID] ?? null, /* @ts-ignore */
@@ -92,6 +97,21 @@ class NavigationService {
92
97
  currentState(id) {
93
98
  return this.states()[this.normalizeId(id)] ?? null;
94
99
  }
100
+ /** Data terdaftar untuk sebuah id sebagai signal; `[]` bila belum ada `<Navigation>` dengan id tersebut. */
101
+ data(id) {
102
+ const navId = this.normalizeId(id);
103
+ return computed(() => this.dataById()[navId] ?? EMPTY_NAV_DATA);
104
+ }
105
+ /** Dipanggil `<Navigation>` untuk mempublikasikan datanya ke registry by id. */
106
+ publishData(id, data) {
107
+ const navId = this.normalizeId(id);
108
+ this.dataById.update((map) => ({ ...map, [navId]: data }));
109
+ }
110
+ /** Dipanggil `<Navigation>` saat destroy untuk melepas datanya dari registry. */
111
+ clearData(id) {
112
+ const navId = this.normalizeId(id);
113
+ this.dataById.update((map) => this.withoutKey(map, navId));
114
+ }
95
115
  currentPanelKey(id) {
96
116
  return this.openPanelKeys()[this.normalizeId(id)] ?? null;
97
117
  }
@@ -189,6 +189,7 @@ class NavigationContainerComponent {
189
189
  ...(ngDevMode ? [{ debugName: "openedIds" }] : /* istanbul ignore next */ []));
190
190
  itemSelected = output();
191
191
  nav = inject(NavigationService);
192
+ destroyRef = inject(DestroyRef);
192
193
  hoverPreviewExpanded = signal(false, /* @ts-ignore */
193
194
  ...(ngDevMode ? [{ debugName: "hoverPreviewExpanded" }] : /* istanbul ignore next */ []));
194
195
  /** Konfigurasi type aktif yang didaftarkan wrapper anak (sidebar/dockbar/navbar/flyout). */
@@ -302,6 +303,12 @@ class NavigationContainerComponent {
302
303
  ? 'overflow-visible'
303
304
  : 'overflow-hidden', this.class()), /* @ts-ignore */
304
305
  ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
306
+ constructor() {
307
+ // Publikasikan data ke registry by id agar surface lain (mis. apps-launcher di `Page`)
308
+ // bisa membaca nav by id tanpa mendaftarkan ulang `<Navigation>` dengan id yang sama.
309
+ effect(() => this.nav.publishData(this.navId(), this.data()));
310
+ this.destroyRef.onDestroy(() => this.nav.clearData(this.navId()));
311
+ }
305
312
  /**
306
313
  * Dipanggil komponen type saat dibuat. Satu `<Navigation>` hanya boleh
307
314
  * memuat satu type hidup — pendaftaran ganda dianggap salah konfigurasi.
@@ -352,7 +359,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.3", ngImpor
352
359
  },
353
360
  template: ` <ng-content /> `,
354
361
  }]
355
- }], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapse-tree", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-group-class", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }, { type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], iconTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationIconDirective), { isSignal: true }] }] } });
362
+ }], ctorParameters: () => [], propDecorators: { navId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], collapseTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapse-tree", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], groupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "nav-group-class", required: false }] }], activeIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIds", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], openedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "openedIds", required: false }] }, { type: i0.Output, args: ["openedIdsChange"] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], iconTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NavigationIconDirective), { isSignal: true }] }] } });
356
363
 
357
364
  class NavigationItemContentComponent {
358
365
  nav = inject(NavigationService);
@@ -1178,12 +1185,13 @@ class NavigationDockbarMenuComponent {
1178
1185
  // berpindah group lain tanpa menutup drawer lebih dulu.
1179
1186
  this.isDrawerMode() && this.openGroup() !== null && 'relative z-50'), /* @ts-ignore */
1180
1187
  ...(ngDevMode ? [{ debugName: "railClasses" }] : /* istanbul ignore next */ []));
1181
- asideClasses = computed(() => cn('absolute inset-y-0 flex w-60 flex-col bg-background', this.position() === 'right'
1182
- ? 'right-16 border-r border-[hsl(var(--border)/var(--opacity-70))]'
1183
- : 'left-16 border-l border-[hsl(var(--border)/var(--opacity-70))]', this.isDrawerMode() &&
1184
- cn('z-50 shadow-xl', this.position() === 'right'
1185
- ? 'border-l border-l-[hsl(var(--border)/var(--opacity-70))]'
1186
- : 'border-r border-r-[hsl(var(--border)/var(--opacity-70))]')), /* @ts-ignore */
1188
+ asideClasses = computed(() => cn('absolute inset-y-0 flex w-60 flex-col bg-background',
1189
+ // Border only on the CONTENT-facing edge. The dockbar rail already draws the
1190
+ // rail-facing separator, so a rail-facing border here would double up
1191
+ // (right of the mini-dock + left of the aside).
1192
+ this.position() === 'right'
1193
+ ? 'right-16 border-l border-[hsl(var(--border)/var(--opacity-70))]'
1194
+ : 'left-16 border-r border-[hsl(var(--border)/var(--opacity-70))]', this.isDrawerMode() && 'z-50 shadow-xl'), /* @ts-ignore */
1187
1195
  ...(ngDevMode ? [{ debugName: "asideClasses" }] : /* istanbul ignore next */ []));
1188
1196
  /**
1189
1197
  * Offset backdrop agar kolom navigasi (rail + header/footer) benar-benar bebas
@@ -2286,7 +2294,7 @@ class NavigationFlyoutMenuComponent {
2286
2294
  // scrollRegionClasses) yang scroll; bar ROW 1 & kontainer panel sendiri tetap diam.
2287
2295
  'max-h-[calc(100dvh-5rem)] overflow-hidden', this.isBorderRail()
2288
2296
  ? cn('rounded-none border-border', this.isBottom() ? 'border-t-[1.5px]' : 'border-b-[1.5px]')
2289
- : 'rounded-xl border border-[hsl(var(--border)/var(--opacity-70))]');
2297
+ : 'rounded-[var(--layout-frame-radius)] border border-[hsl(var(--border)/var(--opacity-70))]');
2290
2298
  }
2291
2299
  rowClasses() {
2292
2300
  // Menu item = bagian tengah ROW 1: isi ruang antara Footer & Header (flex-1) lalu
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ojiepermana/angular-navigation",
3
- "version": "22.0.35",
3
+ "version": "22.0.41",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/edsis/angular.git"
@@ -13,7 +13,7 @@
13
13
  "@angular/common": ">=22.0.0",
14
14
  "@angular/core": ">=22.0.0",
15
15
  "@angular/router": ">=22.0.0",
16
- "@ojiepermana/angular-component": "^22.0.35",
16
+ "@ojiepermana/angular-component": "^22.0.41",
17
17
  "rxjs": ">=7.8.0"
18
18
  },
19
19
  "dependencies": {
@@ -78,6 +78,8 @@ declare class NavigationService {
78
78
  private readonly states;
79
79
  private readonly openPanelKeys;
80
80
  private readonly drawerOpenState;
81
+ /** Data mentah per id, dipublikasikan oleh `<Navigation>` agar surface lain (mis. apps-launcher di `Page`) bisa membaca nav by id tanpa mendaftarkan ulang id yang sama. */
82
+ private readonly dataById;
81
83
  /** id navigasi → token owner instance, untuk menjaga setiap id hanya dipakai satu <Navigation> hidup. */
82
84
  private readonly idOwners;
83
85
  readonly openPanelKey: Signal<string | null>;
@@ -96,6 +98,12 @@ declare class NavigationService {
96
98
  private releaseId;
97
99
  state(id: string): Signal<NavigationState | null>;
98
100
  currentState(id: string): NavigationState | null;
101
+ /** Data terdaftar untuk sebuah id sebagai signal; `[]` bila belum ada `<Navigation>` dengan id tersebut. */
102
+ data(id: string): Signal<readonly NavigationItem[]>;
103
+ /** Dipanggil `<Navigation>` untuk mempublikasikan datanya ke registry by id. */
104
+ publishData(id: string, data: readonly NavigationItem[]): void;
105
+ /** Dipanggil `<Navigation>` saat destroy untuk melepas datanya dari registry. */
106
+ clearData(id: string): void;
99
107
  currentPanelKey(id: string): string | null;
100
108
  update(id: string, patch: Partial<NavigationRegisterInput>): NavigationState;
101
109
  setType(id: string, type: NavigationType): NavigationState;
@@ -178,6 +178,7 @@ declare class NavigationContainerComponent implements NavigationShellContext {
178
178
  readonly openedIds: _angular_core.ModelSignal<readonly string[]>;
179
179
  readonly itemSelected: _angular_core.OutputEmitterRef<NavigationSelection>;
180
180
  private readonly nav;
181
+ private readonly destroyRef;
181
182
  private readonly hoverPreviewExpanded;
182
183
  /** Konfigurasi type aktif yang didaftarkan wrapper anak (sidebar/dockbar/navbar/flyout). */
183
184
  private readonly typeConfig;
@@ -210,6 +211,7 @@ declare class NavigationContainerComponent implements NavigationShellContext {
210
211
  readonly shellClasses: _angular_core.Signal<string>;
211
212
  readonly state: _angular_core.Signal<_ojiepermana_angular_navigation.NavigationState>;
212
213
  protected readonly hostClasses: _angular_core.Signal<string>;
214
+ constructor();
213
215
  /**
214
216
  * Dipanggil komponen type saat dibuat. Satu `<Navigation>` hanya boleh
215
217
  * memuat satu type hidup — pendaftaran ganda dianggap salah konfigurasi.