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,134 @@
|
|
|
1
|
+
import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
|
|
2
|
+
import { WrCropHandle } from 'ngwr/image-cropper';
|
|
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-image-cropper>` a harness query matches. */
|
|
12
|
+
interface WrImageCropperHarnessFilters extends BaseHarnessFilters {
|
|
13
|
+
/**
|
|
14
|
+
* Match croppers holding an image (`false`) or showing the empty state (`true`).
|
|
15
|
+
* A cropper with a `src` it has not measured yet is NOT empty — see
|
|
16
|
+
* `WrImageCropperHarness.isReady`.
|
|
17
|
+
*/
|
|
18
|
+
readonly empty?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @license
|
|
23
|
+
*
|
|
24
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/** Where the crop window sits over the DISPLAYED image, in CSS pixels. */
|
|
29
|
+
interface WrCropWindowBox {
|
|
30
|
+
readonly x: number;
|
|
31
|
+
readonly y: number;
|
|
32
|
+
readonly width: number;
|
|
33
|
+
readonly height: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Test harness for `<wr-image-cropper>`.
|
|
37
|
+
*
|
|
38
|
+
* **This is the smallest honest surface of any harness here, and the reason is worth
|
|
39
|
+
* reading before you reach for a method that is not on it.** Almost everything the
|
|
40
|
+
* cropper does is measured: it reads the `<img>`'s rendered box and its
|
|
41
|
+
* `naturalWidth`, converts between display and source pixels, and moves the crop
|
|
42
|
+
* window with pointer deltas. jsdom measures nothing — every rect is 0×0 and
|
|
43
|
+
* `naturalWidth` is 0 — so an image never "loads", the crop UI never renders, and a
|
|
44
|
+
* synthetic drag divides by zero. There is deliberately no `moveCrop()` or
|
|
45
|
+
* `resizeCrop()`: either would write `NaN` and report success.
|
|
46
|
+
*
|
|
47
|
+
* What a spec CAN do is give the image a box and a natural size itself, then call
|
|
48
|
+
* {@link dispatchImageLoad} — the two numbers `onImageLoad` reads are the whole
|
|
49
|
+
* stub, and from there {@link getCropBox} and {@link getHandles} are real answers,
|
|
50
|
+
* because the component writes the crop window's geometry as inline pixels.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* // In your spec, before dispatching the load:
|
|
54
|
+
* const img = fixture.nativeElement.querySelector('.wr-image-cropper__image');
|
|
55
|
+
* img.getBoundingClientRect = () => ({ width: 400, height: 400, x: 0, y: 0 }) as DOMRect;
|
|
56
|
+
* Object.defineProperty(img, 'naturalWidth', { value: 800 });
|
|
57
|
+
* Object.defineProperty(img, 'naturalHeight', { value: 800 });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* **There is also nothing to click.** The cropper renders no buttons: a consumer
|
|
61
|
+
* takes the result by calling `crop()` on the component through a `viewChild`, and
|
|
62
|
+
* reads `cropRect()` the same way. Those are component API rather than DOM, so they
|
|
63
|
+
* are outside what a harness can reach at all — which is worth knowing rather than
|
|
64
|
+
* discovering.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const cropper = await loader.getHarness(WrImageCropperHarness);
|
|
69
|
+
*
|
|
70
|
+
* expect(await cropper.isEmpty()).toBe(false);
|
|
71
|
+
* expect(await cropper.isReady()).toBe(false); // nothing measured yet
|
|
72
|
+
*
|
|
73
|
+
* await cropper.dispatchImageLoad();
|
|
74
|
+
* expect(await cropper.getCropBox()).toEqual({ x: 80, y: 80, width: 240, height: 240 });
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @see https://ngwr.dev/guides/testing
|
|
78
|
+
*/
|
|
79
|
+
declare class WrImageCropperHarness extends ComponentHarness {
|
|
80
|
+
static hostSelector: string;
|
|
81
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
82
|
+
static with(options?: WrImageCropperHarnessFilters): HarnessPredicate<WrImageCropperHarness>;
|
|
83
|
+
private readonly image;
|
|
84
|
+
private readonly cropWindow;
|
|
85
|
+
/** Whether the cropper has no source at all, and is showing its placeholder. */
|
|
86
|
+
isEmpty(): Promise<boolean>;
|
|
87
|
+
/** The placeholder's text, or `null` when there is an image. Comes from the catalog. */
|
|
88
|
+
getEmptyText(): Promise<string | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the crop UI is up.
|
|
91
|
+
*
|
|
92
|
+
* Not the same question as {@link isEmpty}: a cropper with a perfectly good `src`
|
|
93
|
+
* shows nothing but the image until it has been MEASURED, because the window's size
|
|
94
|
+
* is a fraction of the rendered box. In a browser that happens on load; in a unit
|
|
95
|
+
* test it happens when the spec stubs the box and calls
|
|
96
|
+
* {@link dispatchImageLoad}.
|
|
97
|
+
*/
|
|
98
|
+
isReady(): Promise<boolean>;
|
|
99
|
+
/**
|
|
100
|
+
* What the `<img>` is pointing at.
|
|
101
|
+
*
|
|
102
|
+
* A `File` or `Blob` source becomes an object URL, so this is `blob:…` for those
|
|
103
|
+
* and the plain string for a string `src`. Comparing the two is not useful; asking
|
|
104
|
+
* whether it CHANGED is.
|
|
105
|
+
*/
|
|
106
|
+
getImageSrc(): Promise<string | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Fire the image's `load` event.
|
|
109
|
+
*
|
|
110
|
+
* The event, not a real load: jsdom fetches nothing, and the handler reads
|
|
111
|
+
* `getBoundingClientRect()` and `naturalWidth` off the element. Stub those first —
|
|
112
|
+
* see this class's docs — or the crop window will still not render and
|
|
113
|
+
* {@link isReady} will stay `false`, which is exactly what a real cropper does with
|
|
114
|
+
* a zero-sized image.
|
|
115
|
+
*/
|
|
116
|
+
dispatchImageLoad(): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Where the crop window sits over the displayed image, in CSS pixels.
|
|
119
|
+
*
|
|
120
|
+
* From the inline styles the component writes — a measured box would be 0×0 — and
|
|
121
|
+
* in DISPLAY pixels, which is not what a consumer receives: `cropRect()` converts
|
|
122
|
+
* to the image's natural pixels, and that conversion is the component's own contract
|
|
123
|
+
* rather than something the DOM shows.
|
|
124
|
+
*/
|
|
125
|
+
getCropBox(): Promise<WrCropWindowBox>;
|
|
126
|
+
/** The eight resize handles, by their compass suffix. Throws before the crop UI is up. */
|
|
127
|
+
getHandles(): Promise<WrCropHandle[]>;
|
|
128
|
+
/** Whether the dimming backdrop with the cut-out is drawn. */
|
|
129
|
+
hasBackdrop(): Promise<boolean>;
|
|
130
|
+
private requireReady;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { WrImageCropperHarness };
|
|
134
|
+
export type { WrImageCropperHarnessFilters };
|
|
@@ -61,6 +61,7 @@ declare class WrImageCropper {
|
|
|
61
61
|
readonly cropped: _angular_core.OutputEmitterRef<Blob>;
|
|
62
62
|
protected readonly imgEl: _angular_core.Signal<ElementRef<HTMLImageElement>>;
|
|
63
63
|
/** Resolved object URL for `src` (so File / Blob render in `<img>`). */
|
|
64
|
+
protected readonly emptyText: _angular_core.Signal<string>;
|
|
64
65
|
protected readonly objectUrl: _angular_core.WritableSignal<string | null>;
|
|
65
66
|
/** Previous object URL we created — kept off-signal so the resolve
|
|
66
67
|
* effect doesn't depend on its own writes (which would loop). */
|
|
@@ -79,6 +79,17 @@ declare class WrInputNumber implements FormValueControl<number | null> {
|
|
|
79
79
|
*/
|
|
80
80
|
readonly ariaLabel: _angular_core.InputSignal<string | null>;
|
|
81
81
|
protected readonly resolvedAriaLabel: _angular_core.Signal<string | null>;
|
|
82
|
+
/** Increment button aria-label. Falls back to `inputNumber.increment`. */
|
|
83
|
+
readonly incrementLabel: _angular_core.InputSignal<string | null>;
|
|
84
|
+
/** Decrement button aria-label. Falls back to `inputNumber.decrement`. */
|
|
85
|
+
readonly decrementLabel: _angular_core.InputSignal<string | null>;
|
|
86
|
+
/**
|
|
87
|
+
* The steppers are icon-only buttons, so these ARE their accessible names.
|
|
88
|
+
* They were hard-coded English while the catalog carried the keys for them
|
|
89
|
+
* unread — a Russian app announced "Increment".
|
|
90
|
+
*/
|
|
91
|
+
protected readonly resolvedIncrement: _angular_core.Signal<string>;
|
|
92
|
+
protected readonly resolvedDecrement: _angular_core.Signal<string>;
|
|
82
93
|
/** Disable interaction. @default false */
|
|
83
94
|
readonly disabled: _angular_core.InputSignalWithTransform<boolean, any>;
|
|
84
95
|
/** Read-only — values cannot be changed (steppers + typing disabled). @default false */
|
|
@@ -97,6 +108,27 @@ declare class WrInputNumber implements FormValueControl<number | null> {
|
|
|
97
108
|
protected readonly atMin: _angular_core.Signal<boolean>;
|
|
98
109
|
protected readonly atMax: _angular_core.Signal<boolean>;
|
|
99
110
|
protected readonly classes: _angular_core.Signal<string>;
|
|
111
|
+
/**
|
|
112
|
+
* Fraction digits the stepper rounds its arithmetic to when `decimals` says
|
|
113
|
+
* nothing. High enough to leave a real value alone, low enough to erase the
|
|
114
|
+
* binary-float tail that repeated stepping accumulates.
|
|
115
|
+
*/
|
|
116
|
+
private static readonly STEP_PRECISION;
|
|
117
|
+
/**
|
|
118
|
+
* Above this, the anti-drift round is skipped — it would MANUFACTURE drift.
|
|
119
|
+
*
|
|
120
|
+
* `round(v, 10)` is `Math.round((v + EPSILON) * 1e10) / 1e10`, and the scale
|
|
121
|
+
* factor is only exact while `v * 1e10` stays inside 2^53, i.e. |v| under
|
|
122
|
+
* about 900,720. In practice the round-trip still recovers up to ~9.2e8 and
|
|
123
|
+
* then breaks: `round(1000000001, 10)` is `1000000000.9999999`, and since
|
|
124
|
+
* `format` prints up to 20 fraction digits that tail reaches the screen —
|
|
125
|
+
* and compounds, because the next press starts from it. Integer stepping at
|
|
126
|
+
* that magnitude is exact in IEEE754 and needed no help; the only thing this
|
|
127
|
+
* rounding exists to defend is `0.1 + 0.1 + 0.1`.
|
|
128
|
+
*/
|
|
129
|
+
private static readonly SAFE_ROUND_MAGNITUDE;
|
|
130
|
+
/** Steps finer than this would be rounded away by {@link STEP_PRECISION}. */
|
|
131
|
+
private static readonly SAFE_ROUND_STEP;
|
|
100
132
|
constructor();
|
|
101
133
|
protected onInput(event: Event): void;
|
|
102
134
|
protected onFocus(): void;
|
|
@@ -112,7 +144,7 @@ declare class WrInputNumber implements FormValueControl<number | null> {
|
|
|
112
144
|
/** Format a value using `Intl.NumberFormat` for the active locale. */
|
|
113
145
|
private format;
|
|
114
146
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrInputNumber, never>;
|
|
115
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrInputNumber, "wr-input-number", never, { "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "decimals": { "alias": "decimals"; "required": false; "isSignal": true; }; "showSteppers": { "alias": "showSteppers"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "prefix": { "alias": "prefix"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, never, never, true, never>;
|
|
147
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrInputNumber, "wr-input-number", never, { "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "decimals": { "alias": "decimals"; "required": false; "isSignal": true; }; "showSteppers": { "alias": "showSteppers"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "prefix": { "alias": "prefix"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "incrementLabel": { "alias": "incrementLabel"; "required": false; "isSignal": true; }; "decrementLabel": { "alias": "decrementLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, never, never, true, never>;
|
|
116
148
|
}
|
|
117
149
|
|
|
118
150
|
export { WrInputNumber };
|
|
@@ -0,0 +1,150 @@
|
|
|
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-knob>` a harness query matches. */
|
|
11
|
+
interface WrKnobHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the dial's accessible name — a string is an exact match, a RegExp is tested. */
|
|
13
|
+
readonly label?: string | RegExp;
|
|
14
|
+
/** Match the current value, as `aria-valuenow` reports it. */
|
|
15
|
+
readonly value?: number;
|
|
16
|
+
/** Match only enabled (`false`) or only disabled (`true`) dials. */
|
|
17
|
+
readonly disabled?: boolean;
|
|
18
|
+
/** Match only writable (`false`) or only read-only (`true`) dials. */
|
|
19
|
+
readonly readonly?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @license
|
|
24
|
+
*
|
|
25
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
26
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** The two arrow keys that raise the value, and the two that lower it. */
|
|
30
|
+
type Arrow = 'left' | 'right' | 'up' | 'down';
|
|
31
|
+
/**
|
|
32
|
+
* Test harness for `<wr-knob>` — the radial dial.
|
|
33
|
+
*
|
|
34
|
+
* **Driven by the keyboard, and the drag is not merely unsupported.** Turning the
|
|
35
|
+
* dial with a pointer takes `getBoundingClientRect()`, measures the angle from the
|
|
36
|
+
* centre to the cursor, and maps it onto a 270° arc. jsdom lays nothing out, so the
|
|
37
|
+
* centre is `(0, 0)` and every synthetic gesture writes the same corner of the arc
|
|
38
|
+
* whatever coordinates it is given — a `turnTo()` built on one would pass while
|
|
39
|
+
* proving nothing. The arrows reach every value on the grid and are the accessible
|
|
40
|
+
* path anyway.
|
|
41
|
+
*
|
|
42
|
+
* **Two questions about the value, not one.** {@link getValue} is the number
|
|
43
|
+
* `aria-valuenow` carries; {@link getDisplayValue} is the string in the middle of the
|
|
44
|
+
* dial, which the `suffix` input can make `"50%"` while the announced value stays
|
|
45
|
+
* `50`. They are separate methods because they can disagree, and because
|
|
46
|
+
* `showValue` can remove the text entirely without touching the value.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const knob = await loader.getHarness(WrKnobHarness);
|
|
51
|
+
*
|
|
52
|
+
* await knob.setValue(60);
|
|
53
|
+
* expect(await knob.getValue()).toBe(60);
|
|
54
|
+
* expect(await knob.getDisplayValue()).toBe('60%');
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see https://ngwr.dev/guides/testing
|
|
58
|
+
*/
|
|
59
|
+
declare class WrKnobHarness extends ComponentHarness {
|
|
60
|
+
static hostSelector: string;
|
|
61
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
62
|
+
static with(options?: WrKnobHarnessFilters): HarnessPredicate<WrKnobHarness>;
|
|
63
|
+
private readonly surface;
|
|
64
|
+
/** The value the dial announces, from `aria-valuenow`. */
|
|
65
|
+
getValue(): Promise<number>;
|
|
66
|
+
/** The bottom of the range, from `aria-valuemin`. */
|
|
67
|
+
getMin(): Promise<number>;
|
|
68
|
+
/** The top of the range, from `aria-valuemax`. */
|
|
69
|
+
getMax(): Promise<number>;
|
|
70
|
+
/**
|
|
71
|
+
* The text printed in the middle of the dial, suffix included, or `null` when the
|
|
72
|
+
* knob was built with `[showValue]="false"`.
|
|
73
|
+
*
|
|
74
|
+
* Not the same question as {@link getValue}: with a `suffix` the two disagree by
|
|
75
|
+
* design, and a screen reader is told the bare number — the component publishes no
|
|
76
|
+
* `aria-valuetext`, so `50` is what gets announced for a dial that reads `50%`.
|
|
77
|
+
*/
|
|
78
|
+
getDisplayValue(): Promise<string | null>;
|
|
79
|
+
/** The suffix alone, or `null` when there is none (or no value text at all). */
|
|
80
|
+
getSuffix(): Promise<string | null>;
|
|
81
|
+
/** The dial's accessible name — `role="slider"` needs one. */
|
|
82
|
+
getLabel(): Promise<string | null>;
|
|
83
|
+
/** Whether the dial is disabled, from `aria-disabled`. */
|
|
84
|
+
isDisabled(): Promise<boolean>;
|
|
85
|
+
/** Whether the dial is read-only, from `aria-readonly`. */
|
|
86
|
+
isReadonly(): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Whether the dial is a tab stop.
|
|
89
|
+
*
|
|
90
|
+
* The component drops it out of the tab order for BOTH disabled and read-only,
|
|
91
|
+
* which is worth knowing: a read-only slider that a keyboard user cannot reach is
|
|
92
|
+
* also one they cannot read, and this is the method that says so.
|
|
93
|
+
*/
|
|
94
|
+
isFocusable(): Promise<boolean>;
|
|
95
|
+
/** Move keyboard focus to the dial. */
|
|
96
|
+
focus(): Promise<void>;
|
|
97
|
+
/** Whether the dial currently holds focus. */
|
|
98
|
+
isFocused(): Promise<boolean>;
|
|
99
|
+
/** Blur the dial — which is what emits `touch` for a knob moved with the keyboard. */
|
|
100
|
+
blur(): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Press one arrow key.
|
|
103
|
+
*
|
|
104
|
+
* Right and Up raise the value, Left and Down lower it — all four are live on this
|
|
105
|
+
* component, which has one axis and no mirroring to do. `shift` multiplies the step
|
|
106
|
+
* by ten.
|
|
107
|
+
*/
|
|
108
|
+
pressArrow(arrow: Arrow, options?: {
|
|
109
|
+
shift?: boolean;
|
|
110
|
+
}): Promise<void>;
|
|
111
|
+
/** Press Home — the bottom of the range. */
|
|
112
|
+
pressHome(): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Press End — the top of the range, or the last value ON the grid below it: a range
|
|
115
|
+
* that is not a whole number of steps cannot reach its own maximum.
|
|
116
|
+
*/
|
|
117
|
+
pressEnd(): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Walk the dial to a value with the arrow keys, and assert it landed there.
|
|
120
|
+
*
|
|
121
|
+
* It measures the step as it goes rather than being told it — `step` is an input
|
|
122
|
+
* with no DOM presence, and the value can arrive off the grid, since an external
|
|
123
|
+
* write is clamped but never snapped. So the first press may move by less than a
|
|
124
|
+
* step (it snaps onto the grid) and the walk adapts, which also means the ten-step
|
|
125
|
+
* hops only start once a real step has been seen.
|
|
126
|
+
*
|
|
127
|
+
* Throws rather than half-arriving, and the two reasons read differently: a target
|
|
128
|
+
* outside `[min, max]` is refused before anything moves, while a target BETWEEN two
|
|
129
|
+
* grid points is only discovered by overshooting it, and says where it landed. A
|
|
130
|
+
* dial that will not move at all — disabled, read-only — is the third.
|
|
131
|
+
*/
|
|
132
|
+
setValue(target: number): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Where the handle dot sits, in the SVG's own 100×100 viewBox units.
|
|
135
|
+
*
|
|
136
|
+
* The dial's whole visual state is an arc path and this dot, and neither can be
|
|
137
|
+
* measured in a unit test — but the dot's centre is written as plain `cx` / `cy`
|
|
138
|
+
* attributes, so it reads with no layout at all. That makes it the evidence that
|
|
139
|
+
* the drawing followed the value: at `min` the handle is at the 7 o'clock end of
|
|
140
|
+
* the arc, at `max` the 5 o'clock end.
|
|
141
|
+
*/
|
|
142
|
+
getHandlePosition(): Promise<{
|
|
143
|
+
x: number;
|
|
144
|
+
y: number;
|
|
145
|
+
}>;
|
|
146
|
+
private numeric;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { WrKnobHarness };
|
|
150
|
+
export type { WrKnobHarnessFilters };
|
|
@@ -0,0 +1,154 @@
|
|
|
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-lightbox>` a harness query matches. */
|
|
11
|
+
interface WrLightboxHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the image's alt text — a string is an exact match, a RegExp is tested. */
|
|
13
|
+
readonly alt?: string | RegExp;
|
|
14
|
+
/** Match the caption shown under the full image. */
|
|
15
|
+
readonly caption?: string | RegExp;
|
|
16
|
+
/** Match only open (`true`) or only closed (`false`) lightboxes. */
|
|
17
|
+
readonly open?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @license
|
|
22
|
+
*
|
|
23
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
24
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Test harness for `<wr-lightbox>` — the thumbnail, and the full-size viewer it
|
|
29
|
+
* opens.
|
|
30
|
+
*
|
|
31
|
+
* The thumbnail is an element in your fixture and the viewer is a portal in the NGWR
|
|
32
|
+
* overlay container, so this is loaded from the normal fixture loader and reaches
|
|
33
|
+
* across for you — scoped by the id the trigger publishes as `aria-controls`, never
|
|
34
|
+
* by `.wr-lightbox-viewer`, which would answer with whichever lightbox opened first.
|
|
35
|
+
*
|
|
36
|
+
* **A closed lightbox has no viewer at all**, unlike the collapse or the speed dial:
|
|
37
|
+
* the overlay is created on open and disposed on close, so every viewer read here
|
|
38
|
+
* throws while it is shut rather than answering about a stale element.
|
|
39
|
+
*
|
|
40
|
+
* **`disablePreview` removes the button, not just its behaviour.** The thumbnail is
|
|
41
|
+
* then a bare `<img>` with nothing to click and nothing in the tab order, which is
|
|
42
|
+
* why {@link isInteractive} exists and why {@link open} explains itself rather than
|
|
43
|
+
* timing out on a missing element.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const lightbox = await loader.getHarness(WrLightboxHarness.with({ alt: 'Mountain' }));
|
|
48
|
+
*
|
|
49
|
+
* await lightbox.open();
|
|
50
|
+
* expect(await lightbox.getFullSrc()).toBe('/photo.jpg');
|
|
51
|
+
*
|
|
52
|
+
* await lightbox.sendEscape();
|
|
53
|
+
* expect(await lightbox.isOpen()).toBe(false);
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @see https://ngwr.dev/guides/testing
|
|
57
|
+
*/
|
|
58
|
+
declare class WrLightboxHarness extends ComponentHarness {
|
|
59
|
+
static hostSelector: string;
|
|
60
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
61
|
+
static with(options?: WrLightboxHarnessFilters): HarnessPredicate<WrLightboxHarness>;
|
|
62
|
+
private readonly thumb;
|
|
63
|
+
private readonly trigger;
|
|
64
|
+
/**
|
|
65
|
+
* Whether the viewer is open, from the host's own modifier.
|
|
66
|
+
*
|
|
67
|
+
* The class rather than the overlay, because it is the answer that holds for a
|
|
68
|
+
* harness you are HOLDING: the viewer is disposed on close, and a query for it
|
|
69
|
+
* cannot tell "shut" apart from "never opened".
|
|
70
|
+
*/
|
|
71
|
+
isOpen(): Promise<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Whether the thumbnail has settled — loaded OR failed.
|
|
74
|
+
*
|
|
75
|
+
* A failure counts on purpose: the loading state animates a shimmer and hides the
|
|
76
|
+
* image, so a broken `src` with no error path would shimmer for ever instead of
|
|
77
|
+
* falling back to its alt text. The two cases are deliberately not separated here,
|
|
78
|
+
* because the DOM does not separate them either.
|
|
79
|
+
*/
|
|
80
|
+
isLoading(): Promise<boolean>;
|
|
81
|
+
/** The thumbnail's alt text — the same string the viewer takes its name from. */
|
|
82
|
+
getAlt(): Promise<string>;
|
|
83
|
+
/**
|
|
84
|
+
* What the THUMBNAIL is showing: `preview` when one was given, `src` otherwise.
|
|
85
|
+
*
|
|
86
|
+
* Worth its own method because the two images are different files by design — a
|
|
87
|
+
* grid of thumbnails should not pull full-size originals — and because the
|
|
88
|
+
* thumbnail never swaps to `src` later. Compare with {@link getFullSrc}.
|
|
89
|
+
*/
|
|
90
|
+
getThumbSrc(): Promise<string>;
|
|
91
|
+
/** Whether the thumbnail can be clicked open at all (`disablePreview` off). */
|
|
92
|
+
isInteractive(): Promise<boolean>;
|
|
93
|
+
/** The trigger's accessible name — falls back to the alt text, then to the catalog. */
|
|
94
|
+
getOpenLabel(): Promise<string | null>;
|
|
95
|
+
/** Open the viewer. An already-open one is left alone; a non-interactive one throws. */
|
|
96
|
+
open(): Promise<void>;
|
|
97
|
+
/** Close the viewer through its ✕ button. An already-closed one is left alone. */
|
|
98
|
+
close(): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Click the full image — which closes the viewer.
|
|
101
|
+
*
|
|
102
|
+
* It looks like decoration and is not: the image is styled `cursor: zoom-out`, and
|
|
103
|
+
* that is a promise. It is deliberately NOT in the tab order, since the ✕ button,
|
|
104
|
+
* Escape, the backdrop and a swipe all do the same thing and all reach a keyboard —
|
|
105
|
+
* so this is a mouse affordance, and the only way to assert it still works.
|
|
106
|
+
*/
|
|
107
|
+
clickImage(): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Press Escape.
|
|
110
|
+
*
|
|
111
|
+
* Sent to the viewer, though it would arrive from anywhere: the overlay is fed by
|
|
112
|
+
* the CDK's keyboard dispatcher, which keeps one document listener and routes to
|
|
113
|
+
* the top-most overlay.
|
|
114
|
+
*/
|
|
115
|
+
sendEscape(): Promise<void>;
|
|
116
|
+
/** The full-size image's `src`. Throws while the viewer is closed. */
|
|
117
|
+
getFullSrc(): Promise<string>;
|
|
118
|
+
/** The caption under the full image, or `null` when there is none. Throws while closed. */
|
|
119
|
+
getCaption(): Promise<string | null>;
|
|
120
|
+
/** The name the viewer dialog announces — its alt text, or the catalog's fallback. */
|
|
121
|
+
getViewerLabel(): Promise<string | null>;
|
|
122
|
+
/** The ✕ button's accessible name. Throws while the viewer is closed. */
|
|
123
|
+
getCloseLabel(): Promise<string | null>;
|
|
124
|
+
/** Whether the viewer announces itself as a modal dialog. */
|
|
125
|
+
isModal(): Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* Whether focus is inside the viewer, where the trap should be holding it.
|
|
128
|
+
*
|
|
129
|
+
* `role="dialog"` with `aria-modal` promises the page behind is out of reach, and a
|
|
130
|
+
* missing trap makes that a lie — Tab walks straight through the backdrop. Note
|
|
131
|
+
* that in a unit test the trap needs elements with a box to find anything tabbable,
|
|
132
|
+
* so a spec asserting this has to hand the DOM some dimensions first.
|
|
133
|
+
*/
|
|
134
|
+
isFocusTrapped(): Promise<boolean>;
|
|
135
|
+
/**
|
|
136
|
+
* Whether the trigger's `aria-controls` names THIS lightbox's viewer, and nothing
|
|
137
|
+
* else on the page.
|
|
138
|
+
*
|
|
139
|
+
* The reference only exists while the viewer does — an id naming an element that is
|
|
140
|
+
* not in the document is not a pairing, it is a dangling reference — so this is
|
|
141
|
+
* `false` for a closed lightbox by construction. Counted across the document too,
|
|
142
|
+
* because two viewers answering to one id hand every reference to the first.
|
|
143
|
+
*/
|
|
144
|
+
isViewerBound(): Promise<boolean>;
|
|
145
|
+
/** The caption without the open check — for filters, which must not throw. */
|
|
146
|
+
private readCaption;
|
|
147
|
+
/** The id the trigger currently points at, or `null` while the viewer is closed. */
|
|
148
|
+
private viewerId;
|
|
149
|
+
private requireViewer;
|
|
150
|
+
private viewerPart;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export { WrLightboxHarness };
|
|
154
|
+
export type { WrLightboxHarnessFilters };
|
package/types/ngwr-lightbox.d.ts
CHANGED
|
@@ -50,6 +50,12 @@ declare class WrLightbox {
|
|
|
50
50
|
readonly aspectRatio: _angular_core.InputSignal<string | number | null>;
|
|
51
51
|
protected readonly open: _angular_core.WritableSignal<boolean>;
|
|
52
52
|
protected readonly loaded: _angular_core.WritableSignal<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Id the trigger's `aria-controls` points at while the viewer is open.
|
|
55
|
+
*
|
|
56
|
+
* @internal Public so the host bindings can read it.
|
|
57
|
+
*/
|
|
58
|
+
protected readonly viewerId: string;
|
|
53
59
|
protected readonly classes: _angular_core.Signal<string>;
|
|
54
60
|
protected readonly panelTpl: _angular_core.Signal<TemplateRef<unknown>>;
|
|
55
61
|
private readonly overlay;
|
|
@@ -0,0 +1,93 @@
|
|
|
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-line-chart>` a harness query matches. */
|
|
11
|
+
interface WrLineChartHarnessFilters extends BaseHarnessFilters {
|
|
12
|
+
/** Match the plot's accessible name. */
|
|
13
|
+
readonly ariaLabel?: string | RegExp;
|
|
14
|
+
/** Match a chart whose legend holds this series. */
|
|
15
|
+
readonly seriesLabel?: string | RegExp;
|
|
16
|
+
}
|
|
17
|
+
/** One row of the hover tooltip — a series and its value at the hovered index. */
|
|
18
|
+
interface WrLineChartTooltipRow {
|
|
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-line-chart>`.
|
|
32
|
+
*
|
|
33
|
+
* **The lines are paths and the paths are not assertable.** A `d` attribute is a
|
|
34
|
+
* rendering detail — it moves with the viewBox, the padding and the value range — so
|
|
35
|
+
* this harness counts the lines and reads everything TEXTUAL instead: the legend, the
|
|
36
|
+
* axis ticks, the x labels and the tooltip. Those are what a reader gets, and they
|
|
37
|
+
* are what breaks when the data wiring does.
|
|
38
|
+
*
|
|
39
|
+
* **The tooltip cannot be opened from a spec, and the reason is worth knowing.** It
|
|
40
|
+
* follows a `pointermove` over the plot, and the component turns the cursor's x into
|
|
41
|
+
* an index by measuring the plot's box — which jsdom reports as 0×0, so every
|
|
42
|
+
* synthetic move resolves to the same index or to none at all. There is deliberately
|
|
43
|
+
* no `hoverAt()`; {@link getTooltipRows} reads the tooltip when something else has
|
|
44
|
+
* opened it, which in practice means a browser-run harness.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const chart = await loader.getHarness(WrLineChartHarness);
|
|
49
|
+
*
|
|
50
|
+
* expect(await chart.getSeriesLabels()).toEqual(['Revenue', 'Costs']);
|
|
51
|
+
* expect(await chart.getLineCount()).toBe(2);
|
|
52
|
+
* expect(await chart.getXLabels()).toEqual(['Jan', 'Feb', 'Mar']);
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @see https://ngwr.dev/guides/testing
|
|
56
|
+
*/
|
|
57
|
+
declare class WrLineChartHarness extends ComponentHarness {
|
|
58
|
+
static hostSelector: string;
|
|
59
|
+
/** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
|
|
60
|
+
static with(options?: WrLineChartHarnessFilters): HarnessPredicate<WrLineChartHarness>;
|
|
61
|
+
/** The plot's accessible name — the only name the drawing has. */
|
|
62
|
+
getAccessibleName(): Promise<string | null>;
|
|
63
|
+
/** Whether the legend is rendered (`showLegend`, and at least one series). */
|
|
64
|
+
hasLegend(): Promise<boolean>;
|
|
65
|
+
/** The series names from the legend, in order. */
|
|
66
|
+
getSeriesLabels(): Promise<string[]>;
|
|
67
|
+
/**
|
|
68
|
+
* How many lines were drawn.
|
|
69
|
+
*
|
|
70
|
+
* Worth comparing with {@link getSeriesLabels}: the legend and the paths come from
|
|
71
|
+
* the same list, so a mismatch is a series that got filtered out of one of them.
|
|
72
|
+
*/
|
|
73
|
+
getLineCount(): Promise<number>;
|
|
74
|
+
/** How many point dots were drawn across every series (`showDots`). */
|
|
75
|
+
getDotCount(): Promise<number>;
|
|
76
|
+
/** Whether the horizontal grid lines are drawn (`showGrid`). */
|
|
77
|
+
hasGrid(): Promise<boolean>;
|
|
78
|
+
/** The y-axis tick labels, top to bottom as drawn. */
|
|
79
|
+
getYTicks(): Promise<string[]>;
|
|
80
|
+
/** The x-axis labels under the plot, in order. */
|
|
81
|
+
getXLabels(): Promise<string[]>;
|
|
82
|
+
/** Whether the hover tooltip is showing. */
|
|
83
|
+
hasTooltip(): Promise<boolean>;
|
|
84
|
+
/** The tooltip's heading — the x label of the hovered point — or `null` while it is closed. */
|
|
85
|
+
getTooltipLabel(): Promise<string | null>;
|
|
86
|
+
/** The tooltip's rows, one per series, or `[]` while it is closed. */
|
|
87
|
+
getTooltipRows(): Promise<WrLineChartTooltipRow[]>;
|
|
88
|
+
/** The plot's height in pixels, as the component writes it inline. */
|
|
89
|
+
getPlotHeight(): Promise<number>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { WrLineChartHarness };
|
|
93
|
+
export type { WrLineChartHarnessFilters, WrLineChartTooltipRow };
|