ngwr 11.1.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.
- package/circular-text/styles/_index.scss +11 -0
- package/command-palette/styles/_index.scss +12 -0
- package/fesm2022/ngwr-action-sheet-testing.mjs +313 -0
- package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -0
- package/fesm2022/ngwr-bar-chart-testing.mjs +89 -0
- package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-blur-text-testing.mjs +203 -0
- package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-blur-text.mjs +15 -1
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow-testing.mjs +325 -0
- package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs +95 -0
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar-testing.mjs +368 -0
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar.mjs +43 -3
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +12 -0
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +8 -0
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text-testing.mjs +230 -0
- package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-circular-text.mjs +2 -2
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker-testing.mjs +432 -0
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -0
- package/fesm2022/ngwr-color-picker.mjs +29 -3
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +25 -5
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs +10 -79
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-decrypt-text-testing.mjs +261 -0
- package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-decrypt-text.mjs +6 -1
- package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart-testing.mjs +93 -0
- package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-drawer.mjs +36 -7
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +32 -2
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar-testing.mjs +446 -0
- package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -0
- package/fesm2022/ngwr-event-calendar.mjs +43 -18
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text-testing.mjs +218 -0
- package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-fuzzy-text-testing.mjs +134 -0
- package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-gauge-testing.mjs +86 -0
- package/fesm2022/ngwr-gauge-testing.mjs.map +1 -0
- package/fesm2022/ngwr-glitch-text-testing.mjs +181 -0
- package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-gradient-text-testing.mjs +223 -0
- package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-i18n-en.mjs +14 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +14 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper-testing.mjs +156 -0
- package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -0
- package/fesm2022/ngwr-image-cropper.mjs +10 -3
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +73 -6
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-knob-testing.mjs +220 -0
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -0
- package/fesm2022/ngwr-lightbox-testing.mjs +223 -0
- package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -0
- package/fesm2022/ngwr-lightbox.mjs +9 -2
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart-testing.mjs +119 -0
- package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-marquee-testing.mjs +336 -0
- package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
- package/fesm2022/ngwr-meter-group-testing.mjs +80 -0
- package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -0
- package/fesm2022/ngwr-overlay.mjs +28 -1
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +14 -0
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text-testing.mjs +220 -0
- package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-rotating-text.mjs +2 -2
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +70 -11
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text-testing.mjs +237 -0
- package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-slider.mjs +44 -6
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline-testing.mjs +76 -0
- package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -0
- package/fesm2022/ngwr-speed-dial-testing.mjs +279 -0
- package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -0
- package/fesm2022/ngwr-splash-cursor-testing.mjs +89 -0
- package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -0
- package/fesm2022/ngwr-split-text-testing.mjs +224 -0
- package/fesm2022/ngwr-split-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-split-text.mjs +15 -1
- package/fesm2022/ngwr-split-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter-testing.mjs +245 -0
- package/fesm2022/ngwr-splitter-testing.mjs.map +1 -0
- package/fesm2022/ngwr-spotlight-card-testing.mjs +368 -0
- package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -0
- package/fesm2022/ngwr-star-border-testing.mjs +172 -0
- package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
- package/fesm2022/ngwr-table.mjs +13 -3
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +15 -1
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card-testing.mjs +190 -0
- package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tilt-card.mjs +19 -1
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-toast.mjs +36 -7
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-tour-testing.mjs +173 -0
- package/fesm2022/ngwr-tour-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tour.mjs +2 -2
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +10 -3
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter-testing.mjs +228 -0
- package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -0
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-waves-testing.mjs +128 -0
- package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
- package/fesm2022/ngwr-window-testing.mjs +361 -0
- package/fesm2022/ngwr-window-testing.mjs.map +1 -0
- package/fesm2022/ngwr-window.mjs +84 -10
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/i18n/en.json +16 -2
- package/i18n/ru.json +16 -2
- package/llms-full.txt +147 -0
- package/llms.txt +27 -8
- package/mcp/providers.js +29 -0
- package/mcp/tools.js +1 -29
- package/package.json +145 -1
- package/skills/ngwr/SKILL.md +115 -0
- package/skills/ngwr/references/catalog.md +212 -0
- package/skills/ngwr/references/setup.md +73 -0
- package/types/ngwr-action-sheet-testing.d.ts +260 -0
- package/types/ngwr-bar-chart-testing.d.ts +77 -0
- package/types/ngwr-blur-text-testing.d.ts +180 -0
- package/types/ngwr-blur-text.d.ts +12 -0
- package/types/ngwr-border-glow-testing.d.ts +219 -0
- package/types/ngwr-calendar-heatmap-testing.d.ts +79 -0
- package/types/ngwr-calendar-testing.d.ts +277 -0
- package/types/ngwr-calendar.d.ts +10 -0
- package/types/ngwr-checkbox.d.ts +13 -0
- package/types/ngwr-circular-text-testing.d.ts +196 -0
- package/types/ngwr-color-picker-testing.d.ts +291 -0
- package/types/ngwr-color-picker.d.ts +13 -1
- package/types/ngwr-context-menu.d.ts +15 -1
- package/types/ngwr-date-picker-testing.d.ts +6 -66
- package/types/ngwr-decrypt-text-testing.d.ts +222 -0
- package/types/ngwr-donut-chart-testing.d.ts +79 -0
- package/types/ngwr-drawer.d.ts +12 -0
- package/types/ngwr-dropdown.d.ts +9 -0
- package/types/ngwr-event-calendar-testing.d.ts +301 -0
- package/types/ngwr-event-calendar.d.ts +9 -6
- package/types/ngwr-falling-text-testing.d.ts +186 -0
- package/types/ngwr-fuzzy-text-testing.d.ts +130 -0
- package/types/ngwr-gauge-testing.d.ts +71 -0
- package/types/ngwr-glitch-text-testing.d.ts +172 -0
- package/types/ngwr-gradient-text-testing.d.ts +173 -0
- package/types/ngwr-image-cropper-testing.d.ts +134 -0
- package/types/ngwr-image-cropper.d.ts +1 -0
- package/types/ngwr-input-number.d.ts +33 -1
- package/types/ngwr-knob-testing.d.ts +150 -0
- package/types/ngwr-lightbox-testing.d.ts +154 -0
- package/types/ngwr-lightbox.d.ts +6 -0
- package/types/ngwr-line-chart-testing.d.ts +93 -0
- package/types/ngwr-marquee-testing.d.ts +280 -0
- package/types/ngwr-meter-group-testing.d.ts +67 -0
- package/types/ngwr-overlay.d.ts +19 -1
- package/types/ngwr-rotating-text-testing.d.ts +191 -0
- package/types/ngwr-select.d.ts +32 -0
- package/types/ngwr-shiny-text-testing.d.ts +165 -0
- package/types/ngwr-slider.d.ts +15 -0
- package/types/ngwr-sparkline-testing.d.ts +69 -0
- package/types/ngwr-speed-dial-testing.d.ts +195 -0
- package/types/ngwr-splash-cursor-testing.d.ts +95 -0
- package/types/ngwr-split-text-testing.d.ts +209 -0
- package/types/ngwr-split-text.d.ts +12 -0
- package/types/ngwr-splitter-testing.d.ts +174 -0
- package/types/ngwr-spotlight-card-testing.d.ts +303 -0
- package/types/ngwr-star-border-testing.d.ts +135 -0
- package/types/ngwr-table.d.ts +10 -1
- package/types/ngwr-tilt-card-testing.d.ts +158 -0
- package/types/ngwr-tilt-card.d.ts +2 -0
- package/types/ngwr-toast.d.ts +14 -5
- package/types/ngwr-tour-testing.d.ts +143 -0
- package/types/ngwr-tree.d.ts +7 -0
- package/types/ngwr-typewriter-testing.d.ts +201 -0
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-waves-testing.d.ts +121 -0
- package/types/ngwr-window-testing.d.ts +263 -0
- package/types/ngwr-window.d.ts +27 -10
- package/window/styles/_index.scss +44 -16
|
@@ -0,0 +1,191 @@
|
|
|
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-rotating-text>` a harness query matches. */
|
|
11
|
+
interface WrRotatingTextHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/**
|
|
13
|
+
* Match the string showing right now — the readable copy, not the animated pieces.
|
|
14
|
+
* A string is an exact match, a RegExp is tested.
|
|
15
|
+
*
|
|
16
|
+
* It matches a MOMENT, not a rotator: the component cycles, so a filter that hits today
|
|
17
|
+
* misses two seconds later. Use it to address the one that is currently showing a known
|
|
18
|
+
* word, and prefer `selector` for a rotator you need to hold on to.
|
|
19
|
+
*/
|
|
20
|
+
readonly text?: string | RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* Match on how many word groups the split produced. Word boundaries survive every
|
|
23
|
+
* granularity — three words stay three groups even when each is exploded into
|
|
24
|
+
* characters — so this is stable across the split, unlike the piece count.
|
|
25
|
+
*/
|
|
26
|
+
readonly wordCount?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @license
|
|
31
|
+
*
|
|
32
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
33
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Test harness for `<wr-rotating-text>`.
|
|
38
|
+
*
|
|
39
|
+
* **What is announced and what is drawn are two questions, and this component is worth a
|
|
40
|
+
* harness mostly because it answers them separately.** The string showing now is carried
|
|
41
|
+
* verbatim in a visually-hidden span; the animated layer beside it is one span per
|
|
42
|
+
* grapheme, word or line and is `aria-hidden` as a whole, so a screen reader hears `one`
|
|
43
|
+
* rather than `o. n. e.` {@link getAccessibleText} is the first, {@link getRenderedText}
|
|
44
|
+
* and {@link getPieces} the second, and {@link isAnimatedLayerHidden} together with
|
|
45
|
+
* {@link hasAccessibleCopy} is the pairing that regresses silently when someone
|
|
46
|
+
* restructures the template — pieces hidden AND no readable copy is an element with no
|
|
47
|
+
* accessible text at all, which reads as a pass on either check alone.
|
|
48
|
+
*
|
|
49
|
+
* **The sr-only span is deliberately not a live region, and no method here implies
|
|
50
|
+
* otherwise.** `auto` advances every two seconds by default, and the APG's answer for
|
|
51
|
+
* self-advancing content is silence, not an announcement on a timer. What the harness
|
|
52
|
+
* pins is that the announced copy TRACKS the current word — nothing about it being
|
|
53
|
+
* spoken.
|
|
54
|
+
*
|
|
55
|
+
* **There is no `getIndex()`, and no `next()` / `previous()` / `jumpTo()` / `reset()`.**
|
|
56
|
+
* The index appears nowhere in the DOM — no attribute, no data hook — so deriving it
|
|
57
|
+
* would mean matching the shown string against a list the harness was never given, and
|
|
58
|
+
* guessing between duplicates. And the component renders no controls at all: rotation is
|
|
59
|
+
* a timer or a method call on the instance, so a harness "click" would have nothing to
|
|
60
|
+
* click and reaching into the component would make this a wrapper around the class rather
|
|
61
|
+
* than a reader of the DOM. Drive it from the spec — through the instance, or by
|
|
62
|
+
* advancing the interval — and assert the `nextChange` output for the index.
|
|
63
|
+
*
|
|
64
|
+
* **Nothing here reports the tween.** `duration`, `easing`, `staggerDuration` and
|
|
65
|
+
* `staggerFrom` are passed straight into Web Animation options and never written to the
|
|
66
|
+
* document; `delayFor()` is arithmetic with no rendered trace. So no `getDuration()`, no
|
|
67
|
+
* `getStagger()`, no `isAnimating()`. The pieces do carry inline `opacity` and
|
|
68
|
+
* `transform`, but on the animated path those are the FIRST keyframe — `opacity: 0` on
|
|
69
|
+
* text the user can see perfectly well — which is why the only reading offered is
|
|
70
|
+
* {@link isSettled}, and why it is spelled as a commitment rather than as a state of
|
|
71
|
+
* motion. The host's `overflow: hidden` clipping is layout, and every rect in a unit test
|
|
72
|
+
* is 0×0, so there is no `isClipped()` either.
|
|
73
|
+
*
|
|
74
|
+
* jsdom implements no Web Animations API, so the animated path throws on the first
|
|
75
|
+
* `el.animate` — before any assertion runs. Every spec supplies one half or the other:
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* // Either: mount under reduced motion, where each swap is instant and nothing tweens.
|
|
79
|
+
* // (jsdom has no matchMedia, so WrPlatform must be provided as a value.)
|
|
80
|
+
* TestBed.configureTestingModule({ providers: [{ provide: WrPlatform, useValue: reducedMotion }] });
|
|
81
|
+
*
|
|
82
|
+
* // Or: stub the API — and remember a stub that never fires `onfinish` never resolves
|
|
83
|
+
* // the exit step, so the rotator stops after one swap.
|
|
84
|
+
* Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined, onfinish: null }));
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const rotator = await loader.getHarness(WrRotatingTextHarness);
|
|
90
|
+
*
|
|
91
|
+
* expect(await rotator.getAccessibleText()).toBe('design');
|
|
92
|
+
* expect(await rotator.getPieces()).toEqual(['d', 'e', 's', 'i', 'g', 'n']);
|
|
93
|
+
* expect(await rotator.isAnimatedLayerHidden()).toBe(true);
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @see https://ngwr.dev/guides/testing
|
|
97
|
+
*/
|
|
98
|
+
declare class WrRotatingTextHarness extends ComponentHarness {
|
|
99
|
+
static hostSelector: string;
|
|
100
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
101
|
+
static with(options?: WrRotatingTextHarnessFilters): HarnessPredicate<WrRotatingTextHarness>;
|
|
102
|
+
private readonly chars;
|
|
103
|
+
/**
|
|
104
|
+
* The string showing right now, as the one readable copy holds it.
|
|
105
|
+
*
|
|
106
|
+
* Literally what a screen reader gets, the animated layer being out of the tree — and
|
|
107
|
+
* the thing to assert a rotation against, since it is where `next()`, `previous()`, a
|
|
108
|
+
* clamped `jumpTo()`, `reset()`, the wrap at either end, the stop when `loop` is off and
|
|
109
|
+
* the shrinking-list clamp all become visible.
|
|
110
|
+
*
|
|
111
|
+
* Throws when the copy is missing rather than answering with the pieces' text: an empty
|
|
112
|
+
* string is what a rotator holding an empty list correctly reports, so a plausible
|
|
113
|
+
* nothing here is indistinguishable from the component having lost its accessible name
|
|
114
|
+
* entirely. Ask {@link hasAccessibleCopy} when presence is the question.
|
|
115
|
+
*/
|
|
116
|
+
getAccessibleText(): Promise<string>;
|
|
117
|
+
/**
|
|
118
|
+
* Everything the animated layer draws, in document order, as one string.
|
|
119
|
+
*
|
|
120
|
+
* A different fact from {@link getAccessibleText}, and the comparison between them is
|
|
121
|
+
* the point: a split that drops its spacer renders `hellothere` while the readable copy
|
|
122
|
+
* stays perfect, and nothing else in the DOM says so.
|
|
123
|
+
*
|
|
124
|
+
* The spacer between words is a non-breaking space (` `), which is a rendering
|
|
125
|
+
* choice rather than a contract, so it is normalized to a plain space here — otherwise
|
|
126
|
+
* every round-trip assertion would have to spell U+00A0 out to pass against a working
|
|
127
|
+
* component. Note that `splitBy="lines"` genuinely does not round-trip: the newline the
|
|
128
|
+
* readable copy carries is drawn as that same spacer.
|
|
129
|
+
*/
|
|
130
|
+
getRenderedText(): Promise<string>;
|
|
131
|
+
/**
|
|
132
|
+
* The animated pieces, in document order.
|
|
133
|
+
*
|
|
134
|
+
* The granularity actually applied: one piece per grapheme for `splitBy="characters"`,
|
|
135
|
+
* one per word for `"words"`, one per line for `"lines"`. It is also where the grapheme
|
|
136
|
+
* contract shows — `a🚀b` must come back as three pieces, not four with two broken
|
|
137
|
+
* halves of a surrogate pair.
|
|
138
|
+
*/
|
|
139
|
+
getPieces(): Promise<string[]>;
|
|
140
|
+
/**
|
|
141
|
+
* How many word groups the split produced.
|
|
142
|
+
*
|
|
143
|
+
* Word boundaries survive every granularity: three words stay three groups even when
|
|
144
|
+
* each is exploded into characters, which is what keeps the line wrapping sane. A
|
|
145
|
+
* splitter that flattened the grouping would leave {@link getPieces} correct and break
|
|
146
|
+
* only this.
|
|
147
|
+
*/
|
|
148
|
+
getWordCount(): Promise<number>;
|
|
149
|
+
/**
|
|
150
|
+
* Whether the animated layer is out of the accessibility tree.
|
|
151
|
+
*
|
|
152
|
+
* ONE attribute answers it — `aria-hidden` sits on the `__inner` wrapper, so the pieces
|
|
153
|
+
* inherit it and none carries it itself, which keeps the attribute off the nodes the
|
|
154
|
+
* tween writes to. Asserting it per piece would fail on a component that is behaving.
|
|
155
|
+
*
|
|
156
|
+
* If it regresses, every rotation is spelled out letter by letter beside the copy that
|
|
157
|
+
* was already read, and nothing changes on screen — so no other check catches it.
|
|
158
|
+
*/
|
|
159
|
+
isAnimatedLayerHidden(): Promise<boolean>;
|
|
160
|
+
/**
|
|
161
|
+
* Whether the readable copy is rendered at all.
|
|
162
|
+
*
|
|
163
|
+
* The other half of {@link isAnimatedLayerHidden}, and it exists as a separate question
|
|
164
|
+
* because the failure the two catch together is invisible to each alone: a layer
|
|
165
|
+
* correctly hidden with no readable copy beside it is a control with no accessible text
|
|
166
|
+
* whatsoever, and `isAnimatedLayerHidden() === true` is exactly what it reports.
|
|
167
|
+
*/
|
|
168
|
+
hasAccessibleCopy(): Promise<boolean>;
|
|
169
|
+
/**
|
|
170
|
+
* Whether the enter step committed its end state on every piece — NOT whether an
|
|
171
|
+
* animation finished.
|
|
172
|
+
*
|
|
173
|
+
* The component writes `opacity: 1` inline on each piece when the swap settles: instantly
|
|
174
|
+
* under reduced motion, and from the tween's `onfinish` otherwise. So this answers "the
|
|
175
|
+
* new word was actually taken over", which is the bug the deferred enter exists to
|
|
176
|
+
* prevent — a swap that animates the OLD spans leaves the new ones staged at `opacity: 0`
|
|
177
|
+
* and the text invisible, while the readable copy reports the new word correctly.
|
|
178
|
+
*
|
|
179
|
+
* It is all-or-nothing: one piece left staged is one invisible glyph in the middle of a
|
|
180
|
+
* word. On the animated path it stays `false` until each tween finishes, which in a unit
|
|
181
|
+
* test means forever, since a stubbed `Element.animate` never fires anything — that is
|
|
182
|
+
* an honest answer about a swap that never landed, not a limitation to work around.
|
|
183
|
+
*
|
|
184
|
+
* Throws when there are no pieces: "every piece is settled" is true of none of them,
|
|
185
|
+
* and that is also what a component that stopped rendering its text would report.
|
|
186
|
+
*/
|
|
187
|
+
isSettled(): Promise<boolean>;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export { WrRotatingTextHarness };
|
|
191
|
+
export type { WrRotatingTextHarnessFilters };
|
package/types/ngwr-select.d.ts
CHANGED
|
@@ -478,6 +478,15 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
|
|
|
478
478
|
* Virtualization engaged: opt-in, search mode, a non-empty filtered array, and
|
|
479
479
|
* NO projected `<wr-option>` children (those keep the full-render registry path
|
|
480
480
|
* so their DOM-derived labels / selection still work).
|
|
481
|
+
*
|
|
482
|
+
* NOT gated on there being matches. It used to also require
|
|
483
|
+
* `filteredDynamicOptions().length > 0`, which meant a query matching nothing
|
|
484
|
+
* fell back to the full-render path and mounted the ENTIRE unfiltered array —
|
|
485
|
+
* 2000 `<wr-option>` hosts, every one of them `--hidden`, behind a "No
|
|
486
|
+
* results" line — and then tore all of them down again on the next keystroke
|
|
487
|
+
* that matched. The empty window is handled where it belongs: `virtualWindow`
|
|
488
|
+
* already short-circuits on `total === 0`, and `firstEnabled` / `lastEnabled`
|
|
489
|
+
* already answer -1.
|
|
481
490
|
*/
|
|
482
491
|
protected readonly virtualActive: _angular_core.Signal<boolean>;
|
|
483
492
|
private readonly scrollTop;
|
|
@@ -537,6 +546,7 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
|
|
|
537
546
|
protected onChipsBlur(): void;
|
|
538
547
|
protected onSearchInput(event: Event): void;
|
|
539
548
|
protected onSearchFocus(): void;
|
|
549
|
+
protected onSearchBlur(): void;
|
|
540
550
|
protected onSearchKey(event: KeyboardEvent): void;
|
|
541
551
|
/**
|
|
542
552
|
* Display text for the search input. Shows the selected option's
|
|
@@ -544,6 +554,15 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
|
|
|
544
554
|
* @internal
|
|
545
555
|
*/
|
|
546
556
|
protected readonly searchDisplay: _angular_core.Signal<string>;
|
|
557
|
+
/**
|
|
558
|
+
* Whether the search field holds focus.
|
|
559
|
+
*
|
|
560
|
+
* Read by `searchDisplay`, so it has to be a signal — and it is also what
|
|
561
|
+
* lets the panel-close effect tell "the user walked away" (reset the query)
|
|
562
|
+
* from "the query dropped under `minChars` and they are still typing" (keep
|
|
563
|
+
* it).
|
|
564
|
+
*/
|
|
565
|
+
private readonly searchHasFocus;
|
|
547
566
|
private readonly host;
|
|
548
567
|
private readonly overlay;
|
|
549
568
|
private readonly outsideClick;
|
|
@@ -573,6 +592,19 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
|
|
|
573
592
|
protected onTriggerKey(event: KeyboardEvent): void;
|
|
574
593
|
private seedActiveIndex;
|
|
575
594
|
private moveActive;
|
|
595
|
+
/**
|
|
596
|
+
* Both scan `orderedRegistry`, and that is not interchangeable with
|
|
597
|
+
* `registry`.
|
|
598
|
+
*
|
|
599
|
+
* They RETURN an index, and every reader of `activeIndex` — `activeOptionId`,
|
|
600
|
+
* `moveActive`, `seedActiveIndex`, the Enter branch of `onTriggerKey` —
|
|
601
|
+
* resolves it against DOM order. Scanning creation order here produced an
|
|
602
|
+
* index into the other list: with projected `<wr-option>` children next to
|
|
603
|
+
* `[options]` rows the two differ, so opening or searching left the cursor on
|
|
604
|
+
* a row the user was not looking at, and Enter committed whatever happened to
|
|
605
|
+
* sit at that position in DOM order — a filter-hidden option, which commits
|
|
606
|
+
* nothing at all.
|
|
607
|
+
*/
|
|
576
608
|
private firstEnabled;
|
|
577
609
|
private lastEnabled;
|
|
578
610
|
/** Coerce the multi-mode value into an array (tolerates a scalar or null write). */
|
|
@@ -0,0 +1,165 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* Which way the bright stripe travels. Mirrors the component's `direction` input, which
|
|
12
|
+
* declares the union inline and exports no name for it.
|
|
13
|
+
*/
|
|
14
|
+
type WrShinyTextSweepDirection = 'left' | 'right';
|
|
15
|
+
/** Narrows which `<wr-shiny-text>` a harness query matches. */
|
|
16
|
+
interface WrShinyTextHarnessFilters extends BaseHarnessFilters {
|
|
17
|
+
/** Match the rendered text — a string is an exact match, a RegExp is tested. */
|
|
18
|
+
readonly text?: string | RegExp;
|
|
19
|
+
/**
|
|
20
|
+
* Match only the stopped (`true`) or only the running (`false`) instances. Named for the
|
|
21
|
+
* DOM contract rather than for the input: `[disabled]` writes `wr-shiny-text--paused`.
|
|
22
|
+
*/
|
|
23
|
+
readonly paused?: boolean;
|
|
24
|
+
/** Match the sweep direction — `'left'` is the absence of the reverse modifier. */
|
|
25
|
+
readonly direction?: WrShinyTextSweepDirection;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @license
|
|
30
|
+
*
|
|
31
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
32
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Test harness for `<wr-shiny-text>`.
|
|
37
|
+
*
|
|
38
|
+
* **The duration is the assertion that matters.** The pause between sweeps is not
|
|
39
|
+
* `animation-delay` and not a second animation — it is folded INTO `animation-duration`,
|
|
40
|
+
* because the keyframe finishes at 50% and holds there. So `[speed]="2"` with
|
|
41
|
+
* `[delay]="3"` has to read 5 seconds, and anyone reimplementing the pause the obvious
|
|
42
|
+
* way passes every other check here and fails {@link getCycleDurationSeconds}.
|
|
43
|
+
*
|
|
44
|
+
* **The stripe is five stops and only one of them is the shine.** The base colour fills
|
|
45
|
+
* 0%, 35%, 65% and 100%; the highlight sits alone at 50%. {@link getBaseColor} and
|
|
46
|
+
* {@link getShineColor} are offered as a pair because swapping the two inputs is
|
|
47
|
+
* otherwise undetectable — the gradient stays well-formed, the angle is unchanged, and
|
|
48
|
+
* the text simply stops shimmering.
|
|
49
|
+
*
|
|
50
|
+
* **Both gradient reads come off the inline `style` attribute**, not through computed
|
|
51
|
+
* style. Unset colours fall through to the literal `var(--wr-shiny-text-base)` /
|
|
52
|
+
* `var(--wr-shiny-text-shine)` tokens, which is exactly what makes the dark-theme
|
|
53
|
+
* override work — and a computed read resolves those tokens in a real browser while
|
|
54
|
+
* handing them back verbatim in a unit test. Reading what the component wrote gives the
|
|
55
|
+
* same answer in both places.
|
|
56
|
+
*
|
|
57
|
+
* The colours still pass through the CSSOM on their way back out, and it has its own
|
|
58
|
+
* spelling: a hex literal is re-serialised, so `[color]="'#444'"` reads
|
|
59
|
+
* `rgb(68, 68, 68)`. Functional notations and `var()` tokens survive untouched. Assert
|
|
60
|
+
* the form the CSSOM returns, not the one the template passed in.
|
|
61
|
+
*
|
|
62
|
+
* There is no inner element to query: the template is the bare interpolation, so the text
|
|
63
|
+
* is a node on the host. A locator copied from the gradient-text harness finds nothing.
|
|
64
|
+
*
|
|
65
|
+
* **What the harness deliberately does not offer**, and why. There is no `isAnimating()`
|
|
66
|
+
* / `getBackgroundPosition()`: the sweep is a stylesheet keyframe over
|
|
67
|
+
* `background-position`, and a unit test neither loads the sheet nor runs the animation.
|
|
68
|
+
* There is no `getAnimationName()` / `getIterationCount()` / `getPlayState()`: every
|
|
69
|
+
* animation property except the duration lives in the stylesheet, so those reads answer
|
|
70
|
+
* the same empty string for a working component and a deleted one. {@link isPaused} and
|
|
71
|
+
* {@link pausesOnHover} claim the CLASSES and not the pauses — `:hover` is a selector and
|
|
72
|
+
* `animation-play-state` is a stylesheet rule, so what they honestly pin is that the
|
|
73
|
+
* input arrived. There is no `respectsReducedMotion()`: the handling is a `@media` block
|
|
74
|
+
* with no TypeScript counterpart. And there is nothing reporting the painted text colour,
|
|
75
|
+
* because `-webkit-text-fill-color: transparent` is a stylesheet declaration and a read
|
|
76
|
+
* would report the inherited colour as if the text were solid.
|
|
77
|
+
*
|
|
78
|
+
* The `[wrShimmer]` directive shipped from the same entry point has no harness: it adds
|
|
79
|
+
* one static class and nothing else, so a harness could only restate its own selector.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const shiny = await loader.getHarness(WrShinyTextHarness);
|
|
84
|
+
*
|
|
85
|
+
* expect(await shiny.getCycleDurationSeconds()).toBe(5);
|
|
86
|
+
* expect(await shiny.getShineColor()).toBe('var(--wr-shiny-text-shine)');
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @see https://ngwr.dev/guides/testing
|
|
90
|
+
*/
|
|
91
|
+
declare class WrShinyTextHarness extends ComponentHarness {
|
|
92
|
+
static hostSelector: string;
|
|
93
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
94
|
+
static with(options?: WrShinyTextHarnessFilters): HarnessPredicate<WrShinyTextHarness>;
|
|
95
|
+
/** The rendered text, trimmed. It is a text node on the host — there is no inner span. */
|
|
96
|
+
getText(): Promise<string>;
|
|
97
|
+
/**
|
|
98
|
+
* The whole stripe gradient the component computed, as written.
|
|
99
|
+
*
|
|
100
|
+
* Unresolved on purpose. With no `[color]` / `[shineColor]` given this string contains
|
|
101
|
+
* the theme's own custom-property tokens rather than colours, and that is the working
|
|
102
|
+
* state, not a gap — resolving them would need the stylesheet, and the resolved answer
|
|
103
|
+
* would differ between a unit test and a browser.
|
|
104
|
+
*/
|
|
105
|
+
getGradient(): Promise<string>;
|
|
106
|
+
/**
|
|
107
|
+
* The gradient's angle in degrees, from `[spread]`.
|
|
108
|
+
*
|
|
109
|
+
* The only observable effect that input has, `numAttr` coercion included. Note the name
|
|
110
|
+
* is inherited vocabulary and describes the ANGLE, not the width of the bright stripe:
|
|
111
|
+
* the stop positions are hard-coded, so no input narrows the shine.
|
|
112
|
+
*/
|
|
113
|
+
getSpreadDegrees(): Promise<number>;
|
|
114
|
+
/**
|
|
115
|
+
* The colour outside the bright stripe — the 0% stop.
|
|
116
|
+
*
|
|
117
|
+
* The same colour fills 35%, 65% and 100%; only the 50% stop differs. Assert it next to
|
|
118
|
+
* {@link getShineColor}: a `[color]` that lands in the shine slot instead leaves a
|
|
119
|
+
* perfectly valid gradient that no longer shimmers.
|
|
120
|
+
*/
|
|
121
|
+
getBaseColor(): Promise<string>;
|
|
122
|
+
/** The highlight colour — the lone 50% stop the stripe is made of. */
|
|
123
|
+
getShineColor(): Promise<string>;
|
|
124
|
+
/**
|
|
125
|
+
* One full cycle in seconds — the sweep AND the pause after it.
|
|
126
|
+
*
|
|
127
|
+
* `[delay]` is not `animation-delay` and not a second animation: the keyframe reaches
|
|
128
|
+
* its end at 50% and holds, so the wait is bought by making the animation twice as long.
|
|
129
|
+
* That is why this reads `speed + delay` and why the method is named for the cycle
|
|
130
|
+
* rather than for the sweep.
|
|
131
|
+
*
|
|
132
|
+
* Read from the inline declaration rather than from computed style, so a missing binding
|
|
133
|
+
* is reported as missing instead of being answered from the stylesheet.
|
|
134
|
+
*/
|
|
135
|
+
getCycleDurationSeconds(): Promise<number>;
|
|
136
|
+
/**
|
|
137
|
+
* Whether the animation is stopped (`disabled`).
|
|
138
|
+
*
|
|
139
|
+
* Three names for one thing, which is why this method exists rather than a spec reading
|
|
140
|
+
* the class: the input is `disabled`, its JSDoc says "pause", and the DOM contract is
|
|
141
|
+
* `wr-shiny-text--paused`. Only the last of those is public API.
|
|
142
|
+
*/
|
|
143
|
+
isPaused(): Promise<boolean>;
|
|
144
|
+
/** Whether the opt-in reached the class the `:hover` rule needs. */
|
|
145
|
+
pausesOnHover(): Promise<boolean>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether the stripe bounces instead of restarting (`yoyo`).
|
|
148
|
+
*
|
|
149
|
+
* Defaults to `false` here — the opposite of the same-named input on `wr-gradient-text`,
|
|
150
|
+
* which is worth pinning in a spec that uses both. Together with {@link getDirection}
|
|
151
|
+
* this is the whole four-way matrix the stylesheet derives `animation-direction` from.
|
|
152
|
+
*/
|
|
153
|
+
isYoyo(): Promise<boolean>;
|
|
154
|
+
/** Which way the stripe travels — `'left'` is the absence of the reverse modifier. */
|
|
155
|
+
getDirection(): Promise<WrShinyTextSweepDirection>;
|
|
156
|
+
/** The five stops of the stripe, positions attached, in gradient order. */
|
|
157
|
+
private gradientStops;
|
|
158
|
+
/** The gradient's arguments — the angle first, then the stops. */
|
|
159
|
+
private gradientArguments;
|
|
160
|
+
/** One of the host's two inline declarations, or a failure that says which one is missing. */
|
|
161
|
+
private require;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { WrShinyTextHarness };
|
|
165
|
+
export type { WrShinyTextHarnessFilters, WrShinyTextSweepDirection };
|
package/types/ngwr-slider.d.ts
CHANGED
|
@@ -77,7 +77,22 @@ declare class WrSlider implements FormValueControl<WrSliderValue> {
|
|
|
77
77
|
/** Emitted on blur so a bound field can mark itself touched. */
|
|
78
78
|
readonly touch: _angular_core.OutputEmitterRef<void>;
|
|
79
79
|
protected readonly low: _angular_core.WritableSignal<number>;
|
|
80
|
+
/**
|
|
81
|
+
* The high thumb's cell. Its literal default stands in for `maxValue()`,
|
|
82
|
+
* which cannot be read at field-initialisation time — see `highSeeded` and
|
|
83
|
+
* the constructor effect.
|
|
84
|
+
*/
|
|
80
85
|
protected readonly high: _angular_core.WritableSignal<number>;
|
|
86
|
+
/**
|
|
87
|
+
* Whether `high` has ever been told a real value by the model.
|
|
88
|
+
*
|
|
89
|
+
* `<wr-slider range [min]="200" [max]="300" />` binds no value, so the model
|
|
90
|
+
* holds its own scalar default and the tuple branch below never runs: `high`
|
|
91
|
+
* kept the literal 100, which is not inside every `[min, max]`. The thumb
|
|
92
|
+
* rendered off the track and the first interaction committed `[low, 100]` —
|
|
93
|
+
* a value the slider itself calls out of range.
|
|
94
|
+
*/
|
|
95
|
+
private highSeeded;
|
|
81
96
|
protected readonly track: _angular_core.Signal<ElementRef<HTMLElement>>;
|
|
82
97
|
/**
|
|
83
98
|
* Ambient reading direction. Optional so a bare `TestBed` — or any consumer
|
|
@@ -0,0 +1,69 @@
|
|
|
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-sparkline>` a harness query matches. */
|
|
11
|
+
interface WrSparklineHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the sparkline's accessible name — `null` for the decorative ones. */
|
|
13
|
+
readonly ariaLabel?: string | RegExp;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @license
|
|
18
|
+
*
|
|
19
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
20
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Test harness for `<wr-sparkline>`.
|
|
25
|
+
*
|
|
26
|
+
* **The interesting assertion here is the ARIA one.** A sparkline is a trend line
|
|
27
|
+
* with no axes and no labels, so it is either given an `ariaLabel` — in which case it
|
|
28
|
+
* announces itself as an image — or it is decoration, and must be `aria-hidden` so a
|
|
29
|
+
* screen reader does not stop on a nameless graphic. The component switches between
|
|
30
|
+
* those two states on one input, and {@link isDecorative} is how a spec pins which
|
|
31
|
+
* one it is in.
|
|
32
|
+
*
|
|
33
|
+
* The line itself is an SVG path, and a path's `d` is not something a spec should
|
|
34
|
+
* assert: it is a rendering detail that changes with the viewBox, the stroke width
|
|
35
|
+
* and the smoothing. What IS worth asserting is whether the parts are there —
|
|
36
|
+
* {@link hasLine}, {@link hasArea}, {@link hasTip} — since each is an input the
|
|
37
|
+
* consumer set, and an empty dataset draws none of them.
|
|
38
|
+
*
|
|
39
|
+
* @see https://ngwr.dev/guides/testing
|
|
40
|
+
*/
|
|
41
|
+
declare class WrSparklineHarness extends ComponentHarness {
|
|
42
|
+
static hostSelector: string;
|
|
43
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
44
|
+
static with(options?: WrSparklineHarnessFilters): HarnessPredicate<WrSparklineHarness>;
|
|
45
|
+
private readonly svg;
|
|
46
|
+
/** The name the chart announces, or `null` when it is decoration. */
|
|
47
|
+
getAccessibleName(): Promise<string | null>;
|
|
48
|
+
/** The role the chart claims — `img` when it is named, `null` when it is not. */
|
|
49
|
+
getRole(): Promise<string | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the chart is hidden from assistive tech.
|
|
52
|
+
*
|
|
53
|
+
* The other half of {@link getAccessibleName}, and the pairing worth asserting
|
|
54
|
+
* together: a named sparkline must NOT be hidden, and an unnamed one must be, or a
|
|
55
|
+
* screen reader announces a graphic with nothing to say about it.
|
|
56
|
+
*/
|
|
57
|
+
isDecorative(): Promise<boolean>;
|
|
58
|
+
/** Whether a trend line was drawn — `false` for an empty or single-point dataset. */
|
|
59
|
+
hasLine(): Promise<boolean>;
|
|
60
|
+
/** Whether the area under the line is filled (`showArea`). */
|
|
61
|
+
hasArea(): Promise<boolean>;
|
|
62
|
+
/** Whether the last point is marked with a dot (`showTip`). */
|
|
63
|
+
hasTip(): Promise<boolean>;
|
|
64
|
+
/** The stroke colour as the component passed it through — a CSS value, not a resolved one. */
|
|
65
|
+
getColor(): Promise<string | null>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { WrSparklineHarness };
|
|
69
|
+
export type { WrSparklineHarnessFilters };
|