@cdevhub/ngx-tw 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +18 -3
- 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 +110 -36
- package/theme/_high-contrast-dark.css +367 -0
- package/theme/_high-contrast.css +13 -2
- package/theme/_light.css +276 -0
- package/theme/_semantic.css +47 -12
- 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
package/theme/_semantic.css
CHANGED
|
@@ -22,10 +22,31 @@
|
|
|
22
22
|
--color-fg-muted: var(--color-gray-600);
|
|
23
23
|
--color-fg-subtle: var(--color-gray-500);
|
|
24
24
|
|
|
25
|
-
/* ===== Border =====
|
|
26
|
-
|
|
25
|
+
/* ===== Border =====
|
|
26
|
+
`--color-border` and `--color-border-strong` carry the boundary that
|
|
27
|
+
IDENTIFIES a control — the outline of an input, a checkbox, a select
|
|
28
|
+
trigger. WCAG 2.2 SC 1.4.11 (Non-text Contrast) requires 3:1 for exactly
|
|
29
|
+
that, and for an unchecked checkbox the border IS the component. Measured
|
|
30
|
+
against `--color-surface`, gray-300 gave 1.47:1 and gray-400 gave 2.60:1,
|
|
31
|
+
so both failed; the values below are the first palette steps that clear
|
|
32
|
+
3:1 (4.84:1 and 7.56:1 in light, 4.16:1 and 7.73:1 in dark).
|
|
33
|
+
(The dark `-strong` figure read 8.59 until 2026-09-03; measured it is
|
|
34
|
+
7.73, and no plausible pairing reproduces 8.59 — gray-400 on gray-900 is
|
|
35
|
+
6.82. The verdict is unchanged: it was and is the first step clearing 3:1.
|
|
36
|
+
Re-measure with `scratchpad/p6-pairs.mjs` rather than estimating.)
|
|
37
|
+
|
|
38
|
+
`--color-border-muted` is deliberately NOT raised. It is the decorative
|
|
39
|
+
divider — ghost-variant footers, subtle rules between rows — and SC 1.4.11
|
|
40
|
+
exempts boundaries that are purely decorative and not needed to identify a
|
|
41
|
+
component or its state. Raising it would darken every hairline in the
|
|
42
|
+
library for no accessibility gain.
|
|
43
|
+
|
|
44
|
+
axe does not catch any of this: its `color-contrast` rule tests TEXT only,
|
|
45
|
+
so these three tokens were invisible to the a11y sweep and were measured
|
|
46
|
+
by hand. See docs/audit-2026-09-register.md. */
|
|
47
|
+
--color-border: var(--color-gray-500);
|
|
27
48
|
--color-border-muted: var(--color-gray-200);
|
|
28
|
-
--color-border-strong: var(--color-gray-
|
|
49
|
+
--color-border-strong: var(--color-gray-600);
|
|
29
50
|
|
|
30
51
|
/* ===== Table sticky shadows =====
|
|
31
52
|
Hairline 1px shadows used to separate sticky table chrome from scrolled
|
|
@@ -36,15 +57,6 @@
|
|
|
36
57
|
--shadow-table-sticky-cell-start: 1px 0 0 0 var(--color-border);
|
|
37
58
|
--shadow-table-sticky-cell-end: -1px 0 0 0 var(--color-border);
|
|
38
59
|
|
|
39
|
-
/* ===== Calendar widths =====
|
|
40
|
-
Pinned per size so month / year / multi-year views share the same footprint
|
|
41
|
-
across view transitions. Each value is roughly `cell-size × 7 + gutters`. */
|
|
42
|
-
--width-calendar-xs: 210px;
|
|
43
|
-
--width-calendar-sm: 240px;
|
|
44
|
-
--width-calendar-md: 292px;
|
|
45
|
-
--width-calendar-lg: 320px;
|
|
46
|
-
--width-calendar-xl: 376px;
|
|
47
|
-
|
|
48
60
|
/* ===== Extra-small typography =====
|
|
49
61
|
Used for xs-density secondary text (xs descriptions, calendar cell labels,
|
|
50
62
|
keyboard hints). Sits one step below Tailwind's `text-xs` (0.75rem).
|
|
@@ -176,6 +188,29 @@
|
|
|
176
188
|
-solid-fg text on -solid (AA body)
|
|
177
189
|
-border subtle border (outline variant, dividers)
|
|
178
190
|
-border-strong accent border (indicators, rings)
|
|
191
|
+
|
|
192
|
+
`-border` reads as "subtle", but it is NOT decorative the way
|
|
193
|
+
`--color-border-muted` is: it is the alert `outline` variant's only
|
|
194
|
+
boundary (`alert.ts:50`, transparent background), so SC 1.4.11's 3:1
|
|
195
|
+
applies to it. The four schemes currently disagree about whether they
|
|
196
|
+
honour that, and the disagreement is deliberate, not drift:
|
|
197
|
+
|
|
198
|
+
scheme {role}-border on surface 3:1?
|
|
199
|
+
light {role}-300 1.40 – 1.92 ✗ (all 7 roles)
|
|
200
|
+
dark see `_dark.css` 3.42 – 4.22 ✓ (raised 2026-09-03)
|
|
201
|
+
high-contrast {hue}-700 4.94 – 10.34 ✓
|
|
202
|
+
high-contrast-dark {hue}-300 10.93 – 15.02 ✓
|
|
203
|
+
|
|
204
|
+
The ✓/✗ column is ENFORCED — `theme-contrast.spec.ts` recomputes it for
|
|
205
|
+
every scheme on every run, and `light` is its one dated allowance. The
|
|
206
|
+
ranges and step names are indicative and were measured on 2026-09-03; if
|
|
207
|
+
you need a current number, re-run the harness rather than quoting this.
|
|
208
|
+
|
|
209
|
+
Light is the outstanding one. Raising it means darkening the default
|
|
210
|
+
scheme's outline tier across eight colours — a visual-baseline change
|
|
211
|
+
with its own blast radius, reported for a pass of its own rather than
|
|
212
|
+
folded into the dark fix. Re-measure any row here with
|
|
213
|
+
`scratchpad/p6-contrast.mjs <scheme> <baseline>`; do not estimate.
|
|
179
214
|
-fg colored text on neutral surface (tab labels, links)
|
|
180
215
|
-icon icon tint on -soft / surface contexts
|
|
181
216
|
|
package/theme/_typography.css
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
|
|
4
4
|
--font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace;
|
|
5
5
|
|
|
6
|
+
/* ===== Font sizes — line-heights pinned in `rem`, deliberately =====
|
|
7
|
+
Tailwind's defaults are UNITLESS ratios (e.g. `--text-sm--line-height:
|
|
8
|
+
calc(1.25 / 0.875)`). A consumer who re-units `--text-sm` therefore
|
|
9
|
+
rescales every line box, which silently overflows controls whose height is
|
|
10
|
+
pinned. Absolute values make the line box a fixed 4px multiple that cannot
|
|
11
|
+
be rescaled out from under a pinned height.
|
|
12
|
+
|
|
13
|
+
These reproduce Tailwind's own COMPUTED defaults exactly (16 / 20 / 24px),
|
|
14
|
+
so the visual diff of adopting them is zero. This is robustness, not a
|
|
15
|
+
redesign — do not "simplify" them back to ratios. */
|
|
16
|
+
--text-xs: 0.75rem;
|
|
17
|
+
--text-xs--line-height: 1rem; /* 12 / 16 */
|
|
18
|
+
--text-sm: 0.875rem;
|
|
19
|
+
--text-sm--line-height: 1.25rem; /* 14 / 20 */
|
|
20
|
+
--text-base: 1rem;
|
|
21
|
+
--text-base--line-height: 1.5rem; /* 16 / 24 */
|
|
22
|
+
|
|
6
23
|
/* ===== Animation durations ===== */
|
|
7
24
|
--duration-fast: 150ms;
|
|
8
25
|
--duration-normal: 200ms;
|
package/theme/index.css
CHANGED
|
@@ -3,23 +3,85 @@
|
|
|
3
3
|
/* ===== Dark variant binding =====
|
|
4
4
|
Re-binds Tailwind's `dark:` variant so it activates on the same condition
|
|
5
5
|
that flips the semantic tokens in `_dark.css`:
|
|
6
|
-
1. an explicit `[data-theme="dark"]`
|
|
7
|
-
|
|
6
|
+
1. an explicit `[data-theme="dark"]` or `[data-theme="high-contrast-dark"]`
|
|
7
|
+
ancestor, OR
|
|
8
|
+
2. `prefers-color-scheme: dark` AND no explicit `data-theme` opt-out,
|
|
9
|
+
and in BOTH cases only while no nearer `[data-theme="light"]` /
|
|
10
|
+
`[data-theme="high-contrast"]` ancestor has opted the subtree back out.
|
|
11
|
+
|
|
12
|
+
`high-contrast-dark` counts as dark here because it IS dark — a subtree
|
|
13
|
+
scoped to it must keep the same `dark:` utilities a `dark` subtree gets, or
|
|
14
|
+
consumer overrides silently stop applying inside it.
|
|
8
15
|
|
|
9
16
|
Without this binding `dark:` defaults to `@media (prefers-color-scheme: dark)`,
|
|
10
17
|
which drifts from the `[data-theme="dark"]` selector — producing inverted
|
|
11
18
|
token state but un-inverted dark utilities (or vice versa) whenever OS
|
|
12
|
-
preference disagrees with the consumer's chosen theme.
|
|
13
|
-
|
|
19
|
+
preference disagrees with the consumer's chosen theme.
|
|
20
|
+
|
|
21
|
+
Keep this rule in lock-step with the activation predicates in `_dark.css`
|
|
22
|
+
and `_light.css` — with ONE deliberate divergence, stated here so a later
|
|
23
|
+
pass does not "fix" it into a bug. `_dark.css`'s media branch excludes
|
|
24
|
+
`[data-theme="high-contrast-dark"]` roots, because a root asking for the
|
|
25
|
+
dark high-contrast TOKENS must not be handed the plain dark ones. The media
|
|
26
|
+
branch below does NOT exclude them, because a root asking for dark high
|
|
27
|
+
contrast is still asking for dark, and `dark:` utilities must keep applying
|
|
28
|
+
there. The two predicates answer different questions — "which token set" and
|
|
29
|
+
"is this dark" — and only agree on three of the four schemes.
|
|
30
|
+
|
|
31
|
+
The `:not(:where(…))` exclusions carry zero specificity, so they cannot
|
|
32
|
+
change how a consumer's own `dark:` utility resolves against their other
|
|
33
|
+
rules — they only narrow *when* it applies. Both branches need one, but the
|
|
34
|
+
two are deliberately NOT the same shape:
|
|
35
|
+
|
|
36
|
+
- The media branch excludes any `[data-theme="light"]` /
|
|
37
|
+
`[data-theme="high-contrast"]` ancestor outright. Re-entering dark below
|
|
38
|
+
such a subtree is still handled, because the explicit branch above matches
|
|
39
|
+
it independently.
|
|
40
|
+
- The explicit branch can only exclude a light/high-contrast boundary that
|
|
41
|
+
sits *below* a dark one (`[data-theme="dark"] [data-theme="light"] *`).
|
|
42
|
+
The plain form would also strip `dark:` from a dark subtree nested inside
|
|
43
|
+
a light one, where it is correct — CSS has no "nearest themed ancestor"
|
|
44
|
+
combinator, and inherited custom properties get that semantic for free
|
|
45
|
+
while selectors do not. The residual gap is depth-3 alternation
|
|
46
|
+
(dark → light → dark), which is no worse than before this rule existed.
|
|
47
|
+
|
|
48
|
+
With two dark schemes and two light ones that exclusion is a 2×2 product,
|
|
49
|
+
so it is written with nested `:where()` groups rather than four spelled-out
|
|
50
|
+
descendant pairs. `:where()` contributes zero specificity and the whole
|
|
51
|
+
thing already sits inside a zero-specificity `:not(:where(…))`, so the
|
|
52
|
+
grouped form is exactly equivalent to the enumeration — just not four times
|
|
53
|
+
as long.
|
|
54
|
+
|
|
55
|
+
The library ships no `dark:` variants of its own, so this is consumer-facing
|
|
56
|
+
only. */
|
|
14
57
|
@custom-variant dark {
|
|
15
|
-
&:where(
|
|
58
|
+
&:where(
|
|
59
|
+
[data-theme="dark"],
|
|
60
|
+
[data-theme="dark"] *,
|
|
61
|
+
[data-theme="high-contrast-dark"],
|
|
62
|
+
[data-theme="high-contrast-dark"] *
|
|
63
|
+
):not(
|
|
64
|
+
:where(
|
|
65
|
+
:where([data-theme="dark"], [data-theme="high-contrast-dark"])
|
|
66
|
+
:where([data-theme="light"], [data-theme="high-contrast"]),
|
|
67
|
+
:where([data-theme="dark"], [data-theme="high-contrast-dark"])
|
|
68
|
+
:where([data-theme="light"], [data-theme="high-contrast"]) *
|
|
69
|
+
)
|
|
70
|
+
) {
|
|
16
71
|
@slot;
|
|
17
72
|
}
|
|
18
73
|
@media (prefers-color-scheme: dark) {
|
|
19
74
|
&:where(
|
|
20
75
|
:root:not([data-theme="light"]):not([data-theme="high-contrast"]),
|
|
21
76
|
:root:not([data-theme="light"]):not([data-theme="high-contrast"]) *
|
|
22
|
-
)
|
|
77
|
+
):not(
|
|
78
|
+
:where(
|
|
79
|
+
[data-theme="light"],
|
|
80
|
+
[data-theme="light"] *,
|
|
81
|
+
[data-theme="high-contrast"],
|
|
82
|
+
[data-theme="high-contrast"] *
|
|
83
|
+
)
|
|
84
|
+
) {
|
|
23
85
|
@slot;
|
|
24
86
|
}
|
|
25
87
|
}
|
|
@@ -54,8 +116,25 @@
|
|
|
54
116
|
/* Semantic token definitions */
|
|
55
117
|
@import "./_semantic.css";
|
|
56
118
|
|
|
57
|
-
/* Theme overrides
|
|
119
|
+
/* Theme overrides.
|
|
120
|
+
`_high-contrast.css` must stay LAST of the four, and every other scheme file
|
|
121
|
+
before it. Each scheme's own block is a bare `[data-theme=…]` at specificity
|
|
122
|
+
0,1,0, and `_high-contrast.css`'s `@media (forced-colors: active)` list
|
|
123
|
+
names all four of them at that same 0,1,0 — so source order is the only
|
|
124
|
+
tie-breaker and the forced-colors remap has to come last to win. That is why
|
|
125
|
+
`_light.css` leads and why `_high-contrast-dark.css` sits above
|
|
126
|
+
`_high-contrast.css` rather than below it.
|
|
127
|
+
|
|
128
|
+
Between the first three the order is grouping, not cascade: `[data-theme]`
|
|
129
|
+
values are matched exactly, so no two scheme blocks can ever apply to the
|
|
130
|
+
same element. `_high-contrast-dark.css` sits next to `_dark.css` because it
|
|
131
|
+
is the dark family's contrast variant, and because `_dark.css`'s
|
|
132
|
+
`prefers-color-scheme` branch has to exclude it by name — that branch is
|
|
133
|
+
0,4,0 and would otherwise outrank it. See the header of
|
|
134
|
+
`_high-contrast-dark.css`. */
|
|
135
|
+
@import "./_light.css";
|
|
58
136
|
@import "./_dark.css";
|
|
137
|
+
@import "./_high-contrast-dark.css";
|
|
59
138
|
@import "./_high-contrast.css";
|
|
60
139
|
|
|
61
140
|
/* Base/reset */
|
|
@@ -4,7 +4,13 @@ import { CollapsibleGroupComponent } from '@cdevhub/ngx-tw/collapsible';
|
|
|
4
4
|
/** Open mode of the accordion. */
|
|
5
5
|
type AccordionType = 'single' | 'multiple';
|
|
6
6
|
/** Visual style of the accordion container. */
|
|
7
|
-
type AccordionVariant = 'default' | '
|
|
7
|
+
type AccordionVariant = 'default' | 'outline' | 'ghost' | AccordionVariantLegacy;
|
|
8
|
+
/**
|
|
9
|
+
* Legacy `variant` spellings, kept so existing templates keep compiling.
|
|
10
|
+
* @deprecated `'bordered'` is an alias for `'outline'` and renders identically.
|
|
11
|
+
* It will be removed in the next major — prefer `'outline'`.
|
|
12
|
+
*/
|
|
13
|
+
type AccordionVariantLegacy = 'bordered';
|
|
8
14
|
/**
|
|
9
15
|
* Accordion — single- or multiple-open-panel group built on top of
|
|
10
16
|
* `<tw-collapsible>` children. Extends `CollapsibleGroupComponent` to inherit
|
|
@@ -24,16 +30,18 @@ type AccordionVariant = 'default' | 'bordered' | 'ghost';
|
|
|
24
30
|
declare class AccordionComponent extends CollapsibleGroupComponent {
|
|
25
31
|
/** Open mode. `'single'` allows one panel open at a time; `'multiple'` allows many. Defaults to `'single'`. */
|
|
26
32
|
readonly type: _angular_core.InputSignal<AccordionType>;
|
|
27
|
-
/** Visual style of the accordion container. Defaults to `'default'`. */
|
|
33
|
+
/** Visual style of the accordion container. Defaults to `'default'`. `'bordered'` is a deprecated alias for `'outline'` and renders identically. */
|
|
28
34
|
readonly variant: _angular_core.InputSignal<AccordionVariant>;
|
|
29
35
|
/** In `'single'` mode, whether re-clicking the open panel closes it. Defaults to `true` — accordions are collapsible by definition; opt-out only. */
|
|
30
36
|
readonly collapsible: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
31
|
-
/** Accessible name for the accordion. Use when surrounding context doesn't make the purpose obvious. */
|
|
37
|
+
/** Accessible name for the accordion. Use when surrounding context doesn't make the purpose obvious. Defaults to `undefined`. Alias: `aria-label`. */
|
|
32
38
|
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
33
|
-
/** ID(s) of element(s) that label the accordion. Use instead of `aria-label` when a visible heading is available. */
|
|
39
|
+
/** ID(s) of element(s) that label the accordion. Use instead of `aria-label` when a visible heading is available. Defaults to `undefined`. Alias: `aria-labelledby`. */
|
|
34
40
|
readonly ariaLabelledby: _angular_core.InputSignal<string | undefined>;
|
|
35
41
|
/** @internal APG: accordions don't carry `role="group"`. */
|
|
36
42
|
readonly hostRole: _angular_core.Signal<string | null>;
|
|
43
|
+
/** @internal Canonical variant with legacy spellings folded in. */
|
|
44
|
+
private readonly resolvedVariant;
|
|
37
45
|
/** @internal Variant-driven container classes; replaces the parent's default group string. */
|
|
38
46
|
readonly hostClasses: _angular_core.Signal<string>;
|
|
39
47
|
/** @internal Drive single-open-panel behaviour from `type`, ignoring the inherited `accordion` input. */
|
|
@@ -17,6 +17,13 @@ interface AvatarAppearance {
|
|
|
17
17
|
* Injection token used by `AvatarGroupComponent` to propagate its size
|
|
18
18
|
* to child avatars. When present, overrides the individual avatar's `size` input.
|
|
19
19
|
*/
|
|
20
|
+
declare const TW_AVATAR_GROUP_SIZE: InjectionToken<() => TwSize>;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Renamed to {@link TW_AVATAR_GROUP_SIZE} for consistency with every
|
|
23
|
+
* other ngx-tw injection token. This is the *same token instance*, not a copy —
|
|
24
|
+
* providing under either name and injecting under the other resolves — so the
|
|
25
|
+
* rename is safe to adopt incrementally. Removed in the next major.
|
|
26
|
+
*/
|
|
20
27
|
declare const AVATAR_GROUP_SIZE: InjectionToken<() => TwSize>;
|
|
21
28
|
declare class AvatarComponent {
|
|
22
29
|
/** URL of the avatar image. When set, renders an `<img>`. Falls back to initials or projected content on load error. Defaults to `null`. */
|
|
@@ -64,7 +71,7 @@ declare class AvatarGroupComponent {
|
|
|
64
71
|
readonly size: _angular_core.InputSignal<TwSize>;
|
|
65
72
|
/** Maximum number of avatars to display. Remaining count is shown as a "+N" overflow indicator. Defaults to `null` (show all). */
|
|
66
73
|
readonly max: _angular_core.InputSignal<number | null>;
|
|
67
|
-
/** Accessible label for the avatar group
|
|
74
|
+
/** Accessible label for the avatar group, mirrored to `aria-label`. Defaults to `'Avatar group'` (English) — override for localisation. */
|
|
68
75
|
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
69
76
|
private readonly avatars;
|
|
70
77
|
readonly overflowCount: _angular_core.Signal<number>;
|
|
@@ -72,8 +79,8 @@ declare class AvatarGroupComponent {
|
|
|
72
79
|
readonly overflowClasses: _angular_core.Signal<string>;
|
|
73
80
|
private readonly visibilityEffect;
|
|
74
81
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AvatarGroupComponent, never>;
|
|
75
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AvatarGroupComponent, "tw-avatar-group", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "
|
|
82
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AvatarGroupComponent, "tw-avatar-group", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; }, {}, ["avatars"], ["*"], true, never>;
|
|
76
83
|
}
|
|
77
84
|
|
|
78
|
-
export { AVATAR_GROUP_SIZE, AvatarComponent, AvatarGroupComponent };
|
|
85
|
+
export { AVATAR_GROUP_SIZE, AvatarComponent, AvatarGroupComponent, TW_AVATAR_GROUP_SIZE };
|
|
79
86
|
export type { AvatarAppearance, AvatarRounded, AvatarStatus };
|
|
@@ -49,6 +49,7 @@ declare class ButtonDirective implements OnInit {
|
|
|
49
49
|
readonly isNativeButton: _angular_core.Signal<boolean>;
|
|
50
50
|
readonly classes: _angular_core.Signal<string>;
|
|
51
51
|
ngOnInit(): void;
|
|
52
|
+
/** @internal Swallows clicks while the button is disabled or loading, so neither navigation nor consumer handlers run. */
|
|
52
53
|
handleClick(event: MouseEvent): void;
|
|
53
54
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ButtonDirective, never>;
|
|
54
55
|
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ButtonDirective, "[twButton]", ["twButton"], { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
@@ -20,7 +20,7 @@ interface TwLuxonDateFormat {
|
|
|
20
20
|
readonly preset?: Intl.DateTimeFormatOptions;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Luxon-backed `DateAdapter`. Honors the calendar's `
|
|
23
|
+
* Luxon-backed `DateAdapter`. Honors the calendar's `TW_TZ_OVERRIDE` injection
|
|
24
24
|
* token so `today()` resolves against the consumer-configured timezone, and
|
|
25
25
|
* implements the §20.2 TZ-aware virtuals (`getTimezone`, `withTimezone`,
|
|
26
26
|
* `isDST`, `resolveAmbiguous`).
|
|
@@ -45,7 +45,7 @@ declare class LuxonDateAdapter extends DateAdapter<DateTime> {
|
|
|
45
45
|
private get locale();
|
|
46
46
|
/**
|
|
47
47
|
* Returns the configured timezone for new dates. Precedence: per-instance
|
|
48
|
-
* `
|
|
48
|
+
* `TW_TZ_OVERRIDE` → Luxon's `Settings.defaultZone` → `'local'`.
|
|
49
49
|
*/
|
|
50
50
|
private get zone();
|
|
51
51
|
/** Builds a `DateTime` in the adapter's configured zone + locale. */
|
|
@@ -19,7 +19,7 @@ declare class CalendarCellHarness extends ComponentHarness {
|
|
|
19
19
|
getText(): Promise<string>;
|
|
20
20
|
/** The cell's `aria-label`. */
|
|
21
21
|
getAriaLabel(): Promise<string | null>;
|
|
22
|
-
/** Whether the cell carries `aria-selected="true"`. */
|
|
22
|
+
/** Whether the cell carries `aria-selected="true"`. Read from the `role="gridcell"` host, which is the element that carries selection state — a `<button>`'s implicit role does not support `aria-selected`. */
|
|
23
23
|
isSelected(): Promise<boolean>;
|
|
24
24
|
/** Whether the cell is disabled — true if the button has `disabled` or carries `aria-disabled="true"`. */
|
|
25
25
|
isDisabled(): Promise<boolean>;
|