@tempoxyz/ds 0.2.0 → 0.2.4

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 (428) hide show
  1. package/README.md +36 -0
  2. package/dist/mobile/components/Avatar.d.ts +1 -1
  3. package/dist/mobile/components/Avatar.d.ts.map +1 -1
  4. package/dist/mobile/components/Avatar.js.map +1 -1
  5. package/dist/mobile/components/Button.d.ts +2 -2
  6. package/dist/mobile/components/Button.d.ts.map +1 -1
  7. package/dist/mobile/components/Button.js +6 -2
  8. package/dist/mobile/components/Button.js.map +1 -1
  9. package/dist/mobile/components/CodeInput.d.ts +1 -1
  10. package/dist/mobile/components/CodeInput.d.ts.map +1 -1
  11. package/dist/mobile/components/CodeInput.js.map +1 -1
  12. package/dist/mobile/components/IconButton.d.ts +2 -2
  13. package/dist/mobile/components/IconButton.d.ts.map +1 -1
  14. package/dist/mobile/components/IconButton.js +6 -2
  15. package/dist/mobile/components/IconButton.js.map +1 -1
  16. package/dist/mobile/components/Skeleton.d.ts.map +1 -1
  17. package/dist/mobile/components/Skeleton.js.map +1 -1
  18. package/dist/mobile/components/Spinner.d.ts +4 -4
  19. package/dist/mobile/components/Spinner.d.ts.map +1 -1
  20. package/dist/mobile/components/Spinner.js +3 -3
  21. package/dist/mobile/components/Spinner.js.map +1 -1
  22. package/dist/mobile/components/TextButton.d.ts.map +1 -1
  23. package/dist/mobile/components/TextButton.js +7 -2
  24. package/dist/mobile/components/TextButton.js.map +1 -1
  25. package/dist/mobile/components/TextInput.d.ts.map +1 -1
  26. package/dist/mobile/components/TextInput.js +1 -1
  27. package/dist/mobile/components/TextInput.js.map +1 -1
  28. package/dist/mobile/components/Toast.d.ts +1 -1
  29. package/dist/mobile/components/Toast.d.ts.map +1 -1
  30. package/dist/mobile/components/Toast.js +1 -1
  31. package/dist/mobile/components/Toast.js.map +1 -1
  32. package/dist/mobile/components/Toggle.d.ts +2 -2
  33. package/dist/mobile/components/Toggle.js +2 -2
  34. package/dist/mobile/components/Toggle.js.map +1 -1
  35. package/dist/mobile/vars.d.ts +24 -0
  36. package/dist/mobile/vars.d.ts.map +1 -1
  37. package/dist/mobile/vars.js +12 -0
  38. package/dist/mobile/vars.js.map +1 -1
  39. package/dist/mobile/zyzz.config.d.ts +96 -0
  40. package/dist/mobile/zyzz.config.d.ts.map +1 -1
  41. package/dist/oxlint/index.d.ts +43 -0
  42. package/dist/oxlint/index.d.ts.map +1 -0
  43. package/dist/oxlint/index.js +68 -0
  44. package/dist/oxlint/index.js.map +1 -0
  45. package/dist/oxlint/internal/Imports.d.ts +22 -0
  46. package/dist/oxlint/internal/Imports.d.ts.map +1 -0
  47. package/dist/oxlint/internal/Imports.js +52 -0
  48. package/dist/oxlint/internal/Imports.js.map +1 -0
  49. package/dist/oxlint/rules/NoCrossSurface.d.ts +16 -0
  50. package/dist/oxlint/rules/NoCrossSurface.d.ts.map +1 -0
  51. package/dist/oxlint/rules/NoCrossSurface.js +55 -0
  52. package/dist/oxlint/rules/NoCrossSurface.js.map +1 -0
  53. package/dist/oxlint/rules/NoInternalImports.d.ts +8 -0
  54. package/dist/oxlint/rules/NoInternalImports.d.ts.map +1 -0
  55. package/dist/oxlint/rules/NoInternalImports.js +22 -0
  56. package/dist/oxlint/rules/NoInternalImports.js.map +1 -0
  57. package/dist/oxlint/rules/NoRawValues.d.ts +9 -0
  58. package/dist/oxlint/rules/NoRawValues.d.ts.map +1 -0
  59. package/dist/oxlint/rules/NoRawValues.js +73 -0
  60. package/dist/oxlint/rules/NoRawValues.js.map +1 -0
  61. package/dist/oxlint/rules/PreferComponent.d.ts +16 -0
  62. package/dist/oxlint/rules/PreferComponent.d.ts.map +1 -0
  63. package/dist/oxlint/rules/PreferComponent.js +92 -0
  64. package/dist/oxlint/rules/PreferComponent.js.map +1 -0
  65. package/dist/oxlint/rules/RequireAccessibleName.d.ts +9 -0
  66. package/dist/oxlint/rules/RequireAccessibleName.d.ts.map +1 -0
  67. package/dist/oxlint/rules/RequireAccessibleName.js +104 -0
  68. package/dist/oxlint/rules/RequireAccessibleName.js.map +1 -0
  69. package/dist/web/components/Accordion.css +1 -1
  70. package/dist/web/components/Accordion.d.ts +7 -7
  71. package/dist/web/components/Accordion.js.map +1 -1
  72. package/dist/web/components/Accordion.js.zyzz.json +1 -1
  73. package/dist/web/components/AlertDialog.css +1 -1
  74. package/dist/web/components/AlertDialog.d.ts.map +1 -1
  75. package/dist/web/components/AlertDialog.js +1 -1
  76. package/dist/web/components/AlertDialog.js.map +1 -1
  77. package/dist/web/components/AlertDialog.js.zyzz.json +1 -1
  78. package/dist/web/components/Amount.d.ts +10 -3
  79. package/dist/web/components/Amount.d.ts.map +1 -1
  80. package/dist/web/components/Amount.js +19 -9
  81. package/dist/web/components/Amount.js.map +1 -1
  82. package/dist/web/components/Amount.js.zyzz.json +1 -1
  83. package/dist/web/components/AmountInput.css +1 -1
  84. package/dist/web/components/AmountInput.d.ts +15 -2
  85. package/dist/web/components/AmountInput.d.ts.map +1 -1
  86. package/dist/web/components/AmountInput.js +43 -12
  87. package/dist/web/components/AmountInput.js.map +1 -1
  88. package/dist/web/components/AmountInput.js.zyzz.json +1 -1
  89. package/dist/web/components/AppShell.css +1 -1
  90. package/dist/web/components/AppShell.d.ts +10 -10
  91. package/dist/web/components/AppShell.js.map +1 -1
  92. package/dist/web/components/AppShell.js.zyzz.json +1 -1
  93. package/dist/web/components/Autocomplete.js.zyzz.json +1 -1
  94. package/dist/web/components/Avatar.css +1 -1
  95. package/dist/web/components/Avatar.d.ts +3 -3
  96. package/dist/web/components/Avatar.js.map +1 -1
  97. package/dist/web/components/Avatar.js.zyzz.json +1 -1
  98. package/dist/web/components/Banner.css +1 -1
  99. package/dist/web/components/Banner.js +3 -3
  100. package/dist/web/components/Banner.js.map +1 -1
  101. package/dist/web/components/Banner.js.zyzz.json +1 -1
  102. package/dist/web/components/Breadcrumbs.css +1 -1
  103. package/dist/web/components/Breadcrumbs.d.ts +4 -4
  104. package/dist/web/components/Breadcrumbs.js.map +1 -1
  105. package/dist/web/components/Breadcrumbs.js.zyzz.json +1 -1
  106. package/dist/web/components/Button.css +1 -1
  107. package/dist/web/components/Button.d.ts +12 -11
  108. package/dist/web/components/Button.d.ts.map +1 -1
  109. package/dist/web/components/Button.js +2 -2
  110. package/dist/web/components/Button.js.map +1 -1
  111. package/dist/web/components/Button.js.zyzz.json +1 -1
  112. package/dist/web/components/Calendar.css +1 -1
  113. package/dist/web/components/Calendar.d.ts.map +1 -1
  114. package/dist/web/components/Calendar.js +7 -5
  115. package/dist/web/components/Calendar.js.map +1 -1
  116. package/dist/web/components/Calendar.js.zyzz.json +1 -1
  117. package/dist/web/components/Callout.css +1 -1
  118. package/dist/web/components/Callout.d.ts +6 -6
  119. package/dist/web/components/Callout.d.ts.map +1 -1
  120. package/dist/web/components/Callout.js +5 -2
  121. package/dist/web/components/Callout.js.map +1 -1
  122. package/dist/web/components/Callout.js.zyzz.json +1 -1
  123. package/dist/web/components/Checkbox.css +1 -1
  124. package/dist/web/components/Checkbox.d.ts +8 -8
  125. package/dist/web/components/Checkbox.js.map +1 -1
  126. package/dist/web/components/Checkbox.js.zyzz.json +1 -1
  127. package/dist/web/components/CheckboxGroup.js.zyzz.json +1 -1
  128. package/dist/web/components/ChoiceGroup.css +1 -1
  129. package/dist/web/components/ChoiceGroup.d.ts +2 -2
  130. package/dist/web/components/ChoiceGroup.d.ts.map +1 -1
  131. package/dist/web/components/ChoiceGroup.js +2 -2
  132. package/dist/web/components/ChoiceGroup.js.map +1 -1
  133. package/dist/web/components/ChoiceGroup.js.zyzz.json +1 -1
  134. package/dist/web/components/Choicebox.css +1 -1
  135. package/dist/web/components/Choicebox.d.ts +4 -4
  136. package/dist/web/components/Choicebox.js +1 -1
  137. package/dist/web/components/Choicebox.js.map +1 -1
  138. package/dist/web/components/Choicebox.js.zyzz.json +1 -1
  139. package/dist/web/components/Combobox.css +1 -1
  140. package/dist/web/components/Combobox.js.map +1 -1
  141. package/dist/web/components/Combobox.js.zyzz.json +1 -1
  142. package/dist/web/components/Container.js.zyzz.json +1 -1
  143. package/dist/web/components/CopyButton.js.zyzz.json +1 -1
  144. package/dist/web/components/DatePicker.css +1 -1
  145. package/dist/web/components/DatePicker.d.ts +20 -20
  146. package/dist/web/components/DatePicker.d.ts.map +1 -1
  147. package/dist/web/components/DatePicker.js +2 -2
  148. package/dist/web/components/DatePicker.js.map +1 -1
  149. package/dist/web/components/DatePicker.js.zyzz.json +1 -1
  150. package/dist/web/components/Dialog.css +1 -1
  151. package/dist/web/components/Dialog.d.ts.map +1 -1
  152. package/dist/web/components/Dialog.js +3 -3
  153. package/dist/web/components/Dialog.js.map +1 -1
  154. package/dist/web/components/Dialog.js.zyzz.json +1 -1
  155. package/dist/web/components/Drawer.css +1 -1
  156. package/dist/web/components/Drawer.js +2 -2
  157. package/dist/web/components/Drawer.js.map +1 -1
  158. package/dist/web/components/Drawer.js.zyzz.json +1 -1
  159. package/dist/web/components/Empty.js.zyzz.json +1 -1
  160. package/dist/web/components/Field.css +1 -1
  161. package/dist/web/components/Field.d.ts +7 -0
  162. package/dist/web/components/Field.d.ts.map +1 -1
  163. package/dist/web/components/Field.js +25 -3
  164. package/dist/web/components/Field.js.map +1 -1
  165. package/dist/web/components/Field.js.zyzz.json +1 -1
  166. package/dist/web/components/Fieldset.js.zyzz.json +1 -1
  167. package/dist/web/components/Frame.css +1 -1
  168. package/dist/web/components/Frame.d.ts +27 -10
  169. package/dist/web/components/Frame.d.ts.map +1 -1
  170. package/dist/web/components/Frame.js +12 -5
  171. package/dist/web/components/Frame.js.map +1 -1
  172. package/dist/web/components/Frame.js.zyzz.json +1 -1
  173. package/dist/web/components/Gauge.css +1 -1
  174. package/dist/web/components/Gauge.js.map +1 -1
  175. package/dist/web/components/Gauge.js.zyzz.json +1 -1
  176. package/dist/web/components/Grid.js.zyzz.json +1 -1
  177. package/dist/web/components/Hex.css +1 -1
  178. package/dist/web/components/Hex.d.ts +5 -5
  179. package/dist/web/components/Hex.js +1 -1
  180. package/dist/web/components/Hex.js.map +1 -1
  181. package/dist/web/components/Hex.js.zyzz.json +1 -1
  182. package/dist/web/components/IconChip.css +1 -1
  183. package/dist/web/components/IconChip.d.ts +1 -1
  184. package/dist/web/components/IconChip.js.map +1 -1
  185. package/dist/web/components/IconChip.js.zyzz.json +1 -1
  186. package/dist/web/components/Identicon.js.zyzz.json +1 -1
  187. package/dist/web/components/Inline.js.zyzz.json +1 -1
  188. package/dist/web/components/Input.css +1 -1
  189. package/dist/web/components/Input.js.map +1 -1
  190. package/dist/web/components/Input.js.zyzz.json +1 -1
  191. package/dist/web/components/Inset.js.zyzz.json +1 -1
  192. package/dist/web/components/Kbd.css +1 -1
  193. package/dist/web/components/Kbd.d.ts +32 -10
  194. package/dist/web/components/Kbd.d.ts.map +1 -1
  195. package/dist/web/components/Kbd.js +55 -13
  196. package/dist/web/components/Kbd.js.map +1 -1
  197. package/dist/web/components/Kbd.js.zyzz.json +1 -1
  198. package/dist/web/components/LoadingDots.css +1 -1
  199. package/dist/web/components/LoadingDots.d.ts +2 -2
  200. package/dist/web/components/LoadingDots.js.map +1 -1
  201. package/dist/web/components/LoadingDots.js.zyzz.json +1 -1
  202. package/dist/web/components/Menu.css +1 -1
  203. package/dist/web/components/Menu.d.ts +11 -11
  204. package/dist/web/components/Menu.d.ts.map +1 -1
  205. package/dist/web/components/Menu.js +2 -2
  206. package/dist/web/components/Menu.js.map +1 -1
  207. package/dist/web/components/Menu.js.zyzz.json +1 -1
  208. package/dist/web/components/NumberField.css +1 -1
  209. package/dist/web/components/NumberField.js +1 -1
  210. package/dist/web/components/NumberField.js.map +1 -1
  211. package/dist/web/components/NumberField.js.zyzz.json +1 -1
  212. package/dist/web/components/OtpField.css +1 -1
  213. package/dist/web/components/OtpField.d.ts.map +1 -1
  214. package/dist/web/components/OtpField.js +1 -1
  215. package/dist/web/components/OtpField.js.map +1 -1
  216. package/dist/web/components/OtpField.js.zyzz.json +1 -1
  217. package/dist/web/components/Pagination.css +1 -1
  218. package/dist/web/components/Pagination.d.ts +13 -13
  219. package/dist/web/components/Pagination.js +1 -1
  220. package/dist/web/components/Pagination.js.map +1 -1
  221. package/dist/web/components/Pagination.js.zyzz.json +1 -1
  222. package/dist/web/components/Popover.css +1 -1
  223. package/dist/web/components/Popover.d.ts.map +1 -1
  224. package/dist/web/components/Popover.js +1 -1
  225. package/dist/web/components/Popover.js.map +1 -1
  226. package/dist/web/components/Popover.js.zyzz.json +1 -1
  227. package/dist/web/components/Progress.css +1 -1
  228. package/dist/web/components/Progress.js.map +1 -1
  229. package/dist/web/components/Progress.js.zyzz.json +1 -1
  230. package/dist/web/components/Qr.js.zyzz.json +1 -1
  231. package/dist/web/components/RadioGroup.css +1 -1
  232. package/dist/web/components/RadioGroup.d.ts +4 -4
  233. package/dist/web/components/RadioGroup.js.map +1 -1
  234. package/dist/web/components/RadioGroup.js.zyzz.json +1 -1
  235. package/dist/web/components/Rows.css +1 -1
  236. package/dist/web/components/Rows.d.ts +7 -7
  237. package/dist/web/components/Rows.d.ts.map +1 -1
  238. package/dist/web/components/Rows.js +3 -3
  239. package/dist/web/components/Rows.js.map +1 -1
  240. package/dist/web/components/Rows.js.zyzz.json +1 -1
  241. package/dist/web/components/SecretValue.css +1 -1
  242. package/dist/web/components/SecretValue.d.ts +4 -4
  243. package/dist/web/components/SecretValue.js +1 -1
  244. package/dist/web/components/SecretValue.js.map +1 -1
  245. package/dist/web/components/SecretValue.js.zyzz.json +1 -1
  246. package/dist/web/components/Select.css +1 -1
  247. package/dist/web/components/Select.js.map +1 -1
  248. package/dist/web/components/Select.js.zyzz.json +1 -1
  249. package/dist/web/components/Separator.js.zyzz.json +1 -1
  250. package/dist/web/components/SidebarMenu.css +1 -1
  251. package/dist/web/components/SidebarMenu.d.ts +11 -11
  252. package/dist/web/components/SidebarMenu.d.ts.map +1 -1
  253. package/dist/web/components/SidebarMenu.js +1 -1
  254. package/dist/web/components/SidebarMenu.js.map +1 -1
  255. package/dist/web/components/SidebarMenu.js.zyzz.json +1 -1
  256. package/dist/web/components/Skeleton.js.zyzz.json +1 -1
  257. package/dist/web/components/Slider.css +1 -1
  258. package/dist/web/components/Slider.d.ts.map +1 -1
  259. package/dist/web/components/Slider.js.map +1 -1
  260. package/dist/web/components/Slider.js.zyzz.json +1 -1
  261. package/dist/web/components/Snippet.css +1 -1
  262. package/dist/web/components/Snippet.d.ts +4 -4
  263. package/dist/web/components/Snippet.js +2 -2
  264. package/dist/web/components/Snippet.js.map +1 -1
  265. package/dist/web/components/Snippet.js.zyzz.json +1 -1
  266. package/dist/web/components/Spinner.js.zyzz.json +1 -1
  267. package/dist/web/components/SplitButton.css +1 -1
  268. package/dist/web/components/SplitButton.d.ts.map +1 -1
  269. package/dist/web/components/SplitButton.js +1 -1
  270. package/dist/web/components/SplitButton.js.map +1 -1
  271. package/dist/web/components/SplitButton.js.zyzz.json +1 -1
  272. package/dist/web/components/Stack.js.zyzz.json +1 -1
  273. package/dist/web/components/Stepper.css +1 -1
  274. package/dist/web/components/Stepper.d.ts +1 -1
  275. package/dist/web/components/Stepper.js.map +1 -1
  276. package/dist/web/components/Stepper.js.zyzz.json +1 -1
  277. package/dist/web/components/Surface.css +1 -1
  278. package/dist/web/components/Surface.d.ts +46 -46
  279. package/dist/web/components/Surface.js +2 -2
  280. package/dist/web/components/Surface.js.map +1 -1
  281. package/dist/web/components/Surface.js.zyzz.json +1 -1
  282. package/dist/web/components/Switch.css +1 -1
  283. package/dist/web/components/Switch.d.ts +14 -14
  284. package/dist/web/components/Switch.d.ts.map +1 -1
  285. package/dist/web/components/Switch.js.map +1 -1
  286. package/dist/web/components/Switch.js.zyzz.json +1 -1
  287. package/dist/web/components/Table.css +1 -1
  288. package/dist/web/components/Table.d.ts +10 -7
  289. package/dist/web/components/Table.d.ts.map +1 -1
  290. package/dist/web/components/Table.js +5 -2
  291. package/dist/web/components/Table.js.map +1 -1
  292. package/dist/web/components/Table.js.zyzz.json +1 -1
  293. package/dist/web/components/Tabs.css +1 -1
  294. package/dist/web/components/Tabs.d.ts +14 -14
  295. package/dist/web/components/Tabs.js +1 -1
  296. package/dist/web/components/Tabs.js.map +1 -1
  297. package/dist/web/components/Tabs.js.zyzz.json +1 -1
  298. package/dist/web/components/Tag.css +1 -1
  299. package/dist/web/components/Tag.d.ts +10 -10
  300. package/dist/web/components/Tag.js +1 -1
  301. package/dist/web/components/Tag.js.map +1 -1
  302. package/dist/web/components/Tag.js.zyzz.json +1 -1
  303. package/dist/web/components/Textarea.css +1 -1
  304. package/dist/web/components/Textarea.d.ts +15 -15
  305. package/dist/web/components/Textarea.js.map +1 -1
  306. package/dist/web/components/Textarea.js.zyzz.json +1 -1
  307. package/dist/web/components/Toast.css +1 -1
  308. package/dist/web/components/Toast.d.ts.map +1 -1
  309. package/dist/web/components/Toast.js +7 -3
  310. package/dist/web/components/Toast.js.map +1 -1
  311. package/dist/web/components/Toast.js.zyzz.json +1 -1
  312. package/dist/web/components/Token.js.zyzz.json +1 -1
  313. package/dist/web/components/Tooltip.css +1 -1
  314. package/dist/web/components/Tooltip.d.ts.map +1 -1
  315. package/dist/web/components/Tooltip.js +1 -1
  316. package/dist/web/components/Tooltip.js.map +1 -1
  317. package/dist/web/components/Tooltip.js.zyzz.json +1 -1
  318. package/dist/web/components/internal/Field.css +1 -1
  319. package/dist/web/components/internal/Field.d.ts +7 -7
  320. package/dist/web/components/internal/Field.js.map +1 -1
  321. package/dist/web/components/internal/Field.js.zyzz.json +1 -1
  322. package/dist/web/components/internal/InputGroup.css +1 -1
  323. package/dist/web/components/internal/InputGroup.d.ts +12 -12
  324. package/dist/web/components/internal/InputGroup.d.ts.map +1 -1
  325. package/dist/web/components/internal/InputGroup.js +1 -1
  326. package/dist/web/components/internal/InputGroup.js.map +1 -1
  327. package/dist/web/components/internal/InputGroup.js.zyzz.json +1 -1
  328. package/dist/web/components/internal/Listbox.css +1 -1
  329. package/dist/web/components/internal/Listbox.d.ts +9 -9
  330. package/dist/web/components/internal/Listbox.d.ts.map +1 -1
  331. package/dist/web/components/internal/Listbox.js +1 -1
  332. package/dist/web/components/internal/Listbox.js.map +1 -1
  333. package/dist/web/components/internal/Listbox.js.zyzz.json +1 -1
  334. package/dist/web/icons/BadgeX.d.ts.map +1 -1
  335. package/dist/web/icons/BadgeX.js.map +1 -1
  336. package/dist/web/icons/InfinityIcon.d.ts.map +1 -1
  337. package/dist/web/icons/InfinityIcon.js.map +1 -1
  338. package/dist/web/icons/LightMode.d.ts.map +1 -1
  339. package/dist/web/icons/LightMode.js.map +1 -1
  340. package/dist/web/icons/OctagonAlert.d.ts.map +1 -1
  341. package/dist/web/icons/OctagonAlert.js.map +1 -1
  342. package/dist/web/icons/Unlink.d.ts.map +1 -1
  343. package/dist/web/icons/Unlink.js.map +1 -1
  344. package/dist/web/index.js.zyzz.json +1 -1
  345. package/dist/web/vars.d.ts +91 -0
  346. package/dist/web/vars.d.ts.map +1 -1
  347. package/dist/web/vars.js.map +1 -1
  348. package/dist/web/vars.js.zyzz.json +1 -1
  349. package/dist/web/zyzz.config.d.ts +455 -0
  350. package/dist/web/zyzz.config.d.ts.map +1 -1
  351. package/dist/web/zyzz.config.js.zyzz.json +1 -1
  352. package/package.json +7 -1
  353. package/src/mobile/components/Avatar.tsx +2 -2
  354. package/src/mobile/components/Button.tsx +6 -3
  355. package/src/mobile/components/CodeInput.tsx +2 -2
  356. package/src/mobile/components/IconButton.tsx +6 -3
  357. package/src/mobile/components/Skeleton.tsx +1 -1
  358. package/src/mobile/components/Spinner.tsx +4 -5
  359. package/src/mobile/components/TextButton.tsx +6 -2
  360. package/src/mobile/components/TextInput.tsx +1 -1
  361. package/src/mobile/components/Toast.tsx +1 -2
  362. package/src/mobile/components/Toggle.tsx +2 -2
  363. package/src/mobile/vars.ts +14 -0
  364. package/src/oxlint/index.ts +89 -0
  365. package/src/oxlint/internal/Imports.ts +68 -0
  366. package/src/oxlint/rules/NoCrossSurface.ts +71 -0
  367. package/src/oxlint/rules/NoInternalImports.ts +25 -0
  368. package/src/oxlint/rules/NoRawValues.ts +76 -0
  369. package/src/oxlint/rules/PreferComponent.ts +113 -0
  370. package/src/oxlint/rules/RequireAccessibleName.ts +132 -0
  371. package/src/web/components/Accordion.tsx +8 -8
  372. package/src/web/components/AlertDialog.tsx +11 -8
  373. package/src/web/components/Amount.tsx +29 -9
  374. package/src/web/components/AmountInput.tsx +60 -24
  375. package/src/web/components/AppShell.tsx +23 -23
  376. package/src/web/components/Avatar.tsx +3 -3
  377. package/src/web/components/Banner.tsx +16 -16
  378. package/src/web/components/Breadcrumbs.tsx +4 -4
  379. package/src/web/components/Button.tsx +15 -12
  380. package/src/web/components/Calendar.tsx +10 -11
  381. package/src/web/components/Callout.tsx +19 -16
  382. package/src/web/components/Checkbox.tsx +9 -9
  383. package/src/web/components/ChoiceGroup.tsx +13 -14
  384. package/src/web/components/Choicebox.tsx +21 -21
  385. package/src/web/components/Combobox.tsx +3 -3
  386. package/src/web/components/DatePicker.tsx +25 -25
  387. package/src/web/components/Dialog.tsx +28 -19
  388. package/src/web/components/Drawer.tsx +8 -8
  389. package/src/web/components/Field.tsx +46 -11
  390. package/src/web/components/Frame.tsx +30 -9
  391. package/src/web/components/Gauge.tsx +1 -1
  392. package/src/web/components/Hex.tsx +5 -5
  393. package/src/web/components/IconChip.tsx +1 -1
  394. package/src/web/components/Input.tsx +11 -11
  395. package/src/web/components/Kbd.tsx +77 -21
  396. package/src/web/components/LoadingDots.tsx +4 -4
  397. package/src/web/components/Menu.tsx +17 -14
  398. package/src/web/components/NumberField.tsx +17 -17
  399. package/src/web/components/OtpField.tsx +14 -6
  400. package/src/web/components/Pagination.tsx +13 -13
  401. package/src/web/components/Popover.tsx +14 -11
  402. package/src/web/components/Progress.tsx +2 -2
  403. package/src/web/components/RadioGroup.tsx +11 -11
  404. package/src/web/components/Rows.tsx +8 -9
  405. package/src/web/components/SecretValue.tsx +4 -4
  406. package/src/web/components/Select.tsx +2 -2
  407. package/src/web/components/SidebarMenu.tsx +14 -15
  408. package/src/web/components/Slider.tsx +6 -7
  409. package/src/web/components/Snippet.tsx +9 -9
  410. package/src/web/components/SplitButton.tsx +17 -5
  411. package/src/web/components/Stepper.tsx +1 -1
  412. package/src/web/components/Surface.tsx +47 -47
  413. package/src/web/components/Switch.tsx +21 -23
  414. package/src/web/components/Table.tsx +11 -7
  415. package/src/web/components/Tabs.tsx +14 -14
  416. package/src/web/components/Tag.tsx +12 -12
  417. package/src/web/components/Textarea.tsx +15 -15
  418. package/src/web/components/Toast.tsx +28 -21
  419. package/src/web/components/Tooltip.tsx +12 -9
  420. package/src/web/components/internal/Field.ts +20 -20
  421. package/src/web/components/internal/InputGroup.ts +13 -14
  422. package/src/web/components/internal/Listbox.ts +19 -16
  423. package/src/web/icons/BadgeX.tsx +1 -1
  424. package/src/web/icons/InfinityIcon.tsx +1 -1
  425. package/src/web/icons/LightMode.tsx +1 -1
  426. package/src/web/icons/OctagonAlert.tsx +1 -1
  427. package/src/web/icons/Unlink.tsx +1 -1
  428. package/src/web/vars.ts +81 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tempoxyz/ds",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.4",
5
5
  "license": "MIT",
6
6
  "files": [
7
7
  "DESIGN.md",
@@ -16,6 +16,7 @@
16
16
  "description": "Tempo Design System",
17
17
  "dependencies": {
18
18
  "@base-ui/react": "^1.8.0",
19
+ "@oxlint/plugins": "1.79.0",
19
20
  "cuer": "0.0.3",
20
21
  "midcut": "0.2.0",
21
22
  "torph": "0.1.3"
@@ -1262,6 +1263,11 @@
1262
1263
  "types": "./dist/mobile/icons/index.d.ts",
1263
1264
  "react-native": "./src/mobile/icons/index.ts",
1264
1265
  "default": "./dist/mobile/icons/index.js"
1266
+ },
1267
+ "./oxlint": {
1268
+ "src": "./src/oxlint/index.ts",
1269
+ "types": "./dist/oxlint/index.d.ts",
1270
+ "default": "./dist/oxlint/index.js"
1265
1271
  }
1266
1272
  },
1267
1273
  "peerDependencies": {
@@ -1,5 +1,5 @@
1
- import { useState, type ComponentPropsWithRef } from 'react'
2
- import { Image, Text, View, type ImageSourcePropType } from 'react-native'
1
+ import { type ComponentPropsWithRef, useState } from 'react'
2
+ import { Image, type ImageSourcePropType, Text, View } from 'react-native'
3
3
  import type * as zyzz from 'zyzz'
4
4
  import { style, variants } from '../zyzz.config.js'
5
5
 
@@ -1,6 +1,6 @@
1
1
  import * as Haptics from 'expo-haptics'
2
2
  import { cloneElement, type ComponentPropsWithRef, type ReactElement } from 'react'
3
- import { Pressable, Text, View, type ColorValue } from 'react-native'
3
+ import { type ColorValue, Pressable, Text, View } from 'react-native'
4
4
  import type * as zyzz from 'zyzz'
5
5
  import { useColor } from '../internal/useColor.js'
6
6
  import { inverse } from '../vars.js'
@@ -58,7 +58,10 @@ export function Button(props: Button.Props) {
58
58
  styles.button({
59
59
  appearance,
60
60
  scale,
61
- state: disabled ? 'disabled' : state.pressed ? 'pressed' : undefined,
61
+ state: (() => {
62
+ if (disabled) return 'disabled'
63
+ return state.pressed ? 'pressed' : undefined
64
+ })(),
62
65
  variant,
63
66
  }).style,
64
67
  typeof props.style === 'function' ? props.style(state) : props.style,
@@ -136,7 +139,7 @@ export namespace styles {
136
139
  {
137
140
  // React Native has no backdrop blur, so the overlay keeps only its translucent fill.
138
141
  when: { appearance: 'overlay', variant: 'secondary' },
139
- style: { backgroundColor: 'rgba(112, 112, 112, 0.32) !custom' },
142
+ style: { backgroundColor: 'component.button.overlay.fill' },
140
143
  },
141
144
  ],
142
145
  },
@@ -1,5 +1,5 @@
1
- import { useEffect, useImperativeHandle, useRef, useState, type ComponentPropsWithRef } from 'react'
2
- import { Keyboard, Text, TextInput, View, type StyleProp, type ViewStyle } from 'react-native'
1
+ import { type ComponentPropsWithRef, useEffect, useImperativeHandle, useRef, useState } from 'react'
2
+ import { Keyboard, type StyleProp, Text, TextInput, View, type ViewStyle } from 'react-native'
3
3
  import type * as zyzz from 'zyzz'
4
4
  import { style, variants } from '../zyzz.config.js'
5
5
 
@@ -1,6 +1,6 @@
1
1
  import * as Haptics from 'expo-haptics'
2
2
  import { cloneElement, type ComponentPropsWithRef, type ReactElement } from 'react'
3
- import { Pressable, type ColorValue } from 'react-native'
3
+ import { type ColorValue, Pressable } from 'react-native'
4
4
  import type * as zyzz from 'zyzz'
5
5
  import { useColor } from '../internal/useColor.js'
6
6
  import { inverse } from '../vars.js'
@@ -46,7 +46,10 @@ export function IconButton(props: IconButton.Props) {
46
46
  styles.button({
47
47
  appearance,
48
48
  scale,
49
- state: disabled ? 'disabled' : state.pressed ? 'pressed' : undefined,
49
+ state: (() => {
50
+ if (disabled) return 'disabled'
51
+ return state.pressed ? 'pressed' : undefined
52
+ })(),
50
53
  variant,
51
54
  }).style,
52
55
  typeof props.style === 'function' ? props.style(state) : props.style,
@@ -105,7 +108,7 @@ export namespace styles {
105
108
  {
106
109
  // React Native has no backdrop blur, so the overlay keeps only its translucent fill.
107
110
  when: { appearance: 'overlay', variant: 'secondary' },
108
- style: { backgroundColor: 'rgba(112, 112, 112, 0.32) !custom' },
111
+ style: { backgroundColor: 'component.button.overlay.fill' },
109
112
  },
110
113
  ],
111
114
  },
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPropsWithRef } from 'react'
2
- import { View, type DimensionValue } from 'react-native'
2
+ import { type DimensionValue, View } from 'react-native'
3
3
  import Animated from 'react-native-reanimated'
4
4
  import type * as zyzz from 'zyzz'
5
5
  import { useReducedMotion } from '../internal/useReducedMotion.js'
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPropsWithRef } from 'react'
2
- import { View, type ColorValue } from 'react-native'
2
+ import { type ColorValue, View } from 'react-native'
3
3
  import Animated from 'react-native-reanimated'
4
4
  import { Circle, Path, Svg } from 'react-native-svg'
5
5
  import type * as zyzz from 'zyzz'
@@ -90,11 +90,10 @@ export namespace styles {
90
90
  true: {
91
91
  backgroundColor: 'background.elevated',
92
92
  borderRadius: 'xs',
93
- boxShadow:
94
- 'rgba(0, 0, 0, 0.04) 0px 4px 12px, rgba(0, 0, 0, 0.04) 0px 8px 32px, rgba(0, 0, 0, 0.04) 0px 12px 36px !custom',
95
- height: '44px !custom',
93
+ boxShadow: 'elevated',
94
+ height: '44',
96
95
  padding: '2',
97
- width: '44px !custom',
96
+ width: '44',
98
97
  },
99
98
  },
100
99
  },
@@ -39,8 +39,12 @@ export function TextButton(props: TextButton.Props) {
39
39
  props.onPress?.(event)
40
40
  }}
41
41
  style={(state) => [
42
- styles.button({ state: disabled ? 'disabled' : state.pressed ? 'pressed' : undefined })
43
- .style,
42
+ styles.button({
43
+ state: (() => {
44
+ if (disabled) return 'disabled'
45
+ return state.pressed ? 'pressed' : undefined
46
+ })(),
47
+ }).style,
44
48
  typeof props.style === 'function' ? props.style(state) : props.style,
45
49
  ]}
46
50
  >
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPropsWithRef } from 'react'
2
- import { Text, TextInput as NativeTextInput, View } from 'react-native'
2
+ import { TextInput as NativeTextInput, Text, View } from 'react-native'
3
3
  import type * as zyzz from 'zyzz'
4
4
  import { useColor } from '../internal/useColor.js'
5
5
  import { style, variants } from '../zyzz.config.js'
@@ -74,8 +74,7 @@ export namespace styles {
74
74
  alignSelf: 'flex-start',
75
75
  backgroundColor: 'background.elevated',
76
76
  borderRadius: 'full',
77
- boxShadow:
78
- 'rgba(0, 0, 0, 0.04) 0px 2px 8px, rgba(0, 0, 0, 0.08) 0px 8px 48px, rgba(0, 0, 0, 0.08) 0px 24px 64px !custom',
77
+ boxShadow: 'floating',
79
78
  flexDirection: 'row',
80
79
  gap: '12',
81
80
  minHeight: '48',
@@ -71,9 +71,9 @@ export namespace styles {
71
71
  {
72
72
  base: {
73
73
  borderRadius: 'full',
74
- height: '28px !custom',
74
+ height: '28',
75
75
  justifyContent: 'center',
76
- width: '44px !custom',
76
+ width: '44',
77
77
  },
78
78
  defaultVariants: { disabled: false, value: false },
79
79
  variants: {
@@ -47,6 +47,10 @@ export const variables = Vars.define(
47
47
  },
48
48
  component: {
49
49
  button: {
50
+ // Neutral 056 at 32% alpha. `primitives.ts` has no step for it, so the value stays literal.
51
+ overlay: {
52
+ fill: { light: 'rgba(112, 112, 112, 0.32)', dark: 'rgba(112, 112, 112, 0.32)' },
53
+ },
50
54
  primary: {
51
55
  border: {
52
56
  light: core.color.neutral.shade['000'],
@@ -145,15 +149,25 @@ export const variables = Vars.define(
145
149
  xs: core.spacing['12'],
146
150
  },
147
151
  responsive: { '2Tier': 'Mobile', '3Tier': 'Mobile', '4Tier': 'Mobile' },
152
+ // Box shadows, since `color.shadow` holds only shadow colors. `elevated` lifts a control off its
153
+ // background, and `floating` lifts an overlay such as a toast.
154
+ shadow: {
155
+ elevated:
156
+ '0px 4px 12px rgba(0, 0, 0, 0.04), 0px 8px 32px rgba(0, 0, 0, 0.04), 0px 12px 36px rgba(0, 0, 0, 0.04)',
157
+ floating:
158
+ '0px 2px 8px rgba(0, 0, 0, 0.04), 0px 8px 48px rgba(0, 0, 0, 0.08), 0px 24px 64px rgba(0, 0, 0, 0.08)',
159
+ },
148
160
  spacing: {
149
161
  '12': core.spacing['12'],
150
162
  '16': core.spacing['16'],
151
163
  '2': core.spacing['2'],
152
164
  '20': core.spacing['20'],
153
165
  '24': core.spacing['24'],
166
+ '28': core.spacing['28'],
154
167
  '32': core.spacing['32'],
155
168
  '4': core.spacing['4'],
156
169
  '40': core.spacing['40'],
170
+ '44': core.spacing['44'],
157
171
  '48': core.spacing['48'],
158
172
  '64': core.spacing['64'],
159
173
  '8': core.spacing['8'],
@@ -0,0 +1,89 @@
1
+ /** Oxlint plugin and configurations that check how an app uses `@tempoxyz/ds`. @module */
2
+ import type { Plugin } from '@oxlint/plugins'
3
+ import * as NoCrossSurface from './rules/NoCrossSurface.ts'
4
+ import * as NoInternalImports from './rules/NoInternalImports.ts'
5
+ import * as NoRawValues from './rules/NoRawValues.ts'
6
+ import * as PreferComponent from './rules/PreferComponent.ts'
7
+ import * as RequireAccessibleName from './rules/RequireAccessibleName.ts'
8
+
9
+ /** An Oxlint rule severity. */
10
+ export type Severity = 'error' | 'off' | 'warn'
11
+
12
+ /**
13
+ * A lint configuration that Oxlint and the `lint` option of Vite Plus accept. Arrays stay mutable
14
+ * because Oxlint's configuration type declares them mutable.
15
+ */
16
+ export type Config = {
17
+ /** Plugins to load, keyed by the name that prefixes their rules. */
18
+ jsPlugins: { name: string; specifier: string }[]
19
+ /** Rule severities, with options as the second tuple member. */
20
+ rules: Record<string, Severity | [Severity, ...unknown[]]>
21
+ }
22
+
23
+ const plugins: Config['jsPlugins'] = [
24
+ { name: 'tds', specifier: '@tempoxyz/ds/oxlint' },
25
+ { name: 'zyzz', specifier: 'zyzz/oxlint' },
26
+ ]
27
+
28
+ const zyzz: Config['rules'] = {
29
+ 'zyzz/no-conflicting-props': 'error',
30
+ 'zyzz/no-unused': 'warn',
31
+ 'zyzz/valid-styles': 'error',
32
+ }
33
+
34
+ /**
35
+ * Enables the TDS and Zyzz rules for an app that renders `@tempoxyz/ds/mobile`.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { mobile } from '@tempoxyz/ds/oxlint'
40
+ *
41
+ * export default defineConfig({ lint: mobile })
42
+ * ```
43
+ */
44
+ export const mobile: Config = {
45
+ jsPlugins: plugins,
46
+ rules: {
47
+ 'tds/no-cross-surface': ['error', { surface: 'mobile' }],
48
+ 'tds/no-internal-imports': 'error',
49
+ 'tds/no-raw-values': 'warn',
50
+ 'tds/require-accessible-name': 'error',
51
+ ...zyzz,
52
+ },
53
+ }
54
+
55
+ /**
56
+ * Enables the TDS and Zyzz rules for an app that renders `@tempoxyz/ds`.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * import { web } from '@tempoxyz/ds/oxlint'
61
+ *
62
+ * export default defineConfig({ lint: web })
63
+ * ```
64
+ */
65
+ export const web: Config = {
66
+ jsPlugins: plugins,
67
+ rules: {
68
+ 'tds/no-cross-surface': ['error', { surface: 'web' }],
69
+ 'tds/no-internal-imports': 'error',
70
+ 'tds/no-raw-values': 'warn',
71
+ 'tds/prefer-component': 'warn',
72
+ 'tds/require-accessible-name': 'error',
73
+ ...zyzz,
74
+ },
75
+ }
76
+
77
+ /** Register through `jsPlugins` as `tds`, then enable `tds/*` rules or spread `web` or `mobile`. */
78
+ const plugin: Plugin = {
79
+ meta: { name: 'tds' },
80
+ rules: {
81
+ 'no-cross-surface': NoCrossSurface.rule,
82
+ 'no-internal-imports': NoInternalImports.rule,
83
+ 'no-raw-values': NoRawValues.rule,
84
+ 'prefer-component': PreferComponent.rule,
85
+ 'require-accessible-name': RequireAccessibleName.rule,
86
+ },
87
+ }
88
+
89
+ export default plugin
@@ -0,0 +1,68 @@
1
+ /** Classifies `@tempoxyz/ds` import specifiers and visits every static module reference in a file. @module */
2
+ import type { ESTree, Visitor } from '@oxlint/plugins'
3
+ import * as Module from 'node:module'
4
+
5
+ /** A library surface, named after the entrypoint that ships it. */
6
+ export type Surface = 'mobile' | 'web'
7
+
8
+ // The manifest sits three levels up from both `src/oxlint/internal` and `dist/oxlint/internal`.
9
+ const manifest: { exports: Record<string, unknown>; name: string } = Module.createRequire(
10
+ import.meta.url,
11
+ )('../../../package.json')
12
+
13
+ /** The published package name, `@tempoxyz/ds`. */
14
+ export const name = manifest.name
15
+
16
+ /** Returns whether `source` names the package or one of its subpaths. */
17
+ export function owned(source: string): boolean {
18
+ return source === name || source.startsWith(`${name}/`)
19
+ }
20
+
21
+ /** Returns whether `source` resolves through a subpath that the package `exports` map publishes. */
22
+ export function published(source: string): boolean {
23
+ return owned(source) && Object.hasOwn(manifest.exports, `.${source.slice(name.length)}`)
24
+ }
25
+
26
+ /** Returns the surface a published specifier belongs to, or `undefined` for tooling entrypoints. */
27
+ export function surface(source: string): Surface | undefined {
28
+ if (!published(source)) return undefined
29
+
30
+ const subpath = source.slice(name.length)
31
+
32
+ if (subpath === '/mobile' || subpath.startsWith('/mobile/')) return 'mobile'
33
+ if (subpath === '' || subpath.startsWith('/fonts/') || subpath.startsWith('/icons')) return 'web'
34
+ return undefined
35
+ }
36
+
37
+ /**
38
+ * Returns a visitor that calls `fn` with each string specifier in an import, a re-export, an
39
+ * `import()` expression, or an `import()` type.
40
+ */
41
+ export function visit(fn: visit.Callback): Visitor {
42
+ function literal(node: ESTree.Node | null | undefined) {
43
+ if (node?.type === 'Literal' && typeof node.value === 'string') fn(node.value, node)
44
+ }
45
+
46
+ return {
47
+ ExportAllDeclaration(node) {
48
+ literal(node.source)
49
+ },
50
+ ExportNamedDeclaration(node) {
51
+ literal(node.source)
52
+ },
53
+ ImportDeclaration(node) {
54
+ literal(node.source)
55
+ },
56
+ ImportExpression(node) {
57
+ literal(node.source)
58
+ },
59
+ TSImportType(node) {
60
+ literal(node.source)
61
+ },
62
+ }
63
+ }
64
+
65
+ export declare namespace visit {
66
+ /** Receives the specifier and the string literal that spells it. */
67
+ type Callback = (source: string, node: ESTree.Node) => void
68
+ }
@@ -0,0 +1,71 @@
1
+ /** Keeps a file, or a whole app, on one `@tempoxyz/ds` surface. @module */
2
+ import type { ESTree, Rule } from '@oxlint/plugins'
3
+ import * as Imports from '../internal/Imports.ts'
4
+
5
+ /**
6
+ * Reports an import from the other surface. With `surface` set, every import from the other surface
7
+ * is reported. Without it, the rule reports a file that imports from both surfaces.
8
+ */
9
+ export const rule: Rule = {
10
+ meta: {
11
+ docs: { description: 'Keep an app on one `@tempoxyz/ds` surface.' },
12
+ messages: {
13
+ configured:
14
+ "'{{source}}' belongs to the {{found}} surface, but this app uses the {{surface}} surface.",
15
+ mixed:
16
+ "'{{source}}' belongs to the {{found}} surface, but this file imports the {{surface}} surface.",
17
+ },
18
+ schema: [
19
+ {
20
+ additionalProperties: false,
21
+ properties: { surface: { enum: ['mobile', 'web'], type: 'string' } },
22
+ type: 'object',
23
+ },
24
+ ],
25
+ type: 'problem',
26
+ },
27
+ create(context) {
28
+ const options = context.options[0] as rule.Options | undefined
29
+
30
+ type Reference = { node: ESTree.Node; source: string; surface: Imports.Surface }
31
+
32
+ const references: Reference[] = []
33
+
34
+ return {
35
+ ...Imports.visit((source, node) => {
36
+ const surface = Imports.surface(source)
37
+
38
+ if (!surface) return
39
+ if (options?.surface && surface !== options.surface)
40
+ context.report({
41
+ data: { found: surface, source, surface: options.surface },
42
+ messageId: 'configured',
43
+ node,
44
+ })
45
+ references.push({ node, source, surface })
46
+ }),
47
+ 'Program:exit'() {
48
+ if (options?.surface) return
49
+
50
+ const first = references[0]
51
+
52
+ if (!first) return
53
+ for (const reference of references)
54
+ if (reference.surface !== first.surface)
55
+ context.report({
56
+ data: { found: reference.surface, source: reference.source, surface: first.surface },
57
+ messageId: 'mixed',
58
+ node: reference.node,
59
+ })
60
+ },
61
+ }
62
+ },
63
+ }
64
+
65
+ export declare namespace rule {
66
+ /** Options for `tds/no-cross-surface`. */
67
+ type Options = {
68
+ /** The surface the app renders. When absent, the rule checks each file on its own. */
69
+ surface?: Imports.Surface | undefined
70
+ }
71
+ }
@@ -0,0 +1,25 @@
1
+ /** Restricts `@tempoxyz/ds` imports to the subpaths that the package publishes. @module */
2
+ import type { Rule } from '@oxlint/plugins'
3
+ import * as Imports from '../internal/Imports.ts'
4
+
5
+ /**
6
+ * Reports a `@tempoxyz/ds` specifier that the package `exports` map does not publish, such as
7
+ * `@tempoxyz/ds/src/web/components/Button`. Internal paths change without a release note.
8
+ */
9
+ export const rule: Rule = {
10
+ meta: {
11
+ docs: { description: 'Allow only the published `@tempoxyz/ds` entrypoints.' },
12
+ messages: {
13
+ internal:
14
+ "'{{source}}' is not a published entrypoint. Import from '@tempoxyz/ds', '@tempoxyz/ds/mobile', or their `icons` subpaths.",
15
+ },
16
+ schema: [],
17
+ type: 'problem',
18
+ },
19
+ create(context) {
20
+ return Imports.visit((source, node) => {
21
+ if (Imports.owned(source) && !Imports.published(source))
22
+ context.report({ data: { source }, messageId: 'internal', node })
23
+ })
24
+ },
25
+ }
@@ -0,0 +1,76 @@
1
+ /** Finds raw colors, lengths, and font stacks in inline `style` props. @module */
2
+ import type { ESTree, Rule } from '@oxlint/plugins'
3
+
4
+ const color = /#[\da-f]{3,8}\b|\b(?:color|hsla?|hwb|lab|lch|oklab|oklch|rgba?)\(/i
5
+ const length = /(?:^|[\s(,])-?(?:\d*\.)?\d+(?:em|pt|px|rem)\b/i
6
+
7
+ // React and React Native read a bare number on these properties as pixels or points.
8
+ const lengths =
9
+ /^(?:bottom|columnGap|end|flexBasis|fontSize|gap|height|inset\w*|left|margin\w*|maxHeight|maxWidth|minHeight|minWidth|padding\w*|right|rowGap|start|top|width|\w*Radius|\w*Width)$/
10
+
11
+ /**
12
+ * Reports a color, length, or font family written as a literal in a JSX `style` prop. Values that
13
+ * read a custom property through `var()` pass, since they resolve to a token. Style values
14
+ * inside `style()` and `variants()` calls belong to `zyzz/valid-styles`.
15
+ */
16
+ export const rule: Rule = {
17
+ meta: {
18
+ docs: { description: 'Use design tokens instead of raw values in inline styles.' },
19
+ messages: {
20
+ raw: "'{{property}}' sets the raw value {{value}}. Use a token through a Zyzz style instead.",
21
+ },
22
+ schema: [],
23
+ type: 'suggestion',
24
+ },
25
+ create(context) {
26
+ function raw(property: string, node: ESTree.Node) {
27
+ if (node.type === 'UnaryExpression' && node.operator === '-')
28
+ return raw(property, node.argument)
29
+ if (node.type === 'Literal' && typeof node.value === 'number')
30
+ return node.value !== 0 && lengths.test(property)
31
+ if (node.type === 'TemplateLiteral' && node.expressions.length === 0)
32
+ return text(property, node.quasis.map((quasi) => quasi.value.cooked ?? '').join(''))
33
+ if (node.type === 'Literal' && typeof node.value === 'string')
34
+ return text(property, node.value)
35
+ return false
36
+ }
37
+
38
+ function text(property: string, value: string) {
39
+ if (value.includes('var(')) return false
40
+ return property === 'fontFamily' || color.test(value) || length.test(value)
41
+ }
42
+
43
+ function check(node: ESTree.Node) {
44
+ if (node.type !== 'ObjectExpression') return
45
+ for (const property of node.properties) {
46
+ if (property.type !== 'Property' || property.computed) continue
47
+
48
+ const key = (() => {
49
+ if (property.key.type === 'Identifier') return property.key.name
50
+ if (property.key.type === 'Literal') return String(property.key.value)
51
+ return undefined
52
+ })()
53
+
54
+ if (key !== undefined && raw(key, property.value))
55
+ context.report({
56
+ data: { property: key, value: context.sourceCode.getText(property.value) },
57
+ messageId: 'raw',
58
+ node: property.value,
59
+ })
60
+ }
61
+ }
62
+
63
+ return {
64
+ JSXAttribute(node) {
65
+ if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'style') return
66
+ if (node.value?.type !== 'JSXExpressionContainer') return
67
+
68
+ const expression = node.value.expression
69
+
70
+ if (expression.type === 'ArrayExpression')
71
+ for (const element of expression.elements) if (element) check(element)
72
+ check(expression)
73
+ },
74
+ }
75
+ },
76
+ }
@@ -0,0 +1,113 @@
1
+ /** Points native HTML controls and structures at the Web components that replace them. @module */
2
+ import type { ESTree, Rule } from '@oxlint/plugins'
3
+
4
+ // Each element maps to the component that renders it with Tempo styles, states, and semantics.
5
+ const elements: Record<string, string> = {
6
+ button: 'Button',
7
+ details: 'Accordion',
8
+ dialog: 'Dialog',
9
+ fieldset: 'Fieldset',
10
+ hr: 'Separator',
11
+ kbd: 'Kbd',
12
+ meter: 'Gauge',
13
+ progress: 'Progress',
14
+ select: 'Select',
15
+ table: 'Table',
16
+ textarea: 'Textarea',
17
+ }
18
+
19
+ // Input types without an entry, such as `file`, `hidden`, and `color`, have no replacement.
20
+ const inputs: Record<string, string> = {
21
+ button: 'Button',
22
+ checkbox: 'Checkbox',
23
+ date: 'DatePicker',
24
+ email: 'Input',
25
+ number: 'NumberField',
26
+ password: 'Input',
27
+ radio: 'RadioGroup',
28
+ range: 'Slider',
29
+ reset: 'Button',
30
+ search: 'Input',
31
+ submit: 'Button',
32
+ tel: 'Input',
33
+ text: 'Input',
34
+ url: 'Input',
35
+ }
36
+
37
+ /**
38
+ * Reports a native element that a `@tempoxyz/ds` component replaces, such as `<button>` or
39
+ * `<input type="checkbox">`. Elements inside a `render` prop are skipped, since the component that
40
+ * receives them supplies the styles.
41
+ */
42
+ export const rule: Rule = {
43
+ meta: {
44
+ docs: {
45
+ description: 'Prefer `@tempoxyz/ds` components over the native elements they replace.',
46
+ },
47
+ messages: {
48
+ component: "Use '{{component}}' from '@tempoxyz/ds' instead of <{{element}}>.",
49
+ },
50
+ schema: [
51
+ {
52
+ additionalProperties: false,
53
+ properties: { allow: { items: { type: 'string' }, type: 'array' } },
54
+ type: 'object',
55
+ },
56
+ ],
57
+ type: 'suggestion',
58
+ },
59
+ create(context) {
60
+ const options = context.options[0] as rule.Options | undefined
61
+ const allow = new Set(options?.allow)
62
+
63
+ function component(node: ESTree.JSXOpeningElement) {
64
+ if (node.name.type !== 'JSXIdentifier') return undefined
65
+
66
+ const element = node.name.name
67
+
68
+ if (element !== 'input') return elements[element]
69
+
70
+ const type = node.attributes.find(
71
+ (attribute) =>
72
+ attribute.type === 'JSXAttribute' &&
73
+ attribute.name.type === 'JSXIdentifier' &&
74
+ attribute.name.name === 'type',
75
+ )
76
+
77
+ if (!type) return inputs.text
78
+ if (type.type !== 'JSXAttribute' || type.value?.type !== 'Literal') return undefined
79
+ return typeof type.value.value === 'string' ? inputs[type.value.value] : undefined
80
+ }
81
+
82
+ return {
83
+ JSXOpeningElement(node) {
84
+ if (node.name.type !== 'JSXIdentifier' || allow.has(node.name.name)) return
85
+
86
+ for (let parent: ESTree.Node | null = node.parent; parent; parent = parent.parent)
87
+ if (
88
+ parent.type === 'JSXAttribute' &&
89
+ parent.name.type === 'JSXIdentifier' &&
90
+ parent.name.name === 'render'
91
+ )
92
+ return
93
+
94
+ const replacement = component(node)
95
+
96
+ if (replacement)
97
+ context.report({
98
+ data: { component: replacement, element: node.name.name },
99
+ messageId: 'component',
100
+ node,
101
+ })
102
+ },
103
+ }
104
+ },
105
+ }
106
+
107
+ export declare namespace rule {
108
+ /** Options for `tds/prefer-component`. */
109
+ type Options = {
110
+ /** Element names to accept, such as `['table']` for a page that renders raw data. */
111
+ allow?: readonly string[] | undefined
112
+ }
113
+ }