@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
package/src/tag/tag.css
ADDED
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* ── The chip box ───────────────────────────────────────────────────────
|
|
4
|
+
*
|
|
5
|
+
* An entity, a filter or a compact value. It is not metadata — that is
|
|
6
|
+
* `badge`, and the two share this tone and this type scale on purpose — and
|
|
7
|
+
* it is not a command until a member says so.
|
|
8
|
+
*
|
|
9
|
+
* Two attributes on every selector, always. `group` is the one part in this
|
|
10
|
+
* family that contains its family's root instead of sitting inside it, so it
|
|
11
|
+
* carries `data-ui` itself, as `badge`'s `anchor` does.
|
|
12
|
+
*
|
|
13
|
+
* **The root is never the interactive element.** A `button` cannot contain a
|
|
14
|
+
* `button` and an `a` cannot contain either, so a chip that both acts and
|
|
15
|
+
* removes has to put its two controls side by side. The root paints the box;
|
|
16
|
+
* `body` holds the content and is the primary target; `remove` is its
|
|
17
|
+
* sibling. That decision is taken once, for every member, which is what
|
|
18
|
+
* removes the branch Primer needs (`hasMultipleActionTargets`) and the grid
|
|
19
|
+
* React Aria and Angular Material reach for.
|
|
20
|
+
*
|
|
21
|
+
* There is no height token. The block size is the chip's own line box plus a
|
|
22
|
+
* symmetric inset, floored at the WCAG target minimum, so a tag never
|
|
23
|
+
* disagrees with the type it contains and no density can leave one of its
|
|
24
|
+
* controls unhittable.
|
|
25
|
+
*/
|
|
26
|
+
[data-ui='tag'][data-part='root'] {
|
|
27
|
+
/**
|
|
28
|
+
* Tone. The neutral fill is the tone's `solid-hover` step rather than its
|
|
29
|
+
* `solid` one, for the reason `badge` recorded: `solid` is the colour of
|
|
30
|
+
* the surface itself in all three schemes, so a filled neutral chip and a
|
|
31
|
+
* tinted one were the same rectangle and neither read as filled.
|
|
32
|
+
*/
|
|
33
|
+
--_solid: var(--slotted-tone-secondary-solid-hover);
|
|
34
|
+
--_solid-hover: var(--slotted-tone-secondary-solid-active);
|
|
35
|
+
--_solid-active: var(--slotted-tone-secondary-solid-active);
|
|
36
|
+
--_on-solid: var(--slotted-tone-secondary-on-solid);
|
|
37
|
+
--_surface: var(--slotted-tone-secondary-surface);
|
|
38
|
+
--_subtle-hover: var(--slotted-tone-secondary-subtle-hover);
|
|
39
|
+
--_subtle-active: var(--slotted-tone-secondary-subtle-active);
|
|
40
|
+
--_border: var(--slotted-tag-border-color, var(--slotted-tone-secondary-border));
|
|
41
|
+
--_text: var(--slotted-tone-secondary-text);
|
|
42
|
+
/**
|
|
43
|
+
* What a filled chip draws around itself, and for four of the five tones
|
|
44
|
+
* the answer is its own fill: the edge is the ground, so the chip is one
|
|
45
|
+
* shape. `secondary` overrides it below, because its fill is the page's
|
|
46
|
+
* own colour in `high-contrast` and a chip with neither edge nor contrast
|
|
47
|
+
* is a run of text.
|
|
48
|
+
*/
|
|
49
|
+
--_edge: var(--_solid);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Size. Type, glyph and gap come from the control scale, which is the only
|
|
53
|
+
* scale that moves with density, so a tag shrinks beside the controls it
|
|
54
|
+
* sits with. The insets come from the space scale: a density step inside
|
|
55
|
+
* an inset this small would be sub-pixel, and density already moves the
|
|
56
|
+
* type, which moves the box.
|
|
57
|
+
*/
|
|
58
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
59
|
+
--_icon-size: var(--slotted-control-icon-size-sm, 14px);
|
|
60
|
+
--_inner-size: var(--slotted-control-inner-size-sm, 22px);
|
|
61
|
+
/**
|
|
62
|
+
* The two tokens a host sets on a row of chips and never on a chip: the
|
|
63
|
+
* block inset, so a frame that is shorter than the chip at `dense` can
|
|
64
|
+
* ask it to give up its air rather than its type (`multi-select` and
|
|
65
|
+
* `tags-input` set it from the room their frame has left); and the edge,
|
|
66
|
+
* so a host can mark one chip — the one that answered a duplicate —
|
|
67
|
+
* without reaching into this sheet. Both are read here, once, and a host
|
|
68
|
+
* writes `[data-ui='tag']` nowhere.
|
|
69
|
+
*/
|
|
70
|
+
--_inset-block: var(--slotted-tag-inset-block, var(--slotted-space-2, 0.25rem));
|
|
71
|
+
--_inset-inline: var(--slotted-space-4, 0.5rem);
|
|
72
|
+
--_gap: var(--slotted-space-2, 0.25rem);
|
|
73
|
+
|
|
74
|
+
--_line-height: var(--slotted-line-height-xs, 1.4);
|
|
75
|
+
--_edge-width: var(--slotted-tag-border-width, var(--slotted-border-width-thin, 1px));
|
|
76
|
+
--_radius: var(--slotted-radius-full, 9999px);
|
|
77
|
+
/**
|
|
78
|
+
* The corner the fills inside the border box are cut to. A fill drawn to
|
|
79
|
+
* the outer radius bleeds past the border's inner curve on a square chip;
|
|
80
|
+
* the difference is invisible on a pill, where both are round.
|
|
81
|
+
*/
|
|
82
|
+
--_inner-radius: max(0px, calc(var(--_radius) - var(--_edge-width)));
|
|
83
|
+
/**
|
|
84
|
+
* The chip's own line box plus its inset, and nothing else. It carried a
|
|
85
|
+
* floor at the WCAG 2.2 2.5.8 minimum for a while, so that the remove
|
|
86
|
+
* control — which stretches to the chip — would be hittable; the floor
|
|
87
|
+
* bound on `sm` alone and it still did not deliver the target, because a
|
|
88
|
+
* control stretched inside a 24px border box is 22px of content between
|
|
89
|
+
* two edges (TG2). The target is the control's own now, taken from a
|
|
90
|
+
* transparent halo below, which is the answer
|
|
91
|
+
* `docs/token-foundation.md` names for a target short in one axis and the
|
|
92
|
+
* answer R2 gives for every inner control. A chip is the height of what it
|
|
93
|
+
* says.
|
|
94
|
+
*/
|
|
95
|
+
--_own-size: calc(
|
|
96
|
+
var(--_font-size) * var(--_line-height) + 2 * var(--_inset-block) + 2 * var(--_edge-width)
|
|
97
|
+
);
|
|
98
|
+
/**
|
|
99
|
+
* Inside a control the chip is the height the foundation gives the inside
|
|
100
|
+
* of a control — `--slotted-control-inner-size`, which the host writes on
|
|
101
|
+
* the row of chips from its own size step — and its line and its inset
|
|
102
|
+
* are derived from that height rather than the other way round. On its own
|
|
103
|
+
* the two derivations return exactly the type-and-inset height above, so a
|
|
104
|
+
* chip in running text is unchanged. The scale exists because a chip whose
|
|
105
|
+
* height followed its type shrank one pixel between comfortable and dense
|
|
106
|
+
* while the control around it shrank eight (`docs/token-foundation.md`,
|
|
107
|
+
* Control geometry).
|
|
108
|
+
*/
|
|
109
|
+
--_block-size: var(--slotted-control-inner-size, var(--_own-size));
|
|
110
|
+
--_line: min(
|
|
111
|
+
calc(var(--_font-size) * var(--_line-height)),
|
|
112
|
+
calc(var(--_block-size) - 2 * var(--_edge-width))
|
|
113
|
+
);
|
|
114
|
+
--_inset: max(0px, calc((var(--_block-size) - var(--_line) - 2 * var(--_edge-width)) / 2));
|
|
115
|
+
|
|
116
|
+
align-items: stretch;
|
|
117
|
+
border: var(--_edge-width) solid transparent;
|
|
118
|
+
border-radius: var(--_radius);
|
|
119
|
+
box-sizing: border-box;
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
font-family: var(--slotted-tag-font-family, var(--slotted-control-font-family, sans-serif));
|
|
122
|
+
font-size: var(--_font-size);
|
|
123
|
+
font-weight: var(--slotted-tag-font-weight, var(--slotted-font-weight-medium, 500));
|
|
124
|
+
line-height: var(--_line);
|
|
125
|
+
/**
|
|
126
|
+
* One line, always, and no wider than what it is given. A tag holds a
|
|
127
|
+
* name; a tag that reflows into a paragraph has stopped being one. The
|
|
128
|
+
* clipping is visual only — `text-overflow` shortens nothing — so the whole
|
|
129
|
+
* value stays in the DOM, stays in the accessibility tree, and a page
|
|
130
|
+
* search still finds it.
|
|
131
|
+
*/
|
|
132
|
+
max-inline-size: 100%;
|
|
133
|
+
min-block-size: var(--_block-size);
|
|
134
|
+
/* Written inside a sentence, a tag sits on the text's centre. */
|
|
135
|
+
vertical-align: middle;
|
|
136
|
+
white-space: nowrap;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A tag a collapse is hiding. The rule exists because `display: inline-flex`
|
|
141
|
+
* above beats the user agent's own `[hidden] { display: none }` — author
|
|
142
|
+
* styles win over the user agent sheet — so without it every hidden chip
|
|
143
|
+
* rendered and the collapse did nothing at all: six chosen values drew six
|
|
144
|
+
* chips, which ran out of the lane the control gives them and under the
|
|
145
|
+
* controls that end it (SL9). `breadcrumb`, `toolbar`, `tabs`, `alert` and
|
|
146
|
+
* `progress-indicator` each write this rule for the same reason; `tag` is
|
|
147
|
+
* the sheet that was missing it, and the two hosts that collapse a row of
|
|
148
|
+
* chips both write the attribute and neither could have known.
|
|
149
|
+
*/
|
|
150
|
+
[data-ui='tag'][data-part='root'][hidden] {
|
|
151
|
+
display: none;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* ── Tone: which of the five semantic colours the tag speaks in ────────── */
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The one tone whose fill is the colour of the page. It keeps the tone's own
|
|
158
|
+
* border, where the other four let their fill be their edge.
|
|
159
|
+
*/
|
|
160
|
+
[data-ui='tag'][data-part='root'][data-tone='secondary'] {
|
|
161
|
+
--_edge: var(--_border);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
[data-ui='tag'][data-part='root'][data-tone='accent'] {
|
|
165
|
+
--_solid: var(--slotted-tone-accent-solid);
|
|
166
|
+
--_solid-hover: var(--slotted-tone-accent-solid-hover);
|
|
167
|
+
--_solid-active: var(--slotted-tone-accent-solid-active);
|
|
168
|
+
--_on-solid: var(--slotted-tone-accent-on-solid);
|
|
169
|
+
--_surface: var(--slotted-tone-accent-surface);
|
|
170
|
+
--_subtle-hover: var(--slotted-tone-accent-subtle-hover);
|
|
171
|
+
--_subtle-active: var(--slotted-tone-accent-subtle-active);
|
|
172
|
+
--_border: var(--slotted-tag-border-color, var(--slotted-tone-accent-border));
|
|
173
|
+
--_text: var(--slotted-tone-accent-text);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
[data-ui='tag'][data-part='root'][data-tone='success'] {
|
|
177
|
+
--_solid: var(--slotted-tone-success-solid);
|
|
178
|
+
--_solid-hover: var(--slotted-tone-success-solid-hover);
|
|
179
|
+
--_solid-active: var(--slotted-tone-success-solid-active);
|
|
180
|
+
--_on-solid: var(--slotted-tone-success-on-solid);
|
|
181
|
+
--_surface: var(--slotted-tone-success-surface);
|
|
182
|
+
--_subtle-hover: var(--slotted-tone-success-subtle-hover);
|
|
183
|
+
--_subtle-active: var(--slotted-tone-success-subtle-active);
|
|
184
|
+
--_border: var(--slotted-tag-border-color, var(--slotted-tone-success-border));
|
|
185
|
+
--_text: var(--slotted-tone-success-text);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
[data-ui='tag'][data-part='root'][data-tone='warning'] {
|
|
189
|
+
--_solid: var(--slotted-tone-warning-solid);
|
|
190
|
+
--_solid-hover: var(--slotted-tone-warning-solid-hover);
|
|
191
|
+
--_solid-active: var(--slotted-tone-warning-solid-active);
|
|
192
|
+
--_on-solid: var(--slotted-tone-warning-on-solid);
|
|
193
|
+
--_surface: var(--slotted-tone-warning-surface);
|
|
194
|
+
--_subtle-hover: var(--slotted-tone-warning-subtle-hover);
|
|
195
|
+
--_subtle-active: var(--slotted-tone-warning-subtle-active);
|
|
196
|
+
--_border: var(--slotted-tag-border-color, var(--slotted-tone-warning-border));
|
|
197
|
+
--_text: var(--slotted-tone-warning-text);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
[data-ui='tag'][data-part='root'][data-tone='danger'] {
|
|
201
|
+
--_solid: var(--slotted-tone-danger-solid);
|
|
202
|
+
--_solid-hover: var(--slotted-tone-danger-solid-hover);
|
|
203
|
+
--_solid-active: var(--slotted-tone-danger-solid-active);
|
|
204
|
+
--_on-solid: var(--slotted-tone-danger-on-solid);
|
|
205
|
+
--_surface: var(--slotted-tone-danger-surface);
|
|
206
|
+
--_subtle-hover: var(--slotted-tone-danger-subtle-hover);
|
|
207
|
+
--_subtle-active: var(--slotted-tone-danger-subtle-active);
|
|
208
|
+
--_border: var(--slotted-tag-border-color, var(--slotted-tone-danger-border));
|
|
209
|
+
--_text: var(--slotted-tone-danger-text);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* ── Variant: three paintings, and only two of them have an edge ────────
|
|
214
|
+
*
|
|
215
|
+
* The same three words, and the same reasoning, `badge` uses: `solid` fills
|
|
216
|
+
* and its edge is its own fill; `soft` fills with the tone's tinted
|
|
217
|
+
* `surface` and draws the tone's `border` around it; `outline` is that edge
|
|
218
|
+
* with nothing behind it. `soft` keeps its edge because in `high-contrast`
|
|
219
|
+
* every tone surface collapses to the page's own white, and there it
|
|
220
|
+
* converges with `outline` — which is what a high-contrast scheme is for.
|
|
221
|
+
*/
|
|
222
|
+
|
|
223
|
+
[data-ui='tag'][data-part='root'][data-variant='solid'] {
|
|
224
|
+
background-color: var(--_solid, ButtonFace);
|
|
225
|
+
border-color: var(--_edge, ButtonFace);
|
|
226
|
+
color: var(--_on-solid, ButtonText);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
[data-ui='tag'][data-part='root'][data-variant='soft'] {
|
|
230
|
+
background-color: var(--_surface, ButtonFace);
|
|
231
|
+
border-color: var(--_border, ButtonBorder);
|
|
232
|
+
color: var(--_text, ButtonText);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
[data-ui='tag'][data-part='root'][data-variant='outline'] {
|
|
236
|
+
background-color: transparent;
|
|
237
|
+
border-color: var(--_border, ButtonBorder);
|
|
238
|
+
color: var(--_text, ButtonText);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ── Size ─────────────────────────────────────────────────────────────── */
|
|
242
|
+
|
|
243
|
+
[data-ui='tag'][data-part='root'][data-size='sm'] {
|
|
244
|
+
--_font-size: var(--slotted-control-font-size-sm, 12px);
|
|
245
|
+
--_inset-block: var(--slotted-tag-inset-block, var(--slotted-space-1, 0.125rem));
|
|
246
|
+
--_inset-inline: var(--slotted-space-3, 0.375rem);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* The glyph scale has three steps and this family's three sizes span less of
|
|
251
|
+
* it, so `sm` and `md` land on the same one — the answer `badge` reached for
|
|
252
|
+
* the same reason: a 12px chip and a 13px chip should not carry visibly
|
|
253
|
+
* different glyphs.
|
|
254
|
+
*/
|
|
255
|
+
[data-ui='tag'][data-part='root'][data-size='lg'] {
|
|
256
|
+
--_font-size: var(--slotted-control-font-size-lg, 14px);
|
|
257
|
+
--_icon-size: var(--slotted-control-icon-size-md, 16px);
|
|
258
|
+
--_inner-size: var(--slotted-control-inner-size-md, 24px);
|
|
259
|
+
--_inset-block: var(--slotted-tag-inset-block, var(--slotted-space-3, 0.375rem));
|
|
260
|
+
--_inset-inline: var(--slotted-space-5, 0.75rem);
|
|
261
|
+
--_gap: var(--slotted-space-3, 0.375rem);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* ── Shape ────────────────────────────────────────────────────────────── */
|
|
265
|
+
|
|
266
|
+
[data-ui='tag'][data-part='root'][data-shape='square'] {
|
|
267
|
+
--_radius: var(--slotted-radius-sm, 4px);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* ── The content box, and the primary target ────────────────────────────
|
|
272
|
+
*
|
|
273
|
+
* It carries the chip's inset rather than the root, so a hovered or pressed
|
|
274
|
+
* body fills the chip to its edge instead of leaving a ring of untouched
|
|
275
|
+
* ground around itself. It is a `span` when the tag does nothing and the
|
|
276
|
+
* element its member names when it does.
|
|
277
|
+
*/
|
|
278
|
+
[data-ui='tag'] [data-part='body'] {
|
|
279
|
+
align-items: center;
|
|
280
|
+
/* The root paints the ground; the body paints only its own states. */
|
|
281
|
+
background-color: transparent;
|
|
282
|
+
border: 0;
|
|
283
|
+
border-end-start-radius: var(--_inner-radius);
|
|
284
|
+
border-start-start-radius: var(--_inner-radius);
|
|
285
|
+
box-sizing: border-box;
|
|
286
|
+
color: inherit;
|
|
287
|
+
display: inline-flex;
|
|
288
|
+
font: inherit;
|
|
289
|
+
gap: var(--_gap);
|
|
290
|
+
letter-spacing: inherit;
|
|
291
|
+
/* What lets a long chip shrink below its content, which is the condition
|
|
292
|
+
`text-overflow` needs to have anything to do. */
|
|
293
|
+
min-inline-size: 0;
|
|
294
|
+
padding-block: var(--_inset);
|
|
295
|
+
padding-inline: var(--_inset-inline);
|
|
296
|
+
text-align: start;
|
|
297
|
+
/* A body that renders as an anchor keeps the chip's shape as its
|
|
298
|
+
affordance; the underline belongs to `link`, on a link. */
|
|
299
|
+
text-decoration: none;
|
|
300
|
+
transition:
|
|
301
|
+
background-color var(--slotted-control-transition-duration)
|
|
302
|
+
var(--slotted-control-transition-easing),
|
|
303
|
+
color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* The only child rounds both ends, which is every tag that cannot be removed. */
|
|
307
|
+
[data-ui='tag'] [data-part='body']:last-child {
|
|
308
|
+
border-end-end-radius: var(--_inner-radius);
|
|
309
|
+
border-start-end-radius: var(--_inner-radius);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* A body followed by a remove control gives back most of its trailing inset.
|
|
314
|
+
* The control is a square as tall as the chip, so its own centring already
|
|
315
|
+
* puts seven pixels between the words and the glyph at the medium step; the
|
|
316
|
+
* full inset on top of that made the label sit closer to the start edge than
|
|
317
|
+
* to the X, which the capture of a one-character chip showed as a pill made
|
|
318
|
+
* mostly of air. What is left is the gap the chip uses between any two things
|
|
319
|
+
* inside it.
|
|
320
|
+
*/
|
|
321
|
+
[data-ui='tag'] [data-part='body']:has(+ [data-part='remove']) {
|
|
322
|
+
padding-inline-end: var(--_gap);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
[data-ui='tag'] [data-part='body']:is(a, button) {
|
|
326
|
+
cursor: pointer;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ── The words, and the glyphs on either side of them ─────────────────── */
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Where the line is clipped. `min-inline-size: 0` is what lets the box
|
|
333
|
+
* shrink below its content inside the flex body.
|
|
334
|
+
*/
|
|
335
|
+
[data-ui='tag'] [data-part='label'] {
|
|
336
|
+
min-inline-size: 0;
|
|
337
|
+
overflow: hidden;
|
|
338
|
+
text-overflow: ellipsis;
|
|
339
|
+
/**
|
|
340
|
+
* A tag holds a value somebody typed, and its direction is the value's own
|
|
341
|
+
* rather than the page's. `plaintext` is the CSS form of `dir="auto"`: the
|
|
342
|
+
* first strong character decides, so an Arabic name inside an English page
|
|
343
|
+
* reads right to left, a Latin name inside an Arabic page reads left to
|
|
344
|
+
* right, and each one is clipped at its own end rather than at the page's.
|
|
345
|
+
* The right-to-left capture is what asked the question — a Latin value with
|
|
346
|
+
* leading punctuation was reordered by the paragraph around it.
|
|
347
|
+
*/
|
|
348
|
+
unicode-bidi: plaintext;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
@supports (text-box: trim-both cap alphabetic) {
|
|
352
|
+
[data-ui='tag'] [data-part='label'] {
|
|
353
|
+
/**
|
|
354
|
+
* The line box a flex container centres is not symmetric around the
|
|
355
|
+
* letters inside it: the ascender reaches further above the cap than the
|
|
356
|
+
* descender reaches below the baseline, so a word with no descender sits
|
|
357
|
+
* high in its chip and a word with one looks right. `text-box` centres
|
|
358
|
+
* the ink instead of the font's metrics.
|
|
359
|
+
*
|
|
360
|
+
* The padding gives `overflow: hidden` room for the descenders and the
|
|
361
|
+
* tall diacritics that live outside a trimmed box, and the negative
|
|
362
|
+
* margin gives the space straight back — the same correction `badge`
|
|
363
|
+
* needed after a capture showed it beheading a `g`. A proportion of the
|
|
364
|
+
* type rather than a step of any scale, because what has to be cleared
|
|
365
|
+
* is the font's own overshoot.
|
|
366
|
+
*/
|
|
367
|
+
margin-block: -0.3em;
|
|
368
|
+
padding-block: 0.3em;
|
|
369
|
+
text-box: trim-both cap alphabetic;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* The slot sizes what it holds: an icon box reads `--slotted-icon-size`
|
|
375
|
+
* from its container, and a bare glyph host such as `ng-icon` reads the
|
|
376
|
+
* slot's font-size, so both are the glyph scale.
|
|
377
|
+
*/
|
|
378
|
+
[data-ui='tag'] [data-part='start'],
|
|
379
|
+
[data-ui='tag'] [data-part='end'] {
|
|
380
|
+
--slotted-icon-size: var(--_icon-size);
|
|
381
|
+
|
|
382
|
+
align-items: center;
|
|
383
|
+
block-size: var(--_icon-size);
|
|
384
|
+
box-sizing: border-box;
|
|
385
|
+
display: inline-flex;
|
|
386
|
+
flex: none;
|
|
387
|
+
font-size: var(--_icon-size);
|
|
388
|
+
inline-size: var(--_icon-size);
|
|
389
|
+
justify-content: center;
|
|
390
|
+
line-height: 1;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
[data-ui='tag'] [data-part='start'] > *,
|
|
394
|
+
[data-ui='tag'] [data-part='end'] > * {
|
|
395
|
+
block-size: 100%;
|
|
396
|
+
display: block;
|
|
397
|
+
inline-size: 100%;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* ── The selection mark ─────────────────────────────────────────────────
|
|
402
|
+
*
|
|
403
|
+
* A selected chip changes its ground, and a ground is a colour. WCAG 2.2
|
|
404
|
+
* 1.4.1 asks for a second signal, so the check is drawn as well — the
|
|
405
|
+
* `check` glyph the binding renders in an icon box, never a character.
|
|
406
|
+
*
|
|
407
|
+
* It arrives by growing from nothing rather than appearing, because the
|
|
408
|
+
* words beside it move to make room and an eye that cannot follow that reads
|
|
409
|
+
* the row as having jumped. Angular Material takes the jump and offers
|
|
410
|
+
* `hideSingleSelectionIndicator` to avoid it; the transition is the third
|
|
411
|
+
* answer, and the theme collapses its duration under reduced motion.
|
|
412
|
+
*/
|
|
413
|
+
[data-ui='tag'] [data-part='indicator'] {
|
|
414
|
+
--slotted-icon-size: var(--_icon-size);
|
|
415
|
+
|
|
416
|
+
align-items: center;
|
|
417
|
+
block-size: var(--_icon-size);
|
|
418
|
+
display: inline-flex;
|
|
419
|
+
flex: none;
|
|
420
|
+
inline-size: 0;
|
|
421
|
+
/* The icon keeps its size while the box grows round it, centred and
|
|
422
|
+
clipped, so the check is uncovered from its middle outwards. */
|
|
423
|
+
justify-content: center;
|
|
424
|
+
/* A flex gap is drawn beside a zero-width item as readily as beside a wide
|
|
425
|
+
one, so the mark that is not there would still cost the chip a gap of
|
|
426
|
+
leading space. The negative margin is that gap, given back. */
|
|
427
|
+
margin-inline-end: calc(-1 * var(--_gap));
|
|
428
|
+
opacity: 0;
|
|
429
|
+
overflow: hidden;
|
|
430
|
+
transition:
|
|
431
|
+
inline-size var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
432
|
+
margin-inline-end var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
433
|
+
opacity var(--slotted-duration-short) var(--slotted-easing-standard);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
[data-ui='tag'][data-part='root'][data-selected] [data-part='indicator'] {
|
|
437
|
+
inline-size: var(--_icon-size);
|
|
438
|
+
margin-inline-end: 0;
|
|
439
|
+
opacity: 1;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* ── The remove control ─────────────────────────────────────────────────
|
|
444
|
+
*
|
|
445
|
+
* A segment as tall as the chip, at its end. That is Carbon's and Fluent's
|
|
446
|
+
* picture, and it is the one geometry that makes the target reach the WCAG
|
|
447
|
+
* 2.2 2.5.8 minimum in the block axis without a hidden hit area — an
|
|
448
|
+
* invisible box taller than the chip would reach past it and take the
|
|
449
|
+
* pointer from the neighbour in a wrapped run. Its width is the inner
|
|
450
|
+
* control's (R2): the glyph plus a step of air on each side, floored at the
|
|
451
|
+
* same minimum, so the segment is a square on the `sm` and `md` chips and
|
|
452
|
+
* a step narrower than tall on `lg`.
|
|
453
|
+
*
|
|
454
|
+
* The cost, on a pill: a hovered remove is a rounded-ended segment rather
|
|
455
|
+
* than a disc. That is the shape of the target, which is the truth.
|
|
456
|
+
*
|
|
457
|
+
* The mark is the `x` glyph the binding renders; the control hands its icon
|
|
458
|
+
* box the chip's glyph size.
|
|
459
|
+
*/
|
|
460
|
+
[data-ui='tag'] [data-part='remove'] {
|
|
461
|
+
--slotted-icon-size: var(--_icon-size);
|
|
462
|
+
|
|
463
|
+
align-items: center;
|
|
464
|
+
appearance: none;
|
|
465
|
+
background-color: transparent;
|
|
466
|
+
border: 0;
|
|
467
|
+
border-end-end-radius: var(--_inner-radius);
|
|
468
|
+
border-start-end-radius: var(--_inner-radius);
|
|
469
|
+
box-sizing: border-box;
|
|
470
|
+
color: inherit;
|
|
471
|
+
cursor: pointer;
|
|
472
|
+
display: inline-flex;
|
|
473
|
+
flex: none;
|
|
474
|
+
inline-size: max(
|
|
475
|
+
var(--slotted-target-min, 24px),
|
|
476
|
+
min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size))
|
|
477
|
+
);
|
|
478
|
+
justify-content: center;
|
|
479
|
+
padding: 0;
|
|
480
|
+
position: relative;
|
|
481
|
+
transition: background-color var(--slotted-control-transition-duration)
|
|
482
|
+
var(--slotted-control-transition-easing);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* The halo that completes the target where the box is shorter than it. The
|
|
487
|
+
* control stretches to the chip's content box, which is the chip less its
|
|
488
|
+
* two edges, so on the shortest chip the box was 24 wide and 22 tall and the
|
|
489
|
+
* press area failed SC 2.5.8 on the axis nobody was measuring. The halo is
|
|
490
|
+
* transparent and it is `min(0px, …)`, so it grows the box only where the box
|
|
491
|
+
* falls short and is inert on the two larger sizes, where the chip is already
|
|
492
|
+
* taller than the minimum.
|
|
493
|
+
*/
|
|
494
|
+
[data-ui='tag'] [data-part='remove']::after {
|
|
495
|
+
content: '';
|
|
496
|
+
inset: min(0px, calc((100% - var(--slotted-target-min, 24px)) / 2));
|
|
497
|
+
position: absolute;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* On a finger the target is the comfortable size in both axes, and the
|
|
502
|
+
* control's ground is never taller than it is wide: the box is at least as
|
|
503
|
+
* wide as the chip is tall inside its edges, where a large chip drew a
|
|
504
|
+
* segment 24 wide and 32 tall. The halo above grows to 44 pixels around it.
|
|
505
|
+
*/
|
|
506
|
+
@media (pointer: coarse) {
|
|
507
|
+
[data-ui='tag'] [data-part='remove'] {
|
|
508
|
+
inline-size: max(
|
|
509
|
+
var(--slotted-target-min, 24px),
|
|
510
|
+
min(calc(var(--_icon-size) + 2 * var(--slotted-space-2, 0.25rem)), var(--_inner-size)),
|
|
511
|
+
calc(var(--_block-size) - 2 * var(--_edge-width))
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
[data-ui='tag'] [data-part='remove']::after {
|
|
516
|
+
inset: min(0px, calc((100% - var(--slotted-target-comfortable, 44px)) / 2));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/* A tag that is only a remove control is not a tag, but the rounding is one
|
|
521
|
+
rule either way rather than a case the sheet has to know about. */
|
|
522
|
+
[data-ui='tag'] [data-part='remove']:first-child {
|
|
523
|
+
border-end-start-radius: var(--_inner-radius);
|
|
524
|
+
border-start-start-radius: var(--_inner-radius);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* ── Selected, held back for the one state stronger than it ───────────── */
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* A chip that is on takes the tone's solid fill whatever its variant, which
|
|
531
|
+
* is the rule `button` set for `pressed`: "on" is never one shade away from
|
|
532
|
+
* "hovered".
|
|
533
|
+
*/
|
|
534
|
+
[data-ui='tag'][data-part='root'][data-selected]:not([data-disabled]) {
|
|
535
|
+
background-color: var(--_solid, ButtonFace);
|
|
536
|
+
border-color: var(--_edge, ButtonBorder);
|
|
537
|
+
color: var(--_on-solid, ButtonText);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* ── Hover and press, held back for every stronger state ────────────────
|
|
542
|
+
*
|
|
543
|
+
* Each control answers on its own, because the chip holds two of them and a
|
|
544
|
+
* wash over the whole box could not say which one the pointer is on.
|
|
545
|
+
*
|
|
546
|
+
* Three variants, two mechanisms. `solid` and `outline` step along the
|
|
547
|
+
* tone's own ramp, which is what `button` does with the same two words.
|
|
548
|
+
* `soft` cannot: the tinted ramp ends at `surface` — measured in the light
|
|
549
|
+
* scheme, `subtle-hover` is #f1f5f9 against a #e2e8f0 ground and
|
|
550
|
+
* `subtle-active` is that ground exactly — so a tinted chip hovering to a
|
|
551
|
+
* tinted role either lightened or did nothing, and the first hover capture
|
|
552
|
+
* showed the remove segment reading paler than the chip it sits in.
|
|
553
|
+
*
|
|
554
|
+
* Its step is a state layer instead: the chip's own text colour, at a low
|
|
555
|
+
* strength, over whatever ground it already has. It darkens a tinted chip
|
|
556
|
+
* and never depends on a role the foundation does not carry. The cost is
|
|
557
|
+
* that a theme retunes it by strength rather than by colour, which is what
|
|
558
|
+
* the two component tokens are for.
|
|
559
|
+
*/
|
|
560
|
+
|
|
561
|
+
[data-ui='tag'][data-part='root'] {
|
|
562
|
+
--_state-hover: color-mix(
|
|
563
|
+
in oklab,
|
|
564
|
+
currentColor var(--slotted-tag-state-layer-hover, 8%),
|
|
565
|
+
transparent
|
|
566
|
+
);
|
|
567
|
+
--_state-active: color-mix(
|
|
568
|
+
in oklab,
|
|
569
|
+
currentColor var(--slotted-tag-state-layer-active, 14%),
|
|
570
|
+
transparent
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
[data-ui='tag'][data-part='root'][data-variant='soft']:not([data-disabled]):not([data-selected])
|
|
575
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):hover:not(:disabled) {
|
|
576
|
+
background-color: var(--_state-hover);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
[data-ui='tag'][data-part='root'][data-variant='soft']:not([data-disabled]):not([data-selected])
|
|
580
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):active:not(:disabled) {
|
|
581
|
+
background-color: var(--_state-active);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
[data-ui='tag'][data-part='root'][data-variant='outline']:not([data-disabled]):not(
|
|
585
|
+
[data-selected]
|
|
586
|
+
)
|
|
587
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):hover:not(:disabled) {
|
|
588
|
+
background-color: var(--_subtle-hover, ButtonFace);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
[data-ui='tag'][data-part='root'][data-variant='outline']:not([data-disabled]):not(
|
|
592
|
+
[data-selected]
|
|
593
|
+
)
|
|
594
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):active:not(:disabled) {
|
|
595
|
+
background-color: var(--_subtle-active, ButtonFace);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* A filled chip washes along its own ramp, as `button` does — and a selected
|
|
600
|
+
* chip is a filled chip whatever its variant, so the two share these rules.
|
|
601
|
+
*/
|
|
602
|
+
[data-ui='tag'][data-part='root'][data-variant='solid']:not([data-disabled])
|
|
603
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):hover:not(:disabled),
|
|
604
|
+
[data-ui='tag'][data-part='root'][data-selected]:not([data-disabled])
|
|
605
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):hover:not(:disabled) {
|
|
606
|
+
background-color: var(--_solid-hover, Highlight);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
[data-ui='tag'][data-part='root'][data-variant='solid']:not([data-disabled])
|
|
610
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):active:not(:disabled),
|
|
611
|
+
[data-ui='tag'][data-part='root'][data-selected]:not([data-disabled])
|
|
612
|
+
:is([data-part='body']:is(a, button), [data-part='remove']):active:not(:disabled) {
|
|
613
|
+
background-color: var(--_solid-active, Highlight);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* ── Focus ────────────────────────────────────────────────────────────── */
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Drawn on the control rather than on the chip, because the chip can hold
|
|
620
|
+
* two of them and a ring around the whole box could not say which one has
|
|
621
|
+
* focus. It is never held back for `disabled`: a control that keeps its
|
|
622
|
+
* place in the tab sequence while unavailable still has to show where focus
|
|
623
|
+
* is.
|
|
624
|
+
*
|
|
625
|
+
* The offset is negative, so the ring is drawn inside the control's own box.
|
|
626
|
+
* A positive offset on the body would put the ring over the remove control
|
|
627
|
+
* beside it, and on the remove it would spill outside the chip and touch the
|
|
628
|
+
* next tag in a wrapped run.
|
|
629
|
+
*
|
|
630
|
+
* It is two ring widths rather than one. At one the ring's outer edge landed
|
|
631
|
+
* exactly on the chip's own border, and the first zoomed capture showed it
|
|
632
|
+
* reading as a thickened rim rather than as a ring; a second width leaves a
|
|
633
|
+
* sliver of the chip's ground outside it, which is what separates the two.
|
|
634
|
+
*
|
|
635
|
+
* The ring takes the control's own corners, so on a pill the remove's is
|
|
636
|
+
* flat on the inside and round on the outside. That is the shape of the
|
|
637
|
+
* target: a rounded rectangle floating inside the segment would be prettier
|
|
638
|
+
* and would say the hit area is somewhere it is not.
|
|
639
|
+
*/
|
|
640
|
+
[data-ui='tag'] [data-part='body']:focus-visible,
|
|
641
|
+
[data-ui='tag'] [data-part='remove']:focus-visible {
|
|
642
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
643
|
+
outline-offset: calc(-2 * var(--slotted-focus-ring-width, 2px));
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* The group's own ring sits outside it, because nothing is adjacent to it.
|
|
648
|
+
* It is drawn for one moment: the group takes focus when the last tag it
|
|
649
|
+
* held is removed, so the keyboard is not returned to the top of the page.
|
|
650
|
+
*/
|
|
651
|
+
[data-ui='tag'][data-part='group']:focus-visible {
|
|
652
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
653
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/* ── Disabled ─────────────────────────────────────────────────────────── */
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Per variant, for the reason `button` records: a flat control that fills
|
|
660
|
+
* with grey on the way to being unavailable reads as a different control
|
|
661
|
+
* rather than as the same one unavailable.
|
|
662
|
+
*
|
|
663
|
+
* `[data-disabled]` rather than `:disabled` alone, because the root is never
|
|
664
|
+
* a control and a control that keeps its place in the tab sequence carries
|
|
665
|
+
* `aria-disabled` and no `:disabled`.
|
|
666
|
+
*/
|
|
667
|
+
[data-ui='tag'][data-part='root'][data-disabled] {
|
|
668
|
+
color: var(--slotted-disabled-foreground, GrayText);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Three variants become two. What survives the loss of the tone is whether
|
|
673
|
+
* the chip is filled, and the rim has to stay on the filled one: in
|
|
674
|
+
* `high-contrast` the disabled ground is the page's own white, so a filled
|
|
675
|
+
* chip drawing its own ground as its edge had no edge at all — the third
|
|
676
|
+
* capture showed "Disabled selected" as a check and two words floating on
|
|
677
|
+
* the page with no box around them.
|
|
678
|
+
*/
|
|
679
|
+
[data-ui='tag'][data-part='root'][data-variant='solid'][data-disabled],
|
|
680
|
+
[data-ui='tag'][data-part='root'][data-variant='soft'][data-disabled],
|
|
681
|
+
[data-ui='tag'][data-part='root'][data-selected][data-disabled] {
|
|
682
|
+
background-color: var(--slotted-disabled-background, Canvas);
|
|
683
|
+
border-color: var(--slotted-disabled-border, GrayText);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
[data-ui='tag'][data-part='root'][data-variant='outline'][data-disabled] {
|
|
687
|
+
background-color: transparent;
|
|
688
|
+
border-color: var(--slotted-disabled-border, GrayText);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
[data-ui='tag'][data-part='root'][data-disabled] :is([data-part='body'], [data-part='remove']),
|
|
692
|
+
[data-ui='tag'] [data-part='body']:disabled,
|
|
693
|
+
[data-ui='tag'] [data-part='remove']:disabled {
|
|
694
|
+
background-color: transparent;
|
|
695
|
+
cursor: not-allowed;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* A remove control the consumer disabled on its own, inside a chip that is
|
|
700
|
+
* otherwise operable. It loses its colour rather than the whole chip's.
|
|
701
|
+
*/
|
|
702
|
+
[data-ui='tag'] [data-part='remove']:disabled {
|
|
703
|
+
color: var(--slotted-disabled-foreground, GrayText);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* ── The run of tags ────────────────────────────────────────────────────
|
|
708
|
+
*
|
|
709
|
+
* It wraps, because a filter bar with eleven filters is the normal case and
|
|
710
|
+
* a row that scrolls sideways hides the eleventh. It is one tab stop, and
|
|
711
|
+
* the arrow keys move between the controls inside it — the APG Toolbar
|
|
712
|
+
* pattern, which is a container for grouping a set of controls.
|
|
713
|
+
*/
|
|
714
|
+
[data-ui='tag'][data-part='group'] {
|
|
715
|
+
align-items: center;
|
|
716
|
+
display: flex;
|
|
717
|
+
flex-wrap: wrap;
|
|
718
|
+
gap: var(--slotted-tag-group-gap, var(--slotted-space-2, 0.25rem));
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
[data-ui='tag'][data-part='group'][data-orientation='vertical'] {
|
|
722
|
+
align-items: start;
|
|
723
|
+
flex-direction: column;
|
|
724
|
+
flex-wrap: nowrap;
|
|
725
|
+
inline-size: fit-content;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* An empty group takes no room. An actions area built from a permission
|
|
730
|
+
* filter renders one often, and the empty box still eats a gap in the row
|
|
731
|
+
* that holds it — the defect `button-group` recorded when it found the same
|
|
732
|
+
* thing.
|
|
733
|
+
*/
|
|
734
|
+
[data-ui='tag'][data-part='group']:empty {
|
|
735
|
+
display: none;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* ── Forced colours ─────────────────────────────────────────────────────
|
|
740
|
+
*
|
|
741
|
+
* The one place a family may write its own rule. The theme maps every tone
|
|
742
|
+
* ground to `ButtonFace` or `Canvas` and every tone border to
|
|
743
|
+
* `ButtonBorder`, so a `solid`, a `soft` and an `outline` chip become the
|
|
744
|
+
* same rectangle and a chip whose edge was its fill has no edge at all.
|
|
745
|
+
* `currentColor` is the only paint left that still separates the chip from
|
|
746
|
+
* the page.
|
|
747
|
+
*
|
|
748
|
+
* The selected chip is the second case: its whole signal is a ground the
|
|
749
|
+
* system has replaced, so there it is drawn with the system's own selected
|
|
750
|
+
* pair instead.
|
|
751
|
+
*/
|
|
752
|
+
@media (forced-colors: active) {
|
|
753
|
+
[data-ui='tag'][data-part='root'] {
|
|
754
|
+
border-color: currentColor;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
[data-ui='tag'][data-part='root'][data-selected]:not([data-disabled]) {
|
|
758
|
+
background-color: Highlight;
|
|
759
|
+
color: HighlightText;
|
|
760
|
+
forced-color-adjust: none;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
[data-ui='tag'][data-part='root'][data-disabled] {
|
|
764
|
+
border-color: GrayText;
|
|
765
|
+
color: GrayText;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|