@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,462 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── The badge box ──────────────────────────────────────────────────────
4
+ *
5
+ * A short, non-editable piece of metadata: a count, a status, a label. It is
6
+ * never a command, so it answers no hover and gives no press feedback.
7
+ *
8
+ * Two attributes on every selector, always. `anchor` is the one part in the
9
+ * library that contains its family's root instead of sitting inside it, so it
10
+ * carries `data-ui` itself and the pair is what tells the frame from the box.
11
+ *
12
+ * There is no height token. The block size is the badge's own line box plus a
13
+ * symmetric inset from the space scale, so a badge never disagrees with the
14
+ * type it contains and no density can leave it clipped. `--_block-size`
15
+ * restates that sum for the two places that need it as a number: the minimum
16
+ * that keeps an icon-only badge the same height as a text one, and the
17
+ * minimum inline size that makes a one-figure pill a circle.
18
+ */
19
+ [data-ui='badge'][data-part='root'] {
20
+ /**
21
+ * Tone. The default is the one a badge carrying a value should speak in: a
22
+ * badge with no tone stated is holding a number, not an opinion.
23
+ *
24
+ * The neutral fill is the tone's `solid-hover` step rather than its
25
+ * `solid` one. `solid` is the same colour as `surface` in all three
26
+ * schemes, so a filled neutral badge and a tinted one were the same
27
+ * rectangle, and neither of them read as filled. One step down the tone's
28
+ * own ramp — 1.48:1 against the light surface where `solid` is 1.23:1,
29
+ * 1.78:1 in `dark` where it is 1.25:1 — is a chip the eye finds without
30
+ * becoming an announcement.
31
+ */
32
+ --_solid: var(--slotted-tone-secondary-solid-hover);
33
+ --_on-solid: var(--slotted-tone-secondary-on-solid);
34
+ --_surface: var(--slotted-tone-secondary-surface);
35
+ --_border: var(--slotted-tone-secondary-border);
36
+ --_text: var(--slotted-tone-secondary-text);
37
+ /**
38
+ * What a filled badge draws around itself, and for four of the five tones
39
+ * the answer is nothing: the edge is the fill, so there is no rim. A rim on
40
+ * a filled chip reads as a second, quieter chip drawn behind the first.
41
+ *
42
+ * `secondary` is the exception, and it is the only one. Its fill is
43
+ * `#e6e6e6` against the page's own white in `high-contrast` — 1.25:1 — so a
44
+ * filled neutral badge with no edge is not a badge there, it is a run of
45
+ * text. Every other tone carries its own boundary: 6.70, 5.02 and 4.83 in
46
+ * `light`, 9 to 10 in `high-contrast`, and `warning` is chromatic rather
47
+ * than luminous at 1.53 but unmistakably yellow on white.
48
+ */
49
+ --_edge: var(--_solid);
50
+
51
+ /**
52
+ * Size. Type and glyph come from the control scale, which is the only scale
53
+ * that moves with density, so a badge shrinks beside the controls it sits
54
+ * with. Inset and gap come from the space scale: a density step inside an
55
+ * inset this small would be sub-pixel, and density moves the type, which
56
+ * moves the box.
57
+ */
58
+ --_font-size: var(--slotted-control-font-size-md, 13px);
59
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
60
+ --_inset-block: var(--slotted-space-1, 0.125rem);
61
+ --_inset-inline: var(--slotted-space-4, 0.5rem);
62
+ --_gap: var(--slotted-space-2, 0.25rem);
63
+ /**
64
+ * The disc is as wide as the type it stands beside, rather than a step of
65
+ * the space scale chosen for it. Two readings of the harness produced the
66
+ * rule: at six pixels the 3:1 rim left four pixels of tone and every small
67
+ * dot read as dark rather than as its own colour, and at a free sixteen the
68
+ * large dot stood taller than the fourteen-pixel words next to it. A mark
69
+ * that accompanies text is the height of that text, it can never outgrow
70
+ * it, and it answers density without a third scale saying how.
71
+ */
72
+ --_dot-size: var(--_font-size);
73
+
74
+ --_line-height: var(--slotted-line-height-xs, 1.4);
75
+ --_edge-width: var(--slotted-badge-border-width, var(--slotted-border-width-thin, 1px));
76
+ --_block-size: calc(
77
+ var(--_font-size) * var(--_line-height) + 2 * var(--_inset-block) + 2 * var(--_edge-width)
78
+ );
79
+
80
+ align-items: center;
81
+ border: var(--_edge-width) solid transparent;
82
+ border-radius: var(--slotted-radius-full, 9999px);
83
+ box-sizing: border-box;
84
+ display: inline-flex;
85
+ font-family: var(--slotted-badge-font-family, var(--slotted-control-font-family, sans-serif));
86
+ font-size: var(--_font-size);
87
+ /**
88
+ * A count that ticks 8 → 9 → 10 grows by one figure width instead of
89
+ * jittering on every digit, because every figure is the same width.
90
+ */
91
+ font-variant-numeric: tabular-nums;
92
+ font-weight: var(--slotted-badge-font-weight, var(--slotted-font-weight-medium, 500));
93
+ gap: var(--_gap);
94
+ justify-content: center;
95
+ line-height: var(--_line-height);
96
+ /**
97
+ * One line, always. A badge holds a count, a status or a short piece of
98
+ * metadata, and a badge that reflows into a paragraph has stopped being
99
+ * one — the length is the content's error, and the family reports it rather
100
+ * than absorbing it. `tag` holds an entity's name and will answer the same
101
+ * question for itself.
102
+ *
103
+ * The clipping is visual only: `text-overflow` shortens nothing, so the
104
+ * whole string stays in the DOM, stays in the accessibility tree, and a
105
+ * page search still finds it. That is what the briefing's rule protects —
106
+ * it forbids removing content, not clipping it.
107
+ */
108
+ max-inline-size: 100%;
109
+ min-block-size: var(--_block-size);
110
+ min-inline-size: var(--_block-size);
111
+ padding-block: var(--_inset-block);
112
+ padding-inline: var(--_inset-inline);
113
+ /**
114
+ * `render` can make the root an `<a>`, and a rule the browser writes on
115
+ * every anchor would put a line under the words inside a pill. The chip is
116
+ * the affordance; the underline belongs to `link`, on a link.
117
+ */
118
+ text-decoration: none;
119
+ /* Written inside a sentence, a badge sits on the text's centre. */
120
+ vertical-align: middle;
121
+ white-space: nowrap;
122
+ }
123
+
124
+ /* ── Tone: which of the five semantic colours the badge speaks in ─────── */
125
+
126
+ [data-ui='badge'][data-part='root'][data-tone='secondary'] {
127
+ --_edge: var(--_border);
128
+ }
129
+
130
+ [data-ui='badge'][data-part='root'][data-tone='accent'] {
131
+ --_solid: var(--slotted-tone-accent-solid);
132
+ --_on-solid: var(--slotted-tone-accent-on-solid);
133
+ --_surface: var(--slotted-tone-accent-surface);
134
+ --_border: var(--slotted-tone-accent-border);
135
+ --_text: var(--slotted-tone-accent-text);
136
+ }
137
+
138
+ [data-ui='badge'][data-part='root'][data-tone='success'] {
139
+ --_solid: var(--slotted-tone-success-solid);
140
+ --_on-solid: var(--slotted-tone-success-on-solid);
141
+ --_surface: var(--slotted-tone-success-surface);
142
+ --_border: var(--slotted-tone-success-border);
143
+ --_text: var(--slotted-tone-success-text);
144
+ }
145
+
146
+ [data-ui='badge'][data-part='root'][data-tone='warning'] {
147
+ --_solid: var(--slotted-tone-warning-solid);
148
+ --_on-solid: var(--slotted-tone-warning-on-solid);
149
+ --_surface: var(--slotted-tone-warning-surface);
150
+ --_border: var(--slotted-tone-warning-border);
151
+ --_text: var(--slotted-tone-warning-text);
152
+ }
153
+
154
+ [data-ui='badge'][data-part='root'][data-tone='danger'] {
155
+ --_solid: var(--slotted-tone-danger-solid);
156
+ --_on-solid: var(--slotted-tone-danger-on-solid);
157
+ --_surface: var(--slotted-tone-danger-surface);
158
+ --_border: var(--slotted-tone-danger-border);
159
+ --_text: var(--slotted-tone-danger-text);
160
+ }
161
+
162
+ /**
163
+ * ── Variant: three paintings, and only two of them have an edge ────────
164
+ *
165
+ * `solid` fills and draws no rim: its edge is its own fill, so the chip is
166
+ * one shape. `soft` fills with the tone's tinted `surface` role and draws the
167
+ * tone's `border` role around it. `outline` is that edge with nothing behind
168
+ * it. The three read as filled, tinted and outlined rather than as three
169
+ * weights of the same rimmed chip, which is what a shared edge made of them.
170
+ *
171
+ * `soft` keeps its edge for a reason the light scheme hides: in
172
+ * `high-contrast` every tone `surface` collapses to the page's own white, so
173
+ * a tinted badge with no edge is a run of text. There it converges with
174
+ * `outline`, which is what a high-contrast scheme is for.
175
+ *
176
+ * Button reached the opposite conclusion for its own `outline` variant — a
177
+ * neutral edge, with the tone left in the label — because five saturated
178
+ * rectangles in a row of actions read as status chips before they read as
179
+ * words. A badge is a status chip. The two families agree about what a tone
180
+ * border looks like and disagree about which of them should wear it.
181
+ */
182
+
183
+ [data-ui='badge'][data-part='root'][data-variant='solid'] {
184
+ background-color: var(--_solid, ButtonFace);
185
+ border-color: var(--_edge, ButtonFace);
186
+ color: var(--_on-solid, ButtonText);
187
+ }
188
+
189
+ [data-ui='badge'][data-part='root'][data-variant='soft'] {
190
+ background-color: var(--_surface, ButtonFace);
191
+ border-color: var(--_border, ButtonBorder);
192
+ color: var(--_text, ButtonText);
193
+ }
194
+
195
+ [data-ui='badge'][data-part='root'][data-variant='outline'] {
196
+ background-color: transparent;
197
+ border-color: var(--_border, ButtonBorder);
198
+ color: var(--_text, ButtonText);
199
+ }
200
+
201
+ /* ── Size ─────────────────────────────────────────────────────────────── */
202
+
203
+ [data-ui='badge'][data-part='root'][data-size='sm'] {
204
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
205
+ /* `0px` rather than `0`: a unitless zero inside the `--_block-size` sum
206
+ makes the whole calculation invalid, and `min-block-size` silently fell
207
+ back to `auto` for the one size that stated it. */
208
+ --_inset-block: 0px;
209
+ --_inset-inline: var(--slotted-space-3, 0.375rem);
210
+ --_gap: var(--slotted-space-2, 0.25rem);
211
+ }
212
+
213
+ /**
214
+ * The glyph scale has three steps and the badge's own three span less of it,
215
+ * so `sm` and `md` land on the same one. That is the right answer rather than
216
+ * a rounding error: a 12px badge and a 13px badge should not carry visibly
217
+ * different glyphs.
218
+ */
219
+ [data-ui='badge'][data-part='root'][data-size='lg'] {
220
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
221
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
222
+ --_inset-block: var(--slotted-space-2, 0.25rem);
223
+ --_inset-inline: var(--slotted-space-5, 0.75rem);
224
+ --_gap: var(--slotted-space-3, 0.375rem);
225
+ }
226
+
227
+ /* ── Shape ────────────────────────────────────────────────────────────── */
228
+
229
+ [data-ui='badge'][data-part='root'][data-shape='square'] {
230
+ border-radius: var(--slotted-badge-radius, var(--slotted-radius-sm, 4px));
231
+ }
232
+
233
+ /**
234
+ * The mark that carries no value. It is a shape and not a boolean because it
235
+ * is the same badge, the same tone and the same hidden text, drawn without a
236
+ * number.
237
+ *
238
+ * It is also the only badge whose entire meaning is a graphic, so WCAG 2.2
239
+ * 1.4.11 binds its edge rather than merely decorating it. The rim is
240
+ * `--slotted-border-strong`, the one border token the theme holds to 3:1
241
+ * against the surface it separates: a `secondary` dot rimmed with its own
242
+ * tone border would measure 2.56:1 in `light` and 1.78:1 in `dark`.
243
+ *
244
+ * A dot renders no value, so nothing is clipped. Text a consumer forces into
245
+ * one overflows rather than disappearing.
246
+ */
247
+ [data-ui='badge'][data-part='root'][data-shape='dot'] {
248
+ block-size: var(--_dot-size);
249
+ border-color: var(--slotted-badge-dot-border-color, var(--slotted-border-strong, CanvasText));
250
+ border-radius: var(--slotted-radius-full, 9999px);
251
+ inline-size: var(--_dot-size);
252
+ min-block-size: 0;
253
+ min-inline-size: 0;
254
+ padding-block: 0;
255
+ padding-inline: 0;
256
+ }
257
+
258
+ /* ── Focus ────────────────────────────────────────────────────────────── */
259
+
260
+ /**
261
+ * A badge is not focusable on its own. It is painted anyway, because `render`
262
+ * can make the root an `<a>` and a ring that appears only where a family
263
+ * expects focus is a ring that goes missing.
264
+ */
265
+ [data-ui='badge'][data-part='root']:focus-visible {
266
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
267
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
268
+ }
269
+
270
+ /* ── The words, and the glyphs on either side of them ─────────────────── */
271
+
272
+ /**
273
+ * The text has a box of its own, as it does in `button`, and that box is what
274
+ * makes the badge's one real typographic problem solvable.
275
+ *
276
+ * A flex container centres the *line box*, and a line box is not symmetric
277
+ * around the letters inside it: the ascender reaches further above the cap
278
+ * than the descender reaches below the baseline. Measured on this family
279
+ * before the part existed, a word with no descender sat 2.19 pixels high in a
280
+ * 24-pixel badge — six pixels of clearance above the ink and eight below it —
281
+ * while a word with a descender looked correct. `text-box` trims the line box
282
+ * to the cap and the baseline, so what is centred is the ink rather than the
283
+ * font's metrics, and every word sits the same way whatever letters it holds.
284
+ *
285
+ * It is applied here rather than on the root because `text-box-trim` needs a
286
+ * block container and a flex container has none: its text lives in an
287
+ * anonymous item no selector can reach. Measured in Chrome 150 — the
288
+ * declaration on an `inline-block` takes an 18.19-pixel line box to 9, and on
289
+ * an `inline-flex` it does nothing at all.
290
+ */
291
+ /**
292
+ * Where the line is clipped. `min-inline-size: 0` is what lets the box shrink
293
+ * below its content inside the flex root, which is the condition
294
+ * `text-overflow` needs to have anything to do.
295
+ */
296
+ [data-ui='badge'] [data-part='label'] {
297
+ min-inline-size: 0;
298
+ overflow: hidden;
299
+ text-overflow: ellipsis;
300
+ }
301
+
302
+ @supports (text-box: trim-both cap alphabetic) {
303
+ [data-ui='badge'] [data-part='label'] {
304
+ /**
305
+ * A descender and a tall diacritic both live outside a box trimmed to the
306
+ * cap and the baseline, and `overflow: hidden` cut them off — visible in
307
+ * the first capture as a beheaded `g` in `Awaiting`. The padding gives
308
+ * the clip region room for them and the negative margin gives the space
309
+ * straight back, so the box the root centres is still the trimmed one and
310
+ * the badge is the height it was.
311
+ *
312
+ * A proportion of the type rather than a step of any scale: what has to
313
+ * be cleared is the font's own overshoot, and it scales with the font.
314
+ */
315
+ margin-block: -0.3em;
316
+ padding-block: 0.3em;
317
+ text-box: trim-both cap alphabetic;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * The slot sizes what it holds: an icon box reads `--slotted-icon-size`
323
+ * from its container, and a bare glyph host such as `ng-icon` reads the
324
+ * slot's font-size, so both are the glyph scale.
325
+ */
326
+ [data-ui='badge'] [data-part='start'],
327
+ [data-ui='badge'] [data-part='end'] {
328
+ --slotted-icon-size: var(--_icon-size);
329
+
330
+ align-items: center;
331
+ block-size: var(--_icon-size);
332
+ box-sizing: border-box;
333
+ display: inline-flex;
334
+ flex: none;
335
+ font-size: var(--_icon-size);
336
+ inline-size: var(--_icon-size);
337
+ justify-content: center;
338
+ line-height: 1;
339
+ }
340
+
341
+ [data-ui='badge'] [data-part='start'] > *,
342
+ [data-ui='badge'] [data-part='end'] > * {
343
+ block-size: 100%;
344
+ display: block;
345
+ inline-size: 100%;
346
+ }
347
+
348
+ /**
349
+ * ── The frame ──────────────────────────────────────────────────────────
350
+ *
351
+ * What places a badge on the corner of something else. It wraps the host
352
+ * rather than rewriting it: neither binding can safely reach into an element
353
+ * it did not render, and a family that only works when the host is one of the
354
+ * elements it knows is a family that fails silently.
355
+ *
356
+ * `--_dir` is the one physical fact in the sheet. `translate` has no logical
357
+ * form, so the inline half of the overhang is multiplied by the direction the
358
+ * frame is read in. Everything else — which corner, how far in from it — is
359
+ * written in logical insets and mirrors on its own.
360
+ */
361
+ [data-ui='badge'][data-part='anchor'] {
362
+ --_dir: 1;
363
+ /* Half the badge's own size. A proportion of the box rather than a step of
364
+ any scale, which is why it is geometry here and not a token. */
365
+ --_overhang-inline: 50%;
366
+ --_overhang-block: -50%;
367
+ /* How far in from the corner the badge starts. A rectangle overhangs the
368
+ corner itself; a circle's corner is empty, so the badge moves in far
369
+ enough to meet the curve. */
370
+ --_anchor-inset: 0%;
371
+ /**
372
+ * The correction the frame cannot compute. `overlap` has two values and
373
+ * hosts have many: how far a badge should sit into one depends on that
374
+ * host's own curve, shadow and optical weight, and the last pixel or two is
375
+ * the page's to state (BD1). Nought on both axes, so a frame that says
376
+ * nothing places the badge exactly where the overhang put it.
377
+ *
378
+ * The inline correction is multiplied by the direction below, with the
379
+ * overhang it corrects: a badge nudged two pixels into its host stays two
380
+ * pixels into it in a mirrored document, rather than jumping to the far
381
+ * side of the corner. The block correction has no such axis and is used as
382
+ * it is written.
383
+ */
384
+ --_offset-inline: var(--slotted-badge-anchor-offset-x, 0px);
385
+ --_offset-block: var(--slotted-badge-anchor-offset-y, 0px);
386
+
387
+ display: inline-flex;
388
+ position: relative;
389
+ vertical-align: middle;
390
+ }
391
+
392
+ [data-ui='badge'][data-part='anchor']:dir(rtl) {
393
+ --_dir: -1;
394
+ }
395
+
396
+ [data-ui='badge'][data-part='anchor'][data-overlap='circle'] {
397
+ --_anchor-inset: 14%;
398
+ }
399
+
400
+ [data-ui='badge'][data-part='anchor'][data-placement='top-start'],
401
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-start'] {
402
+ --_overhang-inline: -50%;
403
+ }
404
+
405
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-start'],
406
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-end'] {
407
+ --_overhang-block: 50%;
408
+ }
409
+
410
+ [data-ui='badge'][data-part='anchor'] > [data-ui='badge'][data-part='root'] {
411
+ /**
412
+ * The ring is what separates the badge from whatever it is sitting on.
413
+ * It is a token rather than a boolean, because a badge inside a card, a
414
+ * toolbar or a coloured row is not sitting on the page's own surface.
415
+ */
416
+ box-shadow: 0 0 0 var(--slotted-badge-ring-width, var(--slotted-border-width-thick, 2px))
417
+ var(--slotted-badge-ring-color, var(--slotted-surface, Canvas));
418
+ /* A count is short by construction and sits outside its host's box, so it
419
+ is the one badge with nothing to be clipped by. */
420
+ max-inline-size: none;
421
+ position: absolute;
422
+ translate: calc((var(--_overhang-inline) + var(--_offset-inline)) * var(--_dir))
423
+ calc(var(--_overhang-block) + var(--_offset-block));
424
+ z-index: 1;
425
+ }
426
+
427
+ [data-ui='badge'][data-part='anchor'][data-placement='top-end'] > [data-part='root'],
428
+ [data-ui='badge'][data-part='anchor'][data-placement='top-start'] > [data-part='root'] {
429
+ inset-block-start: var(--_anchor-inset);
430
+ }
431
+
432
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-end'] > [data-part='root'],
433
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-start'] > [data-part='root'] {
434
+ inset-block-end: var(--_anchor-inset);
435
+ }
436
+
437
+ [data-ui='badge'][data-part='anchor'][data-placement='top-end'] > [data-part='root'],
438
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-end'] > [data-part='root'] {
439
+ inset-inline-end: var(--_anchor-inset);
440
+ }
441
+
442
+ [data-ui='badge'][data-part='anchor'][data-placement='top-start'] > [data-part='root'],
443
+ [data-ui='badge'][data-part='anchor'][data-placement='bottom-start'] > [data-part='root'] {
444
+ inset-inline-start: var(--_anchor-inset);
445
+ }
446
+
447
+ /**
448
+ * ── Forced colours ─────────────────────────────────────────────────────
449
+ *
450
+ * The one place a family may write its own rule: the theme maps every tone
451
+ * ground to `ButtonFace` or `Canvas` and every tone border to `ButtonBorder`,
452
+ * so an `outline` badge, a `soft` badge and a `solid` badge become the same
453
+ * rectangle, and a badge whose edge happened to match its fill has no edge at
454
+ * all. `currentColor` is the only paint left that still separates the badge
455
+ * from the page.
456
+ */
457
+ @media (forced-colors: active) {
458
+ [data-ui='badge'][data-part='root'] {
459
+ border-color: currentColor;
460
+ }
461
+ }
462
+ }
@@ -0,0 +1,58 @@
1
+ [
2
+ "--slotted-badge-anchor-offset-x",
3
+ "--slotted-badge-anchor-offset-y",
4
+ "--slotted-badge-border-width",
5
+ "--slotted-badge-dot-border-color",
6
+ "--slotted-badge-font-family",
7
+ "--slotted-badge-font-weight",
8
+ "--slotted-badge-radius",
9
+ "--slotted-badge-ring-color",
10
+ "--slotted-badge-ring-width",
11
+ "--slotted-border-strong",
12
+ "--slotted-border-width-thick",
13
+ "--slotted-border-width-thin",
14
+ "--slotted-control-font-family",
15
+ "--slotted-control-font-size-lg",
16
+ "--slotted-control-font-size-md",
17
+ "--slotted-control-font-size-sm",
18
+ "--slotted-control-icon-size-md",
19
+ "--slotted-control-icon-size-sm",
20
+ "--slotted-focus-ring-color",
21
+ "--slotted-focus-ring-offset",
22
+ "--slotted-focus-ring-width",
23
+ "--slotted-font-weight-medium",
24
+ "--slotted-line-height-xs",
25
+ "--slotted-radius-full",
26
+ "--slotted-radius-sm",
27
+ "--slotted-space-1",
28
+ "--slotted-space-2",
29
+ "--slotted-space-3",
30
+ "--slotted-space-4",
31
+ "--slotted-space-5",
32
+ "--slotted-surface",
33
+ "--slotted-tone-accent-border",
34
+ "--slotted-tone-accent-on-solid",
35
+ "--slotted-tone-accent-solid",
36
+ "--slotted-tone-accent-surface",
37
+ "--slotted-tone-accent-text",
38
+ "--slotted-tone-danger-border",
39
+ "--slotted-tone-danger-on-solid",
40
+ "--slotted-tone-danger-solid",
41
+ "--slotted-tone-danger-surface",
42
+ "--slotted-tone-danger-text",
43
+ "--slotted-tone-secondary-border",
44
+ "--slotted-tone-secondary-on-solid",
45
+ "--slotted-tone-secondary-solid-hover",
46
+ "--slotted-tone-secondary-surface",
47
+ "--slotted-tone-secondary-text",
48
+ "--slotted-tone-success-border",
49
+ "--slotted-tone-success-on-solid",
50
+ "--slotted-tone-success-solid",
51
+ "--slotted-tone-success-surface",
52
+ "--slotted-tone-success-text",
53
+ "--slotted-tone-warning-border",
54
+ "--slotted-tone-warning-on-solid",
55
+ "--slotted-tone-warning-solid",
56
+ "--slotted-tone-warning-surface",
57
+ "--slotted-tone-warning-text"
58
+ ]