ngwr 14.0.0 → 14.0.1

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 (199) hide show
  1. package/README.md +57 -8
  2. package/aurora/aurora.scss +1 -1
  3. package/aurora/styles/_dark.scss +21 -0
  4. package/aurora/styles/_index.scss +11 -30
  5. package/aurora/styles/_rules.scss +25 -0
  6. package/border-glow/styles/_dark.scss +46 -0
  7. package/border-glow/styles/_index.scss +5 -0
  8. package/border-glow/styles/_rules.scss +0 -31
  9. package/button/styles/_index.scss +16 -0
  10. package/event-calendar/styles/_index.scss +15 -0
  11. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  12. package/fesm2022/ngwr-affix.mjs +3 -3
  13. package/fesm2022/ngwr-alert.mjs +3 -3
  14. package/fesm2022/ngwr-anchor.mjs +3 -3
  15. package/fesm2022/ngwr-aurora.mjs +4 -4
  16. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  17. package/fesm2022/ngwr-avatar.mjs +3 -3
  18. package/fesm2022/ngwr-back-top.mjs +3 -3
  19. package/fesm2022/ngwr-badge.mjs +6 -6
  20. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  21. package/fesm2022/ngwr-blur-text.mjs +3 -3
  22. package/fesm2022/ngwr-border-glow.mjs +4 -4
  23. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  24. package/fesm2022/ngwr-breadcrumbs.mjs +7 -7
  25. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  26. package/fesm2022/ngwr-burger.mjs +3 -3
  27. package/fesm2022/ngwr-button.mjs +86 -8
  28. package/fesm2022/ngwr-button.mjs.map +1 -1
  29. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  30. package/fesm2022/ngwr-calendar.mjs +3 -3
  31. package/fesm2022/ngwr-card.mjs +9 -9
  32. package/fesm2022/ngwr-carousel.mjs +6 -6
  33. package/fesm2022/ngwr-cascader.mjs +4 -4
  34. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  35. package/fesm2022/ngwr-checkbox.mjs +6 -6
  36. package/fesm2022/ngwr-circular-text.mjs +3 -3
  37. package/fesm2022/ngwr-click-spark.mjs +3 -3
  38. package/fesm2022/ngwr-clipboard.mjs +3 -3
  39. package/fesm2022/ngwr-collapse.mjs +9 -9
  40. package/fesm2022/ngwr-color-picker.mjs +6 -6
  41. package/fesm2022/ngwr-command-palette.mjs +3 -3
  42. package/fesm2022/ngwr-compare.mjs +3 -3
  43. package/fesm2022/ngwr-confetti.mjs +3 -3
  44. package/fesm2022/ngwr-context-menu.mjs +12 -12
  45. package/fesm2022/ngwr-cookie.mjs +3 -3
  46. package/fesm2022/ngwr-counter.mjs +6 -6
  47. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  48. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  49. package/fesm2022/ngwr-date-picker.mjs +18 -18
  50. package/fesm2022/ngwr-date.mjs +3 -3
  51. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  52. package/fesm2022/ngwr-density.mjs +6 -6
  53. package/fesm2022/ngwr-descriptions.mjs +6 -6
  54. package/fesm2022/ngwr-dialog.mjs +15 -15
  55. package/fesm2022/ngwr-directives.mjs +12 -12
  56. package/fesm2022/ngwr-divider.mjs +3 -3
  57. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  58. package/fesm2022/ngwr-drag-drop.mjs +7 -7
  59. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  60. package/fesm2022/ngwr-drawer.mjs +18 -18
  61. package/fesm2022/ngwr-dropdown.mjs +28 -12
  62. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  63. package/fesm2022/ngwr-empty.mjs +3 -3
  64. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  65. package/fesm2022/ngwr-falling-text.mjs +3 -3
  66. package/fesm2022/ngwr-file-upload.mjs +3 -3
  67. package/fesm2022/ngwr-form-testing.mjs +13 -7
  68. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  69. package/fesm2022/ngwr-form.mjs +44 -25
  70. package/fesm2022/ngwr-form.mjs.map +1 -1
  71. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  72. package/fesm2022/ngwr-gauge.mjs +3 -3
  73. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  74. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  75. package/fesm2022/ngwr-hotkey.mjs +6 -6
  76. package/fesm2022/ngwr-i18n.mjs +9 -9
  77. package/fesm2022/ngwr-icon.mjs +6 -6
  78. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  79. package/fesm2022/ngwr-input-number.mjs +3 -3
  80. package/fesm2022/ngwr-input-otp.mjs +3 -3
  81. package/fesm2022/ngwr-input.mjs +24 -20
  82. package/fesm2022/ngwr-input.mjs.map +1 -1
  83. package/fesm2022/ngwr-keyboard.mjs +3 -3
  84. package/fesm2022/ngwr-knob.mjs +3 -3
  85. package/fesm2022/ngwr-layout.mjs +15 -15
  86. package/fesm2022/ngwr-lightbox.mjs +4 -4
  87. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  88. package/fesm2022/ngwr-line-chart.mjs +3 -3
  89. package/fesm2022/ngwr-list.mjs +7 -7
  90. package/fesm2022/ngwr-list.mjs.map +1 -1
  91. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  92. package/fesm2022/ngwr-markdown.mjs +6 -6
  93. package/fesm2022/ngwr-marquee.mjs +3 -3
  94. package/fesm2022/ngwr-media.mjs +3 -3
  95. package/fesm2022/ngwr-mention.mjs +6 -6
  96. package/fesm2022/ngwr-meta.mjs +6 -6
  97. package/fesm2022/ngwr-meter-group.mjs +3 -3
  98. package/fesm2022/ngwr-overlay.mjs +6 -6
  99. package/fesm2022/ngwr-page-header.mjs +3 -3
  100. package/fesm2022/ngwr-pagination.mjs +3 -3
  101. package/fesm2022/ngwr-pipes.mjs +21 -21
  102. package/fesm2022/ngwr-platform.mjs +9 -9
  103. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  104. package/fesm2022/ngwr-popover.mjs +6 -6
  105. package/fesm2022/ngwr-progress.mjs +3 -3
  106. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  107. package/fesm2022/ngwr-qr.mjs +3 -3
  108. package/fesm2022/ngwr-radio.mjs +6 -6
  109. package/fesm2022/ngwr-rating.mjs +48 -22
  110. package/fesm2022/ngwr-rating.mjs.map +1 -1
  111. package/fesm2022/ngwr-result.mjs +12 -12
  112. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  113. package/fesm2022/ngwr-scroll.mjs +3 -3
  114. package/fesm2022/ngwr-segmented.mjs +12 -8
  115. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  116. package/fesm2022/ngwr-select.mjs +125 -26
  117. package/fesm2022/ngwr-select.mjs.map +1 -1
  118. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  119. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  120. package/fesm2022/ngwr-sidebar.mjs +3 -3
  121. package/fesm2022/ngwr-skeleton.mjs +3 -3
  122. package/fesm2022/ngwr-slider.mjs +12 -8
  123. package/fesm2022/ngwr-slider.mjs.map +1 -1
  124. package/fesm2022/ngwr-sparkline.mjs +3 -3
  125. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  126. package/fesm2022/ngwr-spinner.mjs +3 -3
  127. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  128. package/fesm2022/ngwr-split-text.mjs +3 -3
  129. package/fesm2022/ngwr-splitter.mjs +3 -3
  130. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  131. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  132. package/fesm2022/ngwr-squircle.mjs +6 -6
  133. package/fesm2022/ngwr-star-border.mjs +4 -4
  134. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  135. package/fesm2022/ngwr-statistic.mjs +9 -9
  136. package/fesm2022/ngwr-stepper.mjs +6 -6
  137. package/fesm2022/ngwr-storage.mjs +11 -3
  138. package/fesm2022/ngwr-storage.mjs.map +1 -1
  139. package/fesm2022/ngwr-switch.mjs +3 -3
  140. package/fesm2022/ngwr-table.mjs +18 -18
  141. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  142. package/fesm2022/ngwr-tabs.mjs +6 -6
  143. package/fesm2022/ngwr-textarea.mjs +26 -5
  144. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  145. package/fesm2022/ngwr-theme.mjs +90 -4
  146. package/fesm2022/ngwr-theme.mjs.map +1 -1
  147. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  148. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  149. package/fesm2022/ngwr-timeline.mjs +6 -6
  150. package/fesm2022/ngwr-toast.mjs +116 -11
  151. package/fesm2022/ngwr-toast.mjs.map +1 -1
  152. package/fesm2022/ngwr-toolbar.mjs +3 -3
  153. package/fesm2022/ngwr-tour.mjs +6 -6
  154. package/fesm2022/ngwr-transfer.mjs +3 -3
  155. package/fesm2022/ngwr-tree.mjs +18 -11
  156. package/fesm2022/ngwr-tree.mjs.map +1 -1
  157. package/fesm2022/ngwr-typewriter.mjs +3 -3
  158. package/fesm2022/ngwr-typography.mjs +3 -3
  159. package/fesm2022/ngwr-version.mjs +1 -1
  160. package/fesm2022/ngwr-version.mjs.map +1 -1
  161. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  162. package/fesm2022/ngwr-waves.mjs +4 -4
  163. package/fesm2022/ngwr-waves.mjs.map +1 -1
  164. package/fesm2022/ngwr-window.mjs +12 -12
  165. package/llms-full.txt +9 -9
  166. package/llms.txt +82 -11
  167. package/package.json +1 -1
  168. package/shiny-text/styles/_dark.scss +20 -0
  169. package/shiny-text/styles/_index.scss +5 -0
  170. package/shiny-text/styles/_rules.scss +0 -4
  171. package/spotlight-card/styles/_dark.scss +21 -0
  172. package/spotlight-card/styles/_index.scss +5 -0
  173. package/spotlight-card/styles/_rules.scss +0 -6
  174. package/star-border/styles/_dark.scss +21 -0
  175. package/star-border/styles/_index.scss +5 -0
  176. package/star-border/styles/_rules.scss +0 -5
  177. package/theme/styles/_colors.scss +102 -0
  178. package/theme/styles/_focus.scss +31 -1
  179. package/tilt-card/styles/_dark.scss +21 -0
  180. package/tilt-card/styles/_index.scss +5 -0
  181. package/tilt-card/styles/_rules.scss +0 -5
  182. package/types/ngwr-button.d.ts +43 -0
  183. package/types/ngwr-dropdown.d.ts +17 -1
  184. package/types/ngwr-form-testing.d.ts +13 -7
  185. package/types/ngwr-form.d.ts +47 -12
  186. package/types/ngwr-input.d.ts +2 -1
  187. package/types/ngwr-rating.d.ts +25 -4
  188. package/types/ngwr-segmented.d.ts +1 -0
  189. package/types/ngwr-select.d.ts +45 -9
  190. package/types/ngwr-slider.d.ts +1 -0
  191. package/types/ngwr-storage.d.ts +39 -1
  192. package/types/ngwr-textarea.d.ts +20 -0
  193. package/types/ngwr-theme.d.ts +92 -2
  194. package/types/ngwr-toast.d.ts +53 -0
  195. package/types/ngwr-tree.d.ts +3 -2
  196. package/types/ngwr-version.d.ts +1 -1
  197. package/waves/styles/_dark.scss +19 -0
  198. package/waves/styles/_index.scss +5 -0
  199. package/waves/styles/_rules.scss +0 -3
@@ -227,15 +227,17 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
227
227
  */
228
228
  protected readonly controlId: _angular_core.Signal<string | null>;
229
229
  /**
230
- * The field's error message, wired to the same element.
230
+ * The field's error message — or, failing that, its hint — wired to the same
231
+ * element, plus the invalid flag.
231
232
  *
232
- * Without it the messages `<wr-form-field>` renders are visible and nothing else:
233
- * a screen reader on the trigger never learns the field is invalid, nor what the
234
- * message says. `aria-invalid` is keyed on the message EXISTING rather than on
235
- * `errorKeys()`, because the field only publishes an id once it is showing
236
- * something — announcing "invalid" while pointing at nothing is worse than
237
- * staying quiet.
238
- */
233
+ * Without it the copy `<wr-form-field>` renders is visible and nothing else: a
234
+ * screen reader on the trigger never learns the field is invalid, nor what the
235
+ * message says. Composed by `useFormFieldAria()` rather than read off the field
236
+ * here, so the trigger picks up the hint the same way the other value controls
237
+ * do and `aria-invalid` stays keyed on the error rather than on "is anything
238
+ * describing me".
239
+ */
240
+ private readonly fieldAria;
239
241
  protected readonly describedBy: _angular_core.Signal<string | null>;
240
242
  protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
241
243
  /**
@@ -605,8 +607,41 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
605
607
  protected virtualRowId(i: number): string;
606
608
  /** The virtual scroll container inside the overlay panel, if attached. */
607
609
  private get vlistElement();
608
- /** Scroll filtered index `i` just into view (sets the `scrollTop` signal synchronously). */
610
+ /** The scrolling listbox inside the overlay panel, if attached. */
611
+ private get panelElement();
612
+ /**
613
+ * Scroll the ordered index `i` just into view. Two implementations, because the
614
+ * two panels scroll different elements and know the row geometry in different
615
+ * ways — the virtual list is index maths against a measured row height, the
616
+ * projected list has to read the row it is moving to.
617
+ *
618
+ * The non-virtual half is not an optimisation, it is the whole keyboard
619
+ * contract: `activeIndex` drives `aria-activedescendant`, and NOTHING else
620
+ * moves a projected panel, because the rows never take DOM focus. Without it
621
+ * End on a 250-option `mode="search"` panel announced Zimbabwe while the panel
622
+ * sat at `scrollTop` 0 with the cursor 9 218 px below the fold, and Enter then
623
+ * committed a row the user could not see.
624
+ */
609
625
  private ensureVisible;
626
+ /**
627
+ * Scroll the projected row at ordered index `i` just into view.
628
+ *
629
+ * Geometry is READ rather than computed: projected `<wr-option>` rows are
630
+ * consumer content, so they are not a uniform height the way a virtual row is
631
+ * — a row with a description, an icon or a wrapped label is taller than its
632
+ * neighbours, and index maths would land the panel next to the cursor instead
633
+ * of on it. The offset is taken relative to the panel's own scroll content
634
+ * (`rect.top` difference plus the current `scrollTop`) rather than from
635
+ * `offsetTop`, which is measured against whichever ancestor happens to be
636
+ * positioned.
637
+ *
638
+ * `scrollTop` is written directly instead of `scrollTo`, so the write is
639
+ * observable in a spec — jsdom implements the property and does not implement
640
+ * the method. It still reads as a no-op there, since every jsdom rect is 0×0:
641
+ * a spec asserting a scroll has to stub `getBoundingClientRect` and
642
+ * `clientHeight` on the panel and the row, which `select.spec.ts` does.
643
+ */
644
+ private ensureRowVisible;
610
645
  /**
611
646
  * Count of registered options that pass the current search filter.
612
647
  * Hides the noResults state when the panel has at least one visible row.
@@ -674,6 +709,7 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
674
709
  private readonly scrollStrategies;
675
710
  private readonly destroyRef;
676
711
  private readonly platformId;
712
+ private readonly injector;
677
713
  private overlayRef;
678
714
  constructor();
679
715
  isSelected(value: unknown): boolean;
@@ -137,6 +137,7 @@ declare class WrSlider implements FormValueControl<WrSliderValue> {
137
137
  * showing something — announcing "invalid" while pointing at nothing is worse
138
138
  * than staying quiet.
139
139
  */
140
+ private readonly fieldAria;
140
141
  protected readonly describedBy: _angular_core.Signal<string | null>;
141
142
  protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
142
143
  /**
@@ -14,6 +14,9 @@ import * as ngwr_storage from 'ngwr/storage';
14
14
  * lazily on the next `get` / `watch` read.
15
15
  * - **Reactive watch** — `watch(key)` returns a `Signal` that updates on
16
16
  * local writes and cross-tab `storage` events.
17
+ * - **On-disk format** — values are wrapped in a {@link WrStorageEnvelope}
18
+ * (`{"v":…,"e":…}`) while `json` is on. Anything reading the same key from
19
+ * outside Angular has to unwrap it.
17
20
  *
18
21
  * SSR-safe: the default engine factory returns an in-memory shim when
19
22
  * `localStorage` is unavailable, so reads always work.
@@ -60,6 +63,11 @@ declare class WrStorage {
60
63
  /**
61
64
  * Write `value` at `key`. Per-call `ttl` (ms) overrides the config
62
65
  * default. JSON-serializable values only when `json` is on (the default).
66
+ *
67
+ * What lands in the engine is a {@link WrStorageEnvelope} —
68
+ * `{"v":<value>}`, plus `"e"` when a TTL applies — not the bare value. Code
69
+ * outside Angular that reads the same key has to unwrap it; see the envelope's
70
+ * own docs for the exact format.
63
71
  */
64
72
  set<T = unknown>(key: string, value: T, opts?: {
65
73
  ttl?: number;
@@ -118,6 +126,36 @@ interface WrStorageConfig {
118
126
  }
119
127
  /** Fully-resolved config (all defaults filled). @internal */
120
128
  type WrStorageConfigResolved = Required<WrStorageConfig>;
129
+ /**
130
+ * The **on-disk format** `WrStorage` writes while `json` is on (the default).
131
+ *
132
+ * Public because it is a wire format, not an implementation detail: the value in
133
+ * `localStorage` is `JSON.stringify(envelope)`, so anything reading the same key
134
+ * from outside Angular — a pre-paint theme script in `index.html`, a service
135
+ * worker, a native shell, another framework on the same origin — has to know
136
+ * that a stored `'dark'` is spelled `{"v":"dark"}` and not `"dark"`. Left
137
+ * undocumented, the only way to learn that was to read the bundle.
138
+ *
139
+ * `e` is an absolute expiry in epoch milliseconds, written only when a TTL
140
+ * applies; a value past it reads as absent and is removed on the next `get`.
141
+ * A key holding anything else — a bare JSON value, or a string that is not JSON
142
+ * at all — is returned as it stands, so keys written by non-ngwr code keep
143
+ * working.
144
+ *
145
+ * @example
146
+ * ```jsonc
147
+ * // localStorage['wr-theme']
148
+ * { "v": "dark" }
149
+ * // localStorage['cart'], written with { ttl: 60_000 }
150
+ * { "v": [{ "sku": "a1" }], "e": 1767225600000 }
151
+ * ```
152
+ */
153
+ interface WrStorageEnvelope<T = unknown> {
154
+ /** The stored value, as handed to `set()`. */
155
+ readonly v: T;
156
+ /** Absolute expiry, epoch ms. Absent when the write carried no TTL. */
157
+ readonly e?: number;
158
+ }
121
159
 
122
160
  declare const DEFAULT_WR_STORAGE_CONFIG: WrStorageConfigResolved;
123
161
  declare const WR_STORAGE_CONFIG: InjectionToken<Required<ngwr_storage.WrStorageConfig>>;
@@ -185,4 +223,4 @@ interface ProvideWrStorageOptions extends WrStorageConfig {
185
223
  declare function provideWrStorage(options?: ProvideWrStorageOptions): EnvironmentProviders;
186
224
 
187
225
  export { DEFAULT_WR_STORAGE_CONFIG, WR_STORAGE_CONFIG, WR_STORAGE_ENGINE, WrStorage, createMemoryStorage, provideWrStorage };
188
- export type { ProvideWrStorageOptions, WrStorageConfig, WrStorageConfigResolved, WrStorageEngine };
226
+ export type { ProvideWrStorageOptions, WrStorageConfig, WrStorageConfigResolved, WrStorageEngine, WrStorageEnvelope };
@@ -71,6 +71,26 @@ declare class WrTextarea implements FormValueControl<string> {
71
71
  protected readonly effectiveResize: _angular_core.Signal<WrTextareaResize>;
72
72
  /** The surrounding `<wr-form-field>`'s error state. @internal */
73
73
  protected readonly fieldAria: ngwr_form.WrFormFieldAria;
74
+ private readonly field;
75
+ /**
76
+ * Id the surrounding `<wr-form-field>`'s `<label for>` points at.
77
+ *
78
+ * The field renders its label before it can see what was projected into it, so
79
+ * the id travels the other way and the control adopts it, exactly as
80
+ * `[wrInput]` and `wr-select` do. Without it the `for` named an element that
81
+ * was nowhere in the document: clicking the label did nothing, and the field
82
+ * was, to a screen reader, an unlabelled block.
83
+ *
84
+ * It lands on the native `<textarea>` rather than on the host, because only a
85
+ * labelable element can be a label's target and `<wr-textarea>` is not one.
86
+ *
87
+ * What it does NOT change is the NAME: `aria-label` outranks a `<label>` in
88
+ * the accname order and `resolvedAriaLabel()` still wins, the same call
89
+ * `wr-select` and `wr-slider` make — the field renders a label only when its
90
+ * `label` input is set, so it cannot promise a name to fall back on. Set
91
+ * `[ariaLabel]` to the field's label where the two should read alike.
92
+ */
93
+ protected readonly controlId: _angular_core.Signal<string | null>;
74
94
  protected readonly classes: _angular_core.Signal<string>;
75
95
  /** Show the corner grip (hidden when direction is 'none' / autosize / disabled). */
76
96
  protected readonly showHandle: _angular_core.Signal<boolean>;
@@ -164,6 +164,15 @@ declare const WR_THEME_CONFIG: InjectionToken<WrThemeConfig>;
164
164
  * `@use 'ngwr' with ($theme-attribute: '...')`. In dev mode the service compares
165
165
  * the two and warns when they disagree.
166
166
  *
167
+ * **Under SSR or prerendering this service cannot prevent a flash of the wrong
168
+ * theme, and nothing inside the application can.** The server has no
169
+ * `localStorage` and no `prefers-color-scheme`, so every rendered page ships the
170
+ * same attribute (`light` under the default config); by the time the client
171
+ * bundle boots and the effect below corrects it, the browser has already
172
+ * painted. Closing that window takes a script that runs before first paint —
173
+ * {@link wrThemePrePaintScript} emits one that reads the persisted mode exactly
174
+ * the way this service does.
175
+ *
167
176
  * @example
168
177
  * ```ts
169
178
  * const theme = inject(WrTheme);
@@ -237,5 +246,86 @@ declare class WrTheme {
237
246
  */
238
247
  declare function provideWrTheme(config?: Partial<WrThemeConfig>): EnvironmentProviders;
239
248
 
240
- export { DEFAULT_WR_THEME_CONFIG, WR_COLORS, WR_THEME_CONFIG, WrTheme, provideWrTheme, wrContrastFor, wrIntentTokens, wrThemeTokens };
241
- export type { WrColor, WrResolvedTheme, WrThemeConfig, WrThemeMode };
249
+ /**
250
+ * @license
251
+ *
252
+ * Use of this source code is governed by an MIT-style license that can be
253
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
254
+ */
255
+
256
+ /** Options for {@link wrThemePrePaintScript}. All optional — defaults mirror the services. */
257
+ interface WrThemePrePaintOptions {
258
+ /**
259
+ * The key {@link WrTheme} persists the mode under — `provideWrTheme({ storageKey })`.
260
+ * @default 'wr-theme'
261
+ */
262
+ readonly storageKey?: string;
263
+ /**
264
+ * The attribute written on `<html>` — `provideWrTheme({ attribute })`, which
265
+ * has to agree with `@use 'ngwr' with ($theme-attribute: '…')`.
266
+ * @default 'data-theme'
267
+ */
268
+ readonly attribute?: string;
269
+ /**
270
+ * What to resolve when nothing is persisted — `provideWrTheme({ defaultMode })`.
271
+ * @default 'auto'
272
+ */
273
+ readonly defaultMode?: WrThemeMode;
274
+ /**
275
+ * `WrStorage`'s key prefix — `provideWrStorage({ prefix })`. The script reads
276
+ * the raw key, so a prefixed app has to pass the same string here.
277
+ * @default ''
278
+ */
279
+ readonly storagePrefix?: string;
280
+ /**
281
+ * Whether `WrStorage` wraps values in its JSON envelope —
282
+ * `provideWrStorage({ json })`. The emitted reader accepts both shapes either
283
+ * way; this only decides which one it tries first, and is here so the option
284
+ * cannot be silently forgotten when an app turns the envelope off.
285
+ * @default true
286
+ */
287
+ readonly json?: boolean;
288
+ }
289
+ /**
290
+ * Source of the blocking script that resolves the theme BEFORE first paint.
291
+ *
292
+ * A server has no `localStorage` and no `prefers-color-scheme`, so every
293
+ * server-rendered or prerendered page ships the same attribute — `light` under
294
+ * the default config — and a dark-mode visitor sees a white page until the
295
+ * client bundle boots and {@link WrTheme}'s effect corrects it. That window is
296
+ * milliseconds on localhost and seconds on a slow connection, and it is not
297
+ * something the service can close from inside the application: by the time
298
+ * Angular runs, the paint has happened.
299
+ *
300
+ * The only fix is a script that runs before the first paint, and the only thing
301
+ * it needs to know is how {@link WrTheme} and `WrStorage` agree to spell the
302
+ * persisted mode. That agreement — the key, the prefix, the JSON envelope
303
+ * `{ v, e }`, the expiry, the `auto` fallback — is what this function writes
304
+ * out, so an app never has to re-derive it from the bundle and never has to keep
305
+ * a hand-copied version in step with a library upgrade.
306
+ *
307
+ * Returns the JS source WITHOUT a `<script>` wrapper, so it can be inlined into
308
+ * `index.html`, emitted from an SSR template, or hashed for a CSP
309
+ * `script-src 'sha256-…'`. It is plain ES5 with no dependency on the app bundle,
310
+ * and every step is wrapped so a blocked `localStorage` (private mode, a
311
+ * sandboxed iframe) leaves the prerendered default in place rather than throwing
312
+ * before anything has rendered.
313
+ *
314
+ * Pass the same values given to `provideWrTheme()` / `provideWrStorage()`; the
315
+ * defaults here are the defaults there.
316
+ *
317
+ * @example
318
+ * ```ts
319
+ * // Build step / SSR template:
320
+ * const html = template.replace('<!--theme-->', `<script>${wrThemePrePaintScript()}</script>`);
321
+ *
322
+ * // Or paste the output straight into <head>, above every stylesheet:
323
+ * // <script>(function(){ … })();</script>
324
+ * ```
325
+ *
326
+ * @see https://ngwr.dev/reference/services/theme
327
+ */
328
+ declare function wrThemePrePaintScript(options?: WrThemePrePaintOptions): string;
329
+
330
+ export { DEFAULT_WR_THEME_CONFIG, WR_COLORS, WR_THEME_CONFIG, WrTheme, provideWrTheme, wrContrastFor, wrIntentTokens, wrThemePrePaintScript, wrThemeTokens };
331
+ export type { WrColor, WrResolvedTheme, WrThemeConfig, WrThemeMode, WrThemePrePaintOptions };
@@ -166,6 +166,8 @@ declare class WrToast {
166
166
  private readonly config;
167
167
  private overlayRef;
168
168
  private hostRef;
169
+ /** Watches the overlay container for overlays opened after the host. */
170
+ private containerObserver;
169
171
  private currentPosition;
170
172
  private currentMode;
171
173
  private nextId;
@@ -187,6 +189,49 @@ declare class WrToast {
187
189
  private startTimer;
188
190
  private pauseTimer;
189
191
  private ensureHost;
192
+ /**
193
+ * Put the host back on top of the browser's top layer.
194
+ *
195
+ * The stacking rule here is not a z-index and cannot be fixed with one. CDK 22
196
+ * promotes every overlay by calling `showPopover()` on its host element, and
197
+ * the top layer is ordered by the MOMENT of promotion — a popover shown later
198
+ * paints over one shown earlier no matter what either element's z-index, DOM
199
+ * order or containing block says. The toast host is created once and kept
200
+ * alive until the last toast leaves, so its place in that order is frozen at
201
+ * whenever the first toast of the run appeared. Every dialog and drawer opened
202
+ * after that sits above it.
203
+ *
204
+ * The symptom was as bad as the mechanism is quiet: a toast raised from inside
205
+ * an open dialog rendered UNDER the dialog's backdrop, dimmed by it and
206
+ * hit-tested as it — so the close button was unreachable and clicking where it
207
+ * appeared closed the dialog instead. Nothing threw, and a toast with
208
+ * `duration: 0` never went away on its own.
209
+ *
210
+ * Hiding and re-showing moves the host to the end of the top layer. Both calls
211
+ * happen in one task, so there is no frame in which the host is `display:
212
+ * none` and nothing re-runs a toast's enter animation.
213
+ *
214
+ * Skipped while focus is inside the host: Chromium keeps focus across this
215
+ * pair, but the hide-popover algorithm is specified to restore focus to the
216
+ * previously focused element, and a host the user is already tabbing through
217
+ * is by definition reachable. In practice the two never coincide — a modal
218
+ * traps focus, so focus inside the host means nothing is above it to escape.
219
+ */
220
+ private raiseHost;
221
+ /**
222
+ * Re-raise the host whenever another overlay joins the container.
223
+ *
224
+ * `show()` covers the reported order (toast raised while a dialog is up). This
225
+ * covers the mirror image, which is the same defect seen from the other side:
226
+ * a toast already on screen when the dialog opens is left under it, unclickable
227
+ * for the rest of its duration, and no further `show()` is coming to fix it.
228
+ *
229
+ * Observing the host's own parent rather than a container resolved from the
230
+ * injector keeps this correct whether or not `provideWrOverlay()` is installed
231
+ * — the host is in whichever container it was actually appended to. Re-showing
232
+ * a popover moves nothing in the DOM, so this cannot re-trigger itself.
233
+ */
234
+ private watchForNewerOverlays;
190
235
  /** Fill any free stack slots from the queue (FIFO), starting each promoted
191
236
  * toast's auto-dismiss timer only as it becomes visible. */
192
237
  private promoteFromQueue;
@@ -222,6 +267,14 @@ declare class WrToast {
222
267
  * ],
223
268
  * });
224
269
  * ```
270
+ *
271
+ * **Bootstrap only, and the three ngwr providers differ here.** {@link WrToast}
272
+ * is root-provided, so it reads this token once from the ROOT injector — a
273
+ * `provideWrToastConfig()` in a route's `providers` is never seen, and used to
274
+ * be ignored in silence. It now warns in dev mode instead. By contrast
275
+ * `provideWrConfig()` IS read per route, because components resolve it from
276
+ * their own injector, and `provideWrIcons()` works at any level and chains, so
277
+ * a route may add icons to the set its parent registered.
225
278
  */
226
279
  declare function provideWrToastConfig(config: Partial<Omit<WrToastConfig, 'labels'>> & {
227
280
  readonly labels?: Partial<WrToastConfig['labels']>;
@@ -165,8 +165,9 @@ declare class WrTree<TId = string> implements FormValueControl<unknown> {
165
165
  /**
166
166
  * Form value — the current selection as seen by a bound field. Bound by
167
167
  * `[formField]`, or two-way via `[(value)]`. Shape follows `selectionMode`:
168
- * `TId | null` in single mode, `readonly TId[]` in multi mode. Meaningful in
169
- * `overlay` mode; inline mode drives selection via `[(selected)]` instead.
168
+ * `TId | null` in single mode, `readonly TId[]` in multi mode. Works in both
169
+ * `openOn` modes; `[(selected)]` stays the inline-native API and always
170
+ * carries an array, whatever the selection mode.
170
171
  */
171
172
  readonly value: _angular_core.ModelSignal<unknown>;
172
173
  /** Emitted on blur so a bound field can mark itself touched. */
@@ -16,7 +16,7 @@ import { InjectionToken } from '@angular/core';
16
16
  * Distinct from `Version` exported by `@angular/core`, which reports the
17
17
  * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.
18
18
  */
19
- declare const NGWR_VERSION = "14.0.0";
19
+ declare const NGWR_VERSION = "14.0.1";
20
20
 
21
21
  /**
22
22
  * @license
@@ -0,0 +1,19 @@
1
+ // Dark theme.
2
+ //
3
+ // Keyed on `theme.dark-selector()`, never on a literal `[data-theme='dark']`.
4
+ // The attribute is renameable — `@use 'ngwr' with ($theme-attribute: '…')`
5
+ // alongside `provideWrTheme({ attribute: '…' })` — and a hand-written literal
6
+ // misses the rename in both directions: this block stops firing under the
7
+ // configured name, and it keeps firing under `data-theme`, which is the
8
+ // attribute a foreign design system owns and the rename exists to escape.
9
+ //
10
+ // It lives outside the `styleUrl` closure for the same reason. A component
11
+ // stylesheet is compiled when the LIBRARY is built, where `$theme-attribute` can
12
+ // only ever be the default, and Angular appends that copy after the app's linked
13
+ // sheet — so an inlined literal would not merely be dead, it would outrank the
14
+ // correctly-named rule beside it.
15
+ @use '../../theme/styles' as theme;
16
+
17
+ #{theme.dark-selector()} .wr-waves {
18
+ --wr-waves-line-color: rgb(255 255 255 / 14%);
19
+ }
@@ -11,5 +11,10 @@
11
11
  // box-sizing reset into the compiled component styles, which ng-packagr then
12
12
  // embeds in the FESM bundle as a string. `waves.scss` forwards `_rules`
13
13
  // instead, so it carries this component's own CSS and nothing else.
14
+ //
15
+ // `_dark` is loaded from HERE for a second reason: its selector is built out of
16
+ // `$theme-attribute`, which only a stylesheet compiled by the consuming app can
17
+ // configure, so a copy inside the bundle could only ever carry the default name.
14
18
  @use '../../theme/styles';
15
19
  @forward 'rules';
20
+ @forward 'dark';
@@ -40,6 +40,3 @@
40
40
  }
41
41
  }
42
42
 
43
- [data-theme='dark'] .wr-waves {
44
- --wr-waves-line-color: rgb(255 255 255 / 14%);
45
- }