@cdevhub/ngx-tw 0.5.0 → 0.6.1
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/README.md +78 -15
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +11 -2
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +28 -4
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs → cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs} +3 -3
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +23 -7
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs → cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs} +107 -19
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +21 -13
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
- package/index.json +1 -1
- package/package.json +63 -2
- package/theme/_base.css +13 -0
- package/theme/_dark.css +111 -36
- package/theme/_high-contrast-dark.css +367 -0
- package/theme/_high-contrast.css +13 -2
- package/theme/_light.css +332 -0
- package/theme/_semantic.css +60 -26
- package/theme/_typography.css +17 -0
- package/theme/index.css +86 -7
- package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
- package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
- package/types/cdevhub-ngx-tw-button.d.ts +1 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
- package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
- package/types/cdevhub-ngx-tw-card.d.ts +11 -3
- package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
- package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
- package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
- package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
- package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
- package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
- package/types/cdevhub-ngx-tw-core.d.ts +152 -21
- package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
- package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
- package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +12 -3
- package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
- package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
- package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
- package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
- package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
- package/types/cdevhub-ngx-tw-input.d.ts +5 -8
- package/types/cdevhub-ngx-tw-item.d.ts +2 -0
- package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
- package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
- package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
- package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
- package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
- package/types/cdevhub-ngx-tw-select.d.ts +104 -33
- package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +19 -3
- package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
- package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
- package/types/cdevhub-ngx-tw-split.d.ts +32 -2
- package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
- package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
- package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
- package/types/cdevhub-ngx-tw-table.d.ts +53 -10
- package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
- package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
- package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
- package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
- package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
- package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
- package/types/cdevhub-ngx-tw-toast.d.ts +20 -6
- package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
- package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
- package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
- package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs.map +0 -1
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs.map +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { ComponentHarness, HarnessPredicate, TestKey } from '@angular/cdk/testing';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Harness for a single option inside an open `tw-combobox` panel.
|
|
5
|
+
*
|
|
6
|
+
* Options render into the CDK overlay, not inside `tw-combobox`, so they are
|
|
7
|
+
* reached through {@link ComboboxHarness} rather than located directly against
|
|
8
|
+
* a fixture.
|
|
9
|
+
*
|
|
10
|
+
* `tw-combobox` is an `aria-activedescendant` listbox: DOM focus never leaves
|
|
11
|
+
* the input, so an option is never the active element. Keyboard highlight is
|
|
12
|
+
* expressed on the input's `aria-activedescendant`, not on the option, and is
|
|
13
|
+
* therefore not exposed here.
|
|
14
|
+
*/
|
|
15
|
+
class ComboboxOptionHarness extends ComponentHarness {
|
|
16
|
+
static hostSelector = '[role="option"]';
|
|
17
|
+
/** Predicate for `locatorFor` / `locatorForAll`. */
|
|
18
|
+
static with(options = {}) {
|
|
19
|
+
return new HarnessPredicate(ComboboxOptionHarness, options)
|
|
20
|
+
.addOption('text', options.text, async (h, text) => HarnessPredicate.stringMatches(await h.getText(), text))
|
|
21
|
+
.addOption('selected', options.selected, async (h, selected) => (await h.isSelected()) === selected)
|
|
22
|
+
.addOption('disabled', options.disabled, async (h, disabled) => (await h.isDisabled()) === disabled);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The option's rendered text, trimmed. An option carrying a `description`
|
|
26
|
+
* renders label and description as sibling block spans, so this returns both
|
|
27
|
+
* concatenated with no separator.
|
|
28
|
+
*/
|
|
29
|
+
async getText() {
|
|
30
|
+
return (await (await this.host()).text()).trim();
|
|
31
|
+
}
|
|
32
|
+
/** Whether the option reports `aria-selected="true"`. */
|
|
33
|
+
async isSelected() {
|
|
34
|
+
return (await (await this.host()).getAttribute('aria-selected')) === 'true';
|
|
35
|
+
}
|
|
36
|
+
/** Whether the option reports `aria-disabled="true"`. */
|
|
37
|
+
async isDisabled() {
|
|
38
|
+
return (await (await this.host()).getAttribute('aria-disabled')) === 'true';
|
|
39
|
+
}
|
|
40
|
+
/** Clicks the option. A disabled option ignores the click, as in the browser. */
|
|
41
|
+
async click() {
|
|
42
|
+
await (await this.host()).click();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Harness for `tw-combobox`.
|
|
48
|
+
*
|
|
49
|
+
* The options panel renders into the CDK overlay container, outside the
|
|
50
|
+
* `tw-combobox` host, so this harness resolves it through
|
|
51
|
+
* `documentRootLocatorFactory()`. A consumer can therefore load this harness
|
|
52
|
+
* from the ordinary fixture loader and still reach the options — no
|
|
53
|
+
* `documentRootLoader` ceremony required.
|
|
54
|
+
*
|
|
55
|
+
* The panel is *disposed* on close rather than merely detached, so option
|
|
56
|
+
* harnesses must be re-read after each `open()`. Do not cache them across a
|
|
57
|
+
* close.
|
|
58
|
+
*/
|
|
59
|
+
class ComboboxHarness extends ComponentHarness {
|
|
60
|
+
static hostSelector = 'tw-combobox';
|
|
61
|
+
input = this.locatorFor('input[role="combobox"]');
|
|
62
|
+
/**
|
|
63
|
+
* The inline clear (×) control. Its `aria-label` is a template literal in
|
|
64
|
+
* `combobox.ts` — not a consumer input — so matching on it is stable.
|
|
65
|
+
*/
|
|
66
|
+
clearButton = this.locatorForOptional('button[aria-label="Clear"]');
|
|
67
|
+
/** Resolves the overlay panel, which lives outside this harness's host. */
|
|
68
|
+
panel = this.documentRootLocatorFactory().locatorForOptional('[role="listbox"]');
|
|
69
|
+
/** Predicate for `locatorFor` / `locatorForAll`. */
|
|
70
|
+
static with(options = {}) {
|
|
71
|
+
return new HarnessPredicate(ComboboxHarness, options)
|
|
72
|
+
.addOption('label', options.label, async (h, label) => HarnessPredicate.stringMatches(await h.getLabel(), label))
|
|
73
|
+
.addOption('inputValue', options.inputValue, async (h, value) => HarnessPredicate.stringMatches(await h.getInputValue(), value))
|
|
74
|
+
.addOption('disabled', options.disabled, async (h, disabled) => (await h.isDisabled()) === disabled);
|
|
75
|
+
}
|
|
76
|
+
/** The input's accessible name, from `aria-label` when one is set. */
|
|
77
|
+
async getLabel() {
|
|
78
|
+
return (await this.input()).getAttribute('aria-label');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The text currently in the input — the typed query while the user is
|
|
82
|
+
* filtering, the committed option's label afterwards. Empty string when the
|
|
83
|
+
* combobox holds nothing (the placeholder is not part of the value).
|
|
84
|
+
*/
|
|
85
|
+
async getInputValue() {
|
|
86
|
+
return (await this.input()).getProperty('value');
|
|
87
|
+
}
|
|
88
|
+
/** The input's `placeholder`, or `null` when none is set. */
|
|
89
|
+
async getPlaceholder() {
|
|
90
|
+
return (await this.input()).getAttribute('placeholder');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Replaces the input text and lets the component filter against it — the
|
|
94
|
+
* harness equivalent of selecting all and typing a query.
|
|
95
|
+
*
|
|
96
|
+
* Does NOT commit a value: `tw-combobox` commits on option pick, Enter, blur
|
|
97
|
+
* or Tab. Follow with `selectOption(...)` to pick from the filtered list.
|
|
98
|
+
*/
|
|
99
|
+
async setInputValue(value) {
|
|
100
|
+
const input = await this.input();
|
|
101
|
+
await input.focus();
|
|
102
|
+
await input.setInputValue(value);
|
|
103
|
+
// `setInputValue` only assigns `element.value`; the component listens on
|
|
104
|
+
// `input`, so the event has to be dispatched explicitly.
|
|
105
|
+
await input.dispatchEvent('input');
|
|
106
|
+
await this.waitForTasksOutsideAngular();
|
|
107
|
+
}
|
|
108
|
+
/** Whether the panel is open, read from the input's `aria-expanded`. */
|
|
109
|
+
async isOpen() {
|
|
110
|
+
return (await (await this.input()).getAttribute('aria-expanded')) === 'true';
|
|
111
|
+
}
|
|
112
|
+
/** Whether the input reports `aria-disabled="true"`. */
|
|
113
|
+
async isDisabled() {
|
|
114
|
+
return (await (await this.input()).getAttribute('aria-disabled')) === 'true';
|
|
115
|
+
}
|
|
116
|
+
/** Whether the input reports `aria-invalid="true"`. */
|
|
117
|
+
async isInvalid() {
|
|
118
|
+
return (await (await this.input()).getAttribute('aria-invalid')) === 'true';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Whether the input reports `aria-required="true"`. Reflects the `required`
|
|
122
|
+
* input *and* a `Validators.required` on a bound control.
|
|
123
|
+
*/
|
|
124
|
+
async isRequired() {
|
|
125
|
+
return (await (await this.input()).getAttribute('aria-required')) === 'true';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Opens the panel with `Alt+ArrowDown`. No-op when already open.
|
|
129
|
+
*
|
|
130
|
+
* Deliberately not a click: `openOnFocus` defaults to `true` but can be
|
|
131
|
+
* turned off, whereas `Alt+ArrowDown` is the APG force-open gesture and works
|
|
132
|
+
* either way. A disabled combobox ignores it, as it does in the browser.
|
|
133
|
+
*/
|
|
134
|
+
async open() {
|
|
135
|
+
if (await this.isOpen())
|
|
136
|
+
return;
|
|
137
|
+
await (await this.input()).sendKeys({ alt: true }, TestKey.DOWN_ARROW);
|
|
138
|
+
await this.waitForTasksOutsideAngular();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Closes the panel with `Alt+ArrowUp`. No-op when already closed.
|
|
142
|
+
*
|
|
143
|
+
* Deliberately not Escape: Escape *also* reverts the input text to the last
|
|
144
|
+
* committed label, which would make `close()` silently destroy a typed query.
|
|
145
|
+
*
|
|
146
|
+
* The overlay runs a leave animation before it detaches, so `isOpen()` flips
|
|
147
|
+
* to `false` immediately while the panel element lingers for a few more
|
|
148
|
+
* frames. Two consequences worth knowing:
|
|
149
|
+
*
|
|
150
|
+
* - Do not assert `getOptions()` is empty on the tick after a close; the
|
|
151
|
+
* old panel is still mounted.
|
|
152
|
+
* - An `open()` inside that window does **not** attach a fresh panel — the
|
|
153
|
+
* component sees an overlay ref it has not disposed yet and silently
|
|
154
|
+
* keeps the outgoing one. Let the animation finish before reopening.
|
|
155
|
+
*/
|
|
156
|
+
async close() {
|
|
157
|
+
if (!(await this.isOpen()))
|
|
158
|
+
return;
|
|
159
|
+
await (await this.input()).sendKeys({ alt: true }, TestKey.UP_ARROW);
|
|
160
|
+
await this.waitForTasksOutsideAngular();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Every option in the open panel, in render order and already filtered by
|
|
164
|
+
* whatever query the input holds. Returns an empty array when the panel has
|
|
165
|
+
* never been opened, because the overlay is disposed rather than hidden.
|
|
166
|
+
*/
|
|
167
|
+
async getOptions(filters = {}) {
|
|
168
|
+
if (!(await this.panel()))
|
|
169
|
+
return [];
|
|
170
|
+
return this.documentRootLocatorFactory().locatorForAll(ComboboxOptionHarness.with(filters))();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The text of every option currently rendered in the open panel. Opens the
|
|
174
|
+
* panel if needed — this is how a consumer reads the result of a filter
|
|
175
|
+
* query.
|
|
176
|
+
*/
|
|
177
|
+
async getOptionTexts() {
|
|
178
|
+
await this.open();
|
|
179
|
+
const options = await this.getOptions();
|
|
180
|
+
return Promise.all(options.map((option) => option.getText()));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Opens the panel if needed and clicks the first option whose text matches.
|
|
184
|
+
* Throws when nothing matches, rather than failing silently.
|
|
185
|
+
*/
|
|
186
|
+
async selectOption(text) {
|
|
187
|
+
await this.open();
|
|
188
|
+
const matches = await this.getOptions({ text });
|
|
189
|
+
if (matches.length === 0) {
|
|
190
|
+
throw new Error(`ComboboxHarness.selectOption: no option matching ${String(text)}.`);
|
|
191
|
+
}
|
|
192
|
+
await matches[0].click();
|
|
193
|
+
await this.waitForTasksOutsideAngular();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Whether the inline clear control is rendered. It appears only while
|
|
197
|
+
* `clearable` is on, the combobox is enabled, and the input is non-empty.
|
|
198
|
+
*/
|
|
199
|
+
async hasClearButton() {
|
|
200
|
+
return (await this.clearButton()) !== null;
|
|
201
|
+
}
|
|
202
|
+
/** Clicks the clear control. Throws when none is rendered. */
|
|
203
|
+
async clear() {
|
|
204
|
+
const button = await this.clearButton();
|
|
205
|
+
if (!button) {
|
|
206
|
+
throw new Error('ComboboxHarness.clear: no clear control is rendered. It appears only while `clearable` is on, the combobox is enabled, and the input is non-empty.');
|
|
207
|
+
}
|
|
208
|
+
await button.click();
|
|
209
|
+
await this.waitForTasksOutsideAngular();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Generated bundle index. Do not edit.
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
export { ComboboxHarness, ComboboxOptionHarness };
|
|
218
|
+
//# sourceMappingURL=cdevhub-ngx-tw-combobox-testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-combobox-testing.mjs","sources":["../../../projects/ngx-tw/combobox/testing/combobox-option-harness.ts","../../../projects/ngx-tw/combobox/testing/combobox-harness.ts","../../../projects/ngx-tw/combobox/testing/cdevhub-ngx-tw-combobox-testing.ts"],"sourcesContent":["import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\nimport type { BaseHarnessFilters } from '@angular/cdk/testing';\n\n/** Filters accepted by `ComboboxOptionHarness.with`. */\nexport interface ComboboxOptionHarnessFilters extends BaseHarnessFilters {\n /** Match by the option's visible text. */\n text?: string | RegExp;\n /** Match selected / unselected options. */\n selected?: boolean;\n /** Match disabled / enabled options. */\n disabled?: boolean;\n}\n\n/**\n * Harness for a single option inside an open `tw-combobox` panel.\n *\n * Options render into the CDK overlay, not inside `tw-combobox`, so they are\n * reached through {@link ComboboxHarness} rather than located directly against\n * a fixture.\n *\n * `tw-combobox` is an `aria-activedescendant` listbox: DOM focus never leaves\n * the input, so an option is never the active element. Keyboard highlight is\n * expressed on the input's `aria-activedescendant`, not on the option, and is\n * therefore not exposed here.\n */\nexport class ComboboxOptionHarness extends ComponentHarness {\n static hostSelector = '[role=\"option\"]';\n\n /** Predicate for `locatorFor` / `locatorForAll`. */\n static with(\n options: ComboboxOptionHarnessFilters = {},\n ): HarnessPredicate<ComboboxOptionHarness> {\n return new HarnessPredicate(ComboboxOptionHarness, options)\n .addOption('text', options.text, async (h, text) =>\n HarnessPredicate.stringMatches(await h.getText(), text),\n )\n .addOption(\n 'selected',\n options.selected,\n async (h, selected) => (await h.isSelected()) === selected,\n )\n .addOption(\n 'disabled',\n options.disabled,\n async (h, disabled) => (await h.isDisabled()) === disabled,\n );\n }\n\n /**\n * The option's rendered text, trimmed. An option carrying a `description`\n * renders label and description as sibling block spans, so this returns both\n * concatenated with no separator.\n */\n async getText(): Promise<string> {\n return (await (await this.host()).text()).trim();\n }\n\n /** Whether the option reports `aria-selected=\"true\"`. */\n async isSelected(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-selected')) === 'true';\n }\n\n /** Whether the option reports `aria-disabled=\"true\"`. */\n async isDisabled(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-disabled')) === 'true';\n }\n\n /** Clicks the option. A disabled option ignores the click, as in the browser. */\n async click(): Promise<void> {\n await (await this.host()).click();\n }\n}\n","import { ComponentHarness, HarnessPredicate, TestKey } from '@angular/cdk/testing';\nimport type { BaseHarnessFilters, TestElement } from '@angular/cdk/testing';\nimport {\n ComboboxOptionHarness,\n type ComboboxOptionHarnessFilters,\n} from './combobox-option-harness';\n\n/** Filters accepted by `ComboboxHarness.with`. */\nexport interface ComboboxHarnessFilters extends BaseHarnessFilters {\n /** Match by the input's accessible name. */\n label?: string | RegExp;\n /** Match by the text currently typed into (or displayed in) the input. */\n inputValue?: string | RegExp;\n /** Match disabled / enabled comboboxes. */\n disabled?: boolean;\n}\n\n/**\n * Harness for `tw-combobox`.\n *\n * The options panel renders into the CDK overlay container, outside the\n * `tw-combobox` host, so this harness resolves it through\n * `documentRootLocatorFactory()`. A consumer can therefore load this harness\n * from the ordinary fixture loader and still reach the options — no\n * `documentRootLoader` ceremony required.\n *\n * The panel is *disposed* on close rather than merely detached, so option\n * harnesses must be re-read after each `open()`. Do not cache them across a\n * close.\n */\nexport class ComboboxHarness extends ComponentHarness {\n static hostSelector = 'tw-combobox';\n\n private readonly input = this.locatorFor('input[role=\"combobox\"]');\n /**\n * The inline clear (×) control. Its `aria-label` is a template literal in\n * `combobox.ts` — not a consumer input — so matching on it is stable.\n */\n private readonly clearButton = this.locatorForOptional('button[aria-label=\"Clear\"]');\n /** Resolves the overlay panel, which lives outside this harness's host. */\n private readonly panel = this.documentRootLocatorFactory().locatorForOptional(\n '[role=\"listbox\"]',\n );\n\n /** Predicate for `locatorFor` / `locatorForAll`. */\n static with(options: ComboboxHarnessFilters = {}): HarnessPredicate<ComboboxHarness> {\n return new HarnessPredicate(ComboboxHarness, options)\n .addOption('label', options.label, async (h, label) =>\n HarnessPredicate.stringMatches(await h.getLabel(), label),\n )\n .addOption('inputValue', options.inputValue, async (h, value) =>\n HarnessPredicate.stringMatches(await h.getInputValue(), value),\n )\n .addOption(\n 'disabled',\n options.disabled,\n async (h, disabled) => (await h.isDisabled()) === disabled,\n );\n }\n\n /** The input's accessible name, from `aria-label` when one is set. */\n async getLabel(): Promise<string | null> {\n return (await this.input()).getAttribute('aria-label');\n }\n\n /**\n * The text currently in the input — the typed query while the user is\n * filtering, the committed option's label afterwards. Empty string when the\n * combobox holds nothing (the placeholder is not part of the value).\n */\n async getInputValue(): Promise<string> {\n return (await this.input()).getProperty<string>('value');\n }\n\n /** The input's `placeholder`, or `null` when none is set. */\n async getPlaceholder(): Promise<string | null> {\n return (await this.input()).getAttribute('placeholder');\n }\n\n /**\n * Replaces the input text and lets the component filter against it — the\n * harness equivalent of selecting all and typing a query.\n *\n * Does NOT commit a value: `tw-combobox` commits on option pick, Enter, blur\n * or Tab. Follow with `selectOption(...)` to pick from the filtered list.\n */\n async setInputValue(value: string): Promise<void> {\n const input = await this.input();\n await input.focus();\n await input.setInputValue(value);\n // `setInputValue` only assigns `element.value`; the component listens on\n // `input`, so the event has to be dispatched explicitly.\n await input.dispatchEvent('input');\n await this.waitForTasksOutsideAngular();\n }\n\n /** Whether the panel is open, read from the input's `aria-expanded`. */\n async isOpen(): Promise<boolean> {\n return (await (await this.input()).getAttribute('aria-expanded')) === 'true';\n }\n\n /** Whether the input reports `aria-disabled=\"true\"`. */\n async isDisabled(): Promise<boolean> {\n return (await (await this.input()).getAttribute('aria-disabled')) === 'true';\n }\n\n /** Whether the input reports `aria-invalid=\"true\"`. */\n async isInvalid(): Promise<boolean> {\n return (await (await this.input()).getAttribute('aria-invalid')) === 'true';\n }\n\n /**\n * Whether the input reports `aria-required=\"true\"`. Reflects the `required`\n * input *and* a `Validators.required` on a bound control.\n */\n async isRequired(): Promise<boolean> {\n return (await (await this.input()).getAttribute('aria-required')) === 'true';\n }\n\n /**\n * Opens the panel with `Alt+ArrowDown`. No-op when already open.\n *\n * Deliberately not a click: `openOnFocus` defaults to `true` but can be\n * turned off, whereas `Alt+ArrowDown` is the APG force-open gesture and works\n * either way. A disabled combobox ignores it, as it does in the browser.\n */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n await (await this.input()).sendKeys({ alt: true }, TestKey.DOWN_ARROW);\n await this.waitForTasksOutsideAngular();\n }\n\n /**\n * Closes the panel with `Alt+ArrowUp`. No-op when already closed.\n *\n * Deliberately not Escape: Escape *also* reverts the input text to the last\n * committed label, which would make `close()` silently destroy a typed query.\n *\n * The overlay runs a leave animation before it detaches, so `isOpen()` flips\n * to `false` immediately while the panel element lingers for a few more\n * frames. Two consequences worth knowing:\n *\n * - Do not assert `getOptions()` is empty on the tick after a close; the\n * old panel is still mounted.\n * - An `open()` inside that window does **not** attach a fresh panel — the\n * component sees an overlay ref it has not disposed yet and silently\n * keeps the outgoing one. Let the animation finish before reopening.\n */\n async close(): Promise<void> {\n if (!(await this.isOpen())) return;\n await (await this.input()).sendKeys({ alt: true }, TestKey.UP_ARROW);\n await this.waitForTasksOutsideAngular();\n }\n\n /**\n * Every option in the open panel, in render order and already filtered by\n * whatever query the input holds. Returns an empty array when the panel has\n * never been opened, because the overlay is disposed rather than hidden.\n */\n async getOptions(\n filters: ComboboxOptionHarnessFilters = {},\n ): Promise<ComboboxOptionHarness[]> {\n if (!(await this.panel())) return [];\n return this.documentRootLocatorFactory().locatorForAll(\n ComboboxOptionHarness.with(filters),\n )();\n }\n\n /**\n * The text of every option currently rendered in the open panel. Opens the\n * panel if needed — this is how a consumer reads the result of a filter\n * query.\n */\n async getOptionTexts(): Promise<string[]> {\n await this.open();\n const options = await this.getOptions();\n return Promise.all(options.map((option) => option.getText()));\n }\n\n /**\n * Opens the panel if needed and clicks the first option whose text matches.\n * Throws when nothing matches, rather than failing silently.\n */\n async selectOption(text: string | RegExp): Promise<void> {\n await this.open();\n const matches = await this.getOptions({ text });\n if (matches.length === 0) {\n throw new Error(\n `ComboboxHarness.selectOption: no option matching ${String(text)}.`,\n );\n }\n await matches[0].click();\n await this.waitForTasksOutsideAngular();\n }\n\n /**\n * Whether the inline clear control is rendered. It appears only while\n * `clearable` is on, the combobox is enabled, and the input is non-empty.\n */\n async hasClearButton(): Promise<boolean> {\n return (await this.clearButton()) !== null;\n }\n\n /** Clicks the clear control. Throws when none is rendered. */\n async clear(): Promise<void> {\n const button: TestElement | null = await this.clearButton();\n if (!button) {\n throw new Error(\n 'ComboboxHarness.clear: no clear control is rendered. It appears only while `clearable` is on, the combobox is enabled, and the input is non-empty.',\n );\n }\n await button.click();\n await this.waitForTasksOutsideAngular();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAaA;;;;;;;;;;;AAWG;AACG,MAAO,qBAAsB,SAAQ,gBAAgB,CAAA;AACzD,IAAA,OAAO,YAAY,GAAG,iBAAiB;;AAGvC,IAAA,OAAO,IAAI,CACT,OAAA,GAAwC,EAAE,EAAA;AAE1C,QAAA,OAAO,IAAI,gBAAgB,CAAC,qBAAqB,EAAE,OAAO;aACvD,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,KAC7C,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC;aAExD,SAAS,CACR,UAAU,EACV,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,EAAE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,QAAQ;aAE3D,SAAS,CACR,UAAU,EACV,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,EAAE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,QAAQ,CAC3D;IACL;AAEA;;;;AAIG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE;IAClD;;AAGA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC7E;;AAGA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC7E;;AAGA,IAAA,MAAM,KAAK,GAAA;QACT,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACnC;;;ACrDF;;;;;;;;;;;;AAYG;AACG,MAAO,eAAgB,SAAQ,gBAAgB,CAAA;AACnD,IAAA,OAAO,YAAY,GAAG,aAAa;AAElB,IAAA,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC;AAClE;;;AAGG;AACc,IAAA,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,4BAA4B,CAAC;;IAEnE,KAAK,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC,kBAAkB,CAC3E,kBAAkB,CACnB;;AAGD,IAAA,OAAO,IAAI,CAAC,OAAA,GAAkC,EAAE,EAAA;AAC9C,QAAA,OAAO,IAAI,gBAAgB,CAAC,eAAe,EAAE,OAAO;aACjD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,KAAK,KAChD,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC;aAE1D,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,KAAK,KAC1D,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,EAAE,KAAK,CAAC;aAE/D,SAAS,CACR,UAAU,EACV,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,EAAE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,QAAQ,CAC3D;IACL;;AAGA,IAAA,MAAM,QAAQ,GAAA;AACZ,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC;IACxD;AAEA;;;;AAIG;AACH,IAAA,MAAM,aAAa,GAAA;AACjB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAS,OAAO,CAAC;IAC1D;;AAGA,IAAA,MAAM,cAAc,GAAA;AAClB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,aAAa,CAAC;IACzD;AAEA;;;;;;AAMG;IACH,MAAM,aAAa,CAAC,KAAa,EAAA;AAC/B,QAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE;AAChC,QAAA,MAAM,KAAK,CAAC,KAAK,EAAE;AACnB,QAAA,MAAM,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;;;AAGhC,QAAA,MAAM,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC;AAClC,QAAA,MAAM,IAAI,CAAC,0BAA0B,EAAE;IACzC;;AAGA,IAAA,MAAM,MAAM,GAAA;AACV,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC9E;;AAGA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC9E;;AAGA,IAAA,MAAM,SAAS,GAAA;AACb,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,cAAc,CAAC,MAAM,MAAM;IAC7E;AAEA;;;AAGG;AACH,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC9E;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,IAAI,GAAA;AACR,QAAA,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE;YAAE;QACzB,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC;AACtE,QAAA,MAAM,IAAI,CAAC,0BAA0B,EAAE;IACzC;AAEA;;;;;;;;;;;;;;;AAeG;AACH,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,IAAI,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YAAE;QAC5B,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC;AACpE,QAAA,MAAM,IAAI,CAAC,0BAA0B,EAAE;IACzC;AAEA;;;;AAIG;AACH,IAAA,MAAM,UAAU,CACd,OAAA,GAAwC,EAAE,EAAA;AAE1C,QAAA,IAAI,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;AAAE,YAAA,OAAO,EAAE;AACpC,QAAA,OAAO,IAAI,CAAC,0BAA0B,EAAE,CAAC,aAAa,CACpD,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CACpC,EAAE;IACL;AAEA;;;;AAIG;AACH,IAAA,MAAM,cAAc,GAAA;AAClB,QAAA,MAAM,IAAI,CAAC,IAAI,EAAE;AACjB,QAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;AACvC,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D;AAEA;;;AAGG;IACH,MAAM,YAAY,CAAC,IAAqB,EAAA;AACtC,QAAA,MAAM,IAAI,CAAC,IAAI,EAAE;QACjB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC;AAC/C,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;YACxB,MAAM,IAAI,KAAK,CACb,CAAA,iDAAA,EAAoD,MAAM,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CACpE;QACH;AACA,QAAA,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AACxB,QAAA,MAAM,IAAI,CAAC,0BAA0B,EAAE;IACzC;AAEA;;;AAGG;AACH,IAAA,MAAM,cAAc,GAAA;QAClB,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI;IAC5C;;AAGA,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,MAAM,MAAM,GAAuB,MAAM,IAAI,CAAC,WAAW,EAAE;QAC3D,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CACb,oJAAoJ,CACrJ;QACH;AACA,QAAA,MAAM,MAAM,CAAC,KAAK,EAAE;AACpB,QAAA,MAAM,IAAI,CAAC,0BAA0B,EAAE;IACzC;;;ACrNF;;AAEG;;;;"}
|