@ojiepermana/angular 0.1.1 → 21.0.2

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 (133) hide show
  1. package/README.md +41 -249
  2. package/collection.json +25 -0
  3. package/fesm2022/ojiepermana-angular-chart.mjs +3714 -0
  4. package/fesm2022/ojiepermana-angular-chart.mjs.map +1 -0
  5. package/fesm2022/ojiepermana-angular-component.mjs +3463 -0
  6. package/fesm2022/ojiepermana-angular-component.mjs.map +1 -0
  7. package/fesm2022/ojiepermana-angular-generator-api.mjs +67 -0
  8. package/fesm2022/ojiepermana-angular-generator-api.mjs.map +1 -0
  9. package/fesm2022/ojiepermana-angular-layout.mjs +296 -408
  10. package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -1
  11. package/fesm2022/ojiepermana-angular-navigation.mjs +2198 -404
  12. package/fesm2022/ojiepermana-angular-navigation.mjs.map +1 -1
  13. package/fesm2022/ojiepermana-angular-theme.mjs +381 -1
  14. package/fesm2022/ojiepermana-angular-theme.mjs.map +1 -1
  15. package/fesm2022/ojiepermana-angular.mjs +16 -1
  16. package/fesm2022/ojiepermana-angular.mjs.map +1 -1
  17. package/generator/api/README.md +183 -0
  18. package/generator/api/bin/schematics/init/index.js +88 -0
  19. package/generator/api/bin/schematics/sdk/index.js +58 -0
  20. package/generator/api/bin/src/config/loader.js +41 -0
  21. package/generator/api/bin/src/config/schema.js +56 -0
  22. package/generator/api/bin/src/emit/client.js +246 -0
  23. package/generator/api/bin/src/emit/metadata.js +295 -0
  24. package/generator/api/bin/src/emit/models.js +106 -0
  25. package/generator/api/bin/src/emit/navigation.js +56 -0
  26. package/generator/api/bin/src/emit/operations.js +122 -0
  27. package/generator/api/bin/src/emit/public-api.js +54 -0
  28. package/generator/api/bin/src/emit/services.js +87 -0
  29. package/generator/api/bin/src/engine.js +65 -0
  30. package/generator/api/bin/src/layout/per-domain.js +346 -0
  31. package/generator/api/bin/src/parser/bundle.js +25 -0
  32. package/generator/api/bin/src/parser/ir.js +320 -0
  33. package/generator/api/bin/src/parser/types.js +7 -0
  34. package/generator/api/bin/src/render/template.js +58 -0
  35. package/generator/api/bin/src/writer/index.js +69 -0
  36. package/generator/api/schematics/init/schema.json +19 -0
  37. package/generator/api/schematics/sdk/schema.json +19 -0
  38. package/generator/api/sdk.config.example.json +22 -0
  39. package/generator/guide/README.md +84 -0
  40. package/generator/guide/bin/schematics/build/index.js +35 -0
  41. package/generator/guide/bin/schematics/init/index.js +70 -0
  42. package/generator/guide/bin/src/config/loader.js +50 -0
  43. package/generator/guide/bin/src/config/schema.js +12 -0
  44. package/generator/guide/bin/src/engine/component.js +73 -0
  45. package/generator/guide/bin/src/engine/frontmatter.js +42 -0
  46. package/generator/guide/bin/src/engine/index.js +42 -0
  47. package/generator/guide/bin/src/engine/naming.js +39 -0
  48. package/generator/guide/bin/src/engine/render.js +18 -0
  49. package/generator/guide/bin/src/engine/routes.js +106 -0
  50. package/generator/guide/bin/src/engine/walk.js +35 -0
  51. package/generator/guide/guide.config.example.json +9 -0
  52. package/generator/guide/schematics/build/schema.json +14 -0
  53. package/generator/guide/schematics/init/schema.json +19 -0
  54. package/package.json +58 -38
  55. package/theme/styles/etos.css +38 -0
  56. package/theme/styles/index.css +32 -8
  57. package/theme/styles/themes/brand/etos/color.css +21 -0
  58. package/theme/styles/themes/brand/etos/style.css +50 -0
  59. package/theme/styles/themes/library/_components.css +63 -0
  60. package/theme/styles/themes/library/_layers.css +15 -0
  61. package/theme/styles/themes/library/_material-overrides.css +254 -0
  62. package/theme/styles/themes/library/_tokens.css +54 -0
  63. package/theme/styles/themes/library/color/amber.css +18 -0
  64. package/theme/styles/themes/library/color/blue.css +23 -0
  65. package/theme/styles/themes/library/color/green.css +18 -0
  66. package/theme/styles/themes/library/color/index.css +9 -0
  67. package/theme/styles/themes/library/color/purple.css +18 -0
  68. package/theme/styles/themes/library/color/red.css +18 -0
  69. package/theme/styles/themes/library/style/brutal.css +47 -0
  70. package/theme/styles/themes/library/style/default.css +51 -0
  71. package/theme/styles/themes/library/style/index.css +8 -0
  72. package/theme/styles/themes/library/style/sharp.css +47 -0
  73. package/theme/styles/themes/library/style/soft.css +47 -0
  74. package/theme/styles/themes/mode/dark.css +20 -0
  75. package/theme/styles/themes/mode/index.css +6 -0
  76. package/theme/styles/themes/mode/light.css +24 -0
  77. package/theme/styles/themes/taildwind.css +109 -0
  78. package/types/ojiepermana-angular-chart.d.ts +1094 -0
  79. package/types/ojiepermana-angular-component.d.ts +1174 -0
  80. package/types/ojiepermana-angular-generator-api.d.ts +85 -0
  81. package/types/ojiepermana-angular-layout.d.ts +125 -76
  82. package/types/ojiepermana-angular-navigation.d.ts +256 -116
  83. package/types/ojiepermana-angular-theme.d.ts +170 -1
  84. package/types/ojiepermana-angular.d.ts +2 -1
  85. package/fesm2022/ojiepermana-angular-internal.mjs +0 -489
  86. package/fesm2022/ojiepermana-angular-internal.mjs.map +0 -1
  87. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs +0 -721
  88. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs.map +0 -1
  89. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs +0 -1647
  90. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs.map +0 -1
  91. package/fesm2022/ojiepermana-angular-shell.mjs +0 -19
  92. package/fesm2022/ojiepermana-angular-shell.mjs.map +0 -1
  93. package/fesm2022/ojiepermana-angular-theme-component.mjs +0 -235
  94. package/fesm2022/ojiepermana-angular-theme-component.mjs.map +0 -1
  95. package/fesm2022/ojiepermana-angular-theme-directive.mjs +0 -29
  96. package/fesm2022/ojiepermana-angular-theme-directive.mjs.map +0 -1
  97. package/fesm2022/ojiepermana-angular-theme-service.mjs +0 -241
  98. package/fesm2022/ojiepermana-angular-theme-service.mjs.map +0 -1
  99. package/layout/README.md +0 -144
  100. package/layout/src/component/horizontal/horizontal.css +0 -130
  101. package/layout/src/component/vertical/vertical.css +0 -75
  102. package/layout/src/layout.css +0 -16
  103. package/navigation/README.md +0 -301
  104. package/navigation/horizontal/README.md +0 -49
  105. package/shell/README.md +0 -41
  106. package/styles/index.css +0 -2
  107. package/styles/resets.css +0 -22
  108. package/theme/README.md +0 -379
  109. package/theme/styles/adapters/material-ui/index.css +0 -205
  110. package/theme/styles/modes/dark.css +0 -84
  111. package/theme/styles/presets/colors/blue.css +0 -45
  112. package/theme/styles/presets/colors/brand.css +0 -52
  113. package/theme/styles/presets/colors/cyan.css +0 -45
  114. package/theme/styles/presets/colors/green.css +0 -45
  115. package/theme/styles/presets/colors/index.css +0 -7
  116. package/theme/styles/presets/colors/orange.css +0 -45
  117. package/theme/styles/presets/colors/purple.css +0 -45
  118. package/theme/styles/presets/colors/red.css +0 -45
  119. package/theme/styles/presets/styles/flat.css +0 -61
  120. package/theme/styles/presets/styles/glass.css +0 -28
  121. package/theme/styles/presets/styles/index.css +0 -2
  122. package/theme/styles/roles/index.css +0 -67
  123. package/theme/styles/tokens/foundation.css +0 -136
  124. package/theme/styles/tokens/semantic.css +0 -87
  125. package/theme/styles/utilities/index.css +0 -88
  126. package/types/ojiepermana-angular-internal.d.ts +0 -90
  127. package/types/ojiepermana-angular-navigation-horizontal.d.ts +0 -81
  128. package/types/ojiepermana-angular-navigation-vertical.d.ts +0 -262
  129. package/types/ojiepermana-angular-shell.d.ts +0 -14
  130. package/types/ojiepermana-angular-theme-component.d.ts +0 -46
  131. package/types/ojiepermana-angular-theme-directive.d.ts +0 -10
  132. package/types/ojiepermana-angular-theme-service.d.ts +0 -68
  133. /package/{navigation/vertical → chart}/README.md +0 -0
@@ -1,464 +1,352 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, PLATFORM_ID, signal, effect, Injectable, Directive, ChangeDetectionStrategy, Component, computed, isDevMode, makeEnvironmentProviders } from '@angular/core';
3
- import { DOCUMENT, isPlatformBrowser } from '@angular/common';
4
- import { LocalStorageStateAdapter, libraryLucideConfigProvider } from '@ojiepermana/angular/internal';
2
+ import { InjectionToken, inject, signal, effect, Injectable, input, computed, ChangeDetectionStrategy, Component, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
5
3
  import { RouterOutlet } from '@angular/router';
6
- import { MatIconButton } from '@angular/material/button';
7
- import { MatTooltip } from '@angular/material/tooltip';
8
- import { LucideExpand, LucideShrink, LucidePanelLeft, LucidePanelTop, LucideAppWindow } from '@lucide/angular';
9
- import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
4
+ import { SidebarComponent, TopbarComponent } from '@ojiepermana/angular/navigation';
5
+ import { ThemeService } from '@ojiepermana/angular/theme';
6
+ import { DOCUMENT } from '@angular/common';
10
7
 
11
- const DEFAULT_NG_LAYOUT_CONFIG = {
8
+ const LAYOUT_MODES = ['vertical', 'horizontal'];
9
+ const LAYOUT_WIDTHS = ['full', 'fixed'];
10
+ const MATERIAL_LAYOUT_CONFIG = new InjectionToken('MATERIAL_LAYOUT_CONFIG');
11
+ const DEFAULT_MATERIAL_LAYOUT_CONFIG = {
12
12
  defaultMode: 'vertical',
13
- defaultContainer: 'full',
13
+ defaultWidth: 'fixed',
14
+ storageKey: 'layout-mode',
15
+ widthStorageKey: 'layout-width',
14
16
  };
15
- const NG_LAYOUT_CONFIG = new InjectionToken('NG_LAYOUT_CONFIG', {
16
- providedIn: 'root',
17
- factory: () => ({ ...DEFAULT_NG_LAYOUT_CONFIG }),
18
- });
19
-
20
- const LAYOUT_MODES = ['vertical', 'horizontal', 'empty'];
21
- const LAYOUT_CONTAINERS = ['full', 'boxed'];
22
- const LAYOUT_MODE_SET = new Set(LAYOUT_MODES);
23
- const LAYOUT_CONTAINER_SET = new Set(LAYOUT_CONTAINERS);
24
17
  function isLayoutMode(value) {
25
- return typeof value === 'string' && LAYOUT_MODE_SET.has(value);
18
+ return LAYOUT_MODES.some((mode) => mode === value);
26
19
  }
27
- function isLayoutContainer(value) {
28
- return typeof value === 'string' && LAYOUT_CONTAINER_SET.has(value);
20
+ function isLayoutWidth(value) {
21
+ return LAYOUT_WIDTHS.some((width) => width === value);
29
22
  }
30
23
 
31
- const STORAGE_KEYS = {
32
- 'layout-mode': 'layout-mode',
33
- 'layout-container': 'layout-container',
34
- };
35
- const LEGACY_STORAGE_PREFIX = 'ng-theme:v2';
36
24
  class LayoutService {
37
- config = inject(NG_LAYOUT_CONFIG);
38
25
  document = inject(DOCUMENT);
39
- isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
40
- storage = new LocalStorageStateAdapter({
41
- isBrowser: this.isBrowser,
42
- storage: this.document.defaultView?.localStorage ?? null,
43
- keys: STORAGE_KEYS,
44
- legacyPrefix: LEGACY_STORAGE_PREFIX,
45
- });
46
- mode = signal(this.storage.read('layout-mode', this.config.defaultMode, isLayoutMode), ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
47
- container = signal(this.storage.read('layout-container', this.config.defaultContainer, isLayoutContainer), ...(ngDevMode ? [{ debugName: "container" }] : /* istanbul ignore next */ []));
26
+ config = this.resolveConfig();
27
+ _mode = signal(this.readPersistedMode() ?? this.config.defaultMode, ...(ngDevMode ? [{ debugName: "_mode" }] : /* istanbul ignore next */ []));
28
+ _width = signal(this.readPersistedWidth() ?? this.config.defaultWidth, ...(ngDevMode ? [{ debugName: "_width" }] : /* istanbul ignore next */ []));
29
+ mode = this._mode.asReadonly();
30
+ width = this._width.asReadonly();
48
31
  constructor() {
49
32
  effect(() => {
50
- if (this.isBrowser) {
51
- this.applyToDOM();
52
- }
33
+ this.persistMode(this._mode());
34
+ });
35
+ effect(() => {
36
+ this.persistWidth(this._width());
53
37
  });
54
38
  }
55
- /**
56
- * Updates the active shell mode and persists the value for future sessions.
57
- */
58
- setMode(value) {
59
- this.storage.persist('layout-mode', value);
60
- this.mode.set(value);
39
+ setMode(mode) {
40
+ this._mode.set(mode);
41
+ }
42
+ toggleMode() {
43
+ this._mode.update((mode) => (mode === 'vertical' ? 'horizontal' : 'vertical'));
44
+ }
45
+ setWidth(width) {
46
+ this._width.set(width);
61
47
  }
62
- /**
63
- * Updates the active container width mode and persists the value for future sessions.
64
- */
65
- setContainer(value) {
66
- this.storage.persist('layout-container', value);
67
- this.container.set(value);
48
+ toggleWidth() {
49
+ this._width.update((width) => (width === 'fixed' ? 'full' : 'fixed'));
68
50
  }
69
- /**
70
- * Clears persisted layout state and restores the configured defaults for mode and container.
71
- */
72
- reset() {
73
- this.storage.clear('layout-mode');
74
- this.storage.clear('layout-container');
75
- this.mode.set(this.config.defaultMode);
76
- this.container.set(this.config.defaultContainer);
51
+ resolveConfig() {
52
+ const config = inject(MATERIAL_LAYOUT_CONFIG, { optional: true }) ?? {};
53
+ const configuredMode = config.mode ?? config.defaultMode;
54
+ const configuredWidth = config.width;
55
+ return {
56
+ defaultMode: isLayoutMode(configuredMode) ? configuredMode : DEFAULT_MATERIAL_LAYOUT_CONFIG.defaultMode,
57
+ defaultWidth: isLayoutWidth(configuredWidth) ? configuredWidth : DEFAULT_MATERIAL_LAYOUT_CONFIG.defaultWidth,
58
+ storageKey: config.storageKey ?? DEFAULT_MATERIAL_LAYOUT_CONFIG.storageKey,
59
+ widthStorageKey: config.widthStorageKey ?? DEFAULT_MATERIAL_LAYOUT_CONFIG.widthStorageKey,
60
+ };
77
61
  }
78
- applyToDOM() {
79
- const element = this.document.documentElement;
80
- element.dataset['layoutMode'] = this.mode();
81
- element.dataset['layoutContainer'] = this.container();
62
+ readPersistedMode() {
63
+ const key = this.config.storageKey;
64
+ if (!key)
65
+ return null;
66
+ try {
67
+ const value = this.document.defaultView?.localStorage?.getItem(key);
68
+ return isLayoutMode(value) ? value : null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ readPersistedWidth() {
75
+ const key = this.config.widthStorageKey;
76
+ if (!key)
77
+ return null;
78
+ try {
79
+ const value = this.document.defaultView?.localStorage?.getItem(key);
80
+ return isLayoutWidth(value) ? value : null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
82
85
  }
83
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
84
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutService, providedIn: 'root' });
86
+ persistMode(mode) {
87
+ const key = this.config.storageKey;
88
+ if (!key)
89
+ return;
90
+ try {
91
+ this.document.defaultView?.localStorage?.setItem(key, mode);
92
+ }
93
+ catch {
94
+ /* ignore */
95
+ }
96
+ }
97
+ persistWidth(width) {
98
+ const key = this.config.widthStorageKey;
99
+ if (!key)
100
+ return;
101
+ try {
102
+ this.document.defaultView?.localStorage?.setItem(key, width);
103
+ }
104
+ catch {
105
+ /* ignore */
106
+ }
107
+ }
108
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
109
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutService, providedIn: 'root' });
85
110
  }
86
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutService, decorators: [{
111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutService, decorators: [{
87
112
  type: Injectable,
88
113
  args: [{ providedIn: 'root' }]
89
114
  }], ctorParameters: () => [] });
90
115
 
91
- class LayoutHostDirective {
116
+ /**
117
+ * Vertical layout — sidebar + main (scrollable).
118
+ *
119
+ * Data navigasi diambil dari `NavigationService` (register via
120
+ * `NavigationService.registerItems()` di bootstrap). Main memegang
121
+ * `<router-outlet>` dan scroll jika konten panjang.
122
+ *
123
+ * Markup:
124
+ * ```html
125
+ * <vertical>
126
+ * <!-- sidebar + router-outlet dirender oleh komponen -->
127
+ * </vertical>
128
+ * ```
129
+ */
130
+ class VerticalLayoutComponent {
92
131
  layout = inject(LayoutService);
93
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutHostDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
94
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LayoutHostDirective, isStandalone: true, selector: "[ngtLayoutHost]", host: { properties: { "attr.data-layout-mode": "layout.mode()", "attr.data-layout-container": "layout.container()" } }, ngImport: i0 });
132
+ theme = inject(ThemeService);
133
+ sidebarAppearance = input('default', ...(ngDevMode ? [{ debugName: "sidebarAppearance" }] : /* istanbul ignore next */ []));
134
+ sidebarPosition = input('left', ...(ngDevMode ? [{ debugName: "sidebarPosition" }] : /* istanbul ignore next */ []));
135
+ sidebarMode = input('side', ...(ngDevMode ? [{ debugName: "sidebarMode" }] : /* istanbul ignore next */ []));
136
+ ariaLabel = input('Primary', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
137
+ layoutWidth = this.layout.width;
138
+ themeStyle = this.theme.style;
139
+ shellBorderWidth = computed(() => (this.layoutWidth() === 'fixed' ? 'var(--border-width)' : null), ...(ngDevMode ? [{ debugName: "shellBorderWidth" }] : /* istanbul ignore next */ []));
140
+ dividerBorderWidth = computed(() => 'var(--border-width)', ...(ngDevMode ? [{ debugName: "dividerBorderWidth" }] : /* istanbul ignore next */ []));
141
+ hostClasses = computed(() => {
142
+ const classes = ['block', 'h-dvh', 'w-full', 'overflow-hidden', 'bg-background', 'text-foreground'];
143
+ if (this.layoutWidth() === 'fixed') {
144
+ classes.push('box-border', 'lg:p-8');
145
+ }
146
+ return classes.join(' ');
147
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
148
+ frameClasses = computed(() => {
149
+ const classes = ['flex', 'h-full', 'w-full', 'overflow-hidden'];
150
+ if (this.layoutWidth() === 'fixed') {
151
+ classes.push('lg:border', 'lg:border-border', 'lg:rounded-lg', 'lg:shadow-sm');
152
+ }
153
+ return classes.join(' ');
154
+ }, ...(ngDevMode ? [{ debugName: "frameClasses" }] : /* istanbul ignore next */ []));
155
+ mainClasses = computed(() => {
156
+ const classes = ['flex-1', 'overflow-auto'];
157
+ if (this.layoutWidth() === 'fixed')
158
+ classes.push('lg:mx-auto', 'lg:max-w-7xl');
159
+ return classes.join(' ');
160
+ }, ...(ngDevMode ? [{ debugName: "mainClasses" }] : /* istanbul ignore next */ []));
161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: VerticalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: VerticalLayoutComponent, isStandalone: true, selector: "vertical", inputs: { sidebarAppearance: { classPropertyName: "sidebarAppearance", publicName: "sidebarAppearance", isSignal: true, isRequired: false, transformFunction: null }, sidebarPosition: { classPropertyName: "sidebarPosition", publicName: "sidebarPosition", isSignal: true, isRequired: false, transformFunction: null }, sidebarMode: { classPropertyName: "sidebarMode", publicName: "sidebarMode", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.data-layout-width": "layoutWidth()", "attr.data-style": "themeStyle()" } }, ngImport: i0, template: `
163
+ <div [class]="frameClasses()" [style.border-width]="shellBorderWidth()">
164
+ <ui-sidebar
165
+ [appearance]="sidebarAppearance()"
166
+ [position]="sidebarPosition()"
167
+ [ariaLabel]="ariaLabel()"
168
+ [style.border-left-width]="dividerBorderWidth()"
169
+ [style.border-right-width]="dividerBorderWidth()" />
170
+ <main [class]="mainClasses()">
171
+ <router-outlet />
172
+ </main>
173
+ </div>
174
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: SidebarComponent, selector: "ui-sidebar", inputs: ["items", "navigationId", "appearance", "position", "ariaLabel", "header", "class", "autoMobile", "autoRegister"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
95
175
  }
96
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutHostDirective, decorators: [{
97
- type: Directive,
176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: VerticalLayoutComponent, decorators: [{
177
+ type: Component,
98
178
  args: [{
99
- selector: '[ngtLayoutHost]',
179
+ selector: 'vertical',
180
+ changeDetection: ChangeDetectionStrategy.OnPush,
181
+ imports: [RouterOutlet, SidebarComponent],
100
182
  host: {
101
- '[attr.data-layout-mode]': 'layout.mode()',
102
- '[attr.data-layout-container]': 'layout.container()',
183
+ '[class]': 'hostClasses()',
184
+ '[attr.data-layout-width]': 'layoutWidth()',
185
+ '[attr.data-style]': 'themeStyle()',
103
186
  },
187
+ template: `
188
+ <div [class]="frameClasses()" [style.border-width]="shellBorderWidth()">
189
+ <ui-sidebar
190
+ [appearance]="sidebarAppearance()"
191
+ [position]="sidebarPosition()"
192
+ [ariaLabel]="ariaLabel()"
193
+ [style.border-left-width]="dividerBorderWidth()"
194
+ [style.border-right-width]="dividerBorderWidth()" />
195
+ <main [class]="mainClasses()">
196
+ <router-outlet />
197
+ </main>
198
+ </div>
199
+ `,
104
200
  }]
105
- }] });
201
+ }], propDecorators: { sidebarAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarAppearance", required: false }] }], sidebarPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarPosition", required: false }] }], sidebarMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarMode", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
106
202
 
107
- class LayoutElementDirective {
108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
109
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LayoutElementDirective, isStandalone: true, selector: "layout", ngImport: i0 });
110
- }
111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutElementDirective, decorators: [{
112
- type: Directive,
113
- args: [{
114
- selector: 'layout',
115
- }]
116
- }] });
117
- class ContentElementDirective {
118
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ContentElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
119
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: ContentElementDirective, isStandalone: true, selector: "content,shell-content", ngImport: i0 });
120
- }
121
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ContentElementDirective, decorators: [{
122
- type: Directive,
123
- args: [{
124
- selector: 'content,shell-content',
125
- }]
126
- }] });
127
- class BrandElementDirective {
128
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BrandElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
129
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: BrandElementDirective, isStandalone: true, selector: "brand", ngImport: i0 });
130
- }
131
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BrandElementDirective, decorators: [{
132
- type: Directive,
133
- args: [{
134
- selector: 'brand',
135
- }]
136
- }] });
137
- class NavigationElementDirective {
138
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NavigationElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
139
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: NavigationElementDirective, isStandalone: true, selector: "navigation", ngImport: i0 });
140
- }
141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NavigationElementDirective, decorators: [{
142
- type: Directive,
143
- args: [{
144
- selector: 'navigation',
145
- }]
146
- }] });
147
- class ActionElementDirective {
148
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ActionElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
149
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: ActionElementDirective, isStandalone: true, selector: "action", ngImport: i0 });
150
- }
151
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ActionElementDirective, decorators: [{
152
- type: Directive,
153
- args: [{
154
- selector: 'action',
155
- }]
156
- }] });
157
-
158
- class LayoutHorizontalComponent {
159
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutHorizontalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
160
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: LayoutHorizontalComponent, isStandalone: true, selector: "horizontal", host: { properties: { "attr.data-layout-mode": "\"horizontal\"" } }, ngImport: i0, template: `
161
- <layout>
162
- <shell-content>
163
- <header>
164
- <brand>
165
- <ng-content select="[brand]"></ng-content>
166
- </brand>
167
-
168
- <navigation>
169
- <div class="layout-horizontal-navigation-slot">
170
- <ng-content select="[navigation]"></ng-content>
171
- </div>
172
- </navigation>
173
-
174
- <action>
175
- <ng-content select="[action]"></ng-content>
176
- </action>
177
- </header>
178
-
179
- <main>
180
- <router-outlet />
181
- </main>
182
- </shell-content>
183
- </layout>
184
- `, isInline: true, styles: [":host{display:block;block-size:100dvh;min-block-size:100dvh;overflow:hidden}:host>layout{display:block;block-size:100dvh;min-block-size:100dvh;padding:var(--layout-shell-padding);background:var(--background);color:var(--foreground);overflow:hidden;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content){display:flex;flex-direction:column;inline-size:min(100%,var(--layout-shell-max-width));block-size:calc(100dvh - (var(--layout-shell-padding) * 2));min-block-size:0;margin-inline:auto;border:1px solid var(--container-border);border-radius:var(--layout-shell-radius);background:var(--container-surface);color:var(--container-foreground);box-shadow:var(--container-shadow);backdrop-filter:var(--container-backdrop);-webkit-backdrop-filter:var(--container-backdrop);overflow:hidden;transition:var(--ngt-shell-transition)}:host>layout>:is(content,shell-content)>header{display:var(--layout-header-display);grid-template-areas:\"brand navigation action\";grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:1rem;min-block-size:var(--layout-header-height);padding:.875rem 1rem;border-bottom:1px solid var(--nav-border);background:var(--nav-surface);color:var(--nav-foreground);transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content)>header>brand,:host>layout>:is(content,shell-content)>header>action{display:flex;min-inline-size:0;align-items:center}:host>layout>:is(content,shell-content)>header>brand{grid-area:brand;justify-content:flex-start;justify-self:start}:host>layout>:is(content,shell-content)>header>navigation{grid-area:navigation;display:flex;inline-size:100%;min-inline-size:0;align-items:center;justify-self:stretch;justify-content:center;gap:.75rem;flex-wrap:wrap}:host>layout>:is(content,shell-content)>header>navigation>.layout-horizontal-navigation-slot{flex:0 1 auto;display:block;min-inline-size:0;max-inline-size:100%}:host>layout>:is(content,shell-content)>header>action{grid-area:action;justify-content:flex-end;justify-self:end;gap:.5rem}:host>layout>:is(content,shell-content)>main{flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:auto;background-color:var(--background);background-image:linear-gradient(180deg,color-mix(in oklab,var(--background) 94%,white 6%),var(--background));color:var(--foreground);transition:background-color var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard),color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard)}@media(max-width:60rem){:host>layout>:is(content,shell-content)>header{grid-template-areas:\"brand action\" \"navigation navigation\";grid-template-columns:minmax(0,1fr) auto;align-items:flex-start}:host>layout>:is(content,shell-content)>header>navigation{justify-content:center}}@media(max-width:40rem){:host>layout>:is(content,shell-content)>header{grid-template-areas:\"brand\" \"navigation\" \"action\";grid-template-columns:1fr}:host>layout>:is(content,shell-content)>header>action{justify-content:flex-end}}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: LayoutElementDirective, selector: "layout" }, { kind: "directive", type: ContentElementDirective, selector: "content,shell-content" }, { kind: "directive", type: BrandElementDirective, selector: "brand" }, { kind: "directive", type: NavigationElementDirective, selector: "navigation" }, { kind: "directive", type: ActionElementDirective, selector: "action" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
185
- }
186
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutHorizontalComponent, decorators: [{
187
- type: Component,
188
- args: [{ selector: 'horizontal', imports: [
189
- RouterOutlet,
190
- LayoutElementDirective,
191
- ContentElementDirective,
192
- BrandElementDirective,
193
- NavigationElementDirective,
194
- ActionElementDirective,
195
- ], host: {
196
- '[attr.data-layout-mode]': '"horizontal"',
197
- }, template: `
198
- <layout>
199
- <shell-content>
200
- <header>
201
- <brand>
202
- <ng-content select="[brand]"></ng-content>
203
- </brand>
204
-
205
- <navigation>
206
- <div class="layout-horizontal-navigation-slot">
207
- <ng-content select="[navigation]"></ng-content>
208
- </div>
209
- </navigation>
210
-
211
- <action>
212
- <ng-content select="[action]"></ng-content>
213
- </action>
214
- </header>
215
-
216
- <main>
217
- <router-outlet />
218
- </main>
219
- </shell-content>
220
- </layout>
221
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;block-size:100dvh;min-block-size:100dvh;overflow:hidden}:host>layout{display:block;block-size:100dvh;min-block-size:100dvh;padding:var(--layout-shell-padding);background:var(--background);color:var(--foreground);overflow:hidden;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content){display:flex;flex-direction:column;inline-size:min(100%,var(--layout-shell-max-width));block-size:calc(100dvh - (var(--layout-shell-padding) * 2));min-block-size:0;margin-inline:auto;border:1px solid var(--container-border);border-radius:var(--layout-shell-radius);background:var(--container-surface);color:var(--container-foreground);box-shadow:var(--container-shadow);backdrop-filter:var(--container-backdrop);-webkit-backdrop-filter:var(--container-backdrop);overflow:hidden;transition:var(--ngt-shell-transition)}:host>layout>:is(content,shell-content)>header{display:var(--layout-header-display);grid-template-areas:\"brand navigation action\";grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:1rem;min-block-size:var(--layout-header-height);padding:.875rem 1rem;border-bottom:1px solid var(--nav-border);background:var(--nav-surface);color:var(--nav-foreground);transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content)>header>brand,:host>layout>:is(content,shell-content)>header>action{display:flex;min-inline-size:0;align-items:center}:host>layout>:is(content,shell-content)>header>brand{grid-area:brand;justify-content:flex-start;justify-self:start}:host>layout>:is(content,shell-content)>header>navigation{grid-area:navigation;display:flex;inline-size:100%;min-inline-size:0;align-items:center;justify-self:stretch;justify-content:center;gap:.75rem;flex-wrap:wrap}:host>layout>:is(content,shell-content)>header>navigation>.layout-horizontal-navigation-slot{flex:0 1 auto;display:block;min-inline-size:0;max-inline-size:100%}:host>layout>:is(content,shell-content)>header>action{grid-area:action;justify-content:flex-end;justify-self:end;gap:.5rem}:host>layout>:is(content,shell-content)>main{flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:auto;background-color:var(--background);background-image:linear-gradient(180deg,color-mix(in oklab,var(--background) 94%,white 6%),var(--background));color:var(--foreground);transition:background-color var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard),color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard)}@media(max-width:60rem){:host>layout>:is(content,shell-content)>header{grid-template-areas:\"brand action\" \"navigation navigation\";grid-template-columns:minmax(0,1fr) auto;align-items:flex-start}:host>layout>:is(content,shell-content)>header>navigation{justify-content:center}}@media(max-width:40rem){:host>layout>:is(content,shell-content)>header{grid-template-areas:\"brand\" \"navigation\" \"action\";grid-template-columns:1fr}:host>layout>:is(content,shell-content)>header>action{justify-content:flex-end}}\n"] }]
222
- }] });
223
-
224
- class LayoutVerticalComponent {
225
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutVerticalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
226
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.8", type: LayoutVerticalComponent, isStandalone: true, selector: "vertical", host: { properties: { "attr.data-layout-mode": "\"vertical\"" } }, ngImport: i0, template: `
227
- <layout>
228
- <shell-content>
229
- <aside>
230
- <ng-content select="[navigation]"></ng-content>
231
- </aside>
232
- <main>
233
- <router-outlet />
234
- </main>
235
- </shell-content>
236
- </layout>
237
- `, isInline: true, styles: [":host{display:block;block-size:100dvh;min-block-size:100dvh;overflow:hidden}:host>layout{display:block;block-size:100dvh;min-block-size:100dvh;padding:var(--layout-shell-padding);background:var(--background);color:var(--foreground);overflow:hidden;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content){display:flex;flex-direction:column;inline-size:min(100%,var(--layout-shell-max-width));block-size:calc(100dvh - (var(--layout-shell-padding) * 2));min-block-size:0;margin-inline:auto;border:1px solid var(--container-border);border-radius:var(--layout-shell-radius);background:var(--container-surface);color:var(--container-foreground);box-shadow:var(--container-shadow);backdrop-filter:var(--container-backdrop);-webkit-backdrop-filter:var(--container-backdrop);overflow:hidden;transition:var(--ngt-shell-transition)}:host>layout>:is(content,shell-content)>aside{display:var(--layout-sidebar-display);flex-direction:column;inline-size:100%;min-block-size:0;border-bottom:1px solid var(--sidebar-chrome-border);background:var(--sidebar-chrome-surface);color:var(--sidebar-chrome-foreground);overflow:auto;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content)>main{flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:auto;background-color:var(--background);background-image:linear-gradient(180deg,color-mix(in oklab,var(--background) 94%,white 6%),var(--background));color:var(--foreground);transition:background-color var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard),color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard)}@media(min-width:48rem){:host>layout>:is(content,shell-content){flex-direction:row}:host>layout>:is(content,shell-content)>aside{flex:0 0 var(--layout-sidebar-width);inline-size:var(--layout-sidebar-width);min-inline-size:var(--layout-sidebar-width);border-bottom:0;border-right:1px solid var(--sidebar-chrome-border)}}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: LayoutElementDirective, selector: "layout" }, { kind: "directive", type: ContentElementDirective, selector: "content,shell-content" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
238
- }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutVerticalComponent, decorators: [{
240
- type: Component,
241
- args: [{ selector: 'vertical', imports: [RouterOutlet, LayoutElementDirective, ContentElementDirective], host: {
242
- '[attr.data-layout-mode]': '"vertical"',
243
- }, template: `
244
- <layout>
245
- <shell-content>
246
- <aside>
247
- <ng-content select="[navigation]"></ng-content>
248
- </aside>
249
- <main>
250
- <router-outlet />
251
- </main>
252
- </shell-content>
253
- </layout>
254
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;block-size:100dvh;min-block-size:100dvh;overflow:hidden}:host>layout{display:block;block-size:100dvh;min-block-size:100dvh;padding:var(--layout-shell-padding);background:var(--background);color:var(--foreground);overflow:hidden;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content){display:flex;flex-direction:column;inline-size:min(100%,var(--layout-shell-max-width));block-size:calc(100dvh - (var(--layout-shell-padding) * 2));min-block-size:0;margin-inline:auto;border:1px solid var(--container-border);border-radius:var(--layout-shell-radius);background:var(--container-surface);color:var(--container-foreground);box-shadow:var(--container-shadow);backdrop-filter:var(--container-backdrop);-webkit-backdrop-filter:var(--container-backdrop);overflow:hidden;transition:var(--ngt-shell-transition)}:host>layout>:is(content,shell-content)>aside{display:var(--layout-sidebar-display);flex-direction:column;inline-size:100%;min-block-size:0;border-bottom:1px solid var(--sidebar-chrome-border);background:var(--sidebar-chrome-surface);color:var(--sidebar-chrome-foreground);overflow:auto;transition:var(--ngt-chrome-transition)}:host>layout>:is(content,shell-content)>main{flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:auto;background-color:var(--background);background-image:linear-gradient(180deg,color-mix(in oklab,var(--background) 94%,white 6%),var(--background));color:var(--foreground);transition:background-color var(--ngt-motion-duration-medium) var(--ngt-motion-ease-standard),color var(--ngt-motion-duration-fast) var(--ngt-motion-ease-standard)}@media(min-width:48rem){:host>layout>:is(content,shell-content){flex-direction:row}:host>layout>:is(content,shell-content)>aside{flex:0 0 var(--layout-sidebar-width);inline-size:var(--layout-sidebar-width);min-inline-size:var(--layout-sidebar-width);border-bottom:0;border-right:1px solid var(--sidebar-chrome-border)}}\n"] }]
255
- }] });
256
-
257
- class LayoutContainerSwitcherComponent {
203
+ /**
204
+ * Horizontal layout topbar (h-12) + main (scrollable).
205
+ *
206
+ * Data navigasi diambil dari `NavigationService`.
207
+ * Consumer app dapat memproyeksikan brand kiri dan profile kanan.
208
+ *
209
+ * Markup:
210
+ * ```html
211
+ * <horizontal>
212
+ * <a ui-layout-brand>Brand</a>
213
+ * <button ui-layout-profile type="button">Profile</button>
214
+ * </horizontal>
215
+ * ```
216
+ */
217
+ class HorizontalLayoutComponent {
258
218
  layout = inject(LayoutService);
259
- label = computed(() => this.layout.container() === 'boxed' ? 'Boxed layout container enabled' : 'Boxed layout container disabled', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
260
- toggle() {
261
- this.layout.setContainer(this.layout.container() === 'full' ? 'boxed' : 'full');
262
- }
263
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutContainerSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
264
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: LayoutContainerSwitcherComponent, isStandalone: true, selector: "layout-container-switcher", providers: [libraryLucideConfigProvider], ngImport: i0, template: `
265
- <button
266
- class="ngt-icon-button"
267
- type="button"
268
- mat-icon-button
269
- aria-label="Boxed layout container"
270
- [attr.aria-pressed]="layout.container() === 'boxed'"
271
- [matTooltip]="label()"
272
- (click)="toggle()">
273
- @if (layout.container() === 'full') {
274
- <svg lucideExpand aria-hidden="true"></svg>
275
- } @else {
276
- <svg lucideShrink aria-hidden="true"></svg>
277
- }
278
- </button>
279
- `, isInline: true, dependencies: [{ kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: LucideExpand, selector: "svg[lucideExpand]" }, { kind: "component", type: LucideShrink, selector: "svg[lucideShrink]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
219
+ theme = inject(ThemeService);
220
+ topbarAppearance = input('default', ...(ngDevMode ? [{ debugName: "topbarAppearance" }] : /* istanbul ignore next */ []));
221
+ ariaLabel = input('Primary', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
222
+ layoutWidth = this.layout.width;
223
+ themeStyle = this.theme.style;
224
+ shellBorderWidth = computed(() => (this.layoutWidth() === 'fixed' ? 'var(--border-width)' : null), ...(ngDevMode ? [{ debugName: "shellBorderWidth" }] : /* istanbul ignore next */ []));
225
+ dividerBorderWidth = computed(() => 'var(--border-width)', ...(ngDevMode ? [{ debugName: "dividerBorderWidth" }] : /* istanbul ignore next */ []));
226
+ hostClasses = computed(() => {
227
+ const classes = ['block', 'h-dvh', 'w-full', 'overflow-hidden', 'bg-background', 'text-foreground'];
228
+ if (this.layoutWidth() === 'fixed') {
229
+ classes.push('box-border', 'lg:p-8');
230
+ }
231
+ return classes.join(' ');
232
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
233
+ frameClasses = computed(() => {
234
+ const classes = ['flex', 'h-full', 'w-full', 'flex-col', 'overflow-hidden'];
235
+ if (this.layoutWidth() === 'fixed') {
236
+ classes.push('lg:mx-auto', 'lg:max-w-7xl', 'lg:border', 'lg:border-border', 'lg:rounded-lg', 'lg:shadow-sm');
237
+ }
238
+ return classes.join(' ');
239
+ }, ...(ngDevMode ? [{ debugName: "frameClasses" }] : /* istanbul ignore next */ []));
240
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: HorizontalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
241
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: HorizontalLayoutComponent, isStandalone: true, selector: "horizontal", inputs: { topbarAppearance: { classPropertyName: "topbarAppearance", publicName: "topbarAppearance", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.data-layout-width": "layoutWidth()", "attr.data-style": "themeStyle()" } }, ngImport: i0, template: `
242
+ <div [class]="frameClasses()" [style.border-width]="shellBorderWidth()">
243
+ <ui-topbar
244
+ class="h-12 w-full shrink-0 border-b border-border"
245
+ [style.border-bottom-width]="dividerBorderWidth()"
246
+ [appearance]="topbarAppearance()"
247
+ [ariaLabel]="ariaLabel()">
248
+ <div ui-topbar-start class="flex min-w-0 items-center">
249
+ <ng-content select="[ui-layout-brand],[ui-topbar-start]" />
250
+ </div>
251
+ <div ui-topbar-end class="flex min-w-0 items-center">
252
+ <ng-content select="[ui-layout-profile],[ui-topbar-end]" />
253
+ </div>
254
+ </ui-topbar>
255
+ <main class="flex-1 overflow-auto">
256
+ <router-outlet />
257
+ </main>
258
+ </div>
259
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: TopbarComponent, selector: "ui-topbar", inputs: ["items", "navigationId", "appearance", "ariaLabel", "class", "autoRegister", "showHamburger", "hamburgerLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
280
260
  }
281
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutContainerSwitcherComponent, decorators: [{
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: HorizontalLayoutComponent, decorators: [{
282
262
  type: Component,
283
263
  args: [{
284
- selector: 'layout-container-switcher',
285
- imports: [MatIconButton, MatTooltip, LucideExpand, LucideShrink],
286
- providers: [libraryLucideConfigProvider],
264
+ selector: 'horizontal',
287
265
  changeDetection: ChangeDetectionStrategy.OnPush,
266
+ imports: [RouterOutlet, TopbarComponent],
267
+ host: {
268
+ '[class]': 'hostClasses()',
269
+ '[attr.data-layout-width]': 'layoutWidth()',
270
+ '[attr.data-style]': 'themeStyle()',
271
+ },
288
272
  template: `
289
- <button
290
- class="ngt-icon-button"
291
- type="button"
292
- mat-icon-button
293
- aria-label="Boxed layout container"
294
- [attr.aria-pressed]="layout.container() === 'boxed'"
295
- [matTooltip]="label()"
296
- (click)="toggle()">
297
- @if (layout.container() === 'full') {
298
- <svg lucideExpand aria-hidden="true"></svg>
299
- } @else {
300
- <svg lucideShrink aria-hidden="true"></svg>
301
- }
302
- </button>
273
+ <div [class]="frameClasses()" [style.border-width]="shellBorderWidth()">
274
+ <ui-topbar
275
+ class="h-12 w-full shrink-0 border-b border-border"
276
+ [style.border-bottom-width]="dividerBorderWidth()"
277
+ [appearance]="topbarAppearance()"
278
+ [ariaLabel]="ariaLabel()">
279
+ <div ui-topbar-start class="flex min-w-0 items-center">
280
+ <ng-content select="[ui-layout-brand],[ui-topbar-start]" />
281
+ </div>
282
+ <div ui-topbar-end class="flex min-w-0 items-center">
283
+ <ng-content select="[ui-layout-profile],[ui-topbar-end]" />
284
+ </div>
285
+ </ui-topbar>
286
+ <main class="flex-1 overflow-auto">
287
+ <router-outlet />
288
+ </main>
289
+ </div>
303
290
  `,
304
291
  }]
305
- }] });
292
+ }], propDecorators: { topbarAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarAppearance", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
306
293
 
307
- class LayoutModeSwitcherComponent {
308
- layout = inject(LayoutService);
309
- // Empty mode remains programmatic so the UI only exposes the two navigational shell variants.
310
- options = [
311
- { value: 'vertical', label: 'Vertical Sidebar' },
312
- { value: 'horizontal', label: 'Horizontal Navbar' },
313
- ];
314
- currentOption = computed(() => this.options.find((option) => option.value === this.layout.mode()) ?? {
315
- value: 'empty',
316
- label: 'Content Only',
317
- }, ...(ngDevMode ? [{ debugName: "currentOption" }] : /* istanbul ignore next */ []));
318
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutModeSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
319
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: LayoutModeSwitcherComponent, isStandalone: true, selector: "layout-mode-switcher", providers: [libraryLucideConfigProvider], ngImport: i0, template: `
320
- <button
321
- class="ngt-icon-button"
322
- type="button"
323
- mat-icon-button
324
- [attr.aria-label]="'Layout mode: ' + currentOption().label"
325
- [matTooltip]="'Layout mode: ' + currentOption().label"
326
- [matMenuTriggerFor]="menu">
327
- @switch (layout.mode()) {
328
- @case ('vertical') {
329
- <svg lucidePanelLeft aria-hidden="true"></svg>
330
- }
331
- @case ('horizontal') {
332
- <svg lucidePanelTop aria-hidden="true"></svg>
333
- }
334
- @default {
335
- <svg lucideAppWindow aria-hidden="true"></svg>
336
- }
337
- }
338
- </button>
339
-
340
- <mat-menu #menu="matMenu">
341
- @for (option of options; track option.value) {
342
- <button
343
- type="button"
344
- mat-menu-item
345
- role="menuitemradio"
346
- [attr.aria-checked]="layout.mode() === option.value"
347
- (click)="layout.setMode(option.value)">
348
- @switch (option.value) {
349
- @case ('vertical') {
350
- <svg lucidePanelLeft aria-hidden="true"></svg>
351
- }
352
- @case ('horizontal') {
353
- <svg lucidePanelTop aria-hidden="true"></svg>
354
- }
355
- @default {
356
- <svg lucideAppWindow aria-hidden="true"></svg>
357
- }
358
- }
359
- <span>{{ option.label }}</span>
360
- </button>
361
- }
362
- </mat-menu>
363
- `, isInline: true, dependencies: [{ kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: LucidePanelLeft, selector: "svg[lucidePanelLeft], svg[lucideSidebar]" }, { kind: "component", type: LucidePanelTop, selector: "svg[lucidePanelTop]" }, { kind: "component", type: LucideAppWindow, selector: "svg[lucideAppWindow]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
294
+ /**
295
+ * Empty layout full-viewport, flex-centered main.
296
+ *
297
+ * Cocok untuk halaman login / error / onboarding (pola shadcn `login-05`).
298
+ * Konten dirender lewat `<router-outlet>`; consumer men-style card / form
299
+ * milik halaman route sendiri.
300
+ *
301
+ * Markup:
302
+ * ```html
303
+ * <empty>
304
+ * <!-- router-outlet dirender oleh komponen -->
305
+ * </empty>
306
+ * ```
307
+ */
308
+ class EmptyLayoutComponent {
309
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
310
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: EmptyLayoutComponent, isStandalone: true, selector: "empty", host: { classAttribute: "flex min-h-dvh w-full items-center justify-center bg-background p-6 text-foreground" }, ngImport: i0, template: `
311
+ <main class="w-full max-w-sm">
312
+ <router-outlet />
313
+ </main>
314
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
364
315
  }
365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LayoutModeSwitcherComponent, decorators: [{
316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EmptyLayoutComponent, decorators: [{
366
317
  type: Component,
367
318
  args: [{
368
- selector: 'layout-mode-switcher',
369
- imports: [
370
- MatIconButton,
371
- MatTooltip,
372
- MatMenu,
373
- MatMenuItem,
374
- MatMenuTrigger,
375
- LucidePanelLeft,
376
- LucidePanelTop,
377
- LucideAppWindow,
378
- ],
379
- providers: [libraryLucideConfigProvider],
319
+ selector: 'empty',
380
320
  changeDetection: ChangeDetectionStrategy.OnPush,
321
+ imports: [RouterOutlet],
322
+ host: {
323
+ class: 'flex min-h-dvh w-full items-center justify-center bg-background p-6 text-foreground',
324
+ },
381
325
  template: `
382
- <button
383
- class="ngt-icon-button"
384
- type="button"
385
- mat-icon-button
386
- [attr.aria-label]="'Layout mode: ' + currentOption().label"
387
- [matTooltip]="'Layout mode: ' + currentOption().label"
388
- [matMenuTriggerFor]="menu">
389
- @switch (layout.mode()) {
390
- @case ('vertical') {
391
- <svg lucidePanelLeft aria-hidden="true"></svg>
392
- }
393
- @case ('horizontal') {
394
- <svg lucidePanelTop aria-hidden="true"></svg>
395
- }
396
- @default {
397
- <svg lucideAppWindow aria-hidden="true"></svg>
398
- }
399
- }
400
- </button>
401
-
402
- <mat-menu #menu="matMenu">
403
- @for (option of options; track option.value) {
404
- <button
405
- type="button"
406
- mat-menu-item
407
- role="menuitemradio"
408
- [attr.aria-checked]="layout.mode() === option.value"
409
- (click)="layout.setMode(option.value)">
410
- @switch (option.value) {
411
- @case ('vertical') {
412
- <svg lucidePanelLeft aria-hidden="true"></svg>
413
- }
414
- @case ('horizontal') {
415
- <svg lucidePanelTop aria-hidden="true"></svg>
416
- }
417
- @default {
418
- <svg lucideAppWindow aria-hidden="true"></svg>
419
- }
420
- }
421
- <span>{{ option.label }}</span>
422
- </button>
423
- }
424
- </mat-menu>
326
+ <main class="w-full max-w-sm">
327
+ <router-outlet />
328
+ </main>
425
329
  `,
426
330
  }]
427
331
  }] });
428
332
 
429
- function warnInvalidLayoutConfig(message) {
430
- if (isDevMode()) {
431
- console.warn(`[provideNgLayout] ${message}`);
432
- }
433
- }
434
- function normalizeLayoutMode(value) {
435
- if (typeof value === 'undefined' || isLayoutMode(value)) {
436
- return value ?? DEFAULT_NG_LAYOUT_CONFIG.defaultMode;
437
- }
438
- warnInvalidLayoutConfig(`Ignoring invalid defaultMode ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_LAYOUT_CONFIG.defaultMode)}.`);
439
- return DEFAULT_NG_LAYOUT_CONFIG.defaultMode;
440
- }
441
- function normalizeLayoutContainer(value) {
442
- if (typeof value === 'undefined' || isLayoutContainer(value)) {
443
- return value ?? DEFAULT_NG_LAYOUT_CONFIG.defaultContainer;
444
- }
445
- warnInvalidLayoutConfig(`Ignoring invalid defaultContainer ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_LAYOUT_CONFIG.defaultContainer)}.`);
446
- return DEFAULT_NG_LAYOUT_CONFIG.defaultContainer;
447
- }
448
- function normalizeLayoutConfig(config) {
449
- return {
450
- ...DEFAULT_NG_LAYOUT_CONFIG,
451
- defaultMode: normalizeLayoutMode(config.defaultMode),
452
- defaultContainer: normalizeLayoutContainer(config.defaultContainer),
453
- };
454
- }
455
- function provideNgLayout(config = {}) {
456
- return makeEnvironmentProviders([{ provide: NG_LAYOUT_CONFIG, useValue: normalizeLayoutConfig(config) }]);
333
+ function provideMaterialLayout(config = {}) {
334
+ return makeEnvironmentProviders([
335
+ { provide: MATERIAL_LAYOUT_CONFIG, useValue: config },
336
+ provideEnvironmentInitializer(() => {
337
+ inject(LayoutService);
338
+ }),
339
+ ]);
457
340
  }
458
341
 
342
+ /*
343
+ * Public API Surface of @ojiepermana/angular/layout
344
+ */
345
+ const LAYOUT_VERSION = '0.0.1';
346
+
459
347
  /**
460
348
  * Generated bundle index. Do not edit.
461
349
  */
462
350
 
463
- export { LayoutContainerSwitcherComponent, LayoutHorizontalComponent, LayoutHostDirective, LayoutModeSwitcherComponent, LayoutService, LayoutVerticalComponent, NG_LAYOUT_CONFIG, provideNgLayout };
351
+ export { DEFAULT_MATERIAL_LAYOUT_CONFIG, EmptyLayoutComponent, HorizontalLayoutComponent, LAYOUT_MODES, LAYOUT_VERSION, LAYOUT_WIDTHS, LayoutService, MATERIAL_LAYOUT_CONFIG, VerticalLayoutComponent, isLayoutMode, isLayoutWidth, provideMaterialLayout };
464
352
  //# sourceMappingURL=ojiepermana-angular-layout.mjs.map