ngwr 14.0.0 → 14.0.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 +57 -8
- package/aurora/aurora.scss +1 -1
- package/aurora/styles/_dark.scss +21 -0
- package/aurora/styles/_index.scss +11 -30
- package/aurora/styles/_rules.scss +25 -0
- package/border-glow/styles/_dark.scss +46 -0
- package/border-glow/styles/_index.scss +5 -0
- package/border-glow/styles/_rules.scss +0 -31
- package/button/styles/_index.scss +16 -0
- package/event-calendar/styles/_index.scss +15 -0
- package/fesm2022/ngwr-action-sheet.mjs +3 -3
- package/fesm2022/ngwr-affix.mjs +3 -3
- package/fesm2022/ngwr-alert.mjs +3 -3
- package/fesm2022/ngwr-anchor.mjs +3 -3
- package/fesm2022/ngwr-aurora.mjs +4 -4
- package/fesm2022/ngwr-aurora.mjs.map +1 -1
- package/fesm2022/ngwr-avatar.mjs +3 -3
- package/fesm2022/ngwr-back-top.mjs +3 -3
- package/fesm2022/ngwr-badge.mjs +6 -6
- package/fesm2022/ngwr-bar-chart.mjs +3 -3
- package/fesm2022/ngwr-blur-text.mjs +3 -3
- package/fesm2022/ngwr-border-glow.mjs +4 -4
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +7 -7
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-burger.mjs +3 -3
- package/fesm2022/ngwr-button.mjs +86 -8
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
- package/fesm2022/ngwr-calendar.mjs +3 -3
- package/fesm2022/ngwr-card.mjs +9 -9
- package/fesm2022/ngwr-carousel.mjs +6 -6
- package/fesm2022/ngwr-cascader.mjs +4 -4
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +6 -6
- package/fesm2022/ngwr-circular-text.mjs +3 -3
- package/fesm2022/ngwr-click-spark.mjs +3 -3
- package/fesm2022/ngwr-clipboard.mjs +3 -3
- package/fesm2022/ngwr-collapse.mjs +9 -9
- package/fesm2022/ngwr-color-picker.mjs +6 -6
- package/fesm2022/ngwr-command-palette.mjs +3 -3
- package/fesm2022/ngwr-compare.mjs +3 -3
- package/fesm2022/ngwr-confetti.mjs +3 -3
- package/fesm2022/ngwr-context-menu.mjs +12 -12
- package/fesm2022/ngwr-cookie.mjs +3 -3
- package/fesm2022/ngwr-counter.mjs +6 -6
- package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
- package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
- package/fesm2022/ngwr-date-picker.mjs +18 -18
- package/fesm2022/ngwr-date.mjs +3 -3
- package/fesm2022/ngwr-decrypt-text.mjs +3 -3
- package/fesm2022/ngwr-density.mjs +6 -6
- package/fesm2022/ngwr-descriptions.mjs +6 -6
- package/fesm2022/ngwr-dialog.mjs +15 -15
- package/fesm2022/ngwr-directives.mjs +12 -12
- package/fesm2022/ngwr-divider.mjs +3 -3
- package/fesm2022/ngwr-donut-chart.mjs +3 -3
- package/fesm2022/ngwr-drag-drop.mjs +7 -7
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +18 -18
- package/fesm2022/ngwr-dropdown.mjs +28 -12
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-empty.mjs +3 -3
- package/fesm2022/ngwr-event-calendar.mjs +6 -6
- package/fesm2022/ngwr-falling-text.mjs +3 -3
- package/fesm2022/ngwr-file-upload.mjs +3 -3
- package/fesm2022/ngwr-form-testing.mjs +13 -7
- package/fesm2022/ngwr-form-testing.mjs.map +1 -1
- package/fesm2022/ngwr-form.mjs +44 -25
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
- package/fesm2022/ngwr-gauge.mjs +3 -3
- package/fesm2022/ngwr-glitch-text.mjs +3 -3
- package/fesm2022/ngwr-gradient-text.mjs +3 -3
- package/fesm2022/ngwr-hotkey.mjs +6 -6
- package/fesm2022/ngwr-i18n.mjs +9 -9
- package/fesm2022/ngwr-icon.mjs +6 -6
- package/fesm2022/ngwr-image-cropper.mjs +3 -3
- package/fesm2022/ngwr-input-number.mjs +3 -3
- package/fesm2022/ngwr-input-otp.mjs +3 -3
- package/fesm2022/ngwr-input.mjs +24 -20
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-keyboard.mjs +3 -3
- package/fesm2022/ngwr-knob.mjs +3 -3
- package/fesm2022/ngwr-layout.mjs +15 -15
- package/fesm2022/ngwr-lightbox.mjs +4 -4
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +3 -3
- package/fesm2022/ngwr-list.mjs +7 -7
- package/fesm2022/ngwr-list.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar.mjs +6 -6
- package/fesm2022/ngwr-markdown.mjs +6 -6
- package/fesm2022/ngwr-marquee.mjs +3 -3
- package/fesm2022/ngwr-media.mjs +3 -3
- package/fesm2022/ngwr-mention.mjs +6 -6
- package/fesm2022/ngwr-meta.mjs +6 -6
- package/fesm2022/ngwr-meter-group.mjs +3 -3
- package/fesm2022/ngwr-overlay.mjs +6 -6
- package/fesm2022/ngwr-page-header.mjs +3 -3
- package/fesm2022/ngwr-pagination.mjs +3 -3
- package/fesm2022/ngwr-pipes.mjs +21 -21
- package/fesm2022/ngwr-platform.mjs +9 -9
- package/fesm2022/ngwr-popconfirm.mjs +6 -6
- package/fesm2022/ngwr-popover.mjs +6 -6
- package/fesm2022/ngwr-progress.mjs +3 -3
- package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
- package/fesm2022/ngwr-qr.mjs +3 -3
- package/fesm2022/ngwr-radio.mjs +6 -6
- package/fesm2022/ngwr-rating.mjs +48 -22
- package/fesm2022/ngwr-rating.mjs.map +1 -1
- package/fesm2022/ngwr-result.mjs +12 -12
- package/fesm2022/ngwr-rotating-text.mjs +3 -3
- package/fesm2022/ngwr-scroll.mjs +3 -3
- package/fesm2022/ngwr-segmented.mjs +12 -8
- package/fesm2022/ngwr-segmented.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +125 -26
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +7 -7
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-sidebar.mjs +3 -3
- package/fesm2022/ngwr-skeleton.mjs +3 -3
- package/fesm2022/ngwr-slider.mjs +12 -8
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +3 -3
- package/fesm2022/ngwr-speed-dial.mjs +3 -3
- package/fesm2022/ngwr-spinner.mjs +3 -3
- package/fesm2022/ngwr-splash-cursor.mjs +3 -3
- package/fesm2022/ngwr-split-text.mjs +3 -3
- package/fesm2022/ngwr-splitter.mjs +3 -3
- package/fesm2022/ngwr-spotlight-card.mjs +7 -7
- package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
- package/fesm2022/ngwr-squircle.mjs +6 -6
- package/fesm2022/ngwr-star-border.mjs +4 -4
- package/fesm2022/ngwr-star-border.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +9 -9
- package/fesm2022/ngwr-stepper.mjs +6 -6
- package/fesm2022/ngwr-storage.mjs +11 -3
- package/fesm2022/ngwr-storage.mjs.map +1 -1
- package/fesm2022/ngwr-switch.mjs +3 -3
- package/fesm2022/ngwr-table.mjs +18 -18
- package/fesm2022/ngwr-tabs-router.mjs +3 -3
- package/fesm2022/ngwr-tabs.mjs +6 -6
- package/fesm2022/ngwr-textarea.mjs +26 -5
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-theme.mjs +90 -4
- package/fesm2022/ngwr-theme.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card.mjs +7 -7
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-timeline.mjs +6 -6
- package/fesm2022/ngwr-toast.mjs +116 -11
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +3 -3
- package/fesm2022/ngwr-tour.mjs +6 -6
- package/fesm2022/ngwr-transfer.mjs +3 -3
- package/fesm2022/ngwr-tree.mjs +18 -11
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter.mjs +3 -3
- package/fesm2022/ngwr-typography.mjs +3 -3
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
- package/fesm2022/ngwr-waves.mjs +4 -4
- package/fesm2022/ngwr-waves.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +12 -12
- package/llms-full.txt +9 -9
- package/llms.txt +82 -11
- package/package.json +1 -1
- package/shiny-text/styles/_dark.scss +20 -0
- package/shiny-text/styles/_index.scss +5 -0
- package/shiny-text/styles/_rules.scss +0 -4
- package/spotlight-card/styles/_dark.scss +21 -0
- package/spotlight-card/styles/_index.scss +5 -0
- package/spotlight-card/styles/_rules.scss +0 -6
- package/star-border/styles/_dark.scss +21 -0
- package/star-border/styles/_index.scss +5 -0
- package/star-border/styles/_rules.scss +0 -5
- package/theme/styles/_colors.scss +102 -0
- package/theme/styles/_focus.scss +31 -1
- package/tilt-card/styles/_dark.scss +21 -0
- package/tilt-card/styles/_index.scss +5 -0
- package/tilt-card/styles/_rules.scss +0 -5
- package/types/ngwr-button.d.ts +43 -0
- package/types/ngwr-dropdown.d.ts +17 -1
- package/types/ngwr-form-testing.d.ts +13 -7
- package/types/ngwr-form.d.ts +47 -12
- package/types/ngwr-input.d.ts +2 -1
- package/types/ngwr-rating.d.ts +25 -4
- package/types/ngwr-segmented.d.ts +1 -0
- package/types/ngwr-select.d.ts +45 -9
- package/types/ngwr-slider.d.ts +1 -0
- package/types/ngwr-storage.d.ts +39 -1
- package/types/ngwr-textarea.d.ts +20 -0
- package/types/ngwr-theme.d.ts +92 -2
- package/types/ngwr-toast.d.ts +53 -0
- package/types/ngwr-tree.d.ts +3 -2
- package/types/ngwr-version.d.ts +1 -1
- package/waves/styles/_dark.scss +19 -0
- package/waves/styles/_index.scss +5 -0
- package/waves/styles/_rules.scss +0 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Dark theme.
|
|
2
|
+
//
|
|
3
|
+
// Keyed on `theme.dark-selector()`, never on a literal `[data-theme='dark']`.
|
|
4
|
+
// The attribute is renameable — `@use 'ngwr' with ($theme-attribute: '…')`
|
|
5
|
+
// alongside `provideWrTheme({ attribute: '…' })` — and a hand-written literal
|
|
6
|
+
// misses the rename in both directions: this block stops firing under the
|
|
7
|
+
// configured name, and it keeps firing under `data-theme`, which is the
|
|
8
|
+
// attribute a foreign design system owns and the rename exists to escape.
|
|
9
|
+
//
|
|
10
|
+
// It lives outside the `styleUrl` closure for the same reason. A component
|
|
11
|
+
// stylesheet is compiled when the LIBRARY is built, where `$theme-attribute` can
|
|
12
|
+
// only ever be the default, and Angular appends that copy after the app's linked
|
|
13
|
+
// sheet — so an inlined literal would not merely be dead, it would outrank the
|
|
14
|
+
// correctly-named rule beside it.
|
|
15
|
+
@use '../../theme/styles' as theme;
|
|
16
|
+
|
|
17
|
+
#{theme.dark-selector()} .wr-shiny-text {
|
|
18
|
+
--wr-shiny-text-base: #b5b5b5;
|
|
19
|
+
--wr-shiny-text-shine: #ffffff;
|
|
20
|
+
}
|
|
@@ -11,5 +11,10 @@
|
|
|
11
11
|
// box-sizing reset into the compiled component styles, which ng-packagr then
|
|
12
12
|
// embeds in the FESM bundle as a string. `shiny-text.scss` forwards `_rules`
|
|
13
13
|
// instead, so it carries this component's own CSS and nothing else.
|
|
14
|
+
//
|
|
15
|
+
// `_dark` is loaded from HERE for a second reason: its selector is built out of
|
|
16
|
+
// `$theme-attribute`, which only a stylesheet compiled by the consuming app can
|
|
17
|
+
// configure, so a copy inside the bundle could only ever carry the default name.
|
|
14
18
|
@use '../../theme/styles';
|
|
15
19
|
@forward 'rules';
|
|
20
|
+
@forward 'dark';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Dark theme: `--wr-color-on-surface-rgb` already flips to a light
|
|
2
|
+
// value, so the default tint becomes a light beam on the navy surface — nudge
|
|
3
|
+
// the alpha up a touch so it reads as bright as the classic spotlight.
|
|
4
|
+
//
|
|
5
|
+
// Keyed on `theme.dark-selector()`, never on a literal `[data-theme='dark']`.
|
|
6
|
+
// The attribute is renameable — `@use 'ngwr' with ($theme-attribute: '…')`
|
|
7
|
+
// alongside `provideWrTheme({ attribute: '…' })` — and a hand-written literal
|
|
8
|
+
// misses the rename in both directions: this block stops firing under the
|
|
9
|
+
// configured name, and it keeps firing under `data-theme`, which is the
|
|
10
|
+
// attribute a foreign design system owns and the rename exists to escape.
|
|
11
|
+
//
|
|
12
|
+
// It lives outside the `styleUrl` closure for the same reason. A component
|
|
13
|
+
// stylesheet is compiled when the LIBRARY is built, where `$theme-attribute` can
|
|
14
|
+
// only ever be the default, and Angular appends that copy after the app's linked
|
|
15
|
+
// sheet — so an inlined literal would not merely be dead, it would outrank the
|
|
16
|
+
// correctly-named rule beside it.
|
|
17
|
+
@use '../../theme/styles' as theme;
|
|
18
|
+
|
|
19
|
+
#{theme.dark-selector()} .wr-spotlight-card {
|
|
20
|
+
--wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.22);
|
|
21
|
+
}
|
|
@@ -11,5 +11,10 @@
|
|
|
11
11
|
// box-sizing reset into the compiled component styles, which ng-packagr then
|
|
12
12
|
// embeds in the FESM bundle as a string. `spotlight-card.scss` forwards `_rules`
|
|
13
13
|
// instead, so it carries this component's own CSS and nothing else.
|
|
14
|
+
//
|
|
15
|
+
// `_dark` is loaded from HERE for a second reason: its selector is built out of
|
|
16
|
+
// `$theme-attribute`, which only a stylesheet compiled by the consuming app can
|
|
17
|
+
// configure, so a copy inside the bundle could only ever carry the default name.
|
|
14
18
|
@use '../../theme/styles';
|
|
15
19
|
@forward 'rules';
|
|
20
|
+
@forward 'dark';
|
|
@@ -39,9 +39,3 @@
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
// Dark mode: `--wr-color-on-surface-rgb` already flips to a light value, so the
|
|
43
|
-
// default tint above becomes a light beam on the navy surface — nudge the
|
|
44
|
-
// alpha up a touch so it reads as bright as the classic spotlight.
|
|
45
|
-
[data-theme='dark'] .wr-spotlight-card {
|
|
46
|
-
--wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.22);
|
|
47
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Dark theme.
|
|
2
|
+
//
|
|
3
|
+
// Keyed on `theme.dark-selector()`, never on a literal `[data-theme='dark']`.
|
|
4
|
+
// The attribute is renameable — `@use 'ngwr' with ($theme-attribute: '…')`
|
|
5
|
+
// alongside `provideWrTheme({ attribute: '…' })` — and a hand-written literal
|
|
6
|
+
// misses the rename in both directions: this block stops firing under the
|
|
7
|
+
// configured name, and it keeps firing under `data-theme`, which is the
|
|
8
|
+
// attribute a foreign design system owns and the rename exists to escape.
|
|
9
|
+
//
|
|
10
|
+
// It lives outside the `styleUrl` closure for the same reason. A component
|
|
11
|
+
// stylesheet is compiled when the LIBRARY is built, where `$theme-attribute` can
|
|
12
|
+
// only ever be the default, and Angular appends that copy after the app's linked
|
|
13
|
+
// sheet — so an inlined literal would not merely be dead, it would outrank the
|
|
14
|
+
// correctly-named rule beside it.
|
|
15
|
+
@use '../../theme/styles' as theme;
|
|
16
|
+
|
|
17
|
+
#{theme.dark-selector()} .wr-star-border {
|
|
18
|
+
--wr-star-border-color: #ffffff;
|
|
19
|
+
--wr-star-border-stop: 10%;
|
|
20
|
+
--wr-star-border-opacity: 0.7;
|
|
21
|
+
}
|
|
@@ -11,5 +11,10 @@
|
|
|
11
11
|
// box-sizing reset into the compiled component styles, which ng-packagr then
|
|
12
12
|
// embeds in the FESM bundle as a string. `star-border.scss` forwards `_rules`
|
|
13
13
|
// instead, so it carries this component's own CSS and nothing else.
|
|
14
|
+
//
|
|
15
|
+
// `_dark` is loaded from HERE for a second reason: its selector is built out of
|
|
16
|
+
// `$theme-attribute`, which only a stylesheet compiled by the consuming app can
|
|
17
|
+
// configure, so a copy inside the bundle could only ever carry the default name.
|
|
14
18
|
@use '../../theme/styles';
|
|
15
19
|
@forward 'rules';
|
|
20
|
+
@forward 'dark';
|
|
@@ -8,6 +8,38 @@
|
|
|
8
8
|
// @use 'ngwr/theme/styles/colors' with (
|
|
9
9
|
// $base-colors: (primary: #...)
|
|
10
10
|
// );
|
|
11
|
+
//
|
|
12
|
+
// **This is the LIGHT palette, and configuring it does not reach the dark
|
|
13
|
+
// theme.** `_dark.scss` re-tunes the intents by hand for the dark canvas and
|
|
14
|
+
// hard-codes what it lands on, so an app that seeds an indigo `primary` here
|
|
15
|
+
// gets indigo in light and the shipped `#3567ff` in dark, with nothing said
|
|
16
|
+
// about it — which is exactly how it reads as a bug rather than a boundary.
|
|
17
|
+
//
|
|
18
|
+
// It is a boundary, and the deriving is what could not be shipped. The dark
|
|
19
|
+
// intents are not the light ones lightened: `success` and `danger` are moved
|
|
20
|
+
// 33% and 21% to clear the black/white flip point on a dark ground, `warning`
|
|
21
|
+
// is deliberately left alone because white cannot reach it at any tone worth
|
|
22
|
+
// shipping, and `primary` is deepened until its label can go white — a
|
|
23
|
+
// direction no formula would take on its own. A `color.scale()` applied to an
|
|
24
|
+
// arbitrary seed reproduces none of that; what it reproduces is the class of
|
|
25
|
+
// failure the hand-tuning exists to prevent, silently, in the theme where
|
|
26
|
+
// nobody looks first. Deriving the dark palette from the seed would trade a
|
|
27
|
+
// visible wrong colour for an invisible failing contrast ratio, and that is
|
|
28
|
+
// the worse of the two.
|
|
29
|
+
//
|
|
30
|
+
// So carry a rebrand across yourself, with the same arithmetic the light
|
|
31
|
+
// palette uses. `rebrand()` below is that arithmetic:
|
|
32
|
+
//
|
|
33
|
+
// @use 'ngwr/theme' as theme;
|
|
34
|
+
//
|
|
35
|
+
// @include theme.dark {
|
|
36
|
+
// @include theme.rebrand((primary: #818cf8));
|
|
37
|
+
// }
|
|
38
|
+
//
|
|
39
|
+
// Pick the dark seed for the dark canvas rather than reusing the light one, and
|
|
40
|
+
// measure it — `pnpm check:contrast` in this repo, axe or any contrast checker
|
|
41
|
+
// in yours. `contrast()` is exported for the same reason: it tells you which
|
|
42
|
+
// label a candidate fill will get before you ship it.
|
|
11
43
|
|
|
12
44
|
// Five intents are deliberately deeper than their "brand" tone, and the reason is
|
|
13
45
|
// arithmetic rather than taste. `_contrast()` picks whichever of black / white
|
|
@@ -319,6 +351,76 @@ $contrast-light: #ffffff !default;
|
|
|
319
351
|
--wr-color-dark-ink: var(--wr-color-dark);
|
|
320
352
|
}
|
|
321
353
|
|
|
354
|
+
/// Re-emit an intent's WHOLE token set on the current selector, from one seed.
|
|
355
|
+
///
|
|
356
|
+
/// `$colors` is a map of intent name to base colour, keyed by the same nine
|
|
357
|
+
/// names as `$base-colors`. Anything else is an `@error`: a typo would otherwise
|
|
358
|
+
/// emit a family of `--wr-color-brnad-*` properties that resolve for nothing.
|
|
359
|
+
///
|
|
360
|
+
/// **This is the supported way to recolour a SUBTREE, and hand-writing the three
|
|
361
|
+
/// obvious properties is not.** Setting `--wr-color-primary`, its `-rgb` and its
|
|
362
|
+
/// `-contrast` on a `.marketing` wrapper looks like it should be enough, and the
|
|
363
|
+
/// guide used to say so. It is not, for two separate reasons, and each hits a
|
|
364
|
+
/// different half of the set:
|
|
365
|
+
///
|
|
366
|
+
/// - `-dark`, `-darker`, `-light` and `-lighter` are `color.adjust()` — Sass
|
|
367
|
+
/// arithmetic, resolved when the stylesheet is COMPILED. No runtime value can
|
|
368
|
+
/// feed them, so a pink subtree kept a blue `:hover`, which is `-dark`.
|
|
369
|
+
/// - `-soft`, `-soft-border`, `-soft-contrast`, `-active` and `-ink` are written
|
|
370
|
+
/// in terms of `var()`, which is the mechanism that lets them re-derive — but
|
|
371
|
+
/// a custom property's references are substituted ON THE ELEMENT THAT DECLARES
|
|
372
|
+
/// IT, and these are declared at `:root`. What inherits into the subtree is
|
|
373
|
+
/// the substituted literal, so an outlined button inside a pink section drew a
|
|
374
|
+
/// pink border around blue text: `-ink` had been frozen two levels up. It is
|
|
375
|
+
/// the same trap `derived()` documents for a scoped dark block, arriving by a
|
|
376
|
+
/// different door.
|
|
377
|
+
///
|
|
378
|
+
/// So the mixin does both halves: it recomputes the four shades and the contrast
|
|
379
|
+
/// pick in Sass, then re-includes `derived()` so every composed token resolves
|
|
380
|
+
/// against the bases on THIS element.
|
|
381
|
+
///
|
|
382
|
+
/// ```scss
|
|
383
|
+
/// @use 'ngwr/theme' as theme;
|
|
384
|
+
///
|
|
385
|
+
/// .marketing {
|
|
386
|
+
/// @include theme.rebrand((primary: #be123c));
|
|
387
|
+
/// }
|
|
388
|
+
/// ```
|
|
389
|
+
///
|
|
390
|
+
/// It is compile-time, so the seed has to be known when the app's stylesheet is
|
|
391
|
+
/// built. For a colour chosen at runtime — a tenant, a builder, a preset picked
|
|
392
|
+
/// from a registry — reach for `wrThemeTokens()` from `ngwr/theme` instead; it
|
|
393
|
+
/// is the same recipe in TypeScript.
|
|
394
|
+
///
|
|
395
|
+
/// The dark theme needs the same treatment and does not get it for free: see the
|
|
396
|
+
/// note on `$base-colors` for why compile-time configuration is light-only, and
|
|
397
|
+
/// wrap this in `theme.dark` to carry a rebrand across.
|
|
398
|
+
@mixin rebrand($colors) {
|
|
399
|
+
@each $name, $base in $colors {
|
|
400
|
+
@if not map.has-key($base-colors, $name) {
|
|
401
|
+
@error 'rebrand(): unknown intent `#{$name}`. Expected one of: #{map.keys($base-colors)}.';
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
--wr-color-#{$name}: #{$base};
|
|
405
|
+
--wr-color-#{$name}-rgb: #{_rgb-channels($base)};
|
|
406
|
+
--wr-color-#{$name}-contrast: #{_contrast($base)};
|
|
407
|
+
--wr-color-#{$name}-dark: #{color.adjust($base, $lightness: -5%)};
|
|
408
|
+
--wr-color-#{$name}-darker: #{color.adjust($base, $lightness: -10%)};
|
|
409
|
+
// unused-ok: `-light` and `-lighter`, for the reason their `:root` twins
|
|
410
|
+
// carry — hover and active DEEPEN an intent, so the catalog reads `-dark` /
|
|
411
|
+
// `-darker` and never these two, and a shade set with holes in it is worse
|
|
412
|
+
// than one half of which is for consumers. They are here rather than only
|
|
413
|
+
// there because a rebrand has to emit the SAME set the `:root` loop does: a
|
|
414
|
+
// subtree that redefines four shades out of six leaves a consumer's own
|
|
415
|
+
// `var(--wr-color-primary-lighter)` on the page palette, which is the
|
|
416
|
+
// half-recoloured subtree this mixin exists to end.
|
|
417
|
+
--wr-color-#{$name}-light: #{color.adjust($base, $lightness: 5%)};
|
|
418
|
+
--wr-color-#{$name}-lighter: #{color.adjust($base, $lightness: 10%)};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
@include derived;
|
|
422
|
+
}
|
|
423
|
+
|
|
322
424
|
:root {
|
|
323
425
|
// Declared here so the light token set also claims the light UA scheme.
|
|
324
426
|
// Without it the browser fell back to the OS preference, and an app running
|
package/theme/styles/_focus.scss
CHANGED
|
@@ -18,6 +18,35 @@
|
|
|
18
18
|
box-shadow: 0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// Button — `wr-btn`, `button[wr-btn]` and `a[wr-btn]` all carry `.wr-btn` on the
|
|
22
|
+
// element that takes focus, so one rule covers all three forms, and with them
|
|
23
|
+
// every control BUILT out of a button: the pagination page cells and its prev /
|
|
24
|
+
// next arrows are `<wr-btn>` elements with a `.wr-pagination__*` class beside
|
|
25
|
+
// this one.
|
|
26
|
+
//
|
|
27
|
+
// It was missing until v14.1, and the button is the widest hole that could have
|
|
28
|
+
// been left: `--wr-focus-ring-*` is documented as "retheme the ring once and
|
|
29
|
+
// every control follows", and rethemed the ring on nine components while the
|
|
30
|
+
// most-used control in the catalog kept the UA outline — which no token
|
|
31
|
+
// reaches, does not honour `--wr-focus-ring-width`, and renders differently in
|
|
32
|
+
// every browser. The rule sits here rather than in `button/styles` because this
|
|
33
|
+
// file IS the ring's home; a second hand-rolled copy is what the mixin exists to
|
|
34
|
+
// prevent.
|
|
35
|
+
//
|
|
36
|
+
// Safe as an OUTSET ring: `.wr-btn` sets no `overflow`, and the one place
|
|
37
|
+
// buttons are packed edge to edge — `.wr-btn-group` — already raises the focused
|
|
38
|
+
// segment with `z-index: 1`, so the ring paints over its neighbours instead of
|
|
39
|
+
// under them.
|
|
40
|
+
.wr-btn:focus-visible {
|
|
41
|
+
@include focus-ring;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Table column-sort control — a bare `<button>` inside `.wr-table__th-inner`,
|
|
45
|
+
// with no focus style of its own.
|
|
46
|
+
.wr-table__sort-btn:focus-visible {
|
|
47
|
+
@include focus-ring;
|
|
48
|
+
}
|
|
49
|
+
|
|
21
50
|
// Tabs — `.wr-tabs__strip` is `overflow-y: hidden` (to suppress a stray
|
|
22
51
|
// vertical scrollbar) and its box is exactly the tab's height, so an outset
|
|
23
52
|
// ring loses both horizontal strokes and renders as two disconnected bars.
|
|
@@ -102,7 +131,8 @@
|
|
|
102
131
|
@include focus-ring;
|
|
103
132
|
}
|
|
104
133
|
|
|
105
|
-
// Pagination ellipsis is non-interactive; page buttons
|
|
134
|
+
// Pagination ellipsis is non-interactive; page buttons take the `.wr-btn` rule
|
|
135
|
+
// at the top of this file, since that is what they are.
|
|
106
136
|
|
|
107
137
|
// Dropdown menu items
|
|
108
138
|
.wr-dropdown-item:focus-visible {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Dark theme.
|
|
2
|
+
//
|
|
3
|
+
// Keyed on `theme.dark-selector()`, never on a literal `[data-theme='dark']`.
|
|
4
|
+
// The attribute is renameable — `@use 'ngwr' with ($theme-attribute: '…')`
|
|
5
|
+
// alongside `provideWrTheme({ attribute: '…' })` — and a hand-written literal
|
|
6
|
+
// misses the rename in both directions: this block stops firing under the
|
|
7
|
+
// configured name, and it keeps firing under `data-theme`, which is the
|
|
8
|
+
// attribute a foreign design system owns and the rename exists to escape.
|
|
9
|
+
//
|
|
10
|
+
// It lives outside the `styleUrl` closure for the same reason. A component
|
|
11
|
+
// stylesheet is compiled when the LIBRARY is built, where `$theme-attribute` can
|
|
12
|
+
// only ever be the default, and Angular appends that copy after the app's linked
|
|
13
|
+
// sheet — so an inlined literal would not merely be dead, it would outrank the
|
|
14
|
+
// correctly-named rule beside it.
|
|
15
|
+
@use '../../theme/styles' as theme;
|
|
16
|
+
|
|
17
|
+
#{theme.dark-selector()} .wr-tilt-glare {
|
|
18
|
+
--wr-tilt-glare-color: rgb(255 255 255 / 25%);
|
|
19
|
+
|
|
20
|
+
mix-blend-mode: overlay;
|
|
21
|
+
}
|
|
@@ -11,5 +11,10 @@
|
|
|
11
11
|
// box-sizing reset into the compiled component styles, which ng-packagr then
|
|
12
12
|
// embeds in the FESM bundle as a string. `tilt-card.scss` forwards `_rules`
|
|
13
13
|
// instead, so it carries this component's own CSS and nothing else.
|
|
14
|
+
//
|
|
15
|
+
// `_dark` is loaded from HERE for a second reason: its selector is built out of
|
|
16
|
+
// `$theme-attribute`, which only a stylesheet compiled by the consuming app can
|
|
17
|
+
// configure, so a copy inside the bundle could only ever carry the default name.
|
|
14
18
|
@use '../../theme/styles';
|
|
15
19
|
@forward 'rules';
|
|
20
|
+
@forward 'dark';
|
package/types/ngwr-button.d.ts
CHANGED
|
@@ -65,6 +65,16 @@ type WrButtonIconPosition = 'start' | 'end';
|
|
|
65
65
|
* every child — child `[shape]` inputs are ignored so the group reads as
|
|
66
66
|
* one coherent control.
|
|
67
67
|
*
|
|
68
|
+
* **Inside a `<form>`, use the native form.** `<wr-btn>` is a custom element
|
|
69
|
+
* carrying `role="button"`, and no custom element submits a form — the platform
|
|
70
|
+
* submits for `<button>`, `<input type="submit">` and `<input type="image">`
|
|
71
|
+
* and nothing else. That is why there is no `type` input: it would look like it
|
|
72
|
+
* worked. Implicit submission (Enter in a text field) does not reach it either.
|
|
73
|
+
*
|
|
74
|
+
* ```html
|
|
75
|
+
* <button wr-btn type="submit" color="primary">Save</button>
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
68
78
|
* @see https://ngwr.dev/reference/components/button
|
|
69
79
|
*/
|
|
70
80
|
declare class WrButton {
|
|
@@ -162,6 +172,39 @@ declare class WrButton {
|
|
|
162
172
|
* `pointer-events: none`.
|
|
163
173
|
*/
|
|
164
174
|
protected onHostKeydown(event: KeyboardEvent): void;
|
|
175
|
+
private readonly injector;
|
|
176
|
+
/**
|
|
177
|
+
* Whether this button is the one the caret was on, so it can be handed back
|
|
178
|
+
* the focus that goes missing while it is off.
|
|
179
|
+
*
|
|
180
|
+
* A control that becomes `disabled` while focused stops being a focusable
|
|
181
|
+
* area, and the browser runs the unfocusing steps: nothing else is nominated,
|
|
182
|
+
* so the caret lands on `<body>`. With `disabledWhenLoading` on by default
|
|
183
|
+
* that happens on EVERY async button — a keyboard user presses Enter on
|
|
184
|
+
* "Save" and the next Tab restarts from the top of the document, while a
|
|
185
|
+
* screen-reader user is told neither that the wait began nor that it ended,
|
|
186
|
+
* because the element they were on has left the a11y tree. The `<wr-btn>`
|
|
187
|
+
* element form loses its `tabindex` instead of gaining `disabled` and is
|
|
188
|
+
* unfocused for the same reason.
|
|
189
|
+
*
|
|
190
|
+
* Deliberately NOT keyed on reading `activeElement` when `isOff()` flips: an
|
|
191
|
+
* effect in this component's own view runs AFTER the parent has applied this
|
|
192
|
+
* directive's host bindings, so by then the attribute has landed and the
|
|
193
|
+
* browser has already moved the caret — the read would answer `<body>` on
|
|
194
|
+
* every real browser and the button on jsdom, which is the worst of both.
|
|
195
|
+
*
|
|
196
|
+
* The flag is written by the focus listeners instead, and a `blur` fired
|
|
197
|
+
* WHILE off keeps it set rather than clearing it: that blur is the browser
|
|
198
|
+
* taking the caret away, not the user leaving. A browser that fires no blur
|
|
199
|
+
* on disable at all is covered too — the flag simply stays as `focus` left it,
|
|
200
|
+
* and the `<body>` test below is what decides whether the focus is orphaned.
|
|
201
|
+
*/
|
|
202
|
+
private hadFocus;
|
|
203
|
+
/** @internal Host `focus` — see `hadFocus`. */
|
|
204
|
+
protected onHostFocus(): void;
|
|
205
|
+
/** @internal Host `blur` — see `hadFocus`. */
|
|
206
|
+
protected onHostBlur(): void;
|
|
207
|
+
constructor();
|
|
165
208
|
protected readonly classes: _angular_core.Signal<string>;
|
|
166
209
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrButton, never>;
|
|
167
210
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrButton, "wr-btn, button[wr-btn], a[wr-btn]", never, { "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "outlined": { "alias": "outlined"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "disabledWhenLoading": { "alias": "disabledWhenLoading"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
package/types/ngwr-dropdown.d.ts
CHANGED
|
@@ -80,14 +80,30 @@ declare class WrDropdown {
|
|
|
80
80
|
private readonly destroyRef;
|
|
81
81
|
/** @internal Public so host bindings can read it. */
|
|
82
82
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
83
|
+
/** The id used only when the consumer's element carries none of its own. */
|
|
84
|
+
private readonly fallbackId;
|
|
83
85
|
/**
|
|
84
86
|
* Id the menu names itself after. The trigger is the CONSUMER's own element, so
|
|
85
87
|
* an `id` they already put there wins: overwriting it broke `<label for>`,
|
|
86
88
|
* `document.getElementById` and any `aria-labelledby` aimed at that button from
|
|
87
89
|
* elsewhere in their app. The generated one is only a fallback so the menu has
|
|
88
90
|
* something to reference.
|
|
91
|
+
*
|
|
92
|
+
* A GETTER, read fresh by the host binding on every pass, rather than a field
|
|
93
|
+
* resolved in the constructor. A static `id="…"` is on the element before a
|
|
94
|
+
* directive is instantiated and so was already honoured; a BOUND `[id]` is
|
|
95
|
+
* not — it lands with the rest of the template's bindings, which run before
|
|
96
|
+
* host bindings but after construction, so the constructor read an empty
|
|
97
|
+
* string, fell through to the fallback, and the host binding then wrote that
|
|
98
|
+
* fallback over the value the template had just set. Everything bound was
|
|
99
|
+
* lost — `[id]`, `[attr.id]` and an interpolated `id="dd-{{ n }}"` alike —
|
|
100
|
+
* while the static form survived, which is the shape that makes it look like
|
|
101
|
+
* a naming convention rather than a defect.
|
|
102
|
+
*
|
|
103
|
+
* `.id` rather than `getAttribute`: it is always a string, and an empty one is
|
|
104
|
+
* no id at all, so it falls through to the fallback.
|
|
89
105
|
*/
|
|
90
|
-
protected
|
|
106
|
+
protected get triggerId(): string;
|
|
91
107
|
private overlayRef;
|
|
92
108
|
constructor();
|
|
93
109
|
/** Open the menu. */
|
|
@@ -169,8 +169,9 @@ declare class WrFormFieldHarness extends ContentContainerComponentHarness {
|
|
|
169
169
|
*
|
|
170
170
|
* `null` does not mean the consumer set no hint: the error block takes the
|
|
171
171
|
* hint's slot outright, so a field with a visible message has no hint in the DOM
|
|
172
|
-
* at all
|
|
173
|
-
*
|
|
172
|
+
* at all — which is also why the hint's id stops being published at the same
|
|
173
|
+
* moment. Whether the CONTROL announces it is a separate question, and one this
|
|
174
|
+
* harness answers through {@link getAnnouncedDescription}.
|
|
174
175
|
*/
|
|
175
176
|
getHint(): Promise<string | null>;
|
|
176
177
|
/**
|
|
@@ -243,11 +244,16 @@ declare class WrFormFieldHarness extends ContentContainerComponentHarness {
|
|
|
243
244
|
/**
|
|
244
245
|
* The ids the projected control names in `aria-describedby`, in order.
|
|
245
246
|
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
247
|
+
* Which id that is depends on the CONTROL, not on the field, and the answer is
|
|
248
|
+
* worth knowing before reading a result. A control that composes the pair with
|
|
249
|
+
* `useFormFieldAria()` names the error block while one is showing and the hint
|
|
250
|
+
* otherwise. A control that reads the field's `describedBy` on its own — the
|
|
251
|
+
* `[wrInput]` directive, `wr-segmented` and `wr-slider` — names the error block
|
|
252
|
+
* and nothing else, so an empty list beside a visible hint is that control's
|
|
253
|
+
* answer rather than a broken field.
|
|
254
|
+
*
|
|
255
|
+
* The two are separate because folding the hint into the one signal announced
|
|
256
|
+
* every hinted field as invalid: those three derive `aria-invalid` from it.
|
|
251
257
|
*/
|
|
252
258
|
getDescribedByIds(): Promise<string[]>;
|
|
253
259
|
/**
|
package/types/ngwr-form.d.ts
CHANGED
|
@@ -66,6 +66,20 @@ interface WrFormFieldContext {
|
|
|
66
66
|
readonly errorKeys: Signal<readonly string[]>;
|
|
67
67
|
/** Id of the element listing the visible messages, or `null` when there are none. */
|
|
68
68
|
readonly describedBy: Signal<string | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Id of the field's hint, or `null` when it is showing none — including while
|
|
71
|
+
* an error has replaced it, since the two never render together and an
|
|
72
|
+
* `aria-describedby` naming an absent element is an author error.
|
|
73
|
+
*
|
|
74
|
+
* Separate from {@link describedBy} rather than folded into it because the two
|
|
75
|
+
* carry different weight: a control keyed `aria-invalid` on "the field is
|
|
76
|
+
* describing me" would announce itself invalid for a plain hint. Compose the
|
|
77
|
+
* pair with `useFormFieldAria()` instead of reading either one directly.
|
|
78
|
+
*
|
|
79
|
+
* Optional so an app that provides its own `WR_FORM_FIELD` keeps compiling; a
|
|
80
|
+
* field without it simply describes nothing but its errors.
|
|
81
|
+
*/
|
|
82
|
+
readonly hintId?: Signal<string | null>;
|
|
69
83
|
}
|
|
70
84
|
/** Present only inside a `<wr-form-field>`; inject with `{ optional: true }`. */
|
|
71
85
|
declare const WR_FORM_FIELD: InjectionToken<WrFormFieldContext>;
|
|
@@ -187,6 +201,20 @@ declare class WrFormField implements WrFormFieldContext {
|
|
|
187
201
|
readonly errorKeys: _angular_core.Signal<readonly string[]>;
|
|
188
202
|
/** @internal Read by the projected control so a screen reader is pointed at the message. */
|
|
189
203
|
readonly describedBy: _angular_core.Signal<string | null>;
|
|
204
|
+
/**
|
|
205
|
+
* @internal Read by the projected control so the hint is announced with the field.
|
|
206
|
+
*
|
|
207
|
+
* The hint used to carry no id at all, so the only thing `aria-describedby`
|
|
208
|
+
* could ever name was the error block: the sentence explaining what to type was
|
|
209
|
+
* on screen and reached a screen-reader user through no path whatsoever, and
|
|
210
|
+
* the one gate that could have said so does not exist — axe has no rule that
|
|
211
|
+
* visible help text must be programmatically associated.
|
|
212
|
+
*
|
|
213
|
+
* `null` while an error is showing, because the template swaps the hint out for
|
|
214
|
+
* the message; publishing the id anyway would point every control at an element
|
|
215
|
+
* that had just left the document.
|
|
216
|
+
*/
|
|
217
|
+
readonly hintId: _angular_core.Signal<string | null>;
|
|
190
218
|
/**
|
|
191
219
|
* Render a catalog message for any error the markup does not already answer.
|
|
192
220
|
*
|
|
@@ -223,24 +251,31 @@ declare class WrFormField implements WrFormFieldContext {
|
|
|
223
251
|
|
|
224
252
|
/** What {@link useFormFieldAria} hands a control to bind on its own element. */
|
|
225
253
|
interface WrFormFieldAria {
|
|
226
|
-
/**
|
|
254
|
+
/**
|
|
255
|
+
* Id of the field's message block while it is showing one, of its hint
|
|
256
|
+
* otherwise, and `null` when it is showing neither.
|
|
257
|
+
*/
|
|
227
258
|
readonly describedBy: Signal<string | null>;
|
|
228
|
-
/** `'true'` while the field
|
|
259
|
+
/** `'true'` while the field has a validation error, `null` otherwise. */
|
|
229
260
|
readonly ariaInvalid: Signal<'true' | null>;
|
|
230
261
|
}
|
|
231
262
|
/**
|
|
232
|
-
* The two attributes that make a `<wr-form-field>`'s visible
|
|
233
|
-
* screen reader
|
|
263
|
+
* The two attributes that make a `<wr-form-field>`'s visible text — its error
|
|
264
|
+
* message, or its hint — reach a screen reader. Bind both on whichever element
|
|
265
|
+
* carries the control's role.
|
|
234
266
|
*
|
|
235
|
-
* Without them the
|
|
236
|
-
* control announces itself as valid, and the
|
|
237
|
-
* No automated gate catches that — axe has no rule that a visible error
|
|
238
|
-
* programmatically associated with its control — so this helper exists
|
|
239
|
-
* the wiring one line per control rather than three, and the specs are
|
|
267
|
+
* Without them the copy the field renders is visible and nothing else: the
|
|
268
|
+
* control announces itself as valid, and the text is associated with nothing.
|
|
269
|
+
* No automated gate catches that — axe has no rule that a visible error or hint
|
|
270
|
+
* must be programmatically associated with its control — so this helper exists
|
|
271
|
+
* to make the wiring one line per control rather than three, and the specs are
|
|
272
|
+
* the gate.
|
|
240
273
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
274
|
+
* The field renders an error OR a hint, never both, so `describedBy` names
|
|
275
|
+
* whichever is on screen and `aria-invalid` is keyed SEPARATELY, on the field's
|
|
276
|
+
* `errorKeys()`. Deriving it from `describedBy` instead — which is what every
|
|
277
|
+
* control did while a hint had no id to name — makes a field with a plain hint
|
|
278
|
+
* announce its control as invalid the moment the hint becomes describable.
|
|
244
279
|
*
|
|
245
280
|
* Must be called from an injection context (a field initialiser or a
|
|
246
281
|
* constructor). Returns inert signals outside a `<wr-form-field>`.
|
package/types/ngwr-input.d.ts
CHANGED
|
@@ -66,8 +66,9 @@ declare class WrInput {
|
|
|
66
66
|
* invisible to a screen reader, which never learns the field is invalid or
|
|
67
67
|
* what the message says.
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
private readonly fieldAria;
|
|
70
70
|
protected readonly describedBy: _angular_core.Signal<string | null>;
|
|
71
|
+
protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
|
|
71
72
|
/**
|
|
72
73
|
* Control size. Unset, it falls back to
|
|
73
74
|
* `provideWrConfig({ input: { size } })`. @default 'md'
|
package/types/ngwr-rating.d.ts
CHANGED
|
@@ -4,8 +4,13 @@ import { FormValueControl } from '@angular/forms/signals';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Star rating input. Click or hover to set a value; supports half-star
|
|
7
|
-
* increments via `step="0.5"`. Value is `number | null
|
|
8
|
-
*
|
|
7
|
+
* increments via `step="0.5"`. Value is `number | null`.
|
|
8
|
+
*
|
|
9
|
+
* `[0, count]` bounds what this control's OWN edits produce — a click, an arrow
|
|
10
|
+
* key, `End`. A value written from outside is displayed and announced clamped
|
|
11
|
+
* (a slider cannot report an `aria-valuenow` past its own `aria-valuemax`) and
|
|
12
|
+
* left in the model as it stands, the same rule `wr-slider` and
|
|
13
|
+
* `wr-input-number` follow.
|
|
9
14
|
*
|
|
10
15
|
* A signal-forms native control: it implements `FormValueControl<number | null>`,
|
|
11
16
|
* so `[formField]` binds straight to its `value` model — no
|
|
@@ -68,8 +73,25 @@ declare class WrRating implements FormValueControl<number | null> {
|
|
|
68
73
|
* an error message on an element nobody could focus.
|
|
69
74
|
*/
|
|
70
75
|
protected readonly focusable: _angular_core.Signal<boolean>;
|
|
71
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* What we actually render — hover wins while hovering.
|
|
78
|
+
*
|
|
79
|
+
* Clamped, because there is no such thing as drawing six stars in a row of
|
|
80
|
+
* five, and the same number is what `aria-valuenow` reports: a `role="slider"`
|
|
81
|
+
* whose value sits outside its own min / max is an invalid slider whatever the
|
|
82
|
+
* model holds. The MODEL is left alone — see the note above `fillFor` for why
|
|
83
|
+
* the clamp is not written back.
|
|
84
|
+
*/
|
|
72
85
|
protected readonly displayValue: _angular_core.Signal<number>;
|
|
86
|
+
/**
|
|
87
|
+
* What the slider REPORTS, and where the arrows start from.
|
|
88
|
+
*
|
|
89
|
+
* Deliberately not `displayValue`: a hover preview is a pointer affordance and
|
|
90
|
+
* must not be announced as the current value, and an arrow press after a hover
|
|
91
|
+
* has to step from the committed number rather than from wherever the mouse
|
|
92
|
+
* happened to rest.
|
|
93
|
+
*/
|
|
94
|
+
protected readonly announcedValue: _angular_core.Signal<number>;
|
|
73
95
|
protected readonly slots: _angular_core.Signal<number[]>;
|
|
74
96
|
/**
|
|
75
97
|
* Reading direction, for the two places it changes the answer: the arrows and
|
|
@@ -84,7 +106,6 @@ declare class WrRating implements FormValueControl<number | null> {
|
|
|
84
106
|
/** The surrounding `<wr-form-field>`'s error state. @internal */
|
|
85
107
|
protected readonly fieldAria: ngwr_form.WrFormFieldAria;
|
|
86
108
|
protected readonly classes: _angular_core.Signal<string>;
|
|
87
|
-
constructor();
|
|
88
109
|
/** Fill ratio for slot `i` in `[0, 1]` — drives the CSS clip width. */
|
|
89
110
|
protected fillFor(i: number): number;
|
|
90
111
|
protected onSlotMove(event: MouseEvent, index: number): void;
|
|
@@ -141,6 +141,7 @@ declare class WrSegmented<T = unknown> implements FormValueControl<T | null> {
|
|
|
141
141
|
* because the field only publishes an id once it is showing something — announcing
|
|
142
142
|
* "invalid" while pointing at nothing is worse than staying quiet.
|
|
143
143
|
*/
|
|
144
|
+
private readonly fieldAria;
|
|
144
145
|
protected readonly describedBy: _angular_core.Signal<string | null>;
|
|
145
146
|
protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
|
|
146
147
|
/** Index of the selected option, or `-1` when nothing is selected. */
|