@ojiepermana/angular 21.1.9 → 21.1.12

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.
@@ -300,10 +300,10 @@ class ThemeService {
300
300
  /* ignore */
301
301
  }
302
302
  }
303
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
304
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ThemeService, providedIn: 'root' });
303
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
304
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ThemeService, providedIn: 'root' });
305
305
  }
306
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ThemeService, decorators: [{
306
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ThemeService, decorators: [{
307
307
  type: Injectable,
308
308
  args: [{ providedIn: 'root' }]
309
309
  }], ctorParameters: () => [] });
@@ -1 +1 @@
1
- {"version":3,"file":"ojiepermana-angular-theme.mjs","sources":["../../../projects/angular/theme/src/lib/core/theme.tokens.ts","../../../projects/angular/theme/src/lib/core/theme.service.ts","../../../projects/angular/theme/src/lib/core/theme.provider.ts","../../../projects/angular/theme/public-api.ts","../../../projects/angular/theme/ojiepermana-angular-theme.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport const MODES = ['light', 'dark'] as const;\n\nexport type ThemeMode = (typeof MODES)[number];\n\nexport const COLOR_SCHEMES = ['light', 'dark', 'system'] as const;\n\nexport type ColorScheme = (typeof COLOR_SCHEMES)[number];\n\nexport const COLORS = ['blue', 'red', 'green', 'purple', 'amber'] as const;\n\nexport type ThemeColor = (typeof COLORS)[number];\n\nexport const STYLES = ['default', 'sharp', 'brutal', 'soft'] as const;\n\nexport type ThemeStyle = (typeof STYLES)[number];\n\nexport const BRANDS = ['etos'] as const;\n\nexport type ThemeBrand = (typeof BRANDS)[number];\n\nexport interface ThemeConfig {\n readonly mode: ThemeMode;\n readonly brand: ThemeBrand | null;\n readonly color: ThemeColor;\n readonly style: ThemeStyle;\n}\n\nexport interface MaterialThemeConfig {\n /** Initial mode preference. Supports `system` for first-visit OS detection. */\n readonly mode?: ColorScheme;\n /** Initial brand bundle. When set, it replaces the explicit color and style layers. */\n readonly brand?: ThemeBrand | null;\n /** Alias for `brand` to match the persisted `theme-brand` setting. */\n readonly 'theme-brand'?: ThemeBrand | null;\n /** Initial brand color layer. */\n readonly color?: ThemeColor;\n /** Initial style personality layer. */\n readonly style?: ThemeStyle;\n /** @deprecated Use `mode` instead. */\n readonly defaultMode?: ColorScheme;\n /** Default brand bundle. When set, it replaces the explicit color and style layers. */\n readonly defaultBrand?: ThemeBrand | null;\n /** @deprecated Use `color` instead. */\n readonly defaultColor?: ThemeColor;\n /** @deprecated Use `style` instead. */\n readonly defaultStyle?: ThemeStyle;\n /** @deprecated Use `defaultMode` instead. */\n readonly defaultScheme?: ColorScheme;\n /** @deprecated Use `defaultColor` instead. */\n readonly defaultTheme?: ThemeColor | string;\n /** @deprecated Use `modeStorageKey` instead. */\n readonly storageKey?: string | null;\n /** @deprecated Use `modeStorageKey` instead. */\n readonly schemeStorageKey?: string | null;\n /** @deprecated Use `colorStorageKey` instead. */\n readonly themeStorageKey?: string | null;\n /** localStorage key used to persist the mode preference. Set to `null` to disable persistence. */\n readonly modeStorageKey?: string | null;\n /** localStorage key used to persist the brand bundle. Set to `null` to disable persistence. */\n readonly brandStorageKey?: string | null;\n /** localStorage key used to persist the color layer. Set to `null` to disable persistence. */\n readonly colorStorageKey?: string | null;\n /** localStorage key used to persist the style layer. Set to `null` to disable persistence. */\n readonly styleStorageKey?: string | null;\n}\n\nexport interface ResolvedMaterialThemeConfig {\n readonly defaultMode: ColorScheme;\n readonly defaultBrand: ThemeBrand | null;\n readonly defaultColor: ThemeColor;\n readonly defaultStyle: ThemeStyle;\n readonly modeStorageKey: string | null;\n readonly brandStorageKey: string | null;\n readonly colorStorageKey: string | null;\n readonly styleStorageKey: string | null;\n}\n\nexport const MATERIAL_THEME_CONFIG = new InjectionToken<MaterialThemeConfig>('MATERIAL_THEME_CONFIG');\n\nexport const DEFAULT_MATERIAL_THEME_CONFIG: ResolvedMaterialThemeConfig = {\n defaultMode: 'light',\n defaultBrand: null,\n defaultColor: 'blue',\n defaultStyle: 'default',\n modeStorageKey: 'theme-mode',\n brandStorageKey: 'theme-brand',\n colorStorageKey: 'theme-color',\n styleStorageKey: 'theme-style',\n};\n\nexport function isColorScheme(value: string | null | undefined): value is ColorScheme {\n return COLOR_SCHEMES.some((scheme) => scheme === value);\n}\n\nexport function isThemeColor(value: string | null | undefined): value is ThemeColor {\n return COLORS.some((color) => color === value);\n}\n\nexport function isThemeStyle(value: string | null | undefined): value is ThemeStyle {\n return STYLES.some((style) => style === value);\n}\n\nexport function isThemeBrand(value: string | null | undefined): value is ThemeBrand {\n return BRANDS.some((brand) => brand === value);\n}\n","import { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Injectable, computed, effect, inject, signal } from '@angular/core';\nimport {\n COLOR_SCHEMES,\n DEFAULT_MATERIAL_THEME_CONFIG,\n MATERIAL_THEME_CONFIG,\n type ColorScheme,\n type ResolvedMaterialThemeConfig,\n type ThemeBrand,\n type ThemeColor,\n type ThemeConfig,\n type ThemeMode,\n type ThemeStyle,\n isThemeBrand,\n isColorScheme,\n isThemeColor,\n isThemeStyle,\n} from './theme.tokens';\n\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly document = inject(DOCUMENT);\n private readonly destroyRef = inject(DestroyRef);\n private readonly config = this.resolveConfig();\n private readonly initialBrand = this.readPersistedBrand() ?? this.config.defaultBrand;\n\n private readonly _modePreference = signal<ColorScheme>(this.readPersistedMode() ?? this.config.defaultMode);\n private readonly _brand = signal<ThemeBrand | null>(this.initialBrand);\n private readonly _color = signal<ThemeColor>(\n this.initialBrand ? this.config.defaultColor : (this.readPersistedColor() ?? this.config.defaultColor),\n );\n private readonly _style = signal<ThemeStyle>(\n this.initialBrand ? this.config.defaultStyle : (this.readPersistedStyle() ?? this.config.defaultStyle),\n );\n private readonly _systemPrefersDark = signal<boolean>(this.prefersDark());\n\n readonly scheme = this._modePreference.asReadonly();\n readonly brand = this._brand.asReadonly();\n readonly color = this._color.asReadonly();\n readonly theme = this._color.asReadonly();\n readonly style = this._style.asReadonly();\n readonly mode = computed<ThemeMode>(() => this.resolveMode(this._modePreference()));\n readonly snapshot = computed<ThemeConfig>(() => ({\n mode: this.mode(),\n brand: this._brand(),\n color: this._color(),\n style: this._style(),\n }));\n\n readonly isDark = computed(() => this.mode() === 'dark');\n\n constructor() {\n this.watchSystemScheme();\n\n effect(() => {\n const root = this.document.documentElement;\n const mode = this.mode();\n const brand = this._brand();\n const color = this._color();\n const style = this._style();\n\n root.dataset['mode'] = mode;\n root.dataset['theme'] = brand ?? color;\n root.classList.toggle('dark', mode === 'dark');\n\n this.persistMode(this._modePreference());\n\n if (brand) {\n root.setAttribute('theme-brand', brand);\n root.removeAttribute('theme-color');\n root.removeAttribute('theme-style');\n delete root.dataset['color'];\n delete root.dataset['style'];\n\n this.persistBrand(brand);\n this.clearPersistedColor();\n this.clearPersistedStyle();\n return;\n }\n\n root.removeAttribute('theme-brand');\n root.setAttribute('theme-color', color);\n root.setAttribute('theme-style', style);\n root.dataset['color'] = color;\n root.dataset['style'] = style;\n\n this.clearPersistedBrand();\n this.persistColor(color);\n this.persistStyle(style);\n });\n }\n\n setMode(mode: ThemeMode): void {\n this._modePreference.set(mode);\n }\n\n setScheme(scheme: ColorScheme): void {\n this._modePreference.set(scheme);\n }\n\n setBrand(brand: ThemeBrand | null): void {\n this._brand.set(brand);\n this._color.set(this.config.defaultColor);\n this._style.set(this.config.defaultStyle);\n }\n\n setColor(color: ThemeColor): void {\n if (this._brand()) {\n this._brand.set(null);\n }\n this._color.set(color);\n }\n\n setTheme(theme: ThemeColor | string): void {\n if (isThemeColor(theme)) {\n this.setColor(theme);\n }\n }\n\n setStyle(style: ThemeStyle): void {\n if (this._brand()) {\n this._brand.set(null);\n }\n this._style.set(style);\n }\n\n setAll(config: Partial<ThemeConfig> & { readonly scheme?: ColorScheme }): void {\n if (config.scheme) {\n this.setScheme(config.scheme);\n }\n if (config.mode) {\n this.setMode(config.mode);\n }\n if (config.brand !== undefined) {\n this.setBrand(config.brand);\n }\n if (config.brand === undefined || config.brand === null) {\n if (config.color) {\n this.setColor(config.color);\n }\n if (config.style) {\n this.setStyle(config.style);\n }\n }\n }\n\n toggleScheme(): void {\n this.toggleMode();\n }\n\n toggleMode(): void {\n this.setMode(this.mode() === 'dark' ? 'light' : 'dark');\n }\n\n reset(): void {\n this._modePreference.set(this.config.defaultMode);\n this._brand.set(this.config.defaultBrand);\n this._color.set(this.config.defaultColor);\n this._style.set(this.config.defaultStyle);\n }\n\n private resolveConfig(): ResolvedMaterialThemeConfig {\n const config = inject(MATERIAL_THEME_CONFIG, { optional: true }) ?? {};\n const configuredMode = config.mode ?? config.defaultMode ?? config.defaultScheme;\n const configuredBrand = config.brand ?? config['theme-brand'] ?? config.defaultBrand;\n const configuredColor = config.color ?? config.defaultColor ?? config.defaultTheme;\n const configuredStyle = config.style ?? config.defaultStyle;\n\n const defaultMode = isColorScheme(configuredMode) ? configuredMode : DEFAULT_MATERIAL_THEME_CONFIG.defaultMode;\n const defaultBrand = isThemeBrand(configuredBrand) ? configuredBrand : DEFAULT_MATERIAL_THEME_CONFIG.defaultBrand;\n const defaultColor = isThemeColor(configuredColor) ? configuredColor : DEFAULT_MATERIAL_THEME_CONFIG.defaultColor;\n const defaultStyle = isThemeStyle(configuredStyle) ? configuredStyle : DEFAULT_MATERIAL_THEME_CONFIG.defaultStyle;\n\n return {\n defaultMode,\n defaultBrand,\n defaultColor,\n defaultStyle,\n modeStorageKey:\n config.modeStorageKey ??\n config.schemeStorageKey ??\n config.storageKey ??\n DEFAULT_MATERIAL_THEME_CONFIG.modeStorageKey,\n brandStorageKey: config.brandStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.brandStorageKey,\n colorStorageKey:\n config.colorStorageKey ?? config.themeStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.colorStorageKey,\n styleStorageKey: config.styleStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.styleStorageKey,\n };\n }\n\n private resolveMode(mode: ColorScheme): ThemeMode {\n return mode === 'system' ? (this._systemPrefersDark() ? 'dark' : 'light') : mode;\n }\n\n private prefersDark(): boolean {\n const mql = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');\n return !!mql?.matches;\n }\n\n private watchSystemScheme(): void {\n const mql = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');\n if (!mql) return;\n\n const listener = (event: MediaQueryListEvent): void => {\n this._systemPrefersDark.set(event.matches);\n };\n mql.addEventListener('change', listener);\n this.destroyRef.onDestroy(() => mql.removeEventListener('change', listener));\n }\n\n private readPersistedMode(): ColorScheme | null {\n const key = this.config.modeStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isColorScheme(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedBrand(): ThemeBrand | null {\n const key = this.config.brandStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeBrand(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedColor(): ThemeColor | null {\n const key = this.config.colorStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeColor(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedStyle(): ThemeStyle | null {\n const key = this.config.styleStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeStyle(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private persistMode(mode: ColorScheme): void {\n const key = this.config.modeStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, mode);\n } catch {\n /* ignore */\n }\n }\n\n private persistBrand(brand: ThemeBrand): void {\n const key = this.config.brandStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, brand);\n } catch {\n /* ignore */\n }\n }\n\n private persistColor(color: ThemeColor): void {\n const key = this.config.colorStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, color);\n } catch {\n /* ignore */\n }\n }\n\n private persistStyle(style: ThemeStyle): void {\n const key = this.config.styleStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, style);\n } catch {\n /* ignore */\n }\n }\n\n private clearPersistedBrand(): void {\n this.clearPersistedItem(this.config.brandStorageKey);\n }\n\n private clearPersistedColor(): void {\n this.clearPersistedItem(this.config.colorStorageKey);\n }\n\n private clearPersistedStyle(): void {\n this.clearPersistedItem(this.config.styleStorageKey);\n }\n\n private clearPersistedItem(key: string | null): void {\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.removeItem(key);\n } catch {\n /* ignore */\n }\n }\n}\n","import {\n inject,\n type EnvironmentProviders,\n type Provider,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n} from '@angular/core';\nimport { MAT_RIPPLE_GLOBAL_OPTIONS } from '@angular/material/core';\nimport { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';\nimport { ThemeService } from './theme.service';\nimport { MATERIAL_THEME_CONFIG, type MaterialThemeConfig } from './theme.tokens';\n\n/**\n * Opaque feature unit consumed by {@link provideMaterialTheme}. Mirrors\n * Angular's router/http feature pattern so add-ons can be composed without\n * widening the primary provider signature.\n */\nexport interface MaterialThemeFeature {\n readonly providers: Provider[];\n}\n\n/**\n * Bootstrap the shared theme for any `@ojiepermana/angular/*` entry point.\n *\n * By default wires up the theme config token and eagerly initializes `ThemeService`\n * so root theme attributes are applied during bootstrap. Opt in\n * to Angular Material defaults (ripple / form-field) via\n * {@link withMaterialDefaults}.\n * Supports shorthand `mode`, `color`, and `style` config keys.\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideAnimations(),\n * provideMaterialTheme(\n * {\n * mode: 'system',\n * color: 'blue',\n * style: 'soft',\n * },\n * withMaterialDefaults(),\n * ),\n * ],\n * };\n */\nexport function provideMaterialTheme(\n config: MaterialThemeConfig = {},\n ...features: MaterialThemeFeature[]\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: MATERIAL_THEME_CONFIG, useValue: config },\n provideEnvironmentInitializer(() => {\n inject(ThemeService);\n }),\n ...features.flatMap((f) => f.providers),\n ]);\n}\n\n/**\n * Opt-in Angular Material defaults tuned for the shared theme layer:\n *\n * - Disables the global Material ripple.\n * - Forces `appearance: 'outline'` + `subscriptSizing: 'dynamic'` on every\n * `mat-form-field`.\n *\n * Only apply when your app actually renders Angular Material components.\n */\nexport function withMaterialDefaults(): MaterialThemeFeature {\n return {\n providers: [\n { provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: { disabled: true } },\n {\n provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,\n useValue: { appearance: 'outline', subscriptSizing: 'dynamic' },\n },\n ],\n };\n}\n","/*\n * Public API Surface of @ojiepermana/angular/theme\n *\n * The single source of truth for 3-layer design tokens, CSS variables,\n * and the `ThemeService` shared by every `@ojiepermana/angular/*` subpath\n * (shadcn, layout, navigation, ...).\n *\n * Usage:\n * // app.config.ts\n * import { provideMaterialTheme } from '@ojiepermana/angular/theme';\n *\n * // styles.css\n * @import '@ojiepermana/angular/theme/styles';\n * @import 'tailwindcss';\n */\n\nexport * from './src/lib/core/theme.tokens';\nexport * from './src/lib/core/theme.service';\nexport * from './src/lib/core/theme.provider';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ojiepermana-angular-theme.mjs","sources":["../../../projects/angular/theme/src/lib/core/theme.tokens.ts","../../../projects/angular/theme/src/lib/core/theme.service.ts","../../../projects/angular/theme/src/lib/core/theme.provider.ts","../../../projects/angular/theme/public-api.ts","../../../projects/angular/theme/ojiepermana-angular-theme.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport const MODES = ['light', 'dark'] as const;\n\nexport type ThemeMode = (typeof MODES)[number];\n\nexport const COLOR_SCHEMES = ['light', 'dark', 'system'] as const;\n\nexport type ColorScheme = (typeof COLOR_SCHEMES)[number];\n\nexport const COLORS = ['blue', 'red', 'green', 'purple', 'amber'] as const;\n\nexport type ThemeColor = (typeof COLORS)[number];\n\nexport const STYLES = ['default', 'sharp', 'brutal', 'soft'] as const;\n\nexport type ThemeStyle = (typeof STYLES)[number];\n\nexport const BRANDS = ['etos'] as const;\n\nexport type ThemeBrand = (typeof BRANDS)[number];\n\nexport interface ThemeConfig {\n readonly mode: ThemeMode;\n readonly brand: ThemeBrand | null;\n readonly color: ThemeColor;\n readonly style: ThemeStyle;\n}\n\nexport interface MaterialThemeConfig {\n /** Initial mode preference. Supports `system` for first-visit OS detection. */\n readonly mode?: ColorScheme;\n /** Initial brand bundle. When set, it replaces the explicit color and style layers. */\n readonly brand?: ThemeBrand | null;\n /** Alias for `brand` to match the persisted `theme-brand` setting. */\n readonly 'theme-brand'?: ThemeBrand | null;\n /** Initial brand color layer. */\n readonly color?: ThemeColor;\n /** Initial style personality layer. */\n readonly style?: ThemeStyle;\n /** @deprecated Use `mode` instead. */\n readonly defaultMode?: ColorScheme;\n /** Default brand bundle. When set, it replaces the explicit color and style layers. */\n readonly defaultBrand?: ThemeBrand | null;\n /** @deprecated Use `color` instead. */\n readonly defaultColor?: ThemeColor;\n /** @deprecated Use `style` instead. */\n readonly defaultStyle?: ThemeStyle;\n /** @deprecated Use `defaultMode` instead. */\n readonly defaultScheme?: ColorScheme;\n /** @deprecated Use `defaultColor` instead. */\n readonly defaultTheme?: ThemeColor | string;\n /** @deprecated Use `modeStorageKey` instead. */\n readonly storageKey?: string | null;\n /** @deprecated Use `modeStorageKey` instead. */\n readonly schemeStorageKey?: string | null;\n /** @deprecated Use `colorStorageKey` instead. */\n readonly themeStorageKey?: string | null;\n /** localStorage key used to persist the mode preference. Set to `null` to disable persistence. */\n readonly modeStorageKey?: string | null;\n /** localStorage key used to persist the brand bundle. Set to `null` to disable persistence. */\n readonly brandStorageKey?: string | null;\n /** localStorage key used to persist the color layer. Set to `null` to disable persistence. */\n readonly colorStorageKey?: string | null;\n /** localStorage key used to persist the style layer. Set to `null` to disable persistence. */\n readonly styleStorageKey?: string | null;\n}\n\nexport interface ResolvedMaterialThemeConfig {\n readonly defaultMode: ColorScheme;\n readonly defaultBrand: ThemeBrand | null;\n readonly defaultColor: ThemeColor;\n readonly defaultStyle: ThemeStyle;\n readonly modeStorageKey: string | null;\n readonly brandStorageKey: string | null;\n readonly colorStorageKey: string | null;\n readonly styleStorageKey: string | null;\n}\n\nexport const MATERIAL_THEME_CONFIG = new InjectionToken<MaterialThemeConfig>('MATERIAL_THEME_CONFIG');\n\nexport const DEFAULT_MATERIAL_THEME_CONFIG: ResolvedMaterialThemeConfig = {\n defaultMode: 'light',\n defaultBrand: null,\n defaultColor: 'blue',\n defaultStyle: 'default',\n modeStorageKey: 'theme-mode',\n brandStorageKey: 'theme-brand',\n colorStorageKey: 'theme-color',\n styleStorageKey: 'theme-style',\n};\n\nexport function isColorScheme(value: string | null | undefined): value is ColorScheme {\n return COLOR_SCHEMES.some((scheme) => scheme === value);\n}\n\nexport function isThemeColor(value: string | null | undefined): value is ThemeColor {\n return COLORS.some((color) => color === value);\n}\n\nexport function isThemeStyle(value: string | null | undefined): value is ThemeStyle {\n return STYLES.some((style) => style === value);\n}\n\nexport function isThemeBrand(value: string | null | undefined): value is ThemeBrand {\n return BRANDS.some((brand) => brand === value);\n}\n","import { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Injectable, computed, effect, inject, signal } from '@angular/core';\nimport {\n COLOR_SCHEMES,\n DEFAULT_MATERIAL_THEME_CONFIG,\n MATERIAL_THEME_CONFIG,\n type ColorScheme,\n type ResolvedMaterialThemeConfig,\n type ThemeBrand,\n type ThemeColor,\n type ThemeConfig,\n type ThemeMode,\n type ThemeStyle,\n isThemeBrand,\n isColorScheme,\n isThemeColor,\n isThemeStyle,\n} from './theme.tokens';\n\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly document = inject(DOCUMENT);\n private readonly destroyRef = inject(DestroyRef);\n private readonly config = this.resolveConfig();\n private readonly initialBrand = this.readPersistedBrand() ?? this.config.defaultBrand;\n\n private readonly _modePreference = signal<ColorScheme>(this.readPersistedMode() ?? this.config.defaultMode);\n private readonly _brand = signal<ThemeBrand | null>(this.initialBrand);\n private readonly _color = signal<ThemeColor>(\n this.initialBrand ? this.config.defaultColor : (this.readPersistedColor() ?? this.config.defaultColor),\n );\n private readonly _style = signal<ThemeStyle>(\n this.initialBrand ? this.config.defaultStyle : (this.readPersistedStyle() ?? this.config.defaultStyle),\n );\n private readonly _systemPrefersDark = signal<boolean>(this.prefersDark());\n\n readonly scheme = this._modePreference.asReadonly();\n readonly brand = this._brand.asReadonly();\n readonly color = this._color.asReadonly();\n readonly theme = this._color.asReadonly();\n readonly style = this._style.asReadonly();\n readonly mode = computed<ThemeMode>(() => this.resolveMode(this._modePreference()));\n readonly snapshot = computed<ThemeConfig>(() => ({\n mode: this.mode(),\n brand: this._brand(),\n color: this._color(),\n style: this._style(),\n }));\n\n readonly isDark = computed(() => this.mode() === 'dark');\n\n constructor() {\n this.watchSystemScheme();\n\n effect(() => {\n const root = this.document.documentElement;\n const mode = this.mode();\n const brand = this._brand();\n const color = this._color();\n const style = this._style();\n\n root.dataset['mode'] = mode;\n root.dataset['theme'] = brand ?? color;\n root.classList.toggle('dark', mode === 'dark');\n\n this.persistMode(this._modePreference());\n\n if (brand) {\n root.setAttribute('theme-brand', brand);\n root.removeAttribute('theme-color');\n root.removeAttribute('theme-style');\n delete root.dataset['color'];\n delete root.dataset['style'];\n\n this.persistBrand(brand);\n this.clearPersistedColor();\n this.clearPersistedStyle();\n return;\n }\n\n root.removeAttribute('theme-brand');\n root.setAttribute('theme-color', color);\n root.setAttribute('theme-style', style);\n root.dataset['color'] = color;\n root.dataset['style'] = style;\n\n this.clearPersistedBrand();\n this.persistColor(color);\n this.persistStyle(style);\n });\n }\n\n setMode(mode: ThemeMode): void {\n this._modePreference.set(mode);\n }\n\n setScheme(scheme: ColorScheme): void {\n this._modePreference.set(scheme);\n }\n\n setBrand(brand: ThemeBrand | null): void {\n this._brand.set(brand);\n this._color.set(this.config.defaultColor);\n this._style.set(this.config.defaultStyle);\n }\n\n setColor(color: ThemeColor): void {\n if (this._brand()) {\n this._brand.set(null);\n }\n this._color.set(color);\n }\n\n setTheme(theme: ThemeColor | string): void {\n if (isThemeColor(theme)) {\n this.setColor(theme);\n }\n }\n\n setStyle(style: ThemeStyle): void {\n if (this._brand()) {\n this._brand.set(null);\n }\n this._style.set(style);\n }\n\n setAll(config: Partial<ThemeConfig> & { readonly scheme?: ColorScheme }): void {\n if (config.scheme) {\n this.setScheme(config.scheme);\n }\n if (config.mode) {\n this.setMode(config.mode);\n }\n if (config.brand !== undefined) {\n this.setBrand(config.brand);\n }\n if (config.brand === undefined || config.brand === null) {\n if (config.color) {\n this.setColor(config.color);\n }\n if (config.style) {\n this.setStyle(config.style);\n }\n }\n }\n\n toggleScheme(): void {\n this.toggleMode();\n }\n\n toggleMode(): void {\n this.setMode(this.mode() === 'dark' ? 'light' : 'dark');\n }\n\n reset(): void {\n this._modePreference.set(this.config.defaultMode);\n this._brand.set(this.config.defaultBrand);\n this._color.set(this.config.defaultColor);\n this._style.set(this.config.defaultStyle);\n }\n\n private resolveConfig(): ResolvedMaterialThemeConfig {\n const config = inject(MATERIAL_THEME_CONFIG, { optional: true }) ?? {};\n const configuredMode = config.mode ?? config.defaultMode ?? config.defaultScheme;\n const configuredBrand = config.brand ?? config['theme-brand'] ?? config.defaultBrand;\n const configuredColor = config.color ?? config.defaultColor ?? config.defaultTheme;\n const configuredStyle = config.style ?? config.defaultStyle;\n\n const defaultMode = isColorScheme(configuredMode) ? configuredMode : DEFAULT_MATERIAL_THEME_CONFIG.defaultMode;\n const defaultBrand = isThemeBrand(configuredBrand) ? configuredBrand : DEFAULT_MATERIAL_THEME_CONFIG.defaultBrand;\n const defaultColor = isThemeColor(configuredColor) ? configuredColor : DEFAULT_MATERIAL_THEME_CONFIG.defaultColor;\n const defaultStyle = isThemeStyle(configuredStyle) ? configuredStyle : DEFAULT_MATERIAL_THEME_CONFIG.defaultStyle;\n\n return {\n defaultMode,\n defaultBrand,\n defaultColor,\n defaultStyle,\n modeStorageKey:\n config.modeStorageKey ??\n config.schemeStorageKey ??\n config.storageKey ??\n DEFAULT_MATERIAL_THEME_CONFIG.modeStorageKey,\n brandStorageKey: config.brandStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.brandStorageKey,\n colorStorageKey:\n config.colorStorageKey ?? config.themeStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.colorStorageKey,\n styleStorageKey: config.styleStorageKey ?? DEFAULT_MATERIAL_THEME_CONFIG.styleStorageKey,\n };\n }\n\n private resolveMode(mode: ColorScheme): ThemeMode {\n return mode === 'system' ? (this._systemPrefersDark() ? 'dark' : 'light') : mode;\n }\n\n private prefersDark(): boolean {\n const mql = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');\n return !!mql?.matches;\n }\n\n private watchSystemScheme(): void {\n const mql = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');\n if (!mql) return;\n\n const listener = (event: MediaQueryListEvent): void => {\n this._systemPrefersDark.set(event.matches);\n };\n mql.addEventListener('change', listener);\n this.destroyRef.onDestroy(() => mql.removeEventListener('change', listener));\n }\n\n private readPersistedMode(): ColorScheme | null {\n const key = this.config.modeStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isColorScheme(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedBrand(): ThemeBrand | null {\n const key = this.config.brandStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeBrand(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedColor(): ThemeColor | null {\n const key = this.config.colorStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeColor(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private readPersistedStyle(): ThemeStyle | null {\n const key = this.config.styleStorageKey;\n if (!key) return null;\n try {\n const value = this.document.defaultView?.localStorage?.getItem(key);\n return isThemeStyle(value) ? value : null;\n } catch {\n return null;\n }\n }\n\n private persistMode(mode: ColorScheme): void {\n const key = this.config.modeStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, mode);\n } catch {\n /* ignore */\n }\n }\n\n private persistBrand(brand: ThemeBrand): void {\n const key = this.config.brandStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, brand);\n } catch {\n /* ignore */\n }\n }\n\n private persistColor(color: ThemeColor): void {\n const key = this.config.colorStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, color);\n } catch {\n /* ignore */\n }\n }\n\n private persistStyle(style: ThemeStyle): void {\n const key = this.config.styleStorageKey;\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.setItem(key, style);\n } catch {\n /* ignore */\n }\n }\n\n private clearPersistedBrand(): void {\n this.clearPersistedItem(this.config.brandStorageKey);\n }\n\n private clearPersistedColor(): void {\n this.clearPersistedItem(this.config.colorStorageKey);\n }\n\n private clearPersistedStyle(): void {\n this.clearPersistedItem(this.config.styleStorageKey);\n }\n\n private clearPersistedItem(key: string | null): void {\n if (!key) return;\n try {\n this.document.defaultView?.localStorage?.removeItem(key);\n } catch {\n /* ignore */\n }\n }\n}\n","import {\n inject,\n type EnvironmentProviders,\n type Provider,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n} from '@angular/core';\nimport { MAT_RIPPLE_GLOBAL_OPTIONS } from '@angular/material/core';\nimport { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';\nimport { ThemeService } from './theme.service';\nimport { MATERIAL_THEME_CONFIG, type MaterialThemeConfig } from './theme.tokens';\n\n/**\n * Opaque feature unit consumed by {@link provideMaterialTheme}. Mirrors\n * Angular's router/http feature pattern so add-ons can be composed without\n * widening the primary provider signature.\n */\nexport interface MaterialThemeFeature {\n readonly providers: Provider[];\n}\n\n/**\n * Bootstrap the shared theme for any `@ojiepermana/angular/*` entry point.\n *\n * By default wires up the theme config token and eagerly initializes `ThemeService`\n * so root theme attributes are applied during bootstrap. Opt in\n * to Angular Material defaults (ripple / form-field) via\n * {@link withMaterialDefaults}.\n * Supports shorthand `mode`, `color`, and `style` config keys.\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideAnimations(),\n * provideMaterialTheme(\n * {\n * mode: 'system',\n * color: 'blue',\n * style: 'soft',\n * },\n * withMaterialDefaults(),\n * ),\n * ],\n * };\n */\nexport function provideMaterialTheme(\n config: MaterialThemeConfig = {},\n ...features: MaterialThemeFeature[]\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: MATERIAL_THEME_CONFIG, useValue: config },\n provideEnvironmentInitializer(() => {\n inject(ThemeService);\n }),\n ...features.flatMap((f) => f.providers),\n ]);\n}\n\n/**\n * Opt-in Angular Material defaults tuned for the shared theme layer:\n *\n * - Disables the global Material ripple.\n * - Forces `appearance: 'outline'` + `subscriptSizing: 'dynamic'` on every\n * `mat-form-field`.\n *\n * Only apply when your app actually renders Angular Material components.\n */\nexport function withMaterialDefaults(): MaterialThemeFeature {\n return {\n providers: [\n { provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: { disabled: true } },\n {\n provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,\n useValue: { appearance: 'outline', subscriptSizing: 'dynamic' },\n },\n ],\n };\n}\n","/*\n * Public API Surface of @ojiepermana/angular/theme\n *\n * The single source of truth for 3-layer design tokens, CSS variables,\n * and the `ThemeService` shared by every `@ojiepermana/angular/*` subpath\n * (shadcn, layout, navigation, ...).\n *\n * Usage:\n * // app.config.ts\n * import { provideMaterialTheme } from '@ojiepermana/angular/theme';\n *\n * // styles.css\n * @import '@ojiepermana/angular/theme/styles';\n * @import 'tailwindcss';\n */\n\nexport * from './src/lib/core/theme.tokens';\nexport * from './src/lib/core/theme.service';\nexport * from './src/lib/core/theme.provider';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -18,6 +18,9 @@ bun run gen:sdk:init
18
18
 
19
19
  # 3. Edit sdk.config.json, then generate
20
20
  bun run gen:sdk
21
+
22
+ # 4. Run the split-by-domain regression checks
23
+ bun run test:gen:sdk
21
24
  ```
22
25
 
23
26
  ## Consumer usage after publish
@@ -174,17 +177,21 @@ client primitives land in `shared/`.
174
177
 
175
178
  Every domain folder contains `services/`, `fn/`, `models/`, `permissions/`,
176
179
  and its own `public-api.ts` (which re-exports `shared/public-api` for
177
- convenience). The root `public-api.ts` aggregates `shared` plus every domain,
178
- so consumers can still do `import { UserService } from './sdk'` regardless of
179
- layout.
180
+ convenience). The root still owns the aggregate metadata barrel:
181
+ `metadata.ts`, `openapi-helpers.ts`, and `permissions/index.ts` stay at the SDK
182
+ root so `shared/` never depends on sibling domains. The root `public-api.ts`
183
+ aggregates `shared`, root metadata helpers, and every domain, so consumers can
184
+ still do `import { UserService } from './sdk'` regardless of layout.
180
185
 
181
186
  Model ownership rule (per-domain mode):
182
187
 
183
188
  - A model used by exactly one domain → emitted inside that domain's `models/`.
184
189
  - A model shared across two or more domains → emitted inside `shared/models/`.
185
190
  - Client primitives (`ApiConfiguration`, `BaseService`, `RequestBuilder`,
186
- `StrictHttpResponse`, `Api`), metadata, validators, and the top-level
187
- `permissions/index.ts` always live under `shared/`.
191
+ `StrictHttpResponse`, `Api`), shared metadata types, validators, and
192
+ navigation always live under `shared/`.
193
+ - Aggregate metadata helpers (`metadata.ts`, `openapi-helpers.ts`) and the
194
+ top-level `permissions/index.ts` stay at the SDK root.
188
195
 
189
196
  Example consumption when using `mode: 'library'` with `splitByDomain: true`:
190
197
 
@@ -197,11 +204,11 @@ import { GCSService } from '@my-scope/sdk/storage/gcs'; // splitDepth: 'tag'
197
204
 
198
205
  ## Output modes
199
206
 
200
- | Mode | What it emits | Use when… |
201
- | ---------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
202
- | `standalone` | A plain folder (no `ng-package.json`). | You consume the SDK via path alias / `tsconfig.paths` inside the same app. |
203
- | `library` | Standalone output **plus** `ng-package.json`, `package.json` (peerDeps), and `README.md`. | You want to build it with ng-packagr and publish to npm. |
204
- | `secondary-entrypoint` | Standalone output **plus** a minimal `ng-package.json` pointing at `public-api.ts`. | You drop the folder inside an existing library so ng-packagr picks it up as a subpath. |
207
+ | Mode | What it emits | Use when… |
208
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
209
+ | `standalone` | A plain folder (no `ng-package.json`). | You consume the SDK via path alias / `tsconfig.paths` inside the same app. |
210
+ | `library` | Standalone output **plus** `ng-package.json`, `package.json` (peerDeps), `README.md`, and nested `ng-package.json` files for split-by-domain secondary entrypoints. | You want to build it with ng-packagr and publish to npm. |
211
+ | `secondary-entrypoint` | Standalone output **plus** a minimal `ng-package.json` pointing at `public-api.ts`, plus nested `ng-package.json` files for split-by-domain secondary entrypoints. | You drop the folder inside an existing library so ng-packagr picks it up as a subpath. |
205
212
 
206
213
  ## Feature flags
207
214
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sdk = sdk;
4
+ exports.writeResult = writeResult;
4
5
  const node_path_1 = require("node:path");
5
6
  const loader_1 = require("../../src/config/loader");
6
7
  const engine_1 = require("../../src/engine");
@@ -39,6 +40,7 @@ function writeResult(tree, workspaceRoot, result, context) {
39
40
  context.logger.info(`[sdk] ${result.target.mode} → ${relOutput} ` +
40
41
  `(schemas=${result.stats.schemas}, operations=${result.stats.operations}, ` +
41
42
  `tags=${result.stats.tags}, files=${result.stats.files})`);
43
+ removeStaleFiles(tree, workspaceRoot, result);
42
44
  for (const file of result.files) {
43
45
  const absolute = (0, node_path_1.resolve)(result.outputDir, file.path);
44
46
  const treePath = normalizeTreePath(workspaceRoot, absolute);
@@ -51,6 +53,22 @@ function writeResult(tree, workspaceRoot, result, context) {
51
53
  }
52
54
  }
53
55
  }
56
+ function removeStaleFiles(tree, workspaceRoot, result) {
57
+ const outputRoot = normalizeTreePath(workspaceRoot, result.outputDir);
58
+ if (outputRoot === '/') {
59
+ return;
60
+ }
61
+ const nextFiles = new Set(result.files.map((file) => normalizeTreePath(workspaceRoot, (0, node_path_1.resolve)(result.outputDir, file.path))));
62
+ const staleFiles = [];
63
+ tree.getDir(outputRoot).visit((path) => {
64
+ if (!nextFiles.has(path)) {
65
+ staleFiles.push(path);
66
+ }
67
+ });
68
+ for (const staleFile of staleFiles) {
69
+ tree.delete(staleFile);
70
+ }
71
+ }
54
72
  function normalizeTreePath(workspaceRoot, absolute) {
55
73
  const rel = (0, node_path_1.relative)(workspaceRoot, absolute);
56
74
  const posix = rel.split(/\\+/).join('/');
@@ -7,7 +7,10 @@ exports.relayoutPerDomain = relayoutPerDomain;
7
7
  *
8
8
  * ```
9
9
  * <outputDir>/
10
- * shared/ client primitives, shared models, metadata, validators
10
+ * shared/ client primitives, shared models, metadata types, validators
11
+ * metadata.ts aggregate metadata barrel (root only)
12
+ * openapi-helpers.ts metadata helpers (root only)
13
+ * permissions/index.ts aggregate operation rules (root only)
11
14
  * <domain>/ one folder per OpenAPI tag (kebab-cased)
12
15
  * models/ models only referenced by this domain
13
16
  * fn/ tree-shakeable operation functions for this domain
@@ -191,12 +194,13 @@ function computeNewPath(oldPath, ctx) {
191
194
  'strict-http-response.ts',
192
195
  'api.ts',
193
196
  'api.navigation.ts',
194
- 'metadata.ts',
195
197
  'metadata-types.ts',
196
- 'openapi-helpers.ts',
197
198
  ]);
198
199
  if (rootShared.has(oldPath))
199
200
  return `${SHARED}/${oldPath}`;
201
+ if (oldPath === 'metadata.ts' || oldPath === 'openapi-helpers.ts') {
202
+ return oldPath;
203
+ }
200
204
  if (oldPath.startsWith('models/')) {
201
205
  const kebab = oldPath.slice('models/'.length).replace(/\.ts$/, '');
202
206
  const name = ctx.kebabToSchema.get(kebab);
@@ -220,7 +224,7 @@ function computeNewPath(oldPath, ctx) {
220
224
  return `${domain}/services/${fileName}`;
221
225
  }
222
226
  if (oldPath === 'permissions/index.ts')
223
- return `${SHARED}/permissions/index.ts`;
227
+ return oldPath;
224
228
  if (oldPath.startsWith('permissions/')) {
225
229
  const fileName = oldPath.slice('permissions/'.length);
226
230
  const tagKebab = fileName.replace(/\.ts$/, '');
@@ -269,7 +273,7 @@ function rewriteImports(content, oldPath, newPath, oldToNew) {
269
273
  function emitPublicApis(ir, target, mapping) {
270
274
  const out = [];
271
275
  const schemaNames = ir.schemas.map((s) => s.name);
272
- // shared/public-api.ts — client primitives + shared models + metadata.
276
+ // shared/public-api.ts — shared primitives + shared models only.
273
277
  const sharedLines = [target.banner, ''];
274
278
  if (target.features.client) {
275
279
  sharedLines.push(`export { ApiConfiguration, provideApiConfiguration } from './api-configuration';`);
@@ -288,8 +292,8 @@ function emitPublicApis(ir, target, mapping) {
288
292
  sharedLines.push('');
289
293
  }
290
294
  if (target.features.metadata) {
291
- sharedLines.push(`export * from './metadata';`);
292
- sharedLines.push(`export * from './openapi-helpers';`);
295
+ sharedLines.push(`export * from './metadata-types';`);
296
+ sharedLines.push(`export * from './validators';`);
293
297
  sharedLines.push('');
294
298
  }
295
299
  if (target.features.navigation) {
@@ -338,6 +342,10 @@ function emitPublicApis(ir, target, mapping) {
338
342
  // Root public-api.ts aggregates everything.
339
343
  const rootLines = [target.banner, ''];
340
344
  rootLines.push(`export * from './${SHARED}/public-api';`);
345
+ if (target.features.metadata) {
346
+ rootLines.push(`export * from './metadata';`);
347
+ rootLines.push(`export * from './openapi-helpers';`);
348
+ }
341
349
  for (const domain of mapping.domains) {
342
350
  rootLines.push(`export * from './${domain}/public-api';`);
343
351
  }
@@ -35,10 +35,8 @@ function writeLibrary(files, ir, target) {
35
35
  };
36
36
  return [
37
37
  ...files,
38
- {
39
- path: 'ng-package.json',
40
- content: (0, template_1.finalize)(JSON.stringify(ngPackage, null, 2)),
41
- },
38
+ createNgPackageFile('ng-package.json', ngPackage),
39
+ ...createNestedEntrypointNgPackages(files),
42
40
  {
43
41
  path: 'package.json',
44
42
  content: (0, template_1.finalize)(JSON.stringify(pkg, null, 2)),
@@ -59,11 +57,26 @@ function writeSecondaryEntrypoint(files, _ir, _target) {
59
57
  const ngPackage = {
60
58
  lib: { entryFile: 'public-api.ts' },
61
59
  };
62
- return [
63
- ...files,
64
- {
65
- path: 'ng-package.json',
66
- content: (0, template_1.finalize)(JSON.stringify(ngPackage, null, 2)),
67
- },
68
- ];
60
+ return [...files, createNgPackageFile('ng-package.json', ngPackage), ...createNestedEntrypointNgPackages(files)];
61
+ }
62
+ function createNestedEntrypointNgPackages(files) {
63
+ return collectSecondaryEntrypointDirs(files).map((dir) => createNgPackageFile(`${dir}/ng-package.json`, {
64
+ lib: { entryFile: 'public-api.ts' },
65
+ }));
66
+ }
67
+ function collectSecondaryEntrypointDirs(files) {
68
+ const dirs = new Set();
69
+ for (const file of files) {
70
+ if (!file.path.endsWith('/public-api.ts')) {
71
+ continue;
72
+ }
73
+ dirs.add(file.path.slice(0, -'/public-api.ts'.length));
74
+ }
75
+ return [...dirs].sort();
76
+ }
77
+ function createNgPackageFile(path, content) {
78
+ return {
79
+ path,
80
+ content: (0, template_1.finalize)(JSON.stringify(content, null, 2)),
81
+ };
69
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ojiepermana/angular",
3
- "version": "21.1.9",
3
+ "version": "21.1.12",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ojiepermana/angular.git"
@@ -15,10 +15,13 @@
15
15
  @custom-variant dark (&:where([data-mode='dark'], [data-mode='dark'] *, .dark, .dark *));
16
16
 
17
17
  @theme inline {
18
+ --color-brand: hsl(var(--brand) / 0.7);
18
19
  --color-border: hsl(var(--border));
19
20
  --color-input: hsl(var(--input));
20
21
  --color-ring: hsl(var(--ring));
21
22
  --color-background: hsl(var(--background));
23
+ --color-surface: hsl(var(--surface, var(--muted)));
24
+ --color-surface-foreground: hsl(var(--surface-foreground, var(--foreground)));
22
25
  --color-foreground: hsl(var(--foreground));
23
26
 
24
27
  --color-primary: hsl(var(--primary));
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { EnvironmentProviders } from '@angular/core';
2
+ import { EnvironmentProviders, TemplateRef } from '@angular/core';
3
3
  import { MaterialLayoutConfig, LayoutMode, LayoutWidth } from '@ojiepermana/angular/layout';
4
- import { NavigationItem, TopbarAppearance, SidebarAppearance, SidebarPosition } from '@ojiepermana/angular/navigation';
4
+ import { NavigationItem } from '@ojiepermana/angular/navigation';
5
5
  import { MaterialThemeConfig, MaterialThemeFeature, ColorScheme } from '@ojiepermana/angular/theme';
6
6
  import { PopoverSide, PopoverAlign } from '@ojiepermana/angular/component';
7
7
 
@@ -12,7 +12,7 @@ declare const ETOS_THEME_CONFIG: {
12
12
  };
13
13
  declare const ETOS_LAYOUT_CONFIG: {
14
14
  mode: "vertical";
15
- width: "fixed";
15
+ width: "container";
16
16
  };
17
17
 
18
18
  interface EtosBrandOptions {
@@ -58,13 +58,14 @@ declare class EtosThemeSwitcherComponent {
58
58
  readonly quickActions: _angular_core.InputSignal<readonly EtosThemeSwitcherQuickAction[]>;
59
59
  readonly notificationShortcut: _angular_core.InputSignal<EtosThemeSwitcherNotificationShortcut | null>;
60
60
  readonly showNotificationShortcut: _angular_core.InputSignal<boolean>;
61
- readonly popoverSide: _angular_core.InputSignal<PopoverSide>;
62
- readonly popoverAlign: _angular_core.InputSignal<PopoverAlign>;
61
+ readonly popoverSide: _angular_core.InputSignal<PopoverSide | null>;
62
+ readonly popoverAlign: _angular_core.InputSignal<PopoverAlign | null>;
63
+ readonly popoverSideOffset: _angular_core.InputSignal<number | null>;
63
64
  readonly actionSelected: _angular_core.OutputEmitterRef<string>;
64
65
  protected readonly themeMode: _angular_core.Signal<"light" | "dark">;
65
66
  protected readonly themeScheme: _angular_core.Signal<"light" | "dark" | "system">;
66
- protected readonly layoutMode: _angular_core.Signal<"vertical" | "horizontal">;
67
- protected readonly layoutWidth: _angular_core.Signal<"fixed" | "full">;
67
+ protected readonly layoutMode: _angular_core.Signal<"vertical" | "horizontal" | "empty">;
68
+ protected readonly layoutWidth: _angular_core.Signal<"container" | "full" | "wide">;
68
69
  protected readonly themeSchemeOptions: readonly [{
69
70
  readonly value: "light";
70
71
  readonly label: "Light";
@@ -86,19 +87,30 @@ declare class EtosThemeSwitcherComponent {
86
87
  readonly value: "vertical";
87
88
  readonly label: "Vertical";
88
89
  readonly icon: "view_sidebar";
90
+ }, {
91
+ readonly value: "empty";
92
+ readonly label: "Empty";
93
+ readonly icon: "crop_square";
89
94
  }];
90
95
  protected readonly layoutWidthOptions: readonly [{
91
96
  readonly value: "full";
92
97
  readonly label: "Full";
93
98
  readonly icon: "fit_screen";
94
99
  }, {
95
- readonly value: "fixed";
96
- readonly label: "Fixed";
100
+ readonly value: "container";
101
+ readonly label: "Container";
97
102
  readonly icon: "center_focus_strong";
103
+ }, {
104
+ readonly value: "wide";
105
+ readonly label: "Wide";
106
+ readonly icon: "width_wide";
98
107
  }];
99
108
  protected readonly notificationShortcutConfig: _angular_core.Signal<Required<EtosThemeSwitcherNotificationShortcut> | null>;
100
109
  protected readonly actionOptions: _angular_core.Signal<readonly EtosThemeSwitcherQuickAction[]>;
101
110
  protected readonly hostClasses: _angular_core.Signal<string>;
111
+ protected readonly resolvedPopoverSide: _angular_core.Signal<PopoverSide>;
112
+ protected readonly resolvedPopoverAlign: _angular_core.Signal<PopoverAlign>;
113
+ protected readonly resolvedPopoverSideOffset: _angular_core.Signal<number>;
102
114
  protected readonly resolvedUserName: _angular_core.Signal<string>;
103
115
  protected readonly resolvedUserSubtitle: _angular_core.Signal<string>;
104
116
  protected readonly resolvedAvatarSrc: _angular_core.Signal<string | null>;
@@ -125,57 +137,22 @@ declare class EtosThemeSwitcherComponent {
125
137
  private labelForLayoutWidth;
126
138
  private toInitials;
127
139
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosThemeSwitcherComponent, never>;
128
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosThemeSwitcherComponent, "etos-theme-switcher", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": false; "isSignal": true; }; "userName": { "alias": "userName"; "required": false; "isSignal": true; }; "userSubtitle": { "alias": "userSubtitle"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarAlt": { "alias": "avatarAlt"; "required": false; "isSignal": true; }; "quickActions": { "alias": "quickActions"; "required": true; "isSignal": true; }; "notificationShortcut": { "alias": "notificationShortcut"; "required": false; "isSignal": true; }; "showNotificationShortcut": { "alias": "showNotificationShortcut"; "required": false; "isSignal": true; }; "popoverSide": { "alias": "popoverSide"; "required": false; "isSignal": true; }; "popoverAlign": { "alias": "popoverAlign"; "required": false; "isSignal": true; }; }, { "actionSelected": "actionSelected"; }, never, never, true, never>;
129
- }
130
-
131
- declare class EtosEmptyLayoutComponent {
132
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosEmptyLayoutComponent, never>;
133
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosEmptyLayoutComponent, "etos-empty-layout", never, {}, {}, never, never, true, never>;
134
- }
135
-
136
- declare class EtosHorizontalLayoutComponent {
137
- private readonly layout;
138
- readonly topbarAppearance: _angular_core.InputSignal<TopbarAppearance>;
139
- readonly ariaLabel: _angular_core.InputSignal<string>;
140
- protected readonly brandLayout = "etos-horizontal";
141
- protected readonly layoutWidth: _angular_core.Signal<"fixed" | "full">;
142
- protected readonly dividerBorderWidth: _angular_core.Signal<string>;
143
- protected readonly hostClasses: _angular_core.Signal<string>;
144
- protected readonly frameClasses: _angular_core.Signal<string>;
145
- protected readonly mainClasses: _angular_core.Signal<string>;
146
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosHorizontalLayoutComponent, never>;
147
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosHorizontalLayoutComponent, "etos-horizontal-layout", never, { "topbarAppearance": { "alias": "topbarAppearance"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["[ui-layout-brand],[ui-topbar-start]", "[ui-layout-profile],[ui-topbar-end]"], true, never>;
140
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosThemeSwitcherComponent, "etos-theme-switcher", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": false; "isSignal": true; }; "userName": { "alias": "userName"; "required": false; "isSignal": true; }; "userSubtitle": { "alias": "userSubtitle"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarAlt": { "alias": "avatarAlt"; "required": false; "isSignal": true; }; "quickActions": { "alias": "quickActions"; "required": true; "isSignal": true; }; "notificationShortcut": { "alias": "notificationShortcut"; "required": false; "isSignal": true; }; "showNotificationShortcut": { "alias": "showNotificationShortcut"; "required": false; "isSignal": true; }; "popoverSide": { "alias": "popoverSide"; "required": false; "isSignal": true; }; "popoverAlign": { "alias": "popoverAlign"; "required": false; "isSignal": true; }; "popoverSideOffset": { "alias": "popoverSideOffset"; "required": false; "isSignal": true; }; }, { "actionSelected": "actionSelected"; }, never, never, true, never>;
148
141
  }
149
142
 
150
143
  declare class EtosLayoutComponent {
144
+ readonly mode: _angular_core.InputSignal<"vertical" | "horizontal" | "empty" | null>;
145
+ readonly sidebarHeaderTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
146
+ readonly sidebarFooterTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
147
+ readonly layoutBrandTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
148
+ readonly layoutProfileTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
151
149
  private readonly layout;
152
- readonly ariaLabel: _angular_core.InputSignal<string>;
153
- protected readonly layoutMode: _angular_core.Signal<"vertical" | "horizontal">;
150
+ protected readonly resolvedMode: _angular_core.Signal<"vertical" | "horizontal" | "empty">;
154
151
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosLayoutComponent, never>;
155
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosLayoutComponent, "etos-layout", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["[ui-layout-brand],[ui-topbar-start]", "[ui-layout-profile],[ui-topbar-end]"], true, never>;
156
- }
157
-
158
- declare class EtosVerticalLayoutComponent {
159
- private readonly layout;
160
- readonly sidebarAppearance: _angular_core.InputSignal<SidebarAppearance>;
161
- readonly sidebarPosition: _angular_core.InputSignal<SidebarPosition>;
162
- readonly ariaLabel: _angular_core.InputSignal<string>;
163
- protected readonly brandLayout = "etos-vertical";
164
- protected readonly layoutWidth: _angular_core.Signal<"fixed" | "full">;
165
- protected readonly dividerBorderWidth: _angular_core.Signal<string>;
166
- protected readonly hostClasses: _angular_core.Signal<string>;
167
- protected readonly frameClasses: _angular_core.Signal<string>;
168
- protected readonly mainClasses: _angular_core.Signal<string>;
169
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosVerticalLayoutComponent, never>;
170
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosVerticalLayoutComponent, "etos-vertical-layout", never, { "sidebarAppearance": { "alias": "sidebarAppearance"; "required": false; "isSignal": true; }; "sidebarPosition": { "alias": "sidebarPosition"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["[ui-layout-brand],[ui-topbar-start],[ui-sidebar-header]", "[ui-layout-profile],[ui-topbar-end],[ui-sidebar-footer]"], true, never>;
171
- }
172
-
173
- declare class EtosAppShellComponent {
174
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<EtosAppShellComponent, never>;
175
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosAppShellComponent, "etos-app-shell", never, {}, {}, never, ["[etos-app-shell-header]", "[etos-app-shell-main]", "[etos-app-shell-footer]"], true, never>;
152
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EtosLayoutComponent, "etos-layout", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "sidebarHeaderTemplate": { "alias": "sidebarHeaderTemplate"; "required": false; "isSignal": true; }; "sidebarFooterTemplate": { "alias": "sidebarFooterTemplate"; "required": false; "isSignal": true; }; "layoutBrandTemplate": { "alias": "layoutBrandTemplate"; "required": false; "isSignal": true; }; "layoutProfileTemplate": { "alias": "layoutProfileTemplate"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
176
153
  }
177
154
 
178
155
  declare const ETOS_BRAND_VERSION = "0.0.1";
179
156
 
180
- export { ETOS_BRAND_NAME, ETOS_BRAND_VERSION, ETOS_LAYOUT_CONFIG, ETOS_THEME_CONFIG, EtosAppShellComponent, EtosEmptyLayoutComponent, EtosHorizontalLayoutComponent, EtosLayoutComponent, EtosThemeSwitcherComponent, EtosVerticalLayoutComponent, provideEtosBrand, provideEtosLayout, provideEtosTheme };
157
+ export { ETOS_BRAND_NAME, ETOS_BRAND_VERSION, ETOS_LAYOUT_CONFIG, ETOS_THEME_CONFIG, EtosLayoutComponent, EtosThemeSwitcherComponent, provideEtosBrand, provideEtosLayout, provideEtosTheme };
181
158
  export type { EtosBrandOptions, EtosThemeSwitcherAction, EtosThemeSwitcherNotificationShortcut, EtosThemeSwitcherQuickAction, EtosThemeSwitcherUserInfo };
@@ -786,6 +786,7 @@ declare class PopoverTriggerDirective {
786
786
  readonly uiPopoverTrigger: _angular_core.InputSignal<PopoverContentDirective>;
787
787
  readonly side: _angular_core.InputSignal<PopoverSide>;
788
788
  readonly align: _angular_core.InputSignal<PopoverAlign>;
789
+ readonly sideOffset: _angular_core.InputSignal<number>;
789
790
  readonly disabled: _angular_core.InputSignal<boolean>;
790
791
  readonly openedChange: _angular_core.OutputEmitterRef<boolean>;
791
792
  private overlayRef;
@@ -795,7 +796,7 @@ declare class PopoverTriggerDirective {
795
796
  close(): void;
796
797
  private oppositeSide;
797
798
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<PopoverTriggerDirective, never>;
798
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<PopoverTriggerDirective, "[uiPopoverTrigger]", ["uiPopoverTrigger"], { "uiPopoverTrigger": { "alias": "uiPopoverTrigger"; "required": true; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "openedChange": "openedChange"; }, never, never, true, never>;
799
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<PopoverTriggerDirective, "[uiPopoverTrigger]", ["uiPopoverTrigger"], { "uiPopoverTrigger": { "alias": "uiPopoverTrigger"; "required": true; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "sideOffset": { "alias": "sideOffset"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "openedChange": "openedChange"; }, never, never, true, never>;
799
800
  }
800
801
 
801
802
  declare class ProgressComponent {