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
@@ -0,0 +1,291 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+ import { WrSegmentedHarness } from 'ngwr/segmented/testing';
3
+
4
+ /**
5
+ * @license
6
+ *
7
+ * Use of this source code is governed by an MIT-style license that can be
8
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
9
+ */
10
+
11
+ /** Which set of numeric fields the picker is showing. */
12
+ type WrColorPickerTab = 'hex' | 'rgb' | 'hsl';
13
+ /** Narrows which `<wr-color-picker>` a harness query matches. */
14
+ interface WrColorPickerHarnessFilters extends BaseHarnessFilters {
15
+ /**
16
+ * Match the picker's current colour, as the preview swatch paints it — always
17
+ * hex, whatever `format` writes into `value`. A string is an exact match, a
18
+ * RegExp is tested.
19
+ */
20
+ readonly color?: string | RegExp;
21
+ /** Match only pickers showing this tab. */
22
+ readonly tab?: WrColorPickerTab;
23
+ /** Match only enabled (`false`) or only disabled (`true`) pickers. */
24
+ readonly disabled?: boolean;
25
+ }
26
+ /** Narrows which `[wrColorPickerTrigger]` a harness query matches. */
27
+ interface WrColorPickerTriggerHarnessFilters extends BaseHarnessFilters {
28
+ /** Match the trigger's own text, an exact string or a RegExp. */
29
+ readonly text?: string | RegExp;
30
+ /** Match only open (`true`) or only closed (`false`) triggers. */
31
+ readonly open?: boolean;
32
+ }
33
+ /** The percentage each of the picker's thumbs sits at along its surface. */
34
+ interface WrColorPickerThumbs {
35
+ /** Saturation across, value down — both 0–100, and `y` is inverted (0 % is full brightness). */
36
+ readonly sv: {
37
+ readonly x: number;
38
+ readonly y: number;
39
+ };
40
+ /** Hue along its slider, 0–100 (so 50 is 180°). */
41
+ readonly hue: number;
42
+ /** Alpha along its slider, 0–100, or `null` when the picker has no alpha. */
43
+ readonly alpha: number | null;
44
+ }
45
+
46
+ /**
47
+ * @license
48
+ *
49
+ * Use of this source code is governed by an MIT-style license that can be
50
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
51
+ */
52
+
53
+ /**
54
+ * Test harness for `<wr-color-picker>` — the inline picker, and the one the
55
+ * `[wrColorPickerTrigger]` directive mounts in an overlay.
56
+ *
57
+ * **What this harness will not do: drag.** The SV canvas and the hue / alpha
58
+ * sliders are pointer surfaces that read `getBoundingClientRect()` and divide by
59
+ * its width. A unit test has no layout, so every box is 0×0 and the division is
60
+ * `NaN` — a `setHue()` built on a synthetic pointer event would report success and
61
+ * write nothing, or write garbage. The numeric fields reach the same state and are
62
+ * also the only keyboard path the component has, so they are the whole write API
63
+ * here. {@link getThumbs} reads where the thumbs ARE, from the percentages the
64
+ * component writes inline, which is how a spec checks a surface followed a value.
65
+ *
66
+ * **And it will not read the preview swatch.** The preview paints the current
67
+ * colour as a CSS background, and jsdom normalises that to `rgb(…)` — dropping the
68
+ * alpha channel entirely, so `#ff880080` and `#ff8800ff` come back identical. A
69
+ * `getColor()` reading it would answer one thing in a unit test and another in a
70
+ * browser. {@link getHex} is the colour: the field holds the canonical 8-digit
71
+ * string, alpha included, whatever `format` writes into `value`.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * const picker = await loader.getHarness(WrColorPickerHarness);
76
+ *
77
+ * await picker.setHex('#3969e2');
78
+ * expect(await picker.getHex()).toBe('#3969e2ff');
79
+ *
80
+ * await picker.setTab('rgb');
81
+ * expect(await picker.getRgb()).toEqual({ r: 57, g: 105, b: 226 });
82
+ * ```
83
+ *
84
+ * @see https://ngwr.dev/guides/testing
85
+ */
86
+ declare class WrColorPickerHarness extends ComponentHarness {
87
+ static hostSelector: string;
88
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
89
+ static with(options?: WrColorPickerHarnessFilters): HarnessPredicate<WrColorPickerHarness>;
90
+ private readonly hexField;
91
+ private readonly tabs;
92
+ /**
93
+ * The tab switcher, as a {@link WrSegmentedHarness}.
94
+ *
95
+ * Handed back rather than re-queried: the switcher IS a `<wr-segmented>`, which
96
+ * already knows that the roving tab stop is not the selection and how the sliding
97
+ * thumb reports itself. Re-reading its buttons here would be a second, worse copy.
98
+ */
99
+ getTabs(): Promise<WrSegmentedHarness>;
100
+ /** Which set of numeric fields is showing. */
101
+ getTab(): Promise<WrColorPickerTab>;
102
+ /** Show a different set of numeric fields. An already-active tab is left alone. */
103
+ setTab(tab: WrColorPickerTab): Promise<void>;
104
+ /**
105
+ * The canonical hex string, as the HEX field shows it — 8 digits while `alpha` is
106
+ * on, 6 while it is off.
107
+ *
108
+ * This is the picker's colour, and deliberately not the same thing as its `value`:
109
+ * `format` decides whether `value` is written as hex, `rgb()` or `hsl()`, while the
110
+ * field always shows hex. A spec that cares about the emitted string should read
111
+ * the bound signal; one that cares about the COLOUR should read this.
112
+ *
113
+ * Throws off the HEX tab, where the field does not exist — see {@link setTab}.
114
+ */
115
+ getHex(): Promise<string>;
116
+ /**
117
+ * Type a colour into the HEX field.
118
+ *
119
+ * Typed rather than assigned, because that is the path the component is built
120
+ * around: it re-parses on every keystroke and applies the first spelling that
121
+ * parses, so a partial `#ff8` commits a colour on its way to `#ff8800`. An
122
+ * unparseable string leaves the committed colour ALONE and lives in the field
123
+ * until {@link blurHex} snaps it back — assert that rather than expecting a throw.
124
+ */
125
+ setHex(value: string): Promise<void>;
126
+ /**
127
+ * Blur the HEX field — re-syncing it with the committed colour and emitting
128
+ * `touch`.
129
+ *
130
+ * The re-sync is the visible half: a field left holding text that never parsed
131
+ * goes back to the canonical hex here, and nowhere else.
132
+ */
133
+ blurHex(): Promise<void>;
134
+ /** Whether the HEX field currently holds focus. */
135
+ isHexFocused(): Promise<boolean>;
136
+ /** The three RGB channels as the RGB tab shows them. Throws off that tab. */
137
+ getRgb(): Promise<{
138
+ r: number;
139
+ g: number;
140
+ b: number;
141
+ }>;
142
+ /** Write one RGB channel, 0–255. Out-of-range numbers are clamped by the component. */
143
+ setRgbChannel(channel: 'r' | 'g' | 'b', value: number): Promise<void>;
144
+ /**
145
+ * Hue, saturation and lightness as the HSL tab shows them — degrees and whole
146
+ * percents, already rounded for display. Throws off that tab.
147
+ */
148
+ getHsl(): Promise<{
149
+ h: number;
150
+ s: number;
151
+ l: number;
152
+ }>;
153
+ /** Write one HSL channel — `h` in degrees, `s` / `l` in percent. */
154
+ setHslChannel(channel: 'h' | 's' | 'l', value: number): Promise<void>;
155
+ /**
156
+ * Alpha as the whole percent the numeric tabs show, or `null` when the picker was
157
+ * built without alpha.
158
+ *
159
+ * Only the RGB and HSL tabs carry the field — the HEX tab spells alpha into the
160
+ * hex string instead — so this throws on the HEX tab rather than answering `null`,
161
+ * which would read as "this picker has no alpha".
162
+ */
163
+ getAlphaPercent(): Promise<number | null>;
164
+ /** Write alpha as a whole percent, 0–100. */
165
+ setAlphaPercent(value: number): Promise<void>;
166
+ /**
167
+ * Whether the picker offers alpha at all.
168
+ *
169
+ * From the host modifier, which is the one answer that holds on every tab: the
170
+ * alpha SLIDER is always rendered when it is on, while the `A%` field only exists
171
+ * on the two numeric tabs.
172
+ */
173
+ hasAlpha(): Promise<boolean>;
174
+ /**
175
+ * Whether the picker refuses interaction.
176
+ *
177
+ * Read from the modifier the host paints rather than from a field's `disabled`
178
+ * property, because the fields come and go with the tab while the state does not —
179
+ * and the drag surfaces, which have no `disabled` of their own, are gated by the
180
+ * same signal.
181
+ */
182
+ isDisabled(): Promise<boolean>;
183
+ /** The preset colours offered under the fields, as the strings the consumer passed. */
184
+ getSwatches(): Promise<string[]>;
185
+ /**
186
+ * Click a preset.
187
+ *
188
+ * Matched on the string the consumer passed, which is what the button publishes as
189
+ * its accessible name — the rendered background is a CSS colour and would come back
190
+ * normalised and alpha-stripped. Throws when nothing matches, naming what is offered.
191
+ */
192
+ pickSwatch(color: string): Promise<void>;
193
+ /**
194
+ * Where the three thumbs sit, in percent along their surfaces.
195
+ *
196
+ * The component writes these as inline `left` / `top` percentages, so they are
197
+ * readable with no layout at all — which makes them the only evidence a spec has
198
+ * that the surfaces followed a colour set through the fields. A measured position
199
+ * would be zero for all three.
200
+ */
201
+ getThumbs(): Promise<WrColorPickerThumbs>;
202
+ /** The HEX field's value without the tab check — for filters, which must not throw. */
203
+ private readHex;
204
+ private requireHexField;
205
+ private channelValues;
206
+ private writeChannel;
207
+ private requireTab;
208
+ /** Every numeric input of the current tab, keyed by the label printed under it. */
209
+ private inputsByLabel;
210
+ }
211
+
212
+ /**
213
+ * @license
214
+ *
215
+ * Use of this source code is governed by an MIT-style license that can be
216
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
217
+ */
218
+
219
+ /**
220
+ * Test harness for `[wrColorPickerTrigger]` — the element that opens a
221
+ * `<wr-color-picker>` in an overlay.
222
+ *
223
+ * The trigger stays in your fixture; the picker it opens does not. So this harness
224
+ * is loaded from the fixture loader like any element, and {@link getPicker} reaches
225
+ * ACROSS into the overlay container for you — scoped by the panel id the trigger
226
+ * publishes through `aria-controls`, never by `.wr-color-picker-overlay`, which
227
+ * answers with whichever trigger opened first.
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * const trigger = await loader.getHarness(WrColorPickerTriggerHarness);
232
+ * const picker = await trigger.open();
233
+ *
234
+ * await picker.setHex('#3969e2');
235
+ * await trigger.sendEscape();
236
+ * expect(await trigger.isOpen()).toBe(false);
237
+ * ```
238
+ *
239
+ * @see https://ngwr.dev/guides/testing
240
+ */
241
+ declare class WrColorPickerTriggerHarness extends ComponentHarness {
242
+ static hostSelector: string;
243
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
244
+ static with(options?: WrColorPickerTriggerHarnessFilters): HarnessPredicate<WrColorPickerTriggerHarness>;
245
+ /** The trigger's own text, trimmed. */
246
+ getText(): Promise<string>;
247
+ /** Whether the picker is showing, from the trigger's `aria-expanded`. */
248
+ isOpen(): Promise<boolean>;
249
+ /**
250
+ * Whether the trigger refuses to open.
251
+ *
252
+ * From `aria-disabled`, which the directive writes for its own `disabled` input.
253
+ * The host is usually a `<button>`, but the directive does not touch its `disabled`
254
+ * PROPERTY — a consumer who binds that as well turns the element off at the DOM
255
+ * level, which is a stronger thing and reads here too.
256
+ */
257
+ isDisabled(): Promise<boolean>;
258
+ /**
259
+ * The picker this trigger opened, or `null` while it is closed.
260
+ *
261
+ * Scoped by the id in `aria-controls`, so two triggers open at once — which
262
+ * nothing in the component prevents, since only an outside click closes one —
263
+ * answer with their own panels rather than with whichever came first.
264
+ */
265
+ getPicker(): Promise<WrColorPickerHarness | null>;
266
+ /**
267
+ * Open the picker and hand it back. An already-open trigger is left alone.
268
+ *
269
+ * Throws on a disabled trigger rather than answering `null` three lines later:
270
+ * `toggle()` returns early while `disabled` is set, so the click lands and nothing
271
+ * happens at all.
272
+ */
273
+ open(): Promise<WrColorPickerHarness>;
274
+ /** Close the picker. An already-closed trigger is left alone. */
275
+ close(): Promise<void>;
276
+ /** Click the trigger once, whichever way that takes it. */
277
+ toggle(): Promise<void>;
278
+ /**
279
+ * Press Escape.
280
+ *
281
+ * Sent to the TRIGGER, and it still reaches the picker: the overlay listens through
282
+ * the CDK's keyboard dispatcher, which keeps one document listener and routes to
283
+ * the top-most overlay — so this does not depend on where focus happens to be.
284
+ */
285
+ sendEscape(): Promise<void>;
286
+ /** The role the trigger claims to open — `dialog`. */
287
+ getHasPopup(): Promise<string | null>;
288
+ }
289
+
290
+ export { WrColorPickerHarness, WrColorPickerTriggerHarness };
291
+ export type { WrColorPickerHarnessFilters, WrColorPickerTab, WrColorPickerThumbs, WrColorPickerTriggerHarnessFilters };
@@ -236,7 +236,17 @@ declare class WrColorPicker implements FormValueControl<string> {
236
236
  protected readonly alphaPercent: _angular_core.Signal<number>;
237
237
  protected readonly tabOptions: readonly WrSegmentedOption<Tab>[];
238
238
  protected readonly classes: _angular_core.Signal<string>;
239
- /** Last string we pushed into `value`; lets the sync effect ignore our own writes. */
239
+ /**
240
+ * The one write we just made, held only until the sync effect has seen it.
241
+ *
242
+ * It exists so a drag keeps its continuous HSV values instead of being
243
+ * re-quantised through its own hex round-trip. It used to be set and never
244
+ * cleared, which turned "ignore this write" into "ignore this STRING,
245
+ * forever": after the picker emitted `#ff0000` once, an app writing
246
+ * `#ff0000` back — a reset button, a form patch, an undo — was silently
247
+ * dropped for the rest of the component's life, and the surface kept
248
+ * whatever colour the user had dragged to.
249
+ */
240
250
  private lastEmitted;
241
251
  constructor();
242
252
  protected onPointerDown(event: PointerEvent, surface: Edges): void;
@@ -301,6 +311,8 @@ declare class WrColorPickerTrigger {
301
311
  private readonly destroyRef;
302
312
  protected readonly isOpen: _angular_core.WritableSignal<boolean>;
303
313
  private overlayRef;
314
+ /** @internal Public so the host binding can read it. */
315
+ protected readonly panelId: string;
304
316
  constructor();
305
317
  /** Toggle the picker. Open if closed, close if open. */
306
318
  toggle(): void;
@@ -66,7 +66,21 @@ declare class WrContextMenu {
66
66
  */
67
67
  protected readonly openMenuId: _angular_core.WritableSignal<string | null>;
68
68
  private overlayRef;
69
- private closingTimer;
69
+ /**
70
+ * Panes waiting out their exit animation, keyed by the timer that disposes
71
+ * them.
72
+ *
73
+ * A SET, because one handle cannot hold two closings. It used to be a single
74
+ * `closingTimer`, and the second close inside the 220ms window cleared the
75
+ * first one's timer instead of its own — so the previous pane's `dispose()`
76
+ * never ran. `onContextMenu` closes and immediately re-opens, so right-clicking
77
+ * one target faster than the animation orphaned a pane per click: an
78
+ * `opacity: 0` box with `pointer-events: auto` eating clicks, a never-destroyed
79
+ * embedded view, a capture-phase document scroll listener still moving it, and
80
+ * an undetached ref still registered with CDK's keyboard dispatcher — which
81
+ * swallowed Escape for the whole page.
82
+ */
83
+ private readonly closingPanes;
70
84
  private leaveTimer;
71
85
  private pressTimer;
72
86
  private pressX;
@@ -1,4 +1,6 @@
1
- import { BaseHarnessFilters, ComponentHarness, HarnessPredicate, TestElement, HarnessLoader } from '@angular/cdk/testing';
1
+ import { WrCalendarDayHarness } from 'ngwr/calendar/testing';
2
+ export { WrCalendarDayHarness as WrDatePickerDayHarness } from 'ngwr/calendar/testing';
3
+ import { BaseHarnessFilters, ComponentHarness, TestElement, HarnessLoader, HarnessPredicate } from '@angular/cdk/testing';
2
4
 
3
5
  /**
4
6
  * @license
@@ -77,68 +79,6 @@ interface WrDatePickerTimeFields {
77
79
  readonly seconds?: number;
78
80
  }
79
81
 
80
- /**
81
- * @license
82
- *
83
- * Use of this source code is governed by an MIT-style license that can be
84
- * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
85
- */
86
-
87
- /**
88
- * Test harness for one day cell of the calendar inside a date-picker popup.
89
- *
90
- * Reached through `WrDatePickerHarness.getDay()` / `getDays()` (or the range
91
- * picker's), which scope it to ONE picker's panel — the cells are in the overlay
92
- * container, so a bare query would answer with whichever picker opened first.
93
- *
94
- * State is read the way a screen reader reads it (`role`, `aria-selected`,
95
- * `aria-disabled`) with the `.wr-calendar__day--*` modifiers filling in what
96
- * ARIA has no word for: today, the spill days of the neighbouring months, and
97
- * the interior of a picked range.
98
- *
99
- * @see https://ngwr.dev/guides/testing
100
- */
101
- declare class WrDatePickerDayHarness extends ComponentHarness {
102
- static hostSelector: string;
103
- /** Build a predicate that narrows the query. */
104
- static with(options?: WrDatePickerDayHarnessFilters): HarnessPredicate<WrDatePickerDayHarness>;
105
- /** The day number as rendered. */
106
- getText(): Promise<string>;
107
- /** The day number as a number, for mapping a list of cells to dates. */
108
- getDayOfMonth(): Promise<number>;
109
- /** `'gridcell'` — the cell is a button, and the grid semantics are what a spec should assert. */
110
- getRole(): Promise<string | null>;
111
- /** Whether this day is (one end of) the current selection. */
112
- isSelected(): Promise<boolean>;
113
- /**
114
- * Whether the day refuses selection — `min` / `max` or `dateFilter` ruled it
115
- * out, or the whole calendar is disabled.
116
- */
117
- isDisabled(): Promise<boolean>;
118
- /** Whether the cell is today's date. */
119
- isToday(): Promise<boolean>;
120
- /**
121
- * Whether the cell belongs to a neighbouring month. The grid is always 6x7, so
122
- * every month is padded with days that are selectable but not "in" the month —
123
- * which is why {@link WrDatePickerHarness.getDay} skips them.
124
- */
125
- isOutOfMonth(): Promise<boolean>;
126
- /** Whether the day lies strictly between the two ends of a picked range. */
127
- isInRange(): Promise<boolean>;
128
- /**
129
- * Whether this is the roving cell — the grid's single tab stop, and where the
130
- * arrow keys move from.
131
- *
132
- * At most ONE cell answers `true`, and it is not always one: the calendar's
133
- * roving date does not follow `next()` / `previous()`, so a grid navigated away
134
- * from that month has no active cell (and, deliberately or not, no tab stop)
135
- * until a cell is clicked or the arrows move it.
136
- */
137
- isActive(): Promise<boolean>;
138
- /** Click the cell. A disabled cell swallows the click — assert, do not assume. */
139
- click(): Promise<void>;
140
- }
141
-
142
82
  /**
143
83
  * @license
144
84
  *
@@ -277,12 +217,12 @@ declare abstract class WrDatePickerHarnessBase extends ComponentHarness {
277
217
  * them, since the grid is always six weeks and pads into the neighbouring
278
218
  * months.
279
219
  */
280
- getDays(filters?: WrDatePickerDayHarnessFilters): Promise<WrDatePickerDayHarness[]>;
220
+ getDays(filters?: WrDatePickerDayHarnessFilters): Promise<WrCalendarDayHarness[]>;
281
221
  /**
282
222
  * One day of the month on show. The padding days of the neighbouring months are
283
223
  * skipped, so `getDay(1)` is the 1st of THIS month and never the 1st of the next.
284
224
  */
285
- getDay(dayOfMonth: number): Promise<WrDatePickerDayHarness>;
225
+ getDay(dayOfMonth: number): Promise<WrCalendarDayHarness>;
286
226
  /** Click a day of the month on show. */
287
227
  selectDay(dayOfMonth: number): Promise<void>;
288
228
  /** The trigger button. Both components render it with the same class. */
@@ -514,5 +454,5 @@ declare class WrDateRangePickerHarness extends WrDatePickerHarnessBase {
514
454
  private timePanel;
515
455
  }
516
456
 
517
- export { WrDatePickerDayHarness, WrDatePickerHarness, WrDateRangePickerHarness };
457
+ export { WrDatePickerHarness, WrDateRangePickerHarness };
518
458
  export type { WrDatePickerDayHarnessFilters, WrDatePickerHarnessFilters, WrDatePickerTimeFields, WrDateRangePickerHarnessFilters };
@@ -0,0 +1,222 @@
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-decrypt-text>` a harness query matches. */
11
+ interface WrDecryptTextHarnessFilters extends BaseHarnessFilters {
12
+ /**
13
+ * Match the string the component ANNOUNCES — the readable copy, never the scramble.
14
+ * A string is an exact match, a RegExp is tested.
15
+ *
16
+ * This is the only stable thing to address one of these by: the visible layer is a
17
+ * fresh random draw on every tick, so a filter written against it would match a
18
+ * different element each time it ran, or none at all.
19
+ */
20
+ readonly text?: string | RegExp;
21
+ /**
22
+ * Match only settled (`true`) or only scrambled (`false`) instances — the way to pick
23
+ * out the one that has not been revealed yet on a page holding several.
24
+ *
25
+ * Read from the encrypted characters rather than from the glyphs, so it needs no
26
+ * `Math.random` stub. An instance that rendered no characters at all matches NEITHER
27
+ * value: "nothing is encrypted" is true of nothing, and a query is the last place that
28
+ * vacuity should quietly hand back a match.
29
+ */
30
+ readonly revealed?: boolean;
31
+ }
32
+
33
+ /**
34
+ * @license
35
+ *
36
+ * Use of this source code is governed by an MIT-style license that can be
37
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
38
+ */
39
+
40
+ /**
41
+ * Test harness for `<wr-decrypt-text>`.
42
+ *
43
+ * **Two layers, two questions, and they are meant to disagree.** The component renders
44
+ * the real string once in a visually-hidden span and the scramble in a parallel
45
+ * `aria-hidden` layer, so {@link getAccessibleText} is what a screen reader hears and
46
+ * {@link getRenderedText} is what a sighted reader sees. Mid-reveal the second is
47
+ * literal gibberish while the first must be untouched — that is the contract, and it is
48
+ * the half nobody looks at. A spec asserting only the visible glyphs would pass on a
49
+ * component that announced `XQ#PZ`.
50
+ *
51
+ * **Prefer the class over the glyphs.** {@link getRevealedIndices},
52
+ * {@link getEncryptedCount} and {@link isFullyRevealed} read
53
+ * `.wr-decrypt-text__char--encrypted`, which is deterministic with no stubbing at all —
54
+ * they are what tell `revealDirection` `'start'` from `'end'` from `'center'`, one index
55
+ * per tick. {@link getRenderedText} reads the glyphs themselves, which are a fresh
56
+ * `Math.random()` draw per tick, so stub it (`vi.spyOn(Math, 'random')
57
+ * .mockReturnValue(0)`) before asserting a string.
58
+ *
59
+ * **The clock is the spec's, not the harness's.** The reveal is a `setInterval` this
60
+ * class does not own, so there is no `advance(ms)` and no `waitUntilRevealed()`: one
61
+ * would flake on a loaded machine and the other would silently require fake timers to
62
+ * have been installed. Fake `setInterval` / `clearInterval` and nothing else — faking
63
+ * the microtask queue freezes the stabilization every `await harness.*()` runs through —
64
+ * then advance the clock yourself between reads.
65
+ *
66
+ * **There is no keyboard path, and this harness does not pretend there is one.**
67
+ * {@link hover}, {@link mouseAway} and {@link click} are the component's only triggers;
68
+ * with `animateOn="click"` the host takes a click handler while carrying no role, no
69
+ * `tabindex` and no keydown handler, so a `focus()` / `sendKeys(Enter)` affordance here
70
+ * would make a spec pass while a keyboard or switch user could not reveal the text at
71
+ * all. There is no `enterViewport()` either: `'view'` and `'inViewHover'` hang off an
72
+ * `IntersectionObserver` jsdom does not implement, so the spec stubs the global and
73
+ * fires it.
74
+ *
75
+ * **Also deliberately absent:** `isAnimating()` — the component has such a signal and it
76
+ * never reaches the DOM, and deriving it from "something is encrypted" would be wrong in
77
+ * exactly the interesting case, since `animateOn="click"` rests fully encrypted and
78
+ * perfectly still. `getSpeed()` / `getMaxIterations()` / `getRevealDirection()` /
79
+ * `getClickMode()` / `getAnimateOn()` — inputs that are never reflected anywhere, so
80
+ * reporting them would mean reading the component instance rather than the rendered
81
+ * control; they are observable as behaviour, which is what the methods above measure.
82
+ * `getScrambleAlphabet()` — the pool is internal and each frame shows one random draw
83
+ * from it, so any reconstruction is a guess that gets worse the shorter the string.
84
+ * `getCharColors()` / `isDimmed()` — the `--encrypted` rule is deliberately EMPTY, a
85
+ * styling hook for consumers, so there is nothing painted to read in any environment.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const secret = await loader.getHarness(WrDecryptTextHarness.with({ text: 'Hello' }));
90
+ *
91
+ * await secret.hover();
92
+ * vi.advanceTimersByTime(50);
93
+ *
94
+ * expect(await secret.getRevealedIndices()).toEqual([0]); // sequential, from the start
95
+ * expect(await secret.getAccessibleText()).toBe('Hello'); // untouched throughout
96
+ * ```
97
+ *
98
+ * @see https://ngwr.dev/guides/testing
99
+ */
100
+ declare class WrDecryptTextHarness extends ComponentHarness {
101
+ static hostSelector: string;
102
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
103
+ static with(options?: WrDecryptTextHarnessFilters): HarnessPredicate<WrDecryptTextHarness>;
104
+ private readonly chars;
105
+ private readonly encrypted;
106
+ /**
107
+ * The real string, as the one readable copy holds it.
108
+ *
109
+ * The single highest-value assertion here: it must stay equal to the `text` input on
110
+ * every frame, while the visible layer is unreadable by design. Lose this span and the
111
+ * component announces nothing at all — every drawn character sits under `aria-hidden`,
112
+ * so no other part of the DOM would change.
113
+ *
114
+ * Untrimmed, so that it can be compared against {@link getRenderedText} without one
115
+ * side of the comparison quietly forgiving a lost leading space.
116
+ */
117
+ getAccessibleText(): Promise<string>;
118
+ /**
119
+ * What is on screen this frame — scramble glyphs and all, in document order.
120
+ *
121
+ * Plain before anything triggers it, gibberish mid-reveal, and the real string once it
122
+ * settles; comparing it against {@link getAccessibleText} is how a spec says which of
123
+ * those it is looking at. `useOriginalCharsOnly` is visible only here — every glyph
124
+ * has to be one the text really contains.
125
+ *
126
+ * Nondeterministic unless the spec stubs `Math.random`, because each unrevealed
127
+ * position is an independent draw from the pool. When the assertion does not actually
128
+ * need the glyphs, {@link getRevealedIndices} answers the same progress question off
129
+ * the class and needs no stub.
130
+ */
131
+ getRenderedText(): Promise<string>;
132
+ /**
133
+ * How many characters the animation walks.
134
+ *
135
+ * CODE POINTS, not UTF-16 units: `'a🚀b'` is 3 here, and the indices
136
+ * {@link getRevealedIndices} returns line up with `[...text]` rather than with plain
137
+ * `text[i]`. That distinction is not pedantry — counting units gave a sequential
138
+ * reveal extra ticks with no character to spend them on, and made "everything is
139
+ * revealed" disagree with what was on screen.
140
+ */
141
+ getCharCount(): Promise<number>;
142
+ /**
143
+ * The positions that have settled on their real character, ascending.
144
+ *
145
+ * The payload method, and the deterministic one: it reads the `--encrypted` modifier
146
+ * rather than the glyphs, so no `Math.random` stub is involved. It is the only thing
147
+ * that separates `revealDirection` `'start'` (`[0]`, `[0, 1]`, …) from `'end'`
148
+ * (`[4]`, `[3, 4]`, …) from `'center'` (`[2]`, `[1, 2]`, …), and one index per tick is
149
+ * what makes a sequential reveal sequential.
150
+ *
151
+ * Ascending by position, NOT in the order the reveal visited them — the DOM records
152
+ * which characters have landed, never the path taken to them. Assert the set after
153
+ * each tick to pin an order.
154
+ */
155
+ getRevealedIndices(): Promise<number[]>;
156
+ /**
157
+ * How many characters are still scrambled.
158
+ *
159
+ * The coarse progress read, and the cheapest way to say "scrambled on hover", "plain on
160
+ * leave", or "a reader who asked for less motion never saw a scramble at all". Class-
161
+ * based like {@link getRevealedIndices}, so it too is random-proof.
162
+ */
163
+ getEncryptedCount(): Promise<number>;
164
+ /**
165
+ * Whether every character has settled.
166
+ *
167
+ * Deliberately does NOT also compare {@link getRenderedText} against
168
+ * {@link getAccessibleText}: folding two conditions into one boolean hides which of
169
+ * them broke, and a spec that wants both should write both lines.
170
+ *
171
+ * Throws when nothing was rendered. "No character is encrypted" is true of no
172
+ * characters, which is the same answer a component that stopped rendering its text
173
+ * would give — and this is the method most likely to be the only assertion in a test.
174
+ */
175
+ isFullyRevealed(): Promise<boolean>;
176
+ /**
177
+ * Whether the scramble layer is out of the accessibility tree.
178
+ *
179
+ * The contract that keeps a screen reader from spelling out `XQ#PZ` beside the real
180
+ * string it already read. Worth a method rather than an assumption because the wrapper
181
+ * holding the characters carries NO class — it can only be addressed as the readable
182
+ * span's next sibling, which any template reshuffle breaks.
183
+ *
184
+ * Throws when that structural selector finds nothing, rather than returning `false`: a
185
+ * missing wrapper and an unhidden one are different failures, and the answer to
186
+ * "is the scramble hidden" when there is no scramble layer at all is not `false`.
187
+ */
188
+ isAnimatedLayerHidden(): Promise<boolean>;
189
+ /**
190
+ * Point at it — the trigger for `animateOn` `'hover'` and `'inViewHover'`.
191
+ *
192
+ * Drives the component the way a user does, and works in a test because the trigger is
193
+ * an event rather than a gesture: `TestElement.hover()` dispatches `pointerenter`,
194
+ * `mouseover` and `mouseenter`, and the component listens for the last of those. A
195
+ * hand-rolled pointer-only dispatch would not reach it.
196
+ *
197
+ * Does nothing in the other two modes, exactly as a real pointer does nothing there.
198
+ */
199
+ hover(): Promise<void>;
200
+ /**
201
+ * Move the pointer off — the other half of hover mode.
202
+ *
203
+ * Pins the promise that leaving mid-scramble restores the real text IMMEDIATELY rather
204
+ * than letting the reveal play out: the reader took the effect away, so the string has
205
+ * to come back at once.
206
+ */
207
+ mouseAway(): Promise<void>;
208
+ /**
209
+ * Click the host — the `animateOn="click"` trigger, and the only way to tell
210
+ * `clickMode` `'once'` from `'toggle'`.
211
+ *
212
+ * There is no keyboard equivalent, and that is a statement about the component rather
213
+ * than about this harness: in click mode the host carries a click handler with no role,
214
+ * no `tabindex` and no keydown handler, so a keyboard or switch user cannot reveal the
215
+ * text at all. A `sendKeys(Enter)` here would invent an affordance that does not exist
216
+ * and let a spec pass over the top of it.
217
+ */
218
+ click(): Promise<void>;
219
+ }
220
+
221
+ export { WrDecryptTextHarness };
222
+ export type { WrDecryptTextHarnessFilters };