{"version":3,"file":"ngx-com-theme.mjs","sources":["../../../projects/com/theme/src/theme.providers.ts","../../../projects/com/theme/src/theme.models.ts","../../../projects/com/theme/src/theme.service.ts","../../../projects/com/theme/src/index.ts","../../../projects/com/theme/src/ngx-com-theme.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport type { Provider } from '@angular/core';\nimport type { ComThemeConfig } from './theme.models';\n\n/**\n * Injection token for theme service configuration.\n *\n * Prefer using `provideComTheme()` instead of providing this token directly.\n */\nexport const COM_THEME_CONFIG: InjectionToken<ComThemeConfig> =\n  new InjectionToken<ComThemeConfig>('COM_THEME_CONFIG');\n\n/**\n * Provides theme service configuration.\n *\n * @example\n * ```typescript\n * // Minimal — defaults to light/dark, localStorage, system preference watching\n * bootstrapApplication(AppComponent, {\n *   providers: [provideComTheme()],\n * });\n *\n * // Custom default theme and storage key\n * bootstrapApplication(AppComponent, {\n *   providers: [\n *     provideComTheme({\n *       defaultTheme: 'ocean',\n *       storageKey: 'my-app-theme',\n *     }),\n *   ],\n * });\n * ```\n */\nexport function provideComTheme(config?: ComThemeConfig): Provider {\n  return { provide: COM_THEME_CONFIG, useValue: config ?? {} };\n}\n","/** Consumer-facing configuration for the theme service. */\nexport interface ComThemeConfig {\n  /** Default theme when no stored/system preference is found. Default: `'light'`. */\n  defaultTheme?: string;\n\n  /**\n   * localStorage key for persistence. Set to `null` to disable persistence.\n   * Default: `'com-theme'`.\n   */\n  storageKey?: string | null;\n\n  /**\n   * Theme to apply when the system reports `prefers-color-scheme: dark`.\n   * Set to `null` to disable system dark preference detection.\n   * Default: `'dark'`.\n   */\n  darkSchemeTheme?: string | null;\n\n  /**\n   * Theme to apply when the system reports `prefers-color-scheme: light`\n   * (or no preference). Defaults to `defaultTheme`.\n   */\n  lightSchemeTheme?: string;\n\n  /**\n   * When `true`, the service listens for live `prefers-color-scheme` changes\n   * and applies the mapped theme — unless the user has explicitly set a theme\n   * (stored in localStorage). Call `clearPreference()` to revert to system following.\n   * Default: `true`.\n   */\n  followSystemPreference?: boolean;\n\n  /**\n   * HTML attribute name used to apply the theme on `documentElement`.\n   * Default: `'data-theme'`.\n   */\n  attribute?: string;\n}\n\n/** @internal Resolved config with all defaults applied. */\nexport interface ComThemeResolvedConfig {\n  defaultTheme: string;\n  storageKey: string | null;\n  darkSchemeTheme: string | null;\n  lightSchemeTheme: string;\n  followSystemPreference: boolean;\n  attribute: string;\n}\n\n/** @internal Default configuration values. */\nexport const COM_THEME_DEFAULTS: ComThemeResolvedConfig = {\n  defaultTheme: 'light',\n  storageKey: 'com-theme',\n  darkSchemeTheme: 'dark',\n  lightSchemeTheme: 'light',\n  followSystemPreference: true,\n  attribute: 'data-theme',\n};\n","import {\n  Injectable,\n  DestroyRef,\n  RendererFactory2,\n  PLATFORM_ID,\n  inject,\n  signal,\n  computed,\n  effect,\n} from '@angular/core';\nimport { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport type { Renderer2, Signal, WritableSignal } from '@angular/core';\n\nimport { COM_THEME_CONFIG } from './theme.providers';\nimport { COM_THEME_DEFAULTS } from './theme.models';\nimport type { ComThemeResolvedConfig } from './theme.models';\n\n/**\n * SSR-safe theme management service.\n *\n * Manages the active theme by setting a `data-theme` attribute on the document\n * element. Supports localStorage persistence, system `prefers-color-scheme`\n * detection with optional live watching, and a signal-based reactive API.\n *\n * Configure via `provideComTheme()` in your application providers.\n *\n * @example\n * ```typescript\n * // In your app config\n * providers: [provideComTheme({ defaultTheme: 'ocean' })]\n *\n * // In a component\n * readonly theme = inject(ComTheme);\n * this.theme.setTheme('dark');\n * this.theme.clearPreference(); // revert to following system\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ComTheme {\n  private readonly document = inject(DOCUMENT);\n  private readonly platformId = inject(PLATFORM_ID);\n  private readonly renderer: Renderer2 = inject(RendererFactory2).createRenderer(null, null);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly config: ComThemeResolvedConfig;\n\n  /**\n   * Whether the current theme was automatically determined by system preference\n   * rather than explicitly set by the user.\n   */\n  private readonly _isAutomatic: WritableSignal<boolean>;\n\n  /** Current active theme. */\n  readonly theme: Signal<string>;\n\n  /** Whether the theme is currently following system preference. */\n  readonly isAutomatic: Signal<boolean>;\n\n  private readonly _theme: WritableSignal<string>;\n\n  constructor() {\n    const userConfig = inject(COM_THEME_CONFIG, { optional: true });\n    this.config = this.resolveConfig(userConfig ?? {});\n\n    const { initial, automatic } = this.determineInitialTheme();\n    this._theme = signal(initial);\n    this._isAutomatic = signal(automatic);\n    this.theme = this._theme.asReadonly();\n    this.isAutomatic = computed(() => this._isAutomatic());\n\n    // Apply theme + persist on every change\n    effect(() => {\n      const theme = this._theme();\n      this.applyTheme(theme);\n\n      if (!this._isAutomatic()) {\n        this.persistTheme(theme);\n      }\n    });\n\n    this.setupSystemPreferenceWatcher();\n  }\n\n  /** Set the active theme explicitly. Persists to localStorage and stops following system preference. */\n  setTheme(theme: string): void {\n    this._isAutomatic.set(false);\n    this._theme.set(theme);\n  }\n\n  /**\n   * Remove the stored theme preference and revert to following system preference.\n   * If system preference watching is enabled, the theme updates to match the current\n   * system color scheme. Otherwise, falls back to the configured default theme.\n   */\n  clearPreference(): void {\n    this.removeStoredTheme();\n    this._isAutomatic.set(true);\n\n    if (this.config.followSystemPreference && isPlatformBrowser(this.platformId)) {\n      this._theme.set(this.getSystemTheme());\n    } else {\n      this._theme.set(this.config.defaultTheme);\n    }\n  }\n\n  private resolveConfig(\n    userConfig: Partial<ComThemeResolvedConfig>,\n  ): ComThemeResolvedConfig {\n    const defaultTheme = userConfig.defaultTheme ?? COM_THEME_DEFAULTS.defaultTheme;\n    return {\n      defaultTheme,\n      storageKey: userConfig.storageKey !== undefined\n        ? userConfig.storageKey\n        : COM_THEME_DEFAULTS.storageKey,\n      darkSchemeTheme: userConfig.darkSchemeTheme !== undefined\n        ? userConfig.darkSchemeTheme\n        : COM_THEME_DEFAULTS.darkSchemeTheme,\n      lightSchemeTheme: userConfig.lightSchemeTheme ?? defaultTheme,\n      followSystemPreference:\n        userConfig.followSystemPreference ?? COM_THEME_DEFAULTS.followSystemPreference,\n      attribute: userConfig.attribute ?? COM_THEME_DEFAULTS.attribute,\n    };\n  }\n\n  private determineInitialTheme(): { initial: string; automatic: boolean } {\n    // 1. Check localStorage for explicit user choice\n    const stored = this.getStoredTheme();\n    if (stored !== null) {\n      return { initial: stored, automatic: false };\n    }\n\n    // 2. Check system preference\n    if (this.config.darkSchemeTheme !== null && isPlatformBrowser(this.platformId)) {\n      return { initial: this.getSystemTheme(), automatic: true };\n    }\n\n    // 3. Fall back to default\n    return { initial: this.config.defaultTheme, automatic: true };\n  }\n\n  private getSystemTheme(): string {\n    const win = this.document.defaultView;\n    if (!win) {\n      return this.config.lightSchemeTheme;\n    }\n    const prefersDark = win.matchMedia('(prefers-color-scheme: dark)').matches;\n    return prefersDark\n      ? (this.config.darkSchemeTheme ?? this.config.lightSchemeTheme)\n      : this.config.lightSchemeTheme;\n  }\n\n  private setupSystemPreferenceWatcher(): void {\n    if (\n      !this.config.followSystemPreference ||\n      this.config.darkSchemeTheme === null ||\n      !isPlatformBrowser(this.platformId)\n    ) {\n      return;\n    }\n\n    const win = this.document.defaultView;\n    if (!win) {\n      return;\n    }\n\n    const mediaQuery = win.matchMedia('(prefers-color-scheme: dark)');\n    const handler = (event: MediaQueryListEvent): void => {\n      // Only react if the user hasn't explicitly overridden\n      if (!this._isAutomatic()) {\n        return;\n      }\n      this._theme.set(\n        event.matches\n          ? (this.config.darkSchemeTheme ?? this.config.lightSchemeTheme)\n          : this.config.lightSchemeTheme,\n      );\n    };\n\n    mediaQuery.addEventListener('change', handler);\n    this.destroyRef.onDestroy(() => {\n      mediaQuery.removeEventListener('change', handler);\n    });\n  }\n\n  private applyTheme(theme: string): void {\n    this.renderer.setAttribute(\n      this.document.documentElement,\n      this.config.attribute,\n      theme,\n    );\n  }\n\n  private persistTheme(theme: string): void {\n    if (this.config.storageKey === null || !isPlatformBrowser(this.platformId)) {\n      return;\n    }\n    try {\n      localStorage.setItem(this.config.storageKey, theme);\n    } catch {\n      // Storage full or unavailable — silently ignore\n    }\n  }\n\n  private getStoredTheme(): string | null {\n    if (this.config.storageKey === null || !isPlatformBrowser(this.platformId)) {\n      return null;\n    }\n    try {\n      return localStorage.getItem(this.config.storageKey);\n    } catch {\n      return null;\n    }\n  }\n\n  private removeStoredTheme(): void {\n    if (this.config.storageKey === null || !isPlatformBrowser(this.platformId)) {\n      return;\n    }\n    try {\n      localStorage.removeItem(this.config.storageKey);\n    } catch {\n      // Silently ignore\n    }\n  }\n}\n","// Service\nexport { ComTheme } from './theme.service';\n\n// Types\nexport type { ComThemeConfig } from './theme.models';\n\n// Providers\nexport { COM_THEME_CONFIG, provideComTheme } from './theme.providers';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}