@sanity/ui 4.2.0 → 5.0.0-alpha.10

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 (339) hide show
  1. package/README.md +194 -28
  2. package/bin/sanity-ui.js +14 -0
  3. package/dist/_chunks-es/LazyRefractor.js +20 -0
  4. package/dist/_chunks-es/LazyRefractor.js.map +1 -0
  5. package/dist/cli/checks.js +148 -0
  6. package/dist/cli/config.js +23 -0
  7. package/dist/cli/detect.js +181 -0
  8. package/dist/cli/doctor.js +49 -0
  9. package/dist/cli/index.js +69 -0
  10. package/dist/cli/init.js +189 -0
  11. package/dist/cli/install.js +79 -0
  12. package/dist/cli/log.js +66 -0
  13. package/dist/cli/selfPackage.js +11 -0
  14. package/dist/cli/styles.js +185 -0
  15. package/dist/cli/test-utils.js +8 -0
  16. package/dist/cli/tsconfig.js +236 -0
  17. package/dist/cli/types.js +1 -0
  18. package/dist/cli/versions.js +45 -0
  19. package/dist/index.d.ts +1203 -1469
  20. package/dist/index.js +2123 -1989
  21. package/dist/index.js.map +1 -1
  22. package/dist/polyfills.d.ts +1 -0
  23. package/dist/polyfills.js +5 -0
  24. package/dist/polyfills.js.map +1 -0
  25. package/dist/styles.css +1 -547
  26. package/package.json +57 -58
  27. package/src/cli/checks.test.ts +38 -0
  28. package/src/cli/checks.ts +200 -0
  29. package/src/cli/config.ts +44 -0
  30. package/src/cli/detect.test.ts +191 -0
  31. package/src/cli/detect.ts +205 -0
  32. package/src/cli/doctor.test.ts +52 -0
  33. package/src/cli/doctor.ts +65 -0
  34. package/src/cli/index.ts +77 -0
  35. package/src/cli/init.ts +225 -0
  36. package/src/cli/install.test.ts +52 -0
  37. package/src/cli/install.ts +108 -0
  38. package/src/cli/log.ts +79 -0
  39. package/src/cli/selfPackage.ts +14 -0
  40. package/src/cli/styles.test.ts +130 -0
  41. package/src/cli/styles.ts +205 -0
  42. package/src/cli/test-utils.ts +10 -0
  43. package/src/cli/tsconfig.test.ts +174 -0
  44. package/src/cli/tsconfig.ts +282 -0
  45. package/src/cli/types.ts +77 -0
  46. package/src/cli/versions.test.ts +35 -0
  47. package/src/cli/versions.ts +41 -0
  48. package/src/components/badge/Badge.tsx +53 -0
  49. package/src/components/badge/badge.css +6 -0
  50. package/src/components/badge/badge.props.ts +31 -0
  51. package/src/components/box/Box.tsx +30 -0
  52. package/src/components/box/box.css +4 -0
  53. package/src/components/box/box.props.ts +29 -0
  54. package/src/components/button/Button.tsx +78 -0
  55. package/src/components/button/button.css +72 -0
  56. package/src/components/button/button.props.ts +122 -0
  57. package/src/components/card/Card.tsx +31 -0
  58. package/src/components/card/card.css +4 -0
  59. package/src/components/card/card.props.ts +58 -0
  60. package/src/components/checkbox/Checkbox.tsx +64 -0
  61. package/src/components/checkbox/checkbox.css +100 -0
  62. package/src/components/checkbox/checkbox.props.ts +33 -0
  63. package/src/components/code/Code.tsx +38 -0
  64. package/src/components/code/LazyRefractor.tsx +9 -0
  65. package/src/components/code/code.css +40 -0
  66. package/src/components/code/code.props.ts +44 -0
  67. package/src/components/container/Container.tsx +30 -0
  68. package/src/components/container/container.css +4 -0
  69. package/src/components/container/container.props.ts +28 -0
  70. package/src/components/dialog/Dialog.tsx +139 -0
  71. package/src/components/dialog/dialog.css +49 -0
  72. package/src/components/dialog/dialog.props.ts +45 -0
  73. package/src/components/divider/Divider.tsx +23 -0
  74. package/src/components/divider/divider.props.ts +9 -0
  75. package/src/components/eyebrow/Eyebrow.tsx +54 -0
  76. package/src/components/eyebrow/eyebrow.css +11 -0
  77. package/src/components/eyebrow/eyebrow.props.ts +28 -0
  78. package/src/components/flex/Flex.tsx +30 -0
  79. package/src/components/flex/flex.css +4 -0
  80. package/src/components/flex/flex.props.ts +33 -0
  81. package/src/components/grid/Grid.tsx +30 -0
  82. package/src/components/grid/grid.css +4 -0
  83. package/src/components/grid/grid.props.ts +33 -0
  84. package/src/components/h-stack/HStack.tsx +34 -0
  85. package/src/components/h-stack/hStack.props.ts +17 -0
  86. package/src/components/heading/Heading.tsx +54 -0
  87. package/src/components/heading/heading.css +9 -0
  88. package/src/components/heading/heading.props.ts +31 -0
  89. package/src/components/icon/Icon.tsx +24 -0
  90. package/src/components/icon/icon.css +17 -0
  91. package/src/components/icon/icon.props.ts +35 -0
  92. package/src/components/icon-button/IconButton.tsx +32 -0
  93. package/src/components/icon-button/iconButton.props.ts +31 -0
  94. package/src/components/index.css +28 -0
  95. package/src/components/indicator/Indicator.tsx +42 -0
  96. package/src/components/indicator/indicator.css +4 -0
  97. package/src/components/indicator/indicator.props.ts +24 -0
  98. package/src/components/indicator-stack/IndicatorStack.tsx +31 -0
  99. package/src/components/indicator-stack/indicator-stack.css +7 -0
  100. package/src/components/indicator-stack/indicatorStack.props.ts +15 -0
  101. package/src/components/inline/Inline.tsx +38 -0
  102. package/src/components/inline/inline.css +4 -0
  103. package/src/components/inline/inline.props.ts +100 -0
  104. package/src/components/label/Label.tsx +34 -0
  105. package/src/components/label/label.css +3 -0
  106. package/src/components/label/label.props.ts +25 -0
  107. package/src/components/link/Link.tsx +29 -0
  108. package/src/components/link/link.css +12 -0
  109. package/src/components/link/link.props.ts +23 -0
  110. package/src/components/list/List.tsx +167 -0
  111. package/src/components/list/list.css +25 -0
  112. package/src/components/list/list.props.ts +130 -0
  113. package/src/components/popover/Popover.tsx +85 -0
  114. package/src/components/popover/popover.css +21 -0
  115. package/src/components/popover/popover.props.ts +38 -0
  116. package/src/components/press-area/PressArea.tsx +29 -0
  117. package/src/components/press-area/press-area.css +22 -0
  118. package/src/components/press-area/pressArea.props.ts +16 -0
  119. package/src/components/radio/Radio.tsx +48 -0
  120. package/src/components/radio/radio.css +97 -0
  121. package/src/components/radio/radio.props.ts +25 -0
  122. package/src/components/skip-to-content/SkipToContent.tsx +35 -0
  123. package/src/components/skip-to-content/skip-to-content.css +9 -0
  124. package/src/components/skip-to-content/skipToContent.props.ts +25 -0
  125. package/src/components/spinner/Spinner.tsx +28 -0
  126. package/src/components/spinner/spinner.css +10 -0
  127. package/src/components/spinner/spinner.props.ts +19 -0
  128. package/src/components/switch/Switch.tsx +48 -0
  129. package/src/components/switch/switch.css +119 -0
  130. package/src/components/switch/switch.props.ts +25 -0
  131. package/src/components/text/Text.tsx +53 -0
  132. package/src/components/text/text.css +9 -0
  133. package/src/components/text/text.props.ts +28 -0
  134. package/src/components/tooltip/Tooltip.tsx +97 -0
  135. package/src/components/tooltip/tooltip.css +31 -0
  136. package/src/components/tooltip/tooltip.props.ts +36 -0
  137. package/src/components/tooltip-group/TooltipGroup.tsx +64 -0
  138. package/src/components/tooltip-group/tooltipGroup.props.ts +15 -0
  139. package/src/components/v-stack/VStack.tsx +32 -0
  140. package/src/components/v-stack/vStack.props.ts +17 -0
  141. package/src/components/visually-hidden/VisuallyHidden.tsx +29 -0
  142. package/src/components/visually-hidden/visually-hidden.css +9 -0
  143. package/src/components/visually-hidden/visuallyHidden.props.ts +23 -0
  144. package/src/css/classes/dynamic/flex-child.css +5 -0
  145. package/src/css/classes/dynamic/grid-child.css +8 -0
  146. package/src/css/classes/dynamic/grid-parent.css +6 -0
  147. package/src/css/classes/dynamic/height.css +5 -0
  148. package/src/css/classes/dynamic/index.css +7 -0
  149. package/src/css/classes/dynamic/line-clamp.css +5 -0
  150. package/src/css/classes/dynamic/readme.md +3 -0
  151. package/src/css/classes/dynamic/width.css +7 -0
  152. package/src/css/classes/dynamic/z-index.css +3 -0
  153. package/src/css/classes/generic/display.css +10 -0
  154. package/src/css/classes/generic/flex.css +24 -0
  155. package/src/css/classes/generic/grid.css +7 -0
  156. package/src/css/classes/generic/index.css +7 -0
  157. package/src/css/classes/generic/overflow.css +19 -0
  158. package/src/css/classes/generic/placement.css +202 -0
  159. package/src/css/classes/generic/position.css +7 -0
  160. package/src/css/classes/generic/readme.md +3 -0
  161. package/src/css/classes/generic/text-align.css +5 -0
  162. package/src/css/classes/index.css +4 -0
  163. package/src/css/classes/local/animation.css +4 -0
  164. package/src/css/classes/local/border.css +20 -0
  165. package/src/css/classes/local/index.css +6 -0
  166. package/src/css/classes/local/readme.md +3 -0
  167. package/src/css/classes/local/text-overflow.css +5 -0
  168. package/src/css/classes/local/text-trim.css +45 -0
  169. package/src/css/classes/local/tone.css +75 -0
  170. package/src/css/classes/local/top-anchor.css +4 -0
  171. package/src/css/classes/system/color.css +223 -0
  172. package/src/css/classes/system/container.css +8 -0
  173. package/src/css/classes/system/font-family.css +2 -0
  174. package/src/css/classes/system/font-weight.css +4 -0
  175. package/src/css/classes/system/gap.css +37 -0
  176. package/src/css/classes/system/index.css +10 -0
  177. package/src/css/classes/system/inset.css +56 -0
  178. package/src/css/classes/system/margin.css +148 -0
  179. package/src/css/classes/system/padding.css +78 -0
  180. package/src/css/classes/system/radius.css +10 -0
  181. package/src/css/classes/system/readme.md +3 -0
  182. package/src/css/classes/system/shadow.css +6 -0
  183. package/src/css/classes/system/typography.css +31 -0
  184. package/src/css/global/font-face.css +20 -0
  185. package/src/css/global/index.css +2 -0
  186. package/src/css/global/reset.css +76 -0
  187. package/src/css/tokens/index.css +3 -0
  188. package/src/css/tokens/opacity.css +6 -0
  189. package/src/css/tokens/semantic.css +25 -0
  190. package/src/css/tokens/surface.css +27 -0
  191. package/src/hooks/useIsClient.ts +10 -0
  192. package/src/index.css +18 -0
  193. package/src/index.ts +65 -0
  194. package/src/polyfills.ts +15 -0
  195. package/src/props/border.ts +51 -0
  196. package/src/props/flexChild.ts +29 -0
  197. package/src/props/flexParent.ts +47 -0
  198. package/src/props/gap.ts +31 -0
  199. package/src/props/gridChild.ts +50 -0
  200. package/src/props/gridParent.ts +45 -0
  201. package/src/props/height.ts +29 -0
  202. package/src/props/layout.ts +44 -0
  203. package/src/props/margin.ts +59 -0
  204. package/src/props/overflow.ts +30 -0
  205. package/src/props/padding.ts +59 -0
  206. package/src/props/placement.ts +16 -0
  207. package/src/props/position.ts +52 -0
  208. package/src/props/shadow.ts +15 -0
  209. package/src/props/tone.ts +15 -0
  210. package/src/props/typography.ts +62 -0
  211. package/src/props/width.ts +29 -0
  212. package/src/props/zIndex.ts +15 -0
  213. package/src/styles.css.d.ts +1 -0
  214. package/src/styles.css.node.js +2 -0
  215. package/src/styles.css.test.ts +24 -0
  216. package/src/types/Button.ts +8 -0
  217. package/src/types/Code.ts +6 -0
  218. package/src/types/Container.ts +3 -0
  219. package/src/types/Density.ts +3 -0
  220. package/src/types/Display.ts +11 -0
  221. package/src/types/Eyebrow.ts +3 -0
  222. package/src/types/Flex.ts +22 -0
  223. package/src/types/FontWeight.ts +3 -0
  224. package/src/types/Grid.ts +3 -0
  225. package/src/types/Heading.ts +6 -0
  226. package/src/types/Icon.ts +3 -0
  227. package/src/types/Interactive.ts +8 -0
  228. package/src/types/List.ts +2 -0
  229. package/src/types/Overflow.ts +3 -0
  230. package/src/types/Placement.ts +16 -0
  231. package/src/types/Position.ts +3 -0
  232. package/src/types/PropDef.ts +73 -0
  233. package/src/types/Radius.ts +3 -0
  234. package/src/types/Responsive.ts +10 -0
  235. package/src/types/Shadow.ts +3 -0
  236. package/src/types/Space.ts +15 -0
  237. package/src/types/Text.ts +3 -0
  238. package/src/types/TextAlign.ts +3 -0
  239. package/src/types/Tone.ts +3 -0
  240. package/src/utils/getProps.test.ts +156 -0
  241. package/src/utils/getProps.ts +156 -0
  242. package/src/utils/mergeTriggerProps.ts +66 -0
  243. package/src/utils/renderPortal.tsx +14 -0
  244. package/src/utils/suffixClassName.ts +5 -0
  245. package/src/version.ts +3 -0
  246. package/LICENSE +0 -21
  247. package/dist/_system-CTe2lb5l.d.ts +0 -40
  248. package/dist/_system-CTe2lb5l.d.ts.map +0 -1
  249. package/dist/arrow-BmX6qbAS.js +0 -170
  250. package/dist/arrow-BmX6qbAS.js.map +0 -1
  251. package/dist/autocomplete.d.ts +0 -140
  252. package/dist/autocomplete.d.ts.map +0 -1
  253. package/dist/autocomplete.js +0 -470
  254. package/dist/autocomplete.js.map +0 -1
  255. package/dist/breadcrumbs.d.ts +0 -18
  256. package/dist/breadcrumbs.d.ts.map +0 -1
  257. package/dist/breadcrumbs.js +0 -119
  258. package/dist/breadcrumbs.js.map +0 -1
  259. package/dist/button-BNyKSDyA.js +0 -180
  260. package/dist/button-BNyKSDyA.js.map +0 -1
  261. package/dist/button-dnqMFkWg.d.ts +0 -76
  262. package/dist/button-dnqMFkWg.d.ts.map +0 -1
  263. package/dist/card-C0a0wQTc.d.ts +0 -7
  264. package/dist/card-C0a0wQTc.d.ts.map +0 -1
  265. package/dist/code.d.ts +0 -20
  266. package/dist/code.d.ts.map +0 -1
  267. package/dist/code.js +0 -90
  268. package/dist/code.js.map +0 -1
  269. package/dist/codeFontStyle-84SMhFtI.js +0 -11
  270. package/dist/codeFontStyle-84SMhFtI.js.map +0 -1
  271. package/dist/component-DVlwaWB-.d.ts +0 -25
  272. package/dist/component-DVlwaWB-.d.ts.map +0 -1
  273. package/dist/element-BYgCE_iK.js +0 -51
  274. package/dist/element-BYgCE_iK.js.map +0 -1
  275. package/dist/factory-BzXTX8_Q.js +0 -3056
  276. package/dist/factory-BzXTX8_Q.js.map +0 -1
  277. package/dist/flex-DmbDG2ks.js +0 -76
  278. package/dist/flex-DmbDG2ks.js.map +0 -1
  279. package/dist/font-EtfxKPUz.d.ts +0 -49
  280. package/dist/font-EtfxKPUz.d.ts.map +0 -1
  281. package/dist/getElementRef-Jw7gY0eV.js +0 -102
  282. package/dist/getElementRef-Jw7gY0eV.js.map +0 -1
  283. package/dist/getScopedTheme-C-sZsyAz.js +0 -267
  284. package/dist/getScopedTheme-C-sZsyAz.js.map +0 -1
  285. package/dist/getTheme_v2-y09KqtEb.js +0 -487
  286. package/dist/getTheme_v2-y09KqtEb.js.map +0 -1
  287. package/dist/grid-6JSgMj1O.js +0 -115
  288. package/dist/grid-6JSgMj1O.js.map +0 -1
  289. package/dist/helpers-C8xxXAQC.js +0 -63
  290. package/dist/helpers-C8xxXAQC.js.map +0 -1
  291. package/dist/hotkeys-CaHsQlsO.js +0 -168
  292. package/dist/hotkeys-CaHsQlsO.js.map +0 -1
  293. package/dist/index.d.ts.map +0 -1
  294. package/dist/layer-Bl5R3uNR.js +0 -61
  295. package/dist/layer-Bl5R3uNR.js.map +0 -1
  296. package/dist/layer-ChlP9Ik6.d.ts +0 -242
  297. package/dist/layer-ChlP9Ik6.d.ts.map +0 -1
  298. package/dist/menu.d.ts +0 -146
  299. package/dist/menu.d.ts.map +0 -1
  300. package/dist/menu.js +0 -626
  301. package/dist/menu.js.map +0 -1
  302. package/dist/popover-B7-28L8y.js +0 -408
  303. package/dist/popover-B7-28L8y.js.map +0 -1
  304. package/dist/popover-CMlQeKn0.d.ts +0 -96
  305. package/dist/popover-CMlQeKn0.d.ts.map +0 -1
  306. package/dist/popover.d.ts +0 -2
  307. package/dist/popover.js +0 -3
  308. package/dist/refractor-CC48DwHi.js +0 -20
  309. package/dist/refractor-CC48DwHi.js.map +0 -1
  310. package/dist/responsiveFont-CilwaORG.js +0 -55
  311. package/dist/responsiveFont-CilwaORG.js.map +0 -1
  312. package/dist/rgba-BSYaEUW6.d.ts +0 -846
  313. package/dist/rgba-BSYaEUW6.d.ts.map +0 -1
  314. package/dist/selectable-B0GUIL74.d.ts +0 -7
  315. package/dist/selectable-B0GUIL74.d.ts.map +0 -1
  316. package/dist/stack-rsNFPq2-.js +0 -112
  317. package/dist/stack-rsNFPq2-.js.map +0 -1
  318. package/dist/styles-css.d.ts +0 -2
  319. package/dist/styles-css.js +0 -4
  320. package/dist/textInput-pSfQjkmx.js +0 -313
  321. package/dist/textInput-pSfQjkmx.js.map +0 -1
  322. package/dist/theme.d.ts +0 -280
  323. package/dist/theme.d.ts.map +0 -1
  324. package/dist/theme.js +0 -55
  325. package/dist/theme.js.map +0 -1
  326. package/dist/toast.d.ts +0 -73
  327. package/dist/toast.d.ts.map +0 -1
  328. package/dist/toast.js +0 -302
  329. package/dist/toast.js.map +0 -1
  330. package/dist/tooltip.d.ts +0 -88
  331. package/dist/tooltip.d.ts.map +0 -1
  332. package/dist/tooltip.js +0 -435
  333. package/dist/tooltip.js.map +0 -1
  334. package/dist/useClickOutsideEvent-wGLGWBZN.js +0 -36
  335. package/dist/useClickOutsideEvent-wGLGWBZN.js.map +0 -1
  336. package/dist/useElementSize-BJvbGHq8.js +0 -51
  337. package/dist/useElementSize-BJvbGHq8.js.map +0 -1
  338. package/dist/useLayer-D1usxIE0.js +0 -712
  339. package/dist/useLayer-D1usxIE0.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "4.2.0",
3
+ "version": "5.0.0-alpha.10",
4
+ "description": "Sanity UI Library",
4
5
  "keywords": [
5
6
  "components",
6
7
  "design-system",
@@ -9,94 +10,92 @@
9
10
  "sanity",
10
11
  "ui"
11
12
  ],
12
- "homepage": "https://www.sanity.io/",
13
+ "homepage": "https://github.com/sanity-io/ui#readme",
13
14
  "bugs": {
14
15
  "url": "https://github.com/sanity-io/ui/issues"
15
16
  },
16
- "license": "MIT",
17
- "author": "Sanity.io <hello@sanity.io>",
17
+ "license": "ISC",
18
+ "author": "Sanity",
18
19
  "repository": {
19
20
  "type": "git",
20
- "url": "git+https://github.com/sanity-io/ui.git",
21
- "directory": "packages/ui"
21
+ "url": "git+https://github.com/sanity-io/ui.git"
22
+ },
23
+ "bin": {
24
+ "sanity-ui": "./bin/sanity-ui.js"
22
25
  },
23
26
  "files": [
24
- "dist"
27
+ "bin",
28
+ "dist",
29
+ "src"
25
30
  ],
26
31
  "type": "module",
27
32
  "sideEffects": [
28
- "*.css"
33
+ "*.css",
34
+ "./src/polyfills.ts",
35
+ "./dist/polyfills.js"
29
36
  ],
30
37
  "types": "./dist/index.d.ts",
31
38
  "exports": {
32
39
  ".": "./dist/index.js",
33
- "./autocomplete": "./dist/autocomplete.js",
34
- "./breadcrumbs": "./dist/breadcrumbs.js",
35
- "./code": "./dist/code.js",
36
- "./menu": "./dist/menu.js",
37
- "./popover": "./dist/popover.js",
38
- "./theme": "./dist/theme.js",
39
- "./toast": "./dist/toast.js",
40
- "./tooltip": "./dist/tooltip.js",
40
+ "./polyfills": "./dist/polyfills.js",
41
+ "./package.json": "./package.json",
41
42
  "./styles.css": {
42
- "types": "./dist/styles-css.d.ts",
43
+ "types": "./src/styles.css.d.ts",
43
44
  "browser": "./dist/styles.css",
44
45
  "style": "./dist/styles.css",
45
- "node": "./dist/styles-css.js",
46
- "default": "./dist/styles-css.js"
47
- },
48
- "./package.json": "./package.json"
46
+ "node": "./src/styles.css.node.js",
47
+ "default": "./src/styles.css.node.js"
48
+ }
49
49
  },
50
50
  "dependencies": {
51
- "@floating-ui/react-dom": "^2.1.9",
52
- "@sanity/color": "^3.0.8",
51
+ "@sanity-labs/design-tokens": "0.0.2-alpha.4",
53
52
  "@sanity/icons": "^5.2.1",
54
- "@vanilla-extract/dynamic": "^2.1.5",
55
53
  "clsx": "^2.1.1",
56
- "csstype": "^3.2.3",
57
- "motion": "^13.2.0",
58
- "react-is": "^19.2.8",
59
- "react-refractor": "^4.0.0",
60
- "use-effect-event": "^2.0.4"
54
+ "comment-json": "^5.0.0",
55
+ "dialog-closedby-polyfill": "^1.3.0",
56
+ "interestfor": "^1.0.8",
57
+ "react-refractor": "^4.0.0"
61
58
  },
62
59
  "devDependencies": {
63
- "@sanity/tsdown-config": "^0.28.0",
64
- "@sanity/vanilla-extract-vite-plugin": "^0.2.18",
65
- "@testing-library/dom": "^10.4.1",
66
- "@testing-library/jest-dom": "^7.0.1",
67
- "@testing-library/react": "^16.3.3",
68
- "@testing-library/user-event": "^14.6.7",
69
- "@types/node": "^24.13.3",
70
- "@types/react": "^19.2.18",
71
- "@types/react-dom": "^19.2.7",
72
- "@types/react-is": "^19.2.0",
73
- "@vanilla-extract/css": "^1.21.2",
74
- "jsdom": "^30.0.1",
75
- "oxc-transform-react": "^0.149.0",
76
- "react": "^19.2.8",
77
- "react-dom": "^19.2.8",
78
- "rimraf": "^5.0.5",
79
- "styled-components": "^6.5.3",
80
- "tsdown": "^0.23.0",
81
- "typescript": "7.0.2",
82
- "unrun": "^0.3.1",
83
- "vite": "^8.2.2",
84
- "vitest": "^5.0.0",
85
- "vitest-axe": "^1.0.0-pre.5"
60
+ "@sanity/browserslist-config": "^1.0.5",
61
+ "@sanity/pkg-utils": "^10.8.2",
62
+ "@sanity/tsconfig": "^1.0.0",
63
+ "@types/node": "^25.5.2",
64
+ "@types/postcss-import": "^14.0.3",
65
+ "@types/postcss-prefix-selector": "^1.16.3",
66
+ "@types/react": "^19.2.17",
67
+ "@types/react-dom": "^19.2.3",
68
+ "autoprefixer": "^10.4.27",
69
+ "babel-plugin-react-compiler": "^1.0.0",
70
+ "concurrently": "^9.2.1",
71
+ "cssnano": "^8.0.0",
72
+ "postcss": "^8.5.14",
73
+ "postcss-cli": "^11.0.1",
74
+ "postcss-import": "^16.1.1",
75
+ "postcss-prefix-selector": "^2.1.1",
76
+ "postcss-selector-parser": "^7.1.1",
77
+ "rimraf": "^6.1.3",
78
+ "typescript": "^5.9.3",
79
+ "vitest": "^4.1.1"
86
80
  },
87
81
  "peerDependencies": {
88
82
  "react": "^19.2",
89
- "react-dom": "^19.2",
90
- "styled-components": "^6.1"
83
+ "react-dom": "^19.2"
91
84
  },
92
85
  "engines": {
93
- "node": ">=22.12"
86
+ "node": ">=20.19 <22 || >=22.12"
94
87
  },
95
88
  "scripts": {
96
- "build": "tsdown",
89
+ "build": "pnpm run sync-version && pnpm run clean && pnpm run build:css && pnpm run build:js && pnpm run build:cli",
90
+ "build:cli": "tsc -p tsconfig.cli.json",
91
+ "build:css": "NODE_ENV=production postcss src/index.css -o dist/styles.css",
92
+ "build:js": "pkg build --strict --check",
97
93
  "clean": "rimraf dist",
94
+ "dev": "concurrently -n css,js \"pnpm run dev:css\" \"pnpm run dev:js\"",
95
+ "dev:css": "postcss src/index.css -o dist/styles.css --watch",
96
+ "dev:js": "pkg watch",
97
+ "sync-version": "node scripts/write-version.js",
98
98
  "test": "vitest run",
99
- "test:watch": "vitest",
100
- "watch": "tsdown --watch"
99
+ "ts:check": "tsc --noEmit"
101
100
  }
102
101
  }
@@ -0,0 +1,38 @@
1
+ import {mkdtempSync, rmSync, writeFileSync} from 'node:fs'
2
+ import {tmpdir} from 'node:os'
3
+ import {join} from 'node:path'
4
+
5
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest'
6
+
7
+ import {collectChecks} from './checks.js'
8
+ import {writeInstalledUiVersion} from './test-utils.js'
9
+
10
+ describe('collectChecks tsconfig', () => {
11
+ let dir: string
12
+ beforeEach(() => {
13
+ dir = mkdtempSync(join(tmpdir(), 'sui-checks-'))
14
+ })
15
+ afterEach(() => {
16
+ rmSync(dir, {recursive: true, force: true})
17
+ })
18
+
19
+ it('fails (not passes) when tsconfig.json cannot be parsed', () => {
20
+ // Genuinely unparseable (unterminated object), not just JSONC that
21
+ // comment-json would tolerate.
22
+ writeFileSync(join(dir, 'tsconfig.json'), '{ "compilerOptions": { "jsx": "react-jsx"')
23
+ const {checks} = collectChecks(dir)
24
+ const tsconfig = checks.find((c) => c.id === 'tsconfig')
25
+ expect(tsconfig?.status).toBe('fail')
26
+ expect(tsconfig?.detail).toMatch(/could not be parsed/)
27
+ })
28
+
29
+ it('fails the version check when @sanity/ui is pre-v5', () => {
30
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: {}}))
31
+ writeInstalledUiVersion(dir, '3.5.1')
32
+ const {checks} = collectChecks(dir)
33
+ expect(checks.find((c) => c.id === 'install')?.status).toBe('pass')
34
+ const version = checks.find((c) => c.id === 'version')
35
+ expect(version?.status).toBe('fail')
36
+ expect(version?.detail).toMatch(/pre-v5 \(expected v5\)/)
37
+ })
38
+ })
@@ -0,0 +1,200 @@
1
+ import {existsSync, readFileSync} from 'node:fs'
2
+ import {createRequire} from 'node:module'
3
+ import {dirname, join} from 'node:path'
4
+ import process from 'node:process'
5
+
6
+ import {
7
+ detect,
8
+ isPackageInstalled,
9
+ isLegacyUiVersion,
10
+ PACKAGE_NAME,
11
+ readInstalledPackageVersion,
12
+ } from './detect.js'
13
+ import {inspectStylesheet, STYLES_SPECIFIER} from './styles.js'
14
+ import {inspectTsconfig} from './tsconfig.js'
15
+ import type {Check, CheckStatus, Detected} from './types.js'
16
+ import {meetsNode, meetsReact, NODE_REQUIREMENT, REACT_MIN} from './versions.js'
17
+
18
+ const ICONS = '@sanity/icons'
19
+
20
+ /** Resolves the built stylesheet on disk (not the Node no-op shim). */
21
+ function resolveStylesheet(cwd: string): string | null {
22
+ try {
23
+ const require = createRequire(join(cwd, 'noop.js'))
24
+ const pkgJsonPath = require.resolve(`${PACKAGE_NAME}/package.json`)
25
+ const path = join(dirname(pkgJsonPath), 'dist/styles.css')
26
+ return existsSync(path) ? path : null
27
+ } catch {
28
+ return null
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Without a browser, "a component renders with a computed background" is
34
+ * verified by confirming the resolved stylesheet ships the component class and
35
+ * a background declaration for it. If both are present and the import is wired,
36
+ * the component renders styled.
37
+ */
38
+ function stylesheetHasComponentStyles(path: string): boolean {
39
+ try {
40
+ const css = readFileSync(path, 'utf8')
41
+ return /\.sui-Card\b/.test(css) && /background/.test(css)
42
+ } catch {
43
+ return false
44
+ }
45
+ }
46
+
47
+ interface CheckMeta {
48
+ title: string
49
+ detail?: string
50
+ fix?: string
51
+ status?: CheckStatus
52
+ }
53
+
54
+ function check(id: string, ok: boolean, meta: CheckMeta): Check {
55
+ return {
56
+ id,
57
+ title: meta.title,
58
+ ok,
59
+ status: meta.status ?? (ok ? 'pass' : 'fail'),
60
+ detail: meta.detail,
61
+ fix: meta.fix,
62
+ }
63
+ }
64
+
65
+ export interface CheckReport {
66
+ detected: Detected
67
+ checks: Check[]
68
+ stylesheetPath: string | null
69
+ }
70
+
71
+ /**
72
+ * Runs every verification and returns structured results. `doctor` prints them
73
+ * all; `init` reuses a subset on exit. Pure read-only.
74
+ */
75
+ export function collectChecks(cwd: string): CheckReport {
76
+ const detected = detect(cwd)
77
+ const checks: Check[] = []
78
+
79
+ const installedVersion = readInstalledPackageVersion(cwd, PACKAGE_NAME)
80
+ checks.push(
81
+ check('install', Boolean(installedVersion), {
82
+ title: 'Package installed',
83
+ detail: installedVersion ? `${PACKAGE_NAME}@${installedVersion}` : 'not installed',
84
+ fix: `Run \`npx ${PACKAGE_NAME}@alpha init\` or install it with your package manager`,
85
+ }),
86
+ )
87
+
88
+ if (installedVersion) {
89
+ const legacyInstalled = isLegacyUiVersion(installedVersion)
90
+ checks.push(
91
+ check('version', !legacyInstalled, {
92
+ title: 'Package version',
93
+ detail: legacyInstalled
94
+ ? `${PACKAGE_NAME}@${installedVersion} is pre-v5 (expected v5)`
95
+ : `${PACKAGE_NAME}@${installedVersion}`,
96
+ fix: `Remove the existing @sanity/ui version, or install v5 with a package alias — see README "For apps using Sanity UI v3"`,
97
+ }),
98
+ )
99
+ }
100
+
101
+ const iconsInstalled = isPackageInstalled(cwd, ICONS)
102
+ checks.push(
103
+ check('icons', iconsInstalled, {
104
+ title: 'Icons installed',
105
+ detail: iconsInstalled ? `${ICONS} present` : `${ICONS} missing`,
106
+ fix: `Install it: add ${ICONS}`,
107
+ }),
108
+ )
109
+
110
+ const stylesheetPath = resolveStylesheet(cwd)
111
+ const stylesheetResolves = Boolean(stylesheetPath)
112
+ checks.push(
113
+ check('stylesheet-resolves', stylesheetResolves, {
114
+ title: 'Stylesheet resolves',
115
+ detail: stylesheetResolves ? `${PACKAGE_NAME}/styles.css` : 'cannot resolve styles.css',
116
+ fix: 'Reinstall the package, or build it if working inside this monorepo',
117
+ }),
118
+ )
119
+
120
+ const stylesheet = inspectStylesheet(cwd, detected.entry)
121
+ checks.push(
122
+ check('stylesheet-wired', stylesheet.imported, {
123
+ title: 'Stylesheet imported',
124
+ detail: stylesheet.imported
125
+ ? `imported in ${stylesheet.importedIn ?? detected.entry}`
126
+ : stylesheet.exists
127
+ ? `missing from ${detected.entry}`
128
+ : `entry file ${detected.entry} not found`,
129
+ fix: `Add \`import '${STYLES_SPECIFIER}'\` to ${detected.entry}`,
130
+ }),
131
+ )
132
+
133
+ if (detected.typescript) {
134
+ const tsconfig = inspectTsconfig(cwd)
135
+ const loadBearing = tsconfig.changes.filter((c) => c.load)
136
+ // An unreadable file has no changes to report, so guard against it explicitly
137
+ // rather than letting an empty change list read as "all good".
138
+ const ok = tsconfig.exists && !tsconfig.unreadable && loadBearing.length === 0
139
+ checks.push(
140
+ check('tsconfig', ok, {
141
+ title: 'tsconfig options',
142
+ detail: !tsconfig.exists
143
+ ? 'tsconfig.json not found'
144
+ : tsconfig.unreadable
145
+ ? 'tsconfig.json could not be parsed'
146
+ : loadBearing.length === 0
147
+ ? tsconfig.changes.length === 0
148
+ ? 'all required options set'
149
+ : 'required options set (some optional additions available)'
150
+ : `needs: ${loadBearing.map((c) => `${c.key}: ${String(c.to)}`).join(', ')}`,
151
+ fix: tsconfig.unreadable
152
+ ? 'Fix the JSON syntax in tsconfig.json'
153
+ : `Run \`npx ${PACKAGE_NAME}@alpha init\` to reconcile tsconfig.json`,
154
+ }),
155
+ )
156
+ }
157
+
158
+ const reactVersion = detected.react.version
159
+ const reactOk = reactVersion ? meetsReact(reactVersion) : false
160
+ checks.push(
161
+ check('react', reactOk, {
162
+ title: 'React version',
163
+ status: reactVersion ? (reactOk ? 'pass' : 'fail') : 'warn',
164
+ detail: reactVersion ? `react ${reactVersion}` : 'react not detected',
165
+ fix: `Upgrade React to >= ${REACT_MIN}`,
166
+ }),
167
+ )
168
+
169
+ const nodeVersion = process.versions.node
170
+ checks.push(
171
+ check('node', meetsNode(nodeVersion), {
172
+ title: 'Node version',
173
+ detail: `node ${nodeVersion} (requires ${NODE_REQUIREMENT})`,
174
+ fix: `Use Node ${NODE_REQUIREMENT}`,
175
+ }),
176
+ )
177
+
178
+ return {detected, checks, stylesheetPath}
179
+ }
180
+
181
+ /** The subset `init` verifies on exit, plus the render probe. */
182
+ export function verifyAfterInit(cwd: string): Check[] {
183
+ const {checks, stylesheetPath} = collectChecks(cwd)
184
+ const ids = new Set(['stylesheet-resolves', 'stylesheet-wired', 'tsconfig'])
185
+ const subset = checks.filter((c) => ids.has(c.id))
186
+
187
+ const probeOk = stylesheetPath ? stylesheetHasComponentStyles(stylesheetPath) : false
188
+ subset.push({
189
+ id: 'probe',
190
+ title: 'Probe renders with background',
191
+ ok: probeOk,
192
+ status: probeOk ? 'pass' : 'fail',
193
+ detail: stylesheetPath
194
+ ? 'Card ships a background declaration'
195
+ : 'stylesheet not resolved, cannot probe',
196
+ fix: 'Ensure the package is installed and built',
197
+ })
198
+
199
+ return subset
200
+ }
@@ -0,0 +1,44 @@
1
+ import {existsSync, writeFileSync} from 'node:fs'
2
+ import {join} from 'node:path'
3
+
4
+ import type {Framework} from './types.js'
5
+
6
+ export const CONFIG_FILE = 'sanity-ui.json'
7
+
8
+ export interface SanityUiConfig {
9
+ $schema: string
10
+ framework: Framework
11
+ entry: string
12
+ }
13
+
14
+ /**
15
+ * Builds the sanity-ui.json contents: a small record of the detected setup
16
+ * (framework, entry) written to the project root for tooling to read.
17
+ */
18
+ export function buildConfig({
19
+ framework,
20
+ entry,
21
+ }: {
22
+ framework: Framework
23
+ entry: string
24
+ }): SanityUiConfig {
25
+ return {
26
+ $schema: 'https://sanity-ui.sanity.dev/schema.json',
27
+ framework,
28
+ entry,
29
+ }
30
+ }
31
+
32
+ export function configExists(cwd: string): boolean {
33
+ return existsSync(join(cwd, CONFIG_FILE))
34
+ }
35
+
36
+ export function writeConfig(
37
+ cwd: string,
38
+ config: SanityUiConfig,
39
+ {dryRun = false} = {},
40
+ ): {file: string; wrote: boolean} {
41
+ const file = join(cwd, CONFIG_FILE)
42
+ if (!dryRun) writeFileSync(file, `${JSON.stringify(config, null, 2)}\n`)
43
+ return {file, wrote: !dryRun}
44
+ }
@@ -0,0 +1,191 @@
1
+ import {mkdirSync, mkdtempSync, rmSync, writeFileSync} from 'node:fs'
2
+ import {tmpdir} from 'node:os'
3
+ import {join} from 'node:path'
4
+
5
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest'
6
+
7
+ import {
8
+ detect,
9
+ detectEntry,
10
+ detectFramework,
11
+ detectPackageManager,
12
+ isLegacyUiVersion,
13
+ } from './detect.js'
14
+ import {writeInstalledUiVersion} from './test-utils.js'
15
+
16
+ describe('detectPackageManager', () => {
17
+ let dir: string
18
+ beforeEach(() => {
19
+ dir = mkdtempSync(join(tmpdir(), 'sui-pm-'))
20
+ })
21
+ afterEach(() => {
22
+ rmSync(dir, {recursive: true, force: true})
23
+ })
24
+
25
+ it('reads lockfiles', () => {
26
+ writeFileSync(join(dir, 'pnpm-lock.yaml'), '')
27
+ expect(detectPackageManager(dir)).toBe('pnpm')
28
+ })
29
+
30
+ it('falls back to the packageManager field, then npm', () => {
31
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({packageManager: 'yarn@4.0.0'}))
32
+ expect(detectPackageManager(dir)).toBe('yarn')
33
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({}))
34
+ expect(detectPackageManager(dir)).toBe('npm')
35
+ })
36
+ })
37
+
38
+ describe('detectFramework', () => {
39
+ let dir: string
40
+ beforeEach(() => {
41
+ dir = mkdtempSync(join(tmpdir(), 'sui-fw-'))
42
+ })
43
+ afterEach(() => {
44
+ rmSync(dir, {recursive: true, force: true})
45
+ })
46
+
47
+ function pkg(deps: Record<string, string>): void {
48
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: deps}))
49
+ }
50
+
51
+ it('distinguishes Next App Router from Pages', () => {
52
+ pkg({next: '16.0.0'})
53
+ mkdirSync(join(dir, 'app'))
54
+ expect(detectFramework(dir)).toBe('next-app')
55
+
56
+ rmSync(join(dir, 'app'), {recursive: true})
57
+ mkdirSync(join(dir, 'pages'))
58
+ expect(detectFramework(dir)).toBe('next-pages')
59
+ })
60
+
61
+ it('detects react-router, remix, astro, vite, and the react fallback', () => {
62
+ pkg({'@react-router/dev': '7.0.0', 'react-router': '7.0.0'})
63
+ expect(detectFramework(dir)).toBe('react-router')
64
+
65
+ pkg({'@remix-run/react': '2.0.0'})
66
+ expect(detectFramework(dir)).toBe('remix')
67
+
68
+ pkg({astro: '4.0.0'})
69
+ expect(detectFramework(dir)).toBe('astro')
70
+
71
+ pkg({vite: '8.0.0'})
72
+ expect(detectFramework(dir)).toBe('vite')
73
+
74
+ pkg({react: '19.2.0'})
75
+ expect(detectFramework(dir)).toBe('react')
76
+ })
77
+ })
78
+
79
+ describe('detectEntry', () => {
80
+ let dir: string
81
+ beforeEach(() => {
82
+ dir = mkdtempSync(join(tmpdir(), 'sui-entry-'))
83
+ })
84
+ afterEach(() => {
85
+ rmSync(dir, {recursive: true, force: true})
86
+ })
87
+
88
+ it('returns the existing entry when present', () => {
89
+ mkdirSync(join(dir, 'src'))
90
+ writeFileSync(join(dir, 'src/main.tsx'), '')
91
+ expect(detectEntry(dir, 'vite')).toEqual({entry: 'src/main.tsx', exists: true})
92
+ })
93
+
94
+ it('returns the canonical default when absent', () => {
95
+ expect(detectEntry(dir, 'next-app')).toEqual({entry: 'app/layout.tsx', exists: false})
96
+ })
97
+ })
98
+
99
+ describe('detect typescript flag', () => {
100
+ let dir: string
101
+ beforeEach(() => {
102
+ dir = mkdtempSync(join(tmpdir(), 'sui-ts-'))
103
+ })
104
+ afterEach(() => {
105
+ rmSync(dir, {recursive: true, force: true})
106
+ })
107
+
108
+ it('does not infer TypeScript from a guessed entry that does not exist', () => {
109
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: {react: '19.2.0'}}))
110
+ // No tsconfig, no typescript dep, and the .tsx entry is only a fallback guess.
111
+ expect(detect(dir).typescript).toBe(false)
112
+ })
113
+
114
+ it('infers TypeScript when the resolved entry file actually exists', () => {
115
+ mkdirSync(join(dir, 'src'))
116
+ writeFileSync(join(dir, 'src/main.tsx'), '')
117
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({devDependencies: {vite: '8.0.0'}}))
118
+ expect(detect(dir).typescript).toBe(true)
119
+ })
120
+ })
121
+
122
+ describe('isLegacyUiVersion', () => {
123
+ it('treats majors 1–4 as legacy and 5+ as v5', () => {
124
+ expect(isLegacyUiVersion('3.5.1')).toBe(true)
125
+ expect(isLegacyUiVersion('5.0.0-alpha.1')).toBe(false)
126
+ expect(isLegacyUiVersion('5.0.0')).toBe(false)
127
+ })
128
+ })
129
+
130
+ describe('detect ui install', () => {
131
+ let dir: string
132
+ beforeEach(() => {
133
+ dir = mkdtempSync(join(tmpdir(), 'sui-ui-install-'))
134
+ })
135
+ afterEach(() => {
136
+ rmSync(dir, {recursive: true, force: true})
137
+ })
138
+
139
+ it('detects a declared pre-v5 range', () => {
140
+ writeFileSync(
141
+ join(dir, 'package.json'),
142
+ JSON.stringify({dependencies: {'@sanity/ui': '^3.5.1'}}),
143
+ )
144
+ expect(detect(dir).legacyInstall).toBe('^3.5.1')
145
+ })
146
+
147
+ it('detects an installed pre-v5 version', () => {
148
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: {}}))
149
+ writeInstalledUiVersion(dir, '3.5.1')
150
+ expect(detect(dir).legacyInstall).toBe('3.5.1')
151
+ })
152
+
153
+ it('detects a v5 npm alias alongside legacy @sanity/ui', () => {
154
+ writeFileSync(
155
+ join(dir, 'package.json'),
156
+ JSON.stringify({dependencies: {'ui5': 'npm:@sanity/ui@5', '@sanity/ui': '^3.5.1'}}),
157
+ )
158
+ const result = detect(dir)
159
+ expect(result.aliasedInstall).toBe('ui5')
160
+ expect(result.legacyInstall).toBe('^3.5.1')
161
+ })
162
+
163
+ it('detects a versioned v5 npm alias', () => {
164
+ writeFileSync(
165
+ join(dir, 'package.json'),
166
+ JSON.stringify({dependencies: {ui5: 'npm:@sanity/ui@5.0.0-alpha.1'}}),
167
+ )
168
+ expect(detect(dir).aliasedInstall).toBe('ui5')
169
+ })
170
+
171
+ it('detects the alpha dist-tag npm alias', () => {
172
+ writeFileSync(
173
+ join(dir, 'package.json'),
174
+ JSON.stringify({dependencies: {ui5: 'npm:@sanity/ui@alpha'}}),
175
+ )
176
+ expect(detect(dir).aliasedInstall).toBe('ui5')
177
+ })
178
+
179
+ it('does not detect uninstalled ui as legacy or alias', () => {
180
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: {react: '19.2.0'}}))
181
+ expect(detect(dir).legacyInstall).toBeNull()
182
+ expect(detect(dir).aliasedInstall).toBeNull()
183
+ })
184
+
185
+ it('does not detect installed v5 as legacy or alias', () => {
186
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({dependencies: {}}))
187
+ writeInstalledUiVersion(dir, '5.0.0-alpha.1')
188
+ expect(detect(dir).legacyInstall).toBeNull()
189
+ expect(detect(dir).aliasedInstall).toBeNull()
190
+ })
191
+ })