@slotted/styles 0.0.0-stage → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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,757 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* ── A frame of typed values, with a field that adds more ────────────────
|
|
4
|
+
*
|
|
5
|
+
* One subtree, where the consumer wrote it. Nothing is portalled and
|
|
6
|
+
* nothing opens: the input is a text box, and the values beside it are the
|
|
7
|
+
* texts the reader typed.
|
|
8
|
+
*
|
|
9
|
+
* ┌─ root ─ the frame ─────────────────────────────────────────┐
|
|
10
|
+
* │ ┌─ control ─ role="grid" ───────────────┐ │
|
|
11
|
+
* │ │ ┌─ chips ─ role="row" ─ wraps ──────┐ │ counter clear │
|
|
12
|
+
* │ │ │ tag ▸ tag ▸ tag(invalid) ▸ +N │ │ │
|
|
13
|
+
* │ │ │ field ▸ input │ │ │
|
|
14
|
+
* │ │ └───────────────────────────────────┘ │ │
|
|
15
|
+
* │ └───────────────────────────────────────┘ │
|
|
16
|
+
* │ hint · message ─ for assistive technology only │
|
|
17
|
+
* └────────────────────────────────────────────────────────────┘
|
|
18
|
+
*
|
|
19
|
+
* ── What this sheet does not decide ──────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* **Nothing about a chip.** The chips are `tag`'s, worn as `data-ui` beside
|
|
22
|
+
* this family's own parts, so the pill, the small step, the `danger` tone an
|
|
23
|
+
* invalid value wears, and the remove control floored at
|
|
24
|
+
* `--slotted-target-min` are all stated once in `tag/tag.css`. This sheet
|
|
25
|
+
* decides where the row is, how it wraps, and the one mark it adds.
|
|
26
|
+
*
|
|
27
|
+
* **The frame.** `text-field`'s arithmetic and `multi-select`'s: the same
|
|
28
|
+
* control on the same form, so the numbers are the same numbers. The control
|
|
29
|
+
* grows by whole rows of chips and by nothing else — an empty control is
|
|
30
|
+
* exactly the height of a text field beside it, and three rows is where it
|
|
31
|
+
* stops growing and starts scrolling.
|
|
32
|
+
*
|
|
33
|
+
* ── What this sheet decides on its own ───────────────────────────────
|
|
34
|
+
*
|
|
35
|
+
* **An invalid value is a chip with a mark.** The tone is `tag`'s `danger`,
|
|
36
|
+
* written in the DOM; the alert glyph in the chip's `start` slot is the
|
|
37
|
+
* `Glyph` element the binding renders there, because `tag` has no opinion
|
|
38
|
+
* about what a slot holds. Colour, mark and — in the tree — a description,
|
|
39
|
+
* which is what §2.5 asks of an invalid state.
|
|
40
|
+
*
|
|
41
|
+
* **A collapsed row opens where the reader is.** Under `overflow='collapse'`
|
|
42
|
+
* the row is one line and a `+N` at rest, and every chip while the control
|
|
43
|
+
* has focus within — `data-expanded`, written by the binding. There is no
|
|
44
|
+
* popup to hold the hidden chips, so the row itself is where they are shown,
|
|
45
|
+
* and it is shown exactly when the reader is about to act on them.
|
|
46
|
+
*
|
|
47
|
+
* **Two parts are for assistive technology alone.** `hint` names the keys
|
|
48
|
+
* the row answers, `message` names why a value is wrong. Both are removed
|
|
49
|
+
* from sight with the rule `visually-hidden/visually-hidden.css` states,
|
|
50
|
+
* restated here because a part of this family cannot wear another family's
|
|
51
|
+
* `data-ui` and mean two things.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/* ── The frame ────────────────────────────────────────────────────────── */
|
|
55
|
+
|
|
56
|
+
[data-ui='tags-input'][data-part='root'] {
|
|
57
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
58
|
+
--_height: var(--slotted-control-height-md, 34px);
|
|
59
|
+
--_padding-inline: var(--slotted-control-padding-inline-md, 13px);
|
|
60
|
+
--_gap: var(--slotted-control-gap-md, 8px);
|
|
61
|
+
/** The floor under the glyph scale at the dense step; a family token so a theme can retune it. */
|
|
62
|
+
--_icon-floor: var(--slotted-tags-input-icon-size-min, 14px);
|
|
63
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
|
|
64
|
+
|
|
65
|
+
/* `text-field`'s arithmetic, because this is the same button in the same
|
|
66
|
+
frame and a second answer would drift from the first. */
|
|
67
|
+
--_action-size: var(
|
|
68
|
+
--slotted-tags-input-action-size,
|
|
69
|
+
min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size))
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The air above and below a row of chips: a space step, kept at every
|
|
74
|
+
* density. It is the chip that yields, below — not the air — so a control
|
|
75
|
+
* holding one row of chips is the height of an empty one beside it and the
|
|
76
|
+
* chip never touches the frame.
|
|
77
|
+
*/
|
|
78
|
+
--_row-air: var(--slotted-space-1, 0.125rem);
|
|
79
|
+
/**
|
|
80
|
+
* One row's height is the height the foundation gives the inside of a
|
|
81
|
+
* control at this size step, `--slotted-control-inner-size-*`: the chip
|
|
82
|
+
* takes it through the property the row writes below, so a `dense` frame
|
|
83
|
+
* of 26 pixels holds an 18-pixel chip with four pixels of air a side, and
|
|
84
|
+
* three rows plus their gaps divide the cap below with no sliver of a
|
|
85
|
+
* fourth. The type stays 12px; the chip's line and inset are derived from
|
|
86
|
+
* the height in `tag.css`, and the remove control keeps its 24-pixel target
|
|
87
|
+
* through `tag`'s own halo.
|
|
88
|
+
*/
|
|
89
|
+
--_inner-size: var(--slotted-control-inner-size-md, 24px);
|
|
90
|
+
--_row-size: var(--_inner-size);
|
|
91
|
+
--_row-gap: var(--slotted-space-2, 0.25rem);
|
|
92
|
+
|
|
93
|
+
align-items: center;
|
|
94
|
+
background-color: var(--slotted-tags-input-background, var(--slotted-control-surface, Field));
|
|
95
|
+
border: var(--slotted-control-border-width, 1px) solid
|
|
96
|
+
var(--slotted-tags-input-border-color, var(--slotted-control-border-color, ButtonBorder));
|
|
97
|
+
border-radius: var(--slotted-tags-input-radius, var(--slotted-control-radius, 4px));
|
|
98
|
+
box-shadow: var(--slotted-tags-input-shadow, var(--slotted-control-shadow, none));
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
color: var(--slotted-tags-input-color, var(--slotted-text, CanvasText));
|
|
101
|
+
display: flex;
|
|
102
|
+
font-family: var(--slotted-control-font-family, system-ui, sans-serif);
|
|
103
|
+
font-size: var(--_font-size);
|
|
104
|
+
gap: var(--slotted-space-1, 0.125rem);
|
|
105
|
+
inline-size: 100%;
|
|
106
|
+
min-block-size: var(--_height);
|
|
107
|
+
min-inline-size: 0;
|
|
108
|
+
padding-inline-start: var(--_padding-inline);
|
|
109
|
+
/* The end padding is the button's gutter rather than the frame's, so the
|
|
110
|
+
glyph — not the button's box — ends where the text begins on the other
|
|
111
|
+
side. `text-field` states the same arithmetic. */
|
|
112
|
+
padding-inline-end: max(
|
|
113
|
+
0px,
|
|
114
|
+
calc(var(--_padding-inline) - (var(--_action-size) - var(--_icon-size)) / 2)
|
|
115
|
+
);
|
|
116
|
+
/* The containing block of the two hidden parts. */
|
|
117
|
+
position: relative;
|
|
118
|
+
transition:
|
|
119
|
+
background-color var(--slotted-control-transition-duration)
|
|
120
|
+
var(--slotted-control-transition-easing),
|
|
121
|
+
border-color var(--slotted-control-transition-duration)
|
|
122
|
+
var(--slotted-control-transition-easing),
|
|
123
|
+
box-shadow var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
[data-ui='tags-input'][data-part='root']:not([data-full-width]) {
|
|
127
|
+
inline-size: auto;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The grid. It holds one row and gives up every visual decision to it: the
|
|
132
|
+
* role is what the layout-grid pattern asks for, and the geometry belongs to
|
|
133
|
+
* the row that wraps.
|
|
134
|
+
*/
|
|
135
|
+
[data-ui='tags-input'] > [data-part='control'] {
|
|
136
|
+
display: flex;
|
|
137
|
+
flex: 1 1 auto;
|
|
138
|
+
min-inline-size: 0;
|
|
139
|
+
align-self: stretch;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The distance between the values and the controls that act on them: the
|
|
144
|
+
* row's own gap rather than the frame's tighter one, so the boundary between
|
|
145
|
+
* what is typed and what acts on it is never narrower than the rhythm inside
|
|
146
|
+
* it. `multi-select` measured the two-pixel version of this and rejected it.
|
|
147
|
+
*/
|
|
148
|
+
[data-ui='tags-input'] > [data-part='control'] + * {
|
|
149
|
+
margin-inline-start: var(--_row-gap);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The row. One DOM row that wraps onto as many visual lines as it needs, so
|
|
154
|
+
* the reading order stays linear and "previous" and "next" have one meaning
|
|
155
|
+
* each — which is why the grid answers neither `ArrowDown` nor `ArrowUp`.
|
|
156
|
+
*/
|
|
157
|
+
[data-ui='tags-input'] [data-part='chips'] {
|
|
158
|
+
/* `safe`, because this box scrolls: centring a scroll container's content
|
|
159
|
+
pushes the first line above the scrollport when there is more than fits,
|
|
160
|
+
and nothing can scroll back to it. `multi-select` found the first three
|
|
161
|
+
chips unreachable at 240 pixels without it. */
|
|
162
|
+
align-content: safe center;
|
|
163
|
+
align-items: center;
|
|
164
|
+
/* The cap below counts rows, gaps and the row's own air, so it has to be a
|
|
165
|
+
border box. */
|
|
166
|
+
box-sizing: border-box;
|
|
167
|
+
column-gap: var(--_row-gap);
|
|
168
|
+
display: flex;
|
|
169
|
+
flex: 1 1 auto;
|
|
170
|
+
flex-wrap: wrap;
|
|
171
|
+
min-inline-size: 0;
|
|
172
|
+
padding-block: var(--_row-air);
|
|
173
|
+
/* A box that scrolls on one axis clips on both, and a chip's remove control
|
|
174
|
+
takes the rest of its target from a halo outside the chip: the row keeps
|
|
175
|
+
two pixels of inline padding for it and takes them back with a negative
|
|
176
|
+
margin, so the chips stand where the gutter puts them. */
|
|
177
|
+
padding-inline: var(--_row-air);
|
|
178
|
+
margin-inline: calc(-1 * var(--_row-air));
|
|
179
|
+
row-gap: var(--_row-gap);
|
|
180
|
+
/* Three whole rows, then it scrolls. Every chip stays in the DOM either
|
|
181
|
+
way, which is what the feature guide asks of an overflow. */
|
|
182
|
+
max-block-size: calc(3 * var(--_row-size) + 2 * var(--_row-gap) + 2 * var(--_row-air));
|
|
183
|
+
overflow-y: auto;
|
|
184
|
+
overscroll-behavior: contain;
|
|
185
|
+
/**
|
|
186
|
+
* The row scrolls and draws no scrollbar. A form control has one frame, and
|
|
187
|
+
* a bar inside it takes width from the chips, moves them when it appears,
|
|
188
|
+
* and paints a second edge inside the control's own. The wheel and every
|
|
189
|
+
* arrow key still reach the rows above and below, because a chip is
|
|
190
|
+
* focusable and the browser scrolls focus into view; what says there is
|
|
191
|
+
* more is the counter and the row's own `aria-label` carrying the count.
|
|
192
|
+
*/
|
|
193
|
+
scrollbar-width: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
[data-ui='tags-input'] [data-part='chips']::-webkit-scrollbar {
|
|
197
|
+
display: none;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* One line high at rest, under `overflow='collapse'`: what does not fit is
|
|
202
|
+
* collapsed by `createCollapse` into the counting chip. There is no popup to
|
|
203
|
+
* hold the rest, so the row itself opens — the rule after this one — while
|
|
204
|
+
* the control has focus within.
|
|
205
|
+
*/
|
|
206
|
+
[data-ui='tags-input'][data-overflow='collapse']:not([data-expanded]) [data-part='chips'] {
|
|
207
|
+
flex-wrap: nowrap;
|
|
208
|
+
max-block-size: none;
|
|
209
|
+
overflow: hidden;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The expanded row is the wrapped row: the same three-line cap and the same
|
|
214
|
+
* scroll past it, so a reader who has learnt one shape has learnt both. The
|
|
215
|
+
* counting chip leaves while every chip is shown, and `createCollapse` is
|
|
216
|
+
* paused by the binding so it does not measure a row that is not clipping.
|
|
217
|
+
*
|
|
218
|
+
* No transition. The row's height changes as focus arrives, and a transition
|
|
219
|
+
* would make the reader wait for the chip they are about to reach.
|
|
220
|
+
*/
|
|
221
|
+
[data-ui='tags-input'][data-overflow='collapse'][data-expanded]
|
|
222
|
+
[data-part='chips']
|
|
223
|
+
> [data-count] {
|
|
224
|
+
display: none;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* A chip being edited. The grid pattern's own answer to a cell holding
|
|
229
|
+
* editable content is a text field inside the cell, so that is what it is —
|
|
230
|
+
* and it gives up every mark of a field, because the chip around it is
|
|
231
|
+
* already the box. Selected by element rather than by part: the field
|
|
232
|
+
* belongs to the chip, and the query's own input is told apart by the part it
|
|
233
|
+
* does have.
|
|
234
|
+
*/
|
|
235
|
+
[data-ui='tags-input'] [data-part='chips'] input:not([data-part='input']) {
|
|
236
|
+
background-color: transparent;
|
|
237
|
+
border: 0;
|
|
238
|
+
color: inherit;
|
|
239
|
+
font: inherit;
|
|
240
|
+
min-inline-size: 0;
|
|
241
|
+
outline: none;
|
|
242
|
+
padding: 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* A chip never shrinks: it either fits on the line or goes to the next one,
|
|
247
|
+
* and the only chip that gives way is one wider than the whole row, which is
|
|
248
|
+
* capped here and truncated by `tag.css`. Its height is the row's own — the
|
|
249
|
+
* target minimum — so three of them plus their gaps divide the cap above
|
|
250
|
+
* exactly, and no fourth row shows as a sliver under the third.
|
|
251
|
+
*/
|
|
252
|
+
[data-ui='tags-input'] [data-part='chips'] > :not([data-part='field']) {
|
|
253
|
+
flex: 0 0 auto;
|
|
254
|
+
max-inline-size: 100%;
|
|
255
|
+
min-block-size: var(--_row-size);
|
|
256
|
+
min-inline-size: 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The chip takes the height the inside of this control has, through the
|
|
261
|
+
* property `tag` reads for it. Set on the row, inherited by every chip, and
|
|
262
|
+
* no rule of this sheet names `[data-ui='tag']`: the host stands beside the
|
|
263
|
+
* tag sheet and never reaches into it.
|
|
264
|
+
*/
|
|
265
|
+
[data-ui='tags-input'] [data-part='chips'] {
|
|
266
|
+
--slotted-control-inner-size: var(--_inner-size);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* The cell that holds the caret. It is the last cell of the row, so it wraps
|
|
271
|
+
* with the chips rather than being pushed to a line of its own, and it asks
|
|
272
|
+
* — rather than demands — for a word's worth of width, so the reader always
|
|
273
|
+
* has somewhere to type and a 240-pixel control holding two values does not
|
|
274
|
+
* stand two rows tall with one row empty.
|
|
275
|
+
*/
|
|
276
|
+
[data-ui='tags-input'] [data-part='field'] {
|
|
277
|
+
align-items: center;
|
|
278
|
+
display: flex;
|
|
279
|
+
flex: 1 1 var(--slotted-tags-input-field-basis, 4rem);
|
|
280
|
+
min-block-size: var(--_row-size);
|
|
281
|
+
min-inline-size: var(--slotted-tags-input-field-min, 2.5rem);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* The control's text. It gives up its own frame entirely and keeps
|
|
286
|
+
* everything that makes it a text control: the caret, the selection, IME
|
|
287
|
+
* composition, autofill, the browser's own completion from a `datalist`, and
|
|
288
|
+
* every native attribute the consumer wrote.
|
|
289
|
+
*/
|
|
290
|
+
[data-ui='tags-input'] [data-part='input'] {
|
|
291
|
+
background-color: transparent;
|
|
292
|
+
border: 0;
|
|
293
|
+
color: inherit;
|
|
294
|
+
flex: 1 1 auto;
|
|
295
|
+
font: inherit;
|
|
296
|
+
/* The frame draws the ring for it, so two rings never nest. */
|
|
297
|
+
outline: none;
|
|
298
|
+
padding: 0;
|
|
299
|
+
/* The intrinsic width of an `input` is about twenty characters, and a flex
|
|
300
|
+
item refuses to shrink below it without this. */
|
|
301
|
+
min-inline-size: 0;
|
|
302
|
+
text-overflow: ellipsis;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
[data-ui='tags-input'] [data-part='input']::placeholder {
|
|
306
|
+
color: var(--slotted-tags-input-placeholder-color, var(--slotted-text-muted, GrayText));
|
|
307
|
+
text-overflow: ellipsis;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Autofill. Chrome paints its own ground over the control's, and a
|
|
312
|
+
* hundred-pixel inset shadow is the only way to reach it. The signal is kept
|
|
313
|
+
* rather than erased, in the accent surface the theme owns — the repair
|
|
314
|
+
* `text-field` makes, for the same reason.
|
|
315
|
+
*/
|
|
316
|
+
[data-ui='tags-input'] [data-part='input']:autofill {
|
|
317
|
+
box-shadow: inset 0 0 0 100px
|
|
318
|
+
var(--slotted-tags-input-autofill-background, var(--slotted-tone-accent-surface));
|
|
319
|
+
-webkit-text-fill-color: var(--slotted-tags-input-color, var(--slotted-text, CanvasText));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* A chip that holds focus. The cell takes the ring rather than the remove
|
|
324
|
+
* button inside it — the departure the contract records against the grid
|
|
325
|
+
* pattern — so the ring is drawn around the value, which is the thing
|
|
326
|
+
* `Delete` acts on. It follows the chip's own radius by being an outline on
|
|
327
|
+
* the pill itself.
|
|
328
|
+
*
|
|
329
|
+
* The ring is drawn one width inside the chip, not at the theme's offset
|
|
330
|
+
* outside it. The row around the chip scrolls, or clips under
|
|
331
|
+
* `overflow='collapse'`, and either way it cuts at its padding edge, two
|
|
332
|
+
* pixels past the chip; a ring two pixels further out lost its outer half on
|
|
333
|
+
* every side, at every density. One width inside is `listbox`'s answer for an
|
|
334
|
+
* option in a scrolling list: the ring covers the chip's own edge and reads
|
|
335
|
+
* as the chip's edge turned to the ring colour, whole, with the text clear
|
|
336
|
+
* of it even at `dense`, where the chip has no inset to spare. `tag` draws
|
|
337
|
+
* its own inner ring two widths in to keep a sliver of ground outside it;
|
|
338
|
+
* here that sliver would cost the text its leading.
|
|
339
|
+
*/
|
|
340
|
+
[data-ui='tags-input'] [data-part='chips'] > :not([data-part='field']):focus-visible {
|
|
341
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
342
|
+
outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The chip that already holds the value the reader just typed again. It
|
|
347
|
+
* takes focus, and for one long step of the motion scale its edge is the
|
|
348
|
+
* accent's, so a reader who looked away from the ring still sees which chip
|
|
349
|
+
* answered — through the edge token `tag` reads, so this sheet names
|
|
350
|
+
* `[data-ui='tag']` nowhere.
|
|
351
|
+
*/
|
|
352
|
+
[data-ui='tags-input'] [data-part='chips'] > [data-current] {
|
|
353
|
+
--slotted-tag-border-color: var(
|
|
354
|
+
--slotted-tags-input-current-border-color,
|
|
355
|
+
var(--slotted-tone-accent-border)
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* The chip that counts what did not fit, under `overflow='collapse'`. It is a
|
|
361
|
+
* chip and not a number beside them, so the row reads as one run of chips
|
|
362
|
+
* whose last one happens to be a count, and `createCollapse` measures it the
|
|
363
|
+
* way it measures every other unit.
|
|
364
|
+
*/
|
|
365
|
+
[data-ui='tags-input'] [data-part='chips'] > [data-count] {
|
|
366
|
+
cursor: pointer;
|
|
367
|
+
flex: none;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* The count of what is held, against the limit that holds it. It is drawn
|
|
372
|
+
* only where it answers something — while `max` is set, or while the frame is
|
|
373
|
+
* too narrow for a chip — because a counter with nothing to count against is
|
|
374
|
+
* furniture.
|
|
375
|
+
*/
|
|
376
|
+
[data-ui='tags-input'] > [data-part='counter'] {
|
|
377
|
+
align-self: center;
|
|
378
|
+
color: var(--slotted-tags-input-counter-color, var(--slotted-text-muted, GrayText));
|
|
379
|
+
flex: none;
|
|
380
|
+
font-size: var(--slotted-font-size-xs, 0.75rem);
|
|
381
|
+
font-variant-numeric: tabular-nums;
|
|
382
|
+
line-height: var(--slotted-line-height-sm, 1.45);
|
|
383
|
+
padding-inline: var(--slotted-space-1, 0.125rem);
|
|
384
|
+
/* Its own bidi run, ordered by its own content: "3 of 5" is a European
|
|
385
|
+
number, a Latin word and another number, and in a right-to-left document
|
|
386
|
+
the neutral spaces resolve to the paragraph and the runs swap. */
|
|
387
|
+
unicode-bidi: plaintext;
|
|
388
|
+
white-space: nowrap;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A full control says so where the count is, in the accent the family already
|
|
393
|
+
* uses for a chosen value. Not a warning tone: reaching the limit is the
|
|
394
|
+
* reader arriving somewhere, not going wrong.
|
|
395
|
+
*/
|
|
396
|
+
[data-ui='tags-input'][data-complete] > [data-part='counter'] {
|
|
397
|
+
color: var(--slotted-tags-input-counter-complete-color, var(--slotted-tone-accent-text));
|
|
398
|
+
font-weight: var(--slotted-font-weight-medium, 500);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* Too narrow for a chip: the count is the whole answer. */
|
|
402
|
+
[data-ui='tags-input'][data-narrow] [data-part='chips'] > :not([data-part='field']) {
|
|
403
|
+
display: none;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* ── The two parts for assistive technology ───────────────────────────
|
|
408
|
+
*
|
|
409
|
+
* Removed from sight and left in the tree: the rule
|
|
410
|
+
* `visually-hidden/visually-hidden.css` states, restated because these are
|
|
411
|
+
* this family's parts and a part cannot wear another family's `data-ui`.
|
|
412
|
+
* The `message` lives inside the chip and the `hint` beside the row; both
|
|
413
|
+
* are positioned against the frame, which is the nearest containing block.
|
|
414
|
+
*/
|
|
415
|
+
[data-ui='tags-input'] :is([data-part='message'], [data-part='hint']) {
|
|
416
|
+
block-size: 1px;
|
|
417
|
+
border: 0;
|
|
418
|
+
clip-path: inset(50%);
|
|
419
|
+
inline-size: 1px;
|
|
420
|
+
margin: -1px;
|
|
421
|
+
overflow: hidden;
|
|
422
|
+
padding: 0;
|
|
423
|
+
position: absolute;
|
|
424
|
+
white-space: nowrap;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ── The button inside the frame ──────────────────────────────────────── */
|
|
428
|
+
|
|
429
|
+
[data-ui='tags-input'] > [data-part='clear'] {
|
|
430
|
+
align-items: center;
|
|
431
|
+
align-self: center;
|
|
432
|
+
appearance: none;
|
|
433
|
+
background-color: transparent;
|
|
434
|
+
block-size: var(--_action-size);
|
|
435
|
+
border: 0;
|
|
436
|
+
border-radius: var(--slotted-tags-input-radius, var(--slotted-control-radius, 4px));
|
|
437
|
+
color: var(--slotted-tags-input-action-color, var(--slotted-text-muted, GrayText));
|
|
438
|
+
cursor: pointer;
|
|
439
|
+
display: inline-flex;
|
|
440
|
+
flex: 0 0 auto;
|
|
441
|
+
inline-size: var(--_action-size);
|
|
442
|
+
justify-content: center;
|
|
443
|
+
/* The user agent pads a button, and inside a box sized to its glyph that
|
|
444
|
+
padding squeezed the glyph to twelve pixels. */
|
|
445
|
+
padding: 0;
|
|
446
|
+
/* The containing block of the hit area below. */
|
|
447
|
+
position: relative;
|
|
448
|
+
touch-action: manipulation;
|
|
449
|
+
transition:
|
|
450
|
+
background-color var(--slotted-control-transition-duration)
|
|
451
|
+
var(--slotted-control-transition-easing),
|
|
452
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
453
|
+
-webkit-tap-highlight-color: transparent;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* The hit area, recovered outside the paint. At `sm` with `dense` the whole
|
|
458
|
+
* control is 24 pixels tall — the WCAG 2.2 minimum — so nothing drawn inside
|
|
459
|
+
* it can also be 24.
|
|
460
|
+
*/
|
|
461
|
+
[data-ui='tags-input'] > [data-part='clear']::after {
|
|
462
|
+
content: '';
|
|
463
|
+
inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
|
|
464
|
+
position: absolute;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* On a finger the target is the comfortable size in both axes and the box
|
|
468
|
+
is the one a mouse sees: the ground and the focus ring stay square, and
|
|
469
|
+
the hit area above grows to 44 pixels around them. It does not reach back
|
|
470
|
+
over the chips, where the last chip's remove stands a few pixels away. */
|
|
471
|
+
@media (pointer: coarse) {
|
|
472
|
+
[data-ui='tags-input'] > [data-part='clear']::after {
|
|
473
|
+
inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
|
|
474
|
+
inset-inline-start: 0;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* The cross is the `Glyph` element the binding renders inside the button,
|
|
479
|
+
drawn at the control's own icon step. */
|
|
480
|
+
[data-ui='tags-input'] > [data-part='clear'] {
|
|
481
|
+
--slotted-icon-size: var(--_icon-size);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/* ── Size ─────────────────────────────────────────────────────────────── */
|
|
485
|
+
|
|
486
|
+
[data-ui='tags-input'][data-part='root'][data-size='sm'] {
|
|
487
|
+
--_font-size: var(--slotted-control-font-size-sm, 12px);
|
|
488
|
+
--_height: var(--slotted-control-height-sm, 30px);
|
|
489
|
+
--_inner-size: var(--slotted-control-inner-size-sm, 22px);
|
|
490
|
+
--_padding-inline: var(--slotted-control-padding-inline-sm, 10px);
|
|
491
|
+
--_gap: var(--slotted-control-gap-sm, 6px);
|
|
492
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-sm, 14px));
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
[data-ui='tags-input'][data-part='root'][data-size='md'] {
|
|
496
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
497
|
+
--_height: var(--slotted-control-height-md, 34px);
|
|
498
|
+
--_padding-inline: var(--slotted-control-padding-inline-md, 13px);
|
|
499
|
+
--_gap: var(--slotted-control-gap-md, 8px);
|
|
500
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-md, 16px));
|
|
501
|
+
--_inner-size: var(--slotted-control-inner-size-md, 24px);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
[data-ui='tags-input'][data-part='root'][data-size='lg'] {
|
|
505
|
+
--_font-size: var(--slotted-control-font-size-lg, 14px);
|
|
506
|
+
--_height: var(--slotted-control-height-lg, 38px);
|
|
507
|
+
--_inner-size: var(--slotted-control-inner-size-lg, 28px);
|
|
508
|
+
--_padding-inline: var(--slotted-control-padding-inline-lg, 16px);
|
|
509
|
+
--_gap: var(--slotted-control-gap-lg, 8px);
|
|
510
|
+
--_icon-size: max(var(--_icon-floor), var(--slotted-control-icon-size-lg, 18px));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* ── Variant ──────────────────────────────────────────────────────────── */
|
|
514
|
+
|
|
515
|
+
[data-ui='tags-input'][data-part='root'][data-variant='subtle'] {
|
|
516
|
+
background-color: var(
|
|
517
|
+
--slotted-tags-input-subtle-background,
|
|
518
|
+
var(--slotted-surface-sunken, Canvas)
|
|
519
|
+
);
|
|
520
|
+
border-color: var(
|
|
521
|
+
--slotted-tags-input-subtle-border-color,
|
|
522
|
+
var(--slotted-border-subtle, ButtonBorder)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* No edge, no lift, no ground and no corner of its own: the cell it sits in
|
|
527
|
+
is the box, the row is the ground, a cell has no corner, and the resting
|
|
528
|
+
shadow would draw the cell where there is none. */
|
|
529
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'] {
|
|
530
|
+
background-color: transparent;
|
|
531
|
+
border-color: transparent;
|
|
532
|
+
border-radius: var(--slotted-radius-none, 0px);
|
|
533
|
+
box-shadow: none;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
@media (forced-colors: active) {
|
|
537
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'] {
|
|
538
|
+
border-color: ButtonBorder;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* ── States on the control ────────────────────────────────────────────── */
|
|
543
|
+
|
|
544
|
+
[data-ui='tags-input'][data-part='root']:hover:not([data-disabled]):not([data-readonly]):not(
|
|
545
|
+
[data-invalid]
|
|
546
|
+
) {
|
|
547
|
+
border-color: var(--slotted-tags-input-hover-border-color, var(--slotted-tone-accent-border));
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
[data-ui='tags-input'][data-part='root'][data-variant='subtle']:hover:not([data-disabled]):not(
|
|
551
|
+
[data-readonly]
|
|
552
|
+
):not([data-invalid]) {
|
|
553
|
+
background-color: var(
|
|
554
|
+
--slotted-tags-input-subtle-hover-background,
|
|
555
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain']:hover:not([data-disabled]):not(
|
|
560
|
+
[data-readonly]
|
|
561
|
+
):not([data-invalid]) {
|
|
562
|
+
background-color: var(
|
|
563
|
+
--slotted-tags-input-plain-hover-background,
|
|
564
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
565
|
+
);
|
|
566
|
+
/* The accent edge the other variants take would draw the cell's outline. */
|
|
567
|
+
border-color: transparent;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* The frame carries the ring for whatever inside it holds focus — the input
|
|
572
|
+
* or a chip — because the frame is the control a reader is operating.
|
|
573
|
+
*/
|
|
574
|
+
[data-ui='tags-input'][data-part='root']:has([data-part='input']:focus-visible),
|
|
575
|
+
[data-ui='tags-input'][data-part='root']:has(
|
|
576
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
577
|
+
) {
|
|
578
|
+
box-shadow: var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
|
|
579
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
580
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
581
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* The ring of a control whose box is not its own is drawn inside that box,
|
|
586
|
+
* the way the inner controls draw theirs inside the frame: two pixels past
|
|
587
|
+
* the control is two pixels over the next row's rule. No lift either — a
|
|
588
|
+
* shadow that appears only under focus is a cell that changes size when it
|
|
589
|
+
* is used.
|
|
590
|
+
*/
|
|
591
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain']:has(
|
|
592
|
+
[data-part='input']:focus-visible
|
|
593
|
+
),
|
|
594
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain']:has(
|
|
595
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
596
|
+
) {
|
|
597
|
+
box-shadow: none;
|
|
598
|
+
outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* A chip already wears the ring, and the frame around it wearing a second one
|
|
603
|
+
* is two rings for one focus. The frame keeps its lift and gives up the
|
|
604
|
+
* outline while the ring is inside it.
|
|
605
|
+
*/
|
|
606
|
+
[data-ui='tags-input'][data-part='root']:has(
|
|
607
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
608
|
+
) {
|
|
609
|
+
outline: none;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
[data-ui='tags-input'][data-part='root'][data-invalid] {
|
|
613
|
+
--slotted-focus-ring-color: var(
|
|
614
|
+
--slotted-tags-input-invalid-focus-ring-color,
|
|
615
|
+
var(--slotted-focus-ring-color-invalid, Highlight)
|
|
616
|
+
);
|
|
617
|
+
--_invalid-edge-width: var(
|
|
618
|
+
--slotted-tags-input-invalid-edge-width,
|
|
619
|
+
var(--slotted-control-invalid-edge-width, 1px)
|
|
620
|
+
);
|
|
621
|
+
--_invalid-edge-color: var(
|
|
622
|
+
--slotted-tags-input-invalid-border-color,
|
|
623
|
+
var(--slotted-tone-danger-border)
|
|
624
|
+
);
|
|
625
|
+
--_invalid-edge: inset 0 0 0 var(--_invalid-edge-width) var(--_invalid-edge-color);
|
|
626
|
+
|
|
627
|
+
border-color: var(--slotted-tags-input-invalid-border-color, var(--slotted-tone-danger-border));
|
|
628
|
+
/*
|
|
629
|
+
* Width as well as colour (WCAG 1.4.1), the edge `text-field` draws: in
|
|
630
|
+
* `high-contrast` the danger border is the resting edge's black. The line
|
|
631
|
+
* is a shadow inside the border, so neither box nor text moves, and it
|
|
632
|
+
* takes the resting lift's place.
|
|
633
|
+
*/
|
|
634
|
+
box-shadow: var(--_invalid-edge);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
[data-ui='tags-input'][data-part='root'][data-invalid]:has([data-part='input']:focus-visible),
|
|
638
|
+
[data-ui='tags-input'][data-part='root'][data-invalid]:has(
|
|
639
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
640
|
+
) {
|
|
641
|
+
box-shadow:
|
|
642
|
+
var(--_invalid-edge),
|
|
643
|
+
var(--slotted-control-shadow-focus-geometry, 0 1px 4px -1px)
|
|
644
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
648
|
+
[data-part='input']:focus-visible
|
|
649
|
+
),
|
|
650
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
651
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
652
|
+
) {
|
|
653
|
+
/* The ring lies inside the box here, over the border and an edge as wide as
|
|
654
|
+
it; the edge reaches past the ring. */
|
|
655
|
+
box-shadow: inset 0 0 0
|
|
656
|
+
calc(
|
|
657
|
+
var(--slotted-focus-ring-offset, 2px) - var(--slotted-control-border-width, 1px) +
|
|
658
|
+
var(--_invalid-edge-width)
|
|
659
|
+
)
|
|
660
|
+
var(--_invalid-edge-color);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/*
|
|
664
|
+
* Forced colours remove every box shadow, and the edge with them. The
|
|
665
|
+
* width comes back as an outline inside the border, and a focused invalid
|
|
666
|
+
* control draws its ring double, which a valid ring is not.
|
|
667
|
+
*/
|
|
668
|
+
@media (forced-colors: active) {
|
|
669
|
+
[data-ui='tags-input'][data-part='root'][data-invalid] {
|
|
670
|
+
outline: var(--_invalid-edge-width) solid CanvasText;
|
|
671
|
+
outline-offset: calc(
|
|
672
|
+
-1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
[data-ui='tags-input'][data-part='root'][data-invalid]:has([data-part='input']:focus-visible) {
|
|
677
|
+
outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
|
|
678
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
679
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
683
|
+
[data-part='input']:focus-visible
|
|
684
|
+
) {
|
|
685
|
+
outline: calc(var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width)) double
|
|
686
|
+
var(--slotted-focus-ring-color, Highlight);
|
|
687
|
+
outline-offset: calc(
|
|
688
|
+
-1 * (var(--slotted-focus-ring-width, 2px) + var(--_invalid-edge-width))
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
[data-ui='tags-input'][data-part='root'][data-invalid]:has(
|
|
693
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
694
|
+
),
|
|
695
|
+
[data-ui='tags-input'][data-part='root'][data-variant='plain'][data-invalid]:has(
|
|
696
|
+
[data-part='chips'] > :not([data-part='field']):focus-visible
|
|
697
|
+
) {
|
|
698
|
+
outline: var(--_invalid-edge-width) solid CanvasText;
|
|
699
|
+
outline-offset: calc(
|
|
700
|
+
-1 * (var(--slotted-control-border-width, 1px) + var(--_invalid-edge-width))
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Read-only keeps the chips, the caret, the selection and the copy, and
|
|
707
|
+
* withholds every remove control. The native `readonly` gives the text half;
|
|
708
|
+
* the rest is the family's.
|
|
709
|
+
*/
|
|
710
|
+
[data-ui='tags-input'][data-part='root'][data-readonly] {
|
|
711
|
+
background-color: var(
|
|
712
|
+
--slotted-tags-input-readonly-background,
|
|
713
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* `:disabled` on the input is matched beside `data-disabled` on the frame,
|
|
719
|
+
* because a disabled `fieldset` disables every control inside it and the
|
|
720
|
+
* control has no way to say so.
|
|
721
|
+
*/
|
|
722
|
+
[data-ui='tags-input'][data-part='root'][data-disabled],
|
|
723
|
+
[data-ui='tags-input'][data-part='root']:has([data-part='input']:disabled) {
|
|
724
|
+
background-color: var(
|
|
725
|
+
--slotted-tags-input-disabled-background,
|
|
726
|
+
var(--slotted-disabled-background)
|
|
727
|
+
);
|
|
728
|
+
border-color: var(--slotted-tags-input-disabled-border-color, var(--slotted-disabled-border));
|
|
729
|
+
box-shadow: none;
|
|
730
|
+
color: var(--slotted-tags-input-disabled-color, var(--slotted-disabled-foreground));
|
|
731
|
+
cursor: not-allowed;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
[data-ui='tags-input'] > [data-part='clear']:hover:not(:disabled):not([data-disabled]) {
|
|
735
|
+
background-color: var(
|
|
736
|
+
--slotted-tags-input-action-hover-background,
|
|
737
|
+
var(--slotted-tone-secondary-subtle-hover)
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
[data-ui='tags-input'] > [data-part='clear']:active:not(:disabled):not([data-disabled]) {
|
|
742
|
+
background-color: var(
|
|
743
|
+
--slotted-tags-input-action-active-background,
|
|
744
|
+
var(--slotted-tone-secondary-subtle-active)
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* The button carries its own ring rather than borrowing the frame's: tabbing
|
|
750
|
+
* from the input to it has to move something visible, and a ring around the
|
|
751
|
+
* whole frame would sit still while focus moved inside it.
|
|
752
|
+
*/
|
|
753
|
+
[data-ui='tags-input'] > [data-part='clear']:focus-visible {
|
|
754
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
755
|
+
outline-offset: calc(var(--slotted-focus-ring-offset, 2px) * -1);
|
|
756
|
+
}
|
|
757
|
+
}
|