@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
@@ -0,0 +1,25 @@
1
+ import {type MarginProps, marginProps} from '../../props/margin'
2
+ import {type PropDef} from '../../types/PropDef'
3
+
4
+ /** @beta */
5
+ export interface LabelProps extends React.ComponentProps<'label'>, MarginProps {
6
+ /**
7
+ * Renders the label in a muted color.
8
+ */
9
+ disabled?: boolean
10
+ /**
11
+ * Renders the label in the error color.
12
+ * @remarks Use when the linked input has a validation error.
13
+ */
14
+ error?: boolean
15
+ }
16
+
17
+ export const labelProps: Record<string, PropDef> = {
18
+ disabled: {
19
+ type: 'boolean',
20
+ },
21
+ error: {
22
+ type: 'boolean',
23
+ },
24
+ ...marginProps,
25
+ }
@@ -0,0 +1,29 @@
1
+ import clsx from 'clsx'
2
+
3
+ import {getProps} from '../../utils/getProps'
4
+ import {suffixClassName} from '../../utils/suffixClassName'
5
+ import {type LinkProps, linkProps} from './link.props'
6
+
7
+ const linkClassName = suffixClassName('sui-Link')
8
+
9
+ /** @beta */
10
+ export function Link({underlined = true, ...props}: LinkProps) {
11
+ const {children, className, style, openInNewTab, ...rest} = getProps(
12
+ {underlined, ...props},
13
+ linkProps,
14
+ )
15
+
16
+ return (
17
+ <a
18
+ className={clsx(linkClassName, className)}
19
+ style={style}
20
+ data-ui="Link"
21
+ {...(openInNewTab ? {target: '_blank', rel: 'noopener noreferrer'} : {})}
22
+ {...rest}
23
+ >
24
+ {children}
25
+ </a>
26
+ )
27
+ }
28
+
29
+ export type {LinkProps}
@@ -0,0 +1,12 @@
1
+ .sui-Link {
2
+ color: inherit;
3
+ text-decoration: none;
4
+ }
5
+
6
+ .sui-Link:focus-visible {
7
+ outline-color: var(--blue-500);
8
+ }
9
+
10
+ .sui-Link.sui-underlined {
11
+ text-decoration: underline;
12
+ }
@@ -0,0 +1,23 @@
1
+ import {type PropDef} from '../../types/PropDef'
2
+
3
+ /** @beta */
4
+ export interface LinkProps extends React.ComponentProps<'a'> {
5
+ /**
6
+ * Sets the link to `target="_blank"` and `rel="noopener noreferrer"`.
7
+ */
8
+ openInNewTab?: boolean
9
+ /**
10
+ * Underlines the link.
11
+ */
12
+ underlined?: boolean
13
+ }
14
+
15
+ export const linkProps: Record<string, PropDef> = {
16
+ openInNewTab: {
17
+ type: 'boolean',
18
+ },
19
+ underlined: {
20
+ type: 'boolean',
21
+ className: 'underlined',
22
+ },
23
+ }
@@ -0,0 +1,167 @@
1
+ import clsx from 'clsx'
2
+ import type {ComponentProps, ComponentPropsWithRef, ElementType} from 'react'
3
+
4
+ import type {ListTag} from '../../types/List'
5
+ import {getProps} from '../../utils/getProps'
6
+ import {suffixClassName} from '../../utils/suffixClassName'
7
+ import {Flex} from '../flex/Flex'
8
+ import {PressArea} from '../press-area/PressArea'
9
+ import {Text} from '../text/Text'
10
+ import {VStack} from '../v-stack/VStack'
11
+ import {
12
+ listButtonItemProps,
13
+ type ListButtonItemProps,
14
+ type ListItemProps,
15
+ listItemProps,
16
+ type ListItemTextProps,
17
+ listItemTextProps,
18
+ type ListProps,
19
+ listProps,
20
+ } from './list.props'
21
+
22
+ const listClassName = suffixClassName('sui-List')
23
+ const listItemClassName = suffixClassName('sui-ListItem')
24
+ const listButtonItemClassName = suffixClassName('sui-ListButtonItem')
25
+ const listItemTextClassName = suffixClassName('sui-ListItemText')
26
+ const listItemImageClassName = suffixClassName('sui-ListItemImage')
27
+
28
+ function ListRoot<T extends ListTag = 'ul'>(
29
+ props: ListProps<T> & Omit<ComponentPropsWithRef<T>, keyof ListProps<T>>,
30
+ ) {
31
+ const {as, children, className, style, ...rest} = getProps(props, listProps)
32
+ const Component = as || 'ul'
33
+
34
+ return (
35
+ <VStack
36
+ as={Component}
37
+ className={clsx(listClassName, className)}
38
+ style={style}
39
+ data-ui="List"
40
+ {...rest}
41
+ >
42
+ {children}
43
+ </VStack>
44
+ )
45
+ }
46
+
47
+ function ListItem({density = 'regular', ...props}: ListItemProps) {
48
+ const {children, className, style, end, start, ...rest} = getProps(
49
+ {density, ...props},
50
+ listItemProps,
51
+ )
52
+
53
+ return (
54
+ <li
55
+ className={clsx(
56
+ listItemClassName,
57
+ 'sui-width-full sui-display-flex sui-align-items-center',
58
+ className,
59
+ )}
60
+ style={style}
61
+ data-ui="ListItem"
62
+ {...rest}
63
+ >
64
+ {start}
65
+
66
+ <Flex flexGrow={1} gap="inherit">
67
+ {children}
68
+ </Flex>
69
+
70
+ {end}
71
+ </li>
72
+ )
73
+ }
74
+
75
+ function ListButtonItem<T extends ElementType = 'button'>({
76
+ density = 'regular',
77
+ ...props
78
+ }: ListButtonItemProps<T> & Omit<ComponentPropsWithRef<T>, keyof ListButtonItemProps<T>>) {
79
+ const {as, children, className, style, end, start, selected, ...rest} = getProps(
80
+ {density, ...props},
81
+ listButtonItemProps,
82
+ )
83
+ const Component = as || 'button'
84
+
85
+ return (
86
+ <li>
87
+ <PressArea
88
+ as={Component}
89
+ className={clsx(
90
+ listButtonItemClassName,
91
+ 'sui-width-full sui-display-flex sui-align-items-center sui-radius2',
92
+ className,
93
+ )}
94
+ style={style}
95
+ data-ui="ListButtonItem"
96
+ data-selected={selected}
97
+ {...rest}
98
+ >
99
+ {start}
100
+
101
+ <Flex flexGrow={1} gap="inherit">
102
+ {children}
103
+ </Flex>
104
+
105
+ {end}
106
+ </PressArea>
107
+ </li>
108
+ )
109
+ }
110
+
111
+ function ListItemText<T extends ElementType = 'div'>(
112
+ props: ListItemTextProps<T> & Omit<ComponentPropsWithRef<T>, keyof ListItemTextProps<T>>,
113
+ ) {
114
+ const {as, className, style, title, subtitle, ...rest} = getProps(props, listItemTextProps)
115
+ const Component = as || 'div'
116
+
117
+ return (
118
+ <Flex
119
+ as={Component}
120
+ className={clsx(listItemTextClassName, className)}
121
+ style={style}
122
+ data-ui="ListItemText"
123
+ flexDirection="column"
124
+ justifyContent="center"
125
+ gap={2}
126
+ flexGrow={1}
127
+ {...rest}
128
+ >
129
+ {title && (
130
+ <Text size={1} weight="medium" trim truncate={1}>
131
+ {title}
132
+ </Text>
133
+ )}
134
+
135
+ {subtitle && (
136
+ <Text size={1} muted trim truncate={1}>
137
+ {subtitle}
138
+ </Text>
139
+ )}
140
+ </Flex>
141
+ )
142
+ }
143
+
144
+ function ListItemImage(props: ComponentProps<'img'>) {
145
+ const {className, style, ...rest} = getProps(props, {})
146
+
147
+ return (
148
+ <img
149
+ className={clsx(listItemImageClassName, 'sui-radius2', className)}
150
+ style={style}
151
+ data-ui="ListItemImage"
152
+ {...rest}
153
+ />
154
+ )
155
+ }
156
+
157
+ ListRoot.displayName = 'List'
158
+
159
+ /** @beta */
160
+ export const List = ListRoot
161
+
162
+ ListRoot.Item = ListItem
163
+ ListRoot.ButtonItem = ListButtonItem
164
+ ListRoot.ItemText = ListItemText
165
+ ListRoot.ItemImage = ListItemImage
166
+
167
+ export type {ListProps, ListItemProps, ListButtonItemProps, ListItemTextProps}
@@ -0,0 +1,25 @@
1
+ .sui-List {
2
+ list-style-type: none;
3
+ }
4
+
5
+ .sui-ListButtonItem:hover,
6
+ .sui-ListButtonItem:focus-visible {
7
+ background: var(--background-low);
8
+ }
9
+
10
+ .sui-ListButtonItem:focus-visible {
11
+ outline: var(--focus-outline);
12
+ outline-offset: var(--focus-offset);
13
+ }
14
+
15
+ .sui-ListButtonItem[data-selected] {
16
+ background: var(--active-background-emphasized);
17
+ color: var(--active-foreground-emphasized);
18
+ }
19
+
20
+ .sui-ListItemImage {
21
+ max-width: 42px;
22
+ aspect-ratio: var(--aspect-ratio, 1 / 1);
23
+ object-fit: cover;
24
+ flex-shrink: 0;
25
+ }
@@ -0,0 +1,130 @@
1
+ import type React from 'react'
2
+
3
+ import {type GapProps, gapProps} from '../../props/gap'
4
+ import {heightProps} from '../../props/height'
5
+ import {paddingProps} from '../../props/padding'
6
+ import {DENSITY, type Density} from '../../types/Density'
7
+ import type {InteractiveAs} from '../../types/Interactive'
8
+ import type {ListTag} from '../../types/List'
9
+ import {type PropDef} from '../../types/PropDef'
10
+ import type {Responsive} from '../../types/Responsive'
11
+
12
+ /** @beta */
13
+ export interface ListProps<T extends ListTag = 'ul'> extends Pick<GapProps, 'gap'> {
14
+ /**
15
+ * HTML element to render.
16
+ */
17
+ as?: T
18
+ }
19
+
20
+ export const listProps: Record<string, PropDef> = {
21
+ as: {
22
+ type: 'string',
23
+ },
24
+ gap: gapProps['gap'] as PropDef,
25
+ }
26
+
27
+ /** @beta */
28
+ export interface ListItemProps extends React.ComponentProps<'li'> {
29
+ /**
30
+ * Sets horizontal padding, gap, and minimum row height together.
31
+ */
32
+ density?: Responsive<Density>
33
+ /**
34
+ * Slot at the left edge of the row.
35
+ */
36
+ start?: React.ReactNode
37
+ /**
38
+ * Slot at the right edge of the row.
39
+ */
40
+ end?: React.ReactNode
41
+ }
42
+
43
+ export const listItemProps: Record<string, PropDef> = {
44
+ density: {
45
+ type: 'composite',
46
+ values: DENSITY,
47
+ composition: {
48
+ gap: {
49
+ propDef: gapProps['gap'] as PropDef,
50
+ mapping: {
51
+ compact: 2,
52
+ regular: 2,
53
+ loose: 3,
54
+ },
55
+ },
56
+ minHeight: {
57
+ propDef: heightProps['minHeight'] as PropDef,
58
+ mapping: {
59
+ compact: '33px',
60
+ regular: '37px',
61
+ loose: '45px',
62
+ },
63
+ },
64
+ paddingX: {
65
+ propDef: paddingProps['padding'] as PropDef,
66
+ mapping: {
67
+ compact: 1,
68
+ regular: 2,
69
+ loose: 3,
70
+ },
71
+ },
72
+ },
73
+ },
74
+ end: {
75
+ type: 'string',
76
+ },
77
+ start: {
78
+ type: 'string',
79
+ },
80
+ }
81
+
82
+ /** @beta */
83
+ export interface ListButtonItemProps<T extends React.ElementType = 'button'> extends ListItemProps {
84
+ /**
85
+ * Element or component to render for the press target.
86
+ */
87
+ as?: InteractiveAs<T>
88
+ /**
89
+ * Marks the row as the current selection.
90
+ */
91
+ selected?: boolean
92
+ }
93
+
94
+ export const listButtonItemProps: Record<string, PropDef> = {
95
+ as: {
96
+ type: 'string',
97
+ },
98
+ selected: {
99
+ type: 'boolean',
100
+ },
101
+ ...listItemProps,
102
+ }
103
+
104
+ /** @beta */
105
+ export interface ListItemTextProps<T extends React.ElementType = 'div'> {
106
+ /**
107
+ * HTML element to render.
108
+ */
109
+ as?: T
110
+ /**
111
+ * Main label.
112
+ */
113
+ title?: React.ReactNode
114
+ /**
115
+ * Text below the title.
116
+ */
117
+ subtitle?: React.ReactNode
118
+ }
119
+
120
+ export const listItemTextProps: Record<string, PropDef> = {
121
+ as: {
122
+ type: 'string',
123
+ },
124
+ title: {
125
+ type: 'string',
126
+ },
127
+ subtitle: {
128
+ type: 'string',
129
+ },
130
+ }
@@ -0,0 +1,85 @@
1
+ import clsx from 'clsx'
2
+ import {Activity, cloneElement, useId, useState, type ToggleEvent} from 'react'
3
+
4
+ import {useIsClient} from '../../hooks/useIsClient'
5
+ import {getProps} from '../../utils/getProps'
6
+ import {mergeTriggerProps} from '../../utils/mergeTriggerProps'
7
+ import {renderPortal} from '../../utils/renderPortal'
8
+ import {suffixClassName} from '../../utils/suffixClassName'
9
+ import {type PopoverProps, popoverProps} from './popover.props'
10
+
11
+ const popoverClassName = suffixClassName('sui-PopoverContent')
12
+
13
+ function PopoverRoot({
14
+ placement = 'bottom',
15
+ ...props
16
+ }: PopoverProps & {
17
+ triggerProps?: Record<string, unknown>
18
+ }) {
19
+ const {
20
+ children,
21
+ className,
22
+ style,
23
+ id: idProp,
24
+ anchorName,
25
+ content,
26
+ portal,
27
+ triggerProps: forwardedTriggerProps,
28
+ ...rest
29
+ } = getProps({placement, ...props}, popoverProps)
30
+ const reactId = useId()
31
+ const id = idProp || reactId
32
+ const [open, setOpen] = useState(false)
33
+ const isClient = useIsClient()
34
+
35
+ const handleToggle = (e: ToggleEvent) => {
36
+ setOpen(e.newState === 'open')
37
+ }
38
+
39
+ const triggerProps = {
40
+ popoverTarget: id,
41
+ style: {anchorName: `--anchor-${anchorName || id}`},
42
+ }
43
+
44
+ const trigger = children.type.forwardsTriggerProps
45
+ ? cloneElement(children, {triggerProps})
46
+ : cloneElement(children, mergeTriggerProps(children.props, forwardedTriggerProps, triggerProps))
47
+
48
+ return (
49
+ <>
50
+ {trigger}
51
+
52
+ {renderPortal(
53
+ <Activity mode={open ? 'visible' : 'hidden'}>
54
+ <div
55
+ className={clsx(
56
+ popoverClassName,
57
+ 'sui-px2 sui-py1 sui-radius2 sui-position-fixed sui-shadow2',
58
+ className,
59
+ )}
60
+ style={{
61
+ ...style,
62
+ positionAnchor: `--anchor-${anchorName || id}`,
63
+ }}
64
+ data-ui="Popover"
65
+ popover="auto"
66
+ id={id}
67
+ onToggle={handleToggle}
68
+ {...rest}
69
+ >
70
+ {content}
71
+ </div>
72
+ </Activity>,
73
+ isClient,
74
+ portal,
75
+ )}
76
+ </>
77
+ )
78
+ }
79
+
80
+ /** @beta */
81
+ export const Popover = Object.assign(PopoverRoot, {
82
+ forwardsTriggerProps: true,
83
+ })
84
+
85
+ export type {PopoverProps}
@@ -0,0 +1,21 @@
1
+ .sui-PopoverContent {
2
+ visibility: hidden;
3
+ opacity: 0;
4
+ scale: 0.9;
5
+ transition: none;
6
+ }
7
+
8
+ .sui-PopoverContent:popover-open {
9
+ visibility: visible;
10
+ opacity: 1;
11
+ scale: 1;
12
+ transition: var(--fade-in-transition);
13
+ }
14
+
15
+ @starting-style {
16
+ .sui-PopoverContent:popover-open {
17
+ visibility: hidden;
18
+ opacity: 0;
19
+ scale: 0.9;
20
+ }
21
+ }
@@ -0,0 +1,38 @@
1
+ import {type PlacementProps, placementProps} from '../../props/placement'
2
+ import {type PropDef} from '../../types/PropDef'
3
+
4
+ /** @beta */
5
+ export interface PopoverProps
6
+ extends Omit<React.ComponentProps<'div'>, 'children' | 'content'>, PlacementProps {
7
+ /**
8
+ * Shared anchor identifier.
9
+ * @remarks Set the same value on a Tooltip and a Popover to point both at one trigger.
10
+ */
11
+ anchorName?: React.ReactNode
12
+ /**
13
+ * The trigger element.
14
+ * @remarks Popover clones it and attaches the `popovertarget` attribute that opens the floating layer.
15
+ */
16
+ children: React.ReactElement<Record<string, unknown>>
17
+ /**
18
+ * The floating content.
19
+ */
20
+ content?: React.ReactNode
21
+ /**
22
+ * Renders the content into `document.body` through a React portal instead of inline.
23
+ */
24
+ portal?: boolean
25
+ }
26
+
27
+ export const popoverProps: Record<string, PropDef> = {
28
+ anchorName: {
29
+ type: 'string',
30
+ },
31
+ content: {
32
+ type: 'string',
33
+ },
34
+ portal: {
35
+ type: 'boolean',
36
+ },
37
+ ...placementProps,
38
+ }
@@ -0,0 +1,29 @@
1
+ import clsx from 'clsx'
2
+ import type {ComponentPropsWithRef, ElementType} from 'react'
3
+
4
+ import {getProps} from '../../utils/getProps'
5
+ import {suffixClassName} from '../../utils/suffixClassName'
6
+ import {type PressAreaProps, pressAreaProps} from './pressArea.props'
7
+
8
+ const pressAreaClassName = suffixClassName('sui-PressArea')
9
+
10
+ /** @public */
11
+ export function PressArea<T extends ElementType = 'button'>(
12
+ props: PressAreaProps<T> & Omit<ComponentPropsWithRef<T>, keyof PressAreaProps<T>>,
13
+ ) {
14
+ const {as, children, className, style, ...rest} = getProps(props, pressAreaProps)
15
+ const Component = as || 'button'
16
+
17
+ return (
18
+ <Component
19
+ className={clsx(pressAreaClassName, 'sui-width-full', className)}
20
+ style={style}
21
+ data-ui="PressArea"
22
+ {...rest}
23
+ >
24
+ {children}
25
+ </Component>
26
+ )
27
+ }
28
+
29
+ export type {PressAreaProps}
@@ -0,0 +1,22 @@
1
+ .sui-PressArea {
2
+ background: none;
3
+ font: inherit;
4
+ color: inherit;
5
+ text-align: inherit;
6
+ text-decoration: inherit;
7
+ appearance: none;
8
+ }
9
+
10
+ .sui-PressArea:focus-visible {
11
+ outline: var(--focus-outline);
12
+ outline-offset: var(--focus-offset);
13
+ }
14
+
15
+ .sui-PressArea:disabled {
16
+ pointer-events: none;
17
+ }
18
+
19
+ .sui-PressArea .sui-Text,
20
+ .sui-PressArea [data-sanity-icon] {
21
+ color: inherit;
22
+ }
@@ -0,0 +1,16 @@
1
+ import type {InteractiveAs} from '../../types/Interactive'
2
+ import {type PropDef} from '../../types/PropDef'
3
+
4
+ /** @public */
5
+ export interface PressAreaProps<T extends React.ElementType = 'button'> {
6
+ /**
7
+ * Element or component to render.
8
+ */
9
+ as?: InteractiveAs<T>
10
+ }
11
+
12
+ export const pressAreaProps: Record<string, PropDef> = {
13
+ as: {
14
+ type: 'string',
15
+ },
16
+ }
@@ -0,0 +1,48 @@
1
+ import clsx from 'clsx'
2
+
3
+ import {getProps} from '../../utils/getProps'
4
+ import {suffixClassName} from '../../utils/suffixClassName'
5
+ import {Box} from '../box/Box'
6
+ import {Label} from '../label/Label'
7
+ import {VisuallyHidden} from '../visually-hidden/VisuallyHidden'
8
+ import {type RadioProps, radioProps} from './radio.props'
9
+
10
+ const radioClassName = suffixClassName('sui-Radio')
11
+ const radioInputClassName = suffixClassName('sui-RadioInput')
12
+ const radioMarkClassName = suffixClassName('sui-RadioMark')
13
+
14
+ /** @beta */
15
+ export function Radio(props: RadioProps) {
16
+ const {className, style, label, disabled, error, ...rest} = getProps(props, radioProps)
17
+
18
+ return (
19
+ <Label
20
+ className={clsx(radioClassName, 'sui-position-relative', className)}
21
+ style={style}
22
+ data-ui="Radio"
23
+ disabled={disabled}
24
+ error={error}
25
+ >
26
+ <VisuallyHidden
27
+ as="input"
28
+ type="radio"
29
+ className={radioInputClassName}
30
+ disabled={disabled}
31
+ {...rest}
32
+ />
33
+
34
+ <Box
35
+ as="span"
36
+ className={clsx(radioMarkClassName, error && 'sui-error')}
37
+ position="relative"
38
+ radius="full"
39
+ width="17px"
40
+ height="17px"
41
+ />
42
+
43
+ {label}
44
+ </Label>
45
+ )
46
+ }
47
+
48
+ export type {RadioProps}