ngwr 11.0.0 → 11.2.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.
Files changed (237) hide show
  1. package/action-sheet/styles/_index.scss +4 -1
  2. package/anchor/styles/_index.scss +2 -1
  3. package/calendar/styles/_index.scss +11 -2
  4. package/cascader/styles/_index.scss +3 -1
  5. package/circular-text/styles/_index.scss +11 -0
  6. package/command-palette/styles/_index.scss +14 -1
  7. package/context-menu/styles/_index.scss +2 -1
  8. package/falling-text/styles/_index.scss +2 -1
  9. package/fesm2022/ngwr-action-sheet-testing.mjs +313 -0
  10. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -0
  11. package/fesm2022/ngwr-bar-chart-testing.mjs +89 -0
  12. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -0
  13. package/fesm2022/ngwr-blur-text-testing.mjs +203 -0
  14. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -0
  15. package/fesm2022/ngwr-blur-text.mjs +15 -1
  16. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  17. package/fesm2022/ngwr-border-glow-testing.mjs +325 -0
  18. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -0
  19. package/fesm2022/ngwr-border-glow.mjs +2 -2
  20. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  21. package/fesm2022/ngwr-calendar-heatmap-testing.mjs +95 -0
  22. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -0
  23. package/fesm2022/ngwr-calendar-testing.mjs +368 -0
  24. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -0
  25. package/fesm2022/ngwr-calendar.mjs +43 -3
  26. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  27. package/fesm2022/ngwr-card.mjs +2 -2
  28. package/fesm2022/ngwr-cascader.mjs +14 -2
  29. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  30. package/fesm2022/ngwr-checkbox.mjs +8 -0
  31. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  32. package/fesm2022/ngwr-circular-text-testing.mjs +230 -0
  33. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -0
  34. package/fesm2022/ngwr-circular-text.mjs +2 -2
  35. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  36. package/fesm2022/ngwr-color-picker-testing.mjs +432 -0
  37. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -0
  38. package/fesm2022/ngwr-color-picker.mjs +29 -3
  39. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  40. package/fesm2022/ngwr-context-menu.mjs +25 -5
  41. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  42. package/fesm2022/ngwr-date-picker-testing.mjs +10 -79
  43. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  44. package/fesm2022/ngwr-decrypt-text-testing.mjs +261 -0
  45. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -0
  46. package/fesm2022/ngwr-decrypt-text.mjs +6 -1
  47. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  48. package/fesm2022/ngwr-donut-chart-testing.mjs +93 -0
  49. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -0
  50. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  51. package/fesm2022/ngwr-drawer.mjs +36 -7
  52. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  53. package/fesm2022/ngwr-dropdown.mjs +32 -2
  54. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  55. package/fesm2022/ngwr-event-calendar-testing.mjs +446 -0
  56. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -0
  57. package/fesm2022/ngwr-event-calendar.mjs +43 -18
  58. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  59. package/fesm2022/ngwr-falling-text-testing.mjs +218 -0
  60. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -0
  61. package/fesm2022/ngwr-falling-text.mjs +2 -2
  62. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  63. package/fesm2022/ngwr-fuzzy-text-testing.mjs +134 -0
  64. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -0
  65. package/fesm2022/ngwr-gauge-testing.mjs +86 -0
  66. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -0
  67. package/fesm2022/ngwr-glitch-text-testing.mjs +181 -0
  68. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -0
  69. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  70. package/fesm2022/ngwr-gradient-text-testing.mjs +223 -0
  71. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
  72. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  73. package/fesm2022/ngwr-i18n-en.mjs +14 -0
  74. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  75. package/fesm2022/ngwr-i18n-ru.mjs +14 -0
  76. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  77. package/fesm2022/ngwr-image-cropper-testing.mjs +156 -0
  78. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -0
  79. package/fesm2022/ngwr-image-cropper.mjs +10 -3
  80. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  81. package/fesm2022/ngwr-input-number.mjs +73 -6
  82. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  83. package/fesm2022/ngwr-knob-testing.mjs +220 -0
  84. package/fesm2022/ngwr-knob-testing.mjs.map +1 -0
  85. package/fesm2022/ngwr-lightbox-testing.mjs +223 -0
  86. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -0
  87. package/fesm2022/ngwr-lightbox.mjs +9 -2
  88. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  89. package/fesm2022/ngwr-line-chart-testing.mjs +119 -0
  90. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -0
  91. package/fesm2022/ngwr-list.mjs +2 -2
  92. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  93. package/fesm2022/ngwr-marquee-testing.mjs +336 -0
  94. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
  95. package/fesm2022/ngwr-marquee.mjs +2 -2
  96. package/fesm2022/ngwr-meter-group-testing.mjs +80 -0
  97. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -0
  98. package/fesm2022/ngwr-overlay.mjs +28 -1
  99. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  100. package/fesm2022/ngwr-popover.mjs +14 -0
  101. package/fesm2022/ngwr-popover.mjs.map +1 -1
  102. package/fesm2022/ngwr-rotating-text-testing.mjs +220 -0
  103. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -0
  104. package/fesm2022/ngwr-rotating-text.mjs +2 -2
  105. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  106. package/fesm2022/ngwr-select.mjs +70 -11
  107. package/fesm2022/ngwr-select.mjs.map +1 -1
  108. package/fesm2022/ngwr-shiny-text-testing.mjs +237 -0
  109. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -0
  110. package/fesm2022/ngwr-shiny-text.mjs +2 -2
  111. package/fesm2022/ngwr-slider.mjs +44 -6
  112. package/fesm2022/ngwr-slider.mjs.map +1 -1
  113. package/fesm2022/ngwr-sparkline-testing.mjs +76 -0
  114. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -0
  115. package/fesm2022/ngwr-speed-dial-testing.mjs +279 -0
  116. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -0
  117. package/fesm2022/ngwr-splash-cursor-testing.mjs +89 -0
  118. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -0
  119. package/fesm2022/ngwr-split-text-testing.mjs +224 -0
  120. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -0
  121. package/fesm2022/ngwr-split-text.mjs +15 -1
  122. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  123. package/fesm2022/ngwr-splitter-testing.mjs +245 -0
  124. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -0
  125. package/fesm2022/ngwr-spotlight-card-testing.mjs +368 -0
  126. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -0
  127. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  128. package/fesm2022/ngwr-star-border-testing.mjs +172 -0
  129. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
  130. package/fesm2022/ngwr-star-border.mjs +2 -2
  131. package/fesm2022/ngwr-table.mjs +13 -3
  132. package/fesm2022/ngwr-table.mjs.map +1 -1
  133. package/fesm2022/ngwr-tabs.mjs +15 -1
  134. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  135. package/fesm2022/ngwr-tilt-card-testing.mjs +190 -0
  136. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -0
  137. package/fesm2022/ngwr-tilt-card.mjs +21 -3
  138. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  139. package/fesm2022/ngwr-toast.mjs +36 -7
  140. package/fesm2022/ngwr-toast.mjs.map +1 -1
  141. package/fesm2022/ngwr-tour-testing.mjs +173 -0
  142. package/fesm2022/ngwr-tour-testing.mjs.map +1 -0
  143. package/fesm2022/ngwr-tour.mjs +2 -2
  144. package/fesm2022/ngwr-tour.mjs.map +1 -1
  145. package/fesm2022/ngwr-tree.mjs +10 -3
  146. package/fesm2022/ngwr-tree.mjs.map +1 -1
  147. package/fesm2022/ngwr-typewriter-testing.mjs +228 -0
  148. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -0
  149. package/fesm2022/ngwr-typewriter.mjs +2 -2
  150. package/fesm2022/ngwr-version.mjs +1 -1
  151. package/fesm2022/ngwr-version.mjs.map +1 -1
  152. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  153. package/fesm2022/ngwr-waves-testing.mjs +128 -0
  154. package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
  155. package/fesm2022/ngwr-waves.mjs +2 -2
  156. package/fesm2022/ngwr-window-testing.mjs +361 -0
  157. package/fesm2022/ngwr-window-testing.mjs.map +1 -0
  158. package/fesm2022/ngwr-window.mjs +84 -10
  159. package/fesm2022/ngwr-window.mjs.map +1 -1
  160. package/file-upload/styles/_index.scss +7 -2
  161. package/i18n/en.json +16 -2
  162. package/i18n/ru.json +16 -2
  163. package/llms-full.txt +147 -0
  164. package/llms.txt +27 -8
  165. package/mcp/providers.js +29 -0
  166. package/mcp/tools.js +1 -29
  167. package/package.json +145 -1
  168. package/result/styles/_index.scss +3 -1
  169. package/segmented/styles/_index.scss +5 -1
  170. package/select/styles/_index.scss +3 -1
  171. package/skills/ngwr/SKILL.md +115 -0
  172. package/skills/ngwr/references/catalog.md +212 -0
  173. package/skills/ngwr/references/setup.md +73 -0
  174. package/stepper/styles/_index.scss +18 -2
  175. package/table/styles/_index.scss +3 -1
  176. package/theme/styles/_colors.scss +15 -2
  177. package/theme/styles/_dark.scss +24 -12
  178. package/tree/styles/_index.scss +4 -2
  179. package/types/ngwr-action-sheet-testing.d.ts +260 -0
  180. package/types/ngwr-bar-chart-testing.d.ts +77 -0
  181. package/types/ngwr-blur-text-testing.d.ts +180 -0
  182. package/types/ngwr-blur-text.d.ts +12 -0
  183. package/types/ngwr-border-glow-testing.d.ts +219 -0
  184. package/types/ngwr-calendar-heatmap-testing.d.ts +79 -0
  185. package/types/ngwr-calendar-testing.d.ts +277 -0
  186. package/types/ngwr-calendar.d.ts +10 -0
  187. package/types/ngwr-checkbox.d.ts +13 -0
  188. package/types/ngwr-circular-text-testing.d.ts +196 -0
  189. package/types/ngwr-color-picker-testing.d.ts +291 -0
  190. package/types/ngwr-color-picker.d.ts +13 -1
  191. package/types/ngwr-context-menu.d.ts +15 -1
  192. package/types/ngwr-date-picker-testing.d.ts +6 -66
  193. package/types/ngwr-decrypt-text-testing.d.ts +222 -0
  194. package/types/ngwr-donut-chart-testing.d.ts +79 -0
  195. package/types/ngwr-drawer.d.ts +12 -0
  196. package/types/ngwr-dropdown.d.ts +9 -0
  197. package/types/ngwr-event-calendar-testing.d.ts +301 -0
  198. package/types/ngwr-event-calendar.d.ts +9 -6
  199. package/types/ngwr-falling-text-testing.d.ts +186 -0
  200. package/types/ngwr-fuzzy-text-testing.d.ts +130 -0
  201. package/types/ngwr-gauge-testing.d.ts +71 -0
  202. package/types/ngwr-glitch-text-testing.d.ts +172 -0
  203. package/types/ngwr-gradient-text-testing.d.ts +173 -0
  204. package/types/ngwr-image-cropper-testing.d.ts +134 -0
  205. package/types/ngwr-image-cropper.d.ts +1 -0
  206. package/types/ngwr-input-number.d.ts +33 -1
  207. package/types/ngwr-knob-testing.d.ts +150 -0
  208. package/types/ngwr-lightbox-testing.d.ts +154 -0
  209. package/types/ngwr-lightbox.d.ts +6 -0
  210. package/types/ngwr-line-chart-testing.d.ts +93 -0
  211. package/types/ngwr-marquee-testing.d.ts +280 -0
  212. package/types/ngwr-meter-group-testing.d.ts +67 -0
  213. package/types/ngwr-overlay.d.ts +19 -1
  214. package/types/ngwr-rotating-text-testing.d.ts +191 -0
  215. package/types/ngwr-select.d.ts +32 -0
  216. package/types/ngwr-shiny-text-testing.d.ts +165 -0
  217. package/types/ngwr-slider.d.ts +15 -0
  218. package/types/ngwr-sparkline-testing.d.ts +69 -0
  219. package/types/ngwr-speed-dial-testing.d.ts +195 -0
  220. package/types/ngwr-splash-cursor-testing.d.ts +95 -0
  221. package/types/ngwr-split-text-testing.d.ts +209 -0
  222. package/types/ngwr-split-text.d.ts +12 -0
  223. package/types/ngwr-splitter-testing.d.ts +174 -0
  224. package/types/ngwr-spotlight-card-testing.d.ts +303 -0
  225. package/types/ngwr-star-border-testing.d.ts +135 -0
  226. package/types/ngwr-table.d.ts +10 -1
  227. package/types/ngwr-tilt-card-testing.d.ts +158 -0
  228. package/types/ngwr-tilt-card.d.ts +2 -0
  229. package/types/ngwr-toast.d.ts +14 -5
  230. package/types/ngwr-tour-testing.d.ts +143 -0
  231. package/types/ngwr-tree.d.ts +7 -0
  232. package/types/ngwr-typewriter-testing.d.ts +201 -0
  233. package/types/ngwr-version.d.ts +1 -1
  234. package/types/ngwr-waves-testing.d.ts +121 -0
  235. package/types/ngwr-window-testing.d.ts +263 -0
  236. package/types/ngwr-window.d.ts +27 -10
  237. package/window/styles/_index.scss +44 -16
@@ -105,12 +105,21 @@ interface WrToastConfig {
105
105
  * @default 5
106
106
  */
107
107
  readonly maxStack: number;
108
- /** Labels rendered in the UI. Keep short — meant to be overridden for i18n. */
108
+ /**
109
+ * Labels rendered in the UI. Keep short.
110
+ *
111
+ * `null` — the default for every one of them — means "resolve it from the
112
+ * `ngwr/i18n` catalog", which is what makes a Russian app announce a Russian
113
+ * close button without configuring the toast at all. They were English
114
+ * literals here until v11, so the four `toast.*` keys in the shipped catalogs
115
+ * were never read by anything. A string set here still WINS over the catalog:
116
+ * this is the consumer's explicit override, not a default.
117
+ */
109
118
  readonly labels: {
110
- readonly close: string;
111
- readonly copy: string;
112
- readonly copied: string;
113
- readonly closeAll: string;
119
+ readonly close: string | null;
120
+ readonly copy: string | null;
121
+ readonly copied: string | null;
122
+ readonly closeAll: string | null;
114
123
  };
115
124
  }
116
125
 
@@ -0,0 +1,143 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+
10
+ /** Narrows which tour popup a harness query matches. */
11
+ interface WrTourHarnessFilters extends BaseHarnessFilters {
12
+ /** Match the step's heading — a string is an exact match, a RegExp is tested. */
13
+ readonly title?: string | RegExp;
14
+ /** Match the step's body copy. */
15
+ readonly content?: string | RegExp;
16
+ }
17
+ /** Which step of how many, as the popup prints it. */
18
+ interface WrTourProgress {
19
+ /** One-based, the way the card counts. */
20
+ readonly current: number;
21
+ /** How many steps the tour was STARTED with — not how many it will show. */
22
+ readonly total: number;
23
+ }
24
+
25
+ /**
26
+ * @license
27
+ *
28
+ * Use of this source code is governed by an MIT-style license that can be
29
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
30
+ */
31
+
32
+ /**
33
+ * Test harness for the card `WrTour` shows beside the spotlit element.
34
+ *
35
+ * `WrTour` is a service with no element of its own, so there is nothing in your
36
+ * fixture to load: the popup is a portal in the NGWR overlay container, and this
37
+ * comes from `TestbedHarnessEnvironment.documentRootLoader()`. **One card exists at
38
+ * a time** — the service tears the whole step down before opening the next — so a
39
+ * harness held across {@link next} is pointed at a detached element, and a fresh one
40
+ * has to be fetched per step.
41
+ *
42
+ * **The card is rebuilt per step, and that is what makes `getHarnessOrNull` the way
43
+ * to ask whether a tour is running.** There is no "closed" state to read: the popup,
44
+ * the overlay and the spotlight all go away together.
45
+ *
46
+ * **What "last" means here is not `current === total`.** A step whose target is not
47
+ * on the page is skipped, so a tour of three steps can show two, and the service
48
+ * looks AHEAD for a reachable one to decide what the primary button says.
49
+ * {@link getProgress} reports the printed count, {@link getPrimaryLabel} what the
50
+ * button actually reads — asserting the second is what catches a card that says
51
+ * "Next" and then ends the tour.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
56
+ * tour.start(steps);
57
+ * await fixture.whenStable();
58
+ *
59
+ * const card = await rootLoader.getHarness(WrTourHarness);
60
+ * expect(await card.getTitle()).toBe('Search');
61
+ * await card.next();
62
+ * ```
63
+ *
64
+ * @see https://ngwr.dev/guides/testing
65
+ */
66
+ declare class WrTourHarness extends ComponentHarness {
67
+ static hostSelector: string;
68
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
69
+ static with(options?: WrTourHarnessFilters): HarnessPredicate<WrTourHarness>;
70
+ /**
71
+ * Whether this card is still on the page.
72
+ *
73
+ * For a harness you are already HOLDING: moving to another step disposes the
74
+ * overlay, so this flips to `false` where a fresh `getHarnessOrNull()` answers
75
+ * with the NEW card rather than with nothing.
76
+ */
77
+ isShowing(): Promise<boolean>;
78
+ /** The step's heading, or `null` for a step given no `title`. */
79
+ getTitle(): Promise<string | null>;
80
+ /** The step's body copy. */
81
+ getContent(): Promise<string>;
82
+ /** The progress line as printed, e.g. `Step 2 of 4`. */
83
+ getProgressText(): Promise<string>;
84
+ /**
85
+ * The two numbers out of the progress line, or `null` when it does not hold two.
86
+ *
87
+ * Parsed from the rendered string rather than asked of the service, because the
88
+ * service is not something a harness can reach — and the string is what the user
89
+ * actually gets. A catalog that spells the numbers as words, or reverses them,
90
+ * makes this `null` instead of a wrong answer; assert {@link getProgressText} in
91
+ * that case.
92
+ *
93
+ * `total` is how many steps the tour was STARTED with, not how many it will show:
94
+ * a step whose target is missing is skipped and still counted here, which is the
95
+ * component's own choice and worth knowing before writing an assertion on it.
96
+ */
97
+ getProgress(): Promise<WrTourProgress | null>;
98
+ /**
99
+ * The name the card announces — its title and the progress line, or just the
100
+ * progress line for an untitled step.
101
+ *
102
+ * The card is an `aria-modal` dialog, so it needs a name; the progress line is
103
+ * what an untitled step has instead of one.
104
+ */
105
+ getAccessibleName(): Promise<string | null>;
106
+ /** Whether the card announces itself as a modal dialog. */
107
+ isModal(): Promise<boolean>;
108
+ /**
109
+ * Whether the card offers a Back button — which is the same question as "is this
110
+ * the first step", since the button is only rendered past it.
111
+ */
112
+ hasBack(): Promise<boolean>;
113
+ /**
114
+ * What the primary button READS — the "next" label, or the "done" one on the last
115
+ * step the user will see.
116
+ *
117
+ * The assertion worth writing, and not derivable from the count: the service looks
118
+ * ahead for a step whose target is still on the page, so a tour whose last step is
119
+ * hidden ends one card early and this is the only place that shows.
120
+ */
121
+ getPrimaryLabel(): Promise<string>;
122
+ /** The Skip button's label. */
123
+ getSkipLabel(): Promise<string>;
124
+ /** The Back button's label. Throws on the first step, where there is none. */
125
+ getBackLabel(): Promise<string>;
126
+ /**
127
+ * Press the primary button — the next step, or the end of the tour.
128
+ *
129
+ * Composed through {@link WrButtonHarness} rather than clicking an element: these
130
+ * are `wr-btn`s, and that harness already knows how one reports being off.
131
+ */
132
+ next(): Promise<void>;
133
+ /** Press Back. Throws on the first step, where the button is not rendered. */
134
+ back(): Promise<void>;
135
+ /** Press Skip — ending the tour without finishing it. */
136
+ skipTour(): Promise<void>;
137
+ private primary;
138
+ private skip;
139
+ private backButton;
140
+ }
141
+
142
+ export { WrTourHarness };
143
+ export type { WrTourHarnessFilters, WrTourProgress };
@@ -93,6 +93,13 @@ declare class WrTree<TId = string> implements FormValueControl<unknown> {
93
93
  readonly openOn: _angular_core.InputSignal<"inline" | "overlay">;
94
94
  /** Placeholder shown on the trigger when no node is selected. */
95
95
  readonly placeholder: _angular_core.InputSignal<string>;
96
+ /**
97
+ * The same fall-through `wr-select` has had all along: an unset placeholder
98
+ * takes the catalog's `tree.placeholder`, so an overlay trigger with nothing
99
+ * selected reads "Select…" in the app's language instead of rendering an
100
+ * empty span. The key shipped in both catalogs and nothing read it.
101
+ */
102
+ protected readonly resolvedPlaceholder: _angular_core.Signal<string>;
96
103
  /**
97
104
  * Accessible name of the overlay trigger. Falls back to the placeholder, then
98
105
  * to `select.label` — a `role="combobox"` with nothing selected and no
@@ -0,0 +1,201 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+
10
+ /** Narrows which `<wr-typewriter>` a harness query matches. */
11
+ interface WrTypewriterHarnessFilters extends BaseHarnessFilters {
12
+ /**
13
+ * Match what the machine has typed SO FAR — a prefix while it is still going, the
14
+ * whole sentence once it settles, and the empty string before the first tick. A
15
+ * string is an exact match, a RegExp is tested.
16
+ *
17
+ * There is nothing steadier to match on: the component holds no copy of the phrase
18
+ * it is working towards, so a filter cannot address a typewriter by what it is
19
+ * going to say. Pin the clock first — `vi.useFakeTimers` and an explicit advance —
20
+ * or match a RegExp loose enough to survive whichever frame the query lands on.
21
+ */
22
+ readonly text?: string | RegExp;
23
+ /**
24
+ * Match typewriters showing a caret (`true`) or none at all (`false`).
25
+ *
26
+ * The cursor is REMOVED from the DOM rather than hidden, so this changes mid-run on
27
+ * anything with `hideCursorWhileTyping` — see `WrTypewriterHarness.hasCursor`. On a
28
+ * default typewriter it is stable, and it is the one way to tell two otherwise
29
+ * identical machines apart.
30
+ */
31
+ readonly hasCursor?: boolean;
32
+ }
33
+
34
+ /**
35
+ * @license
36
+ *
37
+ * Use of this source code is governed by an MIT-style license that can be
38
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
39
+ */
40
+
41
+ /**
42
+ * Test harness for `<wr-typewriter>`.
43
+ *
44
+ * **The typed string is the entire component, and it is a moving target.**
45
+ * {@link getText} reads the one text node the machine writes into, which mid-run holds
46
+ * a FRAGMENT — `'Hell'` on the way to `'Hello'` — and between sentences holds whatever
47
+ * is left of the previous one. That is not a limitation to work around; it is what the
48
+ * component renders, and pinning it tick by tick is what proves the machine types one
49
+ * character at a time, deletes one at a time, pauses, cycles, and stops when told not to
50
+ * loop. Install fake timers for `setTimeout` / `clearTimeout` only and advance the clock
51
+ * yourself before every read — awaiting a harness method flushes microtasks, never
52
+ * timers, so an unadvanced read answers with the previous frame.
53
+ *
54
+ * **What is typed is also what is announced, and no second copy exists.** There is
55
+ * deliberately no `getAccessibleText()` here: the component renders one plain text node
56
+ * and nothing else, so a screen reader landing mid-word hears the fragment. (Its sibling
57
+ * `wr-rotating-text` carries a visually-hidden copy of the whole phrase; this one does
58
+ * not, and inventing a method that implied otherwise would report an accessible layer
59
+ * that is not there.) The single a11y decision the component does make is the caret, and
60
+ * {@link isCursorDecorative} is how a spec holds it: without `aria-hidden` every phrase
61
+ * is announced as `Hello pipe`, and nothing else in the DOM would change.
62
+ *
63
+ * **The methods that are missing are missing on purpose.** There is no `isTyping()` or
64
+ * `getPhase()` — the phase is a private signal that never reaches the document, and its
65
+ * only proxy, the caret vanishing, exists solely when `hideCursorWhileTyping` is set, so
66
+ * the method would report "not typing" for the DEFAULT configuration while the machine
67
+ * types. No `isComplete()` / `isFinished()`: a machine stopped on its last sentence and
68
+ * one pausing between sentences render the identical string and the identical caret, so
69
+ * assert the `sentenceComplete` output instead. No `isCursorBlinking()` /
70
+ * `getCursorOpacity()`: the blink is a `@keyframes` rule from a stylesheet a unit test
71
+ * never loads, and a mid-animation opacity is a number that means nothing.
72
+ * No `isVisible()` / `waitForVisible()`: `startOnVisible` hangs off an
73
+ * `IntersectionObserver` jsdom does not implement, so any answer would be the spec's own
74
+ * stub echoing back. And no `getTypingSpeed()` / `getDeletingSpeed()` /
75
+ * `getPauseDuration()` / `getInitialDelay()`: none of them is ever written to the DOM, so
76
+ * reading them would mean reading the component instance rather than the rendered
77
+ * control. They are observable exactly once — as the cadence of {@link getText}.
78
+ *
79
+ * What DOES survive a test with no layout, besides the string: the caret's presence,
80
+ * glyph and `aria-hidden`, and the two values the host writes inline —
81
+ * {@link getColor} and {@link getCursorBlinkDuration}.
82
+ *
83
+ * ```ts
84
+ * // jsdom implements no IntersectionObserver, so `[startOnVisible]` throws on boot.
85
+ * vi.stubGlobal('IntersectionObserver', StubObserver);
86
+ * // Fake these two and no more: faking the microtask queue deadlocks `whenStable`,
87
+ * // which is where the machine boots and where every harness read stabilizes.
88
+ * vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] });
89
+ * ```
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const typewriter = await loader.getHarness(WrTypewriterHarness);
94
+ *
95
+ * vi.advanceTimersByTime(0); // the first tick is scheduled at `initialDelay`
96
+ * expect(await typewriter.getText()).toBe('H');
97
+ *
98
+ * vi.advanceTimersByTime(50);
99
+ * expect(await typewriter.getText()).toBe('He');
100
+ * expect(await typewriter.isCursorDecorative()).toBe(true);
101
+ * ```
102
+ *
103
+ * @see https://ngwr.dev/guides/testing
104
+ */
105
+ declare class WrTypewriterHarness extends ComponentHarness {
106
+ static hostSelector: string;
107
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
108
+ static with(options?: WrTypewriterHarnessFilters): HarnessPredicate<WrTypewriterHarness>;
109
+ private readonly content;
110
+ private readonly cursor;
111
+ /**
112
+ * What has been typed so far — a FRAGMENT while the machine is running.
113
+ *
114
+ * This is the whole state machine in one string, and every timing input is observable
115
+ * only through it: one character per `typingSpeed`, one fewer per `deletingSpeed`, the
116
+ * `pauseDuration` gap, the swap to the next entry in `[texts]`, and the stop that
117
+ * `[loop]="false"` puts on the last sentence. `reverseMode` shows up here too, and
118
+ * `[...await getText()].length` is what proves the reversal counted CODE POINTS: a
119
+ * `split('')` reversal turns one emoji into two lone surrogates, which is a pair of
120
+ * broken glyphs on screen and the same character count as a correct answer.
121
+ *
122
+ * Untrimmed, because the fragment is what it is: a phrase typed as far as `'Hello '`
123
+ * genuinely has a trailing space, and trimming would make that frame indistinguishable
124
+ * from the one before it.
125
+ *
126
+ * The empty string is a real state, not a failure — nothing has been typed until the
127
+ * first tick fires, and a deletion run passes back through it on its way to the next
128
+ * sentence.
129
+ */
130
+ getText(): Promise<string>;
131
+ /**
132
+ * Whether a caret is in the document at all.
133
+ *
134
+ * The component removes the element rather than hiding it, which makes this two
135
+ * questions at once. Statically it answers `showCursor`. While the machine runs it
136
+ * also answers `hideCursorWhileTyping` — and the caret going away is the ONLY evidence
137
+ * anywhere in the DOM that the component considers itself mid-phase, since the phase
138
+ * signal is private. Do not read that as `isTyping()`, though: with
139
+ * `hideCursorWhileTyping` off, which is the default, the caret stays put from the first
140
+ * character to the last.
141
+ */
142
+ hasCursor(): Promise<boolean>;
143
+ /**
144
+ * The caret glyph, or `null` when there is no caret.
145
+ *
146
+ * `null` rather than `''` on purpose: "no cursor element" and "a cursor element
147
+ * rendering nothing" are different failures, and an interpolated glyph that stopped
148
+ * arriving is exactly the second one. Untrimmed, since a caret can legitimately be a
149
+ * space-padded glyph and `TestElement.text()` would erase it.
150
+ */
151
+ getCursorCharacter(): Promise<string | null>;
152
+ /**
153
+ * Whether the caret is kept out of the accessibility tree.
154
+ *
155
+ * The component's one deliberate a11y decision, and a silent one to lose: drop the
156
+ * attribute and nothing on screen changes while every phrase starts being announced as
157
+ * `Hello pipe`.
158
+ *
159
+ * Throws when there is no caret. `false` would read as "the caret is announced", which
160
+ * is the opposite of what an absent caret means — and it is the answer a component that
161
+ * stopped rendering its cursor entirely would also give. Ask {@link hasCursor} first
162
+ * when the caret's presence is itself in question.
163
+ */
164
+ isCursorDecorative(): Promise<boolean>;
165
+ /**
166
+ * The caret's blink half-cycle in seconds, from the custom property the host writes.
167
+ *
168
+ * The blink itself is a CSS keyframe and unobservable, so this custom property is the
169
+ * only channel `[cursorBlinkDuration]` has into it — a binding that quietly stopped
170
+ * writing it would leave the blink stuck at the stylesheet's default with no other
171
+ * symptom anywhere.
172
+ *
173
+ * Throws rather than answering when the property is missing or unparseable, and says
174
+ * which it was. The stylesheet's own `0.5s` fallback is never applied in a test that
175
+ * loads no stylesheets, so an absent property reads as the empty string here — and
176
+ * `0.5` returned from a `parseFloat('')` would be indistinguishable from the component
177
+ * writing the default correctly.
178
+ */
179
+ getCursorBlinkDuration(): Promise<number>;
180
+ /**
181
+ * The colour the host paints the phrase in, exactly as it is written inline.
182
+ *
183
+ * `[textColors]` cycles per SENTENCE, so this is how a spec pins that the colour index
184
+ * follows the sentence index rather than drifting; and with no colours given the
185
+ * component writes the literal `inherit`, which is a value worth asserting rather than
186
+ * an absence.
187
+ *
188
+ * Read off the `style` ATTRIBUTE rather than through `getCssValue`, which would answer
189
+ * from a computed style. jsdom hands `inherit` straight back, so `getCssValue` would
190
+ * agree here and lie in a real browser, where the keyword resolves to whatever rgb
191
+ * triple the parent happens to carry.
192
+ *
193
+ * Throws when the host carries no `color` declaration: the component writes one on
194
+ * every render, so its absence means the binding is gone, and any string returned in
195
+ * its place would be a guess at what the page inherits.
196
+ */
197
+ getColor(): Promise<string>;
198
+ }
199
+
200
+ export { WrTypewriterHarness };
201
+ export type { WrTypewriterHarnessFilters };
@@ -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 = "11.0.0";
19
+ declare const NGWR_VERSION = "11.2.0";
20
20
 
21
21
  /**
22
22
  * @license
@@ -0,0 +1,121 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+
10
+ /** Narrows which `<wr-waves>` a harness query matches. */
11
+ interface WrWavesHarnessFilters extends BaseHarnessFilters {
12
+ /**
13
+ * Match only fields whose canvas has drawn (`true`) or only fields still showing the
14
+ * stand-in grid (`false`). A wave field has no name of its own, so this is the one
15
+ * state that tells two of them apart — see `WrWavesHarness.isPainted`, which explains
16
+ * why the answer is always `false` in a unit test.
17
+ */
18
+ readonly painted?: boolean;
19
+ }
20
+
21
+ /**
22
+ * @license
23
+ *
24
+ * Use of this source code is governed by an MIT-style license that can be
25
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
26
+ */
27
+
28
+ /**
29
+ * Test harness for `<wr-waves>` — a field of lines drifting on perlin noise.
30
+ *
31
+ * **The lines themselves are unreadable and always will be.** They are strokes on a 2D
32
+ * canvas, seeded from the host's measured box and redrawn every frame; a unit test has
33
+ * no box and no drawing context, so there is nothing to count and nothing to compare.
34
+ * What the component publishes to the DOM is small, deliberate and worth pinning: the
35
+ * handover flag {@link isPainted}, the pitch {@link getLineGapPx} that the CSS stand-in
36
+ * grid draws at before the canvas takes over, and the surface itself.
37
+ *
38
+ * Two style reads, taken two different ways, and the difference is the point.
39
+ * {@link getBackgroundColor} is computed, because nothing but the component declares
40
+ * that property and the resolved value is what gets painted. {@link getLineGapPx} is
41
+ * read from the inline declaration, because the stylesheet declares
42
+ * `--wr-waves-x-gap` too — as the stand-in's own 10px fallback — so a computed read
43
+ * would answer `10px` on a component that had stopped publishing anything, which is
44
+ * precisely the break the method exists to catch.
45
+ *
46
+ * There is no `getLineCount()`, `getPoints()` or `getCanvasSize()`: the grid is seeded
47
+ * from `getBoundingClientRect()`, which is 0×0 here, and the numbers that fall out of
48
+ * that describe nothing. No `getLineColor()` either — it is a canvas `strokeStyle`
49
+ * resolved from a themed custom property that only a stylesheet can supply. No
50
+ * `moveMouse()`: the pointer listeners are on `window` and are only installed once a
51
+ * context exists. And no `isReducedMotion()`, which is the sharpest of them — the
52
+ * reduced-motion path draws one static grid through the same code and sets the same
53
+ * flag, so the DOM is identical either way and any answer would be a guess.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const waves = await loader.getHarness(WrWavesHarness);
58
+ *
59
+ * expect(await waves.hasCanvas()).toBe(true);
60
+ * expect(await waves.isDecorative()).toBe(true);
61
+ * expect(await waves.getLineGapPx()).toBe(10);
62
+ * ```
63
+ *
64
+ * @see https://ngwr.dev/guides/testing
65
+ */
66
+ declare class WrWavesHarness extends ComponentHarness {
67
+ static hostSelector: string;
68
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
69
+ static with(options?: WrWavesHarnessFilters): HarnessPredicate<WrWavesHarness>;
70
+ private readonly canvas;
71
+ /**
72
+ * Whether the canvas has drawn a frame and retired the CSS stand-in grid.
73
+ *
74
+ * **In a unit test this is always `false`, and asserting exactly that is the point.**
75
+ * jsdom hands back no 2D context, so the component must leave the stand-in up rather
76
+ * than declare itself painted over a blank box — the flag is set inside the draw for
77
+ * that reason, not at the end of the boot. A spec that waits for this to turn `true`
78
+ * waits forever.
79
+ */
80
+ isPainted(): Promise<boolean>;
81
+ /**
82
+ * The horizontal gap between lines, in pixels, as the component publishes it.
83
+ *
84
+ * `[xGap]` feeds the canvas maths, which is invisible here — but it is also published
85
+ * to the stand-in grid, and that is the half a spec can hold: a field whose stand-in
86
+ * draws at 10px and whose canvas then arrives at 40px changes pitch under the reader
87
+ * on hydration, a visible pop that nothing else can catch.
88
+ */
89
+ getLineGapPx(): Promise<number>;
90
+ /**
91
+ * The fill behind the lines, resolved.
92
+ *
93
+ * Comes back as the browser reports it rather than as it was authored — the default
94
+ * `'transparent'` reads as `'rgba(0, 0, 0, 0)'` and `'#5227ff'` as
95
+ * `'rgb(82, 39, 255)'` — which is true in jsdom and in a real browser alike, so an
96
+ * assertion written against it travels. Worth pinning because the alternative
97
+ * implementation is to fill the canvas instead, and a canvas fill is invisible to
98
+ * everything until it has painted: the background has to be a real declaration on the
99
+ * host so the field is the right colour from the prerendered HTML onwards.
100
+ */
101
+ getBackgroundColor(): Promise<string>;
102
+ /**
103
+ * Whether the field is hidden from assistive tech.
104
+ *
105
+ * A background canvas has nothing to announce, so losing this leaves a screen reader
106
+ * stopping on a nameless graphic in front of the section's actual content.
107
+ */
108
+ isDecorative(): Promise<boolean>;
109
+ /**
110
+ * Whether the drawing surface is in the markup.
111
+ *
112
+ * It is there in every state, including the ones where nothing is ever drawn on it —
113
+ * prerendered, no 2D context, reduced motion. That is the contract: the element goes
114
+ * up and the component stops, so the stand-in grid has something to sit behind and
115
+ * {@link isPainted} has something to answer about.
116
+ */
117
+ hasCanvas(): Promise<boolean>;
118
+ }
119
+
120
+ export { WrWavesHarness };
121
+ export type { WrWavesHarnessFilters };