@odx/angular 12.21.4 → 12.21.5

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 (146) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/fesm2022/odx-angular-animations.mjs.map +1 -1
  3. package/fesm2022/odx-angular-breakpoints.mjs +1 -1
  4. package/fesm2022/odx-angular-breakpoints.mjs.map +1 -1
  5. package/fesm2022/odx-angular-cdk-a11y.mjs +1 -1
  6. package/fesm2022/odx-angular-cdk-a11y.mjs.map +1 -1
  7. package/fesm2022/odx-angular-cdk-active-indicator.mjs +1 -1
  8. package/fesm2022/odx-angular-cdk-active-indicator.mjs.map +1 -1
  9. package/fesm2022/odx-angular-cdk-autocomplete-control.mjs +1 -1
  10. package/fesm2022/odx-angular-cdk-autocomplete-control.mjs.map +1 -1
  11. package/fesm2022/odx-angular-cdk-checkbox-control.mjs +1 -1
  12. package/fesm2022/odx-angular-cdk-checkbox-control.mjs.map +1 -1
  13. package/fesm2022/odx-angular-cdk-connected-overlay.mjs +1 -1
  14. package/fesm2022/odx-angular-cdk-connected-overlay.mjs.map +1 -1
  15. package/fesm2022/odx-angular-cdk-custom-form-control.mjs +1 -1
  16. package/fesm2022/odx-angular-cdk-custom-form-control.mjs.map +1 -1
  17. package/fesm2022/odx-angular-cdk-date-input.mjs.map +1 -1
  18. package/fesm2022/odx-angular-cdk-dynamic-view.mjs +1 -1
  19. package/fesm2022/odx-angular-cdk-dynamic-view.mjs.map +1 -1
  20. package/fesm2022/odx-angular-cdk-event-plugins.mjs.map +1 -1
  21. package/fesm2022/odx-angular-cdk-expandable.mjs +1 -1
  22. package/fesm2022/odx-angular-cdk-expandable.mjs.map +1 -1
  23. package/fesm2022/odx-angular-cdk-option-control.mjs +1 -1
  24. package/fesm2022/odx-angular-cdk-option-control.mjs.map +1 -1
  25. package/fesm2022/odx-angular-cdk-radio-group-control.mjs +1 -1
  26. package/fesm2022/odx-angular-cdk-radio-group-control.mjs.map +1 -1
  27. package/fesm2022/odx-angular-cdk-scrollable.mjs.map +1 -1
  28. package/fesm2022/odx-angular-components-accordion.mjs +1 -1
  29. package/fesm2022/odx-angular-components-accordion.mjs.map +1 -1
  30. package/fesm2022/odx-angular-components-action-group.mjs +1 -1
  31. package/fesm2022/odx-angular-components-action-group.mjs.map +1 -1
  32. package/fesm2022/odx-angular-components-anchor-navigation.mjs +1 -1
  33. package/fesm2022/odx-angular-components-anchor-navigation.mjs.map +1 -1
  34. package/fesm2022/odx-angular-components-area-header.mjs +1 -1
  35. package/fesm2022/odx-angular-components-area-header.mjs.map +1 -1
  36. package/fesm2022/odx-angular-components-autocomplete.mjs +1 -1
  37. package/fesm2022/odx-angular-components-autocomplete.mjs.map +1 -1
  38. package/fesm2022/odx-angular-components-avatar.mjs +1 -1
  39. package/fesm2022/odx-angular-components-avatar.mjs.map +1 -1
  40. package/fesm2022/odx-angular-components-badge.mjs +1 -1
  41. package/fesm2022/odx-angular-components-badge.mjs.map +1 -1
  42. package/fesm2022/odx-angular-components-bar.mjs +1 -1
  43. package/fesm2022/odx-angular-components-bar.mjs.map +1 -1
  44. package/fesm2022/odx-angular-components-breadcrumbs.mjs +1 -1
  45. package/fesm2022/odx-angular-components-breadcrumbs.mjs.map +1 -1
  46. package/fesm2022/odx-angular-components-button-group.mjs +1 -1
  47. package/fesm2022/odx-angular-components-button-group.mjs.map +1 -1
  48. package/fesm2022/odx-angular-components-button.mjs +1 -1
  49. package/fesm2022/odx-angular-components-button.mjs.map +1 -1
  50. package/fesm2022/odx-angular-components-calendar.mjs +2 -2
  51. package/fesm2022/odx-angular-components-calendar.mjs.map +1 -1
  52. package/fesm2022/odx-angular-components-card.mjs +2 -2
  53. package/fesm2022/odx-angular-components-card.mjs.map +1 -1
  54. package/fesm2022/odx-angular-components-checkbox.mjs +1 -1
  55. package/fesm2022/odx-angular-components-checkbox.mjs.map +1 -1
  56. package/fesm2022/odx-angular-components-chip.mjs +1 -1
  57. package/fesm2022/odx-angular-components-chip.mjs.map +1 -1
  58. package/fesm2022/odx-angular-components-circular-progress.mjs +1 -1
  59. package/fesm2022/odx-angular-components-circular-progress.mjs.map +1 -1
  60. package/fesm2022/odx-angular-components-content-box.mjs +1 -1
  61. package/fesm2022/odx-angular-components-content-box.mjs.map +1 -1
  62. package/fesm2022/odx-angular-components-data-table.mjs +1 -1
  63. package/fesm2022/odx-angular-components-data-table.mjs.map +1 -1
  64. package/fesm2022/odx-angular-components-datepicker.mjs +2 -2
  65. package/fesm2022/odx-angular-components-datepicker.mjs.map +1 -1
  66. package/fesm2022/odx-angular-components-daterangepicker.mjs +3 -3
  67. package/fesm2022/odx-angular-components-daterangepicker.mjs.map +1 -1
  68. package/fesm2022/odx-angular-components-dropdown.mjs +1 -1
  69. package/fesm2022/odx-angular-components-dropdown.mjs.map +1 -1
  70. package/fesm2022/odx-angular-components-error-page.mjs +1 -1
  71. package/fesm2022/odx-angular-components-error-page.mjs.map +1 -1
  72. package/fesm2022/odx-angular-components-footer.mjs +2 -2
  73. package/fesm2022/odx-angular-components-footer.mjs.map +1 -1
  74. package/fesm2022/odx-angular-components-form-field.mjs +1 -1
  75. package/fesm2022/odx-angular-components-form-field.mjs.map +1 -1
  76. package/fesm2022/odx-angular-components-header-navigation.mjs +1 -1
  77. package/fesm2022/odx-angular-components-header-navigation.mjs.map +1 -1
  78. package/fesm2022/odx-angular-components-header.mjs +1 -1
  79. package/fesm2022/odx-angular-components-header.mjs.map +1 -1
  80. package/fesm2022/odx-angular-components-icon.mjs +1 -1
  81. package/fesm2022/odx-angular-components-icon.mjs.map +1 -1
  82. package/fesm2022/odx-angular-components-inline-message.mjs +1 -1
  83. package/fesm2022/odx-angular-components-inline-message.mjs.map +1 -1
  84. package/fesm2022/odx-angular-components-link.mjs.map +1 -1
  85. package/fesm2022/odx-angular-components-list.mjs +2 -2
  86. package/fesm2022/odx-angular-components-list.mjs.map +1 -1
  87. package/fesm2022/odx-angular-components-loading-spinner.mjs +1 -1
  88. package/fesm2022/odx-angular-components-loading-spinner.mjs.map +1 -1
  89. package/fesm2022/odx-angular-components-logo.mjs +1 -1
  90. package/fesm2022/odx-angular-components-logo.mjs.map +1 -1
  91. package/fesm2022/odx-angular-components-main-menu.mjs +2 -2
  92. package/fesm2022/odx-angular-components-main-menu.mjs.map +1 -1
  93. package/fesm2022/odx-angular-components-mainfilter-group.mjs +1 -1
  94. package/fesm2022/odx-angular-components-mainfilter-group.mjs.map +1 -1
  95. package/fesm2022/odx-angular-components-menu.mjs +1 -1
  96. package/fesm2022/odx-angular-components-menu.mjs.map +1 -1
  97. package/fesm2022/odx-angular-components-modal.mjs +1 -1
  98. package/fesm2022/odx-angular-components-modal.mjs.map +1 -1
  99. package/fesm2022/odx-angular-components-navigation-back.mjs +1 -1
  100. package/fesm2022/odx-angular-components-navigation-back.mjs.map +1 -1
  101. package/fesm2022/odx-angular-components-notification-testing.mjs.map +1 -1
  102. package/fesm2022/odx-angular-components-notification.mjs +3 -3
  103. package/fesm2022/odx-angular-components-notification.mjs.map +1 -1
  104. package/fesm2022/odx-angular-components-paginator.mjs +1 -1
  105. package/fesm2022/odx-angular-components-paginator.mjs.map +1 -1
  106. package/fesm2022/odx-angular-components-progress.mjs +1 -1
  107. package/fesm2022/odx-angular-components-progress.mjs.map +1 -1
  108. package/fesm2022/odx-angular-components-radio-group.mjs +1 -1
  109. package/fesm2022/odx-angular-components-radio-group.mjs.map +1 -1
  110. package/fesm2022/odx-angular-components-rail-navigation.mjs +1 -1
  111. package/fesm2022/odx-angular-components-rail-navigation.mjs.map +1 -1
  112. package/fesm2022/odx-angular-components-rich-list.mjs +1 -1
  113. package/fesm2022/odx-angular-components-rich-list.mjs.map +1 -1
  114. package/fesm2022/odx-angular-components-search-bar.mjs.map +1 -1
  115. package/fesm2022/odx-angular-components-select.mjs +1 -1
  116. package/fesm2022/odx-angular-components-select.mjs.map +1 -1
  117. package/fesm2022/odx-angular-components-slider.mjs +1 -1
  118. package/fesm2022/odx-angular-components-slider.mjs.map +1 -1
  119. package/fesm2022/odx-angular-components-spinbox.mjs +1 -1
  120. package/fesm2022/odx-angular-components-spinbox.mjs.map +1 -1
  121. package/fesm2022/odx-angular-components-switch.mjs +1 -1
  122. package/fesm2022/odx-angular-components-switch.mjs.map +1 -1
  123. package/fesm2022/odx-angular-components-tab-bar.mjs +1 -1
  124. package/fesm2022/odx-angular-components-tab-bar.mjs.map +1 -1
  125. package/fesm2022/odx-angular-components-table.mjs +1 -1
  126. package/fesm2022/odx-angular-components-table.mjs.map +1 -1
  127. package/fesm2022/odx-angular-components-timepicker.mjs +2 -2
  128. package/fesm2022/odx-angular-components-timepicker.mjs.map +1 -1
  129. package/fesm2022/odx-angular-components-toast.mjs +1 -1
  130. package/fesm2022/odx-angular-components-toast.mjs.map +1 -1
  131. package/fesm2022/odx-angular-components-toggle-button-group.mjs +1 -1
  132. package/fesm2022/odx-angular-components-toggle-button-group.mjs.map +1 -1
  133. package/fesm2022/odx-angular-components-tooltip.mjs +1 -1
  134. package/fesm2022/odx-angular-components-tooltip.mjs.map +1 -1
  135. package/fesm2022/odx-angular-components-wizard.mjs +1 -1
  136. package/fesm2022/odx-angular-components-wizard.mjs.map +1 -1
  137. package/fesm2022/odx-angular-internal-translate.mjs.map +1 -1
  138. package/fesm2022/odx-angular-internal.mjs.map +1 -1
  139. package/fesm2022/odx-angular-localization.mjs.map +1 -1
  140. package/fesm2022/odx-angular-rxjs.mjs.map +1 -1
  141. package/fesm2022/odx-angular-sdk.mjs.map +1 -1
  142. package/fesm2022/odx-angular-theming.mjs.map +1 -1
  143. package/fesm2022/odx-angular-utils.mjs.map +1 -1
  144. package/fesm2022/odx-angular.mjs +2 -2
  145. package/fesm2022/odx-angular.mjs.map +1 -1
  146. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"odx-angular-localization.mjs","sources":["../../../../libs/angular/localization/src/lib/localization.config.ts","../../../../libs/angular/localization/src/lib/localization.logger.ts","../../../../libs/angular/localization/src/lib/localization.service.ts","../../../../libs/angular/localization/src/lib/models/localization-feature.ts","../../../../libs/angular/localization/src/lib/features/with-http-language-header.ts","../../../../libs/angular/localization/src/lib/features/with-http-language-query-param.ts","../../../../libs/angular/localization/src/lib/loaders/browser-language-loader.ts","../../../../libs/angular/localization/src/odx-angular-localization.ts"],"sourcesContent":["import { APP_INITIALIZER, EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { createConfigTokens } from '@odx/angular/utils';\nimport { LocalizationService } from './localization.service';\nimport { LanguageLoaderFn, LocalizationFeature } from './models';\n\nexport const DEFAULT_AVAILABLE_LANGUAGES = ['en-US', 'en-GB', 'en', 'de-DE', 'de', 'es-ES', 'es', 'fr-FR', 'fr-CA', 'fr'];\n\n/**\n * Defines the structure for the localization configuration used throughout the application.\n * It allows specifying available languages, and includes an optional loader\n * function for dynamically determining the active language.\n *\n * @property {LanguageLoaderFn} [activeLanguageLoader] Optional function for loading the\n * active language dynamically, useful for scenarios where the application's language\n * needs to be determined based on user settings, browser settings, or external data.\n * @property {string[]} availableLanguages An array of language codes representing the\n * languages available in the application.\n */\nexport interface LocalizationConfig {\n activeLanguageLoader?: LanguageLoaderFn;\n availableLanguages: string[];\n}\n\n/**\n * Utilizes `createConfigTokens` to generate configuration tokens and related utilities for the\n * localization settings within the application. It defines a structured and type-safe approach\n * for managing localization configurations, such as available languages, and potentially\n * a dynamic loader for the active language. The generated tokens and utilities facilitate accessing\n * and providing these configurations throughout the application.\n *\n * @const {InjectionToken<LocalizationConfig>} LocalizationConfig - An InjectionToken for accessing\n * the localization configuration within Angular's dependency injection framework. Use this token to inject\n * localization configurations into services, components, or other tokens.\n *\n * @const {LocalizationConfig} LocalizationDefaultConfig - The default configuration values for localization,\n * based on the provided settings. Includes the default available languages.\n *\n * @const {Function} injectLocalizationConfig - A utility function that returns the injected value of\n * `LocalizationConfig` token. Use this function to access the current localization configuration in\n * a type-safe manner.\n *\n * @const {Function} provideLocalizationConfig - A utility function to provide the `LocalizationConfig` token\n * with specific values. Use this function to configure and override default localization settings within\n * an Angular module or component.\n *\n * @example\n * ```ts\n * // Providing localization settings in an Angular module\n * @NgModule({\n * providers: [\n * provideLocalizationConfig({\n * availableLanguages: ['en', 'es', 'fr'],\n * })\n * ]\n * })\n * export class AppModule { }\n *\n * // Injecting and using the localization configuration in a service\n * @Injectable({ providedIn: 'root' })\n * export class MyLocalizationService {\n * constructor(@Inject(LocalizationConfig) private config: LocalizationConfig) {\n * console.log('Available languages:', config.availableLanguages);\n * }\n * }\n * ```\n */\nexport const { LocalizationConfig, LocalizationDefaultConfig, injectLocalizationConfig, provideLocalizationConfig } = createConfigTokens(\n 'Localization',\n '@odx/angular/internal/translate',\n {\n availableLanguages: DEFAULT_AVAILABLE_LANGUAGES,\n } as LocalizationConfig,\n);\n\n/**\n * Sets up the localization configuration for the application and initializes the localization\n * system with the provided configuration and features. This function is typically called\n * within the main module or a core module of the application to ensure localization settings\n * are available and active as early as possible.\n *\n * @param {Partial<LocalizationConfig>} config The localization configuration settings, including\n * available languages and optionally, a custom loader for the active language.\n * @param {...LocalizationFeature[]} features Additional localization features or configurations\n * to be registered as part of the application's environment providers.\n * @returns {EnvironmentProviders} A collection of providers for setting up the application's\n * localization environment, to be used with Angular's environment-specific injector configuration.\n * @example\n * ```ts\n * // Example of providing localization settings in an Angular module\n * @NgModule({\n * imports: [...],\n * providers: [\n * provideLocalization({\n * availableLanguages: ['en', 'es', 'fr'],\n * activeLanguageLoader: () => fetch('/api/user/language').then(res => res.text()),\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport function provideLocalization(config: Partial<LocalizationConfig>, ...features: LocalizationFeature[]): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideLocalizationConfig(config),\n {\n provide: APP_INITIALIZER,\n useFactory: (localizationService: LocalizationService) => () => localizationService.loadActiveLanguage(),\n deps: [LocalizationService],\n multi: true,\n },\n features,\n ]);\n}\n","import { Logger } from '@odx/angular/internal';\n\nexport default new Logger('@odx/angular/localization');\n","import { Injectable, Injector, inject, runInInjectionContext } from '@angular/core';\nimport { BehaviorSubject, Observable, distinctUntilChanged, filter, firstValueFrom, from, isObservable, map, of, shareReplay } from 'rxjs';\nimport { injectLocalizationConfig } from './localization.config';\nimport logger from './localization.logger';\n\n@Injectable({ providedIn: 'root' })\nexport class LocalizationService {\n private readonly localizationConfig = injectLocalizationConfig();\n private readonly injector = inject(Injector);\n private readonly localeState$ = new BehaviorSubject<Intl.Locale | undefined>(new Intl.Locale(this.localizationConfig.availableLanguages[0]));\n\n /**\n * Represents an observable stream of the active language in the localization service.\n * The active language is determined by the locale state.\n *\n * @emits {string} The active language.\n */\n public readonly activeLanguage$ = this.localeState$.pipe(\n filter(Boolean),\n map((x) => x.baseName),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n\n /**\n * Gets the list of available languages for localization.\n *\n * @type {string[]} The list of available languages.\n */\n public readonly availableLanguages = this.localizationConfig.availableLanguages;\n\n /** Default language derived from the first entry in the available languages list.\n *\n * @type {string}\n */\n public readonly defaultLanguage = this.availableLanguages[0];\n\n /**\n * Retrieves the currently active language. Falls back to the default language if\n * no active language is set.\n *\n * @returns {string} Full locale name e.g. 'en-US' or just 'en' if no region info is attached.\n */\n public getActiveLanguage(): string {\n return this.localeState$.getValue()?.baseName ?? new Intl.Locale(this.defaultLanguage).baseName;\n }\n\n /**\n * Retrieves the active language subtag.\n *\n * @returns {string} The two-digit language subtag, e.g. 'en', 'fr'.\n */\n public getActiveLanguageSubtag(): string {\n return this.localeState$.getValue()?.language ?? new Intl.Locale(this.defaultLanguage).language;\n }\n\n /**\n * Sets the active language based on the provided language code. If the language is not\n * recognized, it logs an error and does not change the active language.\n *\n * @param {string} language The language code to set as the active language.\n */\n public setActiveLanguage(language: string): void {\n try {\n const locale = new Intl.Locale(language);\n if (this.availableLanguages.includes(locale.baseName)) {\n this.localeState$.next(locale);\n } else if (this.availableLanguages.includes(locale.language)) {\n this.localeState$.next(new Intl.Locale(locale.language));\n } else {\n throw new Error(`Unrecognizable language '${language}'. Make sure it's a part of availableLanguages inside LocalizationService config.`);\n }\n } catch (error) {\n logger.error(error);\n }\n }\n\n /**\n * Loads the active language for the localization service.\n * This method runs in an injection context and sets the active language based on the result of the active language loader.\n * If the active language loader fails, the default language is set as the active language.\n *\n * @returns {Promise<void>} A promise that resolves when the active language is loaded and set.\n */\n public async loadActiveLanguage(): Promise<void> {\n return runInInjectionContext(this.injector, async () => {\n const activeLanguageLoader$ = this.createActiveLanguageLoader$();\n const activeLanguage = await firstValueFrom(activeLanguageLoader$).catch(() => null);\n this.setActiveLanguage(activeLanguage ?? this.defaultLanguage);\n });\n }\n\n private createActiveLanguageLoader$(): Observable<string | undefined> {\n const language = this.localizationConfig.activeLanguageLoader?.();\n if (isObservable(language)) {\n return language;\n }\n if (language instanceof Promise) {\n return from(language);\n }\n return of(language);\n }\n}\n","import { EnvironmentProviders, Provider } from '@angular/core';\n\nexport type LocalizationFeature = EnvironmentProviders & { ɵodxBrand: '@odx/angular/localization::LocalizationFeature' };\n\n/**\n * @internal\n * Creates a feature provider for the localization module.\n *\n * @param {Provider[] | EnvironmentProviders} provider - The providers to be used for the localization feature.\n * @returns {LocalizationFeature} The localization feature provider.\n */\nexport function makeLocalizationFeature(provider: Provider[] | EnvironmentProviders): LocalizationFeature {\n return provider as never as LocalizationFeature;\n}\n","import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { matchUrl } from '@odx/angular/utils';\nimport { switchMap, take } from 'rxjs';\nimport { LocalizationService } from '../localization.service';\nimport { LocalizationFeature, makeLocalizationFeature } from '../models';\n\nexport const HTTP_LANGUAGE_HEADER = 'Accept-Language';\n\n/**\n * Configuration object for the HTTP language header interceptor. It specifies which URLs\n * the interceptor should apply to and allows customizing the name of the header used to transmit\n * the current language setting.\n *\n * @property {Array<string | RegExp>} allowedUrls - An array of strings or RegExp patterns\n * indicating the URLs to which the language header should be added.\n * @property {string} [headerName=HTTP_LANGUAGE_HEADER] - Optional. The name of the HTTP header\n * through which the current language setting will be transmitted. Defaults to 'Accept-Language'.\n */\nexport interface HttpLanguageHeaderInterceptorConfig {\n allowedUrls: Array<string | RegExp>;\n headerName?: string;\n}\n\n/**\n * Creates an HTTP interceptor function that adds a language header to outgoing HTTP requests,\n * but only for URLs matching the provided criteria. This allows the server to respond with\n * resources localized in the user's current language.\n *\n * @param {HttpLanguageHeaderInterceptorConfig} config - The configuration for the interceptor,\n * including the list of allowed URLs and optionally a custom header name.\n * @returns {HttpInterceptorFn} An Angular HTTP interceptor function that conditionally adds\n * the current language as an HTTP header based on the request URL.\n *\n * @example\n * ```ts\n * // Use in HTTP client module setup\n * import { HttpClientModule } from '@angular/common/http';\n * import { httpLanguageHeaderInterceptor, HTTP_LANGUAGE_HEADER } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [HttpClientModule],\n * providers: [\n * provideHttpClient(withInterceptors([\n * httpLanguageHeaderInterceptor({ allowedUrls: ['/api'], headerName: HTTP_LANGUAGE_HEADER })\n * ]))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function httpLanguageHeaderInterceptor({ allowedUrls, headerName }: HttpLanguageHeaderInterceptorConfig): HttpInterceptorFn {\n return (req, next) => {\n const language$ = inject(LocalizationService).activeLanguage$.pipe(take(1));\n for (const allowedUrl of allowedUrls) {\n if (!matchUrl(req.url, allowedUrl)) continue;\n return language$.pipe(switchMap((language) => next(req.clone({ setHeaders: { [headerName ?? HTTP_LANGUAGE_HEADER]: language } }))));\n }\n return next(req);\n };\n}\n\n/**\n * Provides a localization feature that automatically adds a language header to HTTP requests\n * for specified URLs, using the current active language. This function simplifies setting up\n * the HTTP language header interceptor by wrapping it into a LocalizationFeature, making it easy\n * to integrate with the application's localization infrastructure.\n *\n * @param {HttpLanguageHeaderInterceptorConfig} config - The configuration for the language header\n * interceptor, specifying which URLs should include the language header and optionally defining a\n * custom header name.\n * @returns {LocalizationFeature} A localization feature object that can be used to configure\n * the application's localization settings to include automatic language header addition for HTTP requests.\n *\n * @example\n * ```ts\n * // Example usage with the localization provider\n * import { provideLocalization, LocalizationModule, withHttpLanguageHeader } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [LocalizationModule],\n * providers: [\n * provideLocalization({}, withHttpLanguageHeader({ allowedUrls: ['/api'] }))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function withHttpLanguageHeader(config: HttpLanguageHeaderInterceptorConfig): LocalizationFeature {\n const providers = provideHttpClient(withInterceptors([httpLanguageHeaderInterceptor(config)]));\n\n return makeLocalizationFeature(providers);\n}\n","import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { matchUrl } from '@odx/angular/utils';\nimport { switchMap, take } from 'rxjs';\nimport { LocalizationService } from '../localization.service';\nimport { LocalizationFeature, makeLocalizationFeature } from '../models';\n\nexport const HTTP_LANGUAGE_QUERY = 'language';\n\n/**\n * Defines the configuration options for the HTTP interceptor that appends the current\n * language setting as a query parameter to outgoing requests. This configuration specifies\n * which requests should have the language parameter appended based on their URLs.\n *\n * @property {Array<string | RegExp>} allowedUrls - URLs (or patterns matching URLs) to which\n * the language query parameter should be appended.\n * @property {string} [queryParamName=HTTP_LANGUAGE_QUERY] - The name of the query parameter\n * used to transmit the current language. Defaults to 'language'.\n */\nexport interface HttpLanguageQueryParamInterceptorConfig {\n allowedUrls: Array<string | RegExp>;\n queryParamName?: string;\n}\n\n/**\n * Creates an HTTP interceptor function that appends the current language as a query parameter\n * to outgoing HTTP requests that match specified URLs. This interceptor enables dynamic content\n * localization by informing the backend of the user's preferred language.\n *\n * @param {HttpLanguageQueryParamInterceptorConfig} config - Configuration for the interceptor,\n * including allowed URLs and an optional custom name for the query parameter.\n * @returns {HttpInterceptorFn} The interceptor function ready to be applied to the HTTP client.\n *\n * @example\n * ```ts\n * // Applying the interceptor in an Angular module\n * import { HttpClientModule } from '@angular/common/http';\n * import { withHttpLanguageQueryParam } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [HttpClientModule],\n * providers: [\n * provideHttpClient(withInterceptors([\n * withHttpLanguageQueryParam({ allowedUrls: ['/api/resources'] })\n * ]))\n * ]\n * })\n * export class ApiModule {}\n * ```\n */\nexport function withHttpLanguageQueryParamInterceptor({ allowedUrls, queryParamName }: HttpLanguageQueryParamInterceptorConfig): HttpInterceptorFn {\n return (req, next) => {\n const language$ = inject(LocalizationService).activeLanguage$.pipe(take(1));\n for (const allowedUrl of allowedUrls) {\n if (!matchUrl(req.url, allowedUrl)) continue;\n return language$.pipe(switchMap((language) => next(req.clone({ setParams: { [queryParamName ?? HTTP_LANGUAGE_QUERY]: language } }))));\n }\n return next(req);\n };\n}\n\n/**\n * Registers the HTTP interceptor that appends the current language as a query parameter to\n * outgoing requests for configured URLs as a localization feature. This utility function\n * simplifies the setup by bundling the interceptor into a feature that can be easily integrated\n * with localization configurations.\n *\n * @param {HttpLanguageQueryParamInterceptorConfig} config - Configuration for appending the\n * language query parameter, including allowed URLs and an optional parameter name.\n * @returns {LocalizationFeature} A localization feature encapsulating the interceptor, ready\n * for integration with the application's localization setup.\n *\n * @example\n * ```ts\n * // Integrating the localization feature in an Angular module\n * import { provideLocalization } from '@angular/core';\n * import { withHttpLanguageQueryParam } from '@odx/angular/localization';\n *\n * @NgModule({\n * providers: [\n * provideLocalization({}, withHttpLanguageQueryParam({ allowedUrls: ['/api'] }))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function withHttpLanguageQueryParam(config: HttpLanguageQueryParamInterceptorConfig): LocalizationFeature {\n const providers = provideHttpClient(withInterceptors([withHttpLanguageQueryParamInterceptor(config)]));\n\n return makeLocalizationFeature(providers);\n}\n","import { inject } from '@angular/core';\nimport { WindowRef } from '@odx/angular';\nimport { LanguageLoaderFn } from '../models';\n\n/**\n * Asynchronously loads the browser's current language setting by utilizing the `WindowRef` service.\n * This function is intended to be used as a dynamic language loader within a localization configuration,\n * allowing applications to automatically adapt to the user's preferred language as specified in their\n * browser settings.\n *\n * The `WindowRef` service abstracts window-related operations, making it easier to interact with global\n * browser properties and methods in a testable and platform-agnostic way. This function makes use of\n * `WindowRef` to access the navigator's language setting in a safe and Angular-friendly manner.\n *\n * @returns {Promise<string>} A promise that resolves to the language code (e.g., 'en', 'fr') of the\n * browser's currently configured language. This can then be used to set the active language in a\n * localization configuration.\n *\n * @example\n * ```ts\n * // Example usage in a localization configuration\n * import { provideLocalization } from '@odx/angular/utils';\n * import { browserLanguageLoader } from '@odx/angular/localization';\n *\n * @NgModule({\n * providers: [\n * provideLocalization({\n * activeLanguageLoader: browserLanguageLoader,\n * availableLanguages: ['en', 'es', 'fr'],\n * availableLocales: ['en-US', 'es-ES', 'fr-FR']\n * })\n * ]\n * })\n * export class AppModule { }\n * ```\n */\nexport const browserLanguageLoader: LanguageLoaderFn = async () => {\n return inject(WindowRef).getLanguage();\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"odx-angular-localization.mjs","sources":["../../../../libs/angular/localization/src/lib/localization.config.ts","../../../../libs/angular/localization/src/lib/localization.logger.ts","../../../../libs/angular/localization/src/lib/localization.service.ts","../../../../libs/angular/localization/src/lib/models/localization-feature.ts","../../../../libs/angular/localization/src/lib/features/with-http-language-header.ts","../../../../libs/angular/localization/src/lib/features/with-http-language-query-param.ts","../../../../libs/angular/localization/src/lib/loaders/browser-language-loader.ts","../../../../libs/angular/localization/src/odx-angular-localization.ts"],"sourcesContent":["import { APP_INITIALIZER, EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { createConfigTokens } from '@odx/angular/utils';\nimport { LocalizationService } from './localization.service';\nimport { LanguageLoaderFn, LocalizationFeature } from './models';\n\nexport const DEFAULT_AVAILABLE_LANGUAGES = ['en-US', 'en-GB', 'en', 'de-DE', 'de', 'es-ES', 'es', 'fr-FR', 'fr-CA', 'fr'];\n\n/**\n * Defines the structure for the localization configuration used throughout the application.\n * It allows specifying available languages, and includes an optional loader\n * function for dynamically determining the active language.\n *\n * @property {LanguageLoaderFn} [activeLanguageLoader] Optional function for loading the\n * active language dynamically, useful for scenarios where the application's language\n * needs to be determined based on user settings, browser settings, or external data.\n * @property {string[]} availableLanguages An array of language codes representing the\n * languages available in the application.\n */\nexport interface LocalizationConfig {\n activeLanguageLoader?: LanguageLoaderFn;\n availableLanguages: string[];\n}\n\n/**\n * Utilizes `createConfigTokens` to generate configuration tokens and related utilities for the\n * localization settings within the application. It defines a structured and type-safe approach\n * for managing localization configurations, such as available languages, and potentially\n * a dynamic loader for the active language. The generated tokens and utilities facilitate accessing\n * and providing these configurations throughout the application.\n *\n * @const {InjectionToken<LocalizationConfig>} LocalizationConfig - An InjectionToken for accessing\n * the localization configuration within Angular's dependency injection framework. Use this token to inject\n * localization configurations into services, components, or other tokens.\n *\n * @const {LocalizationConfig} LocalizationDefaultConfig - The default configuration values for localization,\n * based on the provided settings. Includes the default available languages.\n *\n * @const {Function} injectLocalizationConfig - A utility function that returns the injected value of\n * `LocalizationConfig` token. Use this function to access the current localization configuration in\n * a type-safe manner.\n *\n * @const {Function} provideLocalizationConfig - A utility function to provide the `LocalizationConfig` token\n * with specific values. Use this function to configure and override default localization settings within\n * an Angular module or component.\n *\n * @example\n * ```ts\n * // Providing localization settings in an Angular module\n * @NgModule({\n * providers: [\n * provideLocalizationConfig({\n * availableLanguages: ['en', 'es', 'fr'],\n * })\n * ]\n * })\n * export class AppModule { }\n *\n * // Injecting and using the localization configuration in a service\n * @Injectable({ providedIn: 'root' })\n * export class MyLocalizationService {\n * constructor(@Inject(LocalizationConfig) private config: LocalizationConfig) {\n * console.log('Available languages:', config.availableLanguages);\n * }\n * }\n * ```\n */\nexport const { LocalizationConfig, LocalizationDefaultConfig, injectLocalizationConfig, provideLocalizationConfig } = createConfigTokens(\n 'Localization',\n '@odx/angular/internal/translate',\n {\n availableLanguages: DEFAULT_AVAILABLE_LANGUAGES,\n } as LocalizationConfig,\n);\n\n/**\n * Sets up the localization configuration for the application and initializes the localization\n * system with the provided configuration and features. This function is typically called\n * within the main module or a core module of the application to ensure localization settings\n * are available and active as early as possible.\n *\n * @param {Partial<LocalizationConfig>} config The localization configuration settings, including\n * available languages and optionally, a custom loader for the active language.\n * @param {...LocalizationFeature[]} features Additional localization features or configurations\n * to be registered as part of the application's environment providers.\n * @returns {EnvironmentProviders} A collection of providers for setting up the application's\n * localization environment, to be used with Angular's environment-specific injector configuration.\n * @example\n * ```ts\n * // Example of providing localization settings in an Angular module\n * @NgModule({\n * imports: [...],\n * providers: [\n * provideLocalization({\n * availableLanguages: ['en', 'es', 'fr'],\n * activeLanguageLoader: () => fetch('/api/user/language').then(res => res.text()),\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport function provideLocalization(config: Partial<LocalizationConfig>, ...features: LocalizationFeature[]): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideLocalizationConfig(config),\n {\n provide: APP_INITIALIZER,\n useFactory: (localizationService: LocalizationService) => () => localizationService.loadActiveLanguage(),\n deps: [LocalizationService],\n multi: true,\n },\n features,\n ]);\n}\n","import { Logger } from '@odx/angular/internal';\n\nexport default new Logger('@odx/angular/localization');\n","import { Injectable, Injector, inject, runInInjectionContext } from '@angular/core';\nimport { BehaviorSubject, Observable, distinctUntilChanged, filter, firstValueFrom, from, isObservable, map, of, shareReplay } from 'rxjs';\nimport { injectLocalizationConfig } from './localization.config';\nimport logger from './localization.logger';\n\n@Injectable({ providedIn: 'root' })\nexport class LocalizationService {\n private readonly localizationConfig = injectLocalizationConfig();\n private readonly injector = inject(Injector);\n private readonly localeState$ = new BehaviorSubject<Intl.Locale | undefined>(new Intl.Locale(this.localizationConfig.availableLanguages[0]));\n\n /**\n * Represents an observable stream of the active language in the localization service.\n * The active language is determined by the locale state.\n *\n * @emits {string} The active language.\n */\n public readonly activeLanguage$ = this.localeState$.pipe(\n filter(Boolean),\n map((x) => x.baseName),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n\n /**\n * Gets the list of available languages for localization.\n *\n * @type {string[]} The list of available languages.\n */\n public readonly availableLanguages = this.localizationConfig.availableLanguages;\n\n /** Default language derived from the first entry in the available languages list.\n *\n * @type {string}\n */\n public readonly defaultLanguage = this.availableLanguages[0];\n\n /**\n * Retrieves the currently active language. Falls back to the default language if\n * no active language is set.\n *\n * @returns {string} Full locale name e.g. 'en-US' or just 'en' if no region info is attached.\n */\n public getActiveLanguage(): string {\n return this.localeState$.getValue()?.baseName ?? new Intl.Locale(this.defaultLanguage).baseName;\n }\n\n /**\n * Retrieves the active language subtag.\n *\n * @returns {string} The two-digit language subtag, e.g. 'en', 'fr'.\n */\n public getActiveLanguageSubtag(): string {\n return this.localeState$.getValue()?.language ?? new Intl.Locale(this.defaultLanguage).language;\n }\n\n /**\n * Sets the active language based on the provided language code. If the language is not\n * recognized, it logs an error and does not change the active language.\n *\n * @param {string} language The language code to set as the active language.\n */\n public setActiveLanguage(language: string): void {\n try {\n const locale = new Intl.Locale(language);\n if (this.availableLanguages.includes(locale.baseName)) {\n this.localeState$.next(locale);\n } else if (this.availableLanguages.includes(locale.language)) {\n this.localeState$.next(new Intl.Locale(locale.language));\n } else {\n throw new Error(`Unrecognizable language '${language}'. Make sure it's a part of availableLanguages inside LocalizationService config.`);\n }\n } catch (error) {\n logger.error(error);\n }\n }\n\n /**\n * Loads the active language for the localization service.\n * This method runs in an injection context and sets the active language based on the result of the active language loader.\n * If the active language loader fails, the default language is set as the active language.\n *\n * @returns {Promise<void>} A promise that resolves when the active language is loaded and set.\n */\n public async loadActiveLanguage(): Promise<void> {\n return runInInjectionContext(this.injector, async () => {\n const activeLanguageLoader$ = this.createActiveLanguageLoader$();\n const activeLanguage = await firstValueFrom(activeLanguageLoader$).catch(() => null);\n this.setActiveLanguage(activeLanguage ?? this.defaultLanguage);\n });\n }\n\n private createActiveLanguageLoader$(): Observable<string | undefined> {\n const language = this.localizationConfig.activeLanguageLoader?.();\n if (isObservable(language)) {\n return language;\n }\n if (language instanceof Promise) {\n return from(language);\n }\n return of(language);\n }\n}\n","import { EnvironmentProviders, Provider } from '@angular/core';\n\nexport type LocalizationFeature = EnvironmentProviders & { ɵodxBrand: '@odx/angular/localization::LocalizationFeature' };\n\n/**\n * @internal\n * Creates a feature provider for the localization module.\n *\n * @param {Provider[] | EnvironmentProviders} provider - The providers to be used for the localization feature.\n * @returns {LocalizationFeature} The localization feature provider.\n */\nexport function makeLocalizationFeature(provider: Provider[] | EnvironmentProviders): LocalizationFeature {\n return provider as never as LocalizationFeature;\n}\n","import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { matchUrl } from '@odx/angular/utils';\nimport { switchMap, take } from 'rxjs';\nimport { LocalizationService } from '../localization.service';\nimport { LocalizationFeature, makeLocalizationFeature } from '../models';\n\nexport const HTTP_LANGUAGE_HEADER = 'Accept-Language';\n\n/**\n * Configuration object for the HTTP language header interceptor. It specifies which URLs\n * the interceptor should apply to and allows customizing the name of the header used to transmit\n * the current language setting.\n *\n * @property {Array<string | RegExp>} allowedUrls - An array of strings or RegExp patterns\n * indicating the URLs to which the language header should be added.\n * @property {string} [headerName=HTTP_LANGUAGE_HEADER] - Optional. The name of the HTTP header\n * through which the current language setting will be transmitted. Defaults to 'Accept-Language'.\n */\nexport interface HttpLanguageHeaderInterceptorConfig {\n allowedUrls: Array<string | RegExp>;\n headerName?: string;\n}\n\n/**\n * Creates an HTTP interceptor function that adds a language header to outgoing HTTP requests,\n * but only for URLs matching the provided criteria. This allows the server to respond with\n * resources localized in the user's current language.\n *\n * @param {HttpLanguageHeaderInterceptorConfig} config - The configuration for the interceptor,\n * including the list of allowed URLs and optionally a custom header name.\n * @returns {HttpInterceptorFn} An Angular HTTP interceptor function that conditionally adds\n * the current language as an HTTP header based on the request URL.\n *\n * @example\n * ```ts\n * // Use in HTTP client module setup\n * import { HttpClientModule } from '@angular/common/http';\n * import { httpLanguageHeaderInterceptor, HTTP_LANGUAGE_HEADER } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [HttpClientModule],\n * providers: [\n * provideHttpClient(withInterceptors([\n * httpLanguageHeaderInterceptor({ allowedUrls: ['/api'], headerName: HTTP_LANGUAGE_HEADER })\n * ]))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function httpLanguageHeaderInterceptor({ allowedUrls, headerName }: HttpLanguageHeaderInterceptorConfig): HttpInterceptorFn {\n return (req, next) => {\n const language$ = inject(LocalizationService).activeLanguage$.pipe(take(1));\n for (const allowedUrl of allowedUrls) {\n if (!matchUrl(req.url, allowedUrl)) continue;\n return language$.pipe(switchMap((language) => next(req.clone({ setHeaders: { [headerName ?? HTTP_LANGUAGE_HEADER]: language } }))));\n }\n return next(req);\n };\n}\n\n/**\n * Provides a localization feature that automatically adds a language header to HTTP requests\n * for specified URLs, using the current active language. This function simplifies setting up\n * the HTTP language header interceptor by wrapping it into a LocalizationFeature, making it easy\n * to integrate with the application's localization infrastructure.\n *\n * @param {HttpLanguageHeaderInterceptorConfig} config - The configuration for the language header\n * interceptor, specifying which URLs should include the language header and optionally defining a\n * custom header name.\n * @returns {LocalizationFeature} A localization feature object that can be used to configure\n * the application's localization settings to include automatic language header addition for HTTP requests.\n *\n * @example\n * ```ts\n * // Example usage with the localization provider\n * import { provideLocalization, LocalizationModule, withHttpLanguageHeader } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [LocalizationModule],\n * providers: [\n * provideLocalization({}, withHttpLanguageHeader({ allowedUrls: ['/api'] }))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function withHttpLanguageHeader(config: HttpLanguageHeaderInterceptorConfig): LocalizationFeature {\n const providers = provideHttpClient(withInterceptors([httpLanguageHeaderInterceptor(config)]));\n\n return makeLocalizationFeature(providers);\n}\n","import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { matchUrl } from '@odx/angular/utils';\nimport { switchMap, take } from 'rxjs';\nimport { LocalizationService } from '../localization.service';\nimport { LocalizationFeature, makeLocalizationFeature } from '../models';\n\nexport const HTTP_LANGUAGE_QUERY = 'language';\n\n/**\n * Defines the configuration options for the HTTP interceptor that appends the current\n * language setting as a query parameter to outgoing requests. This configuration specifies\n * which requests should have the language parameter appended based on their URLs.\n *\n * @property {Array<string | RegExp>} allowedUrls - URLs (or patterns matching URLs) to which\n * the language query parameter should be appended.\n * @property {string} [queryParamName=HTTP_LANGUAGE_QUERY] - The name of the query parameter\n * used to transmit the current language. Defaults to 'language'.\n */\nexport interface HttpLanguageQueryParamInterceptorConfig {\n allowedUrls: Array<string | RegExp>;\n queryParamName?: string;\n}\n\n/**\n * Creates an HTTP interceptor function that appends the current language as a query parameter\n * to outgoing HTTP requests that match specified URLs. This interceptor enables dynamic content\n * localization by informing the backend of the user's preferred language.\n *\n * @param {HttpLanguageQueryParamInterceptorConfig} config - Configuration for the interceptor,\n * including allowed URLs and an optional custom name for the query parameter.\n * @returns {HttpInterceptorFn} The interceptor function ready to be applied to the HTTP client.\n *\n * @example\n * ```ts\n * // Applying the interceptor in an Angular module\n * import { HttpClientModule } from '@angular/common/http';\n * import { withHttpLanguageQueryParam } from '@odx/angular/localization';\n *\n * @NgModule({\n * imports: [HttpClientModule],\n * providers: [\n * provideHttpClient(withInterceptors([\n * withHttpLanguageQueryParam({ allowedUrls: ['/api/resources'] })\n * ]))\n * ]\n * })\n * export class ApiModule {}\n * ```\n */\nexport function withHttpLanguageQueryParamInterceptor({ allowedUrls, queryParamName }: HttpLanguageQueryParamInterceptorConfig): HttpInterceptorFn {\n return (req, next) => {\n const language$ = inject(LocalizationService).activeLanguage$.pipe(take(1));\n for (const allowedUrl of allowedUrls) {\n if (!matchUrl(req.url, allowedUrl)) continue;\n return language$.pipe(switchMap((language) => next(req.clone({ setParams: { [queryParamName ?? HTTP_LANGUAGE_QUERY]: language } }))));\n }\n return next(req);\n };\n}\n\n/**\n * Registers the HTTP interceptor that appends the current language as a query parameter to\n * outgoing requests for configured URLs as a localization feature. This utility function\n * simplifies the setup by bundling the interceptor into a feature that can be easily integrated\n * with localization configurations.\n *\n * @param {HttpLanguageQueryParamInterceptorConfig} config - Configuration for appending the\n * language query parameter, including allowed URLs and an optional parameter name.\n * @returns {LocalizationFeature} A localization feature encapsulating the interceptor, ready\n * for integration with the application's localization setup.\n *\n * @example\n * ```ts\n * // Integrating the localization feature in an Angular module\n * import { provideLocalization } from '@angular/core';\n * import { withHttpLanguageQueryParam } from '@odx/angular/localization';\n *\n * @NgModule({\n * providers: [\n * provideLocalization({}, withHttpLanguageQueryParam({ allowedUrls: ['/api'] }))\n * ]\n * })\n * export class AppModule {}\n * ```\n */\nexport function withHttpLanguageQueryParam(config: HttpLanguageQueryParamInterceptorConfig): LocalizationFeature {\n const providers = provideHttpClient(withInterceptors([withHttpLanguageQueryParamInterceptor(config)]));\n\n return makeLocalizationFeature(providers);\n}\n","import { inject } from '@angular/core';\nimport { WindowRef } from '@odx/angular';\nimport { LanguageLoaderFn } from '../models';\n\n/**\n * Asynchronously loads the browser's current language setting by utilizing the `WindowRef` service.\n * This function is intended to be used as a dynamic language loader within a localization configuration,\n * allowing applications to automatically adapt to the user's preferred language as specified in their\n * browser settings.\n *\n * The `WindowRef` service abstracts window-related operations, making it easier to interact with global\n * browser properties and methods in a testable and platform-agnostic way. This function makes use of\n * `WindowRef` to access the navigator's language setting in a safe and Angular-friendly manner.\n *\n * @returns {Promise<string>} A promise that resolves to the language code (e.g., 'en', 'fr') of the\n * browser's currently configured language. This can then be used to set the active language in a\n * localization configuration.\n *\n * @example\n * ```ts\n * // Example usage in a localization configuration\n * import { provideLocalization } from '@odx/angular/utils';\n * import { browserLanguageLoader } from '@odx/angular/localization';\n *\n * @NgModule({\n * providers: [\n * provideLocalization({\n * activeLanguageLoader: browserLanguageLoader,\n * availableLanguages: ['en', 'es', 'fr'],\n * availableLocales: ['en-US', 'es-ES', 'fr-FR']\n * })\n * ]\n * })\n * export class AppModule { }\n * ```\n */\nexport const browserLanguageLoader: LanguageLoaderFn = async () => {\n return inject(WindowRef).getLanguage();\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"odx-angular-rxjs.mjs","sources":["../../../../libs/angular/rxjs/src/lib/delay-until.ts","../../../../libs/angular/rxjs/src/lib/from-element-mutation.ts","../../../../libs/angular/rxjs/src/lib/from-element-resize.ts","../../../../libs/angular/rxjs/src/lib/from-events.ts","../../../../libs/angular/rxjs/src/lib/from-query-list.ts","../../../../libs/angular/rxjs/src/odx-angular-rxjs.ts"],"sourcesContent":["import { map, MonoTypeOperatorFunction, Observable, switchMap, takeUntil, timer } from 'rxjs';\n\n/**\n * Delays the emission of each value from the source Observable by a time span determined by the `delay` function.\n * If the `notifier` Observable emits before the delay expires, the delayed emission is cancelled.\n *\n * This operator is useful for postponing the observable emissions until certain conditions are met,\n * represented by the passage of time defined by `delay`. It also allows for a way to preemptively\n * cancel the delay in response to another observable's emission.\n *\n * @template T The type of items emitted by the source Observable.\n * @param {() => number} delay A function that returns the delay (in milliseconds) before the source Observable's values are emitted.\n * @param {Observable<unknown>} notifier An Observable that cancels the delay when it emits.\n * @returns {MonoTypeOperatorFunction<T>} An Observable that emits the source Observable's items with a delay if not cancelled.\n * @example\n * ```ts\n * // Delay each number emission by 1 second, unless the 'cancel' button is clicked.\n * const delayedNumbers$ = of(1, 2, 3).pipe(\n * delayUntil(() => 1000, fromEvent(cancelButton, 'click'))\n * );\n *\n * delayedNumbers$.subscribe(console.log);\n * ```\n */\nexport function delayUntil<T>(delay: () => number, notifier: Observable<unknown>): MonoTypeOperatorFunction<T> {\n return (source$: Observable<T>) =>\n source$.pipe(\n switchMap((value: T) =>\n timer(delay()).pipe(\n map(() => value),\n takeUntil(notifier),\n ),\n ),\n );\n}\n","import { createMutationObserver } from '@odx/angular/utils';\nimport { Observable } from 'rxjs';\n\n/**\n * Creates an RxJS Observable that emits mutation records for changes in a DOM element's attributes,\n * child list, and subtree. It uses the `MutationObserver` Web API to observe mutations on the specified\n * element according to the options provided.\n *\n * @param {Element} element The DOM element to observe for mutations.\n * @param {MutationObserverInit} options An object that specifies which DOM mutations should be reported.\n * Options include attributes, childList, subtree, attributeOldValue, characterData, characterDataOldValue,\n * and attributeFilter.\n * @returns {Observable<MutationRecord>} An Observable that emits a `MutationRecord` each time a mutation\n * matching the specified options occurs in the observed element.\n * @example\n * ```ts\n * // Observing changes to the child list of an element\n * const element = document.getElementById('my-element');\n * const mutationOptions = { childList: true };\n *\n * fromElementMutation$(element, mutationOptions).subscribe((mutation) => console.log('Mutation detected:', mutation));\n * ```\n * Note: Always remember to unsubscribe from the observable to prevent memory leaks.\n */\nexport function fromElementMutation$(element: Element, options: MutationObserverInit): Observable<MutationRecord> {\n return new Observable<MutationRecord>((observer) => {\n const mutationObserver = createMutationObserver(observer, (events) => events.length > 0);\n observer.add(() => mutationObserver.disconnect());\n mutationObserver.observe(element, options);\n });\n}\n","import { createResizeObserver } from '@odx/angular/utils';\nimport { debounceTime, Observable } from 'rxjs';\n\n/**\n * Creates an RxJS Observable that emits an array of `ResizeObserverEntry` objects whenever\n * the target element's size changes. This function provides a reactive way to observe\n * and respond to changes in an element's dimensions, using the `ResizeObserver` Web API.\n *\n * The observable debounces the emitted values to improve performance and reduce the frequency\n * of change detection runs in Angular applications. The debounce time can be adjusted via\n * the `debounceDuration` parameter.\n *\n * @param {Element} element The DOM element to observe for size changes.\n * @param {number} [debounceDuration=50] The time, in milliseconds, to debounce the emitted\n * values. Defaults to 50ms.\n * @returns {Observable<ResizeObserverEntry[]>} An Observable that emits the resize events\n * for the observed element. Each emission is an array of `ResizeObserverEntry` objects, one\n * for each observed element that experienced a resize.\n * @example\n * ```ts\n * // Observing resize events of an element with a 100ms debounce duration\n * const element = document.getElementById('resizable-element');\n * fromElementResize$(element, 100).subscribe((entries) => console.log('Element resized:', entries));\n * ```\n *\n * Always unsubscribe from the observable to clean up resources and prevent memory leaks.\n */\nexport function fromElementResize$(element: Element, debounceDuration = 50): Observable<ResizeObserverEntry[]> {\n return new Observable<ResizeObserverEntry[]>((observer) => {\n const resizeObserver = createResizeObserver((events) => {\n if (events.length > 0) {\n observer.next(events);\n }\n });\n observer.add(() => resizeObserver.disconnect());\n resizeObserver.observe(element);\n }).pipe(debounceTime(debounceDuration));\n}\n","import { fromEvent, merge, Observable } from 'rxjs';\nimport { HasEventTargetAddRemove } from 'rxjs/internal/observable/fromEvent';\n\n/**\n * Creates an Observable that emits events of a specific type from one or multiple event targets.\n * It listens to multiple event types on the given target(s) and emits the events through a single\n * Observable stream, simplifying the handling of related event types.\n *\n * @template T The event object type that the Observable will emit.\n * @param {HasEventTargetAddRemove<T> | HasEventTargetAddRemove<T>[]} target The DOM element(s) or event target(s) to listen on.\n * @param {...string[]} events The names of the events to listen for on the target(s).\n * @returns {Observable<T>} An Observable that emits an event each time one of the specified events occurs on the given target(s).\n *\n * @example\n * ```ts\n * // Listen to both 'click' and 'keyup' events on document\n * fromEvents(document, 'click', 'keyup').subscribe(event => {\n * console.log('Event occurred:', event);\n * });\n *\n * // Listen to 'mousemove' event on multiple elements\n * const elements = [document.getElementById('first'), document.getElementById('second')];\n * fromEvents(elements, 'mousemove').subscribe(event => {\n * console.log('Mouse moved over:', event.target);\n * });\n * ```\n */\nexport function fromEvents<T>(target: HasEventTargetAddRemove<T> | HasEventTargetAddRemove<T>[], ...events: string[]): Observable<T> {\n return merge(...events.map((event) => fromEvent(target, event)));\n}\n","import { QueryList } from '@angular/core';\nimport { Observable, startWith } from 'rxjs';\n\n/**\n * Creates an Observable from an Angular QueryList. The Observable emits the initial state\n * of the QueryList and continues to emit updates every time the QueryList changes.\n * This utility function is useful for integrating Angular's QueryList changes into\n * the RxJS reactive data flow, allowing developers to apply RxJS operators and\n * subscriptions to respond to QueryList updates.\n *\n * @template T The type of elements contained within the QueryList.\n * @param {QueryList<T>} queryList The QueryList instance to observe.\n * @returns {Observable<QueryList<T>>} An Observable that emits the current state of the QueryList\n * and updates whenever the QueryList changes.\n * @example\n * ```ts\n * // Assuming 'items' is a QueryList of component instances or DOM elements\n * fromQueryList(items).subscribe(queryList => {\n * console.log('QueryList changed:', queryList);\n * });\n * ```\n */\nexport function fromQueryList<T>(queryList: QueryList<T>): Observable<QueryList<T>> {\n return queryList.changes.pipe(startWith(queryList));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACa,SAAA,UAAU,CAAI,KAAmB,EAAE,QAA6B,EAAA;AAC9E,IAAA,OAAO,CAAC,OAAsB,KAC5B,OAAO,CAAC,IAAI,CACV,SAAS,CAAC,CAAC,KAAQ,KACjB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CACjB,GAAG,CAAC,MAAM,KAAK,CAAC,EAChB,SAAS,CAAC,QAAQ,CAAC,CACpB,CACF,CACF,CAAC;AACN;;AC/BA;;;;;;;;;;;;;;;;;;;;AAoBG;AACa,SAAA,oBAAoB,CAAC,OAAgB,EAAE,OAA6B,EAAA;AAClF,IAAA,OAAO,IAAI,UAAU,CAAiB,CAAC,QAAQ,KAAI;AACjD,QAAA,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzF,QAAQ,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAC;AAClD,QAAA,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC7C,KAAC,CAAC,CAAC;AACL;;AC3BA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;SACa,kBAAkB,CAAC,OAAgB,EAAE,gBAAgB,GAAG,EAAE,EAAA;AACxE,IAAA,OAAO,IAAI,UAAU,CAAwB,CAAC,QAAQ,KAAI;AACxD,QAAA,MAAM,cAAc,GAAG,oBAAoB,CAAC,CAAC,MAAM,KAAI;AACrD,YAAA,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;AACrB,gBAAA,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;aACvB;AACH,SAAC,CAAC,CAAC;QACH,QAAQ,CAAC,GAAG,CAAC,MAAM,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC;AAChD,QAAA,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;KACjC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC1C;;AClCA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;SACa,UAAU,CAAI,MAAiE,EAAE,GAAG,MAAgB,EAAA;IAClH,OAAO,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AACnE;;AC1BA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,aAAa,CAAI,SAAuB,EAAA;IACtD,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;AACtD;;ACxBA;;AAEG;;;;"}
1
+ {"version":3,"file":"odx-angular-rxjs.mjs","sources":["../../../../libs/angular/rxjs/src/lib/delay-until.ts","../../../../libs/angular/rxjs/src/lib/from-element-mutation.ts","../../../../libs/angular/rxjs/src/lib/from-element-resize.ts","../../../../libs/angular/rxjs/src/lib/from-events.ts","../../../../libs/angular/rxjs/src/lib/from-query-list.ts","../../../../libs/angular/rxjs/src/odx-angular-rxjs.ts"],"sourcesContent":["import { map, MonoTypeOperatorFunction, Observable, switchMap, takeUntil, timer } from 'rxjs';\n\n/**\n * Delays the emission of each value from the source Observable by a time span determined by the `delay` function.\n * If the `notifier` Observable emits before the delay expires, the delayed emission is cancelled.\n *\n * This operator is useful for postponing the observable emissions until certain conditions are met,\n * represented by the passage of time defined by `delay`. It also allows for a way to preemptively\n * cancel the delay in response to another observable's emission.\n *\n * @template T The type of items emitted by the source Observable.\n * @param {() => number} delay A function that returns the delay (in milliseconds) before the source Observable's values are emitted.\n * @param {Observable<unknown>} notifier An Observable that cancels the delay when it emits.\n * @returns {MonoTypeOperatorFunction<T>} An Observable that emits the source Observable's items with a delay if not cancelled.\n * @example\n * ```ts\n * // Delay each number emission by 1 second, unless the 'cancel' button is clicked.\n * const delayedNumbers$ = of(1, 2, 3).pipe(\n * delayUntil(() => 1000, fromEvent(cancelButton, 'click'))\n * );\n *\n * delayedNumbers$.subscribe(console.log);\n * ```\n */\nexport function delayUntil<T>(delay: () => number, notifier: Observable<unknown>): MonoTypeOperatorFunction<T> {\n return (source$: Observable<T>) =>\n source$.pipe(\n switchMap((value: T) =>\n timer(delay()).pipe(\n map(() => value),\n takeUntil(notifier),\n ),\n ),\n );\n}\n","import { createMutationObserver } from '@odx/angular/utils';\nimport { Observable } from 'rxjs';\n\n/**\n * Creates an RxJS Observable that emits mutation records for changes in a DOM element's attributes,\n * child list, and subtree. It uses the `MutationObserver` Web API to observe mutations on the specified\n * element according to the options provided.\n *\n * @param {Element} element The DOM element to observe for mutations.\n * @param {MutationObserverInit} options An object that specifies which DOM mutations should be reported.\n * Options include attributes, childList, subtree, attributeOldValue, characterData, characterDataOldValue,\n * and attributeFilter.\n * @returns {Observable<MutationRecord>} An Observable that emits a `MutationRecord` each time a mutation\n * matching the specified options occurs in the observed element.\n * @example\n * ```ts\n * // Observing changes to the child list of an element\n * const element = document.getElementById('my-element');\n * const mutationOptions = { childList: true };\n *\n * fromElementMutation$(element, mutationOptions).subscribe((mutation) => console.log('Mutation detected:', mutation));\n * ```\n * Note: Always remember to unsubscribe from the observable to prevent memory leaks.\n */\nexport function fromElementMutation$(element: Element, options: MutationObserverInit): Observable<MutationRecord> {\n return new Observable<MutationRecord>((observer) => {\n const mutationObserver = createMutationObserver(observer, (events) => events.length > 0);\n observer.add(() => mutationObserver.disconnect());\n mutationObserver.observe(element, options);\n });\n}\n","import { createResizeObserver } from '@odx/angular/utils';\nimport { debounceTime, Observable } from 'rxjs';\n\n/**\n * Creates an RxJS Observable that emits an array of `ResizeObserverEntry` objects whenever\n * the target element's size changes. This function provides a reactive way to observe\n * and respond to changes in an element's dimensions, using the `ResizeObserver` Web API.\n *\n * The observable debounces the emitted values to improve performance and reduce the frequency\n * of change detection runs in Angular applications. The debounce time can be adjusted via\n * the `debounceDuration` parameter.\n *\n * @param {Element} element The DOM element to observe for size changes.\n * @param {number} [debounceDuration=50] The time, in milliseconds, to debounce the emitted\n * values. Defaults to 50ms.\n * @returns {Observable<ResizeObserverEntry[]>} An Observable that emits the resize events\n * for the observed element. Each emission is an array of `ResizeObserverEntry` objects, one\n * for each observed element that experienced a resize.\n * @example\n * ```ts\n * // Observing resize events of an element with a 100ms debounce duration\n * const element = document.getElementById('resizable-element');\n * fromElementResize$(element, 100).subscribe((entries) => console.log('Element resized:', entries));\n * ```\n *\n * Always unsubscribe from the observable to clean up resources and prevent memory leaks.\n */\nexport function fromElementResize$(element: Element, debounceDuration = 50): Observable<ResizeObserverEntry[]> {\n return new Observable<ResizeObserverEntry[]>((observer) => {\n const resizeObserver = createResizeObserver((events) => {\n if (events.length > 0) {\n observer.next(events);\n }\n });\n observer.add(() => resizeObserver.disconnect());\n resizeObserver.observe(element);\n }).pipe(debounceTime(debounceDuration));\n}\n","import { fromEvent, merge, Observable } from 'rxjs';\nimport { HasEventTargetAddRemove } from 'rxjs/internal/observable/fromEvent';\n\n/**\n * Creates an Observable that emits events of a specific type from one or multiple event targets.\n * It listens to multiple event types on the given target(s) and emits the events through a single\n * Observable stream, simplifying the handling of related event types.\n *\n * @template T The event object type that the Observable will emit.\n * @param {HasEventTargetAddRemove<T> | HasEventTargetAddRemove<T>[]} target The DOM element(s) or event target(s) to listen on.\n * @param {...string[]} events The names of the events to listen for on the target(s).\n * @returns {Observable<T>} An Observable that emits an event each time one of the specified events occurs on the given target(s).\n *\n * @example\n * ```ts\n * // Listen to both 'click' and 'keyup' events on document\n * fromEvents(document, 'click', 'keyup').subscribe(event => {\n * console.log('Event occurred:', event);\n * });\n *\n * // Listen to 'mousemove' event on multiple elements\n * const elements = [document.getElementById('first'), document.getElementById('second')];\n * fromEvents(elements, 'mousemove').subscribe(event => {\n * console.log('Mouse moved over:', event.target);\n * });\n * ```\n */\nexport function fromEvents<T>(target: HasEventTargetAddRemove<T> | HasEventTargetAddRemove<T>[], ...events: string[]): Observable<T> {\n return merge(...events.map((event) => fromEvent(target, event)));\n}\n","import { QueryList } from '@angular/core';\nimport { Observable, startWith } from 'rxjs';\n\n/**\n * Creates an Observable from an Angular QueryList. The Observable emits the initial state\n * of the QueryList and continues to emit updates every time the QueryList changes.\n * This utility function is useful for integrating Angular's QueryList changes into\n * the RxJS reactive data flow, allowing developers to apply RxJS operators and\n * subscriptions to respond to QueryList updates.\n *\n * @template T The type of elements contained within the QueryList.\n * @param {QueryList<T>} queryList The QueryList instance to observe.\n * @returns {Observable<QueryList<T>>} An Observable that emits the current state of the QueryList\n * and updates whenever the QueryList changes.\n * @example\n * ```ts\n * // Assuming 'items' is a QueryList of component instances or DOM elements\n * fromQueryList(items).subscribe(queryList => {\n * console.log('QueryList changed:', queryList);\n * });\n * ```\n */\nexport function fromQueryList<T>(queryList: QueryList<T>): Observable<QueryList<T>> {\n return queryList.changes.pipe(startWith(queryList));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,UAAU,CAAI,KAAmB,EAAE,QAA6B,EAAA;AAC9E,IAAA,OAAO,CAAC,OAAsB,KAC5B,OAAO,CAAC,IAAI,CACV,SAAS,CAAC,CAAC,KAAQ,KACjB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CACjB,GAAG,CAAC,MAAM,KAAK,CAAC,EAChB,SAAS,CAAC,QAAQ,CAAC,CACpB,CACF,CACF;AACL;;AC/BA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,oBAAoB,CAAC,OAAgB,EAAE,OAA6B,EAAA;AAClF,IAAA,OAAO,IAAI,UAAU,CAAiB,CAAC,QAAQ,KAAI;AACjD,QAAA,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACxF,QAAQ,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,EAAE,CAAC;AACjD,QAAA,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC;AAC5C,IAAA,CAAC,CAAC;AACJ;;AC3BA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;SACa,kBAAkB,CAAC,OAAgB,EAAE,gBAAgB,GAAG,EAAE,EAAA;AACxE,IAAA,OAAO,IAAI,UAAU,CAAwB,CAAC,QAAQ,KAAI;AACxD,QAAA,MAAM,cAAc,GAAG,oBAAoB,CAAC,CAAC,MAAM,KAAI;AACrD,YAAA,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;AACrB,gBAAA,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YACvB;AACF,QAAA,CAAC,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,MAAM,cAAc,CAAC,UAAU,EAAE,CAAC;AAC/C,QAAA,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC;IACjC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;AACzC;;AClCA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;SACa,UAAU,CAAI,MAAiE,EAAE,GAAG,MAAgB,EAAA;IAClH,OAAO,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAClE;;AC1BA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,aAAa,CAAI,SAAuB,EAAA;IACtD,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACrD;;ACxBA;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"odx-angular-sdk.mjs","sources":["../../../../libs/angular/sdk/src/lib/application-environment.ts","../../../../libs/angular/sdk/src/odx-angular-sdk.ts"],"sourcesContent":["import { ApplicationRef, inject, InjectionToken } from '@angular/core';\nimport { bootstrapApplication } from '@angular/platform-browser';\n\n/**\n * A function type definition for loading environment data for an application.\n * It's a generic loader function that accepts parameters and returns a Promise of environment data.\n *\n * @template EnvironmentData The type of the environment data to be loaded.\n * @template Params The types of the parameters accepted by the loader function.\n * @param {...Params} args - Parameters passed to the loader function.\n * @returns {Promise<EnvironmentData>} A promise resolving to the loaded environment data.\n */\nexport type ApplicationEnvironmentLoader<EnvironmentData, Params extends unknown[]> = (...args: Params) => Promise<EnvironmentData>;\n\n/**\n * Creates a loader function for fetching application environment data over HTTP and caching it.\n * Utilizes `CacheStorageClient` for caching the fetched data to optimize performance and reduce network load.\n *\n * @template Data The type of the data expected from the HTTP request.\n * @param {Function} handler - A function that processes the fetched data and returns a promise resolving to the desired environment data format.\n * @returns {ApplicationEnvironmentLoader<Data, Parameters<CacheStorageClient['request']>>} A loader function that fetches, caches, and processes environment data.\n * @example\n * const environmentLoader = createHttpApplicationEnvironmentLoader(async (dto) => {\n * return { apiEndpoint: dto.apiEndpoint, featureFlags: dto.featureFlags };\n * });\n */\nexport function createHttpApplicationEnvironmentLoader<Data>(\n handler: (dto: unknown) => Promise<Data>,\n): ApplicationEnvironmentLoader<Data, Parameters<typeof fetch>> {\n return (...args: Parameters<typeof fetch>) =>\n fetch(...args)\n .then((res) => res.json())\n .then((dto) => handler(dto));\n}\n\n/**\n * The application environment module can be used to load environment data before application startup,\n * that can be used to load environment variables from an external URL.\n *\n * @template Data The type of the environment data.\n * @template Params The types of the parameters accepted by the loader function.\n * @param {ApplicationEnvironmentLoader<Data, Params>} loader - A loader function that asynchronously loads the environment data.\n * @returns An object containing utilities for working with the application environment, including the InjectionToken\n * and functions for loading and bootstrapping the application with the environment.\n * @example\n * To add an application environment to your Angular application, follow the following steps:\n * 1. Create the application environment with your loader:\n * ```ts\n * import { createApplicationEnvironment, createHttpApplicationEnvironmentLoader } from '@odx/angular/sdk';\n * import { z } from 'zod';\n *\n * export const ApplicationConfigSchema = z.object({\n * environment: z.enum(['dev', 'stage', 'prod']),\n * appName: z.string().default('App'),\n * });\n *\n * const httpEnvironmentLoader = createHttpApplicationEnvironmentLoader((res) => res.json().then(ApplicationConfigSchema.parse));\n * export const { injectApplicationEnvironment, bootstrapApplicationWithEnvironment } = createApplicationEnvironment(httpEnvironmentLoader);\n * ```\n * This example creates an HTTP environment loader which parses the response as JSON and validate it against a schema\n *\n * 2. Provide the application environment:\n * ```ts\n * bootstrapApplicationWithEnvironment(['assets/config.json'], AppComponent, { providers: [] });\n * ```\n *\n * 3. Use the application environment via DI\n * ```ts\n * class MyService {\n * private readonly environment = injectApplicationEnvironment();\n * }\n * ```\n */\nexport function createApplicationEnvironment<Data, Params extends unknown[]>(loader: ApplicationEnvironmentLoader<Data, Params>) {\n let environment: Data;\n const APPLICATION_ENVIRONMENT = new InjectionToken<Data>('@odx/angular/sdk::ApplicationEnvironment', {\n providedIn: 'root',\n factory: () => environment as Data,\n });\n\n function injectApplicationEnvironment(): Data {\n return inject(APPLICATION_ENVIRONMENT);\n }\n\n async function loadApplicationEnvironment(...args: Parameters<typeof loader>): Promise<Data> {\n environment = await loader(...args);\n if (!environment) {\n throw new Error('[@odx/angular/sdk] Failed load application environment');\n }\n return environment;\n }\n\n async function bootstrapApplicationWithEnvironment(\n params: Parameters<typeof loader>,\n ...args: Parameters<typeof bootstrapApplication>\n ): Promise<ApplicationRef> {\n await loadApplicationEnvironment(...params);\n\n return bootstrapApplication(...args);\n }\n\n return {\n APPLICATION_ENVIRONMENT,\n injectApplicationEnvironment,\n bootstrapApplicationWithEnvironment,\n loadApplicationEnvironment,\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAcA;;;;;;;;;;;AAWG;AACG,SAAU,sCAAsC,CACpD,OAAwC,EAAA;IAExC,OAAO,CAAC,GAAG,IAA8B,KACvC,KAAK,CAAC,GAAG,IAAI,CAAC;SACX,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCG;AACG,SAAU,4BAA4B,CAAiC,MAAkD,EAAA;AAC7H,IAAA,IAAI,WAAiB,CAAC;AACtB,IAAA,MAAM,uBAAuB,GAAG,IAAI,cAAc,CAAO,0CAA0C,EAAE;AACnG,QAAA,UAAU,EAAE,MAAM;AAClB,QAAA,OAAO,EAAE,MAAM,WAAmB;AACnC,KAAA,CAAC,CAAC;AAEH,IAAA,SAAS,4BAA4B,GAAA;AACnC,QAAA,OAAO,MAAM,CAAC,uBAAuB,CAAC,CAAC;KACxC;AAED,IAAA,eAAe,0BAA0B,CAAC,GAAG,IAA+B,EAAA;AAC1E,QAAA,WAAW,GAAG,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;SAC3E;AACD,QAAA,OAAO,WAAW,CAAC;KACpB;AAED,IAAA,eAAe,mCAAmC,CAChD,MAAiC,EACjC,GAAG,IAA6C,EAAA;AAEhD,QAAA,MAAM,0BAA0B,CAAC,GAAG,MAAM,CAAC,CAAC;AAE5C,QAAA,OAAO,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAAC;KACtC;IAED,OAAO;QACL,uBAAuB;QACvB,4BAA4B;QAC5B,mCAAmC;QACnC,0BAA0B;KAC3B,CAAC;AACJ;;AC3GA;;AAEG;;;;"}
1
+ {"version":3,"file":"odx-angular-sdk.mjs","sources":["../../../../libs/angular/sdk/src/lib/application-environment.ts","../../../../libs/angular/sdk/src/odx-angular-sdk.ts"],"sourcesContent":["import { ApplicationRef, inject, InjectionToken } from '@angular/core';\nimport { bootstrapApplication } from '@angular/platform-browser';\n\n/**\n * A function type definition for loading environment data for an application.\n * It's a generic loader function that accepts parameters and returns a Promise of environment data.\n *\n * @template EnvironmentData The type of the environment data to be loaded.\n * @template Params The types of the parameters accepted by the loader function.\n * @param {...Params} args - Parameters passed to the loader function.\n * @returns {Promise<EnvironmentData>} A promise resolving to the loaded environment data.\n */\nexport type ApplicationEnvironmentLoader<EnvironmentData, Params extends unknown[]> = (...args: Params) => Promise<EnvironmentData>;\n\n/**\n * Creates a loader function for fetching application environment data over HTTP and caching it.\n * Utilizes `CacheStorageClient` for caching the fetched data to optimize performance and reduce network load.\n *\n * @template Data The type of the data expected from the HTTP request.\n * @param {Function} handler - A function that processes the fetched data and returns a promise resolving to the desired environment data format.\n * @returns {ApplicationEnvironmentLoader<Data, Parameters<CacheStorageClient['request']>>} A loader function that fetches, caches, and processes environment data.\n * @example\n * const environmentLoader = createHttpApplicationEnvironmentLoader(async (dto) => {\n * return { apiEndpoint: dto.apiEndpoint, featureFlags: dto.featureFlags };\n * });\n */\nexport function createHttpApplicationEnvironmentLoader<Data>(\n handler: (dto: unknown) => Promise<Data>,\n): ApplicationEnvironmentLoader<Data, Parameters<typeof fetch>> {\n return (...args: Parameters<typeof fetch>) =>\n fetch(...args)\n .then((res) => res.json())\n .then((dto) => handler(dto));\n}\n\n/**\n * The application environment module can be used to load environment data before application startup,\n * that can be used to load environment variables from an external URL.\n *\n * @template Data The type of the environment data.\n * @template Params The types of the parameters accepted by the loader function.\n * @param {ApplicationEnvironmentLoader<Data, Params>} loader - A loader function that asynchronously loads the environment data.\n * @returns An object containing utilities for working with the application environment, including the InjectionToken\n * and functions for loading and bootstrapping the application with the environment.\n * @example\n * To add an application environment to your Angular application, follow the following steps:\n * 1. Create the application environment with your loader:\n * ```ts\n * import { createApplicationEnvironment, createHttpApplicationEnvironmentLoader } from '@odx/angular/sdk';\n * import { z } from 'zod';\n *\n * export const ApplicationConfigSchema = z.object({\n * environment: z.enum(['dev', 'stage', 'prod']),\n * appName: z.string().default('App'),\n * });\n *\n * const httpEnvironmentLoader = createHttpApplicationEnvironmentLoader((res) => res.json().then(ApplicationConfigSchema.parse));\n * export const { injectApplicationEnvironment, bootstrapApplicationWithEnvironment } = createApplicationEnvironment(httpEnvironmentLoader);\n * ```\n * This example creates an HTTP environment loader which parses the response as JSON and validate it against a schema\n *\n * 2. Provide the application environment:\n * ```ts\n * bootstrapApplicationWithEnvironment(['assets/config.json'], AppComponent, { providers: [] });\n * ```\n *\n * 3. Use the application environment via DI\n * ```ts\n * class MyService {\n * private readonly environment = injectApplicationEnvironment();\n * }\n * ```\n */\nexport function createApplicationEnvironment<Data, Params extends unknown[]>(loader: ApplicationEnvironmentLoader<Data, Params>) {\n let environment: Data;\n const APPLICATION_ENVIRONMENT = new InjectionToken<Data>('@odx/angular/sdk::ApplicationEnvironment', {\n providedIn: 'root',\n factory: () => environment as Data,\n });\n\n function injectApplicationEnvironment(): Data {\n return inject(APPLICATION_ENVIRONMENT);\n }\n\n async function loadApplicationEnvironment(...args: Parameters<typeof loader>): Promise<Data> {\n environment = await loader(...args);\n if (!environment) {\n throw new Error('[@odx/angular/sdk] Failed load application environment');\n }\n return environment;\n }\n\n async function bootstrapApplicationWithEnvironment(\n params: Parameters<typeof loader>,\n ...args: Parameters<typeof bootstrapApplication>\n ): Promise<ApplicationRef> {\n await loadApplicationEnvironment(...params);\n\n return bootstrapApplication(...args);\n }\n\n return {\n APPLICATION_ENVIRONMENT,\n injectApplicationEnvironment,\n bootstrapApplicationWithEnvironment,\n loadApplicationEnvironment,\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAcA;;;;;;;;;;;AAWG;AACG,SAAU,sCAAsC,CACpD,OAAwC,EAAA;IAExC,OAAO,CAAC,GAAG,IAA8B,KACvC,KAAK,CAAC,GAAG,IAAI;SACV,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,EAAE;SACxB,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAClC;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCG;AACG,SAAU,4BAA4B,CAAiC,MAAkD,EAAA;AAC7H,IAAA,IAAI,WAAiB;AACrB,IAAA,MAAM,uBAAuB,GAAG,IAAI,cAAc,CAAO,0CAA0C,EAAE;AACnG,QAAA,UAAU,EAAE,MAAM;AAClB,QAAA,OAAO,EAAE,MAAM,WAAmB;AACnC,KAAA,CAAC;AAEF,IAAA,SAAS,4BAA4B,GAAA;AACnC,QAAA,OAAO,MAAM,CAAC,uBAAuB,CAAC;IACxC;AAEA,IAAA,eAAe,0BAA0B,CAAC,GAAG,IAA+B,EAAA;AAC1E,QAAA,WAAW,GAAG,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC;QAC3E;AACA,QAAA,OAAO,WAAW;IACpB;AAEA,IAAA,eAAe,mCAAmC,CAChD,MAAiC,EACjC,GAAG,IAA6C,EAAA;AAEhD,QAAA,MAAM,0BAA0B,CAAC,GAAG,MAAM,CAAC;AAE3C,QAAA,OAAO,oBAAoB,CAAC,GAAG,IAAI,CAAC;IACtC;IAEA,OAAO;QACL,uBAAuB;QACvB,4BAA4B;QAC5B,mCAAmC;QACnC,0BAA0B;KAC3B;AACH;;AC3GA;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"odx-angular-theming.mjs","sources":["../../../../libs/angular/theming/src/lib/helpers/prefers-dark-theme.ts","../../../../libs/angular/theming/src/lib/models/theme.ts","../../../../libs/angular/theming/src/lib/helpers/resolve-theme.ts","../../../../libs/angular/theming/src/lib/helpers/theme-storage.ts","../../../../libs/angular/theming/src/lib/theming.service.ts","../../../../libs/angular/theming/src/lib/theming.config.ts","../../../../libs/angular/theming/src/odx-angular-theming.ts"],"sourcesContent":["/**\n * Determines whether the user's system preferences indicate a preference for dark themes.\n * This is achieved by querying the '(prefers-color-scheme: dark)' media feature, which reflects\n * the user's preference for a light or dark color scheme in their operating system's UI.\n *\n * @param {Window} view - The window object, typically `window`, from which to access the matchMedia method.\n * @returns {boolean} `true` if the user prefers a dark theme, otherwise `false`.\n *\n * @example\n * Example usage in a web application to toggle themes:\n * ```ts\n * if (prefersDarkTheme(window)) {\n * document.body.classList.add('dark-theme');\n * } else {\n * document.body.classList.remove('dark-theme');\n * }\n * ```\n */\nexport function prefersDarkTheme(view: Window): boolean {\n return !!view.matchMedia?.('(prefers-color-scheme: dark)')?.matches;\n}\n","export type Theme = (typeof Theme)[keyof typeof Theme];\nexport const Theme = {\n DARK: 'dark',\n LIGHT: 'light',\n} as const;\n\nexport const availableThemes = Object.values(Theme);\n","import { availableThemes, Theme } from '../models';\n\n/**\n * Resolves the specified theme by checking if it exists in the predefined list of available themes.\n * This function ensures that only valid themes are used in the application, providing a safeguard\n * against invalid theme names and facilitating the dynamic application of themes.\n *\n * @param {string | null} [theme] - The name of the theme to resolve. It's optional and can be `null`.\n * @returns {Theme | null} - Returns the resolved `Theme` object if the theme is found within the list of `availableThemes`;\n * otherwise, returns `null` to indicate the theme is not recognized or available.\n *\n * @example\n * ```ts\n * // Assuming 'dark' and 'light' are in the availableThemes array\n * console.log(resolveTheme('dark')); // Outputs the 'dark' Theme object\n * console.log(resolveTheme('unknown')); // Outputs null\n *\n * // Using resolveTheme to apply a user-selected theme\n * const userSelectedTheme = getUserSelectedTheme(); // This function gets the user's theme choice\n * const themeToApply = resolveTheme(userSelectedTheme);\n * if (themeToApply) {\n * applyTheme(themeToApply); // This function applies the resolved theme to the application\n * } else {\n * console.warn('Selected theme is not available.');\n * }\n * ```\n */\nexport function resolveTheme(theme?: string | null): Theme | null {\n return availableThemes.find((t) => t === theme) ?? null;\n}\n","import { Theme } from '../models';\nimport { resolveTheme } from './resolve-theme';\n\n/**\n * The key used to store the selected theme in `Storage`.\n * This constant ensures consistent access to the theme setting across the application.\n */\nexport const THEME_STORAGE_NAME = '@odx/angular/theming:SelectedTheme';\n\n/**\n * Saves the specified theme to storage. This function abstracts the storage interaction,\n * providing a fail-safe mechanism to avoid exceptions if the storage is not available.\n *\n * @param {Storage | null | undefined} storage - The storage mechanism to use, typically `localStorage` or `sessionStorage`.\n * @param {Theme} theme - The theme to save. Should be a value that is recognized by the application's theming system.\n * @throws Will silently catch and ignore any exceptions caused by storage limitations or permissions.\n *\n * @example\n * ```ts\n * // Example usage with localStorage\n * saveTheme(localStorage, 'dark');\n *\n * // Using sessionStorage instead\n * saveTheme(sessionStorage, 'light');\n * ```\n */\nexport function saveTheme(storage: Storage | null | undefined, theme: Theme): void {\n try {\n storage?.setItem(THEME_STORAGE_NAME, theme);\n } catch {\n //\n }\n}\n\n/**\n * Reads the theme from storage, attempting to resolve it to a valid application theme.\n * If the theme cannot be found or is invalid, `null` is returned. This function also provides\n * error handling for any storage access issues, ensuring the application can gracefully handle\n * scenarios where storage is not available or accessible.\n *\n * @param {Storage | null} [storage] - The storage mechanism to use, typically `localStorage` or `sessionStorage`.\n * @returns {Theme | null} - The resolved theme if found and valid; otherwise, `null`.\n * @throws Will silently catch and ignore any exceptions caused by storage access, returning `null`.\n *\n * @example\n * ```ts\n * // Reading theme from localStorage\n * const theme = readTheme(localStorage);\n * if (theme) {\n * applyTheme(theme); // Assuming applyTheme is a function to apply the theme\n * } else {\n * console.warn('No saved theme found or theme is invalid.');\n * }\n * ```\n */\nexport function readTheme(storage?: Storage | null): Theme | null {\n try {\n return resolveTheme(storage?.getItem(THEME_STORAGE_NAME)) ?? null;\n } catch {\n return null;\n }\n}\n","import { DOCUMENT } from '@angular/common';\nimport { inject, Injectable } from '@angular/core';\nimport { WindowRef } from '@odx/angular';\nimport { BehaviorSubject, distinctUntilChanged, shareReplay } from 'rxjs';\nimport { prefersDarkTheme, readTheme, saveTheme } from './helpers';\nimport { Theme } from './models';\nimport { injectThemingConfig } from './theming.config';\n\nexport const THEME_ATTRIBUTE_NAME = 'odxTheme';\n\n/**\n * Manages theming for the application. It allows for dynamic theme selection, automatically saves theme preferences,\n * and applies the user's preferred theme or the default theme based on configuration settings.\n *\n * The service leverages the BehaviorSubject pattern to reactively handle theme changes across the application,\n * ensuring that subscribers are notified whenever the theme changes. It also interacts with the DOM directly\n * to apply the current theme and with the provided storage mechanism to persist theme preferences.\n */\n@Injectable({ providedIn: 'root' })\nexport class ThemingService {\n private readonly config = injectThemingConfig();\n private readonly document = inject(DOCUMENT);\n private readonly windowRef = inject(WindowRef);\n private readonly theme$$ = new BehaviorSubject<Theme>(this.getInitialTheme());\n\n /**\n * An observable stream of the current theme, emitting values whenever the theme changes.\n * Subscribers to this observable can react to theme changes in real-time.\n *\n * @emits {Theme} The currently selected theme.\n */\n public readonly theme$ = this.theme$$.pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));\n\n constructor() {\n this.theme$.subscribe((theme) => {\n this.document.body.setAttribute(THEME_ATTRIBUTE_NAME, theme);\n saveTheme(this.config.storage, theme);\n });\n }\n\n /**\n * Selects and applies a given theme by updating the BehaviorSubject and persisting the preference.\n *\n * @param {Theme} theme - The theme to apply.\n */\n public selectTheme(theme: Theme): void {\n this.theme$$.next(theme);\n }\n\n /**\n * Retrieves the currently selected theme.\n *\n * @returns {Theme} The currently selected theme.\n */\n public getSelectedTheme(): Theme {\n return this.theme$$.getValue();\n }\n\n /**\n * Toggles between dark and light themes, depending on the current theme.\n */\n public toggleDarkMode(): void {\n const currentTheme = this.getSelectedTheme();\n if (currentTheme === Theme.DARK) {\n this.enableLightMode();\n } else {\n this.enableDarkMode();\n }\n }\n\n /**\n * Enables the dark mode theme.\n */\n public enableDarkMode(): void {\n this.selectTheme(Theme.DARK);\n }\n\n /**\n * Enables the light mode theme.\n */\n public enableLightMode(): void {\n this.selectTheme(Theme.LIGHT);\n }\n\n private getInitialTheme(): Theme {\n let selectedTheme = readTheme(this.config.storage);\n\n if (!selectedTheme && this.config.autoDetect && prefersDarkTheme(this.windowRef.nativeWindow)) {\n selectedTheme = Theme.DARK;\n }\n\n return selectedTheme ?? this.config.defaultTheme;\n }\n}\n","import { ENVIRONMENT_INITIALIZER, EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport { ConfigDependencies, ConfigProvider, createConfigTokens } from '@odx/angular/utils';\nimport { Theme } from './models';\nimport { ThemingService } from './theming.service';\n\n/**\n * Defines the structure for theming configuration options in the application.\n */\nexport interface ThemingConfig {\n /**\n * Determines whether the theme should be auto-detected based on system preferences.\n */\n autoDetect: boolean;\n\n /**\n * Specifies the default theme to be used if auto-detection is not enabled or fails.\n */\n defaultTheme: Theme;\n\n /**\n * The storage mechanism (like `localStorage` or `sessionStorage`) to persist theme settings,\n * or `null` to disable persistence.\n */\n storage?: Storage | null;\n}\n\n/**\n * Utility created by `createConfigTokens` for managing theming configuration tokens and functions.\n * Provides easy access to theming configuration, default values, and dependency injection utilities.\n */\nexport const { ThemingConfig, injectThemingConfig, provideThemingConfig } = createConfigTokens('Theming', '@odx/angular/theme', {\n autoDetect: false,\n defaultTheme: Theme.LIGHT,\n storage: null,\n} as ThemingConfig);\n\n/**\n * Provides the theming configuration to the application and initializes the `ThemingService`\n * based on the provided configuration. This function simplifies the setup of a dynamic theming\n * system, integrating with Angular's environment initializers to ensure proper initialization.\n *\n * @template D - The dependencies required by the theming configuration, if any.\n * @param {ConfigProvider<Partial<ThemingConfig>, D>} config - The theming configuration or a configuration factory provider.\n * @returns {EnvironmentProviders} An array of providers for setting up theming in the application.\n *\n * @example\n * ```ts\n * // Providing a simple theming configuration\n * provideTheming({\n * autoDetect: true,\n * defaultTheme: Theme.DARK,\n * storage: localStorage,\n * });\n *\n * // Providing a theming configuration with dependencies\n * provideTheming({\n * useFactory: (deps: Dependencies) => ({\n * autoDetect: deps.setting,\n * defaultTheme: Theme.DARK,\n * storage: localStorage,\n * }),\n * deps: [SomeDependency],\n * });\n * ```\n */\nexport function provideTheming<D extends ConfigDependencies = ConfigDependencies<ThemingConfig>>(\n config: ConfigProvider<Partial<ThemingConfig>, D>,\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideThemingConfig(config),\n {\n provide: ENVIRONMENT_INITIALIZER,\n useFactory: () => () => inject(ThemingService),\n deps: [ThemingConfig],\n multi: true,\n },\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"odx-angular-theming.mjs","sources":["../../../../libs/angular/theming/src/lib/helpers/prefers-dark-theme.ts","../../../../libs/angular/theming/src/lib/models/theme.ts","../../../../libs/angular/theming/src/lib/helpers/resolve-theme.ts","../../../../libs/angular/theming/src/lib/helpers/theme-storage.ts","../../../../libs/angular/theming/src/lib/theming.service.ts","../../../../libs/angular/theming/src/lib/theming.config.ts","../../../../libs/angular/theming/src/odx-angular-theming.ts"],"sourcesContent":["/**\n * Determines whether the user's system preferences indicate a preference for dark themes.\n * This is achieved by querying the '(prefers-color-scheme: dark)' media feature, which reflects\n * the user's preference for a light or dark color scheme in their operating system's UI.\n *\n * @param {Window} view - The window object, typically `window`, from which to access the matchMedia method.\n * @returns {boolean} `true` if the user prefers a dark theme, otherwise `false`.\n *\n * @example\n * Example usage in a web application to toggle themes:\n * ```ts\n * if (prefersDarkTheme(window)) {\n * document.body.classList.add('dark-theme');\n * } else {\n * document.body.classList.remove('dark-theme');\n * }\n * ```\n */\nexport function prefersDarkTheme(view: Window): boolean {\n return !!view.matchMedia?.('(prefers-color-scheme: dark)')?.matches;\n}\n","export type Theme = (typeof Theme)[keyof typeof Theme];\nexport const Theme = {\n DARK: 'dark',\n LIGHT: 'light',\n} as const;\n\nexport const availableThemes = Object.values(Theme);\n","import { availableThemes, Theme } from '../models';\n\n/**\n * Resolves the specified theme by checking if it exists in the predefined list of available themes.\n * This function ensures that only valid themes are used in the application, providing a safeguard\n * against invalid theme names and facilitating the dynamic application of themes.\n *\n * @param {string | null} [theme] - The name of the theme to resolve. It's optional and can be `null`.\n * @returns {Theme | null} - Returns the resolved `Theme` object if the theme is found within the list of `availableThemes`;\n * otherwise, returns `null` to indicate the theme is not recognized or available.\n *\n * @example\n * ```ts\n * // Assuming 'dark' and 'light' are in the availableThemes array\n * console.log(resolveTheme('dark')); // Outputs the 'dark' Theme object\n * console.log(resolveTheme('unknown')); // Outputs null\n *\n * // Using resolveTheme to apply a user-selected theme\n * const userSelectedTheme = getUserSelectedTheme(); // This function gets the user's theme choice\n * const themeToApply = resolveTheme(userSelectedTheme);\n * if (themeToApply) {\n * applyTheme(themeToApply); // This function applies the resolved theme to the application\n * } else {\n * console.warn('Selected theme is not available.');\n * }\n * ```\n */\nexport function resolveTheme(theme?: string | null): Theme | null {\n return availableThemes.find((t) => t === theme) ?? null;\n}\n","import { Theme } from '../models';\nimport { resolveTheme } from './resolve-theme';\n\n/**\n * The key used to store the selected theme in `Storage`.\n * This constant ensures consistent access to the theme setting across the application.\n */\nexport const THEME_STORAGE_NAME = '@odx/angular/theming:SelectedTheme';\n\n/**\n * Saves the specified theme to storage. This function abstracts the storage interaction,\n * providing a fail-safe mechanism to avoid exceptions if the storage is not available.\n *\n * @param {Storage | null | undefined} storage - The storage mechanism to use, typically `localStorage` or `sessionStorage`.\n * @param {Theme} theme - The theme to save. Should be a value that is recognized by the application's theming system.\n * @throws Will silently catch and ignore any exceptions caused by storage limitations or permissions.\n *\n * @example\n * ```ts\n * // Example usage with localStorage\n * saveTheme(localStorage, 'dark');\n *\n * // Using sessionStorage instead\n * saveTheme(sessionStorage, 'light');\n * ```\n */\nexport function saveTheme(storage: Storage | null | undefined, theme: Theme): void {\n try {\n storage?.setItem(THEME_STORAGE_NAME, theme);\n } catch {\n //\n }\n}\n\n/**\n * Reads the theme from storage, attempting to resolve it to a valid application theme.\n * If the theme cannot be found or is invalid, `null` is returned. This function also provides\n * error handling for any storage access issues, ensuring the application can gracefully handle\n * scenarios where storage is not available or accessible.\n *\n * @param {Storage | null} [storage] - The storage mechanism to use, typically `localStorage` or `sessionStorage`.\n * @returns {Theme | null} - The resolved theme if found and valid; otherwise, `null`.\n * @throws Will silently catch and ignore any exceptions caused by storage access, returning `null`.\n *\n * @example\n * ```ts\n * // Reading theme from localStorage\n * const theme = readTheme(localStorage);\n * if (theme) {\n * applyTheme(theme); // Assuming applyTheme is a function to apply the theme\n * } else {\n * console.warn('No saved theme found or theme is invalid.');\n * }\n * ```\n */\nexport function readTheme(storage?: Storage | null): Theme | null {\n try {\n return resolveTheme(storage?.getItem(THEME_STORAGE_NAME)) ?? null;\n } catch {\n return null;\n }\n}\n","import { DOCUMENT } from '@angular/common';\nimport { inject, Injectable } from '@angular/core';\nimport { WindowRef } from '@odx/angular';\nimport { BehaviorSubject, distinctUntilChanged, shareReplay } from 'rxjs';\nimport { prefersDarkTheme, readTheme, saveTheme } from './helpers';\nimport { Theme } from './models';\nimport { injectThemingConfig } from './theming.config';\n\nexport const THEME_ATTRIBUTE_NAME = 'odxTheme';\n\n/**\n * Manages theming for the application. It allows for dynamic theme selection, automatically saves theme preferences,\n * and applies the user's preferred theme or the default theme based on configuration settings.\n *\n * The service leverages the BehaviorSubject pattern to reactively handle theme changes across the application,\n * ensuring that subscribers are notified whenever the theme changes. It also interacts with the DOM directly\n * to apply the current theme and with the provided storage mechanism to persist theme preferences.\n */\n@Injectable({ providedIn: 'root' })\nexport class ThemingService {\n private readonly config = injectThemingConfig();\n private readonly document = inject(DOCUMENT);\n private readonly windowRef = inject(WindowRef);\n private readonly theme$$ = new BehaviorSubject<Theme>(this.getInitialTheme());\n\n /**\n * An observable stream of the current theme, emitting values whenever the theme changes.\n * Subscribers to this observable can react to theme changes in real-time.\n *\n * @emits {Theme} The currently selected theme.\n */\n public readonly theme$ = this.theme$$.pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));\n\n constructor() {\n this.theme$.subscribe((theme) => {\n this.document.body.setAttribute(THEME_ATTRIBUTE_NAME, theme);\n saveTheme(this.config.storage, theme);\n });\n }\n\n /**\n * Selects and applies a given theme by updating the BehaviorSubject and persisting the preference.\n *\n * @param {Theme} theme - The theme to apply.\n */\n public selectTheme(theme: Theme): void {\n this.theme$$.next(theme);\n }\n\n /**\n * Retrieves the currently selected theme.\n *\n * @returns {Theme} The currently selected theme.\n */\n public getSelectedTheme(): Theme {\n return this.theme$$.getValue();\n }\n\n /**\n * Toggles between dark and light themes, depending on the current theme.\n */\n public toggleDarkMode(): void {\n const currentTheme = this.getSelectedTheme();\n if (currentTheme === Theme.DARK) {\n this.enableLightMode();\n } else {\n this.enableDarkMode();\n }\n }\n\n /**\n * Enables the dark mode theme.\n */\n public enableDarkMode(): void {\n this.selectTheme(Theme.DARK);\n }\n\n /**\n * Enables the light mode theme.\n */\n public enableLightMode(): void {\n this.selectTheme(Theme.LIGHT);\n }\n\n private getInitialTheme(): Theme {\n let selectedTheme = readTheme(this.config.storage);\n\n if (!selectedTheme && this.config.autoDetect && prefersDarkTheme(this.windowRef.nativeWindow)) {\n selectedTheme = Theme.DARK;\n }\n\n return selectedTheme ?? this.config.defaultTheme;\n }\n}\n","import { ENVIRONMENT_INITIALIZER, EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport { ConfigDependencies, ConfigProvider, createConfigTokens } from '@odx/angular/utils';\nimport { Theme } from './models';\nimport { ThemingService } from './theming.service';\n\n/**\n * Defines the structure for theming configuration options in the application.\n */\nexport interface ThemingConfig {\n /**\n * Determines whether the theme should be auto-detected based on system preferences.\n */\n autoDetect: boolean;\n\n /**\n * Specifies the default theme to be used if auto-detection is not enabled or fails.\n */\n defaultTheme: Theme;\n\n /**\n * The storage mechanism (like `localStorage` or `sessionStorage`) to persist theme settings,\n * or `null` to disable persistence.\n */\n storage?: Storage | null;\n}\n\n/**\n * Utility created by `createConfigTokens` for managing theming configuration tokens and functions.\n * Provides easy access to theming configuration, default values, and dependency injection utilities.\n */\nexport const { ThemingConfig, injectThemingConfig, provideThemingConfig } = createConfigTokens('Theming', '@odx/angular/theme', {\n autoDetect: false,\n defaultTheme: Theme.LIGHT,\n storage: null,\n} as ThemingConfig);\n\n/**\n * Provides the theming configuration to the application and initializes the `ThemingService`\n * based on the provided configuration. This function simplifies the setup of a dynamic theming\n * system, integrating with Angular's environment initializers to ensure proper initialization.\n *\n * @template D - The dependencies required by the theming configuration, if any.\n * @param {ConfigProvider<Partial<ThemingConfig>, D>} config - The theming configuration or a configuration factory provider.\n * @returns {EnvironmentProviders} An array of providers for setting up theming in the application.\n *\n * @example\n * ```ts\n * // Providing a simple theming configuration\n * provideTheming({\n * autoDetect: true,\n * defaultTheme: Theme.DARK,\n * storage: localStorage,\n * });\n *\n * // Providing a theming configuration with dependencies\n * provideTheming({\n * useFactory: (deps: Dependencies) => ({\n * autoDetect: deps.setting,\n * defaultTheme: Theme.DARK,\n * storage: localStorage,\n * }),\n * deps: [SomeDependency],\n * });\n * ```\n */\nexport function provideTheming<D extends ConfigDependencies = ConfigDependencies<ThemingConfig>>(\n config: ConfigProvider<Partial<ThemingConfig>, D>,\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideThemingConfig(config),\n {\n provide: ENVIRONMENT_INITIALIZER,\n useFactory: () => () => inject(ThemingService),\n deps: [ThemingConfig],\n multi: true,\n },\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}