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,79 @@
|
|
|
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-donut-chart>` a harness query matches. */
|
|
11
|
+
interface WrDonutChartHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the chart's accessible name. */
|
|
13
|
+
readonly ariaLabel?: string | RegExp;
|
|
14
|
+
/** Match a chart whose legend holds this label. */
|
|
15
|
+
readonly sliceLabel?: string | RegExp;
|
|
16
|
+
}
|
|
17
|
+
/** One legend row — the only place a slice's label and value are readable. */
|
|
18
|
+
interface WrDonutChartLegendEntry {
|
|
19
|
+
readonly label: string;
|
|
20
|
+
readonly value: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @license
|
|
25
|
+
*
|
|
26
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
27
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Test harness for `<wr-donut-chart>`.
|
|
32
|
+
*
|
|
33
|
+
* **The ring itself is unreadable, and that is by design.** The slices are SVG
|
|
34
|
+
* paths inside an `aria-hidden` drawing: a screen reader is given the chart's
|
|
35
|
+
* `aria-label` and nothing else, and a spec cannot get a label or a value off a
|
|
36
|
+
* path's `d`. {@link getLegend} is where the numbers are — which is also the
|
|
37
|
+
* argument for keeping `showLegend` on, since with it off the chart's data has no
|
|
38
|
+
* textual form at all.
|
|
39
|
+
*
|
|
40
|
+
* {@link getSliceCount} is therefore the one thing the ring answers: how many
|
|
41
|
+
* wedges were drawn. Compare it with the legend's length to catch a slice that was
|
|
42
|
+
* filtered out of one and not the other.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const chart = await loader.getHarness(WrDonutChartHarness);
|
|
47
|
+
*
|
|
48
|
+
* expect(await chart.getSliceCount()).toBe(3);
|
|
49
|
+
* expect(await chart.getLegend()).toEqual([
|
|
50
|
+
* { label: 'Direct', value: '48' },
|
|
51
|
+
* { label: 'Search', value: '32' },
|
|
52
|
+
* { label: 'Social', value: '20' },
|
|
53
|
+
* ]);
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @see https://ngwr.dev/guides/testing
|
|
57
|
+
*/
|
|
58
|
+
declare class WrDonutChartHarness extends ComponentHarness {
|
|
59
|
+
static hostSelector: string;
|
|
60
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
61
|
+
static with(options?: WrDonutChartHarnessFilters): HarnessPredicate<WrDonutChartHarness>;
|
|
62
|
+
/** The name the ring announces — the whole chart's, since the slices announce nothing. */
|
|
63
|
+
getAccessibleName(): Promise<string | null>;
|
|
64
|
+
/** How many wedges were drawn. */
|
|
65
|
+
getSliceCount(): Promise<number>;
|
|
66
|
+
/** Whether the legend is rendered (`showLegend`, and at least one slice). */
|
|
67
|
+
hasLegend(): Promise<boolean>;
|
|
68
|
+
/** The legend rows in order — the only textual form the data has. */
|
|
69
|
+
getLegend(): Promise<WrDonutChartLegendEntry[]>;
|
|
70
|
+
/** The big number in the middle, or `null` when the chart has none. */
|
|
71
|
+
getCenterValue(): Promise<string | null>;
|
|
72
|
+
/** The caption under the centre value, or `null`. */
|
|
73
|
+
getCenterLabel(): Promise<string | null>;
|
|
74
|
+
/** The ring's diameter in pixels, as the component writes it inline. */
|
|
75
|
+
getSize(): Promise<number>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { WrDonutChartHarness };
|
|
79
|
+
export type { WrDonutChartHarnessFilters, WrDonutChartLegendEntry };
|
package/types/ngwr-drawer.d.ts
CHANGED
|
@@ -143,6 +143,18 @@ declare class WrDrawer {
|
|
|
143
143
|
private focusTrap;
|
|
144
144
|
private previouslyFocused;
|
|
145
145
|
constructor();
|
|
146
|
+
/**
|
|
147
|
+
* Point the panel's `aria-labelledby` at the CURRENT `[wrDrawerTitle]`.
|
|
148
|
+
*
|
|
149
|
+
* Re-resolved after every render rather than once when the drawer opens,
|
|
150
|
+
* because the title element is projected content and can come and go while
|
|
151
|
+
* the drawer stays open — an `@if` around it, or a heading that only exists
|
|
152
|
+
* once the data arrives. A one-shot lookup leaves the attribute naming an
|
|
153
|
+
* element that has been removed or replaced, and a dangling reference is not
|
|
154
|
+
* a name: the dialog is announced as unnamed, with nothing on screen to say
|
|
155
|
+
* so. A missing title clears the attribute for the same reason.
|
|
156
|
+
*/
|
|
157
|
+
private syncLabel;
|
|
146
158
|
private openOverlay;
|
|
147
159
|
private closeOverlay;
|
|
148
160
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDrawer, never>;
|
package/types/ngwr-dropdown.d.ts
CHANGED
|
@@ -97,6 +97,15 @@ declare class WrDropdown {
|
|
|
97
97
|
/** Toggle the menu. */
|
|
98
98
|
toggle(): void;
|
|
99
99
|
/** @internal */
|
|
100
|
+
/**
|
|
101
|
+
* Whether the pointer, rather than the keyboard, opened the current menu.
|
|
102
|
+
*
|
|
103
|
+
* A hover-opened menu must not take focus — the APG shows a menu on hover and
|
|
104
|
+
* leaves the caret where it was — while a keyboard-opened one must. The
|
|
105
|
+
* trigger MODE cannot answer that on its own: a `trigger="hover"` menu is
|
|
106
|
+
* still openable with Enter, and that open should focus the first item.
|
|
107
|
+
*/
|
|
108
|
+
private openedByPointer;
|
|
100
109
|
protected onClick(event: MouseEvent): void;
|
|
101
110
|
/** @internal */
|
|
102
111
|
protected onMouseEnter(): void;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
|
|
2
|
+
import { WrCalendarView } from 'ngwr/event-calendar';
|
|
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
|
+
/** Narrows which `<wr-event-calendar>` a harness query matches. */
|
|
12
|
+
interface WrEventCalendarHarnessFilters extends BaseHarnessFilters {
|
|
13
|
+
/** Match the header title as printed — a string is an exact match, a RegExp is tested. */
|
|
14
|
+
readonly title?: string | RegExp;
|
|
15
|
+
/** Match the view the calendar is showing. */
|
|
16
|
+
readonly view?: WrCalendarView;
|
|
17
|
+
}
|
|
18
|
+
/** Narrows which event chip a harness query matches. */
|
|
19
|
+
interface WrEventCalendarChipHarnessFilters extends BaseHarnessFilters {
|
|
20
|
+
/**
|
|
21
|
+
* Match the chip's accessible name, which is the time and the title together —
|
|
22
|
+
* the visible text is `aria-hidden`, so this is what a screen reader gets.
|
|
23
|
+
*/
|
|
24
|
+
readonly label?: string | RegExp;
|
|
25
|
+
/** Match the chip's title text as printed. */
|
|
26
|
+
readonly title?: string | RegExp;
|
|
27
|
+
/** Match day-spanning bands (`true`) or timed chips (`false`). */
|
|
28
|
+
readonly band?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @license
|
|
33
|
+
*
|
|
34
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
35
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/** The arrow keys, by the direction a user would say out loud. */
|
|
39
|
+
type Arrow$1 = 'left' | 'right' | 'up' | 'down';
|
|
40
|
+
/**
|
|
41
|
+
* Test harness for one event chip inside a {@link WrEventCalendarHarness}.
|
|
42
|
+
*
|
|
43
|
+
* **The visible text is `aria-hidden`; the name is on the button.** A chip prints a
|
|
44
|
+
* time and a title for the eye, and publishes both as one `aria-label` for a screen
|
|
45
|
+
* reader — so {@link getLabel} is what the control announces and {@link getTitle} is
|
|
46
|
+
* what is drawn. They are separate because a consumer's `[wrCalendarEvent]` template
|
|
47
|
+
* replaces the drawn half and not the announced one.
|
|
48
|
+
*
|
|
49
|
+
* **Moving and resizing are on the keyboard here, and not because of jsdom.** The
|
|
50
|
+
* pointer drag is real, but the same two operations are bound to the arrows —
|
|
51
|
+
* `Alt` to move, `Alt` + `Shift` to resize — precisely so the calendar is usable
|
|
52
|
+
* without one. That is the path this harness drives; a synthetic drag would divide
|
|
53
|
+
* by a rect that measures 0×0 anyway.
|
|
54
|
+
*
|
|
55
|
+
* @see https://ngwr.dev/guides/testing
|
|
56
|
+
*/
|
|
57
|
+
declare class WrEventCalendarChipHarness extends ComponentHarness {
|
|
58
|
+
static hostSelector: string;
|
|
59
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
60
|
+
static with(options?: WrEventCalendarChipHarnessFilters): HarnessPredicate<WrEventCalendarChipHarness>;
|
|
61
|
+
/** What the chip announces — its time and title in one string. */
|
|
62
|
+
getLabel(): Promise<string | null>;
|
|
63
|
+
/**
|
|
64
|
+
* The title as drawn, or `null` when a consumer template replaced it.
|
|
65
|
+
*
|
|
66
|
+
* The default chip prints its own `.wr-event-calendar__chip-title`; a
|
|
67
|
+
* `[wrCalendarEvent]` template renders whatever the consumer wrote instead, and
|
|
68
|
+
* there is no title element to find. {@link getText} is the fallback that always
|
|
69
|
+
* answers.
|
|
70
|
+
*/
|
|
71
|
+
getTitle(): Promise<string | null>;
|
|
72
|
+
/** The chip's whole rendered text, whoever drew it. */
|
|
73
|
+
getText(): Promise<string>;
|
|
74
|
+
/** The time as printed on a timed chip, or `null` on a band, which prints none. */
|
|
75
|
+
getTime(): Promise<string | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this is a day-spanning BAND rather than a timed chip.
|
|
78
|
+
*
|
|
79
|
+
* One shape covers two places — a month cell and the all-day row — and the other
|
|
80
|
+
* is the block in a time grid. They size themselves completely differently (a
|
|
81
|
+
* `calc()` width across columns versus a percentage height down one), which is why
|
|
82
|
+
* the two are worth telling apart.
|
|
83
|
+
*/
|
|
84
|
+
isBand(): Promise<boolean>;
|
|
85
|
+
/** Whether the event started before this cell — the chip is drawn cut off at the leading edge. */
|
|
86
|
+
continuesBefore(): Promise<boolean>;
|
|
87
|
+
/** Whether the event runs past this cell. */
|
|
88
|
+
continuesAfter(): Promise<boolean>;
|
|
89
|
+
/** Whether the chip is mid-drag. */
|
|
90
|
+
isDragging(): Promise<boolean>;
|
|
91
|
+
/**
|
|
92
|
+
* Whether the chip offers a resize grab area.
|
|
93
|
+
*
|
|
94
|
+
* It is `aria-hidden` and not focusable on purpose — the same resize is `Alt` +
|
|
95
|
+
* `Shift` + arrows on the chip itself, so a second tab stop here would lead
|
|
96
|
+
* nowhere. Its
|
|
97
|
+
* presence is still the mouse affordance, and it is dropped on a chip whose event
|
|
98
|
+
* continues past this cell.
|
|
99
|
+
*/
|
|
100
|
+
hasResizeHandle(): Promise<boolean>;
|
|
101
|
+
/**
|
|
102
|
+
* Click the chip — which emits `eventClick` and does NOT bubble to the cell
|
|
103
|
+
* underneath.
|
|
104
|
+
*
|
|
105
|
+
* On an editable calendar this needs `document.elementFromPoint` to exist: the CDK
|
|
106
|
+
* dispatches a whole pointer sequence, and the chip's `pointerdown` hit-tests for
|
|
107
|
+
* the cell under the cursor. jsdom implements no such method, so stub it in your
|
|
108
|
+
* spec — `() => null` is the honest answer where nothing has a box — or the click
|
|
109
|
+
* throws out of the listener.
|
|
110
|
+
*/
|
|
111
|
+
click(): Promise<void>;
|
|
112
|
+
/** Move keyboard focus to the chip. */
|
|
113
|
+
focus(): Promise<void>;
|
|
114
|
+
/** Whether the chip currently holds focus. */
|
|
115
|
+
isFocused(): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Move the event — `Alt` + an arrow, a day sideways or a slot vertically.
|
|
118
|
+
*
|
|
119
|
+
* The calendar never mutates `events`: this emits `eventChange` and the host is
|
|
120
|
+
* expected to apply it. A spec whose host ignores the output is asserting a
|
|
121
|
+
* CANCELLED move, which is the contract and the most common surprise here. A
|
|
122
|
+
* calendar without `editable` ignores the keys entirely — the same gate the pointer
|
|
123
|
+
* path uses.
|
|
124
|
+
*/
|
|
125
|
+
move(arrow: Arrow$1): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Resize the event — `Alt` + `Shift` + an arrow, which moves the END alone.
|
|
128
|
+
*
|
|
129
|
+
* A resize that would end at or before the start emits nothing rather than
|
|
130
|
+
* inverting the event, which is the pointer path's rule too.
|
|
131
|
+
*/
|
|
132
|
+
resize(arrow: Arrow$1): Promise<void>;
|
|
133
|
+
/** Press a bare arrow — which the chip ignores, letting the grid's own navigation run. */
|
|
134
|
+
pressArrow(arrow: Arrow$1): Promise<void>;
|
|
135
|
+
/** Press Escape — handing focus back to the cell the chip sits in. */
|
|
136
|
+
sendEscape(): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @license
|
|
141
|
+
*
|
|
142
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
143
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
/** The arrow keys, by the direction a user would say out loud. */
|
|
147
|
+
type Arrow = 'left' | 'right' | 'up' | 'down';
|
|
148
|
+
/**
|
|
149
|
+
* Test harness for `<wr-event-calendar>` — month, week and day in one component.
|
|
150
|
+
*
|
|
151
|
+
* **Every chip lives inside the `role="gridcell"` where its event STARTS**, and
|
|
152
|
+
* reaches out from there with a `calc()` width or a percentage height. That is a
|
|
153
|
+
* deliberate structural choice — a floating events layer would leave `role="row"`
|
|
154
|
+
* owning something other than cells — and it is why {@link getChips} can be scoped
|
|
155
|
+
* to a cell at all.
|
|
156
|
+
*
|
|
157
|
+
* **The view is read from the DOM, not from the input.** A month renders one grid
|
|
158
|
+
* shape and week / day another, and those two are told apart by how many day columns
|
|
159
|
+
* they draw. That is the honest answer for a harness: `view` is a model a consumer
|
|
160
|
+
* can write, and the grid is what the user sees.
|
|
161
|
+
*
|
|
162
|
+
* **Nothing here mutates the events.** A move or a resize emits `eventChange` and
|
|
163
|
+
* the host applies it — so a spec whose host ignores the output is asserting a
|
|
164
|
+
* CANCELLED gesture, which is the contract rather than a bug.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const calendar = await loader.getHarness(WrEventCalendarHarness);
|
|
169
|
+
*
|
|
170
|
+
* expect(await calendar.getView()).toBe('month');
|
|
171
|
+
* const [standup] = await calendar.getChips({ title: 'Standup' });
|
|
172
|
+
* await standup.move('right');
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* @see https://ngwr.dev/guides/testing
|
|
176
|
+
*/
|
|
177
|
+
declare class WrEventCalendarHarness extends ComponentHarness {
|
|
178
|
+
static hostSelector: string;
|
|
179
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
180
|
+
static with(options?: WrEventCalendarHarnessFilters): HarnessPredicate<WrEventCalendarHarness>;
|
|
181
|
+
private readonly grid;
|
|
182
|
+
/**
|
|
183
|
+
* Which view is on screen.
|
|
184
|
+
*
|
|
185
|
+
* `month` has its own grid modifier; `week` and `day` share the time grid and are
|
|
186
|
+
* told apart by the column count the component publishes on it. Reading the DOM
|
|
187
|
+
* rather than the `view` model is the point — that model is an input a consumer can
|
|
188
|
+
* set to anything, and this is what got rendered.
|
|
189
|
+
*/
|
|
190
|
+
getView(): Promise<WrCalendarView>;
|
|
191
|
+
/** The header title — the month, the week's range, or the day. */
|
|
192
|
+
getTitle(): Promise<string>;
|
|
193
|
+
/** Whether the header is rendered at all (`hideHeader`). */
|
|
194
|
+
hasHeader(): Promise<boolean>;
|
|
195
|
+
/** The grid's accessible name. */
|
|
196
|
+
getAccessibleName(): Promise<string | null>;
|
|
197
|
+
/** Step back one month, week or day, depending on the view. */
|
|
198
|
+
previous(): Promise<void>;
|
|
199
|
+
/** Step forward one month, week or day. */
|
|
200
|
+
next(): Promise<void>;
|
|
201
|
+
/** Press the Today button — jumping to the period containing today. */
|
|
202
|
+
goToday(): Promise<void>;
|
|
203
|
+
/** The back arrow's accessible name — the two steps are icon-only. */
|
|
204
|
+
getPreviousLabel(): Promise<string | null>;
|
|
205
|
+
/** The forward arrow's accessible name. */
|
|
206
|
+
getNextLabel(): Promise<string | null>;
|
|
207
|
+
/** The Today button's label. */
|
|
208
|
+
getTodayLabel(): Promise<string>;
|
|
209
|
+
/**
|
|
210
|
+
* The view switcher's labels, in order — empty when the calendar was given a single
|
|
211
|
+
* view, which drops the switcher entirely.
|
|
212
|
+
*/
|
|
213
|
+
getViewLabels(): Promise<string[]>;
|
|
214
|
+
/** The label of the view currently pressed, or `null` when there is no switcher. */
|
|
215
|
+
getActiveViewLabel(): Promise<string | null>;
|
|
216
|
+
/**
|
|
217
|
+
* Switch view by the label the switcher prints.
|
|
218
|
+
*
|
|
219
|
+
* By label rather than by the `WrCalendarView` value, because the label is what the
|
|
220
|
+
* DOM has — the value never reaches it, and a spec that passed one would be naming
|
|
221
|
+
* something only the component can see. {@link getViewLabels} lists them.
|
|
222
|
+
*/
|
|
223
|
+
setView(label: string): Promise<void>;
|
|
224
|
+
/** The weekday column headers of the month view. */
|
|
225
|
+
getWeekdayNames(): Promise<string[]>;
|
|
226
|
+
/** The day numbers of the month grid, in order — 42 of them, spill days included. */
|
|
227
|
+
getDayNumbers(): Promise<string[]>;
|
|
228
|
+
/** The time-gutter labels down the left of a week or day view. */
|
|
229
|
+
getSlotLabels(): Promise<string[]>;
|
|
230
|
+
/** Whether the time views drew an all-day band, which they only do when something needs it. */
|
|
231
|
+
hasAllDayRow(): Promise<boolean>;
|
|
232
|
+
/**
|
|
233
|
+
* Every chip on screen, in DOM order.
|
|
234
|
+
*
|
|
235
|
+
* A multi-day event has ONE chip, in the cell where it starts — the band reaches
|
|
236
|
+
* across the rest — so this counts events-in-view rather than event-days.
|
|
237
|
+
*/
|
|
238
|
+
getChips(filters?: WrEventCalendarChipHarnessFilters): Promise<WrEventCalendarChipHarness[]>;
|
|
239
|
+
/** The chips' announced names, in DOM order. */
|
|
240
|
+
getChipLabels(): Promise<(string | null)[]>;
|
|
241
|
+
/**
|
|
242
|
+
* The "+N more" overflow buttons of the month view, by the text they print.
|
|
243
|
+
*
|
|
244
|
+
* A month cell shows `maxLanes` chips and hides the rest behind one of these, which
|
|
245
|
+
* opens the day view — so its presence is the only sign that a cell has more than
|
|
246
|
+
* it is showing.
|
|
247
|
+
*/
|
|
248
|
+
getOverflowLabels(): Promise<string[]>;
|
|
249
|
+
/** Click the first "+N more" button, which drops to the day view for that date. */
|
|
250
|
+
openOverflow(): Promise<void>;
|
|
251
|
+
/**
|
|
252
|
+
* Click an empty part of a cell — which emits `slotClick` with its date and minutes.
|
|
253
|
+
*
|
|
254
|
+
* A cell is addressed by its DAY and, in a time view, the minutes from midnight of
|
|
255
|
+
* its row (`-1` means a month cell or the all-day band). Both come off the two data
|
|
256
|
+
* attributes every cell publishes for the drag's own hit-testing, which makes them
|
|
257
|
+
* the one stable way to name a cell from outside — a row index would mean something
|
|
258
|
+
* different in each view.
|
|
259
|
+
*/
|
|
260
|
+
clickCell(day: Date, minutes?: number): Promise<void>;
|
|
261
|
+
/** A cell's accessible name — the date, and the time for a slot. */
|
|
262
|
+
getCellLabel(day: Date, minutes?: number): Promise<string | null>;
|
|
263
|
+
/** The chips inside ONE cell, which is where a chip's event starts. */
|
|
264
|
+
getCellChips(day: Date, minutes?: number): Promise<WrEventCalendarChipHarness[]>;
|
|
265
|
+
/**
|
|
266
|
+
* The grid's single tab stop, as `"<day>:<minutes>"`.
|
|
267
|
+
*
|
|
268
|
+
* The cursor roves rather than every cell being tabbable, and it is RAW — it
|
|
269
|
+
* survives a view switch, so the same pair means a different cell in a month grid
|
|
270
|
+
* and a week one.
|
|
271
|
+
*/
|
|
272
|
+
getCursor(): Promise<string | null>;
|
|
273
|
+
/** Move keyboard focus to a cell, which is also what moves the roving cursor onto it. */
|
|
274
|
+
focusCell(day: Date, minutes?: number): Promise<void>;
|
|
275
|
+
/**
|
|
276
|
+
* Press an arrow on the cell that currently holds the cursor.
|
|
277
|
+
*
|
|
278
|
+
* Sent to that cell rather than to the grid, because the component listens per cell
|
|
279
|
+
* — the element carrying the keyboard should be the one that holds focus — and
|
|
280
|
+
* anything originating inside a chip is deliberately let through untouched.
|
|
281
|
+
*/
|
|
282
|
+
pressArrow(arrow: Arrow): Promise<void>;
|
|
283
|
+
/** Press Home on the cursor cell — the first day of its week. */
|
|
284
|
+
pressHome(): Promise<void>;
|
|
285
|
+
/** Press End on the cursor cell — the last day of its week. */
|
|
286
|
+
pressEnd(): Promise<void>;
|
|
287
|
+
private step;
|
|
288
|
+
private stepElement;
|
|
289
|
+
private headerButton;
|
|
290
|
+
/**
|
|
291
|
+
* The stamp a cell publishes for a day — local midnight, which is what the
|
|
292
|
+
* component's own `startOfDay` produces. Taking a `Date` and normalising here keeps
|
|
293
|
+
* the timestamp out of every spec.
|
|
294
|
+
*/
|
|
295
|
+
private stamp;
|
|
296
|
+
private requireCell;
|
|
297
|
+
private cursorCell;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export { WrEventCalendarChipHarness, WrEventCalendarHarness };
|
|
301
|
+
export type { WrEventCalendarChipHarnessFilters, WrEventCalendarHarnessFilters };
|
|
@@ -220,13 +220,16 @@ declare class WrEventCalendar {
|
|
|
220
220
|
private readonly document;
|
|
221
221
|
private readonly dir;
|
|
222
222
|
private readonly chipTpl;
|
|
223
|
-
protected readonly todayLabel: string
|
|
224
|
-
protected readonly previousLabel: string
|
|
225
|
-
protected readonly nextLabel: string
|
|
226
|
-
protected readonly allDayLabel: string
|
|
227
|
-
protected readonly timeLabel: string
|
|
223
|
+
protected readonly todayLabel: _angular_core.Signal<string>;
|
|
224
|
+
protected readonly previousLabel: _angular_core.Signal<string>;
|
|
225
|
+
protected readonly nextLabel: _angular_core.Signal<string>;
|
|
226
|
+
protected readonly allDayLabel: _angular_core.Signal<string>;
|
|
227
|
+
protected readonly timeLabel: _angular_core.Signal<string>;
|
|
228
228
|
protected readonly moreLabel: (params?: ngwr_i18n.WrI18nParams) => string;
|
|
229
|
-
|
|
229
|
+
private readonly monthLabel;
|
|
230
|
+
private readonly weekLabel;
|
|
231
|
+
private readonly dayLabel;
|
|
232
|
+
protected readonly viewLabels: _angular_core.Signal<Record<WrCalendarView, string>>;
|
|
230
233
|
/** Accessible name of the grid; overridable for a page with several. */
|
|
231
234
|
readonly ariaLabel: _angular_core.InputSignal<string | null>;
|
|
232
235
|
protected readonly resolvedAriaLabel: _angular_core.Signal<string>;
|
|
@@ -0,0 +1,186 @@
|
|
|
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-falling-text>` a harness query matches. */
|
|
11
|
+
interface WrFallingTextHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/**
|
|
13
|
+
* Match the rendered sentence — the only thing that tells two of these apart, the
|
|
14
|
+
* component having no name, id or role of its own. A string is an exact match, a
|
|
15
|
+
* RegExp is tested.
|
|
16
|
+
*
|
|
17
|
+
* Compared against `WrFallingTextHarness.getText()`, so the non-breaking spaces the
|
|
18
|
+
* component types between the words are already back to plain ones: pass the sentence
|
|
19
|
+
* as it was written.
|
|
20
|
+
*/
|
|
21
|
+
readonly text?: string | RegExp;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @license
|
|
26
|
+
*
|
|
27
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
28
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Test harness for `<wr-falling-text>`.
|
|
33
|
+
*
|
|
34
|
+
* **The assertion that matters here is that the animation did not eat the text.** The
|
|
35
|
+
* component cuts the sentence into one span per word so a physics loop can throw them
|
|
36
|
+
* around, and {@link getText} is the check that a screen reader still gets prose out of
|
|
37
|
+
* the other end. It normalises whitespace on the way, because the separators are real
|
|
38
|
+
* ` ` characters rather than plain spaces — so `textContent` is never byte-identical
|
|
39
|
+
* to the `[text]` input, and a spec comparing the two raw would fail on a component that
|
|
40
|
+
* works perfectly.
|
|
41
|
+
*
|
|
42
|
+
* The rest of the readable surface is the split itself: {@link getWords} pins the rule
|
|
43
|
+
* (split on spaces, empty tokens dropped) and {@link getHighlightedWords} pins the
|
|
44
|
+
* prefix match, which is genuine logic — `grav` highlights `gravity`, and a whole-word
|
|
45
|
+
* implementation would satisfy every naive test but not this one.
|
|
46
|
+
*
|
|
47
|
+
* **Nothing positional is offered, and that is not a jsdom concession.** The words'
|
|
48
|
+
* `transform` values are one frame of a loop that never stops, seeded by `Math.random()`,
|
|
49
|
+
* so they are not reproducible even in a real browser; there is no rest state to call
|
|
50
|
+
* settled; the drag path needs `setPointerCapture` and AABB hit-testing over boxes that
|
|
51
|
+
* a unit test measures as 0×0 at the origin, where every word contains every point. Nor
|
|
52
|
+
* is `[gravity]` or `[trigger]` readable — neither reaches the DOM, and answering them
|
|
53
|
+
* would mean reaching into the component instance. There is no `isReducedMotion()`
|
|
54
|
+
* either: under reduced motion the component simply returns before touching anything, so
|
|
55
|
+
* the only honest proxy is {@link hasReleased}, which reports what it did rather than
|
|
56
|
+
* what it was told.
|
|
57
|
+
*
|
|
58
|
+
* **{@link hasReleased} and {@link release} have a precondition, and without it they are
|
|
59
|
+
* worthless.** The simulator measures the host and each word before it starts, and bails
|
|
60
|
+
* on a zero-sized box — which is every box in a test with no layout. So the spec has to
|
|
61
|
+
* give them one, and it has to do it BEFORE the trigger fires: the component marks itself
|
|
62
|
+
* started on the way past that guard, and the trigger listener is `{ once: true }`, so a
|
|
63
|
+
* failed first attempt is permanent.
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* // In your spec, on a fixture mounted with trigger="click", before calling release():
|
|
67
|
+
* const box = { width: 300, height: 120, left: 0, top: 0, right: 300, bottom: 120 } as DOMRect;
|
|
68
|
+
* for (const el of fixture.nativeElement.querySelectorAll('wr-falling-text, .wr-falling-text__word')) {
|
|
69
|
+
* el.getBoundingClientRect = () => box;
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* Assert `hasReleased()` is `true` in that control case before you assert it is `false`
|
|
74
|
+
* anywhere else, or a spec proves only that the guard fired.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const loader = TestbedHarnessEnvironment.loader(fixture);
|
|
79
|
+
* const text = await loader.getHarness(WrFallingTextHarness);
|
|
80
|
+
*
|
|
81
|
+
* expect(await text.getText()).toBe('gravity pulls every word down');
|
|
82
|
+
* expect(await text.getHighlightedWords()).toEqual(['gravity']);
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @see https://ngwr.dev/guides/testing
|
|
86
|
+
*/
|
|
87
|
+
declare class WrFallingTextHarness extends ComponentHarness {
|
|
88
|
+
static hostSelector: string;
|
|
89
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
90
|
+
static with(options?: WrFallingTextHarnessFilters): HarnessPredicate<WrFallingTextHarness>;
|
|
91
|
+
private readonly wordEls;
|
|
92
|
+
/**
|
|
93
|
+
* The whole sentence, as a screen reader reads it: whitespace collapsed and trimmed.
|
|
94
|
+
*
|
|
95
|
+
* The one assertion worth making about a component that dismantles a paragraph. The
|
|
96
|
+
* words are separated by `.wr-falling-text__space` spans holding U+00A0, so this
|
|
97
|
+
* collapses them back to ordinary spaces — losing those spans would be invisible to
|
|
98
|
+
* every other check here while turning the announcement into one run-on word.
|
|
99
|
+
*
|
|
100
|
+
* DOM order never changes once the physics starts. The words are absolutely positioned
|
|
101
|
+
* and scattered on screen, but they are still read in the order they were typeset, so
|
|
102
|
+
* this answers the same before and after {@link release}.
|
|
103
|
+
*/
|
|
104
|
+
getText(): Promise<string>;
|
|
105
|
+
/**
|
|
106
|
+
* Each word, in DOM order.
|
|
107
|
+
*
|
|
108
|
+
* Pins the split rule: on a literal space, with empty tokens dropped. Each of these is
|
|
109
|
+
* also one body in the simulator, so the length is the body count — which is why there
|
|
110
|
+
* is no separate `getWordCount()`, a method that would invite asserting how many
|
|
111
|
+
* without asserting which.
|
|
112
|
+
*/
|
|
113
|
+
getWords(): Promise<string[]>;
|
|
114
|
+
/**
|
|
115
|
+
* The words carrying the highlight, in DOM order.
|
|
116
|
+
*
|
|
117
|
+
* `[highlightWords]` is matched as a PREFIX and case-sensitively, so `['grav']` picks
|
|
118
|
+
* up `gravity` and `['Grav']` picks up nothing. The highlight is colour alone with no
|
|
119
|
+
* non-visual counterpart, which is acceptable only because it adds no meaning the
|
|
120
|
+
* sentence does not already carry.
|
|
121
|
+
*/
|
|
122
|
+
getHighlightedWords(): Promise<string[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Whether one word is highlighted — for asserting a keyword without depending on the
|
|
125
|
+
* order or the completeness of the whole list.
|
|
126
|
+
*
|
|
127
|
+
* Takes the word as it is rendered, not the keyword that matched it: ask for `gravity`,
|
|
128
|
+
* not for `grav`. Throws for a word the sentence does not contain, since `false` there
|
|
129
|
+
* would read as "present and not highlighted" and quietly survive a typo. A word that
|
|
130
|
+
* appears twice is answered once, which is safe — matching is on the text alone, so
|
|
131
|
+
* both copies always agree.
|
|
132
|
+
*/
|
|
133
|
+
isHighlighted(word: string): Promise<boolean>;
|
|
134
|
+
/**
|
|
135
|
+
* The font size as the consumer wrote it — `'2rem'`, not `'32px'`.
|
|
136
|
+
*
|
|
137
|
+
* Read off the inline `style` attribute rather than through `getCssValue()`. The two
|
|
138
|
+
* agree here and would part company in a real browser, which resolves `font-size` to
|
|
139
|
+
* pixels; `[fontSize]` takes a CSS length and handing back a different unit than the
|
|
140
|
+
* one that went in is the sort of green unit test that hides a broken assertion.
|
|
141
|
+
*
|
|
142
|
+
* Throws when nothing is written, which takes an empty `[fontSize]` — the component
|
|
143
|
+
* writes this on every render otherwise, default included.
|
|
144
|
+
*/
|
|
145
|
+
getFontSize(): Promise<string>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether the simulator has taken the words over.
|
|
148
|
+
*
|
|
149
|
+
* Reads the `position: absolute` the component writes onto every word before its first
|
|
150
|
+
* frame — a value it wrote itself, not a measurement, and the only difference in the
|
|
151
|
+
* DOM between "the physics is running" and "the words are still in normal flow". That
|
|
152
|
+
* makes it the way to observe the trigger contract and the reduced-motion escape, since
|
|
153
|
+
* neither leaves anything else behind.
|
|
154
|
+
*
|
|
155
|
+
* **It is `false` by default in a test, for a reason that has nothing to do with the
|
|
156
|
+
* component.** Without layout every box measures 0×0 and the simulator refuses to start
|
|
157
|
+
* — see this class's docs for the stub, and assert a `true` before you trust a `false`.
|
|
158
|
+
*
|
|
159
|
+
* Throws for a component rendering no words at all, where the question does not apply.
|
|
160
|
+
*/
|
|
161
|
+
hasReleased(): Promise<boolean>;
|
|
162
|
+
/**
|
|
163
|
+
* Fire the events a `click` or `hover` trigger is waiting for.
|
|
164
|
+
*
|
|
165
|
+
* Both, because the harness cannot tell which one it is: `[trigger]` never reaches the
|
|
166
|
+
* DOM. The component consumes at most one — its listener is registered `{ once: true }`
|
|
167
|
+
* and the simulator refuses to start twice — so this is safe to call whatever the
|
|
168
|
+
* trigger is, and safe to call again.
|
|
169
|
+
*
|
|
170
|
+
* It does nothing for `auto`, which released on mount, and nothing for `scroll`, which
|
|
171
|
+
* waits on an `IntersectionObserver`: jsdom has none, so a spec has to stub the global
|
|
172
|
+
* and fire the callback itself. Same precondition as {@link hasReleased} — stub the
|
|
173
|
+
* boxes BEFORE calling this, because a start that bails on a zero-sized host still
|
|
174
|
+
* burns the trigger.
|
|
175
|
+
*
|
|
176
|
+
* Both are dispatched as bare events rather than through the harness's `click()` and
|
|
177
|
+
* `hover()` helpers, which would bring a whole pointer sequence with them. Released
|
|
178
|
+
* words listen for `pointerdown` so they can be picked up and thrown, and that handler
|
|
179
|
+
* calls `setPointerCapture` — which a unit environment does not implement, so the
|
|
180
|
+
* realistic version of this method would throw the moment the simulator was running.
|
|
181
|
+
*/
|
|
182
|
+
release(): Promise<void>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export { WrFallingTextHarness };
|
|
186
|
+
export type { WrFallingTextHarnessFilters };
|