@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,135 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /** Filters accepted by `TagsInputTagHarness.with`. */
4
+ interface TagsInputTagHarnessFilters extends BaseHarnessFilters {
5
+ /** Match by the chip's visible label. */
6
+ text?: string | RegExp;
7
+ }
8
+ /**
9
+ * Harness for a single committed chip inside a `tw-tags-input`.
10
+ *
11
+ * Chips are rendered by composing `[twBadge]`, so that attribute is the host
12
+ * selector. Reach these through {@link TagsInputHarness.getTags} rather than
13
+ * locating them directly against a fixture — located from a document root the
14
+ * selector would also match every unrelated badge on the page.
15
+ */
16
+ declare class TagsInputTagHarness extends ComponentHarness {
17
+ static hostSelector: string;
18
+ /**
19
+ * The chip's remove control. It is the only `<button>` a chip contains: the
20
+ * badge's own `dismissible` button is not enabled here, so this always
21
+ * resolves to the tags-input remove control.
22
+ */
23
+ private readonly removeButton;
24
+ /** Predicate for `locatorFor` / `locatorForAll`. */
25
+ static with(options?: TagsInputTagHarnessFilters): HarnessPredicate<TagsInputTagHarness>;
26
+ /**
27
+ * The chip's visible label, trimmed. This is `tagLabel(tag)`, not the tag
28
+ * value — for object tags the two differ.
29
+ */
30
+ getText(): Promise<string>;
31
+ /**
32
+ * The remove control's accessible name (`Remove <label>`). Useful for
33
+ * asserting the control is announced, which is the only signal a screen
34
+ * reader gets for a chip.
35
+ */
36
+ getRemoveLabel(): Promise<string | null>;
37
+ /**
38
+ * Clicks the chip's remove control. The component restores focus to the
39
+ * neighbouring chip (or the text input when none remain), so the caller may
40
+ * assert focus immediately afterwards.
41
+ */
42
+ remove(): Promise<void>;
43
+ }
44
+
45
+ /** Filters accepted by `TagsInputHarness.with`. */
46
+ interface TagsInputHarnessFilters extends BaseHarnessFilters {
47
+ /** Match by the control's accessible name (its `aria-label`). */
48
+ label?: string | RegExp;
49
+ /** Match disabled / enabled controls. */
50
+ disabled?: boolean;
51
+ }
52
+ /**
53
+ * Harness for `tw-tags-input`.
54
+ *
55
+ * The control renders committed tags as chips followed by a single text input;
56
+ * everything lives inside the `tw-tags-input` host, so no overlay handling is
57
+ * needed and the ordinary fixture loader is enough.
58
+ *
59
+ * Note where the ARIA lives: the host is a `role="group"`, which ARIA 1.2 does
60
+ * not allow to carry `aria-required` / `aria-invalid`, so those sit on the
61
+ * inner text input — the element that actually owns the pending value.
62
+ * {@link isRequired} and {@link isInvalid} read them from there;
63
+ * {@link isDisabled} reads `aria-disabled` from the group, which is allowed.
64
+ */
65
+ declare class TagsInputHarness extends ComponentHarness {
66
+ static hostSelector: string;
67
+ private readonly textInput;
68
+ /** Predicate for `locatorFor` / `locatorForAll`. */
69
+ static with(options?: TagsInputHarnessFilters): HarnessPredicate<TagsInputHarness>;
70
+ /** The control's accessible name, from `aria-label` when one is set. */
71
+ getLabel(): Promise<string | null>;
72
+ /** Whether the group reports `aria-disabled="true"`. */
73
+ isDisabled(): Promise<boolean>;
74
+ /** Whether the text input reports `aria-required="true"`. */
75
+ isRequired(): Promise<boolean>;
76
+ /** Whether the text input reports `aria-invalid="true"`. */
77
+ isInvalid(): Promise<boolean>;
78
+ /**
79
+ * Every committed chip, in render order. Remove by index by indexing this
80
+ * array — `(await input.getTags())[1].remove()` — which is why no
81
+ * `removeTagAt(index)` exists.
82
+ */
83
+ getTags(filters?: TagsInputTagHarnessFilters): Promise<TagsInputTagHarness[]>;
84
+ /** The visible label of every committed chip, in render order. */
85
+ getTagTexts(): Promise<string[]>;
86
+ /** The in-progress (uncommitted) text currently in the input. */
87
+ getInputValue(): Promise<string>;
88
+ /**
89
+ * Types `text` into the input and commits it with Enter. Typing appends, so
90
+ * any pending text already in the input is committed along with it.
91
+ *
92
+ * Enter is the commit gesture only while `separatorKeys` contains `'Enter'`
93
+ * (the default). A control configured with, say, `[separatorKeys]="[';']"`
94
+ * commits through {@link typeInput} instead — `typeInput('alpha;')`.
95
+ *
96
+ * The commit may be dropped by the component (empty, duplicate, or `maxTags`
97
+ * reached); assert against {@link getTagTexts} rather than assuming it
98
+ * landed.
99
+ */
100
+ addTag(text: string): Promise<void>;
101
+ /**
102
+ * Types `text` into the input character by character, appending to whatever
103
+ * is already there. Use it to stage pending text that {@link addTag} would
104
+ * commit for you — reading it back, discarding it, or letting `addOnBlur`
105
+ * pick it up.
106
+ *
107
+ * A separator character in `text` does commit the text before it, but CDK's
108
+ * synthetic typing appends every character to the input regardless of the
109
+ * component's `preventDefault()`, so the separator itself is left behind in
110
+ * the input where a real browser swallows it. Commit with {@link addTag},
111
+ * and treat a trailing separator here as staging, not as a commit gesture.
112
+ */
113
+ typeInput(text: string): Promise<void>;
114
+ /**
115
+ * Removes the first chip whose label matches. Throws when nothing matches,
116
+ * rather than failing silently.
117
+ */
118
+ removeTag(text: string | RegExp): Promise<void>;
119
+ /**
120
+ * Discards the in-progress text with Escape — the control's own clear
121
+ * gesture. A no-op when the input is already empty. Does not touch committed
122
+ * chips.
123
+ */
124
+ clearInput(): Promise<void>;
125
+ /** Moves focus to the text input. */
126
+ focus(): Promise<void>;
127
+ /**
128
+ * Moves focus out of the control. This is the gesture that marks the control
129
+ * touched and, with `addOnBlur`, commits the pending text.
130
+ */
131
+ blur(): Promise<void>;
132
+ }
133
+
134
+ export { TagsInputHarness, TagsInputTagHarness };
135
+ export type { TagsInputHarnessFilters, TagsInputTagHarnessFilters };
@@ -59,7 +59,7 @@ declare class TagsInputComponent<T = string> extends FormFieldControl<T[]> imple
59
59
  readonly disabledInput: _angular_core.InputSignal<boolean>;
60
60
  /** Marks the control as required. Mirrored to the input's `aria-required`. Also inferred from `Validators.required` on a bound control. Defaults to `false`. */
61
61
  readonly requiredInput: _angular_core.InputSignal<boolean>;
62
- /** Placeholder shown in the text input only while there are no chips and the input is empty. */
62
+ /** Placeholder shown in the text input only while there are no chips and the input is empty. Defaults to `undefined`. */
63
63
  readonly placeholder: _angular_core.InputSignal<string | undefined>;
64
64
  /** Keys that commit the in-progress text as a tag. Each entry is a `KeyboardEvent.key` value (`'Enter'`) or a single separator character (`','`). Single-character separators also split pasted text. Defaults to `['Enter', ',']`. */
65
65
  readonly separatorKeys: _angular_core.InputSignal<readonly string[]>;
@@ -75,19 +75,30 @@ declare class TagsInputComponent<T = string> extends FormFieldControl<T[]> imple
75
75
  readonly tagLabel: _angular_core.InputSignal<TwTagLabelFn<T>>;
76
76
  /** Equality comparator used for dedup when `allowDuplicates` is false. Defaults to `Object.is` (reference / value identity). String tags dedupe case-sensitively by default; pass `(a, b) => a.toLowerCase() === b.toLowerCase()` for case-insensitive dedup. */
77
77
  readonly compareWith: _angular_core.InputSignal<TwTagCompareFn<T>>;
78
- /** Applied to the text input for labeling and identification only; does not submit the tag array via native (non-Angular) form posting. */
78
+ /** Applied to the text input for labeling and identification only; does not submit the tag array via native (non-Angular) form posting. Defaults to `undefined`. */
79
79
  readonly name: _angular_core.InputSignal<string | undefined>;
80
80
  /** Id on the host element. Auto-generated as `tw-tags-input-N` when not provided. Used by the form-field's `<label for>` association. */
81
81
  readonly idInput: _angular_core.InputSignal<string | undefined>;
82
- /** Accessible name applied to the control when no visible label is wired. Mirrored to `aria-label`. */
82
+ /** Accessible name applied to the control when no visible label is wired. Mirrored to `aria-label`. Defaults to `undefined`. */
83
83
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
84
- /** ID of an external element that labels the control. Mirrored to `aria-labelledby`. */
84
+ /** ID of an external element that labels the control. Mirrored to `aria-labelledby`. Defaults to `undefined`. */
85
85
  readonly ariaLabelledby: _angular_core.InputSignal<string | undefined>;
86
- /** ID of an external element that describes the control. Form-field merges its hint / error ids alongside. */
86
+ /** ID of an external element that describes the control. Form-field merges its hint / error ids alongside. Defaults to `undefined`. Alias: `aria-describedby`. */
87
87
  readonly ariaDescribedby: _angular_core.InputSignal<string | undefined>;
88
88
  /** Per-instance override of the {@link ErrorStateMatcher}. When omitted, uses the `TW_ERROR_STATE_MATCHER` token's value. */
89
89
  readonly errorStateMatcher: _angular_core.InputSignal<ErrorStateMatcher | undefined>;
90
- /** Fires when the tag array changes through user interaction (add, remove, clear). Emits a fresh array reference. Does not fire on `writeValue`. */
90
+ /**
91
+ * Fires when the tag array changes through user interaction (add, remove,
92
+ * clear). Emits a fresh array reference. Does **not** fire on `writeValue` /
93
+ * `FormControl.setValue` / `ngModel`.
94
+ *
95
+ * This is a hand-written, user-gesture-only output. The control exposes no
96
+ * `value` input and therefore no two-way binding, so — unlike
97
+ * `tw-checkbox` / `tw-switch` / `tw-radio-group`, where `(valueChange)` /
98
+ * `(checkedChange)` is minted by a `model()` and fires on programmatic writes
99
+ * too — there is no any-change channel here. Observe programmatic writes
100
+ * through the bound form control's own `valueChanges`.
101
+ */
91
102
  readonly valueChange: _angular_core.OutputEmitterRef<T[]>;
92
103
  /** Fires when a tag is committed via Enter, a separator key, paste, or `addTag()`. Does not fire for dropped duplicates, blocked-by-max commits, empty commits, or `writeValue`. */
93
104
  readonly tagAdded: _angular_core.OutputEmitterRef<TwTagAddedEvent<T>>;
@@ -98,10 +109,14 @@ declare class TagsInputComponent<T = string> extends FormFieldControl<T[]> imple
98
109
  private readonly elementRef;
99
110
  private readonly destroyRef;
100
111
  private readonly ngControl;
101
- private readonly parentForm;
102
- private readonly parentFormGroup;
103
- private readonly defaultMatcher;
104
112
  private readonly formField;
113
+ /**
114
+ * Optional so a consumer that never imports `BidiModule` still gets a working
115
+ * control — chip navigation falls back to LTR when the token is absent. Read
116
+ * imperatively inside the keydown handlers; nothing here needs to re-render
117
+ * on a direction change.
118
+ */
119
+ private readonly directionality;
105
120
  private readonly textInputRef;
106
121
  private readonly removeButtons;
107
122
  private onChange;
@@ -113,8 +128,8 @@ declare class TagsInputComponent<T = string> extends FormFieldControl<T[]> imple
113
128
  protected readonly activeChipIndex: _angular_core.WritableSignal<number | null>;
114
129
  private readonly cvaDisabled;
115
130
  private readonly _focused;
116
- private readonly _ngControlRev;
117
- private readonly _formSubmitRev;
131
+ /** @internal Shared `errorState` / `required` / `errors` derivation — see `wireErrorState`. */
132
+ private readonly errorWiring;
118
133
  private readonly describedByIdsSignal;
119
134
  private readonly labelledByIdsSignal;
120
135
  /** Nonce bumped only on explicit focus intent — keeps the focus effect from stealing focus on unrelated renders. */
@@ -33,7 +33,8 @@ type TwTextareaResize = 'none' | 'vertical' | 'both';
33
33
  */
34
34
  declare class TextareaDirective extends InputDirective {
35
35
  private readonly cdkAutosize;
36
- /** Density of a standalone textarea. Maps to the inline-padding + font scale (`xs` … `xl`). Ignored inside a `<tw-form-field>` — the wrapper's `size` carries density. Defaults to `'md'`. */
36
+ private readonly parentFormField;
37
+ /** Density of a standalone textarea. Maps to the inline-padding + font scale (`xs` … `xl`) and to a `min-h-*` floor on the control-height scale (24/32/36/44/48px) — a floor, not a fixed height, because a textarea must grow with its content. The floor is dropped while `autosize` is on (CDK owns the height then; `minRows` is the floor). Ignored inside a `<tw-form-field>` — the wrapper's `size` carries density. Defaults to `'md'`. */
37
38
  readonly size: _angular_core.InputSignal<TwSize>;
38
39
  /** Grows the textarea with its content (composed from CDK's `CdkTextareaAutosize`). When `true` the user-resize handle is forced off — autosize owns the height. Defaults to `false`. */
39
40
  readonly autosize: _angular_core.InputSignalWithTransform<boolean, unknown>;
@@ -49,7 +50,7 @@ declare class TextareaDirective extends InputDirective {
49
50
  readonly maxLength: _angular_core.InputSignalWithTransform<number | undefined, unknown>;
50
51
  /** Current value length, updates on every `input` event. Wire `<span twHint align="end">{{ ta.valueLength() }} / {{ ta.maxLength() }}</span>` for a character counter. */
51
52
  readonly valueLength: Signal<number>;
52
- /** @internal Textarea-specific Tailwind classes (resize axis). Combined with the inherited `classes()` in the host `[class]` binding. */
53
+ /** @internal Textarea-specific Tailwind classes (resize axis + control-height floor). Combined with the inherited `classes()` in the host `[class]` binding — the two strings never emit conflicting utilities, so concatenating them needs no cross-config merge. */
53
54
  readonly textareaClasses: Signal<string>;
54
55
  constructor();
55
56
  /** Triggers a CDK autosize recalculation. Useful after programmatic value changes that bypass the native `(input)` event (e.g., clipboard write APIs). No-op when `autosize` is `false`. */
@@ -1,84 +1,195 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { OnDestroy, InjectionToken, EnvironmentProviders } from '@angular/core';
3
3
 
4
- /** The user-selectable theme. `'system'` defers to the OS `prefers-color-scheme` setting. */
5
- type TwTheme = 'light' | 'dark' | 'high-contrast' | 'system';
6
- /** The theme actually applied to the DOM after resolving `'system'` against the OS preference. */
7
- type TwResolvedTheme = 'light' | 'dark' | 'high-contrast';
4
+ /**
5
+ * The user-selectable theme. `'system'` defers to the OS, resolving
6
+ * `prefers-color-scheme` and `prefers-contrast` as two independent axes: dark
7
+ * plus increased contrast lands on `'high-contrast-dark'`, light plus increased
8
+ * contrast on `'high-contrast'`.
9
+ */
10
+ type TwTheme = 'light' | 'dark' | 'high-contrast' | 'high-contrast-dark' | 'system';
11
+ /**
12
+ * The theme actually applied to the DOM after resolving `'system'` against the
13
+ * OS preference.
14
+ *
15
+ * The two axes are appearance (light / dark) and contrast (normal / increased),
16
+ * so the four values are their product: `'high-contrast'` is the light-based
17
+ * increased-contrast scheme and `'high-contrast-dark'` the dark-based one.
18
+ */
19
+ type TwResolvedTheme = 'light' | 'dark' | 'high-contrast' | 'high-contrast-dark';
8
20
  /** Ordered list of every {@link TwTheme} value, used by `cycleTheme()` and for UI iteration. */
9
- declare const TW_THEMES: readonly ["light", "dark", "high-contrast", "system"];
21
+ declare const TW_THEMES: readonly ["light", "dark", "high-contrast", "high-contrast-dark", "system"];
10
22
  /** Ordered list of every {@link TwResolvedTheme} value (i.e. {@link TW_THEMES} minus `'system'`). */
11
- declare const TW_RESOLVED_THEMES: readonly ["light", "dark", "high-contrast"];
12
- /** Runtime configuration for {@link provideTheme}; controls storage, attribute name, target element, and default. */
23
+ declare const TW_RESOLVED_THEMES: readonly ["light", "dark", "high-contrast", "high-contrast-dark"];
24
+ /**
25
+ * Runtime configuration for {@link provideTheme}; controls storage, attribute
26
+ * name, target element, and default.
27
+ *
28
+ * Every member is optional. This interface only ever reaches consumers through
29
+ * `provideTheme(config?: Partial<TwThemeConfig>)`, which fills each unset key
30
+ * from {@link DEFAULT_TW_THEME_CONFIG} — so a consumer holding a config object
31
+ * typed as `TwThemeConfig` must not be forced to restate keys they do not
32
+ * override, and adding a member in a future minor must not break them. The
33
+ * resolved value handed to {@link TW_THEME_CONFIG} is `Required<TwThemeConfig>`.
34
+ */
13
35
  interface TwThemeConfig {
14
36
  /** The default theme when no preference is stored. Defaults to `'system'`. */
15
- defaultTheme: TwTheme;
16
- /** localStorage key for persisting theme preference. Defaults to `'ngx-tw-theme'`. */
17
- storageKey: string;
37
+ defaultTheme?: TwTheme;
38
+ /**
39
+ * localStorage key for persisting an explicit theme choice. Defaults to
40
+ * `'ngx-tw-theme'`. Only `setTheme()` / `cycleTheme()` write it — providing
41
+ * the service never does.
42
+ */
43
+ storageKey?: string;
18
44
  /** The HTML attribute written to the target element. Defaults to `'data-theme'`. */
19
- attribute: string;
45
+ attribute?: string;
20
46
  /** Which element receives the theme attribute. Defaults to `'documentElement'`. */
21
- target: 'documentElement' | 'body';
47
+ target?: 'documentElement' | 'body';
22
48
  }
23
- /** Composite snapshot of `ThemeService` state — selected, resolved, system, and boolean flags. */
49
+ /**
50
+ * Composite snapshot of `ThemeService` state — selected, resolved, system, and
51
+ * boolean flags.
52
+ *
53
+ * The three flags are **not** mutually exclusive: `'high-contrast-dark'` sets
54
+ * both {@link isDark} and {@link isHighContrast}, because it is dark *and*
55
+ * high contrast. Branch on {@link resolvedTheme} when you need one case.
56
+ */
24
57
  interface TwThemeState {
25
58
  /** The user-selected theme — may be `'system'`. */
26
59
  readonly theme: TwTheme;
27
60
  /** The theme actually applied to the DOM — never `'system'`. */
28
61
  readonly resolvedTheme: TwResolvedTheme;
29
- /** The OS color-scheme preference detected via `prefers-color-scheme`. */
62
+ /** The OS appearance preference detected via `prefers-color-scheme` and `prefers-contrast`. */
30
63
  readonly systemTheme: TwResolvedTheme;
31
- /** True when {@link resolvedTheme} is `'dark'`. */
64
+ /** True when {@link resolvedTheme} is a dark scheme — `'dark'` or `'high-contrast-dark'`. */
32
65
  readonly isDark: boolean;
33
- /** True when {@link resolvedTheme} is `'light'`. */
66
+ /** True when {@link resolvedTheme} is exactly `'light'`; the light-based `'high-contrast'` does not set it. */
34
67
  readonly isLight: boolean;
35
- /** True when {@link resolvedTheme} is `'high-contrast'`. */
68
+ /** True when {@link resolvedTheme} is an increased-contrast scheme — `'high-contrast'` or `'high-contrast-dark'`. */
36
69
  readonly isHighContrast: boolean;
37
70
  }
38
- /** Built-in defaults merged under any user-provided {@link TwThemeConfig} by `provideTheme()`. */
39
- declare const DEFAULT_TW_THEME_CONFIG: TwThemeConfig;
71
+ /**
72
+ * Built-in defaults merged under any user-provided {@link TwThemeConfig} by
73
+ * `provideTheme()`. Typed `Required<TwThemeConfig>` so readers keep a
74
+ * non-optional `string` / `TwTheme` for every field even though the interface
75
+ * itself is all-optional.
76
+ */
77
+ declare const DEFAULT_TW_THEME_CONFIG: Required<TwThemeConfig>;
40
78
 
41
79
  /**
42
80
  * Stateful runtime service that owns the active theme, reacts to OS
43
- * `prefers-color-scheme` changes, persists the user selection to
44
- * `localStorage`, and writes the resolved theme onto the configured DOM
45
- * target as a `data-theme` attribute.
81
+ * `prefers-color-scheme` / `prefers-contrast` changes, persists an explicit
82
+ * user selection to `localStorage`, and writes the resolved theme onto the
83
+ * configured DOM target as a `data-theme` attribute.
46
84
  *
47
85
  * The selected {@link theme} may be `'system'` (defer to the OS); the
48
86
  * {@link resolvedTheme} computed from it is always one of `'light'`,
49
- * `'dark'`, or `'high-contrast'` — never `'system'`. Register via
50
- * {@link provideTheme} in the app's environment providers.
87
+ * `'dark'`, `'high-contrast'`, or `'high-contrast-dark'` — never `'system'`.
88
+ * Register via
89
+ * {@link provideTheme} in the app's environment providers; `provideTheme`
90
+ * also constructs the service at bootstrap, so injecting it is only needed
91
+ * to read or change the theme.
92
+ *
93
+ * Storage is written **only** by {@link setTheme} / {@link cycleTheme}.
94
+ * Merely providing the service never touches `localStorage`, so the
95
+ * configured `defaultTheme` keeps applying until the user actually picks
96
+ * something, and apps under a storage-consent flow can provide the service
97
+ * before consent is granted.
51
98
  */
52
99
  declare class ThemeService implements OnDestroy {
53
100
  private readonly config;
54
101
  private readonly document;
55
102
  private readonly isBrowser;
56
103
  private readonly ngZone;
57
- private mediaQuery;
104
+ private darkQuery;
105
+ private contrastQuery;
58
106
  private readonly mediaListener;
59
107
  /** The user-selected theme (may be `'system'`). */
60
108
  readonly theme: _angular_core.WritableSignal<TwTheme>;
61
- /** The OS color scheme preference. */
109
+ /** The OS appearance preference — `prefers-color-scheme` plus `prefers-contrast`. */
62
110
  readonly systemTheme: _angular_core.WritableSignal<TwResolvedTheme>;
63
111
  /** The resolved theme actually applied to the DOM (never `'system'`). */
64
112
  readonly resolvedTheme: _angular_core.Signal<TwResolvedTheme>;
65
- /** True when the resolved theme is `'dark'`. */
113
+ /**
114
+ * True when the resolved theme is a **dark** scheme — `'dark'` or
115
+ * `'high-contrast-dark'`.
116
+ *
117
+ * It answers the appearance question, not "which scheme": the canonical use
118
+ * is picking a colour that has to sit on the page background (a chart grid,
119
+ * a canvas fill), and dark high contrast needs the dark answer there just as
120
+ * much as plain dark does. It is therefore **not** mutually exclusive with
121
+ * {@link isHighContrast}; branch on {@link resolvedTheme} for one case.
122
+ */
66
123
  readonly isDark: _angular_core.Signal<boolean>;
67
- /** True when the resolved theme is `'light'`. */
124
+ /**
125
+ * True when the resolved theme is exactly `'light'`.
126
+ *
127
+ * Deliberately narrower than {@link isDark}'s mirror image: the light-based
128
+ * `'high-contrast'` does **not** set it, because widening it would change
129
+ * what a shipped scheme reports to consumers already reading this flag.
130
+ * Use `!isDark()` for the appearance question.
131
+ */
68
132
  readonly isLight: _angular_core.Signal<boolean>;
69
- /** True when the resolved theme is `'high-contrast'`. */
133
+ /**
134
+ * True when the resolved theme is an **increased-contrast** scheme —
135
+ * `'high-contrast'` or `'high-contrast-dark'`.
136
+ *
137
+ * It answers the contrast question, so it can be true at the same time as
138
+ * {@link isDark}.
139
+ */
70
140
  readonly isHighContrast: _angular_core.Signal<boolean>;
71
141
  /** Snapshot of the full theme state — selected, resolved, system, and boolean flags. */
72
142
  readonly state: _angular_core.Signal<TwThemeState>;
73
143
  constructor();
74
- /** Sets the selected theme. Pass `'system'` to follow the OS preference. */
144
+ /**
145
+ * Sets the selected theme and persists it. Pass `'system'` to follow the OS
146
+ * preference.
147
+ *
148
+ * This is the only entry point that writes to `localStorage` — see the note
149
+ * on the class.
150
+ */
75
151
  setTheme(theme: TwTheme): void;
76
- /** Advances the selected theme to the next entry in {@link TW_THEMES}, wrapping around. */
152
+ /** Advances the selected theme to the next entry in {@link TW_THEMES}, wrapping around, and persists it. */
77
153
  cycleTheme(): void;
78
- /** Writes the configured theme attribute onto an arbitrary element — used to scope themes to a subtree. */
154
+ /**
155
+ * Writes the configured theme attribute onto an arbitrary element, scoping
156
+ * that subtree to the given theme.
157
+ *
158
+ * Each of the four schemes ships an element-agnostic `[data-theme=…]` block
159
+ * (`_light.css`, `_dark.css`, `_high-contrast.css`,
160
+ * `_high-contrast-dark.css`), so the tokens really do re-resolve on the
161
+ * element and cascade into its descendants — including back to `'light'`
162
+ * from inside a dark page.
163
+ *
164
+ * Caveat: those CSS blocks key off the literal `data-theme` attribute. If
165
+ * `provideTheme({ attribute })` renamed it, this method writes the renamed
166
+ * attribute and the shipped stylesheet will not react — a custom attribute
167
+ * only works with matching custom CSS.
168
+ */
79
169
  applyToElement(element: HTMLElement, theme: TwResolvedTheme): void;
80
170
  ngOnDestroy(): void;
81
171
  private loadInitialTheme;
172
+ /**
173
+ * Resolves `'system'` against the OS.
174
+ *
175
+ * The two preferences are treated as independent axes and composed, not
176
+ * ranked: `prefers-color-scheme` picks the appearance and
177
+ * `prefers-contrast: more` picks the contrast, giving the full 2×2 —
178
+ * `light` / `dark` / `high-contrast` / `high-contrast-dark`.
179
+ *
180
+ * This is only correct because the library ships **both** high-contrast
181
+ * ramps. While `_high-contrast.css` was the only one, contrast had to be
182
+ * suppressed whenever the OS also asked for dark, or a user running dark +
183
+ * increased contrast — a common pairing — would have been moved from a dark
184
+ * surface onto a white one. `_high-contrast-dark.css` removed that
185
+ * constraint, so the ranking is gone; if a future change ever drops one of
186
+ * the two ramps, this method has to go back to ranking them.
187
+ *
188
+ * Both queries are minted here (not in the constructor) because the
189
+ * `systemTheme` field initialiser calls this before the constructor body
190
+ * runs; the constructor then attaches `change` listeners to the same two
191
+ * objects, so the resolution stays live rather than read-once.
192
+ */
82
193
  private detectSystemTheme;
83
194
  private applyToDocument;
84
195
  private persistTheme;
@@ -87,20 +198,115 @@ declare class ThemeService implements OnDestroy {
87
198
  }
88
199
 
89
200
  declare class ThemeDirective {
90
- /** Scopes a subtree to a specific resolved theme by writing `data-theme` on the host. Required. */
201
+ /**
202
+ * Scopes a subtree to a specific resolved theme by writing `data-theme` on
203
+ * the host. Required.
204
+ *
205
+ * Works in every direction: each of the four schemes ships an
206
+ * element-agnostic `[data-theme="…"]` block (`_light.css`, `_dark.css`,
207
+ * `_high-contrast.css`, `_high-contrast-dark.css`), so a `'light'` pane
208
+ * inside a dark page re-resolves the tokens rather than inheriting the
209
+ * ancestor's.
210
+ *
211
+ * The attribute name is the literal `data-theme` that the shipped CSS keys
212
+ * off — it deliberately ignores `provideTheme({ attribute })`, since a
213
+ * renamed attribute matches none of those blocks.
214
+ */
91
215
  readonly twTheme: _angular_core.InputSignal<TwResolvedTheme>;
92
216
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThemeDirective, never>;
93
217
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ThemeDirective, "[twTheme]", never, { "twTheme": { "alias": "twTheme"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
94
218
  }
95
219
 
96
- /** Injection token carrying the resolved {@link TwThemeConfig} (storage key, attribute, target element, default theme). */
97
- declare const THEME_CONFIG: InjectionToken<TwThemeConfig>;
98
220
  /**
99
- * Registers {@link ThemeService} and a {@link THEME_CONFIG} value built by
100
- * merging `config` over {@link DEFAULT_TW_THEME_CONFIG}. Call once in the
101
- * app's environment providers.
221
+ * Injection token carrying the resolved {@link TwThemeConfig} (storage key,
222
+ * attribute, target element, default theme).
223
+ *
224
+ * The value is `Required<TwThemeConfig>`: `TwThemeConfig`'s members are
225
+ * optional so consumers can pass a partial config, but `provideTheme` fills
226
+ * every key from {@link DEFAULT_TW_THEME_CONFIG} before providing it. Injectors
227
+ * therefore still read a non-optional field for each setting, exactly as
228
+ * before this token's type was tightened.
229
+ */
230
+ declare const TW_THEME_CONFIG: InjectionToken<Required<TwThemeConfig>>;
231
+ /**
232
+ * @deprecated Renamed to {@link TW_THEME_CONFIG} for consistency with every
233
+ * other ngx-tw injection token. This is the *same token instance*, not a copy —
234
+ * providing under either name and injecting under the other resolves — so the
235
+ * rename is safe to adopt incrementally. Removed in the next major.
236
+ */
237
+ declare const THEME_CONFIG: InjectionToken<Required<TwThemeConfig>>;
238
+ /**
239
+ * Registers {@link ThemeService}, a {@link TW_THEME_CONFIG} value built by merging
240
+ * `config` over {@link DEFAULT_TW_THEME_CONFIG}, and an environment initializer
241
+ * that constructs the service at bootstrap. Call once in the app's environment
242
+ * providers.
243
+ *
244
+ * The initializer is what makes the call self-sufficient. Everything that
245
+ * applies a theme lives in `ThemeService`'s field initialisers and constructor
246
+ * effect, so without it the stored preference was read — and `data-theme`
247
+ * written — only once something happened to `inject(ThemeService)`. An app
248
+ * whose theme toggle sits in a lazily-loaded route therefore rendered every
249
+ * other route with no `data-theme` at all, silently falling back to the
250
+ * `prefers-color-scheme` CSS branch; the failure looked intermittent because
251
+ * it disappeared whenever the stored choice agreed with the OS. Injecting the
252
+ * service yourself is still supported and is idempotent.
253
+ *
254
+ * Keys explicitly set to `undefined` are dropped before merging. Root
255
+ * `tsconfig.json` does not set `exactOptionalPropertyTypes`, so
256
+ * `provideTheme({ storageKey: env.themeKey })` type-checks even when
257
+ * `env.themeKey` is `string | undefined` — and a plain spread would then write
258
+ * `undefined` into a field `TwThemeConfig` types as `string`, making
259
+ * `ThemeService` persist under the literal `localStorage` key `"undefined"`
260
+ * (and, for `attribute`, call `setAttribute("undefined", …)`).
261
+ *
262
+ * Providing the service does **not** write to `localStorage`; only an explicit
263
+ * `setTheme()` / `cycleTheme()` does. For a flash-free first paint when the
264
+ * stored choice disagrees with the OS, pair this with
265
+ * {@link TW_THEME_BOOTSTRAP_SCRIPT} in `index.html`.
102
266
  */
103
267
  declare function provideTheme(config?: Partial<TwThemeConfig>): EnvironmentProviders;
104
268
 
105
- export { DEFAULT_TW_THEME_CONFIG, THEME_CONFIG, TW_RESOLVED_THEMES, TW_THEMES, ThemeDirective, ThemeService, provideTheme };
269
+ /**
270
+ * Body of an inline `<head>` script that applies a previously persisted theme
271
+ * before the app bundle runs, eliminating the flash of the wrong theme on
272
+ * reload.
273
+ *
274
+ * `ThemeService` cannot cover this case: it is JavaScript in the application
275
+ * bundle, so the browser has already painted by the time it writes
276
+ * `data-theme` — and `provideTheme`'s environment initializer does not change
277
+ * that. The CSS `@media (prefers-color-scheme: dark)` fallback covers users
278
+ * who never chose a theme; the flash is what an *explicit* choice that
279
+ * disagrees with the OS looks like — light chosen on a dark machine, or
280
+ * either high-contrast scheme chosen on a machine not already asking for
281
+ * increased contrast (the CSS has a `prefers-color-scheme` branch but
282
+ * deliberately no `prefers-contrast` one, so neither contrast scheme is
283
+ * reachable without an explicit `data-theme`).
284
+ *
285
+ * The string is built from {@link DEFAULT_TW_THEME_CONFIG}, so the storage key
286
+ * and attribute cannot drift from what `ThemeService` actually uses — that
287
+ * drift is the reason this ships as code rather than as a README snippet
288
+ * alone. Copy the literal script into `index.html`, or interpolate this
289
+ * constant during an SSR / index transform:
290
+ *
291
+ * ```html
292
+ * <head>
293
+ * <script>try{var t=localStorage.getItem('ngx-tw-theme');if(t&&t!=='system')document.documentElement.setAttribute('data-theme',t)}catch(e){}</script>
294
+ * </head>
295
+ * ```
296
+ *
297
+ * Notes on the behaviour it deliberately does *not* have:
298
+ * - A stored `'system'` writes nothing, so the CSS `prefers-color-scheme`
299
+ * fallback keeps deciding — which is exactly what `'system'` means.
300
+ * - It assumes the default `target: 'documentElement'`. A `<head>` script runs
301
+ * before `<body>` exists, so `target: 'body'` cannot be bootstrapped this
302
+ * way.
303
+ * - If you overrode `storageKey` or `attribute` via `provideTheme`, adapt the
304
+ * literal snippet to match; this constant only encodes the defaults.
305
+ * - It is dependency-free and wrapped in `try`/`catch`, so a browser with
306
+ * storage blocked falls through to the CSS behaviour instead of throwing
307
+ * before the app loads.
308
+ */
309
+ declare const TW_THEME_BOOTSTRAP_SCRIPT: string;
310
+
311
+ export { DEFAULT_TW_THEME_CONFIG, THEME_CONFIG, TW_RESOLVED_THEMES, TW_THEMES, TW_THEME_BOOTSTRAP_SCRIPT, TW_THEME_CONFIG, ThemeDirective, ThemeService, provideTheme };
106
312
  export type { TwResolvedTheme, TwTheme, TwThemeConfig, TwThemeState };