@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.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/package.json +276 -3
  4. package/src/accordion/accordion.css +96 -0
  5. package/src/accordion/accordion.tokens.json +14 -0
  6. package/src/action-bar/action-bar.css +455 -0
  7. package/src/action-bar/action-bar.tokens.json +50 -0
  8. package/src/action-sheet/action-sheet.css +462 -0
  9. package/src/action-sheet/action-sheet.tokens.json +59 -0
  10. package/src/alert/alert.css +764 -0
  11. package/src/alert/alert.tokens.json +77 -0
  12. package/src/app-shell/app-shell.css +1899 -0
  13. package/src/app-shell/app-shell.tokens.json +88 -0
  14. package/src/aspect-ratio/aspect-ratio.css +131 -0
  15. package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
  16. package/src/attachment/attachment.css +906 -0
  17. package/src/attachment/attachment.tokens.json +85 -0
  18. package/src/avatar/avatar.css +598 -0
  19. package/src/avatar/avatar.tokens.json +64 -0
  20. package/src/avatar-group/avatar-group.css +268 -0
  21. package/src/avatar-group/avatar-group.tokens.json +16 -0
  22. package/src/badge/badge.css +462 -0
  23. package/src/badge/badge.tokens.json +58 -0
  24. package/src/breadcrumb/breadcrumb.css +441 -0
  25. package/src/breadcrumb/breadcrumb.tokens.json +50 -0
  26. package/src/button/button.css +754 -0
  27. package/src/button/button.tokens.json +72 -0
  28. package/src/button-group/button-group.css +455 -0
  29. package/src/button-group/button-group.tokens.json +11 -0
  30. package/src/calendar/calendar.css +846 -0
  31. package/src/calendar/calendar.tokens.json +67 -0
  32. package/src/card/card.css +602 -0
  33. package/src/card/card.tokens.json +68 -0
  34. package/src/carousel/carousel.css +860 -0
  35. package/src/carousel/carousel.tokens.json +62 -0
  36. package/src/cascader/cascader.css +1320 -0
  37. package/src/cascader/cascader.tokens.json +103 -0
  38. package/src/chart/chart.css +1473 -0
  39. package/src/chart/chart.tokens.json +107 -0
  40. package/src/checkbox/checkbox.css +1011 -0
  41. package/src/checkbox/checkbox.tokens.json +102 -0
  42. package/src/checkbox-group/checkbox-group.css +70 -0
  43. package/src/checkbox-group/checkbox-group.tokens.json +6 -0
  44. package/src/code-block/code-block.css +555 -0
  45. package/src/code-block/code-block.tokens.json +69 -0
  46. package/src/collapsible/collapsible.css +546 -0
  47. package/src/collapsible/collapsible.tokens.json +55 -0
  48. package/src/color-picker/color-picker.css +607 -0
  49. package/src/color-picker/color-picker.tokens.json +58 -0
  50. package/src/column-manager/column-manager.css +452 -0
  51. package/src/column-manager/column-manager.tokens.json +43 -0
  52. package/src/combobox/combobox.css +1048 -0
  53. package/src/combobox/combobox.tokens.json +112 -0
  54. package/src/command-palette/command-palette.css +1000 -0
  55. package/src/command-palette/command-palette.tokens.json +75 -0
  56. package/src/container/container.css +198 -0
  57. package/src/container/container.tokens.json +18 -0
  58. package/src/context-menu/context-menu.css +104 -0
  59. package/src/context-menu/context-menu.tokens.json +11 -0
  60. package/src/currency-field/currency-field.css +787 -0
  61. package/src/currency-field/currency-field.tokens.json +80 -0
  62. package/src/dashboard-grid/dashboard-grid.css +748 -0
  63. package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
  64. package/src/data-grid/data-grid.css +2484 -0
  65. package/src/data-grid/data-grid.tokens.json +100 -0
  66. package/src/data-list/data-list.css +455 -0
  67. package/src/data-list/data-list.tokens.json +35 -0
  68. package/src/date-field/date-field.css +560 -0
  69. package/src/date-field/date-field.tokens.json +80 -0
  70. package/src/date-picker/date-picker.css +420 -0
  71. package/src/date-picker/date-picker.tokens.json +49 -0
  72. package/src/date-range-picker/date-range-picker.css +983 -0
  73. package/src/date-range-picker/date-range-picker.tokens.json +109 -0
  74. package/src/datetime-field/datetime-field.css +850 -0
  75. package/src/datetime-field/datetime-field.tokens.json +91 -0
  76. package/src/datetime-picker/datetime-picker.css +843 -0
  77. package/src/datetime-picker/datetime-picker.tokens.json +78 -0
  78. package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
  79. package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
  80. package/src/description-list/description-list.css +675 -0
  81. package/src/description-list/description-list.tokens.json +66 -0
  82. package/src/detail-panel/detail-panel.css +329 -0
  83. package/src/detail-panel/detail-panel.tokens.json +33 -0
  84. package/src/dialog/dialog.css +968 -0
  85. package/src/dialog/dialog.tokens.json +66 -0
  86. package/src/divider/divider.css +131 -0
  87. package/src/divider/divider.tokens.json +18 -0
  88. package/src/drawer/drawer.css +1303 -0
  89. package/src/drawer/drawer.tokens.json +75 -0
  90. package/src/entity-picker/entity-picker.css +1367 -0
  91. package/src/entity-picker/entity-picker.tokens.json +118 -0
  92. package/src/event-calendar/event-calendar.css +2148 -0
  93. package/src/event-calendar/event-calendar.tokens.json +87 -0
  94. package/src/field/field.css +707 -0
  95. package/src/field/field.tokens.json +58 -0
  96. package/src/field-group/field-group.css +226 -0
  97. package/src/field-group/field-group.tokens.json +33 -0
  98. package/src/filter-bar/filter-bar.css +1306 -0
  99. package/src/filter-bar/filter-bar.tokens.json +78 -0
  100. package/src/form/form.css +218 -0
  101. package/src/form/form.tokens.json +32 -0
  102. package/src/fullscreen/fullscreen.css +376 -0
  103. package/src/fullscreen/fullscreen.tokens.json +50 -0
  104. package/src/grid/grid.css +173 -0
  105. package/src/grid/grid.tokens.json +20 -0
  106. package/src/highlight/highlight.css +135 -0
  107. package/src/highlight/highlight.tokens.json +16 -0
  108. package/src/hover-card/hover-card.css +93 -0
  109. package/src/hover-card/hover-card.tokens.json +17 -0
  110. package/src/icon/icon.css +136 -0
  111. package/src/icon/icon.tokens.json +14 -0
  112. package/src/image/image.css +449 -0
  113. package/src/image/image.tokens.json +27 -0
  114. package/src/import-export-center/import-export-center.css +1175 -0
  115. package/src/import-export-center/import-export-center.tokens.json +84 -0
  116. package/src/inline/inline.css +149 -0
  117. package/src/inline/inline.tokens.json +14 -0
  118. package/src/inline-message/inline-message.css +396 -0
  119. package/src/inline-message/inline-message.tokens.json +19 -0
  120. package/src/kbd/kbd.css +490 -0
  121. package/src/kbd/kbd.tokens.json +40 -0
  122. package/src/link/link.css +237 -0
  123. package/src/link/link.tokens.json +25 -0
  124. package/src/list/list.css +240 -0
  125. package/src/list/list.tokens.json +42 -0
  126. package/src/list-item/list-item.css +937 -0
  127. package/src/list-item/list-item.tokens.json +114 -0
  128. package/src/listbox/listbox.css +674 -0
  129. package/src/listbox/listbox.tokens.json +72 -0
  130. package/src/loading-overlay/loading-overlay.css +730 -0
  131. package/src/loading-overlay/loading-overlay.tokens.json +48 -0
  132. package/src/markdown/markdown.css +168 -0
  133. package/src/markdown/markdown.tokens.json +18 -0
  134. package/src/menu/menu.css +817 -0
  135. package/src/menu/menu.tokens.json +78 -0
  136. package/src/menubar/menubar.css +170 -0
  137. package/src/menubar/menubar.tokens.json +32 -0
  138. package/src/message/message.css +1453 -0
  139. package/src/message/message.tokens.json +85 -0
  140. package/src/message-scroller/message-scroller.css +371 -0
  141. package/src/message-scroller/message-scroller.tokens.json +47 -0
  142. package/src/multi-select/multi-select.css +1427 -0
  143. package/src/multi-select/multi-select.tokens.json +114 -0
  144. package/src/navigation-menu/navigation-menu.css +1029 -0
  145. package/src/navigation-menu/navigation-menu.tokens.json +70 -0
  146. package/src/notification-center/notification-center.css +856 -0
  147. package/src/notification-center/notification-center.tokens.json +84 -0
  148. package/src/number-field/number-field.css +794 -0
  149. package/src/number-field/number-field.tokens.json +80 -0
  150. package/src/otp-input/otp-input.css +525 -0
  151. package/src/otp-input/otp-input.tokens.json +69 -0
  152. package/src/page/page.css +179 -0
  153. package/src/page/page.tokens.json +20 -0
  154. package/src/page-header/page-header.css +1181 -0
  155. package/src/page-header/page-header.tokens.json +71 -0
  156. package/src/pagination/pagination.css +500 -0
  157. package/src/pagination/pagination.tokens.json +56 -0
  158. package/src/popover/popover.css +526 -0
  159. package/src/popover/popover.tokens.json +60 -0
  160. package/src/progress-indicator/progress-indicator.css +1584 -0
  161. package/src/progress-indicator/progress-indicator.tokens.json +50 -0
  162. package/src/prompt-composer/prompt-composer.css +680 -0
  163. package/src/prompt-composer/prompt-composer.tokens.json +99 -0
  164. package/src/prose/prose.css +733 -0
  165. package/src/prose/prose.tokens.json +79 -0
  166. package/src/radio-group/radio-group.css +778 -0
  167. package/src/radio-group/radio-group.tokens.json +103 -0
  168. package/src/rating/rating.css +1071 -0
  169. package/src/rating/rating.tokens.json +88 -0
  170. package/src/result-state/result-state.css +980 -0
  171. package/src/result-state/result-state.tokens.json +63 -0
  172. package/src/runtime-properties.mjs +321 -0
  173. package/src/saved-views/saved-views.css +394 -0
  174. package/src/saved-views/saved-views.tokens.json +41 -0
  175. package/src/scroll-area/scroll-area.css +481 -0
  176. package/src/scroll-area/scroll-area.tokens.json +15 -0
  177. package/src/section/section.css +177 -0
  178. package/src/section/section.tokens.json +39 -0
  179. package/src/segmented-control/segmented-control.css +564 -0
  180. package/src/segmented-control/segmented-control.tokens.json +67 -0
  181. package/src/select/select.css +1593 -0
  182. package/src/select/select.tokens.json +110 -0
  183. package/src/side-navigation/side-navigation.css +1096 -0
  184. package/src/side-navigation/side-navigation.tokens.json +87 -0
  185. package/src/skeleton/skeleton.css +431 -0
  186. package/src/skeleton/skeleton.tokens.json +29 -0
  187. package/src/slider/slider.css +792 -0
  188. package/src/slider/slider.tokens.json +75 -0
  189. package/src/sparkline/sparkline.css +282 -0
  190. package/src/sparkline/sparkline.tokens.json +45 -0
  191. package/src/spinner/spinner.css +224 -0
  192. package/src/spinner/spinner.tokens.json +8 -0
  193. package/src/split-button/split-button.css +253 -0
  194. package/src/split-button/split-button.tokens.json +12 -0
  195. package/src/splitter/splitter.css +336 -0
  196. package/src/splitter/splitter.tokens.json +24 -0
  197. package/src/stack/stack.css +128 -0
  198. package/src/stack/stack.tokens.json +14 -0
  199. package/src/stat-card/stat-card.css +641 -0
  200. package/src/stat-card/stat-card.tokens.json +95 -0
  201. package/src/status-indicator/status-indicator.css +481 -0
  202. package/src/status-indicator/status-indicator.tokens.json +38 -0
  203. package/src/stepper/stepper.css +629 -0
  204. package/src/stepper/stepper.tokens.json +72 -0
  205. package/src/switch/switch.css +703 -0
  206. package/src/switch/switch.tokens.json +75 -0
  207. package/src/table/table.css +1482 -0
  208. package/src/table/table.tokens.json +69 -0
  209. package/src/table-of-contents/table-of-contents.css +533 -0
  210. package/src/table-of-contents/table-of-contents.tokens.json +53 -0
  211. package/src/tabs/tabs.css +998 -0
  212. package/src/tabs/tabs.tokens.json +82 -0
  213. package/src/tag/tag.css +768 -0
  214. package/src/tag/tag.tokens.json +85 -0
  215. package/src/tags-input/tags-input.css +757 -0
  216. package/src/tags-input/tags-input.tokens.json +84 -0
  217. package/src/text-field/text-field.css +900 -0
  218. package/src/text-field/text-field.tokens.json +87 -0
  219. package/src/textarea/textarea.css +365 -0
  220. package/src/textarea/textarea.tokens.json +59 -0
  221. package/src/time-field/time-field.css +719 -0
  222. package/src/time-field/time-field.tokens.json +86 -0
  223. package/src/time-picker/time-picker.css +665 -0
  224. package/src/time-picker/time-picker.tokens.json +66 -0
  225. package/src/time-range-picker/time-range-picker.css +1287 -0
  226. package/src/time-range-picker/time-range-picker.tokens.json +134 -0
  227. package/src/timeline/timeline.css +1596 -0
  228. package/src/timeline/timeline.tokens.json +96 -0
  229. package/src/toast/toast.css +943 -0
  230. package/src/toast/toast.tokens.json +90 -0
  231. package/src/toggle/toggle.css +290 -0
  232. package/src/toggle/toggle.tokens.json +54 -0
  233. package/src/toggle-group/toggle-group.css +463 -0
  234. package/src/toggle-group/toggle-group.tokens.json +54 -0
  235. package/src/toolbar/toolbar.css +434 -0
  236. package/src/toolbar/toolbar.tokens.json +49 -0
  237. package/src/tooltip/tooltip.css +368 -0
  238. package/src/tooltip/tooltip.tokens.json +39 -0
  239. package/src/top-navigation/top-navigation.css +1287 -0
  240. package/src/top-navigation/top-navigation.tokens.json +91 -0
  241. package/src/tour/tour.css +680 -0
  242. package/src/tour/tour.tokens.json +67 -0
  243. package/src/transfer/transfer.css +571 -0
  244. package/src/transfer/transfer.tokens.json +49 -0
  245. package/src/tree/tree.css +1000 -0
  246. package/src/tree/tree.tokens.json +80 -0
  247. package/src/typography/typography.css +211 -0
  248. package/src/typography/typography.tokens.json +31 -0
  249. package/src/upload/upload.css +1706 -0
  250. package/src/upload/upload.tokens.json +123 -0
  251. package/src/visually-hidden/visually-hidden.css +52 -0
  252. package/src/visually-hidden/visually-hidden.tokens.json +1 -0
  253. package/src/wizard/wizard.css +740 -0
  254. package/src/wizard/wizard.tokens.json +63 -0
@@ -0,0 +1,237 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * A link is text that goes somewhere. It is not a control surface: it has no
4
+ * height, no padding and no fill, it takes the type of the text around it,
5
+ * and `button` owns the anchor that wants the action surface — `ButtonLink`,
6
+ * the same family, the same geometry.
7
+ *
8
+ * Three values carry every variant: the colour at rest, the colour under the
9
+ * pointer, and the colour while it is being pressed. A fourth, `--_strong`,
10
+ * is the maximum-contrast text colour of whatever context the link sits in,
11
+ * and it is what hover mixes toward. That indirection is the whole reason
12
+ * this family was rebuilt: the shipped stylesheet painted hover with
13
+ * `--slotted-tone-accent-solid-hover`, which is a fill colour. In the light
14
+ * scheme a fill that darkens is also a text colour that darkens, so the
15
+ * defect never showed. In the dark scheme that token is `#1d4ed8` over a
16
+ * `#131316` ground, and hovering a link made it harder to read than leaving
17
+ * it alone. A ramp built for fills cannot be a ramp for text, and the tone
18
+ * scale has no `text-hover` role to reach for; mixing toward the colour the
19
+ * theme already holds to the highest ratio in each scheme cannot fail the
20
+ * same way.
21
+ */
22
+ [data-ui='link'] {
23
+ --_strong: var(--slotted-text, CanvasText);
24
+ --_rest: var(--slotted-link-color, var(--slotted-tone-accent-text, LinkText));
25
+ --_hover: var(
26
+ --slotted-link-color-hover,
27
+ color-mix(in oklab, var(--_rest) 65%, var(--_strong))
28
+ );
29
+ --_active: var(
30
+ --slotted-link-color-active,
31
+ color-mix(in oklab, var(--_rest) 35%, var(--_strong))
32
+ );
33
+ --_visited: var(
34
+ --slotted-link-color-visited,
35
+ color-mix(in oklab, var(--_rest) 40%, var(--slotted-text-muted, GrayText))
36
+ );
37
+ /**
38
+ * The underline at rest is lighter than the text it belongs to, and
39
+ * reaches full strength from hover onward. That is what gives `inverse` a
40
+ * hover at all: on a solid surface the text colour is already the
41
+ * strongest one available, so the underline is the only property left that
42
+ * can answer the pointer.
43
+ */
44
+ --_underline: var(
45
+ --slotted-link-underline-color,
46
+ color-mix(in oklab, currentColor 55%, transparent)
47
+ );
48
+
49
+ border-radius: var(--slotted-link-radius, var(--slotted-control-radius, 4px));
50
+ color: var(--_rest);
51
+ /**
52
+ * A link inside a `Stack`, a grid cell or any other flex container is
53
+ * blockified by the layout — `display: inline` is not a choice a flex item
54
+ * gets to keep — and a blockified link stretches to the full inline size of
55
+ * the column. Nothing about the text changes, and then the focus ring is
56
+ * drawn around the whole column instead of around the words, which is what
57
+ * the first focus capture of this family showed. Shrinking to the content
58
+ * is inert for an inline link, where inline-size does not apply at all.
59
+ */
60
+ inline-size: fit-content;
61
+ /**
62
+ * A destination pasted as the link text is one unbroken token. Without
63
+ * this it widens the column it sits in rather than wrapping inside it,
64
+ * which is what a 240-pixel capture shows and a paragraph of ordinary
65
+ * prose never does.
66
+ */
67
+ overflow-wrap: anywhere;
68
+ text-decoration-color: var(--_underline);
69
+ text-decoration-line: underline;
70
+ text-decoration-thickness: var(--slotted-link-underline-thickness, from-font);
71
+ text-underline-offset: var(--slotted-link-underline-offset, 0.15em);
72
+ transition:
73
+ color var(--slotted-duration-short) var(--slotted-easing-standard),
74
+ text-decoration-color var(--slotted-duration-short) var(--slotted-easing-standard);
75
+ }
76
+
77
+ /**
78
+ * The link that takes the colour of the text it sits in — a title inside a
79
+ * card, a name inside a table row — and reaches the accent under the
80
+ * pointer. Fluent calls it `subtle`, Primer `muted`, Polaris `monochrome`,
81
+ * and all three describe the same two colours.
82
+ */
83
+ [data-ui='link'][data-variant='neutral'] {
84
+ --_rest: var(--slotted-link-color, currentColor);
85
+ --_hover: var(--slotted-link-color-hover, var(--slotted-tone-accent-text, LinkText));
86
+ --_active: var(
87
+ --slotted-link-color-active,
88
+ color-mix(in oklab, var(--slotted-tone-accent-text, LinkText) 65%, var(--_strong))
89
+ );
90
+ }
91
+
92
+ /**
93
+ * The link on a solid or inverse surface. The strong colour changes with the
94
+ * ground, so hover has nowhere further to go and the underline carries the
95
+ * state on its own.
96
+ */
97
+ [data-ui='link'][data-variant='inverse'] {
98
+ --_strong: var(--slotted-text-inverse, Canvas);
99
+ --_rest: var(--slotted-link-color, var(--slotted-text-inverse, Canvas));
100
+ }
101
+
102
+ /* ── Underline axis ─────────────────────────────────────────────────────
103
+ *
104
+ * `always` is the default because colour alone does not distinguish a link:
105
+ * the accent text colour clears 4.5:1 against the surface and not 3:1
106
+ * against the body text beside it, which is the ratio a link with no second
107
+ * cue has to meet. The other two values are for a link that stands alone,
108
+ * where there is no sentence for it to disappear into.
109
+ */
110
+
111
+ [data-ui='link'][data-underline='hover'],
112
+ [data-ui='link'][data-underline='none'] {
113
+ text-decoration-line: none;
114
+ }
115
+
116
+ [data-ui='link'][data-underline='hover']:not([data-disabled]):hover {
117
+ text-decoration-line: underline;
118
+ }
119
+
120
+ /**
121
+ * A keyboard has no hover, so focus is where a deferred underline is owed.
122
+ * `none` is left alone: it says the underline does not exist, not that it is
123
+ * waiting for something.
124
+ */
125
+ [data-ui='link'][data-underline='hover']:focus-visible {
126
+ text-decoration-line: underline;
127
+ }
128
+
129
+ /* ── Visited ────────────────────────────────────────────────────────────
130
+ *
131
+ * Opt-in, and declared before the interaction rules so hover still answers a
132
+ * link the reader has already followed. `:visited` accepts colour and
133
+ * nothing else — the restriction is deliberate, and it is also why no test
134
+ * in this repository can read this rule back.
135
+ */
136
+
137
+ [data-ui='link'][data-visited]:visited {
138
+ color: var(--_visited);
139
+ }
140
+
141
+ /* ── Hover and press, held back for disabled ────────────────────────────── */
142
+
143
+ [data-ui='link']:not([data-disabled]):hover {
144
+ --_underline: currentColor;
145
+
146
+ color: var(--_hover);
147
+ }
148
+
149
+ [data-ui='link']:not([data-disabled]):active {
150
+ --_underline: currentColor;
151
+
152
+ color: var(--_active);
153
+ }
154
+
155
+ /* ── Focus ──────────────────────────────────────────────────────────────
156
+ *
157
+ * The ring hugs the text at one pixel rather than the two a control uses: a
158
+ * link has no border for the ring to clear, and on a line of prose a wider
159
+ * offset reaches into the line above.
160
+ */
161
+
162
+ [data-ui='link']:focus-visible {
163
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
164
+ outline-offset: var(--slotted-link-focus-ring-offset, 1px);
165
+ }
166
+
167
+ /* ── Disabled ───────────────────────────────────────────────────────────
168
+ *
169
+ * `[data-disabled]` rather than a pseudo-class, because an anchor has none:
170
+ * what makes the link unavailable is the destination the binding did not
171
+ * render, plus `aria-disabled`. The underline stays, so the element still
172
+ * reads as a link that is not available rather than as plain text.
173
+ */
174
+
175
+ [data-ui='link'][data-disabled] {
176
+ color: var(--slotted-link-color-disabled, var(--slotted-disabled-foreground, GrayText));
177
+ cursor: not-allowed;
178
+ }
179
+
180
+ /* ── The external marker ────────────────────────────────────────────────
181
+ *
182
+ * The arrow is the `Glyph` element inside an `icon` box, so it is the colour
183
+ * of the link at every step of the ramp, in every scheme and under forced
184
+ * colours, and mirrors in a right-to-left document through the box's own
185
+ * `directional`. A character would be a font's opinion of an arrow.
186
+ *
187
+ * The binding writes a word joiner before this element — U+2060, the
188
+ * zero-width character whose whole purpose is to forbid a line break without
189
+ * occupying anything — so the glyph cannot wrap onto the next line without
190
+ * the word it belongs to. A no-break space would do the same job and carry a
191
+ * full word space with it, and "published schedule ↗" then reads as three
192
+ * words rather than a link and its marker. The distance is a token instead.
193
+ *
194
+ * The part stays an inline wrapper around the box: the gap is an inline
195
+ * margin, and the box inside sets its own size and optical alignment from
196
+ * `--slotted-icon-size`, which the part states at the size of the text.
197
+ */
198
+
199
+ [data-ui='link'] [data-part='external-icon'] {
200
+ --slotted-icon-size: var(--slotted-link-external-icon-size, 1em);
201
+
202
+ margin-inline-start: var(--slotted-link-external-icon-gap, 0.15em);
203
+ }
204
+
205
+ /* ── The current link ───────────────────────────────────────────────────
206
+ *
207
+ * Painted from the platform's own attribute, which is the one a React
208
+ * consumer writes by hand and the one Angular's `routerLinkActive` writes
209
+ * through `ariaCurrentWhenActive`. A mirrored `data-current` would need the
210
+ * family to observe an attribute a router sets at runtime, and would paint
211
+ * nothing at all for the consumer who never adopted the mirror.
212
+ *
213
+ * The destination of a current link is the page the reader is already on, so
214
+ * it stops being an invitation and takes the body colour. The underline
215
+ * stays, because it is still a link and colour alone would not say so. The
216
+ * weight does not change: a nav item that thickens shifts every item beside
217
+ * it.
218
+ */
219
+
220
+ [data-ui='link'][aria-current]:not([aria-current='false']) {
221
+ --_rest: var(--slotted-link-color-current, var(--slotted-text, CanvasText));
222
+ }
223
+
224
+ /* ── Forced colours ─────────────────────────────────────────────────────
225
+ *
226
+ * The theme remaps every token it owns, so this block covers only what the
227
+ * family paints itself: an underline the axis may have taken away, where a
228
+ * flattened palette leaves a link with nothing to be recognized by. The
229
+ * external marker is stroked with `currentColor` and follows the link.
230
+ */
231
+
232
+ @media (forced-colors: active) {
233
+ [data-ui='link'] {
234
+ text-decoration-line: underline;
235
+ }
236
+ }
237
+ }
@@ -0,0 +1,25 @@
1
+ [
2
+ "--slotted-control-radius",
3
+ "--slotted-disabled-foreground",
4
+ "--slotted-duration-short",
5
+ "--slotted-easing-standard",
6
+ "--slotted-focus-ring-color",
7
+ "--slotted-focus-ring-width",
8
+ "--slotted-link-color",
9
+ "--slotted-link-color-active",
10
+ "--slotted-link-color-current",
11
+ "--slotted-link-color-disabled",
12
+ "--slotted-link-color-hover",
13
+ "--slotted-link-color-visited",
14
+ "--slotted-link-external-icon-gap",
15
+ "--slotted-link-external-icon-size",
16
+ "--slotted-link-focus-ring-offset",
17
+ "--slotted-link-radius",
18
+ "--slotted-link-underline-color",
19
+ "--slotted-link-underline-offset",
20
+ "--slotted-link-underline-thickness",
21
+ "--slotted-text",
22
+ "--slotted-text-inverse",
23
+ "--slotted-text-muted",
24
+ "--slotted-tone-accent-text"
25
+ ]
@@ -0,0 +1,240 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── The set ────────────────────────────────────────────────────────────
4
+ *
5
+ * A vertical run of related rows. The rows are `list-item`, a family of its
6
+ * own, and **no selector here reaches `[data-ui='list-item']`** — the rule
7
+ * `accordion` and `collapsible` set for the same relationship. What the set
8
+ * decides it hands to each row through the binding, as a `data-` attribute
9
+ * the row's own stylesheet reads.
10
+ *
11
+ * The one thing the two sheets share is a counter name. `slotted-list-item`
12
+ * is reset here, on the root and on every nested group, and incremented by
13
+ * the row; a counter is not a selector, so neither family's DOM becomes part
14
+ * of the other's contract.
15
+ *
16
+ * The native marker is gone in every configuration, because a row is a
17
+ * content box beside its independent targets and CSS has no `display` that is
18
+ * both `list-item` and a grid. The bindings therefore write `role="list"`
19
+ * here and on `section-list`, which is what Safari and VoiceOver need once
20
+ * the marker is removed.
21
+ */
22
+ [data-ui='list'][data-part='root'],
23
+ [data-ui='list'] [data-part='section-list'] {
24
+ /* The row's own number. The set opens the count; each group opens its own,
25
+ so a numbered list of groups restarts rather than running through. */
26
+ counter-reset: slotted-list-item;
27
+ display: flex;
28
+ flex-direction: column;
29
+ list-style: none;
30
+ margin-block: 0;
31
+ margin-inline: 0;
32
+ /* A row's text column can only shrink below its content if every box above
33
+ it can, and a flex item's default `min-inline-size: auto` stops at the
34
+ longest word. Without this a title that is one unbroken token widens the
35
+ whole list instead of breaking inside the row. */
36
+ min-inline-size: 0;
37
+ padding-inline: 0;
38
+ }
39
+
40
+ [data-ui='list'][data-part='root'] {
41
+ /* The distance between rows, and it is spent only by `separated`. The other
42
+ three variants separate rows with a line or with nothing, so a gap there
43
+ would be space the reader cannot account for. */
44
+ --_gap: var(--slotted-list-gap, var(--slotted-space-3, 0.375rem));
45
+ /* The frame `framed` draws, and the ground the sticky group heading needs.
46
+ Both are declared at the root so a theme retunes them once. */
47
+ --_frame-color: var(--slotted-list-border-color, var(--slotted-border-subtle, ButtonBorder));
48
+ --_frame-width: var(--slotted-list-border-width, var(--slotted-border-width-thin, 1px));
49
+ --_frame-radius: var(--slotted-list-radius, var(--slotted-radius-md, 6px));
50
+ --_surface: var(--slotted-list-background, var(--slotted-surface, Canvas));
51
+ /* The group heading's type and colour. It is a heading in the document,
52
+ so it takes the muted ink rather than a tone: a coloured heading over a
53
+ neutral list reads as a status the group does not have. */
54
+ --_section-color: var(--slotted-list-section-color, var(--slotted-text-muted, GrayText));
55
+ --_section-font-size: var(
56
+ --slotted-list-section-font-size,
57
+ var(--slotted-font-size-xs, 0.75rem)
58
+ );
59
+ --_section-weight: var(
60
+ --slotted-list-section-font-weight,
61
+ var(--slotted-font-weight-semibold, 600)
62
+ );
63
+ --_section-inset-block: var(
64
+ --slotted-list-section-padding-block,
65
+ var(--slotted-space-4, 0.5rem)
66
+ );
67
+ --_row-inset-inline: var(
68
+ --slotted-list-padding-inline,
69
+ var(--slotted-control-padding-inline-md, 13px)
70
+ );
71
+ --_empty-color: var(--slotted-list-empty-color, var(--slotted-text-muted, GrayText));
72
+ --_empty-inset: var(--slotted-list-empty-padding, var(--slotted-space-8, 1.5rem));
73
+ }
74
+
75
+ /**
76
+ * Size is this list's own step and density is the application's. The two
77
+ * scale different things — density retunes every control on the page, size
78
+ * says how much room this one list gives a row — so a dense inbox and a
79
+ * roomy settings list stand on the same page without either of them lying
80
+ * about the density.
81
+ */
82
+ [data-ui='list'][data-part='root'][data-size='sm'] {
83
+ --_gap: var(--slotted-list-gap-sm, var(--slotted-space-2, 0.25rem));
84
+ --_section-inset-block: var(
85
+ --slotted-list-section-padding-block-sm,
86
+ var(--slotted-space-3, 0.375rem)
87
+ );
88
+ --_row-inset-inline: var(
89
+ --slotted-list-padding-inline-sm,
90
+ var(--slotted-control-padding-inline-sm, 10px)
91
+ );
92
+ --_empty-inset: var(--slotted-list-empty-padding-sm, var(--slotted-space-6, 1rem));
93
+ }
94
+
95
+ [data-ui='list'][data-part='root'][data-size='lg'] {
96
+ --_gap: var(--slotted-list-gap-lg, var(--slotted-space-4, 0.5rem));
97
+ --_section-inset-block: var(
98
+ --slotted-list-section-padding-block-lg,
99
+ var(--slotted-space-5, 0.75rem)
100
+ );
101
+ --_row-inset-inline: var(
102
+ --slotted-list-padding-inline-lg,
103
+ var(--slotted-control-padding-inline-lg, 16px)
104
+ );
105
+ --_empty-inset: var(--slotted-list-empty-padding-lg, var(--slotted-space-9, 2rem));
106
+ }
107
+
108
+ /**
109
+ * ── How rows are told apart ────────────────────────────────────────────
110
+ *
111
+ * Four words, and they are `accordion`'s four so that two families cannot
112
+ * mean different things by one of them. Only two of them draw anything here:
113
+ * the line between rows and the surface of a separated row belong to the row,
114
+ * which is the only element that knows whether it is first, last or alone.
115
+ *
116
+ * `plain` and `ruled` draw nothing on the set.
117
+ */
118
+ [data-ui='list'][data-part='root'][data-variant='framed'] {
119
+ background-color: var(--_surface);
120
+ border: var(--_frame-width) solid var(--_frame-color);
121
+ border-radius: var(--_frame-radius);
122
+ /* The frame clips its own corners, so the first and last rows do not paint
123
+ a square hover fill over a rounded edge. `clip` rather than `hidden`: the
124
+ set is not a scroll container, and `hidden` would silently make it one. */
125
+ overflow: clip;
126
+ }
127
+
128
+ [data-ui='list'][data-part='root'][data-variant='separated'] {
129
+ row-gap: var(--_gap);
130
+ }
131
+
132
+ /**
133
+ * A group inside the set. It is an `li` holding a heading and a nested list,
134
+ * which is the grouping HTML already has; MUI, Angular Material, Primer and
135
+ * React Aria each leave the heading loose among the rows instead, so a reader
136
+ * hears a heading inside a set rather than a set with a name.
137
+ */
138
+ [data-ui='list'] [data-part='section'] {
139
+ display: flex;
140
+ flex-direction: column;
141
+ min-inline-size: 0;
142
+ }
143
+
144
+ /* A separated set gaps its groups too, and a group gaps its own rows. Both
145
+ read the one distance the root declared. */
146
+ [data-ui='list'][data-variant='separated'] [data-part='section'],
147
+ [data-ui='list'][data-variant='separated'] [data-part='section-list'] {
148
+ row-gap: var(--_gap);
149
+ }
150
+
151
+ /**
152
+ * The group's name. It shares the row's inline inset so the heading and the
153
+ * titles under it stand in one column, which is the alignment that makes a
154
+ * grouped list read as one list rather than as several.
155
+ */
156
+ [data-ui='list'] [data-part='section-label'] {
157
+ color: var(--_section-color);
158
+ font-size: var(--_section-font-size);
159
+ font-weight: var(--_section-weight);
160
+ letter-spacing: var(--slotted-list-section-letter-spacing, 0);
161
+ line-height: var(--slotted-line-height-sm, 1.45);
162
+ margin-block: 0;
163
+ min-inline-size: 0;
164
+ padding-block: var(--_section-inset-block);
165
+ /* The heading takes the row's own inline inset — the control padding scale,
166
+ not a space step — so the group's name and the titles under it stand in
167
+ one column. Reading a different scale left the two a pixel apart. */
168
+ padding-inline: var(--_row-inset-inline);
169
+ }
170
+
171
+ /**
172
+ * `inset` is for a list dropped into a box that already pads its own content
173
+ * — a `card` body, a `dialog`. It takes the row's inline padding away so the
174
+ * content lines up with the box around it, and the heading gives up the same
175
+ * padding so the column holds.
176
+ *
177
+ * The fill and the rule still run edge to edge, which is the half MUI's
178
+ * `disableGutters` leaves out: it removes the padding and leaves the line
179
+ * inset, so a flush list draws a rule stopping short of the box it is in.
180
+ */
181
+ [data-ui='list'][data-inset] [data-part='section-label'],
182
+ [data-ui='list'][data-inset] [data-part='empty'] {
183
+ padding-inline: 0;
184
+ }
185
+
186
+ /**
187
+ * A heading that stays while its own rows scroll past. MUI ships it and is
188
+ * the only surveyed source that does; composing it needs the family's ground
189
+ * and its stack level, and a consumer writing `position: sticky` alone gets a
190
+ * heading with rows showing through it.
191
+ *
192
+ * The ground is the set's surface rather than `transparent`, and the stack
193
+ * level is the library's own sticky step, so a heading never rises above an
194
+ * overlay that is above the page.
195
+ */
196
+ [data-ui='list'] [data-part='section-label'][data-sticky] {
197
+ background-color: var(--_surface);
198
+ inset-block-start: 0;
199
+ position: sticky;
200
+ z-index: var(--slotted-z-index-sticky, 100);
201
+ }
202
+
203
+ /**
204
+ * What the set says when it holds nothing. It is an `li`, so the reader hears
205
+ * "list, one item" and then the message; a message outside the `ul` leaves
206
+ * them with "list, zero items" and silence, and leaves the words outside the
207
+ * box a framed set paints.
208
+ *
209
+ * The family supplies the box, the height and the muted ink. The words are
210
+ * the page's, and `result-state` is what goes in here.
211
+ */
212
+ [data-ui='list'] [data-part='empty'] {
213
+ align-items: center;
214
+ color: var(--_empty-color);
215
+ display: flex;
216
+ flex-direction: column;
217
+ justify-content: center;
218
+ min-inline-size: 0;
219
+ padding-block: var(--_empty-inset);
220
+ padding-inline: var(--_row-inset-inline);
221
+ text-align: center;
222
+ }
223
+
224
+ /**
225
+ * ── Loading ────────────────────────────────────────────────────────────
226
+ *
227
+ * The binding writes `aria-busy="true"`, which ARIA 1.2 section 5.2.6 asks of
228
+ * a container whose required owned elements have not arrived yet. That is the
229
+ * capability; the picture is the page's.
230
+ *
231
+ * The family draws no spinner and no placeholder row. `skeleton` owns
232
+ * placeholder geometry and `progress-indicator` owns a spinner, and a second
233
+ * answer to either question is what `collapsible` already refused for a
234
+ * loading panel. What is left for the set is the pointer, which is the one
235
+ * signal that belongs to the box rather than to its content.
236
+ */
237
+ [data-ui='list'][data-part='root'][data-loading] {
238
+ cursor: progress;
239
+ }
240
+ }
@@ -0,0 +1,42 @@
1
+ [
2
+ "--slotted-border-subtle",
3
+ "--slotted-border-width-thin",
4
+ "--slotted-control-padding-inline-lg",
5
+ "--slotted-control-padding-inline-md",
6
+ "--slotted-control-padding-inline-sm",
7
+ "--slotted-font-size-xs",
8
+ "--slotted-font-weight-semibold",
9
+ "--slotted-line-height-sm",
10
+ "--slotted-list-background",
11
+ "--slotted-list-border-color",
12
+ "--slotted-list-border-width",
13
+ "--slotted-list-empty-color",
14
+ "--slotted-list-empty-padding",
15
+ "--slotted-list-empty-padding-lg",
16
+ "--slotted-list-empty-padding-sm",
17
+ "--slotted-list-gap",
18
+ "--slotted-list-gap-lg",
19
+ "--slotted-list-gap-sm",
20
+ "--slotted-list-padding-inline",
21
+ "--slotted-list-padding-inline-lg",
22
+ "--slotted-list-padding-inline-sm",
23
+ "--slotted-list-radius",
24
+ "--slotted-list-section-color",
25
+ "--slotted-list-section-font-size",
26
+ "--slotted-list-section-font-weight",
27
+ "--slotted-list-section-letter-spacing",
28
+ "--slotted-list-section-padding-block",
29
+ "--slotted-list-section-padding-block-lg",
30
+ "--slotted-list-section-padding-block-sm",
31
+ "--slotted-radius-md",
32
+ "--slotted-space-2",
33
+ "--slotted-space-3",
34
+ "--slotted-space-4",
35
+ "--slotted-space-5",
36
+ "--slotted-space-6",
37
+ "--slotted-space-8",
38
+ "--slotted-space-9",
39
+ "--slotted-surface",
40
+ "--slotted-text-muted",
41
+ "--slotted-z-index-sticky"
42
+ ]