@slotted/styles 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/package.json +276 -3
- package/src/accordion/accordion.css +96 -0
- package/src/accordion/accordion.tokens.json +14 -0
- package/src/action-bar/action-bar.css +455 -0
- package/src/action-bar/action-bar.tokens.json +50 -0
- package/src/action-sheet/action-sheet.css +462 -0
- package/src/action-sheet/action-sheet.tokens.json +59 -0
- package/src/alert/alert.css +764 -0
- package/src/alert/alert.tokens.json +77 -0
- package/src/app-shell/app-shell.css +1899 -0
- package/src/app-shell/app-shell.tokens.json +88 -0
- package/src/aspect-ratio/aspect-ratio.css +131 -0
- package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
- package/src/attachment/attachment.css +906 -0
- package/src/attachment/attachment.tokens.json +85 -0
- package/src/avatar/avatar.css +598 -0
- package/src/avatar/avatar.tokens.json +64 -0
- package/src/avatar-group/avatar-group.css +268 -0
- package/src/avatar-group/avatar-group.tokens.json +16 -0
- package/src/badge/badge.css +462 -0
- package/src/badge/badge.tokens.json +58 -0
- package/src/breadcrumb/breadcrumb.css +441 -0
- package/src/breadcrumb/breadcrumb.tokens.json +50 -0
- package/src/button/button.css +754 -0
- package/src/button/button.tokens.json +72 -0
- package/src/button-group/button-group.css +455 -0
- package/src/button-group/button-group.tokens.json +11 -0
- package/src/calendar/calendar.css +846 -0
- package/src/calendar/calendar.tokens.json +67 -0
- package/src/card/card.css +602 -0
- package/src/card/card.tokens.json +68 -0
- package/src/carousel/carousel.css +860 -0
- package/src/carousel/carousel.tokens.json +62 -0
- package/src/cascader/cascader.css +1320 -0
- package/src/cascader/cascader.tokens.json +103 -0
- package/src/chart/chart.css +1473 -0
- package/src/chart/chart.tokens.json +107 -0
- package/src/checkbox/checkbox.css +1011 -0
- package/src/checkbox/checkbox.tokens.json +102 -0
- package/src/checkbox-group/checkbox-group.css +70 -0
- package/src/checkbox-group/checkbox-group.tokens.json +6 -0
- package/src/code-block/code-block.css +555 -0
- package/src/code-block/code-block.tokens.json +69 -0
- package/src/collapsible/collapsible.css +546 -0
- package/src/collapsible/collapsible.tokens.json +55 -0
- package/src/color-picker/color-picker.css +607 -0
- package/src/color-picker/color-picker.tokens.json +58 -0
- package/src/column-manager/column-manager.css +452 -0
- package/src/column-manager/column-manager.tokens.json +43 -0
- package/src/combobox/combobox.css +1048 -0
- package/src/combobox/combobox.tokens.json +112 -0
- package/src/command-palette/command-palette.css +1000 -0
- package/src/command-palette/command-palette.tokens.json +75 -0
- package/src/container/container.css +198 -0
- package/src/container/container.tokens.json +18 -0
- package/src/context-menu/context-menu.css +104 -0
- package/src/context-menu/context-menu.tokens.json +11 -0
- package/src/currency-field/currency-field.css +787 -0
- package/src/currency-field/currency-field.tokens.json +80 -0
- package/src/dashboard-grid/dashboard-grid.css +748 -0
- package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
- package/src/data-grid/data-grid.css +2484 -0
- package/src/data-grid/data-grid.tokens.json +100 -0
- package/src/data-list/data-list.css +455 -0
- package/src/data-list/data-list.tokens.json +35 -0
- package/src/date-field/date-field.css +560 -0
- package/src/date-field/date-field.tokens.json +80 -0
- package/src/date-picker/date-picker.css +420 -0
- package/src/date-picker/date-picker.tokens.json +49 -0
- package/src/date-range-picker/date-range-picker.css +983 -0
- package/src/date-range-picker/date-range-picker.tokens.json +109 -0
- package/src/datetime-field/datetime-field.css +850 -0
- package/src/datetime-field/datetime-field.tokens.json +91 -0
- package/src/datetime-picker/datetime-picker.css +843 -0
- package/src/datetime-picker/datetime-picker.tokens.json +78 -0
- package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
- package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
- package/src/description-list/description-list.css +675 -0
- package/src/description-list/description-list.tokens.json +66 -0
- package/src/detail-panel/detail-panel.css +329 -0
- package/src/detail-panel/detail-panel.tokens.json +33 -0
- package/src/dialog/dialog.css +968 -0
- package/src/dialog/dialog.tokens.json +66 -0
- package/src/divider/divider.css +131 -0
- package/src/divider/divider.tokens.json +18 -0
- package/src/drawer/drawer.css +1303 -0
- package/src/drawer/drawer.tokens.json +75 -0
- package/src/entity-picker/entity-picker.css +1367 -0
- package/src/entity-picker/entity-picker.tokens.json +118 -0
- package/src/event-calendar/event-calendar.css +2148 -0
- package/src/event-calendar/event-calendar.tokens.json +87 -0
- package/src/field/field.css +707 -0
- package/src/field/field.tokens.json +58 -0
- package/src/field-group/field-group.css +226 -0
- package/src/field-group/field-group.tokens.json +33 -0
- package/src/filter-bar/filter-bar.css +1306 -0
- package/src/filter-bar/filter-bar.tokens.json +78 -0
- package/src/form/form.css +218 -0
- package/src/form/form.tokens.json +32 -0
- package/src/fullscreen/fullscreen.css +376 -0
- package/src/fullscreen/fullscreen.tokens.json +50 -0
- package/src/grid/grid.css +173 -0
- package/src/grid/grid.tokens.json +20 -0
- package/src/highlight/highlight.css +135 -0
- package/src/highlight/highlight.tokens.json +16 -0
- package/src/hover-card/hover-card.css +93 -0
- package/src/hover-card/hover-card.tokens.json +17 -0
- package/src/icon/icon.css +136 -0
- package/src/icon/icon.tokens.json +14 -0
- package/src/image/image.css +449 -0
- package/src/image/image.tokens.json +27 -0
- package/src/import-export-center/import-export-center.css +1175 -0
- package/src/import-export-center/import-export-center.tokens.json +84 -0
- package/src/inline/inline.css +149 -0
- package/src/inline/inline.tokens.json +14 -0
- package/src/inline-message/inline-message.css +396 -0
- package/src/inline-message/inline-message.tokens.json +19 -0
- package/src/kbd/kbd.css +490 -0
- package/src/kbd/kbd.tokens.json +40 -0
- package/src/link/link.css +237 -0
- package/src/link/link.tokens.json +25 -0
- package/src/list/list.css +240 -0
- package/src/list/list.tokens.json +42 -0
- package/src/list-item/list-item.css +937 -0
- package/src/list-item/list-item.tokens.json +114 -0
- package/src/listbox/listbox.css +674 -0
- package/src/listbox/listbox.tokens.json +72 -0
- package/src/loading-overlay/loading-overlay.css +730 -0
- package/src/loading-overlay/loading-overlay.tokens.json +48 -0
- package/src/markdown/markdown.css +168 -0
- package/src/markdown/markdown.tokens.json +18 -0
- package/src/menu/menu.css +817 -0
- package/src/menu/menu.tokens.json +78 -0
- package/src/menubar/menubar.css +170 -0
- package/src/menubar/menubar.tokens.json +32 -0
- package/src/message/message.css +1453 -0
- package/src/message/message.tokens.json +85 -0
- package/src/message-scroller/message-scroller.css +371 -0
- package/src/message-scroller/message-scroller.tokens.json +47 -0
- package/src/multi-select/multi-select.css +1427 -0
- package/src/multi-select/multi-select.tokens.json +114 -0
- package/src/navigation-menu/navigation-menu.css +1029 -0
- package/src/navigation-menu/navigation-menu.tokens.json +70 -0
- package/src/notification-center/notification-center.css +856 -0
- package/src/notification-center/notification-center.tokens.json +84 -0
- package/src/number-field/number-field.css +794 -0
- package/src/number-field/number-field.tokens.json +80 -0
- package/src/otp-input/otp-input.css +525 -0
- package/src/otp-input/otp-input.tokens.json +69 -0
- package/src/page/page.css +179 -0
- package/src/page/page.tokens.json +20 -0
- package/src/page-header/page-header.css +1181 -0
- package/src/page-header/page-header.tokens.json +71 -0
- package/src/pagination/pagination.css +500 -0
- package/src/pagination/pagination.tokens.json +56 -0
- package/src/popover/popover.css +526 -0
- package/src/popover/popover.tokens.json +60 -0
- package/src/progress-indicator/progress-indicator.css +1584 -0
- package/src/progress-indicator/progress-indicator.tokens.json +50 -0
- package/src/prompt-composer/prompt-composer.css +680 -0
- package/src/prompt-composer/prompt-composer.tokens.json +99 -0
- package/src/prose/prose.css +733 -0
- package/src/prose/prose.tokens.json +79 -0
- package/src/radio-group/radio-group.css +778 -0
- package/src/radio-group/radio-group.tokens.json +103 -0
- package/src/rating/rating.css +1071 -0
- package/src/rating/rating.tokens.json +88 -0
- package/src/result-state/result-state.css +980 -0
- package/src/result-state/result-state.tokens.json +63 -0
- package/src/runtime-properties.mjs +321 -0
- package/src/saved-views/saved-views.css +394 -0
- package/src/saved-views/saved-views.tokens.json +41 -0
- package/src/scroll-area/scroll-area.css +481 -0
- package/src/scroll-area/scroll-area.tokens.json +15 -0
- package/src/section/section.css +177 -0
- package/src/section/section.tokens.json +39 -0
- package/src/segmented-control/segmented-control.css +564 -0
- package/src/segmented-control/segmented-control.tokens.json +67 -0
- package/src/select/select.css +1593 -0
- package/src/select/select.tokens.json +110 -0
- package/src/side-navigation/side-navigation.css +1096 -0
- package/src/side-navigation/side-navigation.tokens.json +87 -0
- package/src/skeleton/skeleton.css +431 -0
- package/src/skeleton/skeleton.tokens.json +29 -0
- package/src/slider/slider.css +792 -0
- package/src/slider/slider.tokens.json +75 -0
- package/src/sparkline/sparkline.css +282 -0
- package/src/sparkline/sparkline.tokens.json +45 -0
- package/src/spinner/spinner.css +224 -0
- package/src/spinner/spinner.tokens.json +8 -0
- package/src/split-button/split-button.css +253 -0
- package/src/split-button/split-button.tokens.json +12 -0
- package/src/splitter/splitter.css +336 -0
- package/src/splitter/splitter.tokens.json +24 -0
- package/src/stack/stack.css +128 -0
- package/src/stack/stack.tokens.json +14 -0
- package/src/stat-card/stat-card.css +641 -0
- package/src/stat-card/stat-card.tokens.json +95 -0
- package/src/status-indicator/status-indicator.css +481 -0
- package/src/status-indicator/status-indicator.tokens.json +38 -0
- package/src/stepper/stepper.css +629 -0
- package/src/stepper/stepper.tokens.json +72 -0
- package/src/switch/switch.css +703 -0
- package/src/switch/switch.tokens.json +75 -0
- package/src/table/table.css +1482 -0
- package/src/table/table.tokens.json +69 -0
- package/src/table-of-contents/table-of-contents.css +533 -0
- package/src/table-of-contents/table-of-contents.tokens.json +53 -0
- package/src/tabs/tabs.css +998 -0
- package/src/tabs/tabs.tokens.json +82 -0
- package/src/tag/tag.css +768 -0
- package/src/tag/tag.tokens.json +85 -0
- package/src/tags-input/tags-input.css +757 -0
- package/src/tags-input/tags-input.tokens.json +84 -0
- package/src/text-field/text-field.css +900 -0
- package/src/text-field/text-field.tokens.json +87 -0
- package/src/textarea/textarea.css +365 -0
- package/src/textarea/textarea.tokens.json +59 -0
- package/src/time-field/time-field.css +719 -0
- package/src/time-field/time-field.tokens.json +86 -0
- package/src/time-picker/time-picker.css +665 -0
- package/src/time-picker/time-picker.tokens.json +66 -0
- package/src/time-range-picker/time-range-picker.css +1287 -0
- package/src/time-range-picker/time-range-picker.tokens.json +134 -0
- package/src/timeline/timeline.css +1596 -0
- package/src/timeline/timeline.tokens.json +96 -0
- package/src/toast/toast.css +943 -0
- package/src/toast/toast.tokens.json +90 -0
- package/src/toggle/toggle.css +290 -0
- package/src/toggle/toggle.tokens.json +54 -0
- package/src/toggle-group/toggle-group.css +463 -0
- package/src/toggle-group/toggle-group.tokens.json +54 -0
- package/src/toolbar/toolbar.css +434 -0
- package/src/toolbar/toolbar.tokens.json +49 -0
- package/src/tooltip/tooltip.css +368 -0
- package/src/tooltip/tooltip.tokens.json +39 -0
- package/src/top-navigation/top-navigation.css +1287 -0
- package/src/top-navigation/top-navigation.tokens.json +91 -0
- package/src/tour/tour.css +680 -0
- package/src/tour/tour.tokens.json +67 -0
- package/src/transfer/transfer.css +571 -0
- package/src/transfer/transfer.tokens.json +49 -0
- package/src/tree/tree.css +1000 -0
- package/src/tree/tree.tokens.json +80 -0
- package/src/typography/typography.css +211 -0
- package/src/typography/typography.tokens.json +31 -0
- package/src/upload/upload.css +1706 -0
- package/src/upload/upload.tokens.json +123 -0
- package/src/visually-hidden/visually-hidden.css +52 -0
- package/src/visually-hidden/visually-hidden.tokens.json +1 -0
- package/src/wizard/wizard.css +740 -0
- package/src/wizard/wizard.tokens.json +63 -0
|
@@ -0,0 +1,1000 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* A hierarchy the reader opens, walks and chooses from.
|
|
4
|
+
*
|
|
5
|
+
* ┌─ root ─ the query container ─ the frame ───────────────────────┐
|
|
6
|
+
* │ ┌─ canvas ─ role="tree" ─ scrolls ─ one tab stop ─────────┐ │
|
|
7
|
+
* │ │ ┌─ node ─ role="treeitem" ────────────────────────┐ │ │
|
|
8
|
+
* │ │ │ ┌─ row ─ the band, the target, the indent ─┐ │ │ │
|
|
9
|
+
* │ │ │ │ guide │ expander │ indicator │ icon │ │ │ │
|
|
10
|
+
* │ │ │ │ label │ meta │ loader │ actions │ │ │ │
|
|
11
|
+
* │ │ │ └───────────────────────────────────────────┘ │ │ │
|
|
12
|
+
* │ │ │ ┌─ group ─ role="group" ─ only while open ──┐ │ │ │
|
|
13
|
+
* │ │ │ │ node ▸ … │ │ │ │
|
|
14
|
+
* │ │ │ └───────────────────────────────────────────┘ │ │ │
|
|
15
|
+
* │ │ └──────────────────────────────────────────────────┘ │ │
|
|
16
|
+
* │ │ empty │ │
|
|
17
|
+
* │ └──────────────────────────────────────────────────────────┘ │
|
|
18
|
+
* └─────────────────────────────────────────────────────────────────┘
|
|
19
|
+
*
|
|
20
|
+
* ── Why the indent is on the row and not on the group ───────────────
|
|
21
|
+
*
|
|
22
|
+
* The band a hovered or selected row paints spans the whole width of the
|
|
23
|
+
* tree. Indenting the group — which is what a nested list does on its own —
|
|
24
|
+
* starts that band at the indent, and a selected file three levels down then
|
|
25
|
+
* paints a rectangle that begins in the middle of the page. So the group
|
|
26
|
+
* carries no inset at all, and the row states its own with
|
|
27
|
+
* `padding-inline-start`, from a depth the family writes per node.
|
|
28
|
+
*
|
|
29
|
+
* ── Why the guide is one element ────────────────────────────────────
|
|
30
|
+
*
|
|
31
|
+
* A line per ancestor level is a line per ancestor element, and depth twenty
|
|
32
|
+
* is then twenty elements on every row. One element, sized `depth × step`,
|
|
33
|
+
* with a repeating gradient at the step, draws the same picture at any depth
|
|
34
|
+
* for one box. The cost is that no elbow can be drawn at a last child, which
|
|
35
|
+
* none of the surveyed implementations draws either.
|
|
36
|
+
*
|
|
37
|
+
* ── Why the selected band has no radius ─────────────────────────────
|
|
38
|
+
*
|
|
39
|
+
* With a cascade, a chosen folder and its children are selected together and
|
|
40
|
+
* their bands are adjacent. A radius on each one meets its neighbour at a
|
|
41
|
+
* waist and the column reads as a stack of pills rather than as one block —
|
|
42
|
+
* the defect `selection-block.test.mjs` holds `listbox` to. A tree cannot fix
|
|
43
|
+
* it the way a listbox does, because two adjacent selected rows are often a
|
|
44
|
+
* parent and a child and therefore in two different lists, where `:has(+ …)`
|
|
45
|
+
* cannot reach. A square band has no waist to fix.
|
|
46
|
+
*
|
|
47
|
+
* ── Density ─────────────────────────────────────────────────────────
|
|
48
|
+
*
|
|
49
|
+
* A row is a control, so its height, inset, type, glyph and gap all read
|
|
50
|
+
* control geometry. A dense tree holds more rows and is the same component;
|
|
51
|
+
* only the frame's own inset, radius and shadow come off the space, radius
|
|
52
|
+
* and shadow scales.
|
|
53
|
+
*/
|
|
54
|
+
[data-ui='tree'] {
|
|
55
|
+
--_surface: var(--slotted-tree-surface, var(--slotted-surface, #ffffff));
|
|
56
|
+
--_text: var(--slotted-tree-text, var(--slotted-text, #0f172a));
|
|
57
|
+
--_muted: var(--slotted-tree-text-muted, var(--slotted-text-muted, #5b6b7f));
|
|
58
|
+
--_border-color: var(--slotted-tree-border-color, var(--slotted-control-border-color));
|
|
59
|
+
--_border-width: var(--slotted-border-width-thin, 1px);
|
|
60
|
+
--_radius: var(--slotted-tree-radius, var(--slotted-radius-md, 6px));
|
|
61
|
+
--_shadow: var(--slotted-tree-shadow, var(--slotted-control-shadow));
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* One quiet ground for hover and for the row the keyboard is on, told apart
|
|
65
|
+
* by the ring rather than by two greys. It is the rule `listbox` settled:
|
|
66
|
+
* a second, darker grey made the pointer's feedback shout louder than the
|
|
67
|
+
* keyboard's position.
|
|
68
|
+
*/
|
|
69
|
+
--_highlight: var(--slotted-tree-highlight, var(--slotted-tone-secondary-subtle-hover));
|
|
70
|
+
--_highlight-active: var(
|
|
71
|
+
--slotted-tree-highlight-active,
|
|
72
|
+
var(--slotted-tone-secondary-subtle-active)
|
|
73
|
+
);
|
|
74
|
+
--_selected-surface: var(--slotted-tree-selected-surface, var(--slotted-tone-accent-surface));
|
|
75
|
+
--_selected-text: var(--slotted-tree-selected-text, var(--slotted-tone-accent-text));
|
|
76
|
+
--_selected-edge: var(--slotted-tree-selected-edge, var(--slotted-tone-accent-border));
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The line that says which parent a row belongs to.
|
|
80
|
+
*
|
|
81
|
+
* Measured against the surface it is drawn on: the subtle step alone is
|
|
82
|
+
* 1.23:1 in `light` and 1.25:1 in `dark`, which is a line a reader has to
|
|
83
|
+
* look for; the strong step is 3.59:1 and 3.84:1, which is a separator's
|
|
84
|
+
* weight repeated once per level and reads as a table of columns. The
|
|
85
|
+
* guide is neither — it is a redundant aid, because the indent and
|
|
86
|
+
* `aria-level` already carry the hierarchy — so it wants to be seen at a
|
|
87
|
+
* glance and to stay under the text.
|
|
88
|
+
*
|
|
89
|
+
* Six parts of the strong step to four of the subtle lands between them:
|
|
90
|
+
* `#a1aebd` at 2.26:1 in `light` and `#525258` at 2.39:1 in `dark`,
|
|
91
|
+
* measured on the built page. The dark scheme takes the higher of the two
|
|
92
|
+
* on purpose — a thin light line on a dark ground reads weaker than the
|
|
93
|
+
* same ratio does on white.
|
|
94
|
+
*
|
|
95
|
+
* Mixing the two ends of the scale rather than mixing one end into
|
|
96
|
+
* transparency is what keeps `high-contrast` right: there both ends are
|
|
97
|
+
* black, so the mix is black, the line stays at 21:1, and no rule has to
|
|
98
|
+
* read the scheme.
|
|
99
|
+
*/
|
|
100
|
+
--_guide-color: var(
|
|
101
|
+
--slotted-tree-guide-color,
|
|
102
|
+
color-mix(in oklab, var(--slotted-border-strong) 60%, var(--slotted-border-subtle))
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* One step of depth, stated from the glyph rather than taken from the space
|
|
107
|
+
* scale.
|
|
108
|
+
*
|
|
109
|
+
* What a reader sees on a row is the distance from its deepest guide line
|
|
110
|
+
* to its own chevron, and that distance is `step - glyph / 2`, because the
|
|
111
|
+
* line sits on the centre of the chevron one level up. With the step read
|
|
112
|
+
* from the space scale and the glyph from the control scale, the two moved
|
|
113
|
+
* apart: measured on the built page, five pixels at `sm`, eight at `md`,
|
|
114
|
+
* eleven at `lg`, and nought at 240 pixels, where the line met the chevron.
|
|
115
|
+
* The tree looked tighter at one size than at another for a reason nobody
|
|
116
|
+
* could name.
|
|
117
|
+
*
|
|
118
|
+
* Half a glyph plus a fixed step of the space scale holds it at eight
|
|
119
|
+
* pixels everywhere, and leaves `md` at exactly the sixteen it already was.
|
|
120
|
+
*/
|
|
121
|
+
--_indent: var(
|
|
122
|
+
--slotted-tree-indent,
|
|
123
|
+
calc(var(--_icon-size) / 2 + var(--slotted-space-4, 0.5rem))
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
--_inset-block: var(--slotted-tree-padding-block, var(--slotted-space-2, 0.25rem));
|
|
127
|
+
--_inset-inline: var(--slotted-tree-padding-inline, var(--slotted-space-2, 0.25rem));
|
|
128
|
+
--_row-inset: var(--slotted-control-padding-inline-md, 0.8125rem);
|
|
129
|
+
--_row-height: var(--slotted-control-height-md, 34px);
|
|
130
|
+
--_font-size: var(--slotted-control-font-size-md, 13px);
|
|
131
|
+
--_secondary-font-size: var(--slotted-control-font-size-sm, 12px);
|
|
132
|
+
--_icon-size: var(--slotted-control-icon-size-md, 16px);
|
|
133
|
+
--_gap: var(--slotted-control-gap-md, 0.5rem);
|
|
134
|
+
--_check-size: var(--slotted-selection-size-md, 16px);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* How many rows tall the box is. A tree with no bound is a tree that pushes
|
|
138
|
+
* the page down as its branches open, and a windowed one has no viewport at
|
|
139
|
+
* all.
|
|
140
|
+
*/
|
|
141
|
+
--_rows: var(--slotted-tree-rows, 12);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The cap. Measure belongs to `container`, so the family offers no axis for
|
|
145
|
+
* it and still has to stop a `max-content` row from setting one label the
|
|
146
|
+
* width of the page.
|
|
147
|
+
*/
|
|
148
|
+
--_measure: var(--slotted-tree-measure, 28rem);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* `--slotted-tree-depth` is deliberately not aliased here.
|
|
152
|
+
*
|
|
153
|
+
* A custom property composed on an ancestor resolves its `var()` calls
|
|
154
|
+
* there: `--_depth: var(--slotted-tree-depth, 0)` written on this element
|
|
155
|
+
* would substitute the root's own value — nothing, so nought — and every
|
|
156
|
+
* row would inherit that one number however deep its node is. The family
|
|
157
|
+
* writes the depth per node and the two rules that need it read it
|
|
158
|
+
* directly. It is the same trap `--slotted-control-shadow-focus-geometry`
|
|
159
|
+
* is shaped around, and `docs/token-foundation.md` records that one.
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
box-sizing: border-box;
|
|
163
|
+
color: var(--_text);
|
|
164
|
+
/**
|
|
165
|
+
* The query container is the root and the tracks are one element in:
|
|
166
|
+
* `container-type: inline-size` makes an element a query container for its
|
|
167
|
+
* descendants and not for itself, and what answers the width here is the
|
|
168
|
+
* indent the rows inside carry.
|
|
169
|
+
*/
|
|
170
|
+
container-name: slotted-tree;
|
|
171
|
+
container-type: inline-size;
|
|
172
|
+
display: block;
|
|
173
|
+
font-family: var(--slotted-font-family-sans);
|
|
174
|
+
font-size: var(--_font-size);
|
|
175
|
+
inline-size: 100%;
|
|
176
|
+
max-inline-size: var(--_measure);
|
|
177
|
+
text-align: start;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
[data-ui='tree'][data-size='sm'] {
|
|
181
|
+
--_row-inset: var(--slotted-control-padding-inline-sm, 0.625rem);
|
|
182
|
+
--_row-height: var(--slotted-control-height-sm, 30px);
|
|
183
|
+
--_font-size: var(--slotted-control-font-size-sm, 12px);
|
|
184
|
+
--_secondary-font-size: var(--slotted-font-size-xs, 0.75rem);
|
|
185
|
+
--_icon-size: var(--slotted-control-icon-size-sm, 14px);
|
|
186
|
+
--_gap: var(--slotted-control-gap-sm, 0.375rem);
|
|
187
|
+
--_check-size: var(--slotted-selection-size-sm, 14px);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
[data-ui='tree'][data-size='lg'] {
|
|
191
|
+
--_row-inset: var(--slotted-control-padding-inline-lg, 1rem);
|
|
192
|
+
--_row-height: var(--slotted-control-height-lg, 38px);
|
|
193
|
+
--_font-size: var(--slotted-control-font-size-lg, 14px);
|
|
194
|
+
--_secondary-font-size: var(--slotted-control-font-size-md, 13px);
|
|
195
|
+
--_icon-size: var(--slotted-control-icon-size-lg, 18px);
|
|
196
|
+
--_gap: var(--slotted-control-gap-lg, 0.5rem);
|
|
197
|
+
--_check-size: var(--slotted-selection-size-lg, 18px);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* `framed` is the standalone control; `plain` is what a tree renders as
|
|
202
|
+
* inside a panel, a drawer or a page region that already has an edge.
|
|
203
|
+
*/
|
|
204
|
+
[data-ui='tree'][data-variant='framed'] {
|
|
205
|
+
background-color: var(--_surface);
|
|
206
|
+
border: var(--_border-width) solid var(--_border-color);
|
|
207
|
+
border-radius: var(--_radius);
|
|
208
|
+
box-shadow: var(--_shadow);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
[data-ui='tree'] [data-part='canvas'] {
|
|
212
|
+
/**
|
|
213
|
+
* The block cap is stated rather than the height: a tree of four branches
|
|
214
|
+
* is four rows tall, and one of four hundred stops at `rows` and scrolls.
|
|
215
|
+
* The inset is added so the last row is not cut in half by the padding the
|
|
216
|
+
* frame reserved for itself.
|
|
217
|
+
*/
|
|
218
|
+
max-block-size: calc(var(--_rows) * var(--_row-height) + 2 * var(--_inset-block));
|
|
219
|
+
outline: none;
|
|
220
|
+
overflow: auto;
|
|
221
|
+
padding-block: var(--_inset-block);
|
|
222
|
+
padding-inline: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
[data-ui='tree'] :is([data-part='canvas'], [data-part='group']) {
|
|
226
|
+
list-style: none;
|
|
227
|
+
margin-block: 0;
|
|
228
|
+
margin-inline: 0;
|
|
229
|
+
padding-inline: 0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* The group carries no inset: the row states the whole indent, so the band
|
|
234
|
+
* can span the tree's full width at every level.
|
|
235
|
+
*/
|
|
236
|
+
[data-ui='tree'] [data-part='group'] {
|
|
237
|
+
padding-block: 0;
|
|
238
|
+
padding-inline: 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* A node states its own box rather than inheriting one.
|
|
243
|
+
*
|
|
244
|
+
* The family is built on `ul` and `li`, so it is exposed to whatever reset
|
|
245
|
+
* the page around it has: the reference page gave every `li` after the first
|
|
246
|
+
* seven pixels of margin, and the guide line — which spans one row — broke
|
|
247
|
+
* into segments at each of them. The page was fixed where the page is, and a
|
|
248
|
+
* family that only works under one reset is a family waiting for the next
|
|
249
|
+
* one.
|
|
250
|
+
*/
|
|
251
|
+
[data-ui='tree'] [data-part='node'] {
|
|
252
|
+
display: block;
|
|
253
|
+
margin-block: 0;
|
|
254
|
+
margin-inline: 0;
|
|
255
|
+
padding-block: 0;
|
|
256
|
+
padding-inline: 0;
|
|
257
|
+
/**
|
|
258
|
+
* The node holds focus and the row draws the ring, so the node draws none
|
|
259
|
+
* of its own. Left to the user agent it drew one anyway — Chrome's is a
|
|
260
|
+
* white line inside a dark one — and a focused branch showed two rings at
|
|
261
|
+
* once: the browser's around the whole subtree, and the family's inside it
|
|
262
|
+
* around the row. Suppressing it is only safe because the row replaces it,
|
|
263
|
+
* which is the condition the rule below satisfies.
|
|
264
|
+
*/
|
|
265
|
+
outline: none;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
[data-ui='tree'] [data-part='row'] {
|
|
269
|
+
align-items: center;
|
|
270
|
+
background-color: transparent;
|
|
271
|
+
color: inherit;
|
|
272
|
+
/**
|
|
273
|
+
* ── The hand, and where the library's two answers meet ───────────────
|
|
274
|
+
*
|
|
275
|
+
* `menu`, `menubar` and `listbox` keep the arrow: an option is one of a set
|
|
276
|
+
* the reader picks from, and the set is the control. `button`, `select` and
|
|
277
|
+
* `combobox` draw the hand, and SL11 records why the arrow was wrong for a
|
|
278
|
+
* trigger — the one control in a form that said nothing happens when it is
|
|
279
|
+
* pressed.
|
|
280
|
+
*
|
|
281
|
+
* A tree row is on both sides of that line. It is an option in a set, and
|
|
282
|
+
* under the default `expandOn="row"` it is also the disclosure that opens
|
|
283
|
+
* its own branch. Drawing the arrow on the element that opens the branch
|
|
284
|
+
* would be the defect SL11 fixed, and drawing two cursors inside one tree —
|
|
285
|
+
* the hand on a branch, the arrow on a leaf that selects — is worse than
|
|
286
|
+
* either answer on its own, which is what this stylesheet did until now.
|
|
287
|
+
*
|
|
288
|
+
* So: the hand on every row that does something, and the arrow on a row
|
|
289
|
+
* that does nothing, which is a leaf in a tree that selects nothing.
|
|
290
|
+
*/
|
|
291
|
+
cursor: pointer;
|
|
292
|
+
display: flex;
|
|
293
|
+
/**
|
|
294
|
+
* No `gap`. A gap is drawn between two cells even when one of them is
|
|
295
|
+
* empty, so a tree whose nodes carry no icon opened with a gutter down its
|
|
296
|
+
* start edge and a tree with no mark opened with two. Each optional cell
|
|
297
|
+
* carries its own margin instead, and a cell nothing occupies costs
|
|
298
|
+
* nothing — which is `menu`'s rule and `listbox`'s, and the defect the
|
|
299
|
+
* visual gate found here.
|
|
300
|
+
*/
|
|
301
|
+
min-block-size: var(--_row-height);
|
|
302
|
+
outline: none;
|
|
303
|
+
padding-block: 0;
|
|
304
|
+
/**
|
|
305
|
+
* Every level of depth, plus the frame's own inset, before the first cell.
|
|
306
|
+
* The end inset is the frame's alone: a row is as deep as its node and as
|
|
307
|
+
* wide as the tree.
|
|
308
|
+
*/
|
|
309
|
+
padding-inline: calc(var(--_inset-inline) + var(--slotted-tree-depth, 0) * var(--_indent))
|
|
310
|
+
var(--_row-inset);
|
|
311
|
+
position: relative;
|
|
312
|
+
transition:
|
|
313
|
+
background-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
|
|
314
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
|
|
315
|
+
color var(--slotted-control-transition-duration, var(--slotted-duration-short))
|
|
316
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
317
|
+
user-select: none;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* One element, `depth × step` wide, one line per ancestor level, drawn as a
|
|
322
|
+
* gradient that repeats at the step.
|
|
323
|
+
*
|
|
324
|
+
* ── Where the line sits ──────────────────────────────────────────────
|
|
325
|
+
*
|
|
326
|
+
* Under the centre of the chevron of the level above, which is half a glyph
|
|
327
|
+
* from the start of that level's cell — not half a step. The two agree only
|
|
328
|
+
* at `md`, where the step and the glyph are both sixteen pixels; at `sm` and
|
|
329
|
+
* `lg` they differ by a pixel, and under the narrow container queries, where
|
|
330
|
+
* the step drops to twelve and to eight while the glyph does not, by two and
|
|
331
|
+
* by four. Every line was off its chevron at five of the nine combinations.
|
|
332
|
+
*
|
|
333
|
+
* ── Why the line does not stop at the last child ─────────────────────
|
|
334
|
+
*
|
|
335
|
+
* It did, at half the row's height, which is where an elbow would turn. With
|
|
336
|
+
* no elbow to turn into, a chain of only children — every one of them a last
|
|
337
|
+
* child — drew a staircase of short segments with a gap under each, and the
|
|
338
|
+
* picture read as broken rather than as ended. A straight line through every
|
|
339
|
+
* row is what `VS Code`, Primer and Carbon all draw, and what the reviewer
|
|
340
|
+
* asked for at the visual gate.
|
|
341
|
+
*/
|
|
342
|
+
[data-ui='tree'] [data-part='guide'] {
|
|
343
|
+
background-image: repeating-linear-gradient(
|
|
344
|
+
to right,
|
|
345
|
+
var(--_guide-color) 0 var(--_border-width),
|
|
346
|
+
transparent var(--_border-width) var(--_indent)
|
|
347
|
+
);
|
|
348
|
+
inline-size: calc(var(--slotted-tree-depth, 0) * var(--_indent));
|
|
349
|
+
inset-block: 0;
|
|
350
|
+
inset-inline-start: calc(var(--_inset-inline) + var(--_icon-size) / 2);
|
|
351
|
+
pointer-events: none;
|
|
352
|
+
position: absolute;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
[data-ui='tree'] [data-part='guide']:dir(rtl) {
|
|
356
|
+
background-image: repeating-linear-gradient(
|
|
357
|
+
to left,
|
|
358
|
+
var(--_guide-color) 0 var(--_border-width),
|
|
359
|
+
transparent var(--_border-width) var(--_indent)
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
[data-ui='tree'][data-guides='false'] [data-part='guide'] {
|
|
364
|
+
background-image: none;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The chevron: the `Glyph` the binding draws inside this box for a branch.
|
|
369
|
+
* One glyph turned, rather than two glyphs swapped, so the two states read
|
|
370
|
+
* as one control moving. A leaf keeps the box and the binding draws nothing
|
|
371
|
+
* in it, which is what holds every label in one column whatever its node is.
|
|
372
|
+
*/
|
|
373
|
+
[data-ui='tree'] [data-part='expander'] {
|
|
374
|
+
/**
|
|
375
|
+
* The glyph is the icon size and never the box: under `expandOn="expander"`
|
|
376
|
+
* the box grows by padding to the target minimum, and the `icon` box stays
|
|
377
|
+
* in the content box at the size of the icons beside it.
|
|
378
|
+
*/
|
|
379
|
+
--slotted-icon-size: var(--_icon-size);
|
|
380
|
+
block-size: var(--_icon-size);
|
|
381
|
+
color: var(--_muted);
|
|
382
|
+
display: flex;
|
|
383
|
+
flex: none;
|
|
384
|
+
inline-size: var(--_icon-size);
|
|
385
|
+
/**
|
|
386
|
+
* The hit area the artwork does not have is drawn with padding taken back
|
|
387
|
+
* as a negative margin, rather than with a pseudo-element hanging out of
|
|
388
|
+
* the box: `overflow-clip-margin` does not contain what hangs out, which is
|
|
389
|
+
* the measurement `docs/token-foundation.md` records.
|
|
390
|
+
*/
|
|
391
|
+
margin-inline-end: var(--_gap);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
[data-ui='tree'] [data-part='expander'] > [data-ui='icon'] {
|
|
395
|
+
transition: rotate var(--slotted-control-transition-duration, var(--slotted-duration-short))
|
|
396
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
[data-ui='tree'] [data-part='expander']:dir(rtl) > [data-ui='icon'] {
|
|
400
|
+
rotate: 180deg;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
[data-ui='tree']
|
|
404
|
+
[data-part='node'][data-expanded]
|
|
405
|
+
> [data-part='row']
|
|
406
|
+
[data-part='expander']
|
|
407
|
+
> [data-ui='icon'] {
|
|
408
|
+
rotate: 90deg;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* The chevron is the target under `expandOn="expander"`, and the whole row is
|
|
413
|
+
* the target otherwise. Under the first the box is grown to the WCAG minimum
|
|
414
|
+
* without the artwork growing, and the growth is taken back so no label moves.
|
|
415
|
+
*/
|
|
416
|
+
[data-ui='tree'][data-expand-on='expander']
|
|
417
|
+
[data-part='node'][data-branch]
|
|
418
|
+
> [data-part='row']
|
|
419
|
+
[data-part='expander'] {
|
|
420
|
+
box-sizing: content-box;
|
|
421
|
+
cursor: pointer;
|
|
422
|
+
margin-block: calc((var(--slotted-target-min, 24px) - var(--_icon-size)) / -2);
|
|
423
|
+
/**
|
|
424
|
+
* The start is pulled back by exactly what the padding adds, so the artwork
|
|
425
|
+
* does not move off the guide line under it. The end keeps a real gap
|
|
426
|
+
* instead of the whole one: taking the growth off both sides left the
|
|
427
|
+
* chevron and the box touching, and the pair read as one glyph.
|
|
428
|
+
*/
|
|
429
|
+
margin-inline-end: calc(
|
|
430
|
+
var(--_gap) - (var(--slotted-target-min, 24px) - var(--_icon-size)) / 2
|
|
431
|
+
);
|
|
432
|
+
margin-inline-start: calc((var(--slotted-target-min, 24px) - var(--_icon-size)) / -2);
|
|
433
|
+
padding-block: calc((var(--slotted-target-min, 24px) - var(--_icon-size)) / 2);
|
|
434
|
+
padding-inline: calc((var(--slotted-target-min, 24px) - var(--_icon-size)) / 2);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* A row that does nothing takes the arrow back. With nothing to select, a
|
|
439
|
+
* leaf is text; and with the chevron as the only target, no row is pressed at
|
|
440
|
+
* all.
|
|
441
|
+
*/
|
|
442
|
+
[data-ui='tree'][data-selection='none'][data-expand-on='expander'] [data-part='row'],
|
|
443
|
+
[data-ui='tree'][data-selection='none']
|
|
444
|
+
[data-part='node']:not([data-branch])
|
|
445
|
+
> [data-part='row'] {
|
|
446
|
+
cursor: default;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* A tree the reader may read and not move keeps the arrow throughout, as
|
|
451
|
+
* `listbox` does with the same word.
|
|
452
|
+
*/
|
|
453
|
+
[data-ui='tree'][data-readonly] [data-part='row'] {
|
|
454
|
+
cursor: default;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* ── The box, and why `highlight` has none ──────────────────────────────
|
|
459
|
+
*
|
|
460
|
+
* `highlight` says the selection with the row's ground and its ink, and
|
|
461
|
+
* draws no mark at all. A mark needs a cell, a cell that is empty on every
|
|
462
|
+
* unchosen row is a gutter down the start edge of the whole tree, and a tree
|
|
463
|
+
* already spends one cell on the chevron and one per level on the indent.
|
|
464
|
+
* Every surveyed implementation that highlights — Primer, Carbon, the APG's
|
|
465
|
+
* own examples — draws no mark either, and under forced colours the row takes
|
|
466
|
+
* `Highlight` and `HighlightText`, which is the system's own selection rather
|
|
467
|
+
* than a colour of ours. `listbox` keeps its check because a flat list has
|
|
468
|
+
* one cell to spare and no indent; this is where the two families part, and
|
|
469
|
+
* the reason is the indent.
|
|
470
|
+
*
|
|
471
|
+
* A tree that wants a mark asks for `checkbox`, and then the mark is a box
|
|
472
|
+
* the reader can press.
|
|
473
|
+
*
|
|
474
|
+
* ── Why the box is the one `checkbox` draws ────────────────────────────
|
|
475
|
+
*
|
|
476
|
+
* Same square from the selection scale, same medium edge in the strong
|
|
477
|
+
* border colour, same smallest radius, same solid ground when chosen, and the
|
|
478
|
+
* same mark: a whole two pixels of clearance on every side, at every step,
|
|
479
|
+
* revealed by a clip that opens along the stroke rather than by a scale that
|
|
480
|
+
* grows out of the middle. The clearance is a whole number and not a
|
|
481
|
+
* fraction for the reason `checkbox` states at length — a fraction of a
|
|
482
|
+
* sixteen-pixel box rasterises the mark and the square onto different
|
|
483
|
+
* subpixels — and the two families are held together by
|
|
484
|
+
* `tree.styles.test.mjs`, which reads `checkbox.css` and compares them.
|
|
485
|
+
*/
|
|
486
|
+
[data-ui='tree'] [data-part='indicator'] {
|
|
487
|
+
--_mark-inset: var(--slotted-tree-mark-inset, 2px);
|
|
488
|
+
--_check-border: var(--slotted-border-width-medium, 1.5px);
|
|
489
|
+
--_mark-size: calc(var(--_check-size) - 2 * var(--_mark-inset));
|
|
490
|
+
--slotted-icon-size: var(--_mark-size);
|
|
491
|
+
|
|
492
|
+
background-color: var(--_surface);
|
|
493
|
+
block-size: var(--_check-size);
|
|
494
|
+
border: var(--_check-border) solid var(--slotted-border-strong);
|
|
495
|
+
border-radius: var(--slotted-radius-xs, 2px);
|
|
496
|
+
box-sizing: border-box;
|
|
497
|
+
cursor: pointer;
|
|
498
|
+
flex: none;
|
|
499
|
+
inline-size: var(--_check-size);
|
|
500
|
+
margin-inline-end: var(--_gap);
|
|
501
|
+
position: relative;
|
|
502
|
+
transition:
|
|
503
|
+
background-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
|
|
504
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
|
|
505
|
+
border-color var(--slotted-control-transition-duration, var(--slotted-duration-short))
|
|
506
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* The mark is the `Glyph` the binding draws inside the box — the check, or
|
|
511
|
+
* the dash while the node is indeterminate — rather than a second part, so a
|
|
512
|
+
* node stays one part in the DOM. Its `icon` box is placed against the
|
|
513
|
+
* border box and not the content box: `2px - 1.5px` from the padding edge is
|
|
514
|
+
* two whole pixels from the outside of the square, which is where `checkbox`
|
|
515
|
+
* puts its own.
|
|
516
|
+
*/
|
|
517
|
+
[data-ui='tree'] [data-part='indicator'] > [data-ui='icon'] {
|
|
518
|
+
/* Physical on purpose: a check is not mirrored in a right-to-left row, so
|
|
519
|
+
neither is the hand that draws it. `checkbox` states the same. */
|
|
520
|
+
clip-path: inset(0% 100% 0% 0%);
|
|
521
|
+
color: var(--slotted-tone-accent-on-solid);
|
|
522
|
+
inset-block-start: calc(var(--_mark-inset) - var(--_check-border));
|
|
523
|
+
inset-inline-start: calc(var(--_mark-inset) - var(--_check-border));
|
|
524
|
+
opacity: 0;
|
|
525
|
+
pointer-events: none;
|
|
526
|
+
position: absolute;
|
|
527
|
+
transition:
|
|
528
|
+
clip-path var(--slotted-duration-medium)
|
|
529
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard)),
|
|
530
|
+
opacity var(--slotted-duration-medium)
|
|
531
|
+
var(--slotted-control-transition-easing, var(--slotted-easing-standard));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
[data-ui='tree']
|
|
535
|
+
[data-part='node']:is([data-selected], [data-indeterminate])
|
|
536
|
+
> [data-part='row']
|
|
537
|
+
[data-part='indicator'] {
|
|
538
|
+
background-color: var(--slotted-tone-accent-solid);
|
|
539
|
+
border-color: var(--slotted-tone-accent-solid);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
[data-ui='tree']
|
|
543
|
+
[data-part='node']:is([data-selected], [data-indeterminate])
|
|
544
|
+
> [data-part='row']
|
|
545
|
+
[data-part='indicator']
|
|
546
|
+
> [data-ui='icon'] {
|
|
547
|
+
clip-path: inset(0% 0% 0% 0%);
|
|
548
|
+
opacity: 1;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
[data-ui='tree'] [data-part='node'][data-disabled] > [data-part='row'] [data-part='indicator'] {
|
|
552
|
+
background-color: var(--slotted-disabled-background, Canvas);
|
|
553
|
+
border-color: var(--slotted-disabled-border, GrayText);
|
|
554
|
+
cursor: not-allowed;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Only the box mode draws a cell. `highlight` and `none` render no indicator
|
|
559
|
+
* at all, and the rule is written so a consumer who leaves the element in the
|
|
560
|
+
* markup still gets the tree the axis promises.
|
|
561
|
+
*/
|
|
562
|
+
[data-ui='tree']:is([data-indicator='highlight'], [data-indicator='none'])
|
|
563
|
+
[data-part='indicator'] {
|
|
564
|
+
display: none;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* The node's own picture, which the consumer supplies. The family owns no
|
|
569
|
+
* folder glyph: a folder is content, and the glyph scale holds none.
|
|
570
|
+
*/
|
|
571
|
+
[data-ui='tree'] [data-part='icon'] {
|
|
572
|
+
block-size: var(--_icon-size);
|
|
573
|
+
color: var(--_muted);
|
|
574
|
+
flex: none;
|
|
575
|
+
inline-size: var(--_icon-size);
|
|
576
|
+
margin-inline-end: var(--_gap);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* A tree where some nodes carry a picture and others do not keeps every name
|
|
581
|
+
* in one column: a row with no icon opens the same cell the icon would have
|
|
582
|
+
* taken. Primer asks the consumer to pass a visual on every item or to accept
|
|
583
|
+
* two columns of names; the fact is one the tree can read for itself.
|
|
584
|
+
*/
|
|
585
|
+
[data-ui='tree'][data-part='root']:has([data-part='icon'])
|
|
586
|
+
[data-part='row']:not(:has([data-part='icon']))
|
|
587
|
+
[data-part='label'] {
|
|
588
|
+
margin-inline-start: calc(var(--_icon-size) + var(--_gap));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* The three parts that hold the consumer's own words take their direction
|
|
593
|
+
* from those words rather than from the document.
|
|
594
|
+
*
|
|
595
|
+
* `unicode-bidi: plaintext` reads the first strong character and sets the
|
|
596
|
+
* base direction from it, which is what a file tree needs and what the
|
|
597
|
+
* harness showed: in a right-to-left document an English `4 kB` was laid out
|
|
598
|
+
* as `kB 4`, and `“invoices”` had its closing quote moved to the front.
|
|
599
|
+
* `isolate` does not fix either — it gives the span its own context and still
|
|
600
|
+
* takes the base direction from the document. A node's name, its second line
|
|
601
|
+
* and its count are data of unknown direction, and each one is now its own
|
|
602
|
+
* paragraph.
|
|
603
|
+
*/
|
|
604
|
+
[data-ui='tree']
|
|
605
|
+
:is([data-part='label'], [data-part='description'], [data-part='meta'], [data-part='empty']) {
|
|
606
|
+
unicode-bidi: plaintext;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* The label shrinks to its own words rather than growing to the row.
|
|
611
|
+
*
|
|
612
|
+
* A label that took the free space put its text at the far edge of that box
|
|
613
|
+
* once `unicode-bidi: plaintext` had given it its own direction: in a
|
|
614
|
+
* right-to-left tree an English name sat against the opposite edge from the
|
|
615
|
+
* indent that placed it. Shrink-wrapping the label and pushing the trailing
|
|
616
|
+
* cells to the end with an automatic margin puts every name against the
|
|
617
|
+
* reader's own start edge in both directions, and leaves the truncation
|
|
618
|
+
* where it was.
|
|
619
|
+
*/
|
|
620
|
+
[data-ui='tree'] [data-part='label'] {
|
|
621
|
+
flex: 0 1 auto;
|
|
622
|
+
line-height: var(--slotted-line-height-sm, 1.45);
|
|
623
|
+
/**
|
|
624
|
+
* The one part that gives way. A label that is one unbroken token truncates
|
|
625
|
+
* and stays whole in the DOM, which is the library's standing decision on
|
|
626
|
+
* truncation.
|
|
627
|
+
*/
|
|
628
|
+
min-inline-size: 0;
|
|
629
|
+
overflow: hidden;
|
|
630
|
+
text-overflow: ellipsis;
|
|
631
|
+
white-space: nowrap;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* A placeholder row has no words to shrink to, so its label takes the space a
|
|
636
|
+
* name would have taken. Without this the skeleton resolved to nothing and a
|
|
637
|
+
* branch fetching its children drew a one-pixel mark where a row should be —
|
|
638
|
+
* which is what the harness showed.
|
|
639
|
+
*/
|
|
640
|
+
/**
|
|
641
|
+
* A placeholder row has no words to shrink to, so its label takes the space a
|
|
642
|
+
* name would have taken. Without this the skeleton resolved to nothing and a
|
|
643
|
+
* branch fetching its children drew a one-pixel mark where a row should be.
|
|
644
|
+
*
|
|
645
|
+
* The three widths are what stop a fetching branch from reading as a table of
|
|
646
|
+
* identical bars: names are not all one length, and a placeholder that claims
|
|
647
|
+
* they are is a placeholder the eye refuses. They are literals because they
|
|
648
|
+
* are a proportion of a row rather than a step on any scale.
|
|
649
|
+
*/
|
|
650
|
+
[data-ui='tree'] [data-part='label']:has([data-ui='skeleton']) {
|
|
651
|
+
flex: 1 1 auto;
|
|
652
|
+
max-inline-size: 62%;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
[data-ui='tree']
|
|
656
|
+
[data-part='node']:nth-child(2n)
|
|
657
|
+
> [data-part='row']
|
|
658
|
+
[data-part='label']:has([data-ui='skeleton']) {
|
|
659
|
+
max-inline-size: 44%;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
[data-ui='tree']
|
|
663
|
+
[data-part='node']:nth-child(3n)
|
|
664
|
+
> [data-part='row']
|
|
665
|
+
[data-part='label']:has([data-ui='skeleton']) {
|
|
666
|
+
max-inline-size: 73%;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* The band behind a matched span, mixed from the tone's ink rather than taken
|
|
671
|
+
* from its ground, which is the rule `--slotted-highlight-tint-opacity`
|
|
672
|
+
* states and what `select` and `combobox` already draw.
|
|
673
|
+
*/
|
|
674
|
+
[data-ui='tree'] [data-part='label'] mark {
|
|
675
|
+
background-color: color-mix(
|
|
676
|
+
in oklab,
|
|
677
|
+
var(--slotted-tone-accent-text) calc(var(--slotted-highlight-tint-opacity, 0.075) * 100%),
|
|
678
|
+
transparent
|
|
679
|
+
);
|
|
680
|
+
color: inherit;
|
|
681
|
+
font-weight: var(--slotted-font-weight-semibold, 600);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* A matched span on a chosen row keeps its weight and drops its band. The
|
|
686
|
+
* band is seven and a half per cent of the tone's ink mixed into the surface,
|
|
687
|
+
* and over the tone's own ground it is neither visible nor clean — two washes
|
|
688
|
+
* of one colour, one of them too faint to read as deliberate.
|
|
689
|
+
*/
|
|
690
|
+
[data-ui='tree'] [data-part='node'][data-selected] > [data-part='row'] [data-part='label'] mark {
|
|
691
|
+
background-color: transparent;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
[data-ui='tree'] [data-part='description'] {
|
|
695
|
+
color: var(--_muted);
|
|
696
|
+
margin-inline-start: var(--_gap);
|
|
697
|
+
flex: 0 1 auto;
|
|
698
|
+
font-size: var(--_secondary-font-size);
|
|
699
|
+
min-inline-size: 0;
|
|
700
|
+
overflow: hidden;
|
|
701
|
+
text-overflow: ellipsis;
|
|
702
|
+
white-space: nowrap;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* The trailing count. It keeps its intrinsic width so a label twice as long
|
|
707
|
+
* in translation pushes on itself rather than on the number beside it.
|
|
708
|
+
*/
|
|
709
|
+
[data-ui='tree'] [data-part='meta'] {
|
|
710
|
+
color: var(--_muted);
|
|
711
|
+
flex: none;
|
|
712
|
+
font-size: var(--_secondary-font-size);
|
|
713
|
+
font-variant-numeric: tabular-nums;
|
|
714
|
+
/**
|
|
715
|
+
* The automatic margin pushes the count to the end of the row, and collapses
|
|
716
|
+
* to nothing the moment the name fills the row — which left a truncated
|
|
717
|
+
* label touching its own count. The padding is the separation that does not
|
|
718
|
+
* depend on there being room to spare.
|
|
719
|
+
*/
|
|
720
|
+
margin-inline-start: auto;
|
|
721
|
+
padding-inline-start: var(--_gap);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* The wait is `progress-indicator`'s ring, standing where the chevron stands.
|
|
726
|
+
* A family that drew an arc of its own would be a second answer to the same
|
|
727
|
+
* wait, drifting from the first the moment one of them is retuned.
|
|
728
|
+
*/
|
|
729
|
+
/**
|
|
730
|
+
* The wait is `progress-indicator`'s ring, in the chevron's own cell and at
|
|
731
|
+
* the chevron's own size, so a branch that starts fetching moves nothing: the
|
|
732
|
+
* name does not step sideways and the rows below do not step down. A family
|
|
733
|
+
* that drew an arc of its own would be a second answer to the same wait,
|
|
734
|
+
* drifting from the first the moment one of them is retuned.
|
|
735
|
+
*/
|
|
736
|
+
[data-ui='tree'] [data-part='loader'] {
|
|
737
|
+
--slotted-spinner-size: var(--_icon-size);
|
|
738
|
+
|
|
739
|
+
block-size: var(--_icon-size);
|
|
740
|
+
color: var(--_muted);
|
|
741
|
+
flex: none;
|
|
742
|
+
inline-size: var(--_icon-size);
|
|
743
|
+
margin-inline-end: var(--_gap);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* The consumer's trailing controls. They are always in the DOM and always
|
|
748
|
+
* reachable: revealing them on hover alone puts a control behind a gesture a
|
|
749
|
+
* touch reader does not have.
|
|
750
|
+
*/
|
|
751
|
+
[data-ui='tree'] [data-part='actions'] {
|
|
752
|
+
align-items: center;
|
|
753
|
+
display: flex;
|
|
754
|
+
flex: none;
|
|
755
|
+
gap: var(--slotted-space-1, 0.125rem);
|
|
756
|
+
margin-inline-start: auto;
|
|
757
|
+
padding-inline-start: var(--_gap);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* The free space is taken once. With a count before them, the controls sit a
|
|
761
|
+
gap after it rather than splitting the row between the two. */
|
|
762
|
+
[data-ui='tree'] [data-part='meta'] ~ [data-part='actions'] {
|
|
763
|
+
margin-inline-start: 0;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
[data-ui='tree'] [data-part='empty'] {
|
|
767
|
+
color: var(--_muted);
|
|
768
|
+
padding-block: var(--slotted-space-5, 0.75rem);
|
|
769
|
+
padding-inline: var(--_row-inset);
|
|
770
|
+
text-align: center;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* ── States ─────────────────────────────────────────────────────────
|
|
775
|
+
*
|
|
776
|
+
* A weaker state holds itself back for every stronger one, in the order
|
|
777
|
+
* `STATE_PRECEDENCE` names.
|
|
778
|
+
*/
|
|
779
|
+
[data-ui='tree']
|
|
780
|
+
[data-part='node']:not([data-disabled]):not([data-loading])
|
|
781
|
+
> [data-part='row']:hover {
|
|
782
|
+
background-color: var(--_highlight);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
[data-ui='tree']
|
|
786
|
+
[data-part='node']:not([data-disabled]):not([data-loading])
|
|
787
|
+
> [data-part='row']:active {
|
|
788
|
+
background-color: var(--_highlight-active);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* The row the keyboard is on paints the same quiet ground as hover, and the
|
|
793
|
+
* ring is what tells the two apart.
|
|
794
|
+
*/
|
|
795
|
+
[data-ui='tree'] [data-part='node'][data-current]:not([data-disabled]) > [data-part='row'] {
|
|
796
|
+
background-color: var(--_highlight);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
[data-ui='tree'] [data-part='node'][data-selected]:not([data-disabled]) > [data-part='row'] {
|
|
800
|
+
background-color: var(--_selected-surface);
|
|
801
|
+
color: var(--_selected-text);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
[data-ui='tree']
|
|
805
|
+
[data-part='node'][data-selected]:not([data-disabled])
|
|
806
|
+
> [data-part='row']
|
|
807
|
+
:is([data-part='icon'], [data-part='meta'], [data-part='expander']) {
|
|
808
|
+
color: inherit;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* A collapsed branch holding a selected descendant. Carbon states the rule
|
|
813
|
+
* and ships no API for it: a selection that disappears when its branch closes
|
|
814
|
+
* is a selection the reader has lost.
|
|
815
|
+
*
|
|
816
|
+
* It is said in ink rather than with a bar on the start edge. R1 —
|
|
817
|
+
* `state-rail.test.mjs` — refuses the bar for `current`, `selected`,
|
|
818
|
+
* `active` and `checked`, and a fact that stands in for a selection is the
|
|
819
|
+
* same claim in a quieter voice; a family allowed to draw the rail here would
|
|
820
|
+
* have found the way around the rule rather than an exception to it. Ink is
|
|
821
|
+
* one of the three devices R1 names, and it is quieter than a ground, which
|
|
822
|
+
* is right: the reader chose the descendant and not this.
|
|
823
|
+
*/
|
|
824
|
+
[data-ui='tree']
|
|
825
|
+
[data-part='node'][data-selected-within]:not([data-selected]):not([data-disabled])
|
|
826
|
+
> [data-part='row'] {
|
|
827
|
+
color: var(--_selected-text);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
[data-ui='tree']
|
|
831
|
+
[data-part='node'][data-selected-within]:not([data-selected]):not([data-disabled])
|
|
832
|
+
> [data-part='row']
|
|
833
|
+
[data-part='expander'] {
|
|
834
|
+
color: inherit;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
[data-ui='tree'] [data-part='node'][data-disabled] > [data-part='row'] {
|
|
838
|
+
color: var(--slotted-disabled-foreground, GrayText);
|
|
839
|
+
cursor: not-allowed;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
[data-ui='tree']
|
|
843
|
+
[data-part='node'][data-disabled]
|
|
844
|
+
> [data-part='row']
|
|
845
|
+
:is([data-part='icon'], [data-part='meta'], [data-part='expander'], [data-part='description']) {
|
|
846
|
+
color: inherit;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
[data-ui='tree'] [data-part='node'][data-loading] > [data-part='row'] {
|
|
850
|
+
cursor: progress;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* The ring is drawn inside the row rather than around it, so a focused row at
|
|
855
|
+
* the top or the bottom of a scrolling canvas is not clipped by its own
|
|
856
|
+
* viewport.
|
|
857
|
+
*/
|
|
858
|
+
[data-ui='tree'] [data-part='node']:focus-visible > [data-part='row'],
|
|
859
|
+
[data-ui='tree']
|
|
860
|
+
[data-part='canvas']:focus-visible
|
|
861
|
+
[data-part='node'][data-current]
|
|
862
|
+
> [data-part='row'] {
|
|
863
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color);
|
|
864
|
+
outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
[data-ui='tree'][data-invalid] {
|
|
868
|
+
--slotted-focus-ring-color: var(--slotted-focus-ring-color-invalid);
|
|
869
|
+
--_border-color: var(--slotted-tone-danger-border);
|
|
870
|
+
/* Width as well as colour (WCAG 1.4.1): in `high-contrast` the danger
|
|
871
|
+
border is the resting edge's black. An edge inside the border, so
|
|
872
|
+
nothing moves, in place of the resting lift — the one `text-field`
|
|
873
|
+
draws. */
|
|
874
|
+
--_invalid-edge-width: var(--slotted-control-invalid-edge-width, 1px);
|
|
875
|
+
--_shadow: inset 0 0 0 var(--_invalid-edge-width) var(--slotted-tone-danger-border);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
[data-ui='tree'][data-disabled] {
|
|
879
|
+
color: var(--slotted-disabled-foreground, GrayText);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
[data-ui='tree'][data-disabled][data-variant='framed'] {
|
|
883
|
+
background-color: var(--slotted-disabled-background, Canvas);
|
|
884
|
+
border-color: var(--slotted-disabled-border, GrayText);
|
|
885
|
+
box-shadow: none;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* ── The windowed shape ─────────────────────────────────────────────
|
|
890
|
+
*
|
|
891
|
+
* The scroller moves to the root and the canvas becomes the thing that is
|
|
892
|
+
* sized, which is the split `listbox` already draws: a `ul` cannot be both
|
|
893
|
+
* the box that scrolls and the box that states the height of a list it only
|
|
894
|
+
* holds a slice of. The canvas falls back to `auto`, so a flat tree with no
|
|
895
|
+
* window is laid out exactly as a nested one.
|
|
896
|
+
*/
|
|
897
|
+
[data-ui='tree'][data-structure='flat'] {
|
|
898
|
+
max-block-size: calc(var(--_rows) * var(--_row-height) + 2 * var(--_inset-block));
|
|
899
|
+
overflow: auto;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
[data-ui='tree'][data-structure='flat'] [data-part='canvas'] {
|
|
903
|
+
block-size: var(--_canvas-size, auto);
|
|
904
|
+
max-block-size: none;
|
|
905
|
+
overflow: visible;
|
|
906
|
+
padding-block-start: calc(var(--_inset-block) + var(--_canvas-offset, 0px));
|
|
907
|
+
position: relative;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* A row the window does not cover and the family renders anyway: the active
|
|
912
|
+
* node, and the anchor a range is measured from. Without it the element
|
|
913
|
+
* `aria-activedescendant` names leaves the document under a momentum scroll,
|
|
914
|
+
* and the reader is operating a widget with no focused node at all.
|
|
915
|
+
*
|
|
916
|
+
* It sits at its own place on the canvas rather than being pulled into view,
|
|
917
|
+
* because the reader scrolled it out and moving it back would take the
|
|
918
|
+
* scrollbar away from them.
|
|
919
|
+
*/
|
|
920
|
+
[data-ui='tree'] [data-part='node'][data-pinned] {
|
|
921
|
+
inset-block-start: var(--slotted-tree-row-offset, 0px);
|
|
922
|
+
inset-inline: 0;
|
|
923
|
+
position: absolute;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* ── The narrow container ───────────────────────────────────────────
|
|
928
|
+
*
|
|
929
|
+
* The indent is the first thing to give way, because a tree that has lost a
|
|
930
|
+
* step of indent is still readable and one that has lost its labels is not.
|
|
931
|
+
* The breakpoints are literal: `@container (min-width: var(--x))` is invalid
|
|
932
|
+
* CSS, which `docs/token-foundation.md` records.
|
|
933
|
+
*
|
|
934
|
+
* The retuned value lands on the canvas rather than on the root. A container
|
|
935
|
+
* query styles the container's descendants and never the container itself, so
|
|
936
|
+
* a rule for `[data-ui='tree']` inside this block matches nothing — the tree
|
|
937
|
+
* is not its own descendant. Written on the root it looked correct and did
|
|
938
|
+
* nothing, and the harness at 240 pixels is what showed the indent had not
|
|
939
|
+
* moved. It is the second half of the two-element decision the briefing
|
|
940
|
+
* records, and the half that is easy to write and hard to see.
|
|
941
|
+
*/
|
|
942
|
+
@container slotted-tree (max-width: 320px) {
|
|
943
|
+
[data-ui='tree'] [data-part='canvas'] {
|
|
944
|
+
--_indent: calc(var(--_icon-size) / 2 + var(--slotted-space-3, 0.375rem));
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
@container slotted-tree (max-width: 240px) {
|
|
949
|
+
[data-ui='tree'] [data-part='canvas'] {
|
|
950
|
+
--_indent: calc(var(--_icon-size) / 2 + var(--slotted-space-2, 0.25rem));
|
|
951
|
+
--_row-inset: var(--slotted-control-padding-inline-sm, 0.625rem);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/* The second line has no room to sit beside the first at this width. */
|
|
955
|
+
[data-ui='tree'] [data-part='description'] {
|
|
956
|
+
display: none;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* The one thing the theme cannot reach. Every tone surface becomes `Canvas`
|
|
962
|
+
* under forced colours, so a selection said with a tinted ground alone would
|
|
963
|
+
* say nothing in the mode that needs it most — and under the `highlight`
|
|
964
|
+
* indicator there is no mark to fall back on. `accent` is the selected tone
|
|
965
|
+
* and the theme maps it to `Highlight`, which is what is restated here.
|
|
966
|
+
*/
|
|
967
|
+
@media (forced-colors: active) {
|
|
968
|
+
[data-ui='tree'] [data-part='node'][data-selected] > [data-part='row'] {
|
|
969
|
+
background-color: Highlight;
|
|
970
|
+
color: HighlightText;
|
|
971
|
+
forced-color-adjust: none;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
[data-ui='tree'] [data-part='node'][data-disabled] > [data-part='row'] {
|
|
975
|
+
color: GrayText;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
/*
|
|
979
|
+
* The box and its mark are painted from a tone. The theme maps `accent` to
|
|
980
|
+
* `Highlight` and `on-solid` to `HighlightText`, so the chosen box keeps
|
|
981
|
+
* both; the mark opts out as well, or the system forces its ink to the
|
|
982
|
+
* text colour and the tick loses its contrast with the box it stands on.
|
|
983
|
+
*/
|
|
984
|
+
[data-ui='tree'] [data-part='indicator'] > [data-ui='icon'] {
|
|
985
|
+
forced-color-adjust: none;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/*
|
|
990
|
+
* Forced colours remove every box shadow, and the edge with them. The width
|
|
991
|
+
* comes back as an outline inside the border; the
|
|
992
|
+
* ring belongs to a row and leaves it alone.
|
|
993
|
+
*/
|
|
994
|
+
@media (forced-colors: active) {
|
|
995
|
+
[data-ui='tree'][data-variant='framed'][data-invalid] {
|
|
996
|
+
outline: var(--_invalid-edge-width) solid CanvasText;
|
|
997
|
+
outline-offset: calc(-1 * (var(--_border-width) + var(--_invalid-edge-width)));
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|