@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.
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,490 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── The key cap ────────────────────────────────────────────────────────
4
+ *
5
+ * One key of a keyboard, drawn so a reader can find it on theirs. It is not a
6
+ * control: nothing here is focusable, nothing answers hover, and nothing
7
+ * binds a shortcut.
8
+ *
9
+ * Two attributes on every selector, always. `shortcut` is the part that
10
+ * contains this family's own roots rather than sitting inside one — the shape
11
+ * `badge` proved with `anchor` — so it carries `data-ui` itself and the pair
12
+ * is what tells a whole combination from one key of it.
13
+ *
14
+ * The height is a step of a scale, never a sum of what is inside. A key cap
15
+ * whose height followed its legend drew `⌘` taller than `Esc` (K1), and a
16
+ * cap whose height followed its variant drew a `raised` key one pixel taller
17
+ * than an `outline` one beside it (25.19 against 24.19). Every size states
18
+ * one whole-pixel height, and every legend and every variant fits inside it.
19
+ * The same length is the minimum inline size, which is what makes a
20
+ * one-letter cap square instead of a slot.
21
+ */
22
+ [data-ui='kbd'] {
23
+ /**
24
+ * The height comes from the space scale — 16, 20, 24, 28 — and not from
25
+ * the control geometry. A cap on its own is a glyph box, not a control,
26
+ * and the inner-size steps (22, 24, 28) leave no room below `sm` for the
27
+ * key a caption or a tooltip needs. The type still comes from the control
28
+ * scale, the one that moves with density, so a dense page draws a smaller
29
+ * legend inside the same box.
30
+ */
31
+ --_size: var(--slotted-space-8, 1.5rem);
32
+ --_font-size: var(--slotted-control-font-size-md, 13px);
33
+ --_inset-inline: var(--slotted-space-3, 0.375rem);
34
+ --_radius: var(--slotted-kbd-radius, var(--slotted-radius-md, 6px));
35
+ --_gap: var(--slotted-space-2, 0.25rem);
36
+
37
+ /**
38
+ * The rim, and the edge the face sits above.
39
+ *
40
+ * `raised` draws its bottom edge as a thicker border rather than as a
41
+ * shadow. Chrome drops `box-shadow` outright under `forced-colors: active`
42
+ * — measured while `badge` was built — so a key made of a shadow is a flat
43
+ * key exactly where the reader most needs the affordance. A border
44
+ * survives, and a face sitting a pixel above its own bottom edge is what
45
+ * a keycap looks like anyway. The thicker edge sits inside the stated
46
+ * height: it lifts the legend half a pixel and never grows the cap.
47
+ */
48
+ --_edge-width: var(--slotted-kbd-border-width, var(--slotted-border-width-thin, 1px));
49
+ --_base-width: var(--_edge-width);
50
+
51
+ /**
52
+ * Inside a control — a shortcut hint at the end of a search field — the
53
+ * cap is the height the foundation gives the inside of a control,
54
+ * `--slotted-control-inner-size`, which the field writes on its adornment
55
+ * from its own size step. On its own the cap keeps its size step. A
56
+ * 24-pixel cap sat in a 26-pixel field at dense before this
57
+ * (`docs/token-foundation.md`, Control geometry).
58
+ */
59
+ --_block-size: var(--slotted-control-inner-size, var(--_size));
60
+
61
+ /**
62
+ * The ground, the rim and the ink. `raised` is the default: the rim a
63
+ * control draws on three sides, and `--slotted-border-strong` below, the
64
+ * one border token the theme holds to 3:1 against the surface. The strong
65
+ * edge on all four sides was a frame drawn round a word; on the base alone
66
+ * it is the shadow a key casts, and it is still the signal that says the
67
+ * word inside is a key.
68
+ */
69
+ --_background: var(--slotted-surface-raised, Canvas);
70
+ --_face: none;
71
+ --_border: var(--slotted-control-border-color, ButtonBorder);
72
+ --_base: var(--slotted-border-strong, ButtonBorder);
73
+ --_color: var(--slotted-text, CanvasText);
74
+ }
75
+
76
+ [data-ui='kbd'][data-part='root'] {
77
+ background-color: var(--_background);
78
+ background-image: var(--_face);
79
+ /**
80
+ * The height the family states, not the height the legend asks for. A key
81
+ * is a cap of a fixed size with a symbol drawn on it, and a row of caps
82
+ * whose tops disagree by three pixels is a row of caps of different keys.
83
+ */
84
+ block-size: var(--_block-size);
85
+ border: var(--_edge-width) solid var(--_border);
86
+ border-block-end: var(--_base-width) solid var(--_base);
87
+ border-radius: var(--_radius);
88
+ box-sizing: border-box;
89
+ color: var(--_color);
90
+ /**
91
+ * One cell, and the legend centred in it on both axes. A grid of one cell
92
+ * centres what is inside it against the cell rather than against the line
93
+ * box the text opened, which is the half of the fix that keeps a symbol
94
+ * from sitting low once the box stops following it.
95
+ */
96
+ display: inline-grid;
97
+ /**
98
+ * The interface face, the one the label beside the key is set in. The
99
+ * monospaced face drew `Backspace` 70.45px wide against the interface
100
+ * face's narrower word, and it does not carry `⌘ ⇧ ⌥ ↩ ⌫`, so every
101
+ * modifier came from a second face and a cap held two typefaces. Equal
102
+ * advance, the one thing a monospaced legend gave, the square minimum
103
+ * width already gives a one-letter key, and `tabular-nums` gives figures.
104
+ */
105
+ font-family: var(--slotted-kbd-font-family, var(--slotted-control-font-family, sans-serif));
106
+ font-size: var(--_font-size);
107
+ /* A shortcut that counts — `⌘1` to `⌘9` — must not jitter as the figure
108
+ changes, which is the rule `badge` applies to its own count. */
109
+ font-variant-numeric: tabular-nums;
110
+ font-weight: var(--slotted-kbd-font-weight, var(--slotted-font-weight-medium, 500));
111
+ /**
112
+ * The legend's own line box is the em box and nothing more. Leading is what
113
+ * a fallback font varies — the strut and the glyph's own box are aligned on
114
+ * the baseline and each carries half of its font's leading — so a line box
115
+ * that stops at 1 is a line box no substituted glyph can grow. The air
116
+ * around the legend is the stated height less the em box, and it belongs
117
+ * to the cap, not to the legend.
118
+ */
119
+ line-height: 1;
120
+ min-inline-size: var(--_block-size);
121
+ place-items: center;
122
+ /* The stated height holds the air; the cell centres the legend in it. */
123
+ padding-block: 0;
124
+ padding-inline: var(--_inset-inline);
125
+ /**
126
+ * A key label is never truncated. Half a key name is a wrong instruction,
127
+ * where a wrapped shortcut is only a taller row — so the cap keeps its word
128
+ * whole and the combination around it is what breaks.
129
+ */
130
+ white-space: nowrap;
131
+ /* Written inside a sentence, a key sits on the text's centre. */
132
+ vertical-align: middle;
133
+ /**
134
+ * The one state pair this family has. A menu row that becomes unavailable
135
+ * fades; a cap inside it that snapped would be the only thing on the row
136
+ * that moved instantly. Nothing else here animates, and there is no looping
137
+ * animation to stop under reduced motion.
138
+ */
139
+ transition:
140
+ background-color var(--slotted-control-transition-duration)
141
+ var(--slotted-control-transition-easing),
142
+ border-color var(--slotted-control-transition-duration)
143
+ var(--slotted-control-transition-easing),
144
+ color var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
145
+ }
146
+
147
+ /* ── The word, and the word behind it ──────────────────────────────────── */
148
+
149
+ /**
150
+ * The legend has a box of its own, as the words do in `button` and `badge`,
151
+ * and that box is what makes the family's one typographic problem solvable.
152
+ *
153
+ * The cell centres the *line box*, and a line box is not symmetric around the
154
+ * letters inside it: the ascender reaches further above the cap than the
155
+ * descender reaches below the baseline. `text-box` trims the line to
156
+ * the cap and the baseline, so what is centred is the ink rather than the
157
+ * font's metrics, and `K`, `Esc` and `Página` all sit the same way.
158
+ *
159
+ * It is applied here rather than on the root because `text-box-trim` needs a
160
+ * block container and a grid container has none: its own text lives in an
161
+ * anonymous item no selector can reach.
162
+ *
163
+ * No clip region is involved, which is what makes this simpler than the same
164
+ * rule in `badge`: `⌘`, `↑` and a descender all reach outside a box trimmed
165
+ * to the cap and the baseline, and here they paint into the inset instead of
166
+ * being cut off. The block size is still computed from the untrimmed metrics,
167
+ * so the trim moves the ink and never the box.
168
+ */
169
+ @supports (text-box: trim-both cap alphabetic) {
170
+ [data-ui='kbd'] [data-part='legend'] {
171
+ text-box: trim-both cap alphabetic;
172
+ }
173
+
174
+ /**
175
+ * A mark is not trimmed, and this is the half of the rule that had to be
176
+ * looked at rather than reasoned out. `cap alphabetic` are Latin metrics: a
177
+ * box trimmed to them centres the cap band, and `⌘`, `↩` and `⌫` have no
178
+ * relation to a cap height or an alphabetic baseline — measured here, all
179
+ * three sat visibly high in the cap. Left untrimmed, what gets centred is
180
+ * the em box, which is where a mark is drawn.
181
+ */
182
+ [data-ui='kbd'] [data-part='legend'][data-legend='symbol'] {
183
+ text-box: normal;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * The interface face for a mark, whatever face the legend is set in. A
189
+ * consumer who sets `--slotted-kbd-font-family` to a monospaced face keeps
190
+ * `⌘ ⇧ ⌥ ↩ ⌫` at the weight of the interface type: measured with the
191
+ * monospaced legend, every mark rendered thinner and smaller than `Esc` in the
192
+ * same cap. A tenth larger than the legend: at 1em `⌘` and `↵` stood
193
+ * below the cap height of `K`, and at 1.15em `⌫` stood wider than the
194
+ * `Esc` beside it.
195
+ */
196
+ [data-ui='kbd'] [data-part='legend'][data-legend='symbol'] {
197
+ font-family: var(--slotted-kbd-symbol-font-family, var(--slotted-font-family-sans, sans-serif));
198
+ font-size: 1.1em;
199
+ }
200
+
201
+ /**
202
+ * What a reader hears in place of a symbol. It is content rather than a
203
+ * label because ARIA in HTML maps `kbd` to no role and declares it Naming
204
+ * Prohibited, so `aria-label` is not available to this family at all.
205
+ *
206
+ * The rule is `visually-hidden`'s, restated here rather than depended on: a
207
+ * key cap must not reserve a millimetre for a word nobody sees, and a family
208
+ * whose accessible name disappears when a consumer forgets an import has no
209
+ * accessible name.
210
+ */
211
+ [data-ui='kbd'] [data-part='name'] {
212
+ block-size: 1px;
213
+ border: 0;
214
+ clip-path: inset(50%);
215
+ inline-size: 1px;
216
+ margin: -1px;
217
+ overflow: hidden;
218
+ padding: 0;
219
+ position: absolute;
220
+ white-space: nowrap;
221
+ }
222
+
223
+ /* ── The whole combination ─────────────────────────────────────────────── */
224
+
225
+ /**
226
+ * `direction: ltr`, and it is the deliberate part of this rule.
227
+ *
228
+ * A combination is one formula. The bidi algorithm renders `Ctrl + K` inside
229
+ * an Arabic paragraph as a single left-to-right run, which is also what
230
+ * macOS and Windows show in a right-to-left locale, so a mirrored `K + ⌘` is
231
+ * a shortcut no operating system displays. The combination as a whole still
232
+ * sits where the paragraph puts it; only the order of the caps inside it is
233
+ * pinned. A key legend written in Arabic still renders right-to-left within
234
+ * its own cap, because that is a run of its own.
235
+ */
236
+ [data-ui='kbd'][data-part='shortcut'] {
237
+ align-items: center;
238
+ direction: ltr;
239
+ display: inline-flex;
240
+ /**
241
+ * A shortcut wider than its column wraps between caps and never inside
242
+ * one. The row gets taller; no instruction gets shorter.
243
+ */
244
+ flex-wrap: wrap;
245
+ gap: var(--_gap);
246
+ /**
247
+ * Without this the wrapping above is only ever a coincidence. An
248
+ * `inline-flex` box is sized by its content, so a five-key combination in a
249
+ * 360-pixel column simply ran out of it — the wrap happened where the
250
+ * container narrowed the box and nowhere else. Read at 1280 in a measured
251
+ * column, `Win + Ctrl + Alt + Shift + Backspace` overflowed its stage on
252
+ * one line.
253
+ */
254
+ max-inline-size: 100%;
255
+ vertical-align: middle;
256
+ }
257
+
258
+ /**
259
+ * A Mac joins with nothing, so the gap is the only thing holding the
260
+ * combination together — and at the shared step it was exactly the width of
261
+ * the space between two separate shortcuts on the same line, which made
262
+ * `⌥⇧⌘P` and `⌘K` read as one run of six keys. One step tighter is what says
263
+ * these caps are one shortcut. Everywhere else the `+` says it instead.
264
+ */
265
+ [data-ui='kbd'][data-part='shortcut'][data-platform='mac'] {
266
+ --_gap: var(--slotted-space-1, 0.125rem);
267
+ }
268
+
269
+ [data-ui='kbd'][data-part='shortcut'][data-platform='mac'][data-size='inherit'] {
270
+ --_gap: 0.125em;
271
+ }
272
+
273
+ /**
274
+ * `+` between two keys pressed together, and the word between two steps of a
275
+ * sequence. The plus is hidden from assistive technology — it is punctuation
276
+ * joining two caps, and “Command Shift K” is what the operating systems
277
+ * announce for the same shortcut. The word is not hidden: it is the only
278
+ * thing that tells a sequence from a combination.
279
+ */
280
+ [data-ui='kbd'] [data-part='separator'] {
281
+ color: var(--slotted-text-muted, GrayText);
282
+ flex: none;
283
+ font-family: var(--slotted-kbd-font-family, var(--slotted-control-font-family, sans-serif));
284
+ font-size: var(--_font-size);
285
+ line-height: 1;
286
+ }
287
+
288
+ [data-ui='kbd'] [data-part='separator'][data-separator='then'] {
289
+ font-family: var(--slotted-control-font-family, sans-serif);
290
+ /**
291
+ * A step boundary is a bigger break than a key join, so it gets more air
292
+ * than the plus does. Read at the shared gap, `Ctrl + K then Ctrl + S` was
293
+ * four caps in a row with a word somewhere in it.
294
+ */
295
+ padding-inline: var(--slotted-space-2, 0.25rem);
296
+ }
297
+
298
+ /* ── Size ──────────────────────────────────────────────────────────────── */
299
+
300
+ /**
301
+ * Four absolute steps, 16 to 28 pixels in steps of four, and one relative
302
+ * step. The radius is a quarter of the height or near it (4/16, 6/20, 6/24,
303
+ * 8/28), so a small cap is as round as a large one and not a pill.
304
+ *
305
+ * `xs` is the cap a caption, a tooltip or a dense table cell needs, where a
306
+ * 20-pixel key stood taller than the 12-pixel line it sat in. The type
307
+ * scale starts at 12px, and 12px in a 16-pixel cap left one pixel of air
308
+ * above an ascender, so this step writes the one size the scale lacks.
309
+ */
310
+ [data-ui='kbd'][data-size='xs'] {
311
+ --_size: var(--slotted-space-6, 1rem);
312
+ --_font-size: 0.6875rem;
313
+ --_inset-inline: var(--slotted-space-2, 0.25rem);
314
+ --_radius: var(--slotted-kbd-radius, var(--slotted-radius-sm, 4px));
315
+ --_gap: var(--slotted-space-1, 0.125rem);
316
+ }
317
+
318
+ [data-ui='kbd'][data-size='sm'] {
319
+ --_size: var(--slotted-space-7, 1.25rem);
320
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
321
+ --_inset-inline: var(--slotted-space-2, 0.25rem);
322
+ }
323
+
324
+ [data-ui='kbd'][data-size='lg'] {
325
+ --_size: calc(var(--slotted-space-8, 1.5rem) + var(--slotted-space-2, 0.25rem));
326
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
327
+ --_inset-inline: var(--slotted-space-4, 0.5rem);
328
+ --_radius: var(--slotted-kbd-radius, var(--slotted-radius-lg, 8px));
329
+ }
330
+
331
+ /**
332
+ * The step no surveyed implementation ships, and the one prose needs. Every
333
+ * absolute size makes a key inside an `h2` a stamp and one in fine print a
334
+ * slab; here the cap is a proportion of the text it interrupts, so it is the
335
+ * right size in both. The insets go with it, in the same relative unit, or a
336
+ * large key would carry a small key's padding.
337
+ *
338
+ * The height is 1.5 of the legend, which is 1.2 of the surrounding text: it
339
+ * stays inside a line box of 1.3 or more, so a key in a paragraph never
340
+ * pushes its line away from the next one. The previous sum, legend line plus
341
+ * insets plus edges, made 25.8px on 16px text set at 24px lines. The radius
342
+ * is a quarter of that height, the proportion of the absolute steps.
343
+ */
344
+ [data-ui='kbd'][data-size='inherit'] {
345
+ --_size: 1.5em;
346
+ --_font-size: 0.8em;
347
+ --_inset-inline: 0.4em;
348
+ --_radius: var(--slotted-kbd-radius, 0.375em);
349
+ --_gap: 0.25em;
350
+ }
351
+
352
+ /* A fractional height puts both horizontal edges between pixels. */
353
+ @supports (inline-size: round(nearest, 1.5em, 1px)) {
354
+ [data-ui='kbd'][data-size='inherit'] {
355
+ --_size: round(nearest, 1.5em, 1px);
356
+ }
357
+ }
358
+
359
+ /* ── Painting ──────────────────────────────────────────────────────────── */
360
+
361
+ /**
362
+ * The bottom edge is the whole of the difference between a raised key and an
363
+ * outlined one, and it is why `raised` is the default: it is the only value
364
+ * that reads as an object rather than as a box drawn round a word.
365
+ */
366
+ [data-ui='kbd'][data-variant='raised'] {
367
+ --_base-width: var(--slotted-kbd-base-width, var(--slotted-border-width-thick, 2px));
368
+ /**
369
+ * The skirt. The lower part of the face turns a tenth of the way toward
370
+ * the base colour, so the face runs into the thick edge instead of meeting
371
+ * it at a line: `#ffffff` to `#f1f3f6` in light, `#171719` to `#202023` in
372
+ * dark. The top 40% stays the flat face, which is where the legend's cap
373
+ * band sits. A gradient is an image, so forced colours drop it with the
374
+ * ground and leave the edges, which is the whole key there.
375
+ */
376
+ --_face: linear-gradient(
377
+ to bottom,
378
+ var(--_background) 40%,
379
+ color-mix(in oklab, var(--_background), var(--_base) 10%)
380
+ );
381
+ }
382
+
383
+ /**
384
+ * No ground of its own, so it carries over any surface the page puts under
385
+ * it — a card, a sunken panel, a solid banner.
386
+ *
387
+ * And no ink of its own either, which is the half that had to be looked at.
388
+ * Read on `--slotted-surface-inverse`, an outlined key kept `--slotted-text`
389
+ * and was near-black type on a near-black ground: the variant that exists to
390
+ * survive an unknown surface was the one variant that could not. A box that
391
+ * borrows its ground borrows its foreground with it.
392
+ */
393
+ [data-ui='kbd'][data-variant='outline'] {
394
+ --_background: transparent;
395
+ /* The edge is all this variant draws, so it is the strong one all round. */
396
+ --_border: var(--slotted-border-strong, ButtonBorder);
397
+ --_color: inherit;
398
+ }
399
+
400
+ /**
401
+ * The tinted chip, painted from the neutral tone rather than from a surface
402
+ * token. `--slotted-surface-sunken` is the page's own colour on a sunken
403
+ * panel, where a key painted with it would disappear; the neutral tone's
404
+ * surface is the step `badge` calibrated to read on both.
405
+ */
406
+ [data-ui='kbd'][data-variant='soft'] {
407
+ --_background: var(--slotted-tone-secondary-surface);
408
+ /**
409
+ * The tinted key draws the tone's own edge, as every `badge` variant does,
410
+ * and it is not decoration here either. In the `high-contrast` scheme the
411
+ * neutral surface is the page's own white: read in that scheme with no
412
+ * edge, the chip was gone outright and `Ctrl + B` was a run of text. The
413
+ * edge is also what carries it through forced colours, where the ground
414
+ * flattens to `Canvas` for the same reason.
415
+ */
416
+ --_border: var(--slotted-tone-secondary-border);
417
+ --_base: var(--slotted-tone-secondary-border);
418
+ --_color: var(--slotted-tone-secondary-text);
419
+ }
420
+
421
+ /**
422
+ * A key that is only its word. In a dense menu a column of boxes is noise,
423
+ * and the shortcut there is what macOS and VS Code both draw: muted type, no
424
+ * frame, nothing between it and the row it belongs to.
425
+ */
426
+ /**
427
+ * A key that is only its word, and it takes the colour of the text it sits
428
+ * in rather than choosing one. React Spectrum's `Keyboard` is the surveyed
429
+ * implementation that gets this right — it “provides no specific styling by
430
+ * itself, but receives styling from the parent container” — and inheriting is
431
+ * also what makes the row work: a menu item that dims dims its shortcut with
432
+ * it, with no state to set and nothing left bright at the end of a grey row.
433
+ */
434
+ [data-ui='kbd'][data-variant='plain'] {
435
+ --_background: transparent;
436
+ --_border: transparent;
437
+ --_base: transparent;
438
+ --_color: inherit;
439
+ }
440
+
441
+ [data-ui='kbd'][data-part='root'][data-variant='plain'] {
442
+ min-inline-size: 0;
443
+ padding-inline: 0;
444
+ }
445
+
446
+ /* ── Disabled ──────────────────────────────────────────────────────────── */
447
+
448
+ /**
449
+ * Presentational only, and the strongest state this family has — there is no
450
+ * hover and no press for it to hold itself back for. The item the shortcut
451
+ * belongs to owns the semantics: `kbd` may carry only the global ARIA
452
+ * attributes, and `aria-disabled` is not one of them.
453
+ */
454
+ [data-ui='kbd'][data-disabled] {
455
+ --_background: var(--slotted-disabled-background, Canvas);
456
+ --_face: none;
457
+ --_border: var(--slotted-disabled-border, GrayText);
458
+ --_base: var(--slotted-disabled-border, GrayText);
459
+ --_color: var(--slotted-disabled-foreground, GrayText);
460
+ }
461
+
462
+ [data-ui='kbd'][data-disabled] [data-part='separator'] {
463
+ color: var(--slotted-disabled-foreground, GrayText);
464
+ }
465
+
466
+ /**
467
+ * The two variants that own no ground keep owning none. A disabled `outline`
468
+ * that filled itself grey would be a grey rectangle on whatever surface it
469
+ * was placed over, which is the one thing the variant exists to avoid.
470
+ */
471
+ [data-ui='kbd'][data-variant='outline'][data-disabled],
472
+ [data-ui='kbd'][data-variant='plain'][data-disabled] {
473
+ --_background: transparent;
474
+ }
475
+
476
+ [data-ui='kbd'][data-variant='plain'][data-disabled] {
477
+ --_border: transparent;
478
+ --_base: transparent;
479
+ }
480
+
481
+ /**
482
+ * This family writes no `forced-colors` rule, and the reason is worth
483
+ * recording because it was nearly written twice. Every ground it paints is a
484
+ * token the theme already remaps — `--slotted-surface-raised` to `Canvas`,
485
+ * the neutral tone's surface to `Canvas` — and every edge it draws is a
486
+ * border token remapped to `CanvasText` or `ButtonBorder`. There is no filled
487
+ * variant whose edge is its own fill, which is the case `badge` had to write
488
+ * a rule for. Nothing here is painted with anything the theme cannot reach.
489
+ */
490
+ }
@@ -0,0 +1,40 @@
1
+ [
2
+ "--slotted-border-strong",
3
+ "--slotted-border-width-thick",
4
+ "--slotted-border-width-thin",
5
+ "--slotted-control-border-color",
6
+ "--slotted-control-font-family",
7
+ "--slotted-control-font-size-lg",
8
+ "--slotted-control-font-size-md",
9
+ "--slotted-control-font-size-sm",
10
+ "--slotted-control-inner-size",
11
+ "--slotted-control-transition-duration",
12
+ "--slotted-control-transition-easing",
13
+ "--slotted-disabled-background",
14
+ "--slotted-disabled-border",
15
+ "--slotted-disabled-foreground",
16
+ "--slotted-font-family-sans",
17
+ "--slotted-font-weight-medium",
18
+ "--slotted-kbd-base-width",
19
+ "--slotted-kbd-border-width",
20
+ "--slotted-kbd-font-family",
21
+ "--slotted-kbd-font-weight",
22
+ "--slotted-kbd-radius",
23
+ "--slotted-kbd-symbol-font-family",
24
+ "--slotted-radius-lg",
25
+ "--slotted-radius-md",
26
+ "--slotted-radius-sm",
27
+ "--slotted-space-1",
28
+ "--slotted-space-2",
29
+ "--slotted-space-3",
30
+ "--slotted-space-4",
31
+ "--slotted-space-6",
32
+ "--slotted-space-7",
33
+ "--slotted-space-8",
34
+ "--slotted-surface-raised",
35
+ "--slotted-text",
36
+ "--slotted-text-muted",
37
+ "--slotted-tone-secondary-border",
38
+ "--slotted-tone-secondary-surface",
39
+ "--slotted-tone-secondary-text"
40
+ ]