@tempoxyz/ds 0.3.11 → 0.3.13

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 (212) hide show
  1. package/README.md +7 -6
  2. package/dist/docs/AGENTS.md +8 -5
  3. package/dist/docs/index.md +143 -135
  4. package/dist/docs/marketing/introduction/getting-started.md +241 -0
  5. package/dist/docs/{components → product/components}/accordion.md +8 -8
  6. package/dist/docs/{components → product/components}/address-card.md +5 -5
  7. package/dist/docs/{components → product/components}/agent-logo.md +5 -5
  8. package/dist/docs/{components → product/components}/alert-dialog.md +11 -11
  9. package/dist/docs/{components → product/components}/alert.md +11 -11
  10. package/dist/docs/{components → product/components}/amount-input.md +13 -13
  11. package/dist/docs/{components → product/components}/amount.md +8 -8
  12. package/dist/docs/{components → product/components}/app-shell.md +13 -13
  13. package/dist/docs/{components → product/components}/asset-chip.md +11 -11
  14. package/dist/docs/{components → product/components}/autocomplete.md +10 -9
  15. package/dist/docs/{components → product/components}/avatar.md +8 -8
  16. package/dist/docs/{components → product/components}/badge.md +9 -9
  17. package/dist/docs/{components → product/components}/badged-logo.md +6 -6
  18. package/dist/docs/{components → product/components}/banner.md +8 -8
  19. package/dist/docs/{components → product/components}/bar-chart.md +7 -7
  20. package/dist/docs/{components → product/components}/breadcrumbs.md +8 -8
  21. package/dist/docs/{components → product/components}/button-group.md +8 -8
  22. package/dist/docs/{components → product/components}/button.md +17 -17
  23. package/dist/docs/{components → product/components}/calendar.md +8 -8
  24. package/dist/docs/{components → product/components}/callout.md +5 -5
  25. package/dist/docs/{components → product/components}/checkbox-group.md +13 -13
  26. package/dist/docs/{components → product/components}/checkbox.md +12 -12
  27. package/dist/docs/{components → product/components}/choice-group.md +14 -14
  28. package/dist/docs/{components → product/components}/choicebox.md +9 -9
  29. package/dist/docs/{components → product/components}/code.md +5 -5
  30. package/dist/docs/{components → product/components}/combobox.md +9 -9
  31. package/dist/docs/{components → product/components}/container.md +7 -7
  32. package/dist/docs/{components → product/components}/copy-button.md +13 -13
  33. package/dist/docs/{components → product/components}/date-picker.md +11 -11
  34. package/dist/docs/{components → product/components}/dialog.md +17 -17
  35. package/dist/docs/{components → product/components}/drawer.md +11 -11
  36. package/dist/docs/{components → product/components}/empty.md +9 -9
  37. package/dist/docs/{components → product/components}/field.md +14 -14
  38. package/dist/docs/{components → product/components}/fieldset.md +6 -6
  39. package/dist/docs/{components → product/components}/frame.md +9 -9
  40. package/dist/docs/{components → product/components}/gauge.md +7 -7
  41. package/dist/docs/{components → product/components}/get-started-visual.md +4 -4
  42. package/dist/docs/{components → product/components}/grid.md +7 -7
  43. package/dist/docs/{components → product/components}/hero-visual.md +4 -4
  44. package/dist/docs/{components → product/components}/hex.md +9 -9
  45. package/dist/docs/{components → product/components}/icon-tile.md +8 -8
  46. package/dist/docs/{components → product/components}/identicon.md +7 -7
  47. package/dist/docs/{components → product/components}/inline.md +7 -7
  48. package/dist/docs/{components → product/components}/inset.md +8 -8
  49. package/dist/docs/{components → product/components}/kbd.md +8 -8
  50. package/dist/docs/{components → product/components}/list-group.md +24 -24
  51. package/dist/docs/{components → product/components}/loading-dots.md +8 -8
  52. package/dist/docs/{components → product/components}/menu.md +14 -14
  53. package/dist/docs/{components → product/components}/native-select.md +7 -7
  54. package/dist/docs/{components → product/components}/network-logo.md +7 -7
  55. package/dist/docs/{components → product/components}/number-field.md +8 -8
  56. package/dist/docs/{components → product/components}/otp-field.md +9 -9
  57. package/dist/docs/{components → product/components}/pagination.md +8 -8
  58. package/dist/docs/{components → product/components}/popover.md +11 -11
  59. package/dist/docs/{components → product/components}/progress.md +10 -10
  60. package/dist/docs/{components → product/components}/qr.md +8 -8
  61. package/dist/docs/{components → product/components}/radio-group.md +10 -10
  62. package/dist/docs/{components → product/components}/secret-value.md +8 -8
  63. package/dist/docs/{components → product/components}/select.md +13 -13
  64. package/dist/docs/{components → product/components}/separator.md +7 -7
  65. package/dist/docs/{components → product/components}/sidebar-menu.md +11 -11
  66. package/dist/docs/{components → product/components}/skeleton.md +9 -9
  67. package/dist/docs/{components → product/components}/slider.md +8 -8
  68. package/dist/docs/{components → product/components}/snippet.md +10 -10
  69. package/dist/docs/{components → product/components}/spinner.md +12 -12
  70. package/dist/docs/{components → product/components}/split-bar.md +5 -5
  71. package/dist/docs/{components → product/components}/split-button.md +11 -11
  72. package/dist/docs/{components → product/components}/stack.md +8 -8
  73. package/dist/docs/{components → product/components}/status-chip.md +7 -7
  74. package/dist/docs/{components → product/components}/status-indicator.md +6 -6
  75. package/dist/docs/{components → product/components}/status-row.md +7 -7
  76. package/dist/docs/{components → product/components}/stepper.md +9 -9
  77. package/dist/docs/{components → product/components}/success-hero.md +5 -5
  78. package/dist/docs/{components → product/components}/surface.md +11 -11
  79. package/dist/docs/{components → product/components}/switch.md +11 -11
  80. package/dist/docs/{components → product/components}/table.md +16 -16
  81. package/dist/docs/{components → product/components}/tabs.md +11 -11
  82. package/dist/docs/{components → product/components}/tempo-logo.md +4 -4
  83. package/dist/docs/{components → product/components}/text-input.md +14 -14
  84. package/dist/docs/{components → product/components}/textarea.md +7 -7
  85. package/dist/docs/{components → product/components}/toast.md +11 -11
  86. package/dist/docs/{components → product/components}/token-logo.md +16 -16
  87. package/dist/docs/{components → product/components}/token.md +10 -10
  88. package/dist/docs/{components → product/components}/tooltip.md +11 -11
  89. package/dist/docs/{components → product/components}/verification-code.md +4 -4
  90. package/dist/docs/{components → product/components}/visual.md +5 -5
  91. package/dist/docs/product/components.md +203 -0
  92. package/dist/docs/{foundations → product/foundations}/accessibility.md +16 -16
  93. package/dist/docs/{foundations → product/foundations}/agents.md +17 -17
  94. package/dist/docs/{foundations → product/foundations}/color.md +7 -7
  95. package/dist/docs/{foundations → product/foundations}/content/tone.md +7 -7
  96. package/dist/docs/{foundations → product/foundations}/content/voice.md +2 -2
  97. package/dist/docs/{foundations → product/foundations}/content/writing-style.md +8 -8
  98. package/dist/docs/{foundations → product/foundations}/iconography.md +11 -11
  99. package/dist/docs/{foundations → product/foundations}/intent.md +28 -28
  100. package/dist/docs/{foundations → product/foundations}/layout.md +22 -22
  101. package/dist/docs/product/foundations/linter.md +496 -0
  102. package/dist/docs/{foundations → product/foundations}/motion.md +7 -7
  103. package/dist/docs/{foundations → product/foundations}/radius-and-padding.md +3 -3
  104. package/dist/docs/{foundations → product/foundations}/typography.md +4 -4
  105. package/dist/docs/{introduction → product/introduction}/faq.md +22 -21
  106. package/dist/docs/{introduction → product/introduction}/getting-started.md +4 -4
  107. package/dist/docs/{patterns → product/patterns}/blockchain-values.md +20 -20
  108. package/dist/docs/{patterns → product/patterns}/dashboards.md +28 -28
  109. package/dist/docs/{patterns → product/patterns}/destructive-actions.md +16 -16
  110. package/dist/docs/{patterns → product/patterns}/empty-states.md +14 -14
  111. package/dist/docs/{patterns → product/patterns}/errors-and-validation.md +23 -23
  112. package/dist/docs/{patterns → product/patterns}/feedback-and-status.md +31 -31
  113. package/dist/docs/{patterns → product/patterns}/forms.md +24 -24
  114. package/dist/docs/{patterns → product/patterns}/loading.md +19 -19
  115. package/dist/docs/{patterns → product/patterns}/navigation.md +23 -23
  116. package/dist/docs/{patterns → product/patterns}/payments.md +20 -20
  117. package/dist/docs/{patterns → product/patterns}/responsive-layout.md +23 -23
  118. package/dist/docs/{patterns → product/patterns}/tables-and-lists.md +19 -19
  119. package/dist/docs/{products → product/products}/tempo-console.md +12 -12
  120. package/dist/docs/{products → product/products}/tempo-performance.md +11 -11
  121. package/dist/docs/{products → product/products}/tempo-wallet.md +12 -12
  122. package/dist/marketing/index.d.ts +4 -0
  123. package/dist/marketing/index.d.ts.map +1 -0
  124. package/dist/marketing/index.js +4 -0
  125. package/dist/marketing/index.js.map +1 -0
  126. package/dist/marketing/index.js.zyzz.json +1 -0
  127. package/dist/marketing/vars.d.ts +907 -0
  128. package/dist/marketing/vars.d.ts.map +1 -0
  129. package/dist/marketing/vars.js +15 -0
  130. package/dist/marketing/vars.js.map +1 -0
  131. package/dist/marketing/vars.js.zyzz.json +1 -0
  132. package/dist/marketing/zyzz.config.d.ts +4512 -0
  133. package/dist/marketing/zyzz.config.d.ts.map +1 -0
  134. package/dist/marketing/zyzz.config.js +63 -0
  135. package/dist/marketing/zyzz.config.js.map +1 -0
  136. package/dist/marketing/zyzz.config.js.zyzz.json +1 -0
  137. package/dist/oxlint/index.d.ts +12 -1
  138. package/dist/oxlint/index.d.ts.map +1 -1
  139. package/dist/oxlint/index.js +39 -1
  140. package/dist/oxlint/index.js.map +1 -1
  141. package/dist/oxlint/internal/Docs.d.ts +9 -0
  142. package/dist/oxlint/internal/Docs.d.ts.map +1 -0
  143. package/dist/oxlint/internal/Docs.js +15 -0
  144. package/dist/oxlint/internal/Docs.js.map +1 -0
  145. package/dist/oxlint/internal/Imports.d.ts +1 -1
  146. package/dist/oxlint/internal/Imports.d.ts.map +1 -1
  147. package/dist/oxlint/internal/Imports.js +2 -0
  148. package/dist/oxlint/internal/Imports.js.map +1 -1
  149. package/dist/oxlint/internal/Styles.d.ts +40 -0
  150. package/dist/oxlint/internal/Styles.d.ts.map +1 -0
  151. package/dist/oxlint/internal/Styles.js +194 -0
  152. package/dist/oxlint/internal/Styles.js.map +1 -0
  153. package/dist/oxlint/internal/Tokens.d.ts +16 -0
  154. package/dist/oxlint/internal/Tokens.d.ts.map +1 -0
  155. package/dist/oxlint/internal/Tokens.js +39 -0
  156. package/dist/oxlint/internal/Tokens.js.map +1 -0
  157. package/dist/oxlint/rules/NoCrossSurface.d.ts +2 -2
  158. package/dist/oxlint/rules/NoCrossSurface.js +3 -3
  159. package/dist/oxlint/rules/NoCrossSurface.js.map +1 -1
  160. package/dist/oxlint/rules/NoCustomValues.d.ts +11 -0
  161. package/dist/oxlint/rules/NoCustomValues.d.ts.map +1 -0
  162. package/dist/oxlint/rules/NoCustomValues.js +150 -0
  163. package/dist/oxlint/rules/NoCustomValues.js.map +1 -0
  164. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts +11 -0
  165. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts.map +1 -0
  166. package/dist/oxlint/rules/NoSingleKeyShortcuts.js +158 -0
  167. package/dist/oxlint/rules/NoSingleKeyShortcuts.js.map +1 -0
  168. package/dist/oxlint/rules/PreferComponent.d.ts +3 -2
  169. package/dist/oxlint/rules/PreferComponent.d.ts.map +1 -1
  170. package/dist/oxlint/rules/PreferComponent.js +11 -4
  171. package/dist/oxlint/rules/PreferComponent.js.map +1 -1
  172. package/dist/oxlint/rules/PreferLayout.d.ts +9 -0
  173. package/dist/oxlint/rules/PreferLayout.d.ts.map +1 -0
  174. package/dist/oxlint/rules/PreferLayout.js +90 -0
  175. package/dist/oxlint/rules/PreferLayout.js.map +1 -0
  176. package/dist/oxlint/rules/PreferProgress.d.ts +9 -0
  177. package/dist/oxlint/rules/PreferProgress.d.ts.map +1 -0
  178. package/dist/oxlint/rules/PreferProgress.js +43 -0
  179. package/dist/oxlint/rules/PreferProgress.js.map +1 -0
  180. package/dist/oxlint/rules/PreferSurface.d.ts +9 -0
  181. package/dist/oxlint/rules/PreferSurface.d.ts.map +1 -0
  182. package/dist/oxlint/rules/PreferSurface.js +55 -0
  183. package/dist/oxlint/rules/PreferSurface.js.map +1 -0
  184. package/dist/oxlint/rules/RequireAccessibleName.d.ts.map +1 -1
  185. package/dist/oxlint/rules/RequireAccessibleName.js +3 -1
  186. package/dist/oxlint/rules/RequireAccessibleName.js.map +1 -1
  187. package/dist/oxlint/rules/RequireScrollRegion.d.ts +11 -0
  188. package/dist/oxlint/rules/RequireScrollRegion.d.ts.map +1 -0
  189. package/dist/oxlint/rules/RequireScrollRegion.js +71 -0
  190. package/dist/oxlint/rules/RequireScrollRegion.js.map +1 -0
  191. package/dist/web/icons/index.js.zyzz.json +1 -0
  192. package/package.json +6 -1
  193. package/src/marketing/README.md +21 -0
  194. package/src/marketing/index.ts +3 -0
  195. package/src/marketing/vars.ts +751 -0
  196. package/src/marketing/zyzz.config.ts +376 -0
  197. package/src/oxlint/index.ts +40 -1
  198. package/src/oxlint/internal/Docs.ts +18 -0
  199. package/src/oxlint/internal/Imports.ts +2 -1
  200. package/src/oxlint/internal/Styles.ts +240 -0
  201. package/src/oxlint/internal/Tokens.ts +43 -0
  202. package/src/oxlint/rules/NoCrossSurface.ts +3 -3
  203. package/src/oxlint/rules/NoCustomValues.ts +170 -0
  204. package/src/oxlint/rules/NoSingleKeyShortcuts.ts +190 -0
  205. package/src/oxlint/rules/PreferComponent.ts +11 -4
  206. package/src/oxlint/rules/PreferLayout.ts +96 -0
  207. package/src/oxlint/rules/PreferProgress.ts +49 -0
  208. package/src/oxlint/rules/PreferSurface.ts +70 -0
  209. package/src/oxlint/rules/RequireAccessibleName.ts +3 -1
  210. package/src/oxlint/rules/RequireScrollRegion.ts +92 -0
  211. package/dist/docs/components.md +0 -203
  212. package/dist/docs/foundations/linter.md +0 -296
@@ -0,0 +1,496 @@
1
+ # Linter
2
+
3
+ Oxlint rules that check how your app uses Tempo Design System.
4
+
5
+ ## Overview
6
+
7
+ The library ships an Oxlint plugin that reports the mistakes types cannot catch, such as an unnamed icon-only [Button](../components/button.md), an import from an internal path, or a native control or hand-built card that a component replaces.
8
+
9
+ ## Set Up the Linter
10
+
11
+ Spread the configuration for your surface, web, mobile, or marketing, into the lint options of Vite Plus, then run the linter.
12
+
13
+ ```ts title="vite.config.ts"
14
+ import { web } from '@tempoxyz/ds/oxlint'
15
+ import { defineConfig } from 'vite-plus'
16
+
17
+ export default defineConfig({ lint: web })
18
+ ```
19
+
20
+ ```sh
21
+ vp lint
22
+ ```
23
+
24
+ To change a severity, spread the rules and override one.
25
+
26
+ ```ts title="vite.config.ts"
27
+ import { web } from '@tempoxyz/ds/oxlint'
28
+ import { defineConfig } from 'vite-plus'
29
+
30
+ export default defineConfig({
31
+ lint: { ...web, rules: { ...web.rules, 'tds/no-raw-values': 'error' } },
32
+ })
33
+ ```
34
+
35
+ Without Vite Plus, register both plugins and enable the rules in an Oxlint configuration file.
36
+
37
+ ```json title=".oxlintrc.json"
38
+ {
39
+ "jsPlugins": [
40
+ { "name": "tds", "specifier": "@tempoxyz/ds/oxlint" },
41
+ { "name": "zyzz", "specifier": "zyzz/oxlint" }
42
+ ],
43
+ "rules": {
44
+ "tds/no-cross-surface": ["error", { "surface": "web" }],
45
+ "tds/no-custom-values": "warn",
46
+ "tds/no-internal-imports": "error",
47
+ "tds/no-raw-values": "warn",
48
+ "tds/no-single-key-shortcuts": "warn",
49
+ "tds/prefer-component": "warn",
50
+ "tds/prefer-layout": "warn",
51
+ "tds/prefer-progress": "warn",
52
+ "tds/prefer-surface": "warn",
53
+ "tds/require-accessible-name": "error",
54
+ "tds/require-scroll-region": "warn"
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Rules
60
+
61
+ ### Import From Public Entrypoints
62
+
63
+ Reports a library import from a path that the package does not publish. The root, icons, mobile, and oxlint entrypoints pass, and so do icon SVG and font files.
64
+
65
+ ```json
66
+ { "rules": { "tds/no-internal-imports": "error" } }
67
+ ```
68
+
69
+ **Do:** Import components from `@tempoxyz/ds` and icons from `@tempoxyz/ds/icons`.
70
+
71
+ ````tsx
72
+ ```tsx
73
+ import { Spinner } from '@tempoxyz/ds'
74
+ import { Copy } from '@tempoxyz/ds/icons'
75
+ ```
76
+ ````
77
+
78
+ **Don't:** Import from `src` or `dist`. Internal paths change without a release note.
79
+
80
+ ````tsx
81
+ ```tsx
82
+ import { Spinner } from '@tempoxyz/ds/src/web'
83
+ // @lint: tds/no-internal-imports: '@tempoxyz/ds/src/web' is not a published entrypoint. Import from '@tempoxyz/ds', '@tempoxyz/ds/mobile', or their `icons` subpaths.
84
+ import { Copy } from '@tempoxyz/ds/dist/icons'
85
+ // @lint: tds/no-internal-imports: '@tempoxyz/ds/dist/icons' is not a published entrypoint. Import from '@tempoxyz/ds', '@tempoxyz/ds/mobile', or their `icons` subpaths.
86
+ ```
87
+ ````
88
+
89
+ ### Stay on One Surface
90
+
91
+ Reports an import from the surface that your app does not render. Without a surface option, it reports a file that imports from both surfaces.
92
+
93
+ ```json
94
+ { "rules": { "tds/no-cross-surface": ["error", { "surface": "web" }] } }
95
+ ```
96
+
97
+ **Do:** Import every component and icon of a React Native app from the Mobile entrypoints.
98
+
99
+ ````tsx
100
+ ```tsx
101
+ import { Toggle } from '@tempoxyz/ds/mobile'
102
+ import { Copy } from '@tempoxyz/ds/mobile/icons'
103
+ ```
104
+ ````
105
+
106
+ **Don't:** Mix surfaces in one app. Each surface owns its variables, and a Web component does not render in React Native.
107
+
108
+ ````tsx
109
+ ```tsx
110
+ import { Toggle } from '@tempoxyz/ds/mobile'
111
+ import { Switch } from '@tempoxyz/ds'
112
+ // @lint: tds/no-cross-surface: '@tempoxyz/ds' belongs to the web surface, but this app uses the mobile surface.
113
+ ```
114
+ ````
115
+
116
+ ### Name Controls Without Text
117
+
118
+ Reports a library component that renders no text and has no accessible name, such as an icon-only [Button](../components/button.md) or a [Gauge](../components/gauge.md).
119
+
120
+ ```json
121
+ { "rules": { "tds/require-accessible-name": "error" } }
122
+ ```
123
+
124
+ **Do:** Name the action in `aria-label`, on the button or on the trigger that renders it.
125
+
126
+ ````tsx
127
+ ```tsx
128
+ <Button aria-label="Copy address" shape="icon">
129
+ <Copy />
130
+ </Button>
131
+ ```
132
+ ````
133
+
134
+ **Don't:** Leave an icon-only button or a [Gauge](../components/gauge.md) unnamed. Screen readers announce only its role.
135
+
136
+ ````tsx
137
+ ```tsx
138
+ <Button shape="icon">
139
+ <Copy />
140
+ </Button>
141
+ // @lint: tds/require-accessible-name: 'Button' renders no text. Name it with `aria-label` or `aria-labelledby`.
142
+ ```
143
+ ````
144
+
145
+ ### Name Scroll Regions
146
+
147
+ Reports a native element that scrolls without a role, a tab stop, and a name. A container whose content holds a link, a button, or a field passes, since its content takes focus.
148
+
149
+ ```json
150
+ { "rules": { "tds/require-scroll-region": "warn" } }
151
+ ```
152
+
153
+ **Do:** Name the region and give it a tab stop, so keyboards can scroll it.
154
+
155
+ ````tsx
156
+ ```tsx
157
+ <div aria-label="Fee schedule" role="region" {...styles.scroll()} tabIndex={0}>
158
+ <Table.Root>{rows}</Table.Root>
159
+ </div>
160
+ ```
161
+ ````
162
+
163
+ **Don't:** Leave a scroll container without a tab stop. Keyboard users cannot reach the hidden content.
164
+
165
+ ````tsx
166
+ ```tsx
167
+ <div style={{ overflowX: 'auto' }}>
168
+ // @lint: tds/require-scroll-region: This scrolling <div> needs role="region", tabIndex={0}, and an aria-label, so keyboard and screen reader users can reach and identify it.
169
+ <Table.Root>{rows}</Table.Root>
170
+ </div>
171
+ ```
172
+ ````
173
+
174
+ ### Require a Modifier on Shortcuts
175
+
176
+ Warns on a key listener on the window or the document that matches one printable character, such as G or /, and reads no modifier. A character key on the whole page fires while people type or dictate ([SC 2.1.4](https://www.w3.org/WAI/WCAG22/Understanding/character-key-shortcuts.html)).
177
+
178
+ ```json
179
+ { "rules": { "tds/no-single-key-shortcuts": "warn" } }
180
+ ```
181
+
182
+ A single-key shortcut is valid when people can turn it off or remap it, or when it works only while a component has focus. The rule cannot detect either case. If a shortcut meets one of them, disable the rule on that line and state the reason.
183
+
184
+ ```tsx
185
+ window.addEventListener('keydown', (event) => {
186
+ // oxlint-disable-next-line tds/no-single-key-shortcuts -- Settings turn this shortcut off.
187
+ if (shortcuts.enabled && event.key === '/') open()
188
+ })
189
+ ```
190
+
191
+ **Do:** Require Command or Control, and show the shortcut with [Kbd](../components/kbd.md).
192
+
193
+ ````tsx
194
+ ```tsx
195
+ window.addEventListener('keydown', (event) => {
196
+ if (event.key === 'k' && (event.metaKey || event.ctrlKey)) open()
197
+ })
198
+ ```
199
+ ````
200
+
201
+ **Don't:** Bind a lone character key on the whole page, unless people can turn it off or remap it.
202
+
203
+ ````tsx
204
+ ```tsx
205
+ window.addEventListener('keydown', (event) => {
206
+ if (event.key === '/') open()
207
+ // @lint: tds/no-single-key-shortcuts: '/' is a single-key shortcut on the whole page. Require a modifier, such as metaKey or ctrlKey, or let people turn it off or remap it (WCAG 2.1.4).
208
+ })
209
+ ```
210
+ ````
211
+
212
+ ### Prefer Library Components
213
+
214
+ Warns on a native element that a library component replaces, such as a button, a checkbox, a dialog, a table, or a description list. The message links the docs page of the component. Elements in a render prop pass, and an allow list skips the elements you name.
215
+
216
+ ```json
217
+ { "rules": { "tds/prefer-component": ["warn", { "allow": ["table"] }] } }
218
+ ```
219
+
220
+ **Do:** Use [Checkbox](../components/checkbox.md) and [Button](../components/button.md), which bring Tempo states, focus rings, and motion.
221
+
222
+ ````tsx
223
+ ```tsx
224
+ <Checkbox defaultChecked />
225
+ <Button variant="secondary">Cancel</Button>
226
+ ```
227
+ ````
228
+
229
+ **Don't:** Restyle a native control that the library already ships.
230
+
231
+ ````tsx
232
+ ```tsx
233
+ <input defaultChecked type="checkbox" />
234
+ // @lint: tds/prefer-component: Use 'Checkbox' from '@tempoxyz/ds' instead of <input>. See https://ds.tehq.dev/docs/components/checkbox
235
+ <button type="button">Cancel</button>
236
+ // @lint: tds/prefer-component: Use 'Button' from '@tempoxyz/ds' instead of <button>. See https://ds.tehq.dev/docs/components/button
237
+ ```
238
+ ````
239
+
240
+ ### Use Surface for Cards
241
+
242
+ Warns on an article, aside, div, list item, or section whose styles draw a card: a corner radius and padding with a border or a background. Pills and positioned layers pass.
243
+
244
+ ```json
245
+ { "rules": { "tds/prefer-surface": "warn" } }
246
+ ```
247
+
248
+ **Do:** Use [Surface](../components/surface.md), which sets the radius and padding together.
249
+
250
+ ````tsx
251
+ ```tsx
252
+ <Surface>
253
+ <Surface.Title>Balance</Surface.Title>
254
+ </Surface>
255
+ ```
256
+ ````
257
+
258
+ **Don't:** Rebuild a card from tokens. The radius and padding drift apart.
259
+
260
+ ````tsx
261
+ ```tsx
262
+ namespace styles {
263
+ export const card = style({
264
+ backgroundColor: 'background.elevated',
265
+ borderRadius: 'sm',
266
+ padding: '16',
267
+ })
268
+ }
269
+
270
+ ;<div {...styles.card()} />
271
+ // @lint: tds/prefer-surface: Use 'Surface' from '@tempoxyz/ds' instead of styling <div> as a card. It sets the radius and padding together.
272
+ ```
273
+ ````
274
+
275
+ ### Use Layout Components
276
+
277
+ Warns on a block element whose only styles lay out its children with flex or grid and a gap. A column maps to [Stack](../components/stack.md), a row to [Inline](../components/inline.md), and equal tracks to [Grid](../components/grid.md). An element with any other declaration or a class name passes.
278
+
279
+ ```json
280
+ { "rules": { "tds/prefer-layout": "warn" } }
281
+ ```
282
+
283
+ **Do:** Space siblings with a layout component and its gap token.
284
+
285
+ ````tsx
286
+ ```tsx
287
+ <Stack gap="16">
288
+ <Field.Root />
289
+ <Field.Root />
290
+ </Stack>
291
+ ```
292
+ ````
293
+
294
+ **Don't:** Hand-build a flex or grid wrapper that a layout component replaces.
295
+
296
+ ````tsx
297
+ ```tsx
298
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
299
+ // @lint: tds/prefer-layout: Use 'Stack' from '@tempoxyz/ds' instead of laying out <div> with flex and a gap.
300
+ <Field.Root />
301
+ <Field.Root />
302
+ </div>
303
+ ```
304
+ ````
305
+
306
+ ### Use Progress for Bars
307
+
308
+ Warns on an empty div or span whose inline width is a computed percentage, which draws the fill of a hand-built bar. An element with children passes, since a resizable pane sets its width the same way.
309
+
310
+ ```json
311
+ { "rules": { "tds/prefer-progress": "warn" } }
312
+ ```
313
+
314
+ **Do:** Use [Progress](../components/progress.md), or `ListGroup.Meter` in a [ListGroup](../components/list-group.md) row, which announce the value.
315
+
316
+ ````tsx
317
+ ```tsx
318
+ <Progress.Root value={66}>
319
+ <Progress.Track>
320
+ <Progress.Indicator />
321
+ </Progress.Track>
322
+ </Progress.Root>
323
+ ```
324
+ ````
325
+
326
+ **Don't:** Draw a bar from a sized element. Screen readers announce nothing.
327
+
328
+ ````tsx
329
+ ```tsx
330
+ <div {...styles.track()}>
331
+ <div style={{ width: `${used}%` }} />
332
+ // @lint: tds/prefer-progress: Use 'Progress' from '@tempoxyz/ds', or 'ListGroup.Meter' in a ListGroup row, instead of drawing a bar with <div> and a percentage width.
333
+ </div>
334
+ ```
335
+ ````
336
+
337
+ ### Style With Tokens
338
+
339
+ Warns on a raw color, length, or font family in an inline style. A value that reads a custom property passes.
340
+
341
+ ```json
342
+ { "rules": { "tds/no-raw-values": "warn" } }
343
+ ```
344
+
345
+ **Do:** Set colors and spacing with tokens in a `style` definition.
346
+
347
+ ````tsx
348
+ ```tsx
349
+ namespace styles {
350
+ export const card = style({ padding: '16' })
351
+ }
352
+
353
+ ;<div {...styles.card()} />
354
+ ```
355
+ ````
356
+
357
+ **Don't:** Hardcode colors and lengths in inline styles. They do not follow the scheme or the token scale.
358
+
359
+ ````tsx
360
+ ```tsx
361
+ <div style={{ color: '#000', padding: 16 }} />
362
+ // @lint: tds/no-raw-values: 'color' sets the raw value '#000'. Use a token through a Zyzz style instead.
363
+ // @lint: tds/no-raw-values: 'padding' sets the raw value 16. Use a token through a Zyzz style instead.
364
+ ```
365
+ ````
366
+
367
+ ### Use Tokens for Custom Values
368
+
369
+ Warns on a `!custom` value in a `style` or `variants` definition that equals a token: a px or rem length that equals a spacing, radius, size, or container step, or a `zIndex` number that equals a layer. The message names the token. A value that no token fits, such as `'13px !custom'`, passes.
370
+
371
+ ```json
372
+ { "rules": { "tds/no-custom-values": "warn" } }
373
+ ```
374
+
375
+ * **Spacing ('16'):** Padding, margins, and gaps, with keys in px.
376
+ * **Radius ('xs'):** Corners, from `3xs` at 4px to `2xl` at 64px.
377
+ * **Layers ('popover'):** `overlay` 40, `popover` 50, `modal` 60, and `toast` 1000.
378
+
379
+ **Do:** Set lengths and layers with tokens.
380
+
381
+ ````tsx
382
+ ```tsx
383
+ style({ borderRadius: 'xs', padding: '16', zIndex: 'popover' })
384
+ ```
385
+ ````
386
+
387
+ **Don't:** Mark a value with `!custom` when a token equals it.
388
+
389
+ ````tsx
390
+ ```tsx
391
+ style({ borderRadius: '12px !custom', zIndex: '50 !custom' })
392
+ // @lint: tds/no-custom-values: 'borderRadius' sets the custom value '12px !custom', which equals a token. Use the radius token 'xs'.
393
+ // @lint: tds/no-custom-values: 'zIndex' sets the custom value '50 !custom', which equals a token. Use the zIndex token 'popover'.
394
+ ```
395
+ ````
396
+
397
+ ## Zyzz Rules
398
+
399
+ Both configurations also turn on the rules of the Zyzz plugin, which check style definitions and their use.
400
+
401
+ ### Merge Styling Props Into the Style
402
+
403
+ Reports a className or style prop that would overwrite a style spread.
404
+
405
+ ```json
406
+ { "rules": { "zyzz/no-conflicting-props": "error" } }
407
+ ```
408
+
409
+ **Do:** Pass the caller's class into the style call, which merges it.
410
+
411
+ ````tsx
412
+ ```tsx
413
+ <div {...styles.card({ className: props.className })} />
414
+ ```
415
+ ````
416
+
417
+ **Don't:** Set a class beside a style spread. One overwrites the other.
418
+
419
+ ````tsx
420
+ ```tsx
421
+ <div className="card" {...styles.card()} />
422
+ // @lint: zyzz/no-conflicting-props: Pass 'className' into the Zyzz style call to merge styling props.
423
+ ```
424
+ ````
425
+
426
+ ### Remove Unused Styles
427
+
428
+ Warns on a style in a styles namespace that nothing applies.
429
+
430
+ ```json
431
+ { "rules": { "zyzz/no-unused": "warn" } }
432
+ ```
433
+
434
+ **Do:** Keep only the styles that the module applies.
435
+
436
+ ````tsx
437
+ ```tsx
438
+ namespace styles {
439
+ export const card = style({ padding: '16' })
440
+ }
441
+
442
+ ;<div {...styles.card()} />
443
+ ```
444
+ ````
445
+
446
+ **Don't:** Leave a style that nothing applies. It still ships in the stylesheet.
447
+
448
+ ````tsx
449
+ ```tsx
450
+ namespace styles {
451
+ export const card = style({ padding: '16' })
452
+
453
+ export const legacy = style({ padding: '8' })
454
+ // @lint: zyzz/no-unused: Style 'styles.legacy' is never used.
455
+ }
456
+ ```
457
+ ````
458
+
459
+ ### Write Scalar Declarations
460
+
461
+ Reports a declaration whose value is not a string, a number, or a fallback array.
462
+
463
+ ```json
464
+ { "rules": { "zyzz/valid-styles": "error" } }
465
+ ```
466
+
467
+ **Do:** Set each side with its own property.
468
+
469
+ ````tsx
470
+ ```tsx
471
+ style({ paddingTop: '8' })
472
+ ```
473
+ ````
474
+
475
+ **Don't:** Nest an object inside a declaration.
476
+
477
+ ````tsx
478
+ ```tsx
479
+ style({ padding: { top: '8' } })
480
+ // @lint: zyzz/valid-styles: CSS declarations require scalar values or fallback arrays.
481
+ ```
482
+ ````
483
+
484
+ ## Related
485
+
486
+ [Agents](agents.md)
487
+
488
+ Covers the rules that coding agents follow and the checks they run.
489
+
490
+ [Accessibility](accessibility.md)
491
+
492
+ Covers the accessible names that the linter checks.
493
+
494
+ [Getting Started](../introduction/getting-started.md)
495
+
496
+ Covers the install and the Zyzz setup that the linter builds on.
@@ -17,7 +17,7 @@ Three ease-out curves cover interface motion, so each response starts at full sp
17
17
  * **Snappy (ease.snappy):** Short changes, such as hover, focus, presses, popovers, and menus.
18
18
  * **Overshoot (ease.overshoot):** Only physical feedback, such as switch thumbs and check marks. A dialog or menu would wobble.
19
19
  * **Spring (ease.spring):** Larger travel, such as dialogs, drawers, toasts, and tabs.
20
- * **Constant Rate (linear):** Continuous indicators only, such as [Spinner](/docs/components/spinner), which would pulse with easing.
20
+ * **Constant Rate (linear):** Continuous indicators only, such as [Spinner](../components/spinner.md), which would pulse with easing.
21
21
 
22
22
  ## Durations
23
23
 
@@ -57,7 +57,7 @@ Give every state change a transition, from hover and focus to checked, disabled,
57
57
  A transition reverses from its current point when the state flips back, so a quick hover in and out never jumps. Keep keyframes for feedback that plays once.
58
58
 
59
59
  * **State Changes (transition):** Hover, press, checked, and open states, such as the switch thumb.
60
- * **One-Shot Feedback (keyframes):** The 360ms nudge of an invalid [TextInput](/docs/components/text-input) or [OtpField](/docs/components/otp-field), and the 240ms pop of a [CopyButton](/docs/components/copy-button) check.
60
+ * **One-Shot Feedback (keyframes):** The 360ms nudge of an invalid [TextInput](../components/text-input.md) or [OtpField](../components/otp-field.md), and the 240ms pop of a [CopyButton](../components/copy-button.md) check.
61
61
 
62
62
  ### Animate Transform and Opacity
63
63
 
@@ -128,24 +128,24 @@ When the system asks for reduced motion, components remove movement and scaling,
128
128
  * **Overlays:** Popovers, menus, dialogs, and toasts fade in place, including the narrow-screen dialog sheet.
129
129
  * **Moving Indicators:** The tabs indicator and the switch thumb jump straight to their final position.
130
130
  * **Loading Indicators:** Spinners stop rotating, skeletons stop their sweep, and loading dots stop pulsing.
131
- * **Feedback:** [CopyButton](/docs/components/copy-button) skips its pop, and invalid fields skip their nudge.
131
+ * **Feedback:** [CopyButton](../components/copy-button.md) skips its pop, and invalid fields skip their nudge.
132
132
 
133
133
  ## Accessibility
134
134
 
135
- [Accessibility](/docs/foundations/accessibility#motion) sets the limits for flashing and for content that moves on its own.
135
+ [Accessibility](accessibility.md#motion) sets the limits for flashing and for content that moves on its own.
136
136
 
137
137
  * **Never Motion Alone (Field.Error):** Never convey information through motion alone. Pair a nudge on an invalid field with an error message.
138
138
 
139
139
  ## Related
140
140
 
141
- [Loading](/docs/patterns/loading)
141
+ [Loading](../patterns/loading.md)
142
142
 
143
143
  Covers spinners, skeletons, and progress.
144
144
 
145
- [Feedback and Status](/docs/patterns/feedback-and-status)
145
+ [Feedback and Status](../patterns/feedback-and-status.md)
146
146
 
147
147
  Covers toasts and confirmations.
148
148
 
149
- [Accessibility](/docs/foundations/accessibility)
149
+ [Accessibility](accessibility.md)
150
150
 
151
151
  Covers reduced motion and other preferences.
@@ -73,14 +73,14 @@ A layer inside another takes a smaller radius: a modal at 32px holds boxes at 16
73
73
 
74
74
  ## Related
75
75
 
76
- [Layout](/docs/foundations/layout)
76
+ [Layout](layout.md)
77
77
 
78
78
  Covers the radius, spacing, and shadow scales.
79
79
 
80
- [Surface](/docs/components/surface)
80
+ [Surface](../components/surface.md)
81
81
 
82
82
  Use for padded boxes and cards.
83
83
 
84
- [Dialog](/docs/components/dialog)
84
+ [Dialog](../components/dialog.md)
85
85
 
86
86
  Use for modals.
@@ -32,7 +32,7 @@ Six sets cover the interface, from hero titles down to small labels.
32
32
 
33
33
  ### Display
34
34
 
35
- Hero titles and large amounts, in light and regular weights that let size carry the emphasis. [Amount](/docs/components/amount) uses display type at its largest size.
35
+ Hero titles and large amounts, in light and regular weights that let size carry the emphasis. [Amount](../components/amount.md) uses display type at its largest size.
36
36
 
37
37
  * `display.d1`: 44px, weight 300, line height 41.8px
38
38
  * `display.d2`: 36px, weight 400, line height 34.2px
@@ -112,7 +112,7 @@ Keep headings in order. Choose the element by its place in the outline and the s
112
112
  </Field.Root>
113
113
  ```
114
114
 
115
- **Don't:** Use all caps or bold every line to create hierarchy. Write in [sentence case](/docs/foundations/content/writing-style#capitalization).
115
+ **Don't:** Use all caps or bold every line to create hierarchy. Write in [sentence case](content/writing-style.md#capitalization).
116
116
 
117
117
  ```tsx
118
118
  <p>
@@ -132,7 +132,7 @@ Keep headings in order. Choose the element by its place in the outline and the s
132
132
 
133
133
  ### Use Tabular Figures for Numbers
134
134
 
135
- Tabular figures align digits in columns and keep live values from shifting. [Amount](/docs/components/amount), [NumberField](/docs/components/number-field), [Slider](/docs/components/slider), and numeric table cells already set them.
135
+ Tabular figures align digits in columns and keep live values from shifting. [Amount](../components/amount.md), [NumberField](../components/number-field.md), [Slider](../components/slider.md), and numeric table cells already set them.
136
136
 
137
137
  **Do:** Align amounts with tabular figures, such as `Amount` with `align="right"`.
138
138
 
@@ -201,7 +201,7 @@ style({ fontVariantNumeric: 'tabular-nums !custom' })
201
201
 
202
202
  ### Use Monospace for Hashes and Code
203
203
 
204
- Set addresses, hashes, keys, and code in monospace, so similar characters stay distinct and equal-length values align. [Hex](/docs/components/hex), [Snippet](/docs/components/snippet), and [SecretValue](/docs/components/secret-value) apply it. Labels and prose stay out of it.
204
+ Set addresses, hashes, keys, and code in monospace, so similar characters stay distinct and equal-length values align. [Hex](../components/hex.md), [Snippet](../components/snippet.md), and [SecretValue](../components/secret-value.md) apply it. Labels and prose stay out of it.
205
205
 
206
206
  **Do:** Set hashes in `mono.m1`, so they align and `I`, `l`, `0`, and `O` stay distinct.
207
207
 
@@ -8,18 +8,19 @@ Common questions about building with, and contributing to, Tempo Design System.
8
8
 
9
9
  Choose the surface by the platform you ship to. The surfaces share a design language but not code, so don't import one from the other.
10
10
 
11
- | I am building... | Surface | Import |
12
- | ------------------------- | ------- | --------------------- |
13
- | A web application | Web | `@tempoxyz/ds` |
14
- | A React Native mobile app | Mobile | `@tempoxyz/ds/mobile` |
11
+ | I am building... | Surface | Import |
12
+ | ------------------------- | --------- | ------------------------ |
13
+ | A web application | Web | `@tempoxyz/ds` |
14
+ | A React Native mobile app | Mobile | `@tempoxyz/ds/mobile` |
15
+ | A marketing website | Marketing | `@tempoxyz/ds/marketing` |
15
16
 
16
- Web components render DOM elements and compile with a Zyzz bundler plugin. Mobile components render React Native views and compile with Metro. [Getting Started](/docs/introduction/getting-started) shows each setup.
17
+ Web components render DOM elements and compile with a Zyzz bundler plugin. Mobile components render React Native views and compile with Metro. [Getting Started](getting-started.md) shows each setup.
17
18
 
18
19
  ### Do I Need to Import a Stylesheet?
19
20
 
20
21
  No. The library publishes no stylesheet.
21
22
 
22
- * **Vite:** The [Vite plugin](/docs/introduction/getting-started#setup) emits the variables, the Inter, Pilat, and JetBrains Mono fonts, and keyframes once. Each component emits its own rules, so a build carries only the styles it uses.
23
+ * **Vite:** The [Vite plugin](getting-started.md#setup) emits the variables, the Inter, Pilat, and JetBrains Mono fonts, and keyframes once. Each component emits its own rules, so a build carries only the styles it uses.
23
24
  * **Rollup, Webpack, and esbuild:** The adapters emit a generated `/zyzz.css` that you load once.
24
25
  * **Mobile:** Metro compiles library and app styles during the bundle.
25
26
 
@@ -29,7 +30,7 @@ The Zyzz plugin is the only supported web setup.
29
30
 
30
31
  Use `style` and `variants` from `@tempoxyz/ds` with TDS tokens, such as `content.primary`, `background.elevated`, `'24'`, and `body.b2`. Group the definitions in a `namespace styles` block.
31
32
 
32
- If your app needs its own tokens, extend `variables` in your own Zyzz config, as the Custom Variables setup in [Getting Started](/docs/introduction/getting-started#setup) shows.
33
+ If your app needs its own tokens, extend `variables` in your own Zyzz config, as the Custom Variables setup in [Getting Started](getting-started.md#setup) shows.
33
34
 
34
35
  ## Components
35
36
 
@@ -61,7 +62,7 @@ If an issue already covers the proposal, reuse it. A proposal joins `@tempoxyz/d
61
62
 
62
63
  The library includes only components with a verified production family in Figma. Archived and experimental Figma components stay out until a production version exists.
63
64
 
64
- The [Components](/docs/components) overview lists what ships today. Sidebar pages marked 🚧 are not written yet.
65
+ The [Components](../components.md) overview lists what ships today. Sidebar pages marked 🚧 are not written yet.
65
66
 
66
67
  ### Which Components Exist on Mobile?
67
68
 
@@ -69,21 +70,21 @@ The [Components](/docs/components) overview lists what ships today. Sidebar page
69
70
 
70
71
  | Mobile | Web counterpart |
71
72
  | ------------ | --------------------------------------------------------------------------------- |
72
- | `Avatar` | [Avatar](/docs/components/avatar) |
73
- | `Badge` | [Badge](/docs/components/badge) |
74
- | `Button` | [Button](/docs/components/button) |
75
- | `CodeInput` | [OtpField](/docs/components/otp-field) |
76
- | `IconButton` | [Button](/docs/components/button) with `shape="icon"` |
77
- | `Skeleton` | [Skeleton](/docs/components/skeleton) |
78
- | `Spinner` | [Spinner](/docs/components/spinner) |
79
- | `TextButton` | [Button](/docs/components/button) with `variant="tertiary"` |
80
- | `TextInput` | [TextInput](/docs/components/text-input) inside a [Field](/docs/components/field) |
81
- | `Toast` | [Toast](/docs/components/toast) |
82
- | `Toggle` | [Switch](/docs/components/switch) |
73
+ | `Avatar` | [Avatar](../components/avatar.md) |
74
+ | `Badge` | [Badge](../components/badge.md) |
75
+ | `Button` | [Button](../components/button.md) |
76
+ | `CodeInput` | [OtpField](../components/otp-field.md) |
77
+ | `IconButton` | [Button](../components/button.md) with `shape="icon"` |
78
+ | `Skeleton` | [Skeleton](../components/skeleton.md) |
79
+ | `Spinner` | [Spinner](../components/spinner.md) |
80
+ | `TextButton` | [Button](../components/button.md) with `variant="tertiary"` |
81
+ | `TextInput` | [TextInput](../components/text-input.md) inside a [Field](../components/field.md) |
82
+ | `Toast` | [Toast](../components/toast.md) |
83
+ | `Toggle` | [Switch](../components/switch.md) |
83
84
 
84
85
  ### Do Web Components Work in Mobile Browsers?
85
86
 
86
- Yes. [Responsive Layout](/docs/patterns/responsive-layout) shows how to adapt a layout from a phone to a desktop.
87
+ Yes. [Responsive Layout](../patterns/responsive-layout.md) shows how to adapt a layout from a phone to a desktop.
87
88
 
88
89
  ## Design
89
90
 
@@ -123,7 +124,7 @@ On narrower screens, use the GitHub link at the bottom of the sidebar.
123
124
 
124
125
  ### How Should Coding Agents Use These Docs?
125
126
 
126
- Every page has a Markdown twin, `/llms.txt` indexes them all, and the library documents each export in its source. [Agents](/docs/foundations/agents) lists the files and the rules an agent follows when it generates Tempo UI.
127
+ Every page has a Markdown twin, `/llms.txt` indexes them all, and the library documents each export in its source. [Agents](../foundations/agents.md) lists the files and the rules an agent follows when it generates Tempo UI.
127
128
 
128
129
  ## License
129
130