@ojiepermana/angular 0.1.0 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +41 -246
  2. package/chart/README.md +0 -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-layout.mjs +272 -401
  8. package/fesm2022/ojiepermana-angular-layout.mjs.map +1 -1
  9. package/fesm2022/ojiepermana-angular-navigation.mjs +2225 -135
  10. package/fesm2022/ojiepermana-angular-navigation.mjs.map +1 -1
  11. package/fesm2022/ojiepermana-angular-theme.mjs +381 -1
  12. package/fesm2022/ojiepermana-angular-theme.mjs.map +1 -1
  13. package/fesm2022/ojiepermana-angular.mjs +15 -1
  14. package/fesm2022/ojiepermana-angular.mjs.map +1 -1
  15. package/package.json +49 -36
  16. package/theme/styles/etos.css +38 -0
  17. package/theme/styles/index.css +32 -8
  18. package/theme/styles/themes/brand/etos/color.css +21 -0
  19. package/theme/styles/themes/brand/etos/style.css +50 -0
  20. package/theme/styles/themes/library/_components.css +63 -0
  21. package/theme/styles/themes/library/_layers.css +15 -0
  22. package/theme/styles/themes/library/_material-overrides.css +254 -0
  23. package/theme/styles/themes/library/_tokens.css +54 -0
  24. package/theme/styles/themes/library/color/amber.css +18 -0
  25. package/theme/styles/themes/library/color/blue.css +23 -0
  26. package/theme/styles/themes/library/color/green.css +18 -0
  27. package/theme/styles/themes/library/color/index.css +9 -0
  28. package/theme/styles/themes/library/color/purple.css +18 -0
  29. package/theme/styles/themes/library/color/red.css +18 -0
  30. package/theme/styles/themes/library/style/brutal.css +47 -0
  31. package/theme/styles/themes/library/style/default.css +51 -0
  32. package/theme/styles/themes/library/style/index.css +8 -0
  33. package/theme/styles/themes/library/style/sharp.css +47 -0
  34. package/theme/styles/themes/library/style/soft.css +47 -0
  35. package/theme/styles/themes/mode/dark.css +20 -0
  36. package/theme/styles/themes/mode/index.css +6 -0
  37. package/theme/styles/themes/mode/light.css +24 -0
  38. package/theme/styles/themes/taildwind.css +109 -0
  39. package/types/ojiepermana-angular-chart.d.ts +1094 -0
  40. package/types/ojiepermana-angular-component.d.ts +1174 -0
  41. package/types/ojiepermana-angular-layout.d.ts +123 -76
  42. package/types/ojiepermana-angular-navigation.d.ts +257 -71
  43. package/types/ojiepermana-angular-theme.d.ts +170 -1
  44. package/types/ojiepermana-angular.d.ts +2 -1
  45. package/fesm2022/ojiepermana-angular-internal.mjs +0 -473
  46. package/fesm2022/ojiepermana-angular-internal.mjs.map +0 -1
  47. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs +0 -785
  48. package/fesm2022/ojiepermana-angular-navigation-horizontal.mjs.map +0 -1
  49. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs +0 -1568
  50. package/fesm2022/ojiepermana-angular-navigation-vertical.mjs.map +0 -1
  51. package/fesm2022/ojiepermana-angular-shell.mjs +0 -14
  52. package/fesm2022/ojiepermana-angular-shell.mjs.map +0 -1
  53. package/fesm2022/ojiepermana-angular-theme-component.mjs +0 -235
  54. package/fesm2022/ojiepermana-angular-theme-component.mjs.map +0 -1
  55. package/fesm2022/ojiepermana-angular-theme-directive.mjs +0 -29
  56. package/fesm2022/ojiepermana-angular-theme-directive.mjs.map +0 -1
  57. package/fesm2022/ojiepermana-angular-theme-service.mjs +0 -241
  58. package/fesm2022/ojiepermana-angular-theme-service.mjs.map +0 -1
  59. package/layout/README.md +0 -144
  60. package/navigation/README.md +0 -215
  61. package/shell/README.md +0 -37
  62. package/styles/index.css +0 -2
  63. package/styles/resets.css +0 -22
  64. package/theme/README.md +0 -379
  65. package/theme/styles/adapters/material-ui/index.css +0 -205
  66. package/theme/styles/layout/horizontal.css +0 -109
  67. package/theme/styles/layout/index.css +0 -19
  68. package/theme/styles/layout/vertical.css +0 -75
  69. package/theme/styles/modes/dark.css +0 -84
  70. package/theme/styles/presets/colors/blue.css +0 -45
  71. package/theme/styles/presets/colors/brand.css +0 -52
  72. package/theme/styles/presets/colors/cyan.css +0 -45
  73. package/theme/styles/presets/colors/green.css +0 -45
  74. package/theme/styles/presets/colors/index.css +0 -7
  75. package/theme/styles/presets/colors/orange.css +0 -45
  76. package/theme/styles/presets/colors/purple.css +0 -45
  77. package/theme/styles/presets/colors/red.css +0 -45
  78. package/theme/styles/presets/styles/flat.css +0 -61
  79. package/theme/styles/presets/styles/glass.css +0 -28
  80. package/theme/styles/presets/styles/index.css +0 -2
  81. package/theme/styles/roles/index.css +0 -67
  82. package/theme/styles/tokens/foundation.css +0 -136
  83. package/theme/styles/tokens/semantic.css +0 -87
  84. package/theme/styles/utilities/index.css +0 -88
  85. package/types/ojiepermana-angular-internal.d.ts +0 -89
  86. package/types/ojiepermana-angular-navigation-horizontal.d.ts +0 -77
  87. package/types/ojiepermana-angular-navigation-vertical.d.ts +0 -260
  88. package/types/ojiepermana-angular-shell.d.ts +0 -12
  89. package/types/ojiepermana-angular-theme-component.d.ts +0 -46
  90. package/types/ojiepermana-angular-theme-directive.d.ts +0 -10
  91. package/types/ojiepermana-angular-theme-service.d.ts +0 -68
@@ -1,241 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, DestroyRef, PLATFORM_ID, signal, computed, effect, Injectable, isDevMode, makeEnvironmentProviders } from '@angular/core';
3
- import { DOCUMENT, isPlatformBrowser } from '@angular/common';
4
- import { LocalStorageStateAdapter } from '@ojiepermana/angular/internal';
5
-
6
- const DEFAULT_NG_THEME_CONFIG = {
7
- defaultScheme: 'system',
8
- defaultColor: 'brand',
9
- defaultStyle: 'flat',
10
- };
11
- const NG_THEME_CONFIG = new InjectionToken('NG_THEME_CONFIG', {
12
- providedIn: 'root',
13
- factory: () => ({ ...DEFAULT_NG_THEME_CONFIG }),
14
- });
15
-
16
- const THEME_SCHEMES = ['light', 'dark', 'system'];
17
- const THEME_COLORS = ['brand', 'blue', 'green', 'red', 'cyan', 'purple', 'orange'];
18
- const THEME_STYLES = ['flat', 'glass'];
19
- const THEME_SCHEME_SET = new Set(THEME_SCHEMES);
20
- const THEME_COLOR_SET = new Set(THEME_COLORS);
21
- const THEME_STYLE_SET = new Set(THEME_STYLES);
22
- function isThemeScheme(value) {
23
- return typeof value === 'string' && THEME_SCHEME_SET.has(value);
24
- }
25
- function isThemeColor(value) {
26
- return typeof value === 'string' && THEME_COLOR_SET.has(value);
27
- }
28
- function isThemeStyle(value) {
29
- return typeof value === 'string' && THEME_STYLE_SET.has(value);
30
- }
31
-
32
- const THEME_COLOR_OPTIONS = [
33
- { value: 'brand', label: 'Brand' },
34
- { value: 'blue', label: 'Blue' },
35
- { value: 'green', label: 'Green' },
36
- { value: 'red', label: 'Red' },
37
- { value: 'cyan', label: 'Cyan' },
38
- { value: 'purple', label: 'Purple' },
39
- { value: 'orange', label: 'Orange' },
40
- ];
41
- function createThemeColorOptions(allowedColors, colorLabels) {
42
- const allowedSet = allowedColors ? new Set(allowedColors) : null;
43
- return THEME_COLOR_OPTIONS.filter((option) => !allowedSet || allowedSet.has(option.value)).map((option) => ({
44
- value: option.value,
45
- label: colorLabels?.[option.value] ?? option.label,
46
- }));
47
- }
48
- const STORAGE_KEYS = {
49
- scheme: 'theme-scheme',
50
- color: 'theme-color',
51
- style: 'theme-style',
52
- };
53
- const LEGACY_STORAGE_PREFIX = 'ng-theme:v2';
54
- class ThemeService {
55
- config = inject(NG_THEME_CONFIG);
56
- document = inject(DOCUMENT);
57
- destroyRef = inject(DestroyRef);
58
- isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
59
- storage = new LocalStorageStateAdapter({
60
- isBrowser: this.isBrowser,
61
- storage: this.document.defaultView?.localStorage ?? null,
62
- keys: STORAGE_KEYS,
63
- legacyPrefix: LEGACY_STORAGE_PREFIX,
64
- });
65
- mediaQuery = this.isBrowser
66
- ? typeof this.document.defaultView?.matchMedia === 'function'
67
- ? this.document.defaultView.matchMedia('(prefers-color-scheme: dark)')
68
- : null
69
- : null;
70
- systemPrefersDark = signal(this.mediaQuery?.matches ?? false, ...(ngDevMode ? [{ debugName: "systemPrefersDark" }] : /* istanbul ignore next */ []));
71
- availableColorOptions = createThemeColorOptions(this.config.colors, this.config.colorLabels);
72
- scheme = signal(this.storage.read('scheme', this.config.defaultScheme, isThemeScheme), ...(ngDevMode ? [{ debugName: "scheme" }] : /* istanbul ignore next */ []));
73
- color = signal(this.storage.read('color', this.config.defaultColor, isThemeColor), ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
74
- style = signal(this.storage.read('style', this.config.defaultStyle, isThemeStyle), ...(ngDevMode ? [{ debugName: "style" }] : /* istanbul ignore next */ []));
75
- colorOptions = computed(() => this.availableColorOptions, ...(ngDevMode ? [{ debugName: "colorOptions" }] : /* istanbul ignore next */ []));
76
- resolvedScheme = computed(() => {
77
- if (this.scheme() !== 'system')
78
- return this.scheme();
79
- return this.systemPrefersDark() ? 'dark' : 'light';
80
- }, ...(ngDevMode ? [{ debugName: "resolvedScheme" }] : /* istanbul ignore next */ []));
81
- constructor() {
82
- if (this.mediaQuery) {
83
- const syncSystemPreference = (event) => {
84
- this.systemPrefersDark.set(event.matches);
85
- };
86
- this.mediaQuery.addEventListener('change', syncSystemPreference);
87
- this.destroyRef.onDestroy(() => {
88
- this.mediaQuery?.removeEventListener('change', syncSystemPreference);
89
- });
90
- }
91
- effect(() => {
92
- if (this.isBrowser) {
93
- this.applyToDOM();
94
- }
95
- });
96
- }
97
- /**
98
- * Updates the selected theme scheme and persists the choice for future sessions.
99
- */
100
- setScheme(value) {
101
- this.storage.persist('scheme', value);
102
- this.scheme.set(value);
103
- }
104
- /**
105
- * Updates the active theme color when it is part of the configured preset list.
106
- */
107
- setColor(value) {
108
- if (!this.colorOptions().some((option) => option.value === value)) {
109
- return;
110
- }
111
- this.storage.persist('color', value);
112
- this.color.set(value);
113
- }
114
- /**
115
- * Updates the active style preset and persists it to local storage.
116
- */
117
- setStyle(value) {
118
- this.storage.persist('style', value);
119
- this.style.set(value);
120
- }
121
- /**
122
- * Cycles the scheme through light, dark, and system while keeping the DOM contract in sync.
123
- */
124
- toggleScheme() {
125
- const next = this.scheme() === 'light' ? 'dark' : this.scheme() === 'dark' ? 'system' : 'light';
126
- this.setScheme(next);
127
- }
128
- /**
129
- * Clears persisted theme state and restores the configured defaults for all theme axes.
130
- */
131
- reset() {
132
- this.storage.clear('scheme');
133
- this.storage.clear('color');
134
- this.storage.clear('style');
135
- this.scheme.set(this.config.defaultScheme);
136
- this.color.set(this.config.defaultColor);
137
- this.style.set(this.config.defaultStyle);
138
- }
139
- applyToDOM() {
140
- const element = this.document.documentElement;
141
- element.classList.toggle('dark', this.resolvedScheme() === 'dark');
142
- element.dataset['themeScheme'] = this.scheme();
143
- element.dataset['themeColor'] = this.color();
144
- element.dataset['themeStyle'] = this.style();
145
- element.style.colorScheme = this.resolvedScheme();
146
- }
147
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
148
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ThemeService, providedIn: 'root' });
149
- }
150
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ThemeService, decorators: [{
151
- type: Injectable,
152
- args: [{ providedIn: 'root' }]
153
- }], ctorParameters: () => [] });
154
-
155
- function warnInvalidThemeConfig(message) {
156
- if (isDevMode()) {
157
- console.warn(`[provideNgTheme] ${message}`);
158
- }
159
- }
160
- function normalizeThemeScheme(value) {
161
- if (typeof value === 'undefined' || isThemeScheme(value)) {
162
- return value ?? DEFAULT_NG_THEME_CONFIG.defaultScheme;
163
- }
164
- warnInvalidThemeConfig(`Ignoring invalid defaultScheme ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultScheme)}.`);
165
- return DEFAULT_NG_THEME_CONFIG.defaultScheme;
166
- }
167
- function normalizeThemeColor(value) {
168
- if (typeof value === 'undefined' || isThemeColor(value)) {
169
- return value ?? DEFAULT_NG_THEME_CONFIG.defaultColor;
170
- }
171
- warnInvalidThemeConfig(`Ignoring invalid defaultColor ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultColor)}.`);
172
- return DEFAULT_NG_THEME_CONFIG.defaultColor;
173
- }
174
- function normalizeThemeStyle(value) {
175
- if (typeof value === 'undefined' || isThemeStyle(value)) {
176
- return value ?? DEFAULT_NG_THEME_CONFIG.defaultStyle;
177
- }
178
- warnInvalidThemeConfig(`Ignoring invalid defaultStyle ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultStyle)}.`);
179
- return DEFAULT_NG_THEME_CONFIG.defaultStyle;
180
- }
181
- function normalizeThemeColors(value) {
182
- if (typeof value === 'undefined') {
183
- return undefined;
184
- }
185
- if (!Array.isArray(value)) {
186
- warnInvalidThemeConfig('Ignoring invalid colors config because it is not an array.');
187
- return undefined;
188
- }
189
- const normalizedColors = Array.from(new Set(value.filter(isThemeColor)));
190
- if (normalizedColors.length !== value.length) {
191
- warnInvalidThemeConfig('Ignoring unsupported values in colors config.');
192
- }
193
- return normalizedColors.length > 0 ? normalizedColors : undefined;
194
- }
195
- function normalizeThemeColorLabels(value) {
196
- if (typeof value === 'undefined') {
197
- return undefined;
198
- }
199
- if (!value || Array.isArray(value) || typeof value !== 'object') {
200
- warnInvalidThemeConfig('Ignoring invalid colorLabels config because it is not an object map.');
201
- return undefined;
202
- }
203
- const entries = Object.entries(value);
204
- const normalizedEntries = entries.flatMap(([color, label]) => {
205
- if (isThemeColor(color) && typeof label === 'string' && label.trim().length > 0) {
206
- return [[color, label.trim()]];
207
- }
208
- return [];
209
- });
210
- if (normalizedEntries.length !== entries.length) {
211
- warnInvalidThemeConfig('Ignoring unsupported entries in colorLabels config.');
212
- }
213
- return normalizedEntries.length > 0 ? Object.fromEntries(normalizedEntries) : undefined;
214
- }
215
- function normalizeThemeConfig(config) {
216
- const colors = normalizeThemeColors(config.colors);
217
- const colorLabels = normalizeThemeColorLabels(config.colorLabels);
218
- let defaultColor = normalizeThemeColor(config.defaultColor);
219
- if (colors && !colors.includes(defaultColor)) {
220
- warnInvalidThemeConfig(`Adjusting defaultColor ${JSON.stringify(defaultColor)} to ${JSON.stringify(colors[0])} so it stays within the configured colors list.`);
221
- defaultColor = colors[0];
222
- }
223
- return {
224
- ...DEFAULT_NG_THEME_CONFIG,
225
- defaultScheme: normalizeThemeScheme(config.defaultScheme),
226
- defaultColor,
227
- defaultStyle: normalizeThemeStyle(config.defaultStyle),
228
- ...(colors ? { colors } : {}),
229
- ...(colorLabels ? { colorLabels } : {}),
230
- };
231
- }
232
- function provideNgTheme(config = {}) {
233
- return makeEnvironmentProviders([{ provide: NG_THEME_CONFIG, useValue: normalizeThemeConfig(config) }]);
234
- }
235
-
236
- /**
237
- * Generated bundle index. Do not edit.
238
- */
239
-
240
- export { NG_THEME_CONFIG, ThemeService, provideNgTheme };
241
- //# sourceMappingURL=ojiepermana-angular-theme-service.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ojiepermana-angular-theme-service.mjs","sources":["../../../projects/library/theme/service/src/theme.token.ts","../../../projects/library/theme/service/src/theme.types.ts","../../../projects/library/theme/service/src/theme.service.ts","../../../projects/library/theme/service/src/theme.provider.ts","../../../projects/library/theme/service/ojiepermana-angular-theme-service.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { NgThemeConfig } from './theme.types';\n\nexport const DEFAULT_NG_THEME_CONFIG: NgThemeConfig = {\n defaultScheme: 'system',\n defaultColor: 'brand',\n defaultStyle: 'flat',\n};\n\nexport const NG_THEME_CONFIG = new InjectionToken<NgThemeConfig>('NG_THEME_CONFIG', {\n providedIn: 'root',\n factory: () => ({ ...DEFAULT_NG_THEME_CONFIG }),\n});\n","export const THEME_SCHEMES = ['light', 'dark', 'system'] as const;\nexport type ThemeScheme = (typeof THEME_SCHEMES)[number];\n\nexport const THEME_COLORS = ['brand', 'blue', 'green', 'red', 'cyan', 'purple', 'orange'] as const;\nexport type ThemeColor = (typeof THEME_COLORS)[number];\n\nexport const THEME_STYLES = ['flat', 'glass'] as const;\nexport type ThemeStyle = (typeof THEME_STYLES)[number];\n\nconst THEME_SCHEME_SET = new Set<ThemeScheme>(THEME_SCHEMES);\nconst THEME_COLOR_SET = new Set<ThemeColor>(THEME_COLORS);\nconst THEME_STYLE_SET = new Set<ThemeStyle>(THEME_STYLES);\n\nexport function isThemeScheme(value: unknown): value is ThemeScheme {\n return typeof value === 'string' && THEME_SCHEME_SET.has(value as ThemeScheme);\n}\n\nexport function isThemeColor(value: unknown): value is ThemeColor {\n return typeof value === 'string' && THEME_COLOR_SET.has(value as ThemeColor);\n}\n\nexport function isThemeStyle(value: unknown): value is ThemeStyle {\n return typeof value === 'string' && THEME_STYLE_SET.has(value as ThemeStyle);\n}\n\nexport interface ThemeColorOption {\n readonly value: ThemeColor;\n readonly label: string;\n}\n\nexport type ThemeColorLabels = Partial<Record<ThemeColor, string>>;\n\nexport interface NgThemeConfig {\n defaultScheme: ThemeScheme;\n defaultColor: ThemeColor;\n defaultStyle: ThemeStyle;\n colors?: readonly ThemeColor[];\n colorLabels?: ThemeColorLabels;\n}\n","import { DestroyRef, Injectable, PLATFORM_ID, computed, effect, inject, signal } from '@angular/core';\nimport { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { LocalStorageStateAdapter } from '@ojiepermana/angular/internal';\nimport { NG_THEME_CONFIG } from './theme.token';\nimport {\n isThemeColor,\n isThemeScheme,\n isThemeStyle,\n NgThemeConfig,\n ThemeStyle,\n ThemeColor,\n ThemeColorLabels,\n ThemeColorOption,\n ThemeScheme,\n} from './theme.types';\n\nconst THEME_COLOR_OPTIONS: readonly ThemeColorOption[] = [\n { value: 'brand', label: 'Brand' },\n { value: 'blue', label: 'Blue' },\n { value: 'green', label: 'Green' },\n { value: 'red', label: 'Red' },\n { value: 'cyan', label: 'Cyan' },\n { value: 'purple', label: 'Purple' },\n { value: 'orange', label: 'Orange' },\n] as const;\n\nfunction createThemeColorOptions(\n allowedColors: readonly ThemeColor[] | undefined,\n colorLabels: ThemeColorLabels | undefined,\n): readonly ThemeColorOption[] {\n const allowedSet = allowedColors ? new Set(allowedColors) : null;\n\n return THEME_COLOR_OPTIONS.filter((option) => !allowedSet || allowedSet.has(option.value)).map((option) => ({\n value: option.value,\n label: colorLabels?.[option.value] ?? option.label,\n }));\n}\n\nconst STORAGE_KEYS = {\n scheme: 'theme-scheme',\n color: 'theme-color',\n style: 'theme-style',\n} as const;\n\ntype ThemeStorageAxis = keyof typeof STORAGE_KEYS;\n\nconst LEGACY_STORAGE_PREFIX = 'ng-theme:v2';\n\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly config = inject(NG_THEME_CONFIG);\n private readonly document = inject(DOCUMENT);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly storage = new LocalStorageStateAdapter<ThemeStorageAxis>({\n isBrowser: this.isBrowser,\n storage: this.document.defaultView?.localStorage ?? null,\n keys: STORAGE_KEYS,\n legacyPrefix: LEGACY_STORAGE_PREFIX,\n });\n private readonly mediaQuery = this.isBrowser\n ? typeof this.document.defaultView?.matchMedia === 'function'\n ? this.document.defaultView.matchMedia('(prefers-color-scheme: dark)')\n : null\n : null;\n private readonly systemPrefersDark = signal(this.mediaQuery?.matches ?? false);\n private readonly availableColorOptions = createThemeColorOptions(this.config.colors, this.config.colorLabels);\n\n readonly scheme = signal<ThemeScheme>(this.storage.read('scheme', this.config.defaultScheme, isThemeScheme));\n readonly color = signal<ThemeColor>(this.storage.read('color', this.config.defaultColor, isThemeColor));\n readonly style = signal<ThemeStyle>(this.storage.read('style', this.config.defaultStyle, isThemeStyle));\n readonly colorOptions = computed<readonly ThemeColorOption[]>(() => this.availableColorOptions);\n\n readonly resolvedScheme = computed<'light' | 'dark'>(() => {\n if (this.scheme() !== 'system') return this.scheme() as 'light' | 'dark';\n return this.systemPrefersDark() ? 'dark' : 'light';\n });\n\n constructor() {\n if (this.mediaQuery) {\n const syncSystemPreference = (event: MediaQueryListEvent): void => {\n this.systemPrefersDark.set(event.matches);\n };\n\n this.mediaQuery.addEventListener('change', syncSystemPreference);\n this.destroyRef.onDestroy(() => {\n this.mediaQuery?.removeEventListener('change', syncSystemPreference);\n });\n }\n\n effect(() => {\n if (this.isBrowser) {\n this.applyToDOM();\n }\n });\n }\n\n /**\n * Updates the selected theme scheme and persists the choice for future sessions.\n */\n setScheme(value: ThemeScheme): void {\n this.storage.persist('scheme', value);\n this.scheme.set(value);\n }\n\n /**\n * Updates the active theme color when it is part of the configured preset list.\n */\n setColor(value: ThemeColor): void {\n if (!this.colorOptions().some((option) => option.value === value)) {\n return;\n }\n\n this.storage.persist('color', value);\n this.color.set(value);\n }\n\n /**\n * Updates the active style preset and persists it to local storage.\n */\n setStyle(value: ThemeStyle): void {\n this.storage.persist('style', value);\n this.style.set(value);\n }\n\n /**\n * Cycles the scheme through light, dark, and system while keeping the DOM contract in sync.\n */\n toggleScheme(): void {\n const next: ThemeScheme = this.scheme() === 'light' ? 'dark' : this.scheme() === 'dark' ? 'system' : 'light';\n this.setScheme(next);\n }\n\n /**\n * Clears persisted theme state and restores the configured defaults for all theme axes.\n */\n reset(): void {\n this.storage.clear('scheme');\n this.storage.clear('color');\n this.storage.clear('style');\n this.scheme.set(this.config.defaultScheme);\n this.color.set(this.config.defaultColor);\n this.style.set(this.config.defaultStyle);\n }\n\n private applyToDOM(): void {\n const element = this.document.documentElement;\n\n element.classList.toggle('dark', this.resolvedScheme() === 'dark');\n element.dataset['themeScheme'] = this.scheme();\n element.dataset['themeColor'] = this.color();\n element.dataset['themeStyle'] = this.style();\n element.style.colorScheme = this.resolvedScheme();\n }\n}\n","import { EnvironmentProviders, isDevMode, makeEnvironmentProviders } from '@angular/core';\nimport { DEFAULT_NG_THEME_CONFIG, NG_THEME_CONFIG } from './theme.token';\nimport {\n isThemeColor,\n isThemeScheme,\n isThemeStyle,\n NgThemeConfig,\n ThemeColor,\n ThemeColorLabels,\n ThemeScheme,\n ThemeStyle,\n} from './theme.types';\n\nfunction warnInvalidThemeConfig(message: string): void {\n if (isDevMode()) {\n console.warn(`[provideNgTheme] ${message}`);\n }\n}\n\nfunction normalizeThemeScheme(value: unknown): ThemeScheme {\n if (typeof value === 'undefined' || isThemeScheme(value)) {\n return value ?? DEFAULT_NG_THEME_CONFIG.defaultScheme;\n }\n\n warnInvalidThemeConfig(\n `Ignoring invalid defaultScheme ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultScheme)}.`,\n );\n\n return DEFAULT_NG_THEME_CONFIG.defaultScheme;\n}\n\nfunction normalizeThemeColor(value: unknown): ThemeColor {\n if (typeof value === 'undefined' || isThemeColor(value)) {\n return value ?? DEFAULT_NG_THEME_CONFIG.defaultColor;\n }\n\n warnInvalidThemeConfig(\n `Ignoring invalid defaultColor ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultColor)}.`,\n );\n\n return DEFAULT_NG_THEME_CONFIG.defaultColor;\n}\n\nfunction normalizeThemeStyle(value: unknown): ThemeStyle {\n if (typeof value === 'undefined' || isThemeStyle(value)) {\n return value ?? DEFAULT_NG_THEME_CONFIG.defaultStyle;\n }\n\n warnInvalidThemeConfig(\n `Ignoring invalid defaultStyle ${JSON.stringify(value)}. Falling back to ${JSON.stringify(DEFAULT_NG_THEME_CONFIG.defaultStyle)}.`,\n );\n\n return DEFAULT_NG_THEME_CONFIG.defaultStyle;\n}\n\nfunction normalizeThemeColors(value: unknown): readonly ThemeColor[] | undefined {\n if (typeof value === 'undefined') {\n return undefined;\n }\n\n if (!Array.isArray(value)) {\n warnInvalidThemeConfig('Ignoring invalid colors config because it is not an array.');\n return undefined;\n }\n\n const normalizedColors = Array.from(new Set(value.filter(isThemeColor)));\n\n if (normalizedColors.length !== value.length) {\n warnInvalidThemeConfig('Ignoring unsupported values in colors config.');\n }\n\n return normalizedColors.length > 0 ? normalizedColors : undefined;\n}\n\nfunction normalizeThemeColorLabels(value: unknown): ThemeColorLabels | undefined {\n if (typeof value === 'undefined') {\n return undefined;\n }\n\n if (!value || Array.isArray(value) || typeof value !== 'object') {\n warnInvalidThemeConfig('Ignoring invalid colorLabels config because it is not an object map.');\n return undefined;\n }\n\n const entries = Object.entries(value);\n const normalizedEntries = entries.flatMap(([color, label]) => {\n if (isThemeColor(color) && typeof label === 'string' && label.trim().length > 0) {\n return [[color, label.trim()] as const];\n }\n\n return [];\n });\n\n if (normalizedEntries.length !== entries.length) {\n warnInvalidThemeConfig('Ignoring unsupported entries in colorLabels config.');\n }\n\n return normalizedEntries.length > 0 ? (Object.fromEntries(normalizedEntries) as ThemeColorLabels) : undefined;\n}\n\nfunction normalizeThemeConfig(config: Partial<NgThemeConfig>): NgThemeConfig {\n const colors = normalizeThemeColors(config.colors);\n const colorLabels = normalizeThemeColorLabels(config.colorLabels);\n let defaultColor = normalizeThemeColor(config.defaultColor);\n\n if (colors && !colors.includes(defaultColor)) {\n warnInvalidThemeConfig(\n `Adjusting defaultColor ${JSON.stringify(defaultColor)} to ${JSON.stringify(colors[0])} so it stays within the configured colors list.`,\n );\n defaultColor = colors[0];\n }\n\n return {\n ...DEFAULT_NG_THEME_CONFIG,\n defaultScheme: normalizeThemeScheme(config.defaultScheme),\n defaultColor,\n defaultStyle: normalizeThemeStyle(config.defaultStyle),\n ...(colors ? { colors } : {}),\n ...(colorLabels ? { colorLabels } : {}),\n };\n}\n\nexport function provideNgTheme(config: Partial<NgThemeConfig> = {}): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: NG_THEME_CONFIG, useValue: normalizeThemeConfig(config) }]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/layout/README.md DELETED
@@ -1,144 +0,0 @@
1
- # Layout Library
2
-
3
- Runtime layout state, shell components, layout controls, and shell selectors for `@ojiepermana/angular/layout`.
4
-
5
- ## Package Shape
6
-
7
- Import the public API from:
8
-
9
- - `@ojiepermana/angular/layout`
10
-
11
- If you want one convenience provider that wires layout and theme together, use `@ojiepermana/angular/shell`.
12
-
13
- For styles in consumer applications, use `@ojiepermana/angular/styles/index.css`.
14
- If a consumer wants the library's optional application-level reset helpers, they can additionally import `@ojiepermana/angular/styles/resets.css`.
15
-
16
- ## What This Library Owns
17
-
18
- - Global layout state with Angular signals through `LayoutService`
19
- - Layout runtime DOM contract on `document.documentElement`
20
- - Optional subtree mirroring through `LayoutHostDirective`
21
- - Reusable vertical and horizontal shell components
22
- - Standalone layout controls for mode and container width
23
- - Layout-owned shell selectors and layout state selectors
24
-
25
- ## Runtime Contract
26
-
27
- When `LayoutService` is active, it writes the current state to `document.documentElement`.
28
-
29
- - `data-layout-mode` stores the active shell mode.
30
- - `data-layout-container` stores the active width mode.
31
-
32
- `LayoutHostDirective` mirrors the same contract onto any host element with `ngtLayoutHost`.
33
-
34
- ## Supported Values
35
-
36
- - `LayoutMode`: `vertical`, `horizontal`, `empty`
37
- - `LayoutContainer`: `full`, `boxed`
38
-
39
- ## Public API
40
-
41
- Import from `@ojiepermana/angular/layout`.
42
-
43
- - `LayoutService`
44
- - `provideNgLayout`
45
- - `NG_LAYOUT_CONFIG`
46
- - `LayoutMode`
47
- - `LayoutContainer`
48
- - `NgLayoutConfig`
49
- - `LayoutHostDirective`
50
- - `LayoutVerticalComponent`
51
- - `LayoutHorizontalComponent`
52
- - `LayoutContainerSwitcherComponent`
53
- - `LayoutModeSwitcherComponent`
54
-
55
- `provideNgLayout()` currently defaults to:
56
-
57
- - `defaultMode: 'vertical'`
58
- - `defaultContainer: 'full'`
59
-
60
- Persistence keys are fixed by the runtime. Deprecated config fields such as `storageKey` and `storageVersion` have been removed from `NgLayoutConfig`.
61
-
62
- `LayoutService` also exposes `reset()` to clear persisted layout state and restore the configured defaults.
63
-
64
- `LayoutModeSwitcherComponent` intentionally exposes only `vertical` and `horizontal`. The `empty` mode remains programmatic so consuming applications can opt into a content-only shell state without presenting it as a primary end-user toggle.
65
-
66
- ## Styles
67
-
68
- The layout stylesheet source is `projects/library/layout/styles/index.css` inside this workspace.
69
-
70
- It owns the `data-layout-*` selectors and imports the mode-scoped shell styles.
71
- Layout-wide axis selectors such as `data-layout-container` and `data-layout-mode='empty'` stay in `projects/library/layout/styles/index.css`, while the flat shell rules now live in `projects/library/layout/styles/horizontal/flat.css` and `projects/library/layout/styles/vertical/flat.css`.
72
-
73
- Layout styles consume theme tokens. For application usage, prefer the aggregate stylesheet entry at `projects/library/styles/index.css` in this workspace or `@ojiepermana/angular/styles/index.css` from the published package.
74
- The shared bundle now includes reduced-motion-aware transitions for shell chrome colors, shadows, and radii while keeping structural mode changes immediate to avoid layout jank.
75
-
76
- 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.
77
-
78
- Internally, the shell templates now prefer `<shell-content>` instead of the deprecated HTML `<content>` element name. A legacy `content` selector remains supported for compatibility inside the library's internal shell marker directives.
79
-
80
- ## SSR Notes
81
-
82
- - Providers can be registered on the server safely.
83
- - Layout DOM writes and `localStorage` persistence remain no-op until the browser runtime is available.
84
- - `empty` mode can still be set programmatically on the server or client; the switcher simply does not render it as a menu choice.
85
-
86
- ## Troubleshooting
87
-
88
- - If layout state does not appear to update, verify that the aggregate stylesheet bundle is imported and that the consuming shell actually renders `vertical` or `horizontal`.
89
- - If a consuming application needs a content-only shell, set `LayoutService.setMode('empty')` or configure `defaultMode: 'empty'`; this is supported even though the switcher UI does not display that option.
90
-
91
- ## Usage
92
-
93
- ```ts
94
- import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
95
- import { provideRouter } from '@angular/router';
96
- import { provideNgLayout } from '@ojiepermana/angular/layout';
97
- import { provideNgTheme } from '@ojiepermana/angular/theme/service';
98
-
99
- import { routes } from './app.routes';
100
-
101
- export const appConfig: ApplicationConfig = {
102
- providers: [
103
- provideBrowserGlobalErrorListeners(),
104
- provideRouter(routes),
105
- provideNgTheme(),
106
- provideNgLayout({ defaultMode: 'vertical', defaultContainer: 'boxed' }),
107
- ],
108
- };
109
- ```
110
-
111
- ```ts
112
- import { ChangeDetectionStrategy, Component } from '@angular/core';
113
- import {
114
- LayoutContainerSwitcherComponent,
115
- LayoutModeSwitcherComponent,
116
- LayoutVerticalComponent,
117
- } from '@ojiepermana/angular/layout';
118
-
119
- @Component({
120
- selector: 'app-shell',
121
- imports: [LayoutContainerSwitcherComponent, LayoutModeSwitcherComponent, LayoutVerticalComponent],
122
- template: `
123
- <vertical>
124
- <nav navigation class="flex h-full w-full flex-col gap-3 px-4 py-5">
125
- <div class="flex items-center gap-1">
126
- <layout-mode-switcher />
127
- <layout-container-switcher />
128
- </div>
129
- </nav>
130
- </vertical>
131
- `,
132
- changeDetection: ChangeDetectionStrategy.OnPush,
133
- })
134
- export class AppShellComponent {}
135
- ```
136
-
137
- ## Persistence
138
-
139
- Layout state is persisted in `localStorage` using these flat keys:
140
-
141
- - `layout-mode`
142
- - `layout-container`
143
-
144
- Legacy `ng-theme:v2:layout-mode` and `ng-theme:v2:layout-container` entries are migrated automatically when they are read.
@@ -1,215 +0,0 @@
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, and `NavigationService`.
8
- - `@ojiepermana/angular/navigation/vertical` exposes the vertical navigation container variants and vertical item components.
9
- - `@ojiepermana/angular/navigation/horizontal` exposes the horizontal navigation container 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
- ## Quick Start
20
-
21
- ### 1. Define a navigation tree
22
-
23
- ```ts
24
- import { NavigationItem } from '@ojiepermana/angular/navigation';
25
-
26
- export const appNavigation = [
27
- {
28
- id: 'dashboard',
29
- title: 'Dashboard',
30
- type: 'basic',
31
- icon: 'layout-dashboard',
32
- link: '/dashboard',
33
- },
34
- {
35
- id: 'workspace',
36
- title: 'Workspace',
37
- type: 'collapsable',
38
- icon: 'folders',
39
- children: [
40
- {
41
- id: 'workspace-overview',
42
- title: 'Overview',
43
- type: 'basic',
44
- link: '/workspace/overview',
45
- },
46
- {
47
- id: 'workspace-settings',
48
- title: 'Settings',
49
- type: 'basic',
50
- link: '/workspace/settings',
51
- badge: {
52
- title: 'Beta',
53
- classes: 'bg-primary text-primary-foreground',
54
- },
55
- },
56
- ],
57
- },
58
- ] satisfies NavigationItem[];
59
- ```
60
-
61
- ### 2. Render a vertical navigation
62
-
63
- ```ts
64
- import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
65
- import { NavigationItem } from '@ojiepermana/angular/navigation';
66
- import { VerticalNavigationDefaultComponent } from '@ojiepermana/angular/navigation/vertical';
67
-
68
- import { appNavigation } from './app.navigation';
69
-
70
- @Component({
71
- selector: 'app-shell-navigation',
72
- imports: [VerticalNavigationDefaultComponent],
73
- template: `
74
- <vertical-navigation [navigation]="navigation()" [opened]="true" mode="side" position="left"></vertical-navigation>
75
- `,
76
- changeDetection: ChangeDetectionStrategy.OnPush,
77
- })
78
- export class ShellNavigationComponent {
79
- readonly navigation = signal<NavigationItem[]>(appNavigation);
80
- }
81
- ```
82
-
83
- Vertical variants use these selectors:
84
-
85
- - `<vertical-navigation>` for the default width and density.
86
- - `<vertical-navigation-compact>` for a narrower layout.
87
- - `<vertical-navigation-dense>` for a denser layout.
88
- - `<vertical-navigation-thin>` for the thin icon-first layout.
89
-
90
- 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.
91
-
92
- ### 3. Render a horizontal navigation
93
-
94
- ```ts
95
- import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
96
- import { NavigationItem } from '@ojiepermana/angular/navigation';
97
- import { HorizontalNavigation } from '@ojiepermana/angular/navigation/horizontal';
98
-
99
- import { appNavigation } from './app.navigation';
100
-
101
- @Component({
102
- selector: 'app-top-navigation',
103
- imports: [HorizontalNavigation],
104
- template: `
105
- <horizontal-navigation [navigation]="navigation()" (itemClicked)="onItemClicked($event)"></horizontal-navigation>
106
- `,
107
- changeDetection: ChangeDetectionStrategy.OnPush,
108
- })
109
- export class TopNavigationComponent {
110
- readonly navigation = signal<NavigationItem[]>(appNavigation);
111
-
112
- onItemClicked(item: NavigationItem): void {
113
- console.log('Navigation item clicked:', item.id);
114
- }
115
- }
116
- ```
117
-
118
- ### 4. Optionally mirror the tree into `NavigationService`
119
-
120
- `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.
121
-
122
- ```ts
123
- import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
124
- import { NavigationItem, NavigationService } from '@ojiepermana/angular/navigation';
125
-
126
- import { appNavigation } from './app.navigation';
127
-
128
- @Component({
129
- selector: 'app-navigation-store',
130
- template: '',
131
- changeDetection: ChangeDetectionStrategy.OnPush,
132
- })
133
- export class NavigationStoreComponent {
134
- private readonly navigationService = inject(NavigationService);
135
- readonly navigation = signal<NavigationItem[]>(appNavigation);
136
-
137
- ngOnInit(): void {
138
- this.navigationService.storeNavigation(this.navigation());
139
- }
140
- }
141
- ```
142
-
143
- ## Navigation Item Model
144
-
145
- Every tree node is a `NavigationItem`. The public union is split across these item types:
146
-
147
- - `basic` is a leaf item that can route, open an external link, or run an `action` callback.
148
- - `aside` is a routable branch rendered through the vertical aside panel pattern.
149
- - `collapsable` is a branch that expands and collapses inline.
150
- - `group` is a non-routable section label with children.
151
- - `divider` renders a visual separator.
152
- - `spacer` renders flexible empty space.
153
-
154
- Shared fields available on most item types:
155
-
156
- - `id`, `title`, `subtitle`, `tooltip`, `icon`, `disabled`, and `meta`.
157
- - `classes.wrapper`, `classes.icon`, `classes.title`, and `classes.subtitle` for per-item styling hooks.
158
- - `badge.title` and `badge.classes` for optional item badges.
159
- - `isHidden` for conditional visibility.
160
-
161
- Routable item fields available on `basic`, `aside`, and `collapsable`:
162
-
163
- - `link`, `fragment`, `preserveFragment`, `queryParams`, and `queryParamsHandling`.
164
- - `externalLink` and `target` for external navigation.
165
- - `exactMatch` and `isActiveMatchOptions` for route activity matching.
166
- - `action` for click callbacks.
167
-
168
- ## Navigation Service
169
-
170
- `NavigationService` is provided in root and exposes navigation state as signals plus a small lookup API.
171
-
172
- Readonly state:
173
-
174
- - `navigationItems`
175
- - `activeItemId`
176
- - `flatNavigation`
177
- - `expandedItemIds`
178
-
179
- Mutation and lookup methods:
180
-
181
- - `storeNavigation()` and `deleteNavigation()`
182
- - `setActiveItem()` and `clearActiveItem()`
183
- - `expandItem()`, `collapseItem()`, `toggleItemExpanded()`, and `clearExpandedItems()`
184
- - `getNavigation()`, `getActiveItem()`, `getFlatNavigation()`, `getItem()`, and `getItemParent()`
185
-
186
- ## Styling Notes
187
-
188
- - Pass Tailwind utility classes or other class names through the item `classes` and `badge.classes` fields when you need local visual overrides.
189
- - Icons are resolved from Lucide. Use names such as `layout-dashboard`, `folders`, `settings-2`, or valid Lucide aliases.
190
- - Active state depends on Angular Router. Use `exactMatch` or `isActiveMatchOptions` when the default subset matching is too broad.
191
-
192
- ## Troubleshooting
193
-
194
- ### Nothing renders
195
-
196
- - Confirm the component receives a non-empty `navigation` input.
197
- - If a horizontal navigation intentionally relies on service fallback, call `NavigationService.storeNavigation()` before it renders.
198
- - Check whether `isHidden` returns `true` for the affected items.
199
-
200
- ### Icons do not appear
201
-
202
- - Use Lucide icon names or aliases, not Material icon names.
203
- - Check the `icon` value on the affected item.
204
-
205
- ### Active state is wrong
206
-
207
- - Verify Router is configured and the application uses the expected route paths.
208
- - Tune `exactMatch` or `isActiveMatchOptions` for the affected items.
209
-
210
- ## Notes For Contributors
211
-
212
- - Keep `@ojiepermana/angular/navigation` focused on the item model, helpers, and `NavigationService`.
213
- - Keep render components in `@ojiepermana/angular/navigation/vertical` and `@ojiepermana/angular/navigation/horizontal`.
214
- - Move shared implementation helpers behind `@ojiepermana/angular/internal` instead of reaching across entry point boundaries with relative imports.
215
- - Treat `projects/library/navigation/shared` as a local compatibility layer for tests and source organization, not as consumer API.