@slotted/styles 0.0.0-stage → 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +10 -2
- package/package.json +276 -3
- package/src/accordion/accordion.css +96 -0
- package/src/accordion/accordion.tokens.json +14 -0
- package/src/action-bar/action-bar.css +455 -0
- package/src/action-bar/action-bar.tokens.json +50 -0
- package/src/action-sheet/action-sheet.css +462 -0
- package/src/action-sheet/action-sheet.tokens.json +59 -0
- package/src/alert/alert.css +764 -0
- package/src/alert/alert.tokens.json +77 -0
- package/src/app-shell/app-shell.css +1899 -0
- package/src/app-shell/app-shell.tokens.json +88 -0
- package/src/aspect-ratio/aspect-ratio.css +131 -0
- package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
- package/src/attachment/attachment.css +906 -0
- package/src/attachment/attachment.tokens.json +85 -0
- package/src/avatar/avatar.css +598 -0
- package/src/avatar/avatar.tokens.json +64 -0
- package/src/avatar-group/avatar-group.css +268 -0
- package/src/avatar-group/avatar-group.tokens.json +16 -0
- package/src/badge/badge.css +462 -0
- package/src/badge/badge.tokens.json +58 -0
- package/src/breadcrumb/breadcrumb.css +441 -0
- package/src/breadcrumb/breadcrumb.tokens.json +50 -0
- package/src/button/button.css +754 -0
- package/src/button/button.tokens.json +72 -0
- package/src/button-group/button-group.css +455 -0
- package/src/button-group/button-group.tokens.json +11 -0
- package/src/calendar/calendar.css +846 -0
- package/src/calendar/calendar.tokens.json +67 -0
- package/src/card/card.css +602 -0
- package/src/card/card.tokens.json +68 -0
- package/src/carousel/carousel.css +860 -0
- package/src/carousel/carousel.tokens.json +62 -0
- package/src/cascader/cascader.css +1320 -0
- package/src/cascader/cascader.tokens.json +103 -0
- package/src/chart/chart.css +1473 -0
- package/src/chart/chart.tokens.json +107 -0
- package/src/checkbox/checkbox.css +1011 -0
- package/src/checkbox/checkbox.tokens.json +102 -0
- package/src/checkbox-group/checkbox-group.css +70 -0
- package/src/checkbox-group/checkbox-group.tokens.json +6 -0
- package/src/code-block/code-block.css +555 -0
- package/src/code-block/code-block.tokens.json +69 -0
- package/src/collapsible/collapsible.css +546 -0
- package/src/collapsible/collapsible.tokens.json +55 -0
- package/src/color-picker/color-picker.css +607 -0
- package/src/color-picker/color-picker.tokens.json +58 -0
- package/src/column-manager/column-manager.css +452 -0
- package/src/column-manager/column-manager.tokens.json +43 -0
- package/src/combobox/combobox.css +1048 -0
- package/src/combobox/combobox.tokens.json +112 -0
- package/src/command-palette/command-palette.css +1000 -0
- package/src/command-palette/command-palette.tokens.json +75 -0
- package/src/container/container.css +198 -0
- package/src/container/container.tokens.json +18 -0
- package/src/context-menu/context-menu.css +104 -0
- package/src/context-menu/context-menu.tokens.json +11 -0
- package/src/currency-field/currency-field.css +787 -0
- package/src/currency-field/currency-field.tokens.json +80 -0
- package/src/dashboard-grid/dashboard-grid.css +748 -0
- package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
- package/src/data-grid/data-grid.css +2484 -0
- package/src/data-grid/data-grid.tokens.json +100 -0
- package/src/data-list/data-list.css +455 -0
- package/src/data-list/data-list.tokens.json +35 -0
- package/src/date-field/date-field.css +560 -0
- package/src/date-field/date-field.tokens.json +80 -0
- package/src/date-picker/date-picker.css +420 -0
- package/src/date-picker/date-picker.tokens.json +49 -0
- package/src/date-range-picker/date-range-picker.css +983 -0
- package/src/date-range-picker/date-range-picker.tokens.json +109 -0
- package/src/datetime-field/datetime-field.css +850 -0
- package/src/datetime-field/datetime-field.tokens.json +91 -0
- package/src/datetime-picker/datetime-picker.css +843 -0
- package/src/datetime-picker/datetime-picker.tokens.json +78 -0
- package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
- package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
- package/src/description-list/description-list.css +675 -0
- package/src/description-list/description-list.tokens.json +66 -0
- package/src/detail-panel/detail-panel.css +329 -0
- package/src/detail-panel/detail-panel.tokens.json +33 -0
- package/src/dialog/dialog.css +968 -0
- package/src/dialog/dialog.tokens.json +66 -0
- package/src/divider/divider.css +131 -0
- package/src/divider/divider.tokens.json +18 -0
- package/src/drawer/drawer.css +1303 -0
- package/src/drawer/drawer.tokens.json +75 -0
- package/src/entity-picker/entity-picker.css +1367 -0
- package/src/entity-picker/entity-picker.tokens.json +118 -0
- package/src/event-calendar/event-calendar.css +2148 -0
- package/src/event-calendar/event-calendar.tokens.json +87 -0
- package/src/field/field.css +707 -0
- package/src/field/field.tokens.json +58 -0
- package/src/field-group/field-group.css +226 -0
- package/src/field-group/field-group.tokens.json +33 -0
- package/src/filter-bar/filter-bar.css +1306 -0
- package/src/filter-bar/filter-bar.tokens.json +78 -0
- package/src/form/form.css +218 -0
- package/src/form/form.tokens.json +32 -0
- package/src/fullscreen/fullscreen.css +376 -0
- package/src/fullscreen/fullscreen.tokens.json +50 -0
- package/src/grid/grid.css +173 -0
- package/src/grid/grid.tokens.json +20 -0
- package/src/highlight/highlight.css +135 -0
- package/src/highlight/highlight.tokens.json +16 -0
- package/src/hover-card/hover-card.css +93 -0
- package/src/hover-card/hover-card.tokens.json +17 -0
- package/src/icon/icon.css +136 -0
- package/src/icon/icon.tokens.json +14 -0
- package/src/image/image.css +449 -0
- package/src/image/image.tokens.json +27 -0
- package/src/import-export-center/import-export-center.css +1175 -0
- package/src/import-export-center/import-export-center.tokens.json +84 -0
- package/src/inline/inline.css +149 -0
- package/src/inline/inline.tokens.json +14 -0
- package/src/inline-message/inline-message.css +396 -0
- package/src/inline-message/inline-message.tokens.json +19 -0
- package/src/kbd/kbd.css +490 -0
- package/src/kbd/kbd.tokens.json +40 -0
- package/src/link/link.css +237 -0
- package/src/link/link.tokens.json +25 -0
- package/src/list/list.css +240 -0
- package/src/list/list.tokens.json +42 -0
- package/src/list-item/list-item.css +937 -0
- package/src/list-item/list-item.tokens.json +114 -0
- package/src/listbox/listbox.css +674 -0
- package/src/listbox/listbox.tokens.json +72 -0
- package/src/loading-overlay/loading-overlay.css +730 -0
- package/src/loading-overlay/loading-overlay.tokens.json +48 -0
- package/src/markdown/markdown.css +168 -0
- package/src/markdown/markdown.tokens.json +18 -0
- package/src/menu/menu.css +817 -0
- package/src/menu/menu.tokens.json +78 -0
- package/src/menubar/menubar.css +170 -0
- package/src/menubar/menubar.tokens.json +32 -0
- package/src/message/message.css +1453 -0
- package/src/message/message.tokens.json +85 -0
- package/src/message-scroller/message-scroller.css +371 -0
- package/src/message-scroller/message-scroller.tokens.json +47 -0
- package/src/multi-select/multi-select.css +1427 -0
- package/src/multi-select/multi-select.tokens.json +114 -0
- package/src/navigation-menu/navigation-menu.css +1029 -0
- package/src/navigation-menu/navigation-menu.tokens.json +70 -0
- package/src/notification-center/notification-center.css +856 -0
- package/src/notification-center/notification-center.tokens.json +84 -0
- package/src/number-field/number-field.css +794 -0
- package/src/number-field/number-field.tokens.json +80 -0
- package/src/otp-input/otp-input.css +525 -0
- package/src/otp-input/otp-input.tokens.json +69 -0
- package/src/page/page.css +179 -0
- package/src/page/page.tokens.json +20 -0
- package/src/page-header/page-header.css +1181 -0
- package/src/page-header/page-header.tokens.json +71 -0
- package/src/pagination/pagination.css +500 -0
- package/src/pagination/pagination.tokens.json +56 -0
- package/src/popover/popover.css +526 -0
- package/src/popover/popover.tokens.json +60 -0
- package/src/progress-indicator/progress-indicator.css +1584 -0
- package/src/progress-indicator/progress-indicator.tokens.json +50 -0
- package/src/prompt-composer/prompt-composer.css +680 -0
- package/src/prompt-composer/prompt-composer.tokens.json +99 -0
- package/src/prose/prose.css +733 -0
- package/src/prose/prose.tokens.json +79 -0
- package/src/radio-group/radio-group.css +778 -0
- package/src/radio-group/radio-group.tokens.json +103 -0
- package/src/rating/rating.css +1071 -0
- package/src/rating/rating.tokens.json +88 -0
- package/src/result-state/result-state.css +980 -0
- package/src/result-state/result-state.tokens.json +63 -0
- package/src/runtime-properties.mjs +321 -0
- package/src/saved-views/saved-views.css +394 -0
- package/src/saved-views/saved-views.tokens.json +41 -0
- package/src/scroll-area/scroll-area.css +481 -0
- package/src/scroll-area/scroll-area.tokens.json +15 -0
- package/src/section/section.css +177 -0
- package/src/section/section.tokens.json +39 -0
- package/src/segmented-control/segmented-control.css +564 -0
- package/src/segmented-control/segmented-control.tokens.json +67 -0
- package/src/select/select.css +1593 -0
- package/src/select/select.tokens.json +110 -0
- package/src/side-navigation/side-navigation.css +1096 -0
- package/src/side-navigation/side-navigation.tokens.json +87 -0
- package/src/skeleton/skeleton.css +431 -0
- package/src/skeleton/skeleton.tokens.json +29 -0
- package/src/slider/slider.css +792 -0
- package/src/slider/slider.tokens.json +75 -0
- package/src/sparkline/sparkline.css +282 -0
- package/src/sparkline/sparkline.tokens.json +45 -0
- package/src/spinner/spinner.css +224 -0
- package/src/spinner/spinner.tokens.json +8 -0
- package/src/split-button/split-button.css +253 -0
- package/src/split-button/split-button.tokens.json +12 -0
- package/src/splitter/splitter.css +336 -0
- package/src/splitter/splitter.tokens.json +24 -0
- package/src/stack/stack.css +128 -0
- package/src/stack/stack.tokens.json +14 -0
- package/src/stat-card/stat-card.css +641 -0
- package/src/stat-card/stat-card.tokens.json +95 -0
- package/src/status-indicator/status-indicator.css +481 -0
- package/src/status-indicator/status-indicator.tokens.json +38 -0
- package/src/stepper/stepper.css +629 -0
- package/src/stepper/stepper.tokens.json +72 -0
- package/src/switch/switch.css +703 -0
- package/src/switch/switch.tokens.json +75 -0
- package/src/table/table.css +1482 -0
- package/src/table/table.tokens.json +69 -0
- package/src/table-of-contents/table-of-contents.css +533 -0
- package/src/table-of-contents/table-of-contents.tokens.json +53 -0
- package/src/tabs/tabs.css +998 -0
- package/src/tabs/tabs.tokens.json +82 -0
- package/src/tag/tag.css +768 -0
- package/src/tag/tag.tokens.json +85 -0
- package/src/tags-input/tags-input.css +757 -0
- package/src/tags-input/tags-input.tokens.json +84 -0
- package/src/text-field/text-field.css +900 -0
- package/src/text-field/text-field.tokens.json +87 -0
- package/src/textarea/textarea.css +365 -0
- package/src/textarea/textarea.tokens.json +59 -0
- package/src/time-field/time-field.css +719 -0
- package/src/time-field/time-field.tokens.json +86 -0
- package/src/time-picker/time-picker.css +665 -0
- package/src/time-picker/time-picker.tokens.json +66 -0
- package/src/time-range-picker/time-range-picker.css +1287 -0
- package/src/time-range-picker/time-range-picker.tokens.json +134 -0
- package/src/timeline/timeline.css +1596 -0
- package/src/timeline/timeline.tokens.json +96 -0
- package/src/toast/toast.css +943 -0
- package/src/toast/toast.tokens.json +90 -0
- package/src/toggle/toggle.css +290 -0
- package/src/toggle/toggle.tokens.json +54 -0
- package/src/toggle-group/toggle-group.css +463 -0
- package/src/toggle-group/toggle-group.tokens.json +54 -0
- package/src/toolbar/toolbar.css +434 -0
- package/src/toolbar/toolbar.tokens.json +49 -0
- package/src/tooltip/tooltip.css +368 -0
- package/src/tooltip/tooltip.tokens.json +39 -0
- package/src/top-navigation/top-navigation.css +1287 -0
- package/src/top-navigation/top-navigation.tokens.json +91 -0
- package/src/tour/tour.css +680 -0
- package/src/tour/tour.tokens.json +67 -0
- package/src/transfer/transfer.css +571 -0
- package/src/transfer/transfer.tokens.json +49 -0
- package/src/tree/tree.css +1000 -0
- package/src/tree/tree.tokens.json +80 -0
- package/src/typography/typography.css +211 -0
- package/src/typography/typography.tokens.json +31 -0
- package/src/upload/upload.css +1706 -0
- package/src/upload/upload.tokens.json +123 -0
- package/src/visually-hidden/visually-hidden.css +52 -0
- package/src/visually-hidden/visually-hidden.tokens.json +1 -0
- package/src/wizard/wizard.css +740 -0
- package/src/wizard/wizard.tokens.json +63 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* ── One amount, in one currency ────────────────────────────────────────
|
|
4
|
+
*
|
|
5
|
+
* The frame `number-field` established, around a control that holds money.
|
|
6
|
+
* The shape is the same because the reason is: a `spinbutton`, like a
|
|
7
|
+
* `textbox`, may hold only non-interactive presentational children, so the
|
|
8
|
+
* two steppers are siblings of the control inside a frame with no role.
|
|
9
|
+
*
|
|
10
|
+
* What this family paints that the sibling does not is the alignment. An
|
|
11
|
+
* amount is read from its last digit — a column of them is compared on the
|
|
12
|
+
* cents — and under cents-first entry the caret lives at that edge, so the
|
|
13
|
+
* value is set against the reading end unless a consumer says otherwise.
|
|
14
|
+
*
|
|
15
|
+
* Every rule keys on `data-ui` and `data-part`. The field around the control
|
|
16
|
+
* mirrors its state onto the frame rather than styling through, so a control
|
|
17
|
+
* used outside a field looks the same as one inside it.
|
|
18
|
+
*/
|
|
19
|
+
[data-ui='currency-field'][data-part='root'] {
|
|
20
|
+
/**
|
|
21
|
+
* Type, height, inline padding, gap and glyph size all come from the
|
|
22
|
+
* control scales — the only ones the theme restates per density — so an
|
|
23
|
+
* amount in a dense table shrinks whole rather than in parts.
|
|
24
|
+
*/
|
|
25
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
26
|
+
--_height: var(--slotted-control-height-md, 34px);
|
|
27
|
+
--_padding-inline: var(--slotted-control-padding-inline-md, 13px);
|
|
28
|
+
--_gap: var(--slotted-control-gap-md, 8px);
|
|
29
|
+
/** The floor under the glyph scale at the dense step (SL3); a family token so a theme can retune it. */
|
|
30
|
+
--_icon-floor: var(--slotted-currency-field-icon-size-min, 14px);
|
|
31
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
|
|
32
|
+
--_inner-size: var(--slotted-control-inner-size-md, 24px);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The stepper's cross measurement — the column's width when the two halves
|
|
36
|
+
* are stacked, and each button's width when they are split. The glyph plus
|
|
37
|
+
* a step of air on each side — the box every inner control in the library
|
|
38
|
+
* draws (R2) — capped at the inner size of a control at this step
|
|
39
|
+
* (`--slotted-control-inner-size-*`) and floored at the WCAG 2.2 minimum.
|
|
40
|
+
*/
|
|
41
|
+
--_stepper-size: var(
|
|
42
|
+
--slotted-currency-field-stepper-size,
|
|
43
|
+
max(
|
|
44
|
+
var(--slotted-target-min, 24px),
|
|
45
|
+
min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size))
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The split buttons are the inner controls `text-field` draws: the glyph
|
|
51
|
+
* plus a step of air, capped at the inner size, inset concentrically — the
|
|
52
|
+
* air beside a button equals the air above and below it, and its corner is
|
|
53
|
+
* the frame's less that air (docs/history/designs/2026-10-01-currency-field-reui-dossier.md § 3).
|
|
54
|
+
*/
|
|
55
|
+
--_action-size: var(
|
|
56
|
+
--slotted-currency-field-action-size,
|
|
57
|
+
min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size))
|
|
58
|
+
);
|
|
59
|
+
--_inset: max(
|
|
60
|
+
0px,
|
|
61
|
+
calc(
|
|
62
|
+
(var(--_height) - 2 * var(--slotted-control-border-width, 1px) - var(--_action-size)) / 2
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
--_action-radius: max(
|
|
66
|
+
var(--slotted-radius-xs, 2px),
|
|
67
|
+
calc(var(--slotted-currency-field-radius, var(--slotted-control-radius, 4px)) - var(--_inset))
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The stacked column is inset by the smallest step rather than by
|
|
72
|
+
* `--_inset`: two halves share the frame's height, and the larger air
|
|
73
|
+
* would leave each half 12 pixels tall at `md`.
|
|
74
|
+
*/
|
|
75
|
+
--_column-inset: var(--slotted-space-1, 2px);
|
|
76
|
+
--_column-radius: max(
|
|
77
|
+
var(--slotted-radius-xs, 2px),
|
|
78
|
+
calc(
|
|
79
|
+
var(--slotted-currency-field-radius, var(--slotted-control-radius, 4px)) -
|
|
80
|
+
var(--_column-inset)
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
align-items: center;
|
|
85
|
+
background-color: var(
|
|
86
|
+
--slotted-currency-field-background,
|
|
87
|
+
var(--slotted-control-surface, Field)
|
|
88
|
+
);
|
|
89
|
+
/**
|
|
90
|
+
* The control step of the border scale rather than the strong one: a
|
|
91
|
+
* separator between two surfaces and the edge of a control are the same
|
|
92
|
+
* ratio and not the same weight.
|
|
93
|
+
*/
|
|
94
|
+
border: var(--slotted-control-border-width, 1px) solid
|
|
95
|
+
var(--slotted-currency-field-border-color, var(--slotted-control-border-color, ButtonBorder));
|
|
96
|
+
border-radius: var(--slotted-currency-field-radius, var(--slotted-control-radius, 4px));
|
|
97
|
+
box-shadow: var(--slotted-currency-field-shadow, var(--slotted-control-shadow, none));
|
|
98
|
+
box-sizing: border-box;
|
|
99
|
+
color: var(--slotted-currency-field-color, var(--slotted-text, CanvasText));
|
|
100
|
+
display: flex;
|
|
101
|
+
font-family: var(--slotted-control-font-family, system-ui, sans-serif);
|
|
102
|
+
font-size: var(--_font-size);
|
|
103
|
+
gap: var(--_gap);
|
|
104
|
+
inline-size: 100%;
|
|
105
|
+
/* A control in a grid track narrower than its intrinsic width has to shrink. */
|
|
106
|
+
min-inline-size: 0;
|
|
107
|
+
/* A minimum rather than a height: the frame is the taller of the control
|
|
108
|
+
scale and whatever a consumer put in an adornment. */
|
|
109
|
+
min-block-size: var(--_height);
|
|
110
|
+
padding-inline: var(--_padding-inline);
|
|
111
|
+
transition:
|
|
112
|
+
background-color var(--slotted-control-transition-duration)
|
|
113
|
+
var(--slotted-control-transition-easing),
|
|
114
|
+
border-color var(--slotted-control-transition-duration)
|
|
115
|
+
var(--slotted-control-transition-easing),
|
|
116
|
+
box-shadow var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The control. It gives up its own frame entirely and keeps everything that
|
|
121
|
+
* makes it a text control: the value, the caret, the selection and every
|
|
122
|
+
* native attribute a consumer wrote.
|
|
123
|
+
*
|
|
124
|
+
* The figures are tabular without an axis to ask for it. An amount whose
|
|
125
|
+
* digits change width as they are typed over is an amount that moves under
|
|
126
|
+
* the reader's eye, and under cents-first entry every keystroke rewrites the
|
|
127
|
+
* whole string — so the setting matters more here than anywhere else.
|
|
128
|
+
*/
|
|
129
|
+
[data-ui='currency-field'] > [data-part='input'] {
|
|
130
|
+
background-color: transparent;
|
|
131
|
+
/* The frame's border box, not its content box: on a coarse pointer the frame
|
|
132
|
+
is the touch target's height and the control it holds is too. Stretched
|
|
133
|
+
rather than a percentage of the frame, which is indefinite wherever the
|
|
134
|
+
frame is not stretched itself — a search field in a bar measured 17
|
|
135
|
+
pixels. The control paints no ground, so the frame's edge still shows. */
|
|
136
|
+
align-self: stretch;
|
|
137
|
+
margin-block: calc(var(--slotted-control-border-width, 1px) * -1);
|
|
138
|
+
border: 0;
|
|
139
|
+
color: inherit;
|
|
140
|
+
flex: 1 1 auto;
|
|
141
|
+
font: inherit;
|
|
142
|
+
font-variant-numeric: tabular-nums;
|
|
143
|
+
/* The frame draws the ring for it, so two rings never nest. */
|
|
144
|
+
outline: none;
|
|
145
|
+
padding: 0;
|
|
146
|
+
/* The intrinsic width of an `input` is about twenty characters, and a flex
|
|
147
|
+
item refuses to shrink below it without this. */
|
|
148
|
+
min-inline-size: 0;
|
|
149
|
+
text-overflow: ellipsis;
|
|
150
|
+
/**
|
|
151
|
+
* The value is its own bidi run, ordered by its own content.
|
|
152
|
+
*
|
|
153
|
+
* A formatted amount has no strong character in it — digits, a sign, two
|
|
154
|
+
* separators and a symbol are all weak or neutral — so in a right-to-left
|
|
155
|
+
* document the whole run takes the paragraph's direction and `-R$ 1.480,00`
|
|
156
|
+
* prints with the sign after the amount. `plaintext` resolves a run with no
|
|
157
|
+
* strong character to left-to-right, which is the order every numbering
|
|
158
|
+
* system writes a number in.
|
|
159
|
+
*/
|
|
160
|
+
unicode-bidi: plaintext;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
[data-ui='currency-field'] > [data-part='input']::placeholder {
|
|
164
|
+
color: var(--slotted-currency-field-placeholder-color, var(--slotted-text-muted, GrayText));
|
|
165
|
+
text-overflow: ellipsis;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ── Alignment ────────────────────────────────────────────────────────
|
|
169
|
+
*
|
|
170
|
+
* The two rules below are the only place this family names a side, and they
|
|
171
|
+
* name it because they have to. `unicode-bidi: plaintext` pins the value's
|
|
172
|
+
* run to left-to-right, and a logical `text-align` resolves against that
|
|
173
|
+
* pinned direction rather than against the document's — so `end` in a
|
|
174
|
+
* right-to-left form would align the amount to the left of its own frame
|
|
175
|
+
* while the reader's eye is at the right. There is no logical value that
|
|
176
|
+
* means "the document's end edge, whatever the run inside is doing".
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
[data-ui='currency-field'][data-align='end'] > [data-part='input'] {
|
|
180
|
+
text-align: right;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
[data-ui='currency-field'][data-align='end']:dir(rtl) > [data-part='input'] {
|
|
184
|
+
text-align: left;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
[data-ui='currency-field'][data-align='start'] > [data-part='input'] {
|
|
188
|
+
text-align: left;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
[data-ui='currency-field'][data-align='start']:dir(rtl) > [data-part='input'] {
|
|
192
|
+
text-align: right;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* ── Size ─────────────────────────────────────────────────────────────
|
|
196
|
+
*
|
|
197
|
+
* Three steps, matching the field the control sits in and every sibling
|
|
198
|
+
* control beside it. One library, one scale.
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
[data-ui='currency-field'][data-part='root'][data-size='sm'] {
|
|
202
|
+
--_font-size: var(--slotted-control-font-size-sm, 12px);
|
|
203
|
+
--_height: var(--slotted-control-height-sm, 30px);
|
|
204
|
+
--_padding-inline: var(--slotted-control-padding-inline-sm, 10px);
|
|
205
|
+
--_gap: var(--slotted-control-gap-sm, 6px);
|
|
206
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-sm, 14px));
|
|
207
|
+
--_inner-size: var(--slotted-control-inner-size-sm, 22px);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
[data-ui='currency-field'][data-part='root'][data-size='md'] {
|
|
211
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
212
|
+
--_height: var(--slotted-control-height-md, 34px);
|
|
213
|
+
--_padding-inline: var(--slotted-control-padding-inline-md, 13px);
|
|
214
|
+
--_gap: var(--slotted-control-gap-md, 8px);
|
|
215
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
|
|
216
|
+
--_inner-size: var(--slotted-control-inner-size-md, 24px);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
[data-ui='currency-field'][data-part='root'][data-size='lg'] {
|
|
220
|
+
--_font-size: var(--slotted-control-font-size-lg, 14px);
|
|
221
|
+
--_height: var(--slotted-control-height-lg, 38px);
|
|
222
|
+
--_padding-inline: var(--slotted-control-padding-inline-lg, 16px);
|
|
223
|
+
--_gap: var(--slotted-control-gap-lg, 8px);
|
|
224
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-lg, 18px));
|
|
225
|
+
--_inner-size: var(--slotted-control-inner-size-lg, 28px);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* ── Variant ──────────────────────────────────────────────────────────
|
|
229
|
+
*
|
|
230
|
+
* The three every framed control in this library ships: `outline` takes the
|
|
231
|
+
* ground it is placed on, `subtle` sinks into the page, and `plain` shows
|
|
232
|
+
* nothing at rest, which is what a dense table of amounts needs.
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
[data-ui='currency-field'][data-part='root'][data-variant='subtle'] {
|
|
236
|
+
background-color: var(
|
|
237
|
+
--slotted-currency-field-subtle-background,
|
|
238
|
+
var(--slotted-surface-sunken, Canvas)
|
|
239
|
+
);
|
|
240
|
+
border-color: var(
|
|
241
|
+
--slotted-currency-field-subtle-border-color,
|
|
242
|
+
var(--slotted-border-subtle, ButtonBorder)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* No edge, no lift, no ground and no corner of its own: the cell it sits in
|
|
247
|
+
is the box, the row is the ground, a cell has no corner, and the resting
|
|
248
|
+
shadow would draw the cell where there is none. */
|
|
249
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain'] {
|
|
250
|
+
background-color: transparent;
|
|
251
|
+
border-color: transparent;
|
|
252
|
+
border-radius: var(--slotted-radius-none, 0px);
|
|
253
|
+
box-shadow: none;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The one rule the theme cannot write for the family. A transparent border
|
|
258
|
+
* has no system colour to be remapped to, so the `plain` control would lose
|
|
259
|
+
* its only edge exactly where an edge matters most.
|
|
260
|
+
*/
|
|
261
|
+
@media (forced-colors: active) {
|
|
262
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain'] {
|
|
263
|
+
border-color: ButtonBorder;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ── Adornments ───────────────────────────────────────────────────────
|
|
268
|
+
*
|
|
269
|
+
* A symbol beside the amount rather than inside it. A symbol that belongs
|
|
270
|
+
* inside the value arrives through `Intl` as part of the string the control
|
|
271
|
+
* holds, is selected with it, is copied with it and is parsed back out of
|
|
272
|
+
* it. This one is none of those things, which is the whole distinction.
|
|
273
|
+
*/
|
|
274
|
+
[data-ui='currency-field'] > [data-part='start'],
|
|
275
|
+
[data-ui='currency-field'] > [data-part='end'] {
|
|
276
|
+
align-items: center;
|
|
277
|
+
color: var(--slotted-currency-field-adornment-color, var(--slotted-text-muted, GrayText));
|
|
278
|
+
display: inline-flex;
|
|
279
|
+
/* Never squeezed: the value gives up width first, because the value is the
|
|
280
|
+
part that can scroll. */
|
|
281
|
+
flex: 0 0 auto;
|
|
282
|
+
gap: var(--slotted-space-2, 0.25rem);
|
|
283
|
+
line-height: 1;
|
|
284
|
+
/**
|
|
285
|
+
* Its own bidi run, ordered by its own content, so `R$` reads as itself in
|
|
286
|
+
* a right-to-left document instead of resolving to the paragraph.
|
|
287
|
+
*/
|
|
288
|
+
unicode-bidi: plaintext;
|
|
289
|
+
|
|
290
|
+
--slotted-icon-size: var(--_icon-size);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
[data-ui='currency-field'] > [data-part='start'] > svg,
|
|
294
|
+
[data-ui='currency-field'] > [data-part='end'] > svg {
|
|
295
|
+
block-size: var(--_icon-size);
|
|
296
|
+
inline-size: var(--_icon-size);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Optical alignment between the two kinds of adornment: a glyph fills the
|
|
301
|
+
* whole box and its artwork does not, while a character fills only its own
|
|
302
|
+
* advance width. An adornment that draws no glyph takes the margin the glyph
|
|
303
|
+
* box already has, on both sides — the measurement `text-field` derived.
|
|
304
|
+
*/
|
|
305
|
+
[data-ui='currency-field'] > [data-part='start']:not(:has(svg, img, [data-ui='icon'])),
|
|
306
|
+
[data-ui='currency-field'] > [data-part='end']:not(:has(svg, img, [data-ui='icon'])) {
|
|
307
|
+
padding-inline: calc(var(--_icon-size) / 8);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* A mark that moves the amount when it is dragged sideways — the sibling's
|
|
312
|
+
* gesture, drawn as the sibling draws it. The adornment holding it stands
|
|
313
|
+
* the frame's full height, so the target is the frame's height rather than
|
|
314
|
+
* the mark's.
|
|
315
|
+
*
|
|
316
|
+
* Hover lifts the mark from the adornments' quiet ink to the value's: the
|
|
317
|
+
* mark is not a button, it has no ground to change, and the cursor alone
|
|
318
|
+
* said nothing a reader would look at.
|
|
319
|
+
*/
|
|
320
|
+
[data-ui='currency-field']
|
|
321
|
+
> :is([data-part='start'], [data-part='end']):has(> [data-part='scrub']) {
|
|
322
|
+
align-self: stretch;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
[data-ui='currency-field'] [data-part='scrub'] {
|
|
326
|
+
align-items: center;
|
|
327
|
+
align-self: stretch;
|
|
328
|
+
cursor: ew-resize;
|
|
329
|
+
display: inline-flex;
|
|
330
|
+
gap: var(--slotted-space-2, 0.25rem);
|
|
331
|
+
/* The drag is the gesture; a pan or a text selection would take it. */
|
|
332
|
+
touch-action: none;
|
|
333
|
+
transition: color var(--slotted-control-transition-duration)
|
|
334
|
+
var(--slotted-control-transition-easing);
|
|
335
|
+
/* Its own bidi run, like the adornment around it: as a flex container its
|
|
336
|
+
text is a new block, and `R$` in a right-to-left document read `$R`. */
|
|
337
|
+
unicode-bidi: plaintext;
|
|
338
|
+
user-select: none;
|
|
339
|
+
-webkit-user-select: none;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
[data-ui='currency-field']:not([data-disabled]):not([data-readonly])
|
|
343
|
+
[data-part='scrub']:is(:hover, [data-scrubbing]) {
|
|
344
|
+
color: var(--slotted-currency-field-scrub-active-color, var(--slotted-text, CanvasText));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
[data-ui='currency-field']:is([data-disabled], [data-readonly]) [data-part='scrub'] {
|
|
348
|
+
cursor: default;
|
|
349
|
+
touch-action: auto;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* ── The two steppers ─────────────────────────────────────────────────
|
|
353
|
+
*
|
|
354
|
+
* Withdrawn by default on this family — an invoice total is typed, not
|
|
355
|
+
* nudged — and drawn exactly as the sibling draws them when a product asks
|
|
356
|
+
* for them. Real buttons, out of the tab order, with real names and
|
|
357
|
+
* `aria-controls`. Their glyphs are the `Glyph` element the binding
|
|
358
|
+
* renders: a character is never an icon.
|
|
359
|
+
*/
|
|
360
|
+
[data-ui='currency-field'] > [data-part='stepper'] > button,
|
|
361
|
+
[data-ui='currency-field'] > [data-part='decrement'],
|
|
362
|
+
[data-ui='currency-field'] > [data-part='increment'] {
|
|
363
|
+
align-items: center;
|
|
364
|
+
appearance: none;
|
|
365
|
+
background-color: transparent;
|
|
366
|
+
border: 0;
|
|
367
|
+
color: var(--slotted-currency-field-stepper-color, var(--slotted-text-muted, GrayText));
|
|
368
|
+
cursor: pointer;
|
|
369
|
+
display: inline-flex;
|
|
370
|
+
flex: 0 0 auto;
|
|
371
|
+
justify-content: center;
|
|
372
|
+
padding: 0;
|
|
373
|
+
/* The containing block of the hit area recovered below. */
|
|
374
|
+
position: relative;
|
|
375
|
+
/* No tap delay waiting for a second tap the button cannot use. */
|
|
376
|
+
touch-action: manipulation;
|
|
377
|
+
transition:
|
|
378
|
+
background-color var(--slotted-control-transition-duration)
|
|
379
|
+
var(--slotted-control-transition-easing),
|
|
380
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
381
|
+
-webkit-tap-highlight-color: transparent;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* The `icon` box inside each button is drawn at the control's own icon
|
|
385
|
+
step rather than at the icon family's default. */
|
|
386
|
+
[data-ui='currency-field'] [data-part='decrement'],
|
|
387
|
+
[data-ui='currency-field'] [data-part='increment'] {
|
|
388
|
+
--slotted-icon-size: var(--_icon-size);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Stacked, the marks are chevrons: two halves of one column, pointing at the
|
|
393
|
+
* direction the value moves. The binding draws the down chevron in both, and
|
|
394
|
+
* the up one is that artwork turned half a turn.
|
|
395
|
+
*
|
|
396
|
+
* Split, they are the minus and the plus — one pair on one grid. Less and
|
|
397
|
+
* more do not change with the reading direction, where a chevron along the
|
|
398
|
+
* inline axis would read as "previous" and "next" and would have to mirror.
|
|
399
|
+
*/
|
|
400
|
+
[data-ui='currency-field'][data-stepper='stacked'] [data-part='increment'] > [data-ui='icon'] {
|
|
401
|
+
rotate: 0.5turn;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* ── Stacked: one column at the inline end ────────────────────────────
|
|
405
|
+
*
|
|
406
|
+
* The column stands `--_column-inset` inside the frame's edge, in the block
|
|
407
|
+
* axis and at the inline end, with no rule of its own: each half paints a
|
|
408
|
+
* ground concentric with the frame when it is hovered, pressed or at its
|
|
409
|
+
* bound, and that ground is the only edge a half needs. The value, the
|
|
410
|
+
* column and its halves are one surface. The paint gives the inset back to
|
|
411
|
+
* the pointer: each half's hit area reaches the frame.
|
|
412
|
+
*/
|
|
413
|
+
[data-ui='currency-field'][data-part='root'][data-stepper='stacked'] {
|
|
414
|
+
padding-inline-end: 0;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
[data-ui='currency-field'] > [data-part='stepper'] {
|
|
418
|
+
align-self: stretch;
|
|
419
|
+
box-sizing: content-box;
|
|
420
|
+
display: flex;
|
|
421
|
+
flex: 0 0 auto;
|
|
422
|
+
flex-direction: column;
|
|
423
|
+
inline-size: var(--_stepper-size);
|
|
424
|
+
padding-block: var(--_column-inset);
|
|
425
|
+
padding-inline-end: var(--_column-inset);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
[data-ui='currency-field'] > [data-part='stepper'] > button {
|
|
429
|
+
/* Two halves of the column, whatever the frame's height turns out to be. */
|
|
430
|
+
block-size: 50%;
|
|
431
|
+
border-radius: var(--_column-radius);
|
|
432
|
+
inline-size: 100%;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
[data-ui='currency-field']
|
|
436
|
+
> [data-part='stepper']
|
|
437
|
+
> :is([data-part='increment'], [data-part='decrement'])::after {
|
|
438
|
+
content: '';
|
|
439
|
+
inset-inline: 0 calc(var(--_column-inset) * -1);
|
|
440
|
+
position: absolute;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
[data-ui='currency-field'] > [data-part='stepper'] > [data-part='increment']::after {
|
|
444
|
+
inset-block: calc(var(--_column-inset) * -1) 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
[data-ui='currency-field'] > [data-part='stepper'] > [data-part='decrement']::after {
|
|
448
|
+
inset-block: 0 calc(var(--_column-inset) * -1);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* The glyph box is the control's own, bounded by the half that holds it: a
|
|
453
|
+
* chevron's artwork occupies about a quarter of its box, so a box shrunk to
|
|
454
|
+
* leave visible air would leave a mark a few pixels tall beside a minus and a
|
|
455
|
+
* plus drawn at full size.
|
|
456
|
+
*
|
|
457
|
+
* Size containment keeps the drawing out of the column's intrinsic height.
|
|
458
|
+
* While the frame measures its content the half has no height yet, so the
|
|
459
|
+
* percentage falls back to the `<svg>`'s own square, and two of them plus the
|
|
460
|
+
* divider would stand taller than the value and grow the frame.
|
|
461
|
+
*/
|
|
462
|
+
[data-ui='currency-field'] > [data-part='stepper'] > button > [data-ui='icon'] {
|
|
463
|
+
block-size: min(var(--_icon-size), 100%);
|
|
464
|
+
contain: size;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* ── Split: one button at each end ────────────────────────────────────
|
|
468
|
+
*
|
|
469
|
+
* Each button is a square inner control inset concentrically, and the
|
|
470
|
+
* frame's padding is that inset on both sides. No rule divides a button from
|
|
471
|
+
* the value: the ground it paints is its edge.
|
|
472
|
+
*/
|
|
473
|
+
[data-ui='currency-field'][data-part='root'][data-stepper='split'] {
|
|
474
|
+
gap: 0;
|
|
475
|
+
padding-inline: var(--_inset);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='decrement'],
|
|
479
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='increment'] {
|
|
480
|
+
block-size: var(--_action-size);
|
|
481
|
+
border-radius: var(--_action-radius);
|
|
482
|
+
inline-size: var(--_action-size);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='start'] {
|
|
486
|
+
padding-inline-start: var(--_gap);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='end'] {
|
|
490
|
+
padding-inline-end: var(--_gap);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* The value keeps its own alignment between the two buttons rather than
|
|
495
|
+
* being centred the way a quantity is: a quantity is a token between a minus
|
|
496
|
+
* and a plus, and an amount is still a figure to be compared down a column.
|
|
497
|
+
*
|
|
498
|
+
* Its inset is the frame's own padding rather than the gap the sibling
|
|
499
|
+
* family uses, so the digits sit the same distance from the edge in all
|
|
500
|
+
* three arrangements. Read down a column mixing them, an amount with a
|
|
501
|
+
* stepper beside it would otherwise be five pixels off every amount without
|
|
502
|
+
* one — which is the comparison `align="end"` exists to make.
|
|
503
|
+
*/
|
|
504
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='input'] {
|
|
505
|
+
padding-inline: var(--_padding-inline);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* The hit area, recovered outside the paint. At `sm` with `dense` the whole
|
|
510
|
+
* control is 24 pixels tall, so a button bounded by the frame cannot also be
|
|
511
|
+
* 24 in both axes. This grows the target to the minimum and leaves a larger
|
|
512
|
+
* one alone — the correction `docs/token-foundation.md` leaves to the family.
|
|
513
|
+
*/
|
|
514
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='decrement']::after,
|
|
515
|
+
[data-ui='currency-field'][data-stepper='split'] > [data-part='increment']::after {
|
|
516
|
+
content: '';
|
|
517
|
+
inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
|
|
518
|
+
position: absolute;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* On a finger the target is the comfortable size. The paint stays the inset
|
|
523
|
+
* square a mouse sees; only the hit area grows.
|
|
524
|
+
*
|
|
525
|
+
* Split, each button's hit area reaches 44 in both axes. Stacked, each half
|
|
526
|
+
* keeps its own half of the column in the block axis — reaching the frame's
|
|
527
|
+
* edge, as on a fine pointer — and reaches 44 in the inline axis, over the
|
|
528
|
+
* value's edge and past the frame's.
|
|
529
|
+
*/
|
|
530
|
+
@media (pointer: coarse) {
|
|
531
|
+
[data-ui='currency-field'][data-stepper='split']
|
|
532
|
+
> :is([data-part='decrement'], [data-part='increment'])::after {
|
|
533
|
+
inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
[data-ui='currency-field']
|
|
537
|
+
> [data-part='stepper']
|
|
538
|
+
> :is([data-part='increment'], [data-part='decrement'])::after {
|
|
539
|
+
inset-inline: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/* ── Stepper states ───────────────────────────────────────────────────
|
|
544
|
+
*
|
|
545
|
+
* Written strongest last, and each weaker one guarded against the stronger
|
|
546
|
+
* ones it can meet, which is the order `STATE_PRECEDENCE` sets.
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
[data-ui='currency-field'] [data-part='decrement']:hover:not(:disabled),
|
|
550
|
+
[data-ui='currency-field'] [data-part='increment']:hover:not(:disabled) {
|
|
551
|
+
background-color: var(
|
|
552
|
+
--slotted-currency-field-stepper-hover-background,
|
|
553
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
[data-ui='currency-field'] [data-part='decrement']:active:not(:disabled),
|
|
558
|
+
[data-ui='currency-field'] [data-part='increment']:active:not(:disabled) {
|
|
559
|
+
background-color: var(
|
|
560
|
+
--slotted-currency-field-stepper-active-background,
|
|
561
|
+
var(--slotted-tone-secondary-subtle-active)
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* A stepper at its bound is disabled rather than silently inert, so its name
|
|
567
|
+
* still announces and its appearance says why nothing happens. The ground
|
|
568
|
+
* says it as well as the ink: the disabled foreground and the resting
|
|
569
|
+
* stepper colour are two steps of one neutral.
|
|
570
|
+
*/
|
|
571
|
+
[data-ui='currency-field'] [data-part='decrement']:disabled,
|
|
572
|
+
[data-ui='currency-field'] [data-part='increment']:disabled {
|
|
573
|
+
background-color: var(
|
|
574
|
+
--slotted-currency-field-stepper-disabled-background,
|
|
575
|
+
var(--slotted-disabled-background)
|
|
576
|
+
);
|
|
577
|
+
color: var(--slotted-currency-field-stepper-disabled-color, var(--slotted-disabled-foreground));
|
|
578
|
+
cursor: not-allowed;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* The steppers are out of the tab order, so this answers the pointer path on
|
|
583
|
+
* touch and a screen-reader cursor activating one directly. It sits inside
|
|
584
|
+
* the frame's own edge, so the ring never doubles the border.
|
|
585
|
+
*/
|
|
586
|
+
[data-ui='currency-field'] [data-part='decrement']:focus-visible,
|
|
587
|
+
[data-ui='currency-field'] [data-part='increment']:focus-visible {
|
|
588
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
589
|
+
outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/* ── Frame states ─────────────────────────────────────────────────────── */
|
|
593
|
+
|
|
594
|
+
[data-ui='currency-field'][data-part='root']:hover:not([data-disabled]):not([data-readonly]):not(
|
|
595
|
+
[data-invalid]
|
|
596
|
+
) {
|
|
597
|
+
border-color: var(
|
|
598
|
+
--slotted-currency-field-hover-border-color,
|
|
599
|
+
var(--slotted-tone-accent-border)
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
[data-ui='currency-field'][data-part='root'][data-variant='subtle']:hover:not(
|
|
604
|
+
[data-disabled]
|
|
605
|
+
):not([data-readonly]):not([data-invalid]) {
|
|
606
|
+
background-color: var(
|
|
607
|
+
--slotted-currency-field-subtle-hover-background,
|
|
608
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain']:hover:not([data-disabled]):not(
|
|
613
|
+
[data-readonly]
|
|
614
|
+
):not([data-invalid]) {
|
|
615
|
+
background-color: var(
|
|
616
|
+
--slotted-currency-field-plain-hover-background,
|
|
617
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
618
|
+
);
|
|
619
|
+
/* The accent edge the other variants take would draw the cell's outline. */
|
|
620
|
+
border-color: transparent;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* The ring belongs to the frame and answers the control's focus: a browser
|
|
625
|
+
* matches `:focus-visible` on a text input for a pointer press as well as for
|
|
626
|
+
* a Tab, which is right for a control whose caret is the thing that moved.
|
|
627
|
+
*/
|
|
628
|
+
[data-ui='currency-field'][data-part='root']:has(> [data-part='input']:focus-visible) {
|
|
629
|
+
/* The resting shadow, recoloured: the lift under the control and the ring
|
|
630
|
+
around it are one colour, and the state decides which colour that is. */
|
|
631
|
+
box-shadow: var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
|
|
632
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
633
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
634
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* The ring of a control whose box is not its own is drawn inside that box,
|
|
639
|
+
* the way the inner controls draw theirs inside the frame: two pixels past
|
|
640
|
+
* the control is two pixels over the next row's rule. No lift either — a
|
|
641
|
+
* shadow that appears only under focus is a cell that changes size when it
|
|
642
|
+
* is used.
|
|
643
|
+
*/
|
|
644
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain']:has(
|
|
645
|
+
> [data-part='input']:focus-visible
|
|
646
|
+
) {
|
|
647
|
+
box-shadow: none;
|
|
648
|
+
outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Invalid outranks hover and is written after it for that reason. The ring is
|
|
653
|
+
* retargeted rather than repainted: every rule that draws focus reads
|
|
654
|
+
* `--slotted-focus-ring-color`, so pointing that one name at the invalid
|
|
655
|
+
* colour on the element moves the outline, the shadow and both steppers'
|
|
656
|
+
* rings at once.
|
|
657
|
+
*/
|
|
658
|
+
[data-ui='currency-field'][data-part='root'][data-invalid] {
|
|
659
|
+
--slotted-focus-ring-color: var(
|
|
660
|
+
--slotted-currency-field-invalid-focus-ring-color,
|
|
661
|
+
var(--slotted-focus-ring-color-invalid, Highlight)
|
|
662
|
+
);
|
|
663
|
+
--_invalid-edge-width: var(
|
|
664
|
+
--slotted-currency-field-invalid-edge-width,
|
|
665
|
+
var(--slotted-control-invalid-edge-width, 1px)
|
|
666
|
+
);
|
|
667
|
+
--_invalid-edge-color: var(
|
|
668
|
+
--slotted-currency-field-invalid-border-color,
|
|
669
|
+
var(--slotted-tone-danger-border)
|
|
670
|
+
);
|
|
671
|
+
--_invalid-edge: inset 0 0 0 var(--_invalid-edge-width) var(--_invalid-edge-color);
|
|
672
|
+
|
|
673
|
+
border-color: var(
|
|
674
|
+
--slotted-currency-field-invalid-border-color,
|
|
675
|
+
var(--slotted-tone-danger-border)
|
|
676
|
+
);
|
|
677
|
+
/*
|
|
678
|
+
* Width as well as colour (WCAG 1.4.1), the edge `text-field` draws: in
|
|
679
|
+
* `high-contrast` the danger border is the resting edge's black. The line
|
|
680
|
+
* is a shadow inside the border, so neither box nor text moves, and it
|
|
681
|
+
* takes the resting lift's place.
|
|
682
|
+
*/
|
|
683
|
+
box-shadow: var(--_invalid-edge);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
[data-ui='currency-field'][data-part='root'][data-invalid]:has(
|
|
687
|
+
> [data-part='input']:focus-visible
|
|
688
|
+
) {
|
|
689
|
+
box-shadow:
|
|
690
|
+
var(--_invalid-edge),
|
|
691
|
+
var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
|
|
692
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
696
|
+
> [data-part='input']:focus-visible
|
|
697
|
+
) {
|
|
698
|
+
/* The ring lies inside the box here, over the border and an edge as wide as
|
|
699
|
+
it; the edge reaches past the ring. */
|
|
700
|
+
box-shadow: inset 0 0 0
|
|
701
|
+
calc(
|
|
702
|
+
var(--slotted-focus-ring-offset, 2px) - var(--slotted-control-border-width, 1px) +
|
|
703
|
+
var(--_invalid-edge-width)
|
|
704
|
+
)
|
|
705
|
+
var(--_invalid-edge-color);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/*
|
|
709
|
+
* Forced colours remove every box shadow, and the edge with them. The
|
|
710
|
+
* width comes back as an outline inside the border, and a focused invalid
|
|
711
|
+
* control draws its ring double, which a valid ring is not.
|
|
712
|
+
*/
|
|
713
|
+
@media (forced-colors: active) {
|
|
714
|
+
[data-ui='currency-field'][data-part='root'][data-invalid] {
|
|
715
|
+
outline: var(--_invalid-edge-width) solid CanvasText;
|
|
716
|
+
outline-offset: calc(
|
|
717
|
+
-1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
[data-ui='currency-field'][data-part='root'][data-invalid]:has(
|
|
722
|
+
> [data-part='input']:focus-visible
|
|
723
|
+
) {
|
|
724
|
+
outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
|
|
725
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
726
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
[data-ui='currency-field'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
730
|
+
> [data-part='input']:focus-visible
|
|
731
|
+
) {
|
|
732
|
+
outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
|
|
733
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
734
|
+
outline-offset: calc(
|
|
735
|
+
-1 * (var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width))
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Read-only stays focusable, selectable and legible, and must not be
|
|
742
|
+
* mistakable for disabled: the amount is still real and still submitted. The
|
|
743
|
+
* ground says "not yours to change", the edge steps down to the separator
|
|
744
|
+
* weight, and the ink stays at full strength.
|
|
745
|
+
*/
|
|
746
|
+
[data-ui='currency-field'][data-part='root'][data-readonly] {
|
|
747
|
+
background-color: var(
|
|
748
|
+
--slotted-currency-field-readonly-background,
|
|
749
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
750
|
+
);
|
|
751
|
+
border-color: var(
|
|
752
|
+
--slotted-currency-field-readonly-border-color,
|
|
753
|
+
var(--slotted-border-subtle, ButtonBorder)
|
|
754
|
+
);
|
|
755
|
+
cursor: default;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* `:disabled` on the control is matched beside `data-disabled` on the frame,
|
|
760
|
+
* because a control can be disabled by something that never told it so: a
|
|
761
|
+
* disabled `fieldset` disables every control inside it.
|
|
762
|
+
*/
|
|
763
|
+
[data-ui='currency-field'][data-part='root'][data-disabled],
|
|
764
|
+
[data-ui='currency-field'][data-part='root']:has(> [data-part='input']:disabled) {
|
|
765
|
+
background-color: var(
|
|
766
|
+
--slotted-currency-field-disabled-background,
|
|
767
|
+
var(--slotted-disabled-background)
|
|
768
|
+
);
|
|
769
|
+
border-color: var(
|
|
770
|
+
--slotted-currency-field-disabled-border-color,
|
|
771
|
+
var(--slotted-disabled-border)
|
|
772
|
+
);
|
|
773
|
+
/* Nothing a person cannot reach is lifted off the page. */
|
|
774
|
+
box-shadow: none;
|
|
775
|
+
color: var(--slotted-currency-field-disabled-color, var(--slotted-disabled-foreground));
|
|
776
|
+
cursor: not-allowed;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Muted to the colour the theme measures rather than faded by opacity: an
|
|
781
|
+
* amount nobody can read is a field nobody can check.
|
|
782
|
+
*/
|
|
783
|
+
[data-ui='currency-field'][data-part='root'][data-disabled] > [data-part='start'],
|
|
784
|
+
[data-ui='currency-field'][data-part='root'][data-disabled] > [data-part='end'] {
|
|
785
|
+
color: var(--slotted-disabled-foreground);
|
|
786
|
+
}
|
|
787
|
+
}
|