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.
- package/action-sheet/styles/_index.scss +4 -1
- package/anchor/styles/_index.scss +2 -1
- package/calendar/styles/_index.scss +11 -2
- package/cascader/styles/_index.scss +3 -1
- package/circular-text/styles/_index.scss +11 -0
- package/command-palette/styles/_index.scss +14 -1
- package/context-menu/styles/_index.scss +2 -1
- package/falling-text/styles/_index.scss +2 -1
- 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-border-glow.mjs +2 -2
- package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
- 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-card.mjs +2 -2
- package/fesm2022/ngwr-cascader.mjs +14 -2
- 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-drag-drop.mjs +2 -2
- 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-falling-text.mjs +2 -2
- package/fesm2022/ngwr-falling-text.mjs.map +1 -1
- 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-glitch-text.mjs +2 -2
- package/fesm2022/ngwr-gradient-text-testing.mjs +223 -0
- package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-gradient-text.mjs +2 -2
- 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-list.mjs +2 -2
- package/fesm2022/ngwr-loading-bar.mjs +2 -2
- package/fesm2022/ngwr-marquee-testing.mjs +336 -0
- package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
- package/fesm2022/ngwr-marquee.mjs +2 -2
- 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-shiny-text.mjs +2 -2
- 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-spotlight-card.mjs +2 -2
- package/fesm2022/ngwr-star-border-testing.mjs +172 -0
- package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
- package/fesm2022/ngwr-star-border.mjs +2 -2
- 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 +21 -3
- 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-typewriter.mjs +2 -2
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
- package/fesm2022/ngwr-waves-testing.mjs +128 -0
- package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
- package/fesm2022/ngwr-waves.mjs +2 -2
- 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/file-upload/styles/_index.scss +7 -2
- 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/result/styles/_index.scss +3 -1
- package/segmented/styles/_index.scss +5 -1
- package/select/styles/_index.scss +3 -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/stepper/styles/_index.scss +18 -2
- package/table/styles/_index.scss +3 -1
- package/theme/styles/_colors.scss +15 -2
- package/theme/styles/_dark.scss +24 -12
- package/tree/styles/_index.scss +4 -2
- 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,280 @@
|
|
|
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-marquee>` a harness query matches. */
|
|
11
|
+
interface WrMarqueeHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/**
|
|
13
|
+
* Match the region's accessible name — the only thing telling two strips on one page
|
|
14
|
+
* apart. A string is an exact match, a RegExp is tested.
|
|
15
|
+
*
|
|
16
|
+
* Every marquee has one: with no `[ariaLabel]` and no catalog it is the literal
|
|
17
|
+
* `'Marquee'`, so this never matches on absence.
|
|
18
|
+
*/
|
|
19
|
+
readonly ariaLabel?: string | RegExp;
|
|
20
|
+
}
|
|
21
|
+
/** Narrows which `.wr-marquee__item` a harness query matches. */
|
|
22
|
+
interface WrMarqueeItemHarnessFilters extends BaseHarnessFilters {
|
|
23
|
+
/** Match what the entry announces — see `WrMarqueeItemHarness.getAccessibleName()`. */
|
|
24
|
+
readonly name?: string | RegExp;
|
|
25
|
+
/** Match only linked (`true`) or only plain (`false`) entries. */
|
|
26
|
+
readonly link?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** One linked entry of the strip, as it announces itself and as it navigates. */
|
|
29
|
+
interface WrMarqueeLink {
|
|
30
|
+
/** The `href` exactly as the item declared it, unresolved. */
|
|
31
|
+
readonly href: string | null;
|
|
32
|
+
/**
|
|
33
|
+
* The link's accessible name. Never `null` in practice — an entry with nothing to call
|
|
34
|
+
* itself falls back to the catalog's `marquee.link`, because a bare "link" was what a
|
|
35
|
+
* screen reader used to announce for every unlabelled logo in the strip.
|
|
36
|
+
*/
|
|
37
|
+
readonly name: string | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @license
|
|
42
|
+
*
|
|
43
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
44
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Test harness for one entry of a `<wr-marquee>`.
|
|
49
|
+
*
|
|
50
|
+
* **Reach these through `WrMarqueeHarness.getItems()`, which scopes them to the first
|
|
51
|
+
* copy.** The strip duplicates its whole sequence to make the loop seamless, so asking
|
|
52
|
+
* the document loader for all of these returns one per entry per copy — at least twice
|
|
53
|
+
* everything, and a count assertion that quietly multiplies. The parent harness is the
|
|
54
|
+
* only place that knows which copy is the original.
|
|
55
|
+
*
|
|
56
|
+
* An entry is built from an image or from a projected template, and it may or may not be
|
|
57
|
+
* a link. That is the reason to ask a harness rather than the DOM: the same question —
|
|
58
|
+
* what does this announce, is it decoration — is answered from a different attribute in
|
|
59
|
+
* each of those shapes, and {@link getAccessibleName} and {@link isDecorative} pick the
|
|
60
|
+
* right one.
|
|
61
|
+
*
|
|
62
|
+
* @see https://ngwr.dev/guides/testing
|
|
63
|
+
*/
|
|
64
|
+
declare class WrMarqueeItemHarness extends ComponentHarness {
|
|
65
|
+
static hostSelector: string;
|
|
66
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
67
|
+
static with(options?: WrMarqueeItemHarnessFilters): HarnessPredicate<WrMarqueeItemHarness>;
|
|
68
|
+
private readonly link;
|
|
69
|
+
private readonly image;
|
|
70
|
+
private readonly node;
|
|
71
|
+
/**
|
|
72
|
+
* What this entry announces, without the caller needing to know how it was built.
|
|
73
|
+
*
|
|
74
|
+
* A linked entry answers with the link's own name, which is the end of a four-step
|
|
75
|
+
* ladder — the item's `ariaLabel`, then its `title`, then an image's `alt`, then the
|
|
76
|
+
* catalog's `marquee.link`. An unlinked image answers with its `alt`, where `''` means
|
|
77
|
+
* the logo is decoration and announces nothing. Anything else answers with its text.
|
|
78
|
+
*/
|
|
79
|
+
getAccessibleName(): Promise<string | null>;
|
|
80
|
+
/** Whether this entry became a link — `[items]` carries `href` per entry, optionally. */
|
|
81
|
+
isLink(): Promise<boolean>;
|
|
82
|
+
/** The `href` exactly as the entry declared it, unresolved, or `null` when it is not a link. */
|
|
83
|
+
getHref(): Promise<string | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the link opens in a new tab AND says so safely: `target="_blank"` with both
|
|
86
|
+
* `noreferrer` and `noopener` in `rel`.
|
|
87
|
+
*
|
|
88
|
+
* One question rather than two, because half of it is a reverse-tabnabbing hole that
|
|
89
|
+
* nothing visual would ever show. The library hard-codes the safe pair, so this is a
|
|
90
|
+
* regression check on the template rather than on the caller's data.
|
|
91
|
+
*
|
|
92
|
+
* Throws for an entry that is not a link, where a `false` would read as "it opens in
|
|
93
|
+
* this tab" — an answer about safety that is not true of anything.
|
|
94
|
+
*/
|
|
95
|
+
opensInNewTab(): Promise<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* Whether this entry's content is kept out of the accessible tree, leaving whatever
|
|
98
|
+
* wraps it to do the announcing.
|
|
99
|
+
*
|
|
100
|
+
* The marker depends on how the entry was built, which is the whole reason to ask here:
|
|
101
|
+
* a projected template inside a named link carries `aria-hidden`, so the link's own name
|
|
102
|
+
* is not read twice, while an image says the same thing with `alt=""`. It describes the
|
|
103
|
+
* CONTENT — a decorative logo inside a link is still announced, by the link, and that
|
|
104
|
+
* name is {@link getAccessibleName}.
|
|
105
|
+
*
|
|
106
|
+
* Throws for an entry that rendered neither, which should not happen — every entry of
|
|
107
|
+
* `[items]` is one or the other.
|
|
108
|
+
*/
|
|
109
|
+
isDecorative(): Promise<boolean>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @license
|
|
114
|
+
*
|
|
115
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
116
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Test harness for `<wr-marquee>`.
|
|
121
|
+
*
|
|
122
|
+
* **Almost everything worth asserting about a marquee is structural, not animated.** The
|
|
123
|
+
* strip duplicates its sequence so the loop has no seam, and only the first copy is left
|
|
124
|
+
* in the accessible tree — {@link getAnnouncedCopyCount} is the assertion that catches
|
|
125
|
+
* the regression that matters, because a duplicate leaking in makes a screen reader read
|
|
126
|
+
* the whole logo strip twice and changes nothing on screen. The other half is the naming
|
|
127
|
+
* ladder on linked entries, which is real logic with a real bug in its history: the
|
|
128
|
+
* fallback used to be the hard-coded English word "link".
|
|
129
|
+
*
|
|
130
|
+
* **Every list query is scoped to the first copy**, and that is the reason to use
|
|
131
|
+
* {@link getItems} rather than a raw `.wr-marquee__item` query, which returns at least
|
|
132
|
+
* twice as many elements as there are entries.
|
|
133
|
+
*
|
|
134
|
+
* Nothing about the motion is offered. The track's `translate3d` is written only when the
|
|
135
|
+
* measured sequence is wider than zero, so it never appears in a test at all, and in a
|
|
136
|
+
* browser it is one frame of a loop that is already stale by the time an assertion reads
|
|
137
|
+
* it. `[speed]` and `[direction]` reach the DOM in no form. Neither does the hover state:
|
|
138
|
+
* pausing flips a private signal with no class, attribute or property behind it, so a
|
|
139
|
+
* `hover()` here would fire events that provably change nothing readable. And the
|
|
140
|
+
* reduced-motion freeze is a CSS `!important` rule with no counterpart in TypeScript,
|
|
141
|
+
* which means the DOM is identical either way — see `getGap` for what a harness can
|
|
142
|
+
* honestly read off a stylesheet-driven component, and why it reads it where it does.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const loader = TestbedHarnessEnvironment.loader(fixture);
|
|
147
|
+
* const strip = await loader.getHarness(WrMarqueeHarness);
|
|
148
|
+
*
|
|
149
|
+
* expect(await strip.getAnnouncedCopyCount()).toBe(1);
|
|
150
|
+
* expect(await strip.getItemCount()).toBe(logos.length);
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @see https://ngwr.dev/guides/testing
|
|
154
|
+
*/
|
|
155
|
+
declare class WrMarqueeHarness extends ComponentHarness {
|
|
156
|
+
static hostSelector: string;
|
|
157
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
158
|
+
static with(options?: WrMarqueeHarnessFilters): HarnessPredicate<WrMarqueeHarness>;
|
|
159
|
+
private readonly copies;
|
|
160
|
+
/**
|
|
161
|
+
* The name the region announces.
|
|
162
|
+
*
|
|
163
|
+
* Pins the i18n ladder end to end: `'Marquee'` with no catalog loaded, the consumer's
|
|
164
|
+
* `[ariaLabel]` when one is given, the localized string under a catalog. A landmark
|
|
165
|
+
* with no name is an axe failure, so this is what keeps the `region` legitimate rather
|
|
166
|
+
* than a decoration a screen-reader user is invited to jump to and finds unnamed.
|
|
167
|
+
*/
|
|
168
|
+
getAccessibleName(): Promise<string | null>;
|
|
169
|
+
/**
|
|
170
|
+
* The landmark role the strip claims.
|
|
171
|
+
*
|
|
172
|
+
* Static in the template and one attribute away from being dropped in a refactor, which
|
|
173
|
+
* is exactly why a consumer asserting their page's landmark structure should be able to
|
|
174
|
+
* see it from here.
|
|
175
|
+
*/
|
|
176
|
+
getRole(): Promise<string | null>;
|
|
177
|
+
/**
|
|
178
|
+
* How many copies of the sequence are rendered.
|
|
179
|
+
*
|
|
180
|
+
* The seamless loop is built by repeating the whole list until it covers the container,
|
|
181
|
+
* so the count is decided by measurement — which means it stays at the floor of 2 in a
|
|
182
|
+
* test with no layout, whatever the container would really be. Assert `>= 2`; the
|
|
183
|
+
* growth needs a browser.
|
|
184
|
+
*/
|
|
185
|
+
getCopyCount(): Promise<number>;
|
|
186
|
+
/**
|
|
187
|
+
* How many copies are left in the accessible tree. Must be exactly 1.
|
|
188
|
+
*
|
|
189
|
+
* The one assertion here that catches a silent regression: every copy after the first
|
|
190
|
+
* carries `aria-hidden="true"`, and losing that makes a screen reader read the whole
|
|
191
|
+
* strip once per copy while the page looks unchanged.
|
|
192
|
+
*
|
|
193
|
+
* Note the first copy carries the literal `aria-hidden="false"` rather than no
|
|
194
|
+
* attribute at all, so this compares against the string `'true'` — testing the
|
|
195
|
+
* attribute for presence would count nothing at all as announced.
|
|
196
|
+
*/
|
|
197
|
+
getAnnouncedCopyCount(): Promise<number>;
|
|
198
|
+
/** The entries of the first copy, in order — one per entry of `[items]`. */
|
|
199
|
+
getItems(): Promise<WrMarqueeItemHarness[]>;
|
|
200
|
+
/**
|
|
201
|
+
* How many entries the strip drew, counting the first copy only.
|
|
202
|
+
*
|
|
203
|
+
* One per entry of `[items]` — the mapping a consumer's own data pipeline is really
|
|
204
|
+
* being tested for.
|
|
205
|
+
*/
|
|
206
|
+
getItemCount(): Promise<number>;
|
|
207
|
+
/**
|
|
208
|
+
* The `alt` of each image in the first copy, in order.
|
|
209
|
+
*
|
|
210
|
+
* `null` in this list is the thing to look for: it means the attribute is MISSING, which
|
|
211
|
+
* is a serious axe violation and announces the file name. An empty string is the
|
|
212
|
+
* opposite — a deliberately decorative logo — and the template's `alt || ''` is what
|
|
213
|
+
* keeps the two apart. A method typed `string[]` would have had to flatten them.
|
|
214
|
+
*/
|
|
215
|
+
getImageAlts(): Promise<(string | null)[]>;
|
|
216
|
+
/**
|
|
217
|
+
* Every linked entry of the first copy: where it goes and what it announces.
|
|
218
|
+
*
|
|
219
|
+
* The name is the interesting half. It walks a ladder ending in the catalog's
|
|
220
|
+
* `marquee.link`, so an unlabelled logo announces a localized word rather than nothing
|
|
221
|
+
* — real component logic rather than an echo of the input.
|
|
222
|
+
*/
|
|
223
|
+
getLinks(): Promise<WrMarqueeLink[]>;
|
|
224
|
+
/**
|
|
225
|
+
* Whether the edge fades are on.
|
|
226
|
+
*
|
|
227
|
+
* The fades themselves are `::before` / `::after` gradients, which no unit environment
|
|
228
|
+
* can see — so the modifier class is the observable, and it is public API a consumer
|
|
229
|
+
* may be styling against in any case.
|
|
230
|
+
*/
|
|
231
|
+
hasFade(): Promise<boolean>;
|
|
232
|
+
/**
|
|
233
|
+
* The fade colour as the component passed it through — a CSS value such as
|
|
234
|
+
* `'var(--wr-color-success)'`, not a resolved colour — or `null` when none was given.
|
|
235
|
+
*
|
|
236
|
+
* Worth asserting next to {@link hasFade}: a colour with no fade modifier renders
|
|
237
|
+
* nothing at all, which is a consumer mistake this pairing makes visible.
|
|
238
|
+
*/
|
|
239
|
+
getFadeColor(): Promise<string | null>;
|
|
240
|
+
/**
|
|
241
|
+
* Whether entries scale up under the pointer.
|
|
242
|
+
*
|
|
243
|
+
* A `:hover` transform, so again the modifier is the only honest read — and it earns
|
|
244
|
+
* its place by doing more than the name suggests: it also changes the strip's vertical
|
|
245
|
+
* padding, so a lost class shifts the layout as well as the hover.
|
|
246
|
+
*/
|
|
247
|
+
hasScaleOnHover(): Promise<boolean>;
|
|
248
|
+
/** The gap between entries in pixels — the seam width the stylesheet reads. */
|
|
249
|
+
getGap(): Promise<number>;
|
|
250
|
+
/**
|
|
251
|
+
* The entry height in pixels.
|
|
252
|
+
*
|
|
253
|
+
* It drives the image height AND the entry font size, so a binding that stops arriving
|
|
254
|
+
* collapses the whole strip rather than merely resizing it.
|
|
255
|
+
*/
|
|
256
|
+
getItemHeight(): Promise<number>;
|
|
257
|
+
/**
|
|
258
|
+
* Read a custom property off the host's inline `style`, rather than through
|
|
259
|
+
* `getCssValue()`.
|
|
260
|
+
*
|
|
261
|
+
* Not a jsdom workaround — the opposite. The stylesheet declares its own
|
|
262
|
+
* `--wr-marquee-gap: 32px` and `--wr-marquee-height: 28px` on `.wr-marquee`, so a
|
|
263
|
+
* computed read in a real browser answers with the stylesheet's default when the host
|
|
264
|
+
* binding is the very thing that broke. The inline value is what the component wrote,
|
|
265
|
+
* and nothing else can forge it.
|
|
266
|
+
*/
|
|
267
|
+
private hostStyle;
|
|
268
|
+
/**
|
|
269
|
+
* Parse a `<n>px` custom property, refusing anything that lost its unit.
|
|
270
|
+
*
|
|
271
|
+
* The refusal is the point. `[gap]` and `[itemHeight]` are numbers that the host binding
|
|
272
|
+
* turns into lengths, and the stylesheet uses them raw — a bare `32` is an invalid
|
|
273
|
+
* declaration, so the property falls back to the stylesheet default and the strip looks
|
|
274
|
+
* merely a little different. A `parseFloat` would report 32 either way and hide it.
|
|
275
|
+
*/
|
|
276
|
+
private pixels;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export { WrMarqueeHarness, WrMarqueeItemHarness };
|
|
280
|
+
export type { WrMarqueeHarnessFilters, WrMarqueeItemHarnessFilters, WrMarqueeLink };
|
|
@@ -0,0 +1,67 @@
|
|
|
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-meter-group>` a harness query matches. */
|
|
11
|
+
interface WrMeterGroupHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the bar's accessible name. */
|
|
13
|
+
readonly ariaLabel?: string | RegExp;
|
|
14
|
+
/** Match a group whose legend holds this label. */
|
|
15
|
+
readonly sliceLabel?: string | RegExp;
|
|
16
|
+
}
|
|
17
|
+
/** One band of the bar, as it is drawn and titled. */
|
|
18
|
+
interface WrMeterGroupSlice {
|
|
19
|
+
/** The band's `title` — its only text, since the bar itself is one `progressbar`. */
|
|
20
|
+
readonly label: string | null;
|
|
21
|
+
/** The share of the bar it takes, in percent. */
|
|
22
|
+
readonly percent: 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 `<wr-meter-group>` — one bar divided into labelled bands.
|
|
34
|
+
*
|
|
35
|
+
* **The bar is a single `progressbar`, and its value is the TOTAL.** The bands
|
|
36
|
+
* themselves announce nothing: they carry a `title` for a mouse and their share as an
|
|
37
|
+
* inline width, and the legend is where their labels and values are readable. So a
|
|
38
|
+
* spec that wants "how much of each" reads {@link getLegend} or {@link getSlices},
|
|
39
|
+
* and one that wants "how full" reads {@link getValue}.
|
|
40
|
+
*
|
|
41
|
+
* @see https://ngwr.dev/guides/testing
|
|
42
|
+
*/
|
|
43
|
+
declare class WrMeterGroupHarness extends ComponentHarness {
|
|
44
|
+
static hostSelector: string;
|
|
45
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
46
|
+
static with(options?: WrMeterGroupHarnessFilters): HarnessPredicate<WrMeterGroupHarness>;
|
|
47
|
+
private readonly bar;
|
|
48
|
+
/** The role the bar announces — `progressbar`, for the total. */
|
|
49
|
+
getRole(): Promise<string | null>;
|
|
50
|
+
/** The bar's accessible name. */
|
|
51
|
+
getAccessibleName(): Promise<string | null>;
|
|
52
|
+
/** The total the bands add up to, from `aria-valuenow`. */
|
|
53
|
+
getValue(): Promise<number>;
|
|
54
|
+
/** The full capacity, from `aria-valuemax` — given, or the sum of the bands. */
|
|
55
|
+
getMax(): Promise<number>;
|
|
56
|
+
/** The bands, in order, with the share of the bar each takes. */
|
|
57
|
+
getSlices(): Promise<WrMeterGroupSlice[]>;
|
|
58
|
+
/** Whether the legend is rendered (`showLegend`, and at least one band). */
|
|
59
|
+
hasLegend(): Promise<boolean>;
|
|
60
|
+
/** The legend's labels, in order. */
|
|
61
|
+
getLegendLabels(): Promise<string[]>;
|
|
62
|
+
/** The legend's values, in order — empty when `showValues` is off. */
|
|
63
|
+
getLegendValues(): Promise<string[]>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { WrMeterGroupHarness };
|
|
67
|
+
export type { WrMeterGroupHarnessFilters, WrMeterGroupSlice };
|
package/types/ngwr-overlay.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ declare function wrMirrorOffsets(positions: readonly ConnectedPosition[], isRtl:
|
|
|
90
90
|
*
|
|
91
91
|
* Registration is per subscription: the document listeners go up with the first
|
|
92
92
|
* watcher and come down with the last, so an app with no open overlay has none.
|
|
93
|
+
* That sentence was aspirational until v11 — see {@link outsidePointerEvents}.
|
|
93
94
|
*/
|
|
94
95
|
declare class WrOutsideClick {
|
|
95
96
|
private readonly doc;
|
|
@@ -100,7 +101,24 @@ declare class WrOutsideClick {
|
|
|
100
101
|
private pressOrigin;
|
|
101
102
|
/**
|
|
102
103
|
* Emits every `click` / `auxclick` / `contextmenu` that lands outside the
|
|
103
|
-
* given overlay's pane, for as long as the
|
|
104
|
+
* given overlay's pane, for as long as the overlay is attached.
|
|
105
|
+
*
|
|
106
|
+
* **It completes when the overlay detaches, and that is load-bearing.** Every
|
|
107
|
+
* one of the ten call sites subscribes inside its own `openOverlay()` and
|
|
108
|
+
* pipes `takeUntilDestroyed(destroyRef)` — a DIRECTIVE lifetime, not an
|
|
109
|
+
* overlay one — and none of them unsubscribes on close, because the natural
|
|
110
|
+
* reading of that idiom is "this ends with the component". Without the
|
|
111
|
+
* completion below the teardown never ran: one watcher accumulated per OPEN
|
|
112
|
+
* for the life of the page, each pinning a disposed `OverlayRef` (and through
|
|
113
|
+
* it a detached pane, its portal outlet and their injectors), the four
|
|
114
|
+
* capture-phase document listeners could never come down because
|
|
115
|
+
* `watchers.length` never reached zero, and every click on the page walked a
|
|
116
|
+
* list that only grew. A `mode="tooltip"` popover made it unbounded — one
|
|
117
|
+
* permanent watcher per hover.
|
|
118
|
+
*
|
|
119
|
+
* Completing here rather than fixing ten call sites is deliberate: the next
|
|
120
|
+
* component to open an overlay would have made the same reasonable mistake.
|
|
121
|
+
* It is also what CDK's own `OverlayRef.outsidePointerEvents()` does.
|
|
104
122
|
*/
|
|
105
123
|
outsidePointerEvents(overlayRef: OverlayRef): Observable<MouseEvent>;
|
|
106
124
|
private readonly onPointerDown;
|
|
@@ -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). */
|