@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.
Files changed (209) hide show
  1. package/README.md +78 -15
  2. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
  4. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
  5. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
  6. package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
  7. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
  8. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
  9. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
  10. package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
  11. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
  12. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
  13. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
  14. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
  15. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
  16. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
  17. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
  18. package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
  19. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
  20. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
  21. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
  22. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
  23. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
  24. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
  25. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
  26. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
  27. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
  28. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
  29. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
  30. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
  32. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
  33. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
  34. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
  35. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
  36. package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
  37. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
  38. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
  39. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
  40. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
  41. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
  42. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
  43. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
  44. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
  45. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
  46. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
  47. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
  48. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +11 -2
  49. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
  50. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
  51. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
  52. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
  53. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
  54. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
  55. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
  56. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
  57. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
  58. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
  59. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
  60. package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
  61. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
  62. package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
  63. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
  64. package/fesm2022/cdevhub-ngx-tw-item.mjs +28 -4
  65. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
  66. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
  67. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
  68. package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
  69. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
  70. package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
  71. package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
  72. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
  73. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
  74. package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
  75. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
  76. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
  77. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
  78. package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
  79. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
  80. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
  81. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
  82. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
  83. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
  84. package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
  85. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
  86. package/fesm2022/{cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs → cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs} +3 -3
  87. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
  88. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
  89. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
  90. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +23 -7
  91. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
  92. package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
  93. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
  94. package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
  95. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
  96. package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
  97. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
  98. package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
  99. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
  100. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
  101. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
  102. package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
  103. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
  104. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
  105. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
  106. package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
  107. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
  108. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
  109. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
  110. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
  111. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
  112. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
  113. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
  114. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
  115. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
  116. package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
  117. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
  118. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
  119. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
  120. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
  121. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
  122. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
  123. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
  124. package/fesm2022/{cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs → cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs} +107 -19
  125. package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
  126. package/fesm2022/cdevhub-ngx-tw-toast.mjs +21 -13
  127. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
  128. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
  129. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
  130. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
  131. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
  132. package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
  133. package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
  134. package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
  135. package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
  136. package/index.json +1 -1
  137. package/package.json +63 -2
  138. package/theme/_base.css +13 -0
  139. package/theme/_dark.css +111 -36
  140. package/theme/_high-contrast-dark.css +367 -0
  141. package/theme/_high-contrast.css +13 -2
  142. package/theme/_light.css +332 -0
  143. package/theme/_semantic.css +60 -26
  144. package/theme/_typography.css +17 -0
  145. package/theme/index.css +86 -7
  146. package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
  147. package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
  148. package/types/cdevhub-ngx-tw-button.d.ts +1 -0
  149. package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
  150. package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
  151. package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
  152. package/types/cdevhub-ngx-tw-card.d.ts +11 -3
  153. package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
  154. package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
  155. package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
  156. package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
  157. package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
  158. package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
  159. package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
  160. package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
  161. package/types/cdevhub-ngx-tw-core.d.ts +152 -21
  162. package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
  163. package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
  164. package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
  165. package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
  166. package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
  167. package/types/cdevhub-ngx-tw-dialog.d.ts +12 -3
  168. package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
  169. package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
  170. package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
  171. package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
  172. package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
  173. package/types/cdevhub-ngx-tw-input.d.ts +5 -8
  174. package/types/cdevhub-ngx-tw-item.d.ts +2 -0
  175. package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
  176. package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
  177. package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
  178. package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
  179. package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
  180. package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
  181. package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
  182. package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
  183. package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
  184. package/types/cdevhub-ngx-tw-select.d.ts +104 -33
  185. package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
  186. package/types/cdevhub-ngx-tw-sheet.d.ts +19 -3
  187. package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
  188. package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
  189. package/types/cdevhub-ngx-tw-split.d.ts +32 -2
  190. package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
  191. package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
  192. package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
  193. package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
  194. package/types/cdevhub-ngx-tw-table.d.ts +53 -10
  195. package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
  196. package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
  197. package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
  198. package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
  199. package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
  200. package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
  201. package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
  202. package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
  203. package/types/cdevhub-ngx-tw-toast.d.ts +20 -6
  204. package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
  205. package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
  206. package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
  207. package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
  208. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs.map +0 -1
  209. 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":"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"}