@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,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
|
-
/**
|
|
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
|
-
|
|
117
|
-
private readonly
|
|
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
|
-
|
|
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
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
/**
|
|
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
|
|
16
|
-
/**
|
|
17
|
-
|
|
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
|
|
45
|
+
attribute?: string;
|
|
20
46
|
/** Which element receives the theme attribute. Defaults to `'documentElement'`. */
|
|
21
|
-
target
|
|
47
|
+
target?: 'documentElement' | 'body';
|
|
22
48
|
}
|
|
23
|
-
/**
|
|
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
|
|
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
|
-
/**
|
|
39
|
-
|
|
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
|
|
44
|
-
* `localStorage`, and writes the resolved theme onto the
|
|
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'`.
|
|
50
|
-
*
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
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
|
-
|
|
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 };
|