@sanity/ui 1.8.3 → 2.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 (137) hide show
  1. package/dist/index.cjs.mjs +3 -0
  2. package/dist/index.d.ts +339 -415
  3. package/dist/index.esm.js +5374 -2489
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +5375 -2487
  6. package/dist/index.js.map +1 -1
  7. package/package.json +21 -3
  8. package/src/components/autocomplete/autocomplete.tsx +2 -1
  9. package/src/components/dialog/constants.ts +4 -0
  10. package/src/components/dialog/dialog.tsx +89 -27
  11. package/src/components/dialog/styles.ts +3 -4
  12. package/src/components/hotkeys/hotkeys.tsx +2 -1
  13. package/src/components/menu/__workshop__/closableMenuButton.tsx +2 -2
  14. package/src/components/menu/menuButton.tsx +2 -2
  15. package/src/components/menu/menuDivider.ts +2 -1
  16. package/src/components/menu/menuGroup.tsx +24 -25
  17. package/src/components/menu/menuItem.tsx +31 -37
  18. package/src/components/skeleton/styles.ts +8 -7
  19. package/src/components/tab/tab.tsx +2 -1
  20. package/src/components/tree/style.ts +19 -20
  21. package/src/primitives/_selectable/style.ts +25 -23
  22. package/src/primitives/avatar/avatar.tsx +8 -3
  23. package/src/primitives/avatar/avatarCounter.tsx +5 -4
  24. package/src/primitives/avatar/spotColors.ts +53 -0
  25. package/src/primitives/avatar/styles.ts +6 -8
  26. package/src/primitives/avatar/types.ts +14 -0
  27. package/src/primitives/badge/badge.tsx +5 -3
  28. package/src/primitives/badge/styles.ts +7 -8
  29. package/src/primitives/box/__workshop__/responsive.tsx +2 -2
  30. package/src/primitives/button/__workshop__/sanityUploadButton.tsx +1 -2
  31. package/src/primitives/button/button.tsx +8 -9
  32. package/src/primitives/button/styles.ts +100 -17
  33. package/src/primitives/card/__workshop__/selected.tsx +8 -9
  34. package/src/primitives/card/card.tsx +43 -7
  35. package/src/primitives/card/styles.ts +31 -24
  36. package/src/primitives/card/types.ts +3 -1
  37. package/src/primitives/checkbox/checkbox.tsx +1 -0
  38. package/src/primitives/checkbox/styles.ts +53 -23
  39. package/src/primitives/code/code.tsx +15 -3
  40. package/src/primitives/code/styles.ts +51 -42
  41. package/src/primitives/heading/styles.ts +6 -5
  42. package/src/primitives/kbd/kbd.tsx +7 -6
  43. package/src/primitives/label/styles.ts +3 -2
  44. package/src/primitives/popover/popoverArrow.tsx +3 -2
  45. package/src/primitives/popover/popoverCard.tsx +8 -4
  46. package/src/primitives/radio/radio.tsx +1 -0
  47. package/src/primitives/radio/styles.ts +26 -13
  48. package/src/primitives/select/select.tsx +3 -2
  49. package/src/primitives/select/styles.ts +22 -24
  50. package/src/primitives/switch/__workshop__/props.tsx +4 -4
  51. package/src/primitives/switch/styles.ts +19 -12
  52. package/src/primitives/text/__workshop__/colored.tsx +10 -11
  53. package/src/primitives/text/styles.ts +10 -8
  54. package/src/primitives/textArea/textArea.tsx +8 -12
  55. package/src/primitives/textInput/textInput.tsx +15 -14
  56. package/src/primitives/tooltip/__workshop__/props.tsx +20 -3
  57. package/src/primitives/tooltip/tooltip.tsx +2 -2
  58. package/src/primitives/tooltip/tooltipArrow.tsx +3 -2
  59. package/src/primitives/types.ts +3 -2
  60. package/src/styles/border/borderStyle.ts +2 -1
  61. package/src/styles/colorVars/colorVarsStyle.ts +73 -30
  62. package/src/styles/focusRing/index.ts +8 -4
  63. package/src/styles/input/textInputStyle.ts +78 -94
  64. package/src/styles/margin/marginsStyle.test.ts +1 -2
  65. package/src/styles/padding/paddingStyle.test.ts +1 -2
  66. package/src/styles/radius/radiusStyle.ts +14 -4
  67. package/src/styles/radius/types.ts +3 -1
  68. package/src/styles/shadow/shadowStyle.ts +5 -5
  69. package/src/theme/__workshop__/color.tsx +2 -2
  70. package/src/theme/__workshop__/index.ts +0 -5
  71. package/src/theme/lib/color-fns/blend/multiply.ts +2 -2
  72. package/src/theme/lib/color-fns/blend/screen.ts +2 -2
  73. package/src/theme/lib/color-fns/convert.ts +15 -1
  74. package/src/theme/lib/color-fns/parse.ts +7 -3
  75. package/src/theme/lib/color-fns/types.ts +11 -0
  76. package/src/theme/lib/theme/avatar.ts +3 -0
  77. package/src/theme/lib/theme/color/_legacy/createColorTheme.ts +7 -0
  78. package/src/theme/lib/theme/color/_legacy/index.ts +1 -0
  79. package/src/theme/lib/theme/color/_legacy/legacyColor.ts +3997 -0
  80. package/src/theme/lib/theme/color/cssVariables/cardVariables.ts +88 -0
  81. package/src/theme/lib/theme/color/cssVariables/createCssVars.ts +31 -0
  82. package/src/theme/lib/theme/color/cssVariables/cssVars.test.ts +262 -0
  83. package/src/theme/lib/theme/color/cssVariables/index.ts +1 -0
  84. package/src/theme/lib/theme/color/cssVariables/tints.ts +312 -0
  85. package/src/theme/lib/theme/color/cssVariables/tones.ts +67 -0
  86. package/src/theme/lib/theme/color/cssVariables/utils.test.ts +15 -0
  87. package/src/theme/lib/theme/color/cssVariables/utils.ts +9 -0
  88. package/src/theme/lib/theme/color/index.ts +3 -12
  89. package/src/theme/lib/theme/color/types.ts +6 -37
  90. package/src/theme/lib/theme/input.ts +11 -0
  91. package/src/theme/lib/theme/theme.ts +7 -1
  92. package/src/theme/studioTheme/color.ts +6 -633
  93. package/src/theme/studioTheme/fonts.ts +3 -3
  94. package/src/theme/studioTheme/helpers.ts +15 -1
  95. package/src/theme/studioTheme/theme.ts +26 -6
  96. package/src/theme/themeColorProvider.tsx +2 -0
  97. package/src/theme/themeProvider.tsx +28 -8
  98. package/src/theme/toneContext/toneContext.ts +12 -0
  99. package/src/theme/toneContext/toneProvider.tsx +31 -0
  100. package/src/theme/toneContext/types.ts +10 -0
  101. package/src/theme/toneContext/useToneContext.tsx +26 -0
  102. package/src/theme/types.ts +10 -4
  103. package/src/types/index.ts +1 -0
  104. package/src/types/radius.ts +4 -0
  105. package/src/utils/elementQuery/__workshop__/customMedia.tsx +4 -3
  106. package/src/theme/__workshop__/canvas.tsx +0 -395
  107. package/src/theme/lib/theme/color/_generic/index.ts +0 -1
  108. package/src/theme/lib/theme/color/_generic/types.ts +0 -29
  109. package/src/theme/lib/theme/color/base/index.ts +0 -1
  110. package/src/theme/lib/theme/color/base/types.ts +0 -19
  111. package/src/theme/lib/theme/color/button/createButtonModes.ts +0 -20
  112. package/src/theme/lib/theme/color/button/createButtonTones.ts +0 -52
  113. package/src/theme/lib/theme/color/button/index.ts +0 -1
  114. package/src/theme/lib/theme/color/button/types.ts +0 -44
  115. package/src/theme/lib/theme/color/card/createCardStates.ts +0 -58
  116. package/src/theme/lib/theme/color/card/index.ts +0 -1
  117. package/src/theme/lib/theme/color/card/types.ts +0 -18
  118. package/src/theme/lib/theme/color/color.test.ts +0 -62
  119. package/src/theme/lib/theme/color/defaults.ts +0 -382
  120. package/src/theme/lib/theme/color/factory.ts +0 -138
  121. package/src/theme/lib/theme/color/input/createInputModes.ts +0 -84
  122. package/src/theme/lib/theme/color/input/index.ts +0 -1
  123. package/src/theme/lib/theme/color/input/types.ts +0 -27
  124. package/src/theme/lib/theme/color/muted/createMuted.ts +0 -56
  125. package/src/theme/lib/theme/color/muted/index.ts +0 -1
  126. package/src/theme/lib/theme/color/muted/types.ts +0 -24
  127. package/src/theme/lib/theme/color/selectable/createSelectableTones.ts +0 -73
  128. package/src/theme/lib/theme/color/selectable/index.ts +0 -1
  129. package/src/theme/lib/theme/color/selectable/types.ts +0 -29
  130. package/src/theme/lib/theme/color/solid/createSolidTones.ts +0 -56
  131. package/src/theme/lib/theme/color/solid/index.ts +0 -1
  132. package/src/theme/lib/theme/color/solid/types.ts +0 -24
  133. package/src/theme/lib/theme/color/spot/createSpot.ts +0 -21
  134. package/src/theme/lib/theme/color/spot/index.ts +0 -1
  135. package/src/theme/lib/theme/color/spot/types.ts +0 -28
  136. package/src/theme/lib/theme/color/syntax/index.ts +0 -1
  137. package/src/theme/lib/theme/color/syntax/types.ts +0 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "1.8.3",
3
+ "version": "2.0.0-alpha.10",
4
4
  "sideEffects": false,
5
5
  "types": "./dist/index.d.ts",
6
6
  "source": "./src/index.ts",
@@ -46,11 +46,13 @@
46
46
  "watch": "pkg watch --strict",
47
47
  "workshop:build": "node -r esbuild-register -r tsconfig-paths/register scripts/build",
48
48
  "workshop:dev": "node -r esbuild-register -r tsconfig-paths/register scripts/dev",
49
- "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist"
49
+ "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist",
50
+ "storybook": "storybook dev -p 6006",
51
+ "build-storybook": "storybook build"
50
52
  },
51
53
  "dependencies": {
52
54
  "@floating-ui/react-dom": "2.0.0",
53
- "@sanity/color": "^2.2.5",
55
+ "@sanity/color": "3.0.0-beta.5",
54
56
  "@sanity/icons": "^2.4.1",
55
57
  "csstype": "^3.1.2",
56
58
  "framer-motion": "^10.16.2",
@@ -67,6 +69,20 @@
67
69
  "@sanity/pkg-utils": "^2.4.8",
68
70
  "@sanity/semantic-release-preset": "^4.1.4",
69
71
  "@sanity/ui-workshop": "^1.2.11",
72
+ "@storybook/addon-a11y": "^7.4.5",
73
+ "@storybook/addon-docs": "^7.4.5",
74
+ "@storybook/addon-essentials": "^7.4.5",
75
+ "@storybook/addon-interactions": "^7.4.5",
76
+ "@storybook/addon-links": "^7.4.5",
77
+ "@storybook/addon-storysource": "^7.4.5",
78
+ "@storybook/addon-themes": "^7.4.5",
79
+ "@storybook/blocks": "^7.4.5",
80
+ "@storybook/jest": "^0.2.2",
81
+ "@storybook/manager-api": "^7.4.5",
82
+ "@storybook/react": "^7.4.5",
83
+ "@storybook/react-vite": "^7.4.5",
84
+ "@storybook/testing-library": "^0.2.1",
85
+ "@storybook/theming": "^7.4.5",
70
86
  "@testing-library/dom": "^9.3.1",
71
87
  "@testing-library/jest-dom": "^5.17.0",
72
88
  "@testing-library/react": "^14.0.0",
@@ -93,6 +109,7 @@
93
109
  "eslint-plugin-prettier": "^5.0.0",
94
110
  "eslint-plugin-react": "^7.33.2",
95
111
  "eslint-plugin-react-hooks": "^4.6.0",
112
+ "eslint-plugin-storybook": "^0.6.14",
96
113
  "http-server": "^14.1.1",
97
114
  "husky": "^8.0.3",
98
115
  "jest": "^29.6.4",
@@ -109,6 +126,7 @@
109
126
  "rimraf": "^5.0.1",
110
127
  "semantic-release": "^21.1.1",
111
128
  "start-server-and-test": "^2.0.0",
129
+ "storybook": "^7.4.5",
112
130
  "styled-components": "^6.0.7",
113
131
  "tsconfig-paths": "^4.2.0",
114
132
  "typescript": "^5.2.2"
@@ -31,6 +31,7 @@ import {
31
31
  Text,
32
32
  TextInput,
33
33
  } from '../../primitives'
34
+ import {Radius} from '../../types'
34
35
  import {AnimatedSpinnerIcon, ListBox, Root} from './autocomplete.styles'
35
36
  import {AutocompleteOption} from './autocompleteOption'
36
37
  import {autocompleteReducer} from './autocompleteReducer'
@@ -64,7 +65,7 @@ export interface AutocompleteProps<Option extends BaseAutocompleteOption = BaseA
64
65
  popover?: Omit<PopoverProps, 'content' | 'onMouseEnter' | 'onMouseLeave' | 'open'> &
65
66
  Omit<HTMLProps<HTMLDivElement>, 'as' | 'children' | 'content' | 'ref' | 'width'>
66
67
  prefix?: ReactNode
67
- radius?: number | number[]
68
+ radius?: Radius | Radius[]
68
69
  /** @beta */
69
70
  relatedElements?: HTMLElement[]
70
71
  renderOption?: (option: Option) => ReactElement
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Left/right border offsets for header + footer components (in px).
3
+ */
4
+ export const BORDER_OFFSET_X: number = 12
@@ -8,12 +8,13 @@ import {
8
8
  isHTMLElement,
9
9
  } from '../../helpers'
10
10
  import {useArrayProp, useClickOutside, useForwardedRef, useGlobalKeyDown} from '../../hooks'
11
- import {Box, Button, Card, Container, Flex, Text} from '../../primitives'
11
+ import {Box, Button, Card, CardProps, Container, Flex, Text} from '../../primitives'
12
12
  import {ResponsivePaddingProps, ResponsiveWidthProps} from '../../primitives/types'
13
13
  import {responsivePaddingStyle, ResponsivePaddingStyleProps} from '../../styles/internal'
14
- import {ThemeColorSchemeKey, useTheme} from '../../theme'
15
- import {DialogPosition} from '../../types'
14
+ import {ThemeColorSchemeKey, cssVars, useTheme} from '../../theme'
15
+ import {DialogPosition, Radius} from '../../types'
16
16
  import {Layer, LayerProps, Portal, useBoundaryElement, useLayer, usePortal} from '../../utils'
17
+ import {BORDER_OFFSET_X} from './constants'
17
18
  import {
18
19
  dialogStyle,
19
20
  responsiveDialogPositionStyle,
@@ -33,7 +34,7 @@ export interface DialogProps extends ResponsivePaddingProps, ResponsiveWidthProp
33
34
  * @beta
34
35
  */
35
36
  __unstable_hideCloseButton?: boolean
36
- cardRadius?: number | number[]
37
+ cardRadius?: Radius | Radius[]
37
38
  cardShadow?: number | number[]
38
39
  contentRef?: React.ForwardedRef<HTMLDivElement>
39
40
  footer?: React.ReactNode
@@ -66,11 +67,20 @@ interface DialogCardProps extends ResponsiveWidthProps {
66
67
  onClickOutside?: () => void
67
68
  onClose?: () => void
68
69
  portal?: string
69
- radius: number | number[]
70
+ radius: Radius | Radius[]
70
71
  scheme?: ThemeColorSchemeKey
71
72
  shadow: number | number[]
72
73
  }
73
74
 
75
+ interface DialogHeaderProps extends CardProps {
76
+ $hasScrolledFromTop: boolean
77
+ $isContentScrollable: boolean
78
+ }
79
+ interface DialogFooterProps extends CardProps {
80
+ $hasScrolledToBottom: boolean
81
+ $isContentScrollable: boolean
82
+ }
83
+
74
84
  function isTargetWithinScope(
75
85
  boundaryElement: HTMLElement | null,
76
86
  portalElement: HTMLElement | null,
@@ -118,7 +128,7 @@ const DialogLayout = styled(Flex)`
118
128
  width: 100%;
119
129
  `
120
130
 
121
- const DialogHeader = styled(Card)`
131
+ const DialogHeader = styled(Box)<DialogHeaderProps>`
122
132
  position: relative;
123
133
  z-index: 2;
124
134
 
@@ -126,10 +136,13 @@ const DialogHeader = styled(Card)`
126
136
  content: '';
127
137
  display: block;
128
138
  position: absolute;
129
- left: 0;
130
- right: 0;
139
+ left: ${BORDER_OFFSET_X}px;
140
+ right: ${BORDER_OFFSET_X}px;
131
141
  bottom: -1px;
132
- border-bottom: 1px solid var(--card-hairline-soft-color);
142
+ border-bottom: 1px solid ${cssVars.default['border-base']};
143
+ width: auto;
144
+ opacity: ${(props) => (props.$isContentScrollable && props.$hasScrolledFromTop ? 1 : 0)};
145
+ transition: opacity 200ms ease-in;
133
146
  }
134
147
  `
135
148
 
@@ -140,10 +153,22 @@ const DialogContent = styled(Box)`
140
153
  outline: none;
141
154
  `
142
155
 
143
- const DialogFooter = styled(Box)`
156
+ const DialogFooter = styled(Box)<DialogFooterProps>`
144
157
  position: relative;
145
158
  z-index: 3;
146
- border-top: 1px solid var(--card-hairline-soft-color);
159
+
160
+ &:before {
161
+ content: '';
162
+ display: block;
163
+ position: absolute;
164
+ left: ${BORDER_OFFSET_X}px;
165
+ right: ${BORDER_OFFSET_X}px;
166
+ top: -1px;
167
+ border-top: 1px solid ${cssVars.default['border-base']};
168
+ width: auto;
169
+ opacity: ${(props) => (props.$isContentScrollable && !props.$hasScrolledToBottom ? 1 : 0)};
170
+ transition: opacity 200ms ease-in;
171
+ }
147
172
  `
148
173
 
149
174
  const DialogCard = forwardRef(function DialogCard(
@@ -180,6 +205,9 @@ const DialogCard = forwardRef(function DialogCard(
180
205
  const labelId = `${id}_label`
181
206
  const showCloseButton = Boolean(onClose) && hideCloseButton === false
182
207
  const showHeader = Boolean(header) || showCloseButton
208
+ const [isContentScrollable, setIsContentScrollable] = useState(false)
209
+ const [hasScrolledFromTop, setHasScrolledFromTop] = useState(false)
210
+ const [hasScrolledToBottom, setHasScrolledToBottom] = useState(false)
183
211
 
184
212
  useEffect(() => {
185
213
  if (!autoFocus) return
@@ -248,41 +276,75 @@ const DialogCard = forwardRef(function DialogCard(
248
276
  [contentRef],
249
277
  )
250
278
 
279
+ const handleContentUpdate = useCallback(() => {
280
+ if (localContentRef.current) {
281
+ setIsContentScrollable(
282
+ localContentRef.current.clientHeight < localContentRef.current.scrollHeight,
283
+ )
284
+ setHasScrolledFromTop(localContentRef.current.scrollTop > 0)
285
+ setHasScrolledToBottom(
286
+ localContentRef.current.scrollTop >=
287
+ localContentRef.current.scrollHeight - localContentRef.current.clientHeight,
288
+ )
289
+ }
290
+ }, [])
291
+
292
+ useEffect(() => {
293
+ const resizeObserver = new ResizeObserver(handleContentUpdate)
294
+
295
+ if (localContentRef.current) {
296
+ resizeObserver.observe(localContentRef.current)
297
+ }
298
+
299
+ return () => {
300
+ resizeObserver.disconnect()
301
+ }
302
+ }, [contentRef, handleContentUpdate])
303
+
251
304
  return (
252
305
  <DialogContainer data-ui="DialogCard" width={width}>
253
306
  <DialogCardRoot radius={radius} ref={setRef} scheme={scheme} shadow={shadow}>
254
307
  <DialogLayout direction="column">
255
308
  {showHeader && (
256
- <DialogHeader>
257
- <Flex>
258
- <Box flex={1} padding={4}>
309
+ <DialogHeader
310
+ $isContentScrollable={isContentScrollable}
311
+ $hasScrolledFromTop={hasScrolledFromTop}
312
+ padding={3}
313
+ >
314
+ <Flex align="center">
315
+ <Box flex={1} padding={3}>
259
316
  {header && (
260
- <Text id={labelId} weight="semibold">
317
+ <Text id={labelId} size={1} weight="medium">
261
318
  {header}
262
319
  </Text>
263
320
  )}
264
321
  </Box>
265
322
  {showCloseButton && (
266
- <Box padding={2}>
267
- <Button
268
- aria-label="Close dialog"
269
- disabled={!onClose}
270
- icon={CloseIcon}
271
- mode="bleed"
272
- onClick={onClose}
273
- padding={3}
274
- />
275
- </Box>
323
+ <Button
324
+ aria-label="Close dialog"
325
+ disabled={!onClose}
326
+ icon={CloseIcon}
327
+ mode="bleed"
328
+ onClick={onClose}
329
+ padding={3}
330
+ />
276
331
  )}
277
332
  </Flex>
278
333
  </DialogHeader>
279
334
  )}
280
335
 
281
- <DialogContent flex={1} ref={setContentRef} tabIndex={-1}>
336
+ <DialogContent flex={1} ref={setContentRef} tabIndex={-1} onScroll={handleContentUpdate}>
282
337
  {children}
283
338
  </DialogContent>
284
339
 
285
- {footer && <DialogFooter>{footer}</DialogFooter>}
340
+ {footer && (
341
+ <DialogFooter
342
+ $isContentScrollable={isContentScrollable}
343
+ $hasScrolledToBottom={hasScrolledToBottom}
344
+ >
345
+ {footer}
346
+ </DialogFooter>
347
+ )}
286
348
  </DialogLayout>
287
349
  </DialogCardRoot>
288
350
  </DialogContainer>
@@ -1,4 +1,5 @@
1
1
  import {_responsive, ThemeProps} from '../../styles'
2
+ import {cssVars} from '../../theme'
2
3
  import {DialogPosition} from '../../types'
3
4
  import {CSSObject} from '../../types/styled'
4
5
 
@@ -9,9 +10,7 @@ export interface ResponsiveDialogPositionStyleProps {
9
10
  $position: DialogPosition[]
10
11
  }
11
12
 
12
- export function dialogStyle({theme}: ThemeProps): CSSObject {
13
- const color = theme.sanity.color.base
14
-
13
+ export function dialogStyle(): CSSObject {
15
14
  return {
16
15
  '&:not([hidden])': {
17
16
  display: 'flex',
@@ -24,7 +23,7 @@ export function dialogStyle({theme}: ThemeProps): CSSObject {
24
23
  alignItems: 'center',
25
24
  justifyContent: 'center',
26
25
  outline: 'none',
27
- background: color.shadow.umbra,
26
+ background: cssVars.default['base-shadow-umbra-color'],
28
27
  }
29
28
  }
30
29
 
@@ -2,6 +2,7 @@ import {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
3
  import {useArrayProp} from '../../hooks'
4
4
  import {Inline, KBD} from '../../primitives'
5
+ import {Radius} from '../../types'
5
6
 
6
7
  /**
7
8
  * @public
@@ -9,7 +10,7 @@ import {Inline, KBD} from '../../primitives'
9
10
  export interface HotkeysProps {
10
11
  fontSize?: number | number[]
11
12
  padding?: number | number[]
12
- radius?: number | number[]
13
+ radius?: Radius | Radius[]
13
14
  space?: number | number[]
14
15
  keys?: string[]
15
16
  }
@@ -1,5 +1,5 @@
1
1
  import {AddIcon} from '@sanity/icons'
2
- import {Box, Button, Menu, MenuButton, MenuButtonProps, MenuItem, Stack} from '@sanity/ui'
2
+ import {Box, Button, Menu, MenuButton, MenuButtonProps, MenuItem, Stack, cssVars} from '@sanity/ui'
3
3
  import {useRef} from 'react'
4
4
 
5
5
  const POPOVER_PROPS: MenuButtonProps['popover'] = {
@@ -23,7 +23,7 @@ export default function ClosableMenuButtonStory() {
23
23
  <MenuItem text="Item 3" />
24
24
  <MenuItem text="Item 4" />
25
25
  </Stack>
26
- <Stack padding={1} style={{borderTop: '1px solid var(--card-border-color)'}}>
26
+ <Stack padding={1} style={{borderTop: `1px solid ${cssVars.default['border-base']}`}}>
27
27
  <Button
28
28
  icon={AddIcon}
29
29
  onClick={() => {
@@ -2,7 +2,7 @@ import {cloneElement, forwardRef, useCallback, useMemo, useState, useEffect, use
2
2
  import {isElement} from 'react-is'
3
3
  import {Popover, PopoverProps} from '../../primitives'
4
4
  import {ThemeColorSchemeKey} from '../../theme'
5
- import {Placement} from '../../types'
5
+ import {Placement, Radius} from '../../types'
6
6
  import {MenuProps} from './menu'
7
7
 
8
8
  /**
@@ -34,7 +34,7 @@ export interface MenuButtonProps {
34
34
  /**
35
35
  * @deprecated Use `popover={{radius: 2}}` instead.
36
36
  */
37
- popoverRadius?: number | number[]
37
+ popoverRadius?: Radius | Radius[]
38
38
  /**
39
39
  * @beta Do not use in production.
40
40
  * @deprecated Use `popover={{portal: true}}` instead.
@@ -1,4 +1,5 @@
1
1
  import styled from 'styled-components'
2
+ import {cssVars} from '../../theme'
2
3
 
3
4
  /**
4
5
  * @public
@@ -6,6 +7,6 @@ import styled from 'styled-components'
6
7
  export const MenuDivider = styled.hr`
7
8
  height: 1px;
8
9
  border: 0;
9
- background: var(--card-hairline-soft-color);
10
+ background: ${cssVars.default['border-base']};
10
11
  margin: 0;
11
12
  `
@@ -4,7 +4,8 @@ import {isValidElementType} from 'react-is'
4
4
  import {useArrayProp} from '../../hooks'
5
5
  import {Box, Flex, Popover, PopoverProps, Text} from '../../primitives'
6
6
  import {Selectable} from '../../primitives/_selectable'
7
- import {SelectableTone} from '../../types/selectable'
7
+ import {useToneContext} from '../../theme/toneContext/useToneContext'
8
+ import {Radius, SelectableTone} from '../../types'
8
9
  import {Menu} from './menu'
9
10
  import {useMenu} from './useMenu'
10
11
 
@@ -17,7 +18,7 @@ export interface MenuGroupProps {
17
18
  icon?: React.ElementType | React.ReactNode
18
19
  padding?: number | number[]
19
20
  popover?: Omit<PopoverProps, 'content' | 'open'>
20
- radius?: number | number[]
21
+ radius?: Radius | Radius[]
21
22
  space?: number | number[]
22
23
  text: React.ReactNode
23
24
  tone?: SelectableTone
@@ -33,7 +34,7 @@ export function MenuGroup(
33
34
  const {
34
35
  as = 'button',
35
36
  children,
36
- fontSize,
37
+ fontSize = 1,
37
38
  icon,
38
39
  onClick,
39
40
  padding = 3,
@@ -44,6 +45,7 @@ export function MenuGroup(
44
45
  tone = 'default',
45
46
  ...restProps
46
47
  } = props
48
+ const {scheme} = useToneContext()
47
49
  const menu = useMenu()
48
50
  const {
49
51
  activeElement,
@@ -166,6 +168,7 @@ export function MenuGroup(
166
168
  data-selected={!withinMenu && active ? '' : undefined}
167
169
  $radius={useArrayProp(radius)}
168
170
  $tone={tone}
171
+ $scheme={scheme}
169
172
  onClick={handleClick}
170
173
  onKeyDown={handleKeyDown}
171
174
  onMouseEnter={handleMouseEnter}
@@ -173,28 +176,24 @@ export function MenuGroup(
173
176
  tabIndex={-1}
174
177
  type={as === 'button' ? 'button' : undefined}
175
178
  >
176
- <Box padding={padding}>
177
- <Flex>
178
- {icon && (
179
- <Text size={fontSize}>
180
- {isValidElement(icon) && icon}
181
- {isValidElementType(icon) && createElement(icon)}
182
- </Text>
183
- )}
184
-
185
- <Box flex={1} marginLeft={icon ? space : undefined}>
186
- <Text size={fontSize} textOverflow="ellipsis">
187
- {text}
188
- </Text>
189
- </Box>
190
-
191
- <Box marginLeft={space}>
192
- <Text size={fontSize}>
193
- <ChevronRightIcon />
194
- </Text>
195
- </Box>
196
- </Flex>
197
- </Box>
179
+ <Flex gap={space} padding={padding}>
180
+ {icon && (
181
+ <Text size={fontSize}>
182
+ {isValidElement(icon) && icon}
183
+ {isValidElementType(icon) && createElement(icon)}
184
+ </Text>
185
+ )}
186
+
187
+ <Box flex={1}>
188
+ <Text size={fontSize} textOverflow="ellipsis" weight="medium">
189
+ {text}
190
+ </Text>
191
+ </Box>
192
+
193
+ <Text size={fontSize}>
194
+ <ChevronRightIcon />
195
+ </Text>
196
+ </Flex>
198
197
  </Selectable>
199
198
  </Popover>
200
199
  )
@@ -12,7 +12,8 @@ import {useArrayProp, useForwardedRef} from '../../hooks'
12
12
  import {Box, Flex, Text} from '../../primitives'
13
13
  import {Selectable} from '../../primitives/_selectable'
14
14
  import {ResponsivePaddingProps, ResponsiveRadiusProps} from '../../primitives/types'
15
- import {SelectableTone} from '../../types/selectable'
15
+ import {ThemeColorToneKey} from '../../theme'
16
+ import {useToneContext} from '../../theme/toneContext/useToneContext'
16
17
  import {Hotkeys} from '../hotkeys'
17
18
  import {useMenu} from './useMenu'
18
19
 
@@ -29,7 +30,7 @@ export interface MenuItemProps extends ResponsivePaddingProps, ResponsiveRadiusP
29
30
  selected?: boolean
30
31
  space?: number | number[]
31
32
  text?: React.ReactNode
32
- tone?: SelectableTone
33
+ tone?: ThemeColorToneKey
33
34
  }
34
35
 
35
36
  /**
@@ -44,7 +45,7 @@ export const MenuItem = forwardRef(function MenuItem(
44
45
  as = 'button',
45
46
  children,
46
47
  disabled,
47
- fontSize = 2,
48
+ fontSize = 1,
48
49
  hotkeys,
49
50
  icon,
50
51
  iconRight,
@@ -64,6 +65,7 @@ export const MenuItem = forwardRef(function MenuItem(
64
65
  tone = 'default',
65
66
  ...restProps
66
67
  } = props
68
+ const {scheme} = useToneContext()
67
69
  const menu = useMenu()
68
70
  const {
69
71
  activeElement,
@@ -120,7 +122,8 @@ export const MenuItem = forwardRef(function MenuItem(
120
122
  forwardedAs={as}
121
123
  $radius={useArrayProp(radius)}
122
124
  $padding={useArrayProp(0)}
123
- $tone={tone}
125
+ $tone={disabled ? 'default' : tone}
126
+ $scheme={scheme}
124
127
  disabled={disabled}
125
128
  onClick={handleClick}
126
129
  onMouseEnter={onItemMouseEnter}
@@ -131,43 +134,34 @@ export const MenuItem = forwardRef(function MenuItem(
131
134
  type={as === 'button' ? 'button' : undefined}
132
135
  >
133
136
  {(icon || text || iconRight) && (
134
- <Box as="span" {...paddingProps}>
135
- <Flex as="span">
136
- {icon && (
137
- <Text size={fontSize}>
138
- {isValidElement(icon) && icon}
139
- {isValidElementType(icon) && createElement(icon)}
140
- </Text>
141
- )}
137
+ <Flex as="span" gap={space} align="center" {...paddingProps}>
138
+ {icon && (
139
+ <Text size={fontSize}>
140
+ {isValidElement(icon) && icon}
141
+ {isValidElementType(icon) && createElement(icon)}
142
+ </Text>
143
+ )}
142
144
 
143
- {text && (
144
- <Box
145
- flex={1}
146
- marginLeft={icon ? space : undefined}
147
- marginRight={iconRight ? space : undefined}
148
- >
149
- <Text size={fontSize} textOverflow="ellipsis">
150
- {text}
151
- </Text>
152
- </Box>
153
- )}
145
+ {text && (
146
+ <Box flex={1}>
147
+ <Text size={fontSize} textOverflow="ellipsis" weight="medium">
148
+ {text}
149
+ </Text>
150
+ </Box>
151
+ )}
154
152
 
155
- {hotkeys && (
156
- <Box marginLeft={space} style={{marginTop: -4, marginBottom: -4}}>
157
- <Hotkeys fontSize={fontSize} keys={hotkeys} />
158
- </Box>
159
- )}
153
+ {hotkeys && (
154
+ <Hotkeys fontSize={fontSize} keys={hotkeys} style={{marginTop: -4, marginBottom: -4}} />
155
+ )}
160
156
 
161
- {iconRight && (
162
- <Text size={fontSize}>
163
- {isValidElement(iconRight) && iconRight}
164
- {isValidElementType(iconRight) && createElement(iconRight)}
165
- </Text>
166
- )}
167
- </Flex>
168
- </Box>
157
+ {iconRight && (
158
+ <Text size={fontSize}>
159
+ {isValidElement(iconRight) && iconRight}
160
+ {isValidElementType(iconRight) && createElement(iconRight)}
161
+ </Text>
162
+ )}
163
+ </Flex>
169
164
  )}
170
-
171
165
  {children && (
172
166
  <Box as="span" {...paddingProps}>
173
167
  {children}
@@ -1,4 +1,5 @@
1
1
  import {css, keyframes} from 'styled-components'
2
+ import {cssVars} from '../../theme'
2
3
 
3
4
  const keyframe = keyframes`
4
5
  0% {
@@ -12,11 +13,11 @@ const keyframe = keyframes`
12
13
  const animation = css`
13
14
  background-image: linear-gradient(
14
15
  to right,
15
- var(--card-skeleton-color-from),
16
- var(--card-skeleton-color-to),
17
- var(--card-skeleton-color-from),
18
- var(--card-skeleton-color-from),
19
- var(--card-skeleton-color-from)
16
+ ${cssVars.default['skeleton-from']},
17
+ ${cssVars.default['skeleton-to']},
18
+ ${cssVars.default['skeleton-from']},
19
+ ${cssVars.default['skeleton-from']},
20
+ ${cssVars.default['skeleton-from']}
20
21
  );
21
22
  background-position: 100%;
22
23
  background-size: 200% 100%;
@@ -40,11 +41,11 @@ export const skeletonStyle = css<{$animated: boolean; $visible: boolean}>`
40
41
  $animated
41
42
  ? animation
42
43
  : css`
43
- background-color: var(--card-skeleton-color-from);
44
+ background-color: ${cssVars.default['skeleton-from']};
44
45
  `}
45
46
  }
46
47
 
47
48
  @media screen and (prefers-reduced-motion: reduce) {
48
- background-color: var(--card-skeleton-color-from);
49
+ background-color: ${cssVars.default['skeleton-from']};
49
50
  }
50
51
  `
@@ -38,7 +38,7 @@ export const Tab = forwardRef(function Tab(
38
38
  icon,
39
39
  id,
40
40
  focused,
41
- fontSize,
41
+ fontSize = 1,
42
42
  label,
43
43
  onClick,
44
44
  onFocus,
@@ -88,6 +88,7 @@ export const Tab = forwardRef(function Tab(
88
88
  onBlur={handleBlur}
89
89
  onFocus={handleFocus}
90
90
  padding={padding}
91
+ radius="full"
91
92
  ref={setRef}
92
93
  role="tab"
93
94
  selected={selected}