ngwr 11.1.0 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/circular-text/styles/_index.scss +11 -0
- package/command-palette/styles/_index.scss +12 -0
- package/fesm2022/ngwr-action-sheet-testing.mjs +313 -0
- package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -0
- package/fesm2022/ngwr-bar-chart-testing.mjs +89 -0
- package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-blur-text-testing.mjs +203 -0
- package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-blur-text.mjs +15 -1
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow-testing.mjs +325 -0
- package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs +95 -0
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar-testing.mjs +368 -0
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -0
- package/fesm2022/ngwr-calendar.mjs +43 -3
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +12 -0
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +8 -0
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text-testing.mjs +230 -0
- package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-circular-text.mjs +2 -2
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker-testing.mjs +432 -0
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -0
- package/fesm2022/ngwr-color-picker.mjs +29 -3
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +25 -5
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs +10 -79
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-decrypt-text-testing.mjs +261 -0
- package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-decrypt-text.mjs +6 -1
- package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart-testing.mjs +93 -0
- package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-drawer.mjs +36 -7
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +32 -2
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar-testing.mjs +446 -0
- package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -0
- package/fesm2022/ngwr-event-calendar.mjs +43 -18
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text-testing.mjs +218 -0
- package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-fuzzy-text-testing.mjs +134 -0
- package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-gauge-testing.mjs +86 -0
- package/fesm2022/ngwr-gauge-testing.mjs.map +1 -0
- package/fesm2022/ngwr-glitch-text-testing.mjs +181 -0
- package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-gradient-text-testing.mjs +223 -0
- package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-i18n-en.mjs +14 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +14 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper-testing.mjs +156 -0
- package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -0
- package/fesm2022/ngwr-image-cropper.mjs +10 -3
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +73 -6
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-knob-testing.mjs +220 -0
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -0
- package/fesm2022/ngwr-lightbox-testing.mjs +223 -0
- package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -0
- package/fesm2022/ngwr-lightbox.mjs +9 -2
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart-testing.mjs +119 -0
- package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -0
- package/fesm2022/ngwr-marquee-testing.mjs +336 -0
- package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
- package/fesm2022/ngwr-meter-group-testing.mjs +80 -0
- package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -0
- package/fesm2022/ngwr-overlay.mjs +28 -1
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +14 -0
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text-testing.mjs +220 -0
- package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-rotating-text.mjs +2 -2
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +70 -11
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text-testing.mjs +237 -0
- package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-slider.mjs +44 -6
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline-testing.mjs +76 -0
- package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -0
- package/fesm2022/ngwr-speed-dial-testing.mjs +279 -0
- package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -0
- package/fesm2022/ngwr-splash-cursor-testing.mjs +89 -0
- package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -0
- package/fesm2022/ngwr-split-text-testing.mjs +224 -0
- package/fesm2022/ngwr-split-text-testing.mjs.map +1 -0
- package/fesm2022/ngwr-split-text.mjs +15 -1
- package/fesm2022/ngwr-split-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter-testing.mjs +245 -0
- package/fesm2022/ngwr-splitter-testing.mjs.map +1 -0
- package/fesm2022/ngwr-spotlight-card-testing.mjs +368 -0
- package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -0
- package/fesm2022/ngwr-star-border-testing.mjs +172 -0
- package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
- package/fesm2022/ngwr-table.mjs +13 -3
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +15 -1
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card-testing.mjs +190 -0
- package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tilt-card.mjs +19 -1
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-toast.mjs +36 -7
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-tour-testing.mjs +173 -0
- package/fesm2022/ngwr-tour-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tour.mjs +2 -2
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +10 -3
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter-testing.mjs +228 -0
- package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -0
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-waves-testing.mjs +128 -0
- package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
- package/fesm2022/ngwr-window-testing.mjs +361 -0
- package/fesm2022/ngwr-window-testing.mjs.map +1 -0
- package/fesm2022/ngwr-window.mjs +84 -10
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/i18n/en.json +16 -2
- package/i18n/ru.json +16 -2
- package/llms-full.txt +147 -0
- package/llms.txt +27 -8
- package/mcp/providers.js +29 -0
- package/mcp/tools.js +1 -29
- package/package.json +145 -1
- package/skills/ngwr/SKILL.md +115 -0
- package/skills/ngwr/references/catalog.md +212 -0
- package/skills/ngwr/references/setup.md +73 -0
- package/types/ngwr-action-sheet-testing.d.ts +260 -0
- package/types/ngwr-bar-chart-testing.d.ts +77 -0
- package/types/ngwr-blur-text-testing.d.ts +180 -0
- package/types/ngwr-blur-text.d.ts +12 -0
- package/types/ngwr-border-glow-testing.d.ts +219 -0
- package/types/ngwr-calendar-heatmap-testing.d.ts +79 -0
- package/types/ngwr-calendar-testing.d.ts +277 -0
- package/types/ngwr-calendar.d.ts +10 -0
- package/types/ngwr-checkbox.d.ts +13 -0
- package/types/ngwr-circular-text-testing.d.ts +196 -0
- package/types/ngwr-color-picker-testing.d.ts +291 -0
- package/types/ngwr-color-picker.d.ts +13 -1
- package/types/ngwr-context-menu.d.ts +15 -1
- package/types/ngwr-date-picker-testing.d.ts +6 -66
- package/types/ngwr-decrypt-text-testing.d.ts +222 -0
- package/types/ngwr-donut-chart-testing.d.ts +79 -0
- package/types/ngwr-drawer.d.ts +12 -0
- package/types/ngwr-dropdown.d.ts +9 -0
- package/types/ngwr-event-calendar-testing.d.ts +301 -0
- package/types/ngwr-event-calendar.d.ts +9 -6
- package/types/ngwr-falling-text-testing.d.ts +186 -0
- package/types/ngwr-fuzzy-text-testing.d.ts +130 -0
- package/types/ngwr-gauge-testing.d.ts +71 -0
- package/types/ngwr-glitch-text-testing.d.ts +172 -0
- package/types/ngwr-gradient-text-testing.d.ts +173 -0
- package/types/ngwr-image-cropper-testing.d.ts +134 -0
- package/types/ngwr-image-cropper.d.ts +1 -0
- package/types/ngwr-input-number.d.ts +33 -1
- package/types/ngwr-knob-testing.d.ts +150 -0
- package/types/ngwr-lightbox-testing.d.ts +154 -0
- package/types/ngwr-lightbox.d.ts +6 -0
- package/types/ngwr-line-chart-testing.d.ts +93 -0
- package/types/ngwr-marquee-testing.d.ts +280 -0
- package/types/ngwr-meter-group-testing.d.ts +67 -0
- package/types/ngwr-overlay.d.ts +19 -1
- package/types/ngwr-rotating-text-testing.d.ts +191 -0
- package/types/ngwr-select.d.ts +32 -0
- package/types/ngwr-shiny-text-testing.d.ts +165 -0
- package/types/ngwr-slider.d.ts +15 -0
- package/types/ngwr-sparkline-testing.d.ts +69 -0
- package/types/ngwr-speed-dial-testing.d.ts +195 -0
- package/types/ngwr-splash-cursor-testing.d.ts +95 -0
- package/types/ngwr-split-text-testing.d.ts +209 -0
- package/types/ngwr-split-text.d.ts +12 -0
- package/types/ngwr-splitter-testing.d.ts +174 -0
- package/types/ngwr-spotlight-card-testing.d.ts +303 -0
- package/types/ngwr-star-border-testing.d.ts +135 -0
- package/types/ngwr-table.d.ts +10 -1
- package/types/ngwr-tilt-card-testing.d.ts +158 -0
- package/types/ngwr-tilt-card.d.ts +2 -0
- package/types/ngwr-toast.d.ts +14 -5
- package/types/ngwr-tour-testing.d.ts +143 -0
- package/types/ngwr-tree.d.ts +7 -0
- package/types/ngwr-typewriter-testing.d.ts +201 -0
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-waves-testing.d.ts +121 -0
- package/types/ngwr-window-testing.d.ts +263 -0
- package/types/ngwr-window.d.ts +27 -10
- package/window/styles/_index.scss +44 -16
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Setting up ngwr
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
ng add ngwr
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Prompts for styles, date adapter, density and theme, installs the peers, and
|
|
10
|
+
prints a bootstrap snippet tailored to the answers.
|
|
11
|
+
|
|
12
|
+
## Bootstrap
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { provideWrTheme } from 'ngwr/theme';
|
|
16
|
+
import { provideWrOverlay } from 'ngwr/overlay';
|
|
17
|
+
import { provideWrIcons } from 'ngwr/icon';
|
|
18
|
+
import { lucideIcons } from 'ngwr/icon/adapters/lucide';
|
|
19
|
+
|
|
20
|
+
bootstrapApplication(App, {
|
|
21
|
+
providers: [
|
|
22
|
+
provideZonelessChangeDetection(),
|
|
23
|
+
provideWrTheme(),
|
|
24
|
+
provideWrOverlay(),
|
|
25
|
+
provideWrIcons(lucideIcons({ check, chevronDown })),
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`provideWrOverlay()` gives ngwr its OWN CDK overlay container, which is what
|
|
31
|
+
keeps it from colliding with Material or NG-ZORRO in the same app. It also
|
|
32
|
+
installs `WrVisualViewport`, which publishes `--wr-keyboard-inset`.
|
|
33
|
+
|
|
34
|
+
## Styles
|
|
35
|
+
|
|
36
|
+
```scss
|
|
37
|
+
@use 'ngwr'; // everything
|
|
38
|
+
@use 'ngwr/button'; // or one entry point at a time
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Resolved through the `sass` condition in the package's `exports` map. Entry
|
|
42
|
+
points that ship no stylesheet (the `/testing` harnesses, `ngwr/utils`) have no
|
|
43
|
+
`@use` target — importing one fails the build.
|
|
44
|
+
|
|
45
|
+
## Providers with no default
|
|
46
|
+
|
|
47
|
+
### `provideWrOverlay() // from 'ngwr/overlay'`
|
|
48
|
+
|
|
49
|
+
Overlays render into an ngwr-owned container; without it they never appear. Needed by `WrDialog`, `WrDrawer`, `WrToast`, `WrPopover`, `WrPopconfirm`, `WrContextMenu`, `WrSelect`, `WrDropdown`, `WrCommandPalette`, `WrCascader`, `WrMention`, `WrDatePicker`, `WrTour`, `WrLightbox`.
|
|
50
|
+
|
|
51
|
+
### `provideWrIcons(lucideIcons({ … })) // from 'ngwr/icon' + 'ngwr/icon/adapters/lucide'`
|
|
52
|
+
|
|
53
|
+
Icons resolve by name from a registry you populate. Needed by `WrIcon`.
|
|
54
|
+
|
|
55
|
+
### `provideWrDateAdapter(wrDateFnsAdapter) // from 'ngwr/date-adapter-fns'`
|
|
56
|
+
|
|
57
|
+
Every date mode goes through an adapter; there is no built-in default. Needed by `WrDatePicker`, `WrCalendar`, `WrEventCalendar`.
|
|
58
|
+
|
|
59
|
+
### `provideWrI18n() + provideWrI18nStaticLoader({ en: wrEn }) // from 'ngwr/i18n'`
|
|
60
|
+
|
|
61
|
+
The pipe and directive read from a catalog you provide. Needed by `WrT`, `WrI18n`.
|
|
62
|
+
|
|
63
|
+
## Optional, app-wide
|
|
64
|
+
|
|
65
|
+
- `provideWrConfig({ button: { size: 'sm' } })` — component defaults. A bound
|
|
66
|
+
value always wins, including a bound `false` over a configured `true`.
|
|
67
|
+
- `provideWrDensity('sm' | 'md' | 'lg' | 'touch')` — one control size for the
|
|
68
|
+
whole app; `touch` enlarges every hit area at once.
|
|
69
|
+
- `provideWrResponsiveOverlays()` — overlays present as bottom sheets under the
|
|
70
|
+
breakpoint (640px by default). Per-component opt-out with `[responsive]="false"`.
|
|
71
|
+
- `provideWrFormErrors({ … })` — one place for validation copy; `<wr-form-field>`
|
|
72
|
+
resolves a message per error key through it, then the i18n catalog, then a
|
|
73
|
+
built-in fallback.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
|
|
2
|
+
import { WrActionSheetAction } from 'ngwr/action-sheet';
|
|
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 open `<wr-action-sheet>` a harness query matches. */
|
|
12
|
+
interface WrActionSheetHarnessFilters extends BaseHarnessFilters {
|
|
13
|
+
/**
|
|
14
|
+
* Match the sheet's VISIBLE heading — a string is an exact match, a RegExp is
|
|
15
|
+
* tested. A sheet with no `title` has none and matches nothing here; filter on
|
|
16
|
+
* `accessibleName` to reach one by the name it announces instead.
|
|
17
|
+
*/
|
|
18
|
+
readonly title?: string | RegExp;
|
|
19
|
+
/** Match the muted sub-heading under the title. */
|
|
20
|
+
readonly message?: string | RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* Match the name the dialog announces — the visible title when there is one, and
|
|
23
|
+
* otherwise the screen-reader-only fallback, which is the only name an untitled
|
|
24
|
+
* sheet has.
|
|
25
|
+
*/
|
|
26
|
+
readonly accessibleName?: string | RegExp;
|
|
27
|
+
}
|
|
28
|
+
/** Narrows which row inside an action sheet a harness query matches. */
|
|
29
|
+
interface WrActionSheetActionHarnessFilters extends BaseHarnessFilters {
|
|
30
|
+
/** Match the row's label — a string is an exact match, a RegExp is tested. */
|
|
31
|
+
readonly label?: string | RegExp;
|
|
32
|
+
/**
|
|
33
|
+
* Match the row's visual role. `default` covers every row the caller left
|
|
34
|
+
* unroled, which is what the component itself does with the value.
|
|
35
|
+
*/
|
|
36
|
+
readonly role?: NonNullable<WrActionSheetAction['role']>;
|
|
37
|
+
/** Match only enabled (`false`) or only disabled (`true`) rows. */
|
|
38
|
+
readonly disabled?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @license
|
|
43
|
+
*
|
|
44
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
45
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Test harness for one row inside a {@link WrActionSheetHarness}.
|
|
50
|
+
*
|
|
51
|
+
* A row is a real `<button>`, not an ARIA-decorated div, so `disabled` is the
|
|
52
|
+
* property rather than an attribute and the CDK refuses to click it — which is the
|
|
53
|
+
* behaviour a spec wants asserted, since the component ALSO checks `disabled`
|
|
54
|
+
* inside its own handler. Either guard alone would keep a disabled row inert; both
|
|
55
|
+
* being there means removing one is invisible until the other is removed too, and
|
|
56
|
+
* {@link click} is where that shows up.
|
|
57
|
+
*
|
|
58
|
+
* **Clicking a row closes the sheet.** The component emits `action` and clears
|
|
59
|
+
* `open` in the same call, so a harness held across a {@link click} is pointed at a
|
|
60
|
+
* detached element the moment it returns — read what you need first, and get a
|
|
61
|
+
* fresh harness afterwards if the sheet was reopened.
|
|
62
|
+
*
|
|
63
|
+
* @see https://ngwr.dev/guides/testing
|
|
64
|
+
*/
|
|
65
|
+
declare class WrActionSheetActionHarness extends ComponentHarness {
|
|
66
|
+
/** The class every row carries, cancel rows included. */
|
|
67
|
+
static hostSelector: string;
|
|
68
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
69
|
+
static with(options?: WrActionSheetActionHarnessFilters): HarnessPredicate<WrActionSheetActionHarness>;
|
|
70
|
+
/**
|
|
71
|
+
* The row's label, trimmed.
|
|
72
|
+
*
|
|
73
|
+
* Read from `.wr-action-sheet__label` rather than from the button, so a leading
|
|
74
|
+
* icon can never join it. The icon contributes no text today — it is an `<svg>` —
|
|
75
|
+
* but an icon set that ships a `<title>` for its own accessibility would, and the
|
|
76
|
+
* label element is the thing that actually holds the string.
|
|
77
|
+
*/
|
|
78
|
+
getLabel(): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* The row's visual role, as the component painted it.
|
|
81
|
+
*
|
|
82
|
+
* `default` is returned for a row the caller left unroled, which is what the
|
|
83
|
+
* component does with the value: only `destructive` and `cancel` change anything,
|
|
84
|
+
* and everything else falls through to the plain row. The two modifiers are
|
|
85
|
+
* mutually exclusive by construction — `cancel` rows are filtered into their own
|
|
86
|
+
* group before the destructive class is ever considered — so reading them in
|
|
87
|
+
* either order gives the same answer.
|
|
88
|
+
*/
|
|
89
|
+
getRole(): Promise<NonNullable<WrActionSheetAction['role']>>;
|
|
90
|
+
/**
|
|
91
|
+
* Whether the row refuses interaction, from the button's own `disabled` property
|
|
92
|
+
* — the thing the CDK consults before dispatching a click, and the DOM before
|
|
93
|
+
* delivering one.
|
|
94
|
+
*
|
|
95
|
+
* There is no `aria-disabled` to fall back to here, and none is wanted: the row is
|
|
96
|
+
* a native button, where the property already carries the state to assistive tech.
|
|
97
|
+
*/
|
|
98
|
+
isDisabled(): Promise<boolean>;
|
|
99
|
+
/** Whether the row draws a leading icon. */
|
|
100
|
+
hasIcon(): Promise<boolean>;
|
|
101
|
+
/**
|
|
102
|
+
* The icon's registered name, or `null` on a row without one.
|
|
103
|
+
*
|
|
104
|
+
* From `wr-icon`'s reflected `data-icon`, which is the only place the name reaches
|
|
105
|
+
* the DOM — the rendered `<svg>` carries no trace of which entry of the set it
|
|
106
|
+
* came from.
|
|
107
|
+
*/
|
|
108
|
+
getIconName(): Promise<string | null>;
|
|
109
|
+
/**
|
|
110
|
+
* Pick this row — emitting `action` and closing the sheet.
|
|
111
|
+
*
|
|
112
|
+
* Throws on a disabled row instead of quietly doing nothing. The click would not
|
|
113
|
+
* land anyway (the DOM swallows it), so the alternative is a spec that reads as
|
|
114
|
+
* "picked the row" and asserts a sheet that never moved.
|
|
115
|
+
*/
|
|
116
|
+
click(): Promise<void>;
|
|
117
|
+
/** Move keyboard focus to the row. */
|
|
118
|
+
focus(): Promise<void>;
|
|
119
|
+
/** Whether the row currently holds focus. */
|
|
120
|
+
isFocused(): Promise<boolean>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @license
|
|
125
|
+
*
|
|
126
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
127
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Test harness for an open `<wr-action-sheet>` — the iOS-style bottom sheet of
|
|
132
|
+
* choices.
|
|
133
|
+
*
|
|
134
|
+
* The sheet renders through `<wr-drawer>`, so its rows are in the NGWR overlay
|
|
135
|
+
* container rather than in the fixture: load this from
|
|
136
|
+
* `TestbedHarnessEnvironment.documentRootLoader()`. A fixture-scoped loader finds
|
|
137
|
+
* nothing at all — the `<wr-action-sheet>` host element itself holds no content and
|
|
138
|
+
* the drawer it wraps is `display: none`.
|
|
139
|
+
*
|
|
140
|
+
* The anchor is `.wr-action-sheet`, the sheet's own root inside the drawer panel,
|
|
141
|
+
* which makes each instance self-scoping: two sheets open at once are two hosts, and
|
|
142
|
+
* every query here descends from one of them. That is worth stating because it is
|
|
143
|
+
* NOT how the drawer harness underneath has to work — a drawer publishes no link to
|
|
144
|
+
* the overlay it opened, so `WrDrawerHarness` anchors on the shared pane and scopes
|
|
145
|
+
* by id.
|
|
146
|
+
*
|
|
147
|
+
* **What belongs to the drawer, not here.** Dismissal by backdrop click or by the ✕
|
|
148
|
+
* button, the modal role, the focus trap and the panel's position are all the
|
|
149
|
+
* drawer's surface, and `WrDrawerHarness` from the same root loader answers them.
|
|
150
|
+
* {@link sendEscape} is the one exception, kept because dismissing without choosing
|
|
151
|
+
* is a documented behaviour of the sheet itself: it closes and emits NOTHING, which
|
|
152
|
+
* is the assertion most specs are actually after.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
|
|
157
|
+
* const sheet = await rootLoader.getHarness(WrActionSheetHarness);
|
|
158
|
+
*
|
|
159
|
+
* expect(await sheet.getActionLabels()).toEqual(['Take Photo', 'Delete', 'Cancel']);
|
|
160
|
+
* await sheet.select({ label: 'Delete' });
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @see https://ngwr.dev/guides/testing
|
|
164
|
+
*/
|
|
165
|
+
declare class WrActionSheetHarness extends ComponentHarness {
|
|
166
|
+
/** The sheet's root inside the drawer panel. A closed sheet renders none. */
|
|
167
|
+
static hostSelector: string;
|
|
168
|
+
/** Build a predicate that narrows the query — sheets can be stacked. */
|
|
169
|
+
static with(options?: WrActionSheetHarnessFilters): HarnessPredicate<WrActionSheetHarness>;
|
|
170
|
+
/**
|
|
171
|
+
* Whether this sheet is still open.
|
|
172
|
+
*
|
|
173
|
+
* A harness can only be obtained while the sheet is open — closing disposes the
|
|
174
|
+
* overlay and everything in it — so this is the answer for a harness you are
|
|
175
|
+
* already HOLDING: it flips to `false` after a pick or a dismissal, where a fresh
|
|
176
|
+
* `getHarnessOrNull()` comes back `null`.
|
|
177
|
+
*
|
|
178
|
+
* Attachment is the test rather than a class, because disposal removes the element
|
|
179
|
+
* without changing anything on it.
|
|
180
|
+
*/
|
|
181
|
+
isOpen(): Promise<boolean>;
|
|
182
|
+
/** The visible heading, or `null` when the sheet was opened without a `title`. */
|
|
183
|
+
getTitle(): Promise<string | null>;
|
|
184
|
+
/** The muted sub-heading, or `null` when the sheet has no `message`. */
|
|
185
|
+
getMessage(): Promise<string | null>;
|
|
186
|
+
/**
|
|
187
|
+
* The name the dialog announces.
|
|
188
|
+
*
|
|
189
|
+
* The sheet always publishes one, and for an untitled sheet it is INVISIBLE: the
|
|
190
|
+
* component renders a screen-reader-only `[wrDrawerTitle]` carrying
|
|
191
|
+
* `actionSheet.label` (English default `Actions`), because a bottom sheet is an
|
|
192
|
+
* `aria-modal` dialog and an unnamed one is announced as nothing at all. Nothing
|
|
193
|
+
* on screen changes when that string is wrong or missing, which is exactly why it
|
|
194
|
+
* is worth an assertion.
|
|
195
|
+
*
|
|
196
|
+
* Read from `.wr-drawer__title` — the class the title directive applies — so the
|
|
197
|
+
* one query answers for both shapes: the visible heading carries it too.
|
|
198
|
+
*/
|
|
199
|
+
getAccessibleName(): Promise<string>;
|
|
200
|
+
/** Whether the announced name comes from a visible heading rather than the fallback. */
|
|
201
|
+
isTitleVisible(): Promise<boolean>;
|
|
202
|
+
/**
|
|
203
|
+
* Whether the dialog is actually WIRED to that name — the drawer panel's
|
|
204
|
+
* `aria-labelledby` resolving to this sheet's own title element, and to nothing
|
|
205
|
+
* else on the page.
|
|
206
|
+
*
|
|
207
|
+
* {@link getAccessibleName} only proves a string exists in the markup; a screen
|
|
208
|
+
* reader reads it only if the reference points at it. The two are separate
|
|
209
|
+
* failures and the second is silent: the title renders, the sheet looks right, and
|
|
210
|
+
* the dialog is announced as unnamed. Worth its own assertion because the drawer
|
|
211
|
+
* resolves the reference AFTER attaching the panel rather than while rendering it,
|
|
212
|
+
* so a title that arrives late is named late or not at all.
|
|
213
|
+
*
|
|
214
|
+
* Counted across the document as well, because two panels answering to one id hand
|
|
215
|
+
* every reference to whichever comes first — which is how a second sheet ends up
|
|
216
|
+
* announcing the first one's title.
|
|
217
|
+
*/
|
|
218
|
+
isNamed(): Promise<boolean>;
|
|
219
|
+
/** The rows this sheet offers, in DOM order — cancel rows last, in their own group. */
|
|
220
|
+
getActions(filters?: WrActionSheetActionHarnessFilters): Promise<WrActionSheetActionHarness[]>;
|
|
221
|
+
/** The labels of every row, in DOM order. */
|
|
222
|
+
getActionLabels(): Promise<string[]>;
|
|
223
|
+
/**
|
|
224
|
+
* The labels grouped the way the sheet lays them out: the main group first, then
|
|
225
|
+
* the cancel group when there is one.
|
|
226
|
+
*
|
|
227
|
+
* The grouping is the component's whole visual contract — a `cancel` row is pulled
|
|
228
|
+
* out of the list and pinned to the bottom with a gap above it — and it is
|
|
229
|
+
* invisible to {@link getActionLabels}, which flattens the two. A cancel row that
|
|
230
|
+
* stopped being separated would still come last in DOM order, so the flat list
|
|
231
|
+
* cannot catch it.
|
|
232
|
+
*/
|
|
233
|
+
getActionGroups(): Promise<string[][]>;
|
|
234
|
+
/**
|
|
235
|
+
* Whether the sheet drew a separate bottom group — true exactly when at least one
|
|
236
|
+
* row was given `role: 'cancel'`, since the component omits the group entirely
|
|
237
|
+
* rather than rendering an empty one.
|
|
238
|
+
*/
|
|
239
|
+
hasCancelGroup(): Promise<boolean>;
|
|
240
|
+
/**
|
|
241
|
+
* Pick the first row matching the filters.
|
|
242
|
+
*
|
|
243
|
+
* Throws when nothing matches, naming what the sheet does offer — the alternative
|
|
244
|
+
* is a silent no-op followed by an assertion about a sheet that never moved. A
|
|
245
|
+
* disabled match throws too, from the row harness.
|
|
246
|
+
*/
|
|
247
|
+
select(filters: WrActionSheetActionHarnessFilters): Promise<void>;
|
|
248
|
+
/**
|
|
249
|
+
* Press Escape — dismissing the sheet WITHOUT emitting `action`.
|
|
250
|
+
*
|
|
251
|
+
* The key never needs to reach the sheet itself: the drawer underneath listens
|
|
252
|
+
* through the CDK's keyboard dispatcher, which keeps one document listener and
|
|
253
|
+
* hands the event to the top-most overlay. So with sheets stacked this dismisses
|
|
254
|
+
* the top one whichever harness it is called on.
|
|
255
|
+
*/
|
|
256
|
+
sendEscape(): Promise<void>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export { WrActionSheetActionHarness, WrActionSheetHarness };
|
|
260
|
+
export type { WrActionSheetActionHarnessFilters, WrActionSheetHarnessFilters };
|
|
@@ -0,0 +1,77 @@
|
|
|
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-bar-chart>` a harness query matches. */
|
|
11
|
+
interface WrBarChartHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match a chart holding a bar with this label. */
|
|
13
|
+
readonly barLabel?: string | RegExp;
|
|
14
|
+
}
|
|
15
|
+
/** One column, as the chart draws and announces it. */
|
|
16
|
+
interface WrBarChartBar {
|
|
17
|
+
/** The label printed under the column — decoration, and `aria-hidden`. */
|
|
18
|
+
readonly label: string;
|
|
19
|
+
/** The value printed above it, or `null` when `showValues` is off. */
|
|
20
|
+
readonly value: string | null;
|
|
21
|
+
/** What the column announces: the label and the value in one string. */
|
|
22
|
+
readonly name: string | null;
|
|
23
|
+
/** The bar's height as a percentage of the chart's maximum. */
|
|
24
|
+
readonly heightPercent: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @license
|
|
29
|
+
*
|
|
30
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
31
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Test harness for `<wr-bar-chart>`.
|
|
36
|
+
*
|
|
37
|
+
* **The bars are read as PERCENTAGES, not as pixels.** Each column's height is
|
|
38
|
+
* written inline as a share of the chart's maximum, which is the one number that
|
|
39
|
+
* survives a test with no layout — and it is also the component's whole job, since
|
|
40
|
+
* the maximum is either given or derived from the data.
|
|
41
|
+
*
|
|
42
|
+
* **The visible label row is decoration.** Every column carries `role="img"` with
|
|
43
|
+
* the label AND the value in its name, and the printed labels underneath are
|
|
44
|
+
* `aria-hidden` — so {@link WrBarChartBar.name} is what a screen reader gets and
|
|
45
|
+
* {@link WrBarChartBar.label} is what is drawn. Asserting only the second would pass
|
|
46
|
+
* on a chart that announces nothing.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const chart = await loader.getHarness(WrBarChartHarness);
|
|
51
|
+
*
|
|
52
|
+
* expect(await chart.getLabels()).toEqual(['Mon', 'Tue', 'Wed']);
|
|
53
|
+
* expect((await chart.getBars())[1].heightPercent).toBe(100);
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @see https://ngwr.dev/guides/testing
|
|
57
|
+
*/
|
|
58
|
+
declare class WrBarChartHarness extends ComponentHarness {
|
|
59
|
+
static hostSelector: string;
|
|
60
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
61
|
+
static with(options?: WrBarChartHarnessFilters): HarnessPredicate<WrBarChartHarness>;
|
|
62
|
+
/** Every column, in data order. */
|
|
63
|
+
getBars(): Promise<WrBarChartBar[]>;
|
|
64
|
+
/** The labels printed under the columns, in order. */
|
|
65
|
+
getLabels(): Promise<string[]>;
|
|
66
|
+
/** What each column announces — the label and the value together. */
|
|
67
|
+
getAccessibleNames(): Promise<(string | null)[]>;
|
|
68
|
+
/** How many columns the chart drew. */
|
|
69
|
+
getBarCount(): Promise<number>;
|
|
70
|
+
/** Whether the values are printed above the bars (`showValues`). */
|
|
71
|
+
hasValues(): Promise<boolean>;
|
|
72
|
+
/** The plot's height in pixels, as the component writes it inline. */
|
|
73
|
+
getPlotHeight(): Promise<number>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { WrBarChartHarness };
|
|
77
|
+
export type { WrBarChartBar, WrBarChartHarnessFilters };
|
|
@@ -0,0 +1,180 @@
|
|
|
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-blur-text>` a harness query matches. */
|
|
11
|
+
interface WrBlurTextHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/**
|
|
13
|
+
* Match the string the component announces — the readable copy, not the pieces.
|
|
14
|
+
* A string is an exact match, a RegExp is tested.
|
|
15
|
+
*
|
|
16
|
+
* Matching on the accessible copy rather than on the host's text is deliberate:
|
|
17
|
+
* the host also holds a span per character, so its text reads back as the string
|
|
18
|
+
* twice over, and a filter written against that would depend on the split.
|
|
19
|
+
*/
|
|
20
|
+
readonly text?: string | RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* Match on how many animated pieces the split produced — one per word, or one per
|
|
23
|
+
* character. The blunt way to tell two otherwise identical reveals apart, and the
|
|
24
|
+
* only number about the animation that is present in the DOM at all.
|
|
25
|
+
*/
|
|
26
|
+
readonly pieceCount?: 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-blur-text>`.
|
|
38
|
+
*
|
|
39
|
+
* **Most of what this component does cannot be read from a test, and the methods that
|
|
40
|
+
* are missing are missing on purpose.** The reveal is a Web Animations tween per piece
|
|
41
|
+
* — blur, vertical offset and opacity, staggered — started by an `IntersectionObserver`.
|
|
42
|
+
* A unit test has no layout, no compositor and no WAAPI, so there is no
|
|
43
|
+
* `getOpacity()`, no `getBlurRadius()` and no `getOffset()`: each would report the
|
|
44
|
+
* staged from-state forever in jsdom, and in a real browser it would report the inline
|
|
45
|
+
* value while the compositor paints a different one. There is no `isAnimating()` and no
|
|
46
|
+
* `whenAnimationComplete()` either — nothing in the DOM says a tween is running, and
|
|
47
|
+
* completion is the `animationComplete` OUTPUT, which the host binds. Nor is there an
|
|
48
|
+
* `enterViewport()` / `scrollIntoView()`: the trigger is an observer, which a
|
|
49
|
+
* `TestElement` cannot reach, and a method that pretended to scroll would do nothing in
|
|
50
|
+
* jsdom and something untimed in a browser. The inputs that shape the tween —
|
|
51
|
+
* `direction`, `delay`, `stepDuration`, `easing` — never reach the DOM at all; they live
|
|
52
|
+
* in a keyframe array and an effect timing, and neither is a document.
|
|
53
|
+
*
|
|
54
|
+
* **What is real is the split and the accessible layer, and they are two questions.**
|
|
55
|
+
* The string is carried once in a visually-hidden span, and every animated piece is
|
|
56
|
+
* `aria-hidden` so a screen reader does not spell the text out letter by letter — so
|
|
57
|
+
* {@link getAccessibleText} is what is heard and {@link getPieces} is what is drawn, and
|
|
58
|
+
* a spec that only asserted the second would pass on a component that announces
|
|
59
|
+
* `W. e. l. c. o. m. e.` {@link getRenderedText} closes the loop: the split has to be
|
|
60
|
+
* lossless, and comparing it against the accessible copy is what catches a dropped space
|
|
61
|
+
* or a halved surrogate pair. (Whether the hidden copy is really off-screen is CSS —
|
|
62
|
+
* `clip-path` and a 1px box — and a test running no stylesheets cannot tell a correctly
|
|
63
|
+
* hidden span from one printing the string twice, so nothing here claims to.)
|
|
64
|
+
*
|
|
65
|
+
* **{@link hasStagedMotion} is the one thing about the tween worth pinning**, and it
|
|
66
|
+
* reports that the pieces were taken over rather than that anything is moving. Under
|
|
67
|
+
* reduced motion the component returns before touching them, which is the promise: a
|
|
68
|
+
* reader who asked for less motion must never be left with text staged at `opacity: 0`
|
|
69
|
+
* by an animation that then never runs.
|
|
70
|
+
*
|
|
71
|
+
* Driving the reveal is the spec's job, since jsdom supplies neither half of it:
|
|
72
|
+
*
|
|
73
|
+
* ```ts
|
|
74
|
+
* // Before TestBed.createComponent — keep the callbacks so the spec can fire them.
|
|
75
|
+
* vi.stubGlobal('IntersectionObserver', StubObserver);
|
|
76
|
+
* // Otherwise `el.animate(...)` throws mid-stagger and leaves the DOM half-staged.
|
|
77
|
+
* Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined, onfinish: null }));
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const text = await loader.getHarness(WrBlurTextHarness.with({ text: 'Welcome to ngwr' }));
|
|
83
|
+
*
|
|
84
|
+
* expect(await text.getPieces()).toEqual(['Welcome', 'to', 'ngwr']);
|
|
85
|
+
* expect(await text.getRenderedText()).toBe(await text.getAccessibleText());
|
|
86
|
+
* expect(await text.isTextHidden()).toBe(true);
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @see https://ngwr.dev/guides/testing
|
|
90
|
+
*/
|
|
91
|
+
declare class WrBlurTextHarness extends ComponentHarness {
|
|
92
|
+
static hostSelector: string;
|
|
93
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
94
|
+
static with(options?: WrBlurTextHarnessFilters): HarnessPredicate<WrBlurTextHarness>;
|
|
95
|
+
private readonly pieces;
|
|
96
|
+
private readonly spaces;
|
|
97
|
+
/**
|
|
98
|
+
* The whole string, as the one readable copy holds it.
|
|
99
|
+
*
|
|
100
|
+
* The only thing a screen reader gets, since every drawn piece is out of the tree —
|
|
101
|
+
* lose this span and the component becomes a nameless pile of hidden spans with no
|
|
102
|
+
* other symptom anywhere in the DOM.
|
|
103
|
+
*
|
|
104
|
+
* Untrimmed, deliberately. Leading and trailing whitespace is content the split has to
|
|
105
|
+
* carry through, and {@link getRenderedText} is meant to compare equal to this; a
|
|
106
|
+
* trimmed read on one side of that comparison would quietly forgive the case it exists
|
|
107
|
+
* to catch.
|
|
108
|
+
*/
|
|
109
|
+
getAccessibleText(): Promise<string>;
|
|
110
|
+
/**
|
|
111
|
+
* The animated pieces, in document order — one per word or one per character.
|
|
112
|
+
*
|
|
113
|
+
* This is the split the stagger runs over: `['Hi', 'there']` for `animateBy="words"`
|
|
114
|
+
* against `['H', 'i', 't', 'h', 'e', 'r', 'e']` for `"chars"`, and `['a', '🚀']` for a
|
|
115
|
+
* surrogate pair the code-point split kept whole rather than halved into two broken
|
|
116
|
+
* glyphs. Whitespace is not here — it is rendered separately and never staggered, so
|
|
117
|
+
* see {@link getSpaceCount}.
|
|
118
|
+
*/
|
|
119
|
+
getPieces(): Promise<string[]>;
|
|
120
|
+
/**
|
|
121
|
+
* How many pieces the stagger runs over.
|
|
122
|
+
*
|
|
123
|
+
* `delay` × this is the whole length of the effect, and it is the only number about
|
|
124
|
+
* the animation that exists in the document.
|
|
125
|
+
*/
|
|
126
|
+
getPieceCount(): Promise<number>;
|
|
127
|
+
/**
|
|
128
|
+
* How many whitespace runs sit between the pieces.
|
|
129
|
+
*
|
|
130
|
+
* Worth a method of its own because whitespace is deliberately NOT a staggered piece:
|
|
131
|
+
* a regression that reclassified spaces as pieces would leave {@link getRenderedText}
|
|
132
|
+
* identical, change the stagger count and the rhythm of the reveal, and show up
|
|
133
|
+
* nowhere else.
|
|
134
|
+
*/
|
|
135
|
+
getSpaceCount(): Promise<number>;
|
|
136
|
+
/**
|
|
137
|
+
* Everything the component drew, pieces and spaces together, in document order.
|
|
138
|
+
*
|
|
139
|
+
* The assertion this exists for is `getRenderedText() === getAccessibleText()`: the
|
|
140
|
+
* split must be lossless. A swallowed space, a re-split that dropped a character, or a
|
|
141
|
+
* surrogate pair cut in half all leave the accessible copy untouched and are invisible
|
|
142
|
+
* from anywhere else.
|
|
143
|
+
*/
|
|
144
|
+
getRenderedText(): Promise<string>;
|
|
145
|
+
/**
|
|
146
|
+
* Whether every drawn piece is out of the accessibility tree.
|
|
147
|
+
*
|
|
148
|
+
* The defect this component exists to avoid is a screen reader reading
|
|
149
|
+
* `W. e. l. c. o. m. e.`, and one piece missing `aria-hidden` is enough to bring it
|
|
150
|
+
* back — so this is all-or-nothing, and across both element kinds: a stray readable
|
|
151
|
+
* space is heard as a pause in the middle of a word.
|
|
152
|
+
*
|
|
153
|
+
* Throws when the split produced nothing at all. An empty run of elements satisfies
|
|
154
|
+
* "every one of them is hidden" without anything being hidden, which is the answer a
|
|
155
|
+
* component that stopped rendering its pieces would also give.
|
|
156
|
+
*/
|
|
157
|
+
isTextHidden(): Promise<boolean>;
|
|
158
|
+
/**
|
|
159
|
+
* Whether the reveal has taken the pieces over — NOT whether anything is animating.
|
|
160
|
+
*
|
|
161
|
+
* Read off the inline `style` attribute the component writes itself, so it stays
|
|
162
|
+
* `true` after the reveal finishes: the tween commits its end state back to the same
|
|
163
|
+
* inline properties on `onfinish`. Anyone reaching for `isAnimating()` wants a frame,
|
|
164
|
+
* and there are no frames here.
|
|
165
|
+
*
|
|
166
|
+
* `false` is the answer worth asserting. It means no piece was written to at all,
|
|
167
|
+
* which is both the pre-trigger state and the reduced-motion promise — the component
|
|
168
|
+
* returns before staging anything, so a reader who asked for less motion cannot be
|
|
169
|
+
* left staring at text parked at `opacity: 0` by an animation that never runs.
|
|
170
|
+
*
|
|
171
|
+
* ANY piece counts, not all of them, and that is the conservative reading rather than
|
|
172
|
+
* a loose one: a stagger that stages the first piece and then throws leaves exactly one
|
|
173
|
+
* piece invisible, which is a real failure and one jsdom reproduces whenever
|
|
174
|
+
* `Element.prototype.animate` is missing.
|
|
175
|
+
*/
|
|
176
|
+
hasStagedMotion(): Promise<boolean>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export { WrBlurTextHarness };
|
|
180
|
+
export type { WrBlurTextHarnessFilters };
|
|
@@ -52,6 +52,18 @@ declare class WrBlurText {
|
|
|
52
52
|
private readonly isBrowser;
|
|
53
53
|
private readonly platform;
|
|
54
54
|
private hasAnimated;
|
|
55
|
+
/**
|
|
56
|
+
* The ONE observer, replaced rather than stacked.
|
|
57
|
+
*
|
|
58
|
+
* `startObserver()` used to `new IntersectionObserver(…)` and register its own
|
|
59
|
+
* `destroyRef.onDestroy` every time, and the effect below calls it on every
|
|
60
|
+
* `text` change after setting `hasAnimated = false` — so the guard at the top
|
|
61
|
+
* of `startObserver` never blocked that path. An off-screen element (the only
|
|
62
|
+
* case where the observer does not immediately disconnect itself) therefore
|
|
63
|
+
* leaked one live observer AND one destroy callback per change, all of them
|
|
64
|
+
* watching the same host and all of them able to fire `animate()`.
|
|
65
|
+
*/
|
|
66
|
+
private observer;
|
|
55
67
|
constructor();
|
|
56
68
|
private startObserver;
|
|
57
69
|
private animate;
|