@tempoxyz/ds 0.0.5 → 0.0.7

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 (244) hide show
  1. package/dist/brand/logos/Altitude.js +1 -1
  2. package/dist/brand/logos/Altitude.js.map +1 -1
  3. package/dist/brand/logos/Anthropic.d.ts.map +1 -1
  4. package/dist/brand/logos/Anthropic.js +1 -1
  5. package/dist/brand/logos/Anthropic.js.map +1 -1
  6. package/dist/brand/logos/Arc.js +1 -1
  7. package/dist/brand/logos/Arc.js.map +1 -1
  8. package/dist/brand/logos/BlackRockWordmark.js +1 -1
  9. package/dist/brand/logos/BlackRockWordmark.js.map +1 -1
  10. package/dist/brand/logos/Brex.js +1 -1
  11. package/dist/brand/logos/Brex.js.map +1 -1
  12. package/dist/brand/logos/Coastal.js +1 -1
  13. package/dist/brand/logos/Coastal.js.map +1 -1
  14. package/dist/brand/logos/Coupang.js +1 -1
  15. package/dist/brand/logos/Coupang.js.map +1 -1
  16. package/dist/brand/logos/CrossRiver.js +1 -1
  17. package/dist/brand/logos/CrossRiver.js.map +1 -1
  18. package/dist/brand/logos/Deel.js +1 -1
  19. package/dist/brand/logos/Deel.js.map +1 -1
  20. package/dist/brand/logos/DeutscheBank.js +1 -1
  21. package/dist/brand/logos/DeutscheBank.js.map +1 -1
  22. package/dist/brand/logos/DoorDash.js +1 -1
  23. package/dist/brand/logos/DoorDash.js.map +1 -1
  24. package/dist/brand/logos/ElDorado.js +1 -1
  25. package/dist/brand/logos/ElDorado.js.map +1 -1
  26. package/dist/brand/logos/Faire.js +1 -1
  27. package/dist/brand/logos/Faire.js.map +1 -1
  28. package/dist/brand/logos/Felix.js +1 -1
  29. package/dist/brand/logos/Felix.js.map +1 -1
  30. package/dist/brand/logos/FigureMark.js +1 -1
  31. package/dist/brand/logos/FigureMark.js.map +1 -1
  32. package/dist/brand/logos/FigureWordmark.js +1 -1
  33. package/dist/brand/logos/FigureWordmark.js.map +1 -1
  34. package/dist/brand/logos/Gusto.js +1 -1
  35. package/dist/brand/logos/Gusto.js.map +1 -1
  36. package/dist/brand/logos/HumaFinanceMark.js +1 -1
  37. package/dist/brand/logos/HumaFinanceMark.js.map +1 -1
  38. package/dist/brand/logos/HumaFinanceWordmark.js +1 -1
  39. package/dist/brand/logos/HumaFinanceWordmark.js.map +1 -1
  40. package/dist/brand/logos/Kalshi.js +1 -1
  41. package/dist/brand/logos/Kalshi.js.map +1 -1
  42. package/dist/brand/logos/Karta.js +1 -1
  43. package/dist/brand/logos/Karta.js.map +1 -1
  44. package/dist/brand/logos/Kast.js +1 -1
  45. package/dist/brand/logos/Kast.js.map +1 -1
  46. package/dist/brand/logos/Klarna.js +1 -1
  47. package/dist/brand/logos/Klarna.js.map +1 -1
  48. package/dist/brand/logos/Kraken.js +1 -1
  49. package/dist/brand/logos/Kraken.js.map +1 -1
  50. package/dist/brand/logos/LeadBank.js +1 -1
  51. package/dist/brand/logos/LeadBank.js.map +1 -1
  52. package/dist/brand/logos/MapleFinanceMark.js +1 -1
  53. package/dist/brand/logos/MapleFinanceMark.js.map +1 -1
  54. package/dist/brand/logos/MapleFinanceWordmark.js +1 -1
  55. package/dist/brand/logos/MapleFinanceWordmark.js.map +1 -1
  56. package/dist/brand/logos/Mastercard.js +1 -1
  57. package/dist/brand/logos/Mastercard.js.map +1 -1
  58. package/dist/brand/logos/Mercury.js +1 -1
  59. package/dist/brand/logos/Mercury.js.map +1 -1
  60. package/dist/brand/logos/MoneyGram.js +1 -1
  61. package/dist/brand/logos/MoneyGram.js.map +1 -1
  62. package/dist/brand/logos/MorphoMark.js +1 -1
  63. package/dist/brand/logos/MorphoMark.js.map +1 -1
  64. package/dist/brand/logos/MorphoWordmark.js +1 -1
  65. package/dist/brand/logos/MorphoWordmark.js.map +1 -1
  66. package/dist/brand/logos/Nubank.js +1 -1
  67. package/dist/brand/logos/Nubank.js.map +1 -1
  68. package/dist/brand/logos/OKX.js +1 -1
  69. package/dist/brand/logos/OKX.js.map +1 -1
  70. package/dist/brand/logos/OndoFinanceMark.js +1 -1
  71. package/dist/brand/logos/OndoFinanceMark.js.map +1 -1
  72. package/dist/brand/logos/OndoFinanceWordmark.js +1 -1
  73. package/dist/brand/logos/OndoFinanceWordmark.js.map +1 -1
  74. package/dist/brand/logos/OnePay.js +1 -1
  75. package/dist/brand/logos/OnePay.js.map +1 -1
  76. package/dist/brand/logos/OpenAI.js +1 -1
  77. package/dist/brand/logos/OpenAI.js.map +1 -1
  78. package/dist/brand/logos/Payoneer.js +1 -1
  79. package/dist/brand/logos/Payoneer.js.map +1 -1
  80. package/dist/brand/logos/Persona.js +1 -1
  81. package/dist/brand/logos/Persona.js.map +1 -1
  82. package/dist/brand/logos/Ramp.js +1 -1
  83. package/dist/brand/logos/Ramp.js.map +1 -1
  84. package/dist/brand/logos/Revolut.js +1 -1
  85. package/dist/brand/logos/Revolut.js.map +1 -1
  86. package/dist/brand/logos/Shopify.d.ts.map +1 -1
  87. package/dist/brand/logos/Shopify.js +1 -1
  88. package/dist/brand/logos/Shopify.js.map +1 -1
  89. package/dist/brand/logos/SkyMark.js +1 -1
  90. package/dist/brand/logos/SkyMark.js.map +1 -1
  91. package/dist/brand/logos/SkyWordmark.js +1 -1
  92. package/dist/brand/logos/SkyWordmark.js.map +1 -1
  93. package/dist/brand/logos/StandardChartered.js +1 -1
  94. package/dist/brand/logos/StandardChartered.js.map +1 -1
  95. package/dist/brand/logos/Stripe.js +1 -1
  96. package/dist/brand/logos/Stripe.js.map +1 -1
  97. package/dist/brand/logos/TempoLogoMark.js +1 -1
  98. package/dist/brand/logos/TempoLogoMark.js.map +1 -1
  99. package/dist/brand/logos/TempoLogoWordmark.js +1 -1
  100. package/dist/brand/logos/TempoLogoWordmark.js.map +1 -1
  101. package/dist/brand/logos/TurnkeyMark.js +1 -1
  102. package/dist/brand/logos/TurnkeyMark.js.map +1 -1
  103. package/dist/brand/logos/TurnkeyWordmark.js +1 -1
  104. package/dist/brand/logos/TurnkeyWordmark.js.map +1 -1
  105. package/dist/brand/logos/UBS.js +1 -1
  106. package/dist/brand/logos/UBS.js.map +1 -1
  107. package/dist/brand/logos/VedaMark.js +1 -1
  108. package/dist/brand/logos/VedaMark.js.map +1 -1
  109. package/dist/brand/logos/VedaWordmark.js +1 -1
  110. package/dist/brand/logos/VedaWordmark.js.map +1 -1
  111. package/dist/brand/logos/Visa.js +1 -1
  112. package/dist/brand/logos/Visa.js.map +1 -1
  113. package/dist/brand/styles.css +1 -1
  114. package/dist/core/styles.css +1 -1
  115. package/dist/core/vars.d.ts +16 -0
  116. package/dist/core/vars.d.ts.map +1 -1
  117. package/dist/core/vars.js +8 -0
  118. package/dist/core/vars.js.map +1 -1
  119. package/dist/core/zyzz.config.d.ts +48 -0
  120. package/dist/core/zyzz.config.d.ts.map +1 -1
  121. package/dist/core/zyzz.config.js +21 -0
  122. package/dist/core/zyzz.config.js.map +1 -1
  123. package/dist/fonts/JetBrainsMono-Bold.woff2 +0 -0
  124. package/dist/fonts/JetBrainsMono-Medium.woff2 +0 -0
  125. package/dist/fonts/JetBrainsMono-SemiBold.woff2 +0 -0
  126. package/dist/platform/components/Badge.d.ts +7 -0
  127. package/dist/platform/components/Badge.d.ts.map +1 -1
  128. package/dist/platform/components/Badge.js +8 -3
  129. package/dist/platform/components/Badge.js.map +1 -1
  130. package/dist/platform/components/Card.d.ts +69 -0
  131. package/dist/platform/components/Card.d.ts.map +1 -0
  132. package/dist/platform/components/Card.js +62 -0
  133. package/dist/platform/components/Card.js.map +1 -0
  134. package/dist/platform/components/DenseTable.d.ts +81 -3
  135. package/dist/platform/components/DenseTable.d.ts.map +1 -1
  136. package/dist/platform/components/DenseTable.js +58 -34
  137. package/dist/platform/components/DenseTable.js.map +1 -1
  138. package/dist/platform/components/NativeSelect.d.ts +88 -2
  139. package/dist/platform/components/NativeSelect.d.ts.map +1 -1
  140. package/dist/platform/components/NativeSelect.js +64 -44
  141. package/dist/platform/components/NativeSelect.js.map +1 -1
  142. package/dist/platform/components/SegmentedControl.d.ts +8 -15
  143. package/dist/platform/components/SegmentedControl.d.ts.map +1 -1
  144. package/dist/platform/components/SegmentedControl.js.map +1 -1
  145. package/dist/platform/components/Spinner.d.ts +1 -0
  146. package/dist/platform/components/Spinner.d.ts.map +1 -1
  147. package/dist/platform/components/Spinner.js +1 -1
  148. package/dist/platform/components/Spinner.js.map +1 -1
  149. package/dist/platform/components/TextInput.d.ts +19 -1
  150. package/dist/platform/components/TextInput.d.ts.map +1 -1
  151. package/dist/platform/components/TextInput.js +17 -5
  152. package/dist/platform/components/TextInput.js.map +1 -1
  153. package/dist/platform/index.d.ts +1 -0
  154. package/dist/platform/index.d.ts.map +1 -1
  155. package/dist/platform/index.js +1 -0
  156. package/dist/platform/index.js.map +1 -1
  157. package/dist/platform/styles.css +7 -6
  158. package/dist/platform/vars.d.ts +112 -0
  159. package/dist/platform/vars.d.ts.map +1 -1
  160. package/dist/platform/vars.js +36 -0
  161. package/dist/platform/vars.js.map +1 -1
  162. package/dist/platform/zyzz.config.d.ts +336 -0
  163. package/dist/platform/zyzz.config.d.ts.map +1 -1
  164. package/dist/site/styles.css +1 -1
  165. package/dist/site/vars.d.ts +16 -0
  166. package/dist/site/vars.d.ts.map +1 -1
  167. package/dist/site/zyzz.config.d.ts +48 -0
  168. package/dist/site/zyzz.config.d.ts.map +1 -1
  169. package/package.json +13 -1
  170. package/src/brand/logos/Altitude.tsx +9 -9
  171. package/src/brand/logos/Anthropic.tsx +12 -9
  172. package/src/brand/logos/Arc.tsx +1 -1
  173. package/src/brand/logos/BlackRockWordmark.tsx +1 -1
  174. package/src/brand/logos/Brex.tsx +2 -2
  175. package/src/brand/logos/Coastal.tsx +2 -2
  176. package/src/brand/logos/Coupang.tsx +7 -7
  177. package/src/brand/logos/CrossRiver.tsx +11 -11
  178. package/src/brand/logos/Deel.tsx +5 -5
  179. package/src/brand/logos/DeutscheBank.tsx +13 -13
  180. package/src/brand/logos/DoorDash.tsx +1 -1
  181. package/src/brand/logos/ElDorado.tsx +9 -9
  182. package/src/brand/logos/Faire.tsx +1 -1
  183. package/src/brand/logos/Felix.tsx +6 -6
  184. package/src/brand/logos/FigureMark.tsx +1 -1
  185. package/src/brand/logos/FigureWordmark.tsx +6 -6
  186. package/src/brand/logos/Gusto.tsx +1 -1
  187. package/src/brand/logos/HumaFinanceMark.tsx +1 -1
  188. package/src/brand/logos/HumaFinanceWordmark.tsx +2 -2
  189. package/src/brand/logos/Kalshi.tsx +7 -7
  190. package/src/brand/logos/Karta.tsx +6 -6
  191. package/src/brand/logos/Kast.tsx +2 -2
  192. package/src/brand/logos/Klarna.tsx +1 -1
  193. package/src/brand/logos/Kraken.tsx +2 -2
  194. package/src/brand/logos/LeadBank.tsx +5 -5
  195. package/src/brand/logos/MapleFinanceMark.tsx +2 -2
  196. package/src/brand/logos/MapleFinanceWordmark.tsx +2 -2
  197. package/src/brand/logos/Mastercard.tsx +1 -1
  198. package/src/brand/logos/Mercury.tsx +2 -2
  199. package/src/brand/logos/MoneyGram.tsx +11 -11
  200. package/src/brand/logos/MorphoMark.tsx +4 -4
  201. package/src/brand/logos/MorphoWordmark.tsx +4 -4
  202. package/src/brand/logos/Nubank.tsx +4 -4
  203. package/src/brand/logos/OKX.tsx +9 -9
  204. package/src/brand/logos/OndoFinanceMark.tsx +3 -3
  205. package/src/brand/logos/OndoFinanceWordmark.tsx +3 -3
  206. package/src/brand/logos/OnePay.tsx +8 -8
  207. package/src/brand/logos/OpenAI.tsx +6 -6
  208. package/src/brand/logos/Payoneer.tsx +2 -2
  209. package/src/brand/logos/Persona.tsx +9 -9
  210. package/src/brand/logos/Ramp.tsx +2 -2
  211. package/src/brand/logos/Revolut.tsx +1 -1
  212. package/src/brand/logos/Shopify.tsx +13 -10
  213. package/src/brand/logos/SkyMark.tsx +1 -1
  214. package/src/brand/logos/SkyWordmark.tsx +1 -1
  215. package/src/brand/logos/StandardChartered.tsx +3 -3
  216. package/src/brand/logos/Stripe.tsx +7 -7
  217. package/src/brand/logos/TempoLogoMark.tsx +1 -1
  218. package/src/brand/logos/TempoLogoWordmark.tsx +5 -5
  219. package/src/brand/logos/TurnkeyMark.tsx +1 -1
  220. package/src/brand/logos/TurnkeyWordmark.tsx +1 -1
  221. package/src/brand/logos/UBS.tsx +2 -2
  222. package/src/brand/logos/VedaMark.tsx +1 -1
  223. package/src/brand/logos/VedaWordmark.tsx +2 -2
  224. package/src/brand/logos/Visa.tsx +1 -1
  225. package/src/brand/styles.css +1 -1
  226. package/src/core/styles.css +1 -1
  227. package/src/core/vars.ts +8 -0
  228. package/src/core/zyzz.config.ts +24 -0
  229. package/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
  230. package/src/fonts/JetBrainsMono-Medium.woff2 +0 -0
  231. package/src/fonts/JetBrainsMono-SemiBold.woff2 +0 -0
  232. package/src/fonts/README.md +8 -1
  233. package/src/platform/README.md +150 -6
  234. package/src/platform/components/Badge.tsx +8 -3
  235. package/src/platform/components/Card.tsx +72 -0
  236. package/src/platform/components/DenseTable.tsx +68 -36
  237. package/src/platform/components/NativeSelect.tsx +65 -45
  238. package/src/platform/components/SegmentedControl.tsx +7 -5
  239. package/src/platform/components/Spinner.tsx +1 -1
  240. package/src/platform/components/TextInput.tsx +27 -4
  241. package/src/platform/index.ts +1 -0
  242. package/src/platform/styles.css +7 -6
  243. package/src/platform/vars.ts +36 -0
  244. package/src/site/styles.css +1 -1
@@ -1,6 +1,6 @@
1
1
  # Platform
2
2
 
3
- Use `@tempoxyz/ds/platform` with `@tempoxyz/ds/platform.css` for product interfaces. Implemented exports have Figma mappings, independent style contracts, and browser suites.
3
+ Use `@tempoxyz/ds/platform` with `@tempoxyz/ds/platform.css` for product interfaces. Implemented exports have Figma mappings, independent style contracts, and browser suites. Card has browser suites only, since Platform Figma has no Card family yet.
4
4
 
5
5
  ## Components
6
6
 
@@ -8,27 +8,28 @@ Use `@tempoxyz/ds/platform` with `@tempoxyz/ds/platform.css` for product interfa
8
8
  | ---------------- | ----------------------------------------------------- | -------------------------- |
9
9
  | Alert | `tone`, `title`, `description`, `action`, `onDismiss` | Inline notifications |
10
10
  | Avatar | `alt`, `fallback`, `scale`, `src` | Identity images |
11
- | Badge | `scale`, `variant` | Classification labels |
11
+ | Badge | `compact`, `scale`, `variant` | Classification labels |
12
12
  | Button | `appearance`, `scale`, `variant` | Discrete actions |
13
13
  | ButtonGroup | `horizontal` | Related actions |
14
14
  | Callout | `title`, `children` | Supporting information |
15
+ | Card | `padding`, `render` | Raised content surfaces |
15
16
  | Checkbox | `label`, `checked`, `indeterminate` | Independent choices |
16
- | DenseTable | `children`, native table attributes | Compact tabular data |
17
+ | DenseTable | `compact`, `children`, native table attributes | Compact tabular data |
17
18
  | IconBadge | `appearance`, `scale`, `children` | Icon classification |
18
19
  | IconButton | `appearance`, `scale`, `variant`, `aria-label` | Icon actions |
19
20
  | InlineCode | `children` | Code within text |
20
21
  | KeyboardKey | Native kbd attributes | Keyboard shortcuts |
21
- | NativeSelect | Native select attributes | Native option selection |
22
+ | NativeSelect | `scale`, native select attributes | Native option selection |
22
23
  | Progress | `value`, `max` | Progress toward completion |
23
24
  | RadioGroup | `items`, `value`, `onValueChange` | Mutually exclusive choices |
24
25
  | Search | `appearance`, `value`, `onValueChange` | Search input with clearing |
25
- | SegmentedControl | `items`, `value`, `onValueChange` | Three related choices |
26
+ | SegmentedControl | `items`, `value`, `onValueChange` | Two to four choices |
26
27
  | SimpleTable | `children`, native description list attributes | Description pairs |
27
28
  | Spinner | `elevated` | Indeterminate progress |
28
29
  | StatusIndicator | `tone` | Compact status marks |
29
30
  | Tab | `appearance`, `scale`, `value`, `logo` | Coordinated panels |
30
31
  | TextButton | `children` | Inline actions |
31
- | TextInput | `appearance`, `extended`, `label` | Text entry |
32
+ | TextInput | `appearance`, `extended`, `label`, `stretch` | Text entry |
32
33
  | Toast | `toast`, `icon` | Queued notifications |
33
34
  | Tooltip | `children`, `content` | Contextual hints |
34
35
 
@@ -73,6 +74,45 @@ import '@tempoxyz/ds/platform.css'
73
74
 
74
75
  `DenseTable` also supports `Colgroup`, `Col`, and `Tfoot`. `SimpleTable` renders a native description list.
75
76
 
77
+ ## Dense layouts
78
+
79
+ Defaults follow Figma. These props fit components into toolbars, filters, and data grids.
80
+
81
+ | Component | Prop | Behavior |
82
+ | ---------------------------- | --------- | ----------------------------------------------------------------------------------- |
83
+ | Badge | `compact` | Fits its label instead of the 80px minimum width |
84
+ | DenseTable | `compact` | Uses 8px row padding and 12px column gaps, and sizes columns to unwrapped content |
85
+ | DenseTable.Td, DenseTable.Th | `numeric` | Right-aligns tabular figures without wrapping |
86
+ | NativeSelect | `scale` | Matches Button heights: `large` (48px, default), `medium` (40px), or `small` (32px) |
87
+ | SegmentedControl | `items` | Accepts two to four segments |
88
+ | TextInput | `stretch` | Fills its container instead of the 320px width |
89
+
90
+ ```tsx
91
+ import { Badge, DenseTable, NativeSelect, TextInput } from '@tempoxyz/ds/platform'
92
+ import '@tempoxyz/ds/platform.css'
93
+
94
+ <TextInput aria-label="Search runs" stretch />
95
+ <NativeSelect aria-label="Preset" scale="small">
96
+ <option>All presets</option>
97
+ </NativeSelect>
98
+ <Badge compact scale="small" variant="gray">v2</Badge>
99
+
100
+ <DenseTable compact>
101
+ <DenseTable.Thead>
102
+ <DenseTable.Tr>
103
+ <DenseTable.Th scope="col">Preset</DenseTable.Th>
104
+ <DenseTable.Th numeric scope="col">TPS</DenseTable.Th>
105
+ </DenseTable.Tr>
106
+ </DenseTable.Thead>
107
+ <DenseTable.Tbody>
108
+ <DenseTable.Tr>
109
+ <DenseTable.Td>transfer-heavy</DenseTable.Td>
110
+ <DenseTable.Td numeric>12,480</DenseTable.Td>
111
+ </DenseTable.Tr>
112
+ </DenseTable.Tbody>
113
+ </DenseTable>
114
+ ```
115
+
76
116
  ## Base UI
77
117
 
78
118
  Check [Base UI's component catalog](https://base-ui.com/react/overview/quick-start) before implementing each component. Reuse matching primitives for behavior and retain DS styling and props.
@@ -81,6 +121,7 @@ Check [Base UI's component catalog](https://base-ui.com/react/overview/quick-sta
81
121
  | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
82
122
  | Avatar | Use [Avatar](https://base-ui.com/react/components/avatar) for image loading and fallback. |
83
123
  | Button, IconButton, Search actions, TextButton | Use [Button](https://base-ui.com/react/components/button). |
124
+ | Card | Use [useRender](https://base-ui.com/react/utils/use-render) for the caller's element. Base UI has no card primitive. |
84
125
  | Checkbox | Use [Checkbox](https://base-ui.com/react/components/checkbox) with an enclosing native label. |
85
126
  | Progress, Spinner | Use [Progress](https://base-ui.com/react/components/progress) for progress semantics. |
86
127
  | RadioGroup, SegmentedControl | Use [Radio Group](https://base-ui.com/react/components/radio-group) for keyboard selection and form values. |
@@ -91,6 +132,25 @@ Check [Base UI's component catalog](https://base-ui.com/react/overview/quick-sta
91
132
  | Toast | Use [Toast](https://base-ui.com/react/components/toast) for queues, announcements, timing, and dismissal. |
92
133
  | Tooltip | Use [Tooltip](https://base-ui.com/react/components/tooltip) for positioning, focus, and dismissal. |
93
134
 
135
+ ## Cards
136
+
137
+ Card renders a `div` on `background.secondary` with the Platform `xs` radius. Set `padding` to `none`, `12`, `16`, `20`, `24`, or `32` from the spacing scale. It defaults to `none` for flush content such as charts and tables.
138
+
139
+ Pass a link or button to `render` for an interactive card. Card keeps the native element and its semantics. Element attributes such as `href`, `disabled`, and element refs belong on the `render` element.
140
+
141
+ ```tsx
142
+ import { Card } from '@tempoxyz/ds/platform'
143
+
144
+ <Card padding="24">Throughput summary</Card>
145
+ <Card padding="16" render={<a href="/runs/42" />}>Run 42</Card>
146
+ <Card padding="16" render={<button onClick={openRun} type="button" />}>Open run</Card>
147
+ ```
148
+
149
+ Links and enabled buttons show a `line.primary` outline on hover and a `border.focus` ring on focus-visible. Other elements show no hover or pointer affordance. Button cards inherit the surrounding font and text alignment.
150
+
151
+ > [!NOTE]
152
+ > Platform Figma has no Card family yet. Card follows Platform variables until a family is published and mapped.
153
+
94
154
  ## Coordinated controls
95
155
 
96
156
  ```tsx
@@ -135,10 +195,94 @@ function Notifications() {
135
195
 
136
196
  Scope the provider to the interface that owns notifications. Position the viewport in the consumer layout; the library does not create a global queue.
137
197
 
198
+ ## Accent colors
199
+
200
+ Use `content.accent`, `container.accent`, and `border.accent` for links, selections, and highlighted values. The `inverse` set swaps the content and container colors.
201
+
202
+ ```tsx
203
+ import { style } from '@tempoxyz/ds/platform'
204
+
205
+ const selected = style({
206
+ backgroundColor: 'container.accent',
207
+ borderColor: 'border.accent',
208
+ color: 'content.accent',
209
+ })
210
+ ```
211
+
212
+ > [!NOTE]
213
+ > Figma does not define the accent variables yet. They follow the positive, negative, and warning variables until Figma adds matching ones.
214
+
215
+ ## Charts
216
+
217
+ Chart tokens provide ordered categorical series colors and neutral ink for Light, Dark, and Inverse backgrounds. Series alias Core accents, and ink aliases Platform roles.
218
+
219
+ | Token | Light | Dark |
220
+ | ---------------- | --------------------- | -------------------- |
221
+ | `chart.series.1` | `accent.blueLight` | `accent.blueLight` |
222
+ | `chart.series.2` | `accent.magentaLight` | `accent.magentaDark` |
223
+ | `chart.series.3` | `accent.orangeLight` | `accent.orangeLight` |
224
+ | `chart.series.4` | `accent.purpleLight` | `accent.purpleLight` |
225
+ | `chart.series.5` | `accent.greenLight` | `accent.greenLight` |
226
+ | `chart.series.6` | `accent.violetLight` | `accent.violetDark` |
227
+ | `chart.series.7` | `accent.redLight` | `accent.redLight` |
228
+
229
+ | Token | Alias | Use |
230
+ | ------------- | ------------------- | ----------------------------------- |
231
+ | `chart.axis` | `content.secondary` | Axis labels and tick text |
232
+ | `chart.grid` | `line.secondary` | Grid lines and axis rules |
233
+ | `chart.muted` | `content.tertiary` | De-emphasized series, such as Other |
234
+
235
+ - Assign series in slot order from `chart.series.1`. Keep each series on its slot when filters hide others.
236
+ - Fold an eighth series into `chart.muted` as Other, or split the chart into small multiples. Do not cycle slots.
237
+ - The order keeps adjacent slots distinct under protanopia and deuteranopia for lines, bars, and stacks. In scatter plots, where any two marks can touch, use at most three series.
238
+ - Series 3, 5, and 7 share hues with `content.warning`, `content.positive`, and `content.negative`. When a series means good or bad, use those status tokens, and do not mix them with series tokens in one chart.
239
+ - Label series with text tokens such as `chart.axis`, not series colors. On Light `background.primary`, series 3 and 5 fall below 3:1, so draw charts on `background.secondary` or label series directly.
240
+ - `chart.muted` stays below 3:1 on Light backgrounds, so label muted series directly or offer a table view.
241
+
242
+ Apply chart tokens through CSS `fill` and `stroke` with `style` or `variants`. Browsers do not reliably resolve `var()` or `light-dark()` in SVG presentation attributes. Attributes without tokens, such as `fill="none"` and `strokeWidth`, stay on the element.
243
+
244
+ ```tsx
245
+ import { style, variants } from '@tempoxyz/ds/platform'
246
+
247
+ namespace styles {
248
+ export const axis = style({ fill: 'chart.axis' })
249
+
250
+ export const grid = style({ stroke: 'chart.grid' })
251
+
252
+ export const line = variants({
253
+ variants: {
254
+ series: {
255
+ '1': { stroke: 'chart.series.1' },
256
+ '2': { stroke: 'chart.series.2' },
257
+ },
258
+ },
259
+ })
260
+ }
261
+
262
+ ;<svg viewBox="0 0 320 120">
263
+ <line {...styles.grid()} x1="0" x2="320" y1="100" y2="100" />
264
+ <polyline
265
+ {...styles.line({ series: '1' })}
266
+ fill="none"
267
+ points="0,80 160,40 320,60"
268
+ strokeWidth={2}
269
+ />
270
+ <text {...styles.axis()} x="0" y="116">
271
+ Mon
272
+ </text>
273
+ </svg>
274
+ ```
275
+
276
+ Libraries that accept only color strings can read the resolved value with `getComputedStyle(element).stroke` from an element that applies the token. Read it again when the color scheme changes.
277
+
138
278
  ## Coverage
139
279
 
140
280
  Badge covers all ten Figma scale/style combinations. KeyboardKey covers its single definition. ButtonGroup covers both orientations with keyboard activation and focus checks. Browser suites capture labelled sheets in Light and Dark, at mobile and desktop widths.
141
281
 
282
+ Card has no Figma cases, so its suite defines its own matrix: every padding value, plus link and button cards through hover, focus-visible, pressed, and disabled states.
283
+
284
+ Figma does not define the dense layout props yet. Browser sheets label their rows `not in Figma`, and Figma parity checks skip them.
285
+
142
286
  Checkbox and Radio Group labels retain the unbound black fills in Figma, including Dark mode. Tab logo fixtures exercise the slot using a Platform icon; they do not verify deferred Brand artwork.
143
287
 
144
288
  ## Icons
@@ -5,12 +5,12 @@ import { inverse } from '../vars.js'
5
5
  import { variants } from '../zyzz.config.js'
6
6
 
7
7
  export function Badge(props: Badge.Props) {
8
- const { className, scale, variant, vars, ...attributes } = props
8
+ const { className, compact, scale, variant, vars, ...attributes } = props
9
9
 
10
10
  return (
11
11
  <span
12
12
  {...attributes}
13
- {...styles.badge({ className, scale, style: props.style, variant, vars })}
13
+ {...styles.badge({ className, compact, scale, style: props.style, variant, vars })}
14
14
  />
15
15
  )
16
16
  }
@@ -36,8 +36,13 @@ namespace styles {
36
36
  position: 'relative',
37
37
  whiteSpace: 'nowrap',
38
38
  },
39
- defaultVariants: { scale: 'medium', variant: 'black' },
39
+ defaultVariants: { compact: false, scale: 'medium', variant: 'black' },
40
40
  variants: {
41
+ // Figma badges keep an 80px minimum width. Compact badges fit their content instead.
42
+ compact: {
43
+ false: {},
44
+ true: { minWidth: 'auto !custom' },
45
+ },
41
46
  scale: {
42
47
  medium: {
43
48
  borderRadius: '2xs',
@@ -0,0 +1,72 @@
1
+ import * as BaseUi from '@base-ui/react/use-render'
2
+ import type * as zyzz from 'zyzz'
3
+ import { variants } from '../zyzz.config.js'
4
+
5
+ export function Card(props: Card.Props) {
6
+ const { className, padding, render, vars, ...attributes } = props
7
+
8
+ return BaseUi.useRender({
9
+ defaultTagName: 'div',
10
+ props: {
11
+ ...attributes,
12
+ ...styles.card({ className, padding, style: props.style, vars }),
13
+ },
14
+ render,
15
+ })
16
+ }
17
+
18
+ export namespace Card {
19
+ export type Props = BaseUi.useRender.ComponentProps<'div'> &
20
+ zyzz.Props.Variants<typeof styles.card>
21
+ }
22
+
23
+ // Hover and pointer styles match only links and enabled buttons, so a static card never presents an
24
+ // interactive affordance.
25
+ namespace styles {
26
+ export const card = variants(
27
+ {
28
+ base: {
29
+ backgroundColor: 'background.secondary',
30
+ borderRadius: 'xs',
31
+ boxSizing: 'border-box',
32
+ color: 'content.primary',
33
+ display: 'block',
34
+ margin: 'none',
35
+ selectors: {
36
+ '&:where(button)': {
37
+ border: 'none !custom',
38
+ font: 'inherit !custom',
39
+ letterSpacing: 'inherit !custom',
40
+ textAlign: 'inherit !custom',
41
+ },
42
+ '&:where(:any-link)': { textDecoration: 'none !custom' },
43
+ '&:where(:any-link, button:enabled)': { cursor: 'pointer' },
44
+ // `:where` keeps hover at focus-visible specificity, so the later focus ring wins while
45
+ // a focused card is hovered.
46
+ '&:where(:any-link, button:enabled):hover': {
47
+ outline: '1px solid !custom',
48
+ outlineColor: 'line.primary',
49
+ outlineOffset: '-1px !custom',
50
+ },
51
+ '&:focus-visible': {
52
+ outline: '2px solid !custom',
53
+ outlineColor: 'border.focus',
54
+ outlineOffset: '2px !custom',
55
+ },
56
+ },
57
+ },
58
+ defaultVariants: { padding: 'none' },
59
+ variants: {
60
+ padding: {
61
+ '12': { padding: '12' },
62
+ '16': { padding: '16' },
63
+ '20': { padding: '20' },
64
+ '24': { padding: '24' },
65
+ '32': { padding: '32' },
66
+ none: { padding: 'none' },
67
+ },
68
+ },
69
+ },
70
+ { id: 'tds/platform/card' },
71
+ )
72
+ }
@@ -1,13 +1,13 @@
1
1
  import type { ComponentPropsWithRef } from 'react'
2
2
  import type * as zyzz from 'zyzz'
3
- import { style } from '../zyzz.config.js'
3
+ import { style, variants } from '../zyzz.config.js'
4
4
 
5
5
  export function DenseTable(props: DenseTable.Props) {
6
- const { className, vars, ...attributes } = props
6
+ const { className, compact, vars, ...attributes } = props
7
7
 
8
8
  return (
9
9
  <div {...styles.scroll()}>
10
- <table {...attributes} {...styles.table({ className, style: props.style, vars })} />
10
+ <table {...attributes} {...styles.table({ className, compact, style: props.style, vars })} />
11
11
  </div>
12
12
  )
13
13
  }
@@ -51,11 +51,16 @@ export namespace DenseTable {
51
51
  }
52
52
 
53
53
  export function Td(props: Td.Props) {
54
- return <td {...props} />
54
+ const { numeric, ...attributes } = props
55
+
56
+ return <td {...attributes} data-numeric={numeric ? '' : undefined} />
55
57
  }
56
58
 
57
59
  export namespace Td {
58
- export type Props = ComponentPropsWithRef<'td'>
60
+ export type Props = ComponentPropsWithRef<'td'> & {
61
+ /** Right-aligns the cell with tabular figures and no wrapping. */
62
+ numeric?: boolean | undefined
63
+ }
59
64
  }
60
65
 
61
66
  export function Tfoot(props: Tfoot.Props) {
@@ -67,11 +72,16 @@ export namespace DenseTable {
67
72
  }
68
73
 
69
74
  export function Th(props: Th.Props) {
70
- return <th {...props} />
75
+ const { numeric, ...attributes } = props
76
+
77
+ return <th {...attributes} data-numeric={numeric ? '' : undefined} />
71
78
  }
72
79
 
73
80
  export namespace Th {
74
- export type Props = ComponentPropsWithRef<'th'>
81
+ export type Props = ComponentPropsWithRef<'th'> & {
82
+ /** Right-aligns the header with tabular figures and no wrapping. */
83
+ numeric?: boolean | undefined
84
+ }
75
85
  }
76
86
 
77
87
  export function Thead(props: Thead.Props) {
@@ -102,38 +112,60 @@ namespace styles {
102
112
  { id: 'tds/platform/dense-table/scroll' },
103
113
  )
104
114
 
105
- export const table = style(
115
+ export const table = variants(
106
116
  {
107
- borderCollapse: 'collapse',
108
- color: 'content.primary',
109
- tableLayout: 'fixed',
110
- typography: 'body.b2',
111
- width: '100% !custom',
112
- selectors: {
113
- '& th': {
114
- paddingTop: 'none',
115
- paddingBottom: '16',
116
- paddingRight: '16',
117
- textAlign: 'left',
118
- typography: 'body.b2Strong',
117
+ base: {
118
+ borderCollapse: 'collapse',
119
+ color: 'content.primary',
120
+ tableLayout: 'fixed',
121
+ typography: 'body.b2',
122
+ width: '100% !custom',
123
+ selectors: {
124
+ '& th': {
125
+ paddingTop: 'none',
126
+ paddingBottom: '16',
127
+ paddingRight: '16',
128
+ textAlign: 'left',
129
+ typography: 'body.b2Strong',
130
+ },
131
+ '& td': {
132
+ paddingBlock: '16',
133
+ paddingRight: '16',
134
+ position: 'relative',
135
+ },
136
+ '& td::before': {
137
+ backgroundColor: 'line.secondary',
138
+ content: '"" !custom',
139
+ height: '1px !custom',
140
+ left: '0px !custom',
141
+ position: 'absolute',
142
+ right: '0px !custom',
143
+ top: '-1px !custom',
144
+ },
145
+ '& td, & th': { overflowWrap: 'anywhere', paddingLeft: 'none', verticalAlign: 'middle' },
146
+ '& td:last-child, & th:last-child': { paddingRight: 'none' },
147
+ '& tbody tr:last-child td': { paddingBottom: 'none' },
148
+ '& td[data-numeric], & th[data-numeric]': {
149
+ fontVariantNumeric: 'tabular-nums',
150
+ textAlign: 'right',
151
+ whiteSpace: 'nowrap',
152
+ },
119
153
  },
120
- '& td': {
121
- paddingBlock: '16',
122
- paddingRight: '16',
123
- position: 'relative',
124
- },
125
- '& td::before': {
126
- backgroundColor: 'line.secondary',
127
- content: '"" !custom',
128
- height: '1px !custom',
129
- left: '0px !custom',
130
- position: 'absolute',
131
- right: '0px !custom',
132
- top: '-1px !custom',
154
+ },
155
+ defaultVariants: { compact: false },
156
+ variants: {
157
+ // Figma defines only the regular density. Compact columns size to unwrapped content.
158
+ compact: {
159
+ false: {},
160
+ true: {
161
+ tableLayout: 'auto',
162
+ selectors: {
163
+ '& th': { paddingBottom: '8', paddingRight: '12' },
164
+ '& td': { paddingBlock: '8', paddingRight: '12' },
165
+ '& td, & th': { overflowWrap: 'normal', whiteSpace: 'nowrap' },
166
+ },
167
+ },
133
168
  },
134
- '& td, & th': { overflowWrap: 'anywhere', paddingLeft: 'none', verticalAlign: 'middle' },
135
- '& td:last-child, & th:last-child': { paddingRight: 'none' },
136
- '& tbody tr:last-child td': { paddingBottom: 'none' },
137
169
  },
138
170
  },
139
171
  { id: 'tds/platform/dense-table' },
@@ -1,17 +1,17 @@
1
1
  import type { ComponentPropsWithRef } from 'react'
2
2
  import type * as zyzz from 'zyzz'
3
3
  import { ChevronDown } from '../icons/index.js'
4
- import { style } from '../zyzz.config.js'
4
+ import { style, variants } from '../zyzz.config.js'
5
5
 
6
6
  export function NativeSelect(props: NativeSelect.Props) {
7
- const { children, className, invalid = false, vars, ...attributes } = props
7
+ const { children, className, invalid = false, scale, vars, ...attributes } = props
8
8
 
9
9
  return (
10
- <div {...styles.root({ className, style: props.style, vars })}>
10
+ <div {...styles.root({ className, scale, style: props.style, vars })}>
11
11
  <select
12
12
  {...attributes}
13
13
  aria-invalid={invalid || attributes['aria-invalid']}
14
- {...styles.select()}
14
+ {...styles.select({ scale })}
15
15
  >
16
16
  {children}
17
17
  </select>
@@ -33,61 +33,81 @@ namespace styles {
33
33
  pointerEvents: 'none',
34
34
  position: 'absolute',
35
35
  right: '16',
36
- top: '16',
36
+ top: '50% !custom',
37
+ transform: 'translateY(-50%) !custom',
37
38
  width: '16',
38
39
  },
39
40
  { id: 'tds/platform/native-select/chevron' },
40
41
  )
41
42
 
42
- export const root = style(
43
+ export const root = variants(
43
44
  {
44
- alignItems: 'center',
45
- backgroundColor: 'background.secondary',
46
- borderColor: 'line.secondary',
47
- borderRadius: 'xs',
48
- borderStyle: 'solid',
49
- borderWidth: 'thin',
50
- boxSizing: 'border-box',
51
- columnGap: '8',
52
- display: 'flex',
53
- height: '48',
54
- maxWidth: '100% !custom',
55
- paddingInline: '16',
56
- position: 'relative',
57
- width: '320px !custom',
58
- selectors: {
59
- '&:has(select:disabled)': { backgroundColor: 'container.subtle' },
60
- '&:has(select:disabled) > svg': { opacity: '0.4 !custom' },
61
- '&:has(select[aria-invalid="true"])': {
62
- backgroundColor: 'container.negative',
63
- borderColor: 'border.negative',
64
- borderWidth: 'regular',
45
+ base: {
46
+ alignItems: 'center',
47
+ backgroundColor: 'background.secondary',
48
+ borderColor: 'line.secondary',
49
+ borderRadius: 'xs',
50
+ borderStyle: 'solid',
51
+ borderWidth: 'thin',
52
+ boxSizing: 'border-box',
53
+ columnGap: '8',
54
+ display: 'flex',
55
+ maxWidth: '100% !custom',
56
+ paddingInline: '16',
57
+ position: 'relative',
58
+ width: '320px !custom',
59
+ selectors: {
60
+ '&:has(select:disabled)': { backgroundColor: 'container.subtle' },
61
+ '&:has(select:disabled) > svg': { opacity: '0.4 !custom' },
62
+ '&:has(select[aria-invalid="true"])': {
63
+ backgroundColor: 'container.negative',
64
+ borderColor: 'border.negative',
65
+ borderWidth: 'regular',
66
+ },
67
+ '&:has(select:focus-visible)': {
68
+ outline: '2px solid currentColor !custom',
69
+ outlineOffset: '2px !custom',
70
+ },
65
71
  },
66
- '&:has(select:focus-visible)': {
67
- outline: '2px solid currentColor !custom',
68
- outlineOffset: '2px !custom',
72
+ },
73
+ defaultVariants: { scale: 'large' },
74
+ variants: {
75
+ // Scales follow Button heights. Figma defines only the 48px large scale.
76
+ scale: {
77
+ large: { height: '48' },
78
+ medium: { borderRadius: '2xs', height: '40' },
79
+ small: { borderRadius: '2xs', height: '32' },
69
80
  },
70
81
  },
71
82
  },
72
83
  { id: 'tds/platform/native-select' },
73
84
  )
74
85
 
75
- export const select = style(
86
+ export const select = variants(
76
87
  {
77
- appearance: 'none',
78
- backgroundColor: 'transparent !custom',
79
- border: 'none !custom',
80
- boxSizing: 'border-box',
81
- color: 'content.primary',
82
- height: '100% !custom',
83
- paddingBlock: 'none',
84
- paddingLeft: 'none',
85
- paddingRight: '24',
86
- outline: 'none !custom',
87
- typography: 'body.b2',
88
- width: '100% !custom',
89
- selectors: {
90
- '&:disabled': { color: 'content.tertiary' },
88
+ base: {
89
+ appearance: 'none',
90
+ backgroundColor: 'transparent !custom',
91
+ border: 'none !custom',
92
+ boxSizing: 'border-box',
93
+ color: 'content.primary',
94
+ height: '100% !custom',
95
+ paddingBlock: 'none',
96
+ paddingLeft: 'none',
97
+ paddingRight: '24',
98
+ outline: 'none !custom',
99
+ width: '100% !custom',
100
+ selectors: {
101
+ '&:disabled': { color: 'content.tertiary' },
102
+ },
103
+ },
104
+ defaultVariants: { scale: 'large' },
105
+ variants: {
106
+ scale: {
107
+ large: { typography: 'body.b2' },
108
+ medium: { typography: 'body.b2' },
109
+ small: { typography: 'body.b3' },
110
+ },
91
111
  },
92
112
  },
93
113
  { id: 'tds/platform/native-select/select' },
@@ -28,6 +28,8 @@ export function SegmentedControl<const value extends string>(props: SegmentedCon
28
28
  }
29
29
 
30
30
  export namespace SegmentedControl {
31
+ type Item<value extends string> = { label: ReactNode; value: value }
32
+
31
33
  export type Props<value extends string = string> = Omit<
32
34
  ComponentPropsWithRef<'div'>,
33
35
  'children' | 'defaultValue'
@@ -44,11 +46,11 @@ export namespace SegmentedControl {
44
46
  | 'required'
45
47
  | 'value'
46
48
  > & {
47
- items: readonly [
48
- { label: ReactNode; value: value },
49
- { label: ReactNode; value: value },
50
- { label: ReactNode; value: value },
51
- ]
49
+ /** Two to four segments. Figma defines three, and the 354px control fits four at 80px each. */
50
+ items:
51
+ | readonly [Item<value>, Item<value>]
52
+ | readonly [Item<value>, Item<value>, Item<value>]
53
+ | readonly [Item<value>, Item<value>, Item<value>, Item<value>]
52
54
  }
53
55
  }
54
56
 
@@ -40,7 +40,6 @@ namespace styles {
40
40
  export const glyph = style(
41
41
  {
42
42
  animation: `${rotation} 1s linear infinite !custom`,
43
- color: '#000000 !custom',
44
43
  flexShrink: '0 !custom',
45
44
  height: '16',
46
45
  width: '16',
@@ -56,6 +55,7 @@ namespace styles {
56
55
  backgroundColor: 'transparent !custom',
57
56
  border: 'none !custom',
58
57
  boxSizing: 'border-box',
58
+ color: 'content.primary',
59
59
  display: 'inline-flex',
60
60
  height: '16',
61
61
  justifyContent: 'center',