@eagami/ui 5.17.2 → 5.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,44 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, signal, inject, effect, computed, Injectable, input, ChangeDetectionStrategy, Component, HostBinding, Directive, model, output, Injector, afterNextRender, DestroyRef, viewChild, ElementRef, HostListener, forwardRef, Renderer2, ViewContainerRef, TemplateRef, untracked, ViewEncapsulation, contentChild, viewChildren, PLATFORM_ID } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, inject, CSP_NONCE, signal, effect, computed, Injectable, input, ChangeDetectionStrategy, Component, HostBinding, Directive, model, output, Injector, afterNextRender, DestroyRef, viewChild, ElementRef, HostListener, forwardRef, Renderer2, ViewContainerRef, TemplateRef, untracked, ViewEncapsulation, contentChild, viewChildren, PLATFORM_ID } from '@angular/core';
3
3
  import { NgClass, NgComponentOutlet, NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
4
4
  import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
5
5
 
6
- /**
7
- * Display name, flag, and reading direction for every built-in locale, in
8
- * language-switcher order: English first (the default fallback), then by each
9
- * language's own name (Latin scripts first, then Greek, Cyrillic, Hebrew,
10
- * Arabic, Devanagari, and Chinese by Unicode block order). Keyed by
11
- * `EagamiLocale` so a locale added to the union without an entry fails to
12
- * compile, keeping this single source exhaustive.
13
- */
14
- const LOCALE_DISPLAY = {
15
- en: { label: 'English', flag: '🇬🇧', dir: 'ltr' },
16
- de: { label: 'Deutsch', flag: '🇩🇪', dir: 'ltr' },
17
- 'es-ES': { label: 'Español', flag: '🇪🇸', dir: 'ltr' },
18
- 'fr-FR': { label: 'Français', flag: '🇫🇷', dir: 'ltr' },
19
- is: { label: 'Íslenska', flag: '🇮🇸', dir: 'ltr' },
20
- nl: { label: 'Nederlands', flag: '🇳🇱', dir: 'ltr' },
21
- pl: { label: 'Polski', flag: '🇵🇱', dir: 'ltr' },
22
- 'pt-BR': { label: 'Português (Brasil)', flag: '🇧🇷', dir: 'ltr' },
23
- el: { label: 'Ελληνικά', flag: '🇬🇷', dir: 'ltr' },
24
- ru: { label: 'Русский', flag: '🇷🇺', dir: 'ltr' },
25
- uk: { label: 'Українська', flag: '🇺🇦', dir: 'ltr' },
26
- he: { label: 'עברית', flag: '🇮🇱', dir: 'rtl' },
27
- ar: { label: 'العربية', flag: '🇸🇦', dir: 'rtl' },
28
- hi: { label: 'हिन्दी', flag: '🇮🇳', dir: 'ltr' },
29
- 'zh-CN': { label: '中文', flag: '🇨🇳', dir: 'ltr' },
30
- };
31
- /**
32
- * Display metadata for every built-in locale. The single source the Storybook
33
- * locale toolbar and any consumer-built language switcher derive from, so the
34
- * displayed list never drifts from the locales the library ships.
35
- */
36
- const EAGAMI_LOCALE_META = Object.keys(LOCALE_DISPLAY).map(locale => ({ locale, ...LOCALE_DISPLAY[locale] }));
37
- /**
38
- * Supported locales for language switchers, in display order. Derived from
39
- * `EAGAMI_LOCALE_META` so the two never drift.
40
- */
41
- const EAGAMI_LOCALES = EAGAMI_LOCALE_META.map(m => m.locale);
6
+ /** DI token carrying the consumer-supplied i18n configuration. */
7
+ const EAGAMI_I18N_CONFIG = new InjectionToken('EAGAMI_I18N_CONFIG');
42
8
 
43
9
  const STYLE_TAG_ID = 'eagami-palette';
44
10
  /**
@@ -51,8 +17,12 @@ const STYLE_TAG_ID = 'eagami-palette';
51
17
  * Idempotent: subsequent calls replace the previous stylesheet rather than
52
18
  * append, so a theme switcher can re-apply without leaking style tags.
53
19
  * No-ops outside a DOM context (SSR).
20
+ *
21
+ * Pass `nonce` under a `style-src` policy that requires one, or the browser
22
+ * drops the stylesheet and the app silently renders the library's own colours.
23
+ * `provideEagamiUi()` forwards Angular's `CSP_NONCE` automatically.
54
24
  */
55
- function applyPalette(palette) {
25
+ function applyPalette(palette, nonce) {
56
26
  if (typeof document === 'undefined') {
57
27
  return;
58
28
  }
@@ -61,6 +31,10 @@ function applyPalette(palette) {
61
31
  if (!tag) {
62
32
  tag = document.createElement('style');
63
33
  tag.id = STYLE_TAG_ID;
34
+ // Before insertion: the policy is checked as the tag enters the document
35
+ if (nonce) {
36
+ tag.setAttribute('nonce', nonce);
37
+ }
64
38
  document.head.appendChild(tag);
65
39
  }
66
40
  tag.textContent = css;
@@ -347,8 +321,6 @@ function formatViolations(violations) {
347
321
  ].join('\n');
348
322
  }
349
323
 
350
- /** DI token carrying the consumer-supplied i18n configuration. */
351
- const EAGAMI_I18N_CONFIG = new InjectionToken('EAGAMI_I18N_CONFIG');
352
324
  /**
353
325
  * Configures Eagami UI for the application.
354
326
  *
@@ -378,6 +350,10 @@ const EAGAMI_I18N_CONFIG = new InjectionToken('EAGAMI_I18N_CONFIG');
378
350
  * },
379
351
  * });
380
352
  * ```
353
+ *
354
+ * A `palette` installs a `<style>` tag at bootstrap, carrying Angular's
355
+ * `CSP_NONCE` when the app provides one, so a strict `style-src` policy admits
356
+ * it instead of dropping the theme.
381
357
  */
382
358
  function provideEagamiUi(config = {}) {
383
359
  const i18nConfig = {
@@ -397,11 +373,48 @@ function provideEagamiUi(config = {}) {
397
373
  if (violations.length > 0) {
398
374
  throw new Error(formatViolations(violations));
399
375
  }
400
- applyPalette(palette);
376
+ applyPalette(palette, inject(CSP_NONCE, { optional: true }));
401
377
  }),
402
378
  ]);
403
379
  }
404
380
 
381
+ /**
382
+ * Display name, flag, and reading direction for every built-in locale, in
383
+ * language-switcher order: English first (the default fallback), then by each
384
+ * language's own name (Latin scripts first, then Greek, Cyrillic, Hebrew,
385
+ * Arabic, Devanagari, and Chinese by Unicode block order). Keyed by
386
+ * `EagamiLocale` so a locale added to the union without an entry fails to
387
+ * compile, keeping this single source exhaustive.
388
+ */
389
+ const LOCALE_DISPLAY = {
390
+ en: { label: 'English', flag: '🇬🇧', dir: 'ltr' },
391
+ de: { label: 'Deutsch', flag: '🇩🇪', dir: 'ltr' },
392
+ 'es-ES': { label: 'Español', flag: '🇪🇸', dir: 'ltr' },
393
+ 'fr-FR': { label: 'Français', flag: '🇫🇷', dir: 'ltr' },
394
+ is: { label: 'Íslenska', flag: '🇮🇸', dir: 'ltr' },
395
+ nl: { label: 'Nederlands', flag: '🇳🇱', dir: 'ltr' },
396
+ pl: { label: 'Polski', flag: '🇵🇱', dir: 'ltr' },
397
+ 'pt-BR': { label: 'Português (Brasil)', flag: '🇧🇷', dir: 'ltr' },
398
+ el: { label: 'Ελληνικά', flag: '🇬🇷', dir: 'ltr' },
399
+ ru: { label: 'Русский', flag: '🇷🇺', dir: 'ltr' },
400
+ uk: { label: 'Українська', flag: '🇺🇦', dir: 'ltr' },
401
+ he: { label: 'עברית', flag: '🇮🇱', dir: 'rtl' },
402
+ ar: { label: 'العربية', flag: '🇸🇦', dir: 'rtl' },
403
+ hi: { label: 'हिन्दी', flag: '🇮🇳', dir: 'ltr' },
404
+ 'zh-CN': { label: '中文', flag: '🇨🇳', dir: 'ltr' },
405
+ };
406
+ /**
407
+ * Display metadata for every built-in locale. The single source the Storybook
408
+ * locale toolbar and any consumer-built language switcher derive from, so the
409
+ * displayed list never drifts from the locales the library ships.
410
+ */
411
+ const EAGAMI_LOCALE_META = Object.keys(LOCALE_DISPLAY).map(locale => ({ locale, ...LOCALE_DISPLAY[locale] }));
412
+ /**
413
+ * Supported locales for language switchers, in display order. Derived from
414
+ * `EAGAMI_LOCALE_META` so the two never drift.
415
+ */
416
+ const EAGAMI_LOCALES = EAGAMI_LOCALE_META.map(m => m.locale);
417
+
405
418
  /**
406
419
  * Module-level signal that lets external tooling (notably the Storybook
407
420
  * preview decorator) imperatively override the active locale on a running