@sanity/ui 2.3.6 → 2.3.7-canary.0

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 (53) hide show
  1. package/dist/index.compiled.mjs +7488 -0
  2. package/dist/index.compiled.mjs.map +1 -0
  3. package/dist/index.d.mts +13 -1
  4. package/dist/index.d.ts +13 -1
  5. package/dist/index.esm.js +1047 -1072
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +1054 -1079
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +1047 -1072
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +31 -35
  12. package/src/core/components/autocomplete/autocomplete.tsx +31 -34
  13. package/src/core/components/breadcrumbs/breadcrumbs.tsx +3 -2
  14. package/src/core/components/dialog/dialog.tsx +23 -12
  15. package/src/core/components/hotkeys/hotkeys.tsx +3 -3
  16. package/src/core/components/menu/menu.tsx +5 -1
  17. package/src/core/components/menu/menuButton.tsx +17 -32
  18. package/src/core/components/menu/menuGroup.tsx +7 -5
  19. package/src/core/components/menu/menuItem.tsx +10 -6
  20. package/src/core/components/skeleton/skeleton.tsx +5 -11
  21. package/src/core/components/skeleton/textSkeleton.tsx +6 -7
  22. package/src/core/components/toast/toastProvider.tsx +26 -24
  23. package/src/core/components/tree/treeItem.styles.ts +21 -0
  24. package/src/core/components/tree/treeItem.tsx +31 -44
  25. package/src/core/hooks/useArrayProp.ts +11 -10
  26. package/src/core/primitives/avatar/avatar.tsx +11 -15
  27. package/src/core/primitives/avatar/avatarCounter.tsx +11 -17
  28. package/src/core/primitives/avatar/avatarStack.tsx +3 -7
  29. package/src/core/primitives/badge/badge.tsx +7 -4
  30. package/src/core/primitives/box/box.tsx +53 -27
  31. package/src/core/primitives/button/button.tsx +11 -12
  32. package/src/core/primitives/card/card.tsx +17 -9
  33. package/src/core/primitives/code/code.tsx +4 -3
  34. package/src/core/primitives/container/container.tsx +4 -11
  35. package/src/core/primitives/flex/flex.tsx +13 -7
  36. package/src/core/primitives/grid/grid.tsx +19 -10
  37. package/src/core/primitives/heading/heading.tsx +7 -4
  38. package/src/core/primitives/inline/inline.tsx +3 -2
  39. package/src/core/primitives/kbd/kbd.tsx +4 -3
  40. package/src/core/primitives/label/label.tsx +7 -4
  41. package/src/core/primitives/popover/popover.tsx +49 -49
  42. package/src/core/primitives/select/select.tsx +12 -6
  43. package/src/core/primitives/stack/stack.tsx +4 -3
  44. package/src/core/primitives/text/text.tsx +7 -4
  45. package/src/core/primitives/textArea/textArea.tsx +12 -6
  46. package/src/core/primitives/textInput/textInput.tsx +6 -5
  47. package/src/core/primitives/tooltip/tooltip.tsx +14 -7
  48. package/src/core/theme/themeProvider.tsx +4 -6
  49. package/src/core/utils/elementQuery/elementQuery.tsx +4 -3
  50. package/src/core/utils/layer/getLayerContext.test.ts +0 -4
  51. package/src/core/utils/layer/layer.test.tsx +0 -2
  52. package/src/core/utils/layer/layerProvider.tsx +35 -43
  53. package/src/core/utils/layer/types.ts +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "2.3.6",
3
+ "version": "2.3.7-canary.0",
4
4
  "keywords": [
5
5
  "sanity",
6
6
  "ui",
@@ -23,6 +23,10 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "source": "./exports/index.ts",
26
+ "react-compiler": {
27
+ "source": "./exports/index.ts",
28
+ "default": "./dist/index.compiled.mjs"
29
+ },
26
30
  "import": "./dist/index.mjs",
27
31
  "require": "./dist/index.js",
28
32
  "default": "./dist/index.js"
@@ -51,32 +55,6 @@
51
55
  "src",
52
56
  "theme.js"
53
57
  ],
54
- "scripts": {
55
- "build": "run-s clean pkg:build pkg:check figma:pkg:build",
56
- "clean": "rimraf .workshop dist",
57
- "commit": "cz",
58
- "cypress:dev": "run-p dev cypress:open",
59
- "cypress:open": "cypress open",
60
- "cypress:run": "cypress run",
61
- "dev": "run-p storybook:dev workshop:dev",
62
- "figma:pkg:build": "cd figma && pnpm build",
63
- "format": "prettier --write --cache --ignore-unknown .",
64
- "lint": "eslint . --ext .cjs,.js,.jsx,.mjs,.ts,.tsx",
65
- "pkg:build": "pkg build --strict",
66
- "pkg:check": "pkg --strict",
67
- "prepare": "husky install",
68
- "prepublishOnly": "pnpm build",
69
- "release": "semantic-release",
70
- "storybook:build": "storybook build",
71
- "storybook:dev": "storybook dev -p 6006",
72
- "test": "jest",
73
- "test:browser": "start-server-and-test 'run-s workshop:build workshop:start' http://localhost:1337 'run-s cypress:run'",
74
- "ts:check": "tsc",
75
- "watch": "pkg watch --strict",
76
- "workshop:build": "workshop build",
77
- "workshop:dev": "workshop dev",
78
- "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist"
79
- },
80
58
  "commitlint": {
81
59
  "extends": [
82
60
  "@commitlint/config-conventional"
@@ -106,7 +84,7 @@
106
84
  "dependencies": {
107
85
  "@floating-ui/react-dom": "^2.1.0",
108
86
  "@sanity/color": "^3.0.6",
109
- "@sanity/icons": "^3.2.0",
87
+ "@sanity/icons": "3.2.1-canary.0",
110
88
  "csstype": "^3.1.3",
111
89
  "framer-motion": "11.0.8",
112
90
  "react-refractor": "^2.2.0"
@@ -119,7 +97,7 @@
119
97
  "@commitlint/cli": "^19.3.0",
120
98
  "@commitlint/config-conventional": "^19.2.2",
121
99
  "@juggle/resize-observer": "^3.4.0",
122
- "@sanity/pkg-utils": "^6.9.3",
100
+ "@sanity/pkg-utils": "6.9.4-canary.1",
123
101
  "@sanity/semantic-release-preset": "^4.1.8",
124
102
  "@sanity/ui-workshop": "^2.0.15",
125
103
  "@storybook/addon-a11y": "^8.0.8",
@@ -193,7 +171,6 @@
193
171
  "react-is": "^18",
194
172
  "styled-components": "^5.2 || ^6"
195
173
  },
196
- "packageManager": "pnpm@9.2.0",
197
174
  "engines": {
198
175
  "node": ">=14.0.0"
199
176
  },
@@ -203,9 +180,28 @@
203
180
  "esm.sh": {
204
181
  "bundle": false
205
182
  },
206
- "pnpm": {
207
- "overrides": {
208
- "conventional-changelog-conventionalcommits": ">= 8.0.0"
209
- }
183
+ "scripts": {
184
+ "build": "run-s clean pkg:build pkg:check figma:pkg:build",
185
+ "clean": "rimraf .workshop dist",
186
+ "commit": "cz",
187
+ "cypress:dev": "run-p dev cypress:open",
188
+ "cypress:open": "cypress open",
189
+ "cypress:run": "cypress run",
190
+ "dev": "run-p storybook:dev workshop:dev",
191
+ "figma:pkg:build": "cd figma && pnpm build",
192
+ "format": "prettier --write --cache --ignore-unknown .",
193
+ "lint": "eslint . --ext .cjs,.js,.jsx,.mjs,.ts,.tsx",
194
+ "pkg:build": "pkg build --strict",
195
+ "pkg:check": "pkg --strict",
196
+ "release": "semantic-release",
197
+ "storybook:build": "storybook build",
198
+ "storybook:dev": "storybook dev -p 6006",
199
+ "test": "jest",
200
+ "test:browser": "start-server-and-test 'run-s workshop:build workshop:start' http://localhost:1337 'run-s cypress:run'",
201
+ "ts:check": "tsc",
202
+ "watch": "pkg watch --strict",
203
+ "workshop:build": "workshop build",
204
+ "workshop:dev": "workshop dev",
205
+ "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist"
210
206
  }
211
- }
207
+ }
@@ -20,7 +20,6 @@ import {
20
20
  } from 'react'
21
21
  import {EMPTY_ARRAY, EMPTY_RECORD} from '../../constants'
22
22
  import {_hasFocus, _raf, focusFirstDescendant} from '../../helpers'
23
- import {useArrayProp} from '../../hooks'
24
23
  import {
25
24
  Box,
26
25
  BoxProps,
@@ -32,6 +31,7 @@ import {
32
31
  Text,
33
32
  TextInput,
34
33
  } from '../../primitives'
34
+ import {_getArrayProp} from '../../styles'
35
35
  import {Radius} from '../../types'
36
36
  import {AnimatedSpinnerIcon, ListBox, Root} from './autocomplete.styles'
37
37
  import {AutocompleteOption} from './autocompleteOption'
@@ -200,7 +200,7 @@ const InnerAutocomplete = forwardRef(function InnerAutocomplete<
200
200
 
201
201
  const listBoxId = `${id}-listbox`
202
202
  const options = Array.isArray(optionsProp) ? optionsProp : EMPTY_ARRAY
203
- const padding = useArrayProp(paddingProp)
203
+ const padding = _getArrayProp(paddingProp)
204
204
  const currentOption = useMemo(
205
205
  () => (value !== null ? options.find((o) => o.value === value) : undefined),
206
206
  [options, value],
@@ -213,44 +213,41 @@ const InnerAutocomplete = forwardRef(function InnerAutocomplete<
213
213
  const activeItemId = activeValue ? `${id}-option-${activeValue}` : undefined
214
214
  const expanded = (query !== null && loading) || (focused && query !== null)
215
215
 
216
- const handleRootBlur = useCallback(
217
- (event: FocusEvent<HTMLInputElement>) => {
218
- setTimeout(() => {
219
- // NOTE: This is a workaround for a bug that may happen in Chrome (clicking the scrollbar
220
- // closes the results in certain situations):
221
- // - Do not handle blur if the mouse is within the popover
222
- if (popoverMouseWithinRef.current) {
223
- return
224
- }
216
+ const handleRootBlur = (event: FocusEvent<HTMLInputElement>) => {
217
+ setTimeout(() => {
218
+ // NOTE: This is a workaround for a bug that may happen in Chrome (clicking the scrollbar
219
+ // closes the results in certain situations):
220
+ // - Do not handle blur if the mouse is within the popover
221
+ if (popoverMouseWithinRef.current) {
222
+ return
223
+ }
225
224
 
226
- const elements: HTMLElement[] = (relatedElements || []).concat(
227
- rootElementRef.current ? [rootElementRef.current] : [],
228
- resultsPopoverElementRef.current ? [resultsPopoverElementRef.current] : [],
229
- )
225
+ const elements: HTMLElement[] = (relatedElements || []).concat(
226
+ rootElementRef.current ? [rootElementRef.current] : [],
227
+ resultsPopoverElementRef.current ? [resultsPopoverElementRef.current] : [],
228
+ )
230
229
 
231
- let focusInside = false
230
+ let focusInside = false
232
231
 
233
- if (document.activeElement) {
234
- for (const e of elements) {
235
- if (e === document.activeElement || e.contains(document.activeElement)) {
236
- focusInside = true
237
- break
238
- }
232
+ if (document.activeElement) {
233
+ for (const e of elements) {
234
+ if (e === document.activeElement || e.contains(document.activeElement)) {
235
+ focusInside = true
236
+ break
239
237
  }
240
238
  }
239
+ }
241
240
 
242
- if (focusInside === false) {
243
- dispatch({type: 'root/blur'})
244
- popoverMouseWithinRef.current = false
245
- if (onQueryChange) onQueryChange(null)
246
- if (onBlur) onBlur(event)
247
- }
248
- }, 0)
249
- },
250
- [onBlur, onQueryChange, relatedElements],
251
- )
241
+ if (focusInside === false) {
242
+ dispatch({type: 'root/blur'})
243
+ popoverMouseWithinRef.current = false
244
+ if (onQueryChange) onQueryChange(null)
245
+ if (onBlur) onBlur(event)
246
+ }
247
+ }, 0)
248
+ }
252
249
 
253
- const handleRootFocus = useCallback((event: FocusEvent<HTMLDivElement>) => {
250
+ const handleRootFocus = (event: FocusEvent<HTMLDivElement>) => {
254
251
  const listBoxElement = listBoxElementRef.current
255
252
  const focusedElement = event.target instanceof HTMLElement ? event.target : null
256
253
  const listFocused = listBoxElement?.contains(focusedElement) || false
@@ -260,7 +257,7 @@ const InnerAutocomplete = forwardRef(function InnerAutocomplete<
260
257
 
261
258
  dispatch({type: 'root/setListFocused', listFocused})
262
259
  }
263
- }, [])
260
+ }
264
261
 
265
262
  const handleOptionSelect = useCallback(
266
263
  (v: string) => {
@@ -1,6 +1,7 @@
1
1
  import {Children, forwardRef, Fragment, isValidElement, useCallback, useMemo, useState} from 'react'
2
- import {useArrayProp, useClickOutside} from '../../hooks'
2
+ import {useClickOutside} from '../../hooks'
3
3
  import {Box, Popover, Stack, Text} from '../../primitives'
4
+ import {_getArrayProp} from '../../styles'
4
5
  import {ExpandButton, Root} from './breadcrumbs.styles'
5
6
 
6
7
  /**
@@ -20,7 +21,7 @@ export const Breadcrumbs = forwardRef(function Breadcrumbs(
20
21
  ref: React.ForwardedRef<HTMLOListElement>,
21
22
  ) {
22
23
  const {children, maxLength, separator, space: spaceRaw = 2, ...restProps} = props
23
- const space = useArrayProp(spaceRaw)
24
+ const space = useMemo(() => _getArrayProp(spaceRaw), [spaceRaw])
24
25
  const [open, setOpen] = useState(false)
25
26
  const [expandElement, setExpandElement] = useState<HTMLButtonElement | null>(null)
26
27
  const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)
@@ -1,6 +1,14 @@
1
1
  import {CloseIcon} from '@sanity/icons'
2
2
  import {ThemeColorSchemeKey} from '@sanity/ui/theme'
3
- import {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'
3
+ import {
4
+ forwardRef,
5
+ useCallback,
6
+ useEffect,
7
+ useImperativeHandle,
8
+ useMemo,
9
+ useRef,
10
+ useState,
11
+ } from 'react'
4
12
  import {styled} from 'styled-components'
5
13
  import {
6
14
  containsOrEqualsElement,
@@ -8,9 +16,10 @@ import {
8
16
  focusLastDescendant,
9
17
  isHTMLElement,
10
18
  } from '../../helpers'
11
- import {useArrayProp, useClickOutside, useGlobalKeyDown, usePrefersReducedMotion} from '../../hooks'
19
+ import {useClickOutside, useGlobalKeyDown, usePrefersReducedMotion} from '../../hooks'
12
20
  import {Box, Button, Card, Container, Flex, Text} from '../../primitives'
13
21
  import {ResponsivePaddingProps, ResponsiveWidthProps} from '../../primitives/types'
22
+ import {_getArrayProp} from '../../styles'
14
23
  import {responsivePaddingStyle, ResponsivePaddingStyleProps} from '../../styles/internal'
15
24
  import {useTheme_v2} from '../../theme'
16
25
  import {DialogPosition, Radius} from '../../types'
@@ -166,9 +175,9 @@ const DialogCard = forwardRef(function DialogCard(
166
175
  const portal = usePortal()
167
176
  const portalElement = portalProp ? portal.elements?.[portalProp] || null : portal.element
168
177
  const boundaryElement = useBoundaryElement().element
169
- const radius = useArrayProp(radiusProp)
170
- const shadow = useArrayProp(shadowProp)
171
- const width = useArrayProp(widthProp)
178
+ const radius = useMemo(() => _getArrayProp(radiusProp), [radiusProp])
179
+ const shadow = useMemo(() => _getArrayProp(shadowProp), [shadowProp])
180
+ const width = useMemo(() => _getArrayProp(widthProp), [widthProp])
172
181
  const ref = useRef<HTMLDivElement | null>(null)
173
182
  const [rootElement, setRootElement] = useState<HTMLDivElement | null>(null)
174
183
  const contentRef = useRef<HTMLDivElement | null>(null)
@@ -307,23 +316,25 @@ export const Dialog = forwardRef(function Dialog(
307
316
  onFocus,
308
317
  padding: paddingProp = 3,
309
318
  portal: portalProp,
310
- position: positionProp = dialog.position || 'fixed',
319
+ position: _position,
311
320
  scheme,
312
321
  width: widthProp = 0,
313
- zOffset: zOffsetProp = dialog.zOffset || layer.dialog.zOffset,
322
+ zOffset: _zOffset,
314
323
  animate: _animate = false,
315
324
  ...restProps
316
325
  } = props
326
+ const positionProp = _position ?? (dialog.position || 'fixed')
327
+ const zOffsetProp = _zOffset ?? (dialog.zOffset || layer.dialog.zOffset)
317
328
  const prefersReducedMotion = usePrefersReducedMotion()
318
329
  const animate = prefersReducedMotion ? false : _animate
319
330
  const portal = usePortal()
320
331
  const portalElement = portalProp ? portal.elements?.[portalProp] || null : portal.element
321
332
  const boundaryElement = useBoundaryElement().element
322
- const cardRadius = useArrayProp(cardRadiusProp)
323
- const padding = useArrayProp(paddingProp)
324
- const position = useArrayProp(positionProp)
325
- const width = useArrayProp(widthProp)
326
- const zOffset = useArrayProp(zOffsetProp)
333
+ const cardRadius = useMemo(() => _getArrayProp(cardRadiusProp), [cardRadiusProp])
334
+ const padding = useMemo(() => _getArrayProp(paddingProp), [paddingProp])
335
+ const position = useMemo(() => _getArrayProp(positionProp), [positionProp])
336
+ const width = useMemo(() => _getArrayProp(widthProp), [widthProp])
337
+ const zOffset = useMemo(() => _getArrayProp(zOffsetProp), [zOffsetProp])
327
338
  const preDivRef = useRef<HTMLDivElement | null>(null)
328
339
  const postDivRef = useRef<HTMLDivElement | null>(null)
329
340
  const cardRef = useRef<HTMLDivElement | null>(null)
@@ -1,7 +1,7 @@
1
- import {forwardRef} from 'react'
1
+ import {forwardRef, useMemo} from 'react'
2
2
  import {styled} from 'styled-components'
3
- import {useArrayProp} from '../../hooks'
4
3
  import {Inline, KBD} from '../../primitives'
4
+ import {_getArrayProp} from '../../styles'
5
5
  import {Radius} from '../../types'
6
6
 
7
7
  /**
@@ -40,7 +40,7 @@ export const Hotkeys = forwardRef(function Hotkeys(
40
40
  ref: React.Ref<HTMLElement>,
41
41
  ) {
42
42
  const {fontSize, keys, padding, radius, space: spaceProp = 0.5, ...restProps} = props
43
- const space = useArrayProp(spaceProp)
43
+ const space = useMemo(() => _getArrayProp(spaceProp), [spaceProp])
44
44
 
45
45
  if (!keys || keys.length === 0) {
46
46
  return <></>
@@ -11,6 +11,7 @@ import {useMenuController} from './useMenuController'
11
11
  * @public
12
12
  */
13
13
  export interface MenuProps extends ResponsivePaddingProps {
14
+ 'aria-labelledby'?: string
14
15
  /**
15
16
  * @deprecated Use `shouldFocus="first"` instead.
16
17
  */
@@ -20,6 +21,7 @@ export interface MenuProps extends ResponsivePaddingProps {
20
21
  */
21
22
  focusLast?: boolean
22
23
  onClickOutside?: (event: MouseEvent) => void
24
+ onBlurCapture?: (event: React.FocusEvent<HTMLButtonElement>) => void
23
25
  onEscape?: () => void
24
26
  onItemClick?: () => void
25
27
  onItemSelect?: (index: number) => void
@@ -57,10 +59,12 @@ export const Menu = forwardRef(function Menu(
57
59
  originElement,
58
60
  padding = 1,
59
61
  registerElement,
60
- shouldFocus = (props.focusFirst && 'first') || (props.focusLast && 'last') || null,
62
+ shouldFocus: _shouldFocus,
61
63
  space = 1,
62
64
  ...restProps
63
65
  } = props
66
+ const shouldFocus =
67
+ _shouldFocus ?? ((props.focusFirst && 'first') || (props.focusLast && 'last') || null)
64
68
 
65
69
  const ref = useRef<HTMLDivElement | null>(null)
66
70
 
@@ -203,8 +203,9 @@ export const MenuButton = forwardRef(function MenuButton(
203
203
  }
204
204
  }, [])
205
205
 
206
- const menuProps: MenuProps = useMemo(
207
- () => ({
206
+ const menu =
207
+ menuProp &&
208
+ cloneElement<MenuProps>(menuProp, {
208
209
  'aria-labelledby': id,
209
210
  onBlurCapture: handleBlur,
210
211
  onClickOutside: handleMenuClickOutside,
@@ -213,22 +214,8 @@ export const MenuButton = forwardRef(function MenuButton(
213
214
  originElement: buttonElement,
214
215
  registerElement,
215
216
  shouldFocus,
216
- }),
217
- [
218
- buttonElement,
219
- handleMenuClickOutside,
220
- handleMenuEscape,
221
- handleItemClick,
222
- id,
223
- handleBlur,
224
- registerElement,
225
- shouldFocus,
226
- ],
227
- )
228
-
229
- const menu = menuProp && cloneElement(menuProp, menuProps)
217
+ })
230
218
 
231
- const ref = useRef<HTMLButtonElement | null>(null)
232
219
  const button = useMemo(
233
220
  () =>
234
221
  buttonProp &&
@@ -240,7 +227,7 @@ export const MenuButton = forwardRef(function MenuButton(
240
227
  onMouseDown: handleMouseDown,
241
228
  'aria-haspopup': true,
242
229
  'aria-expanded': open,
243
- ref: ref,
230
+ ref: setButtonElement,
244
231
  selected: buttonProp.props.selected ?? open,
245
232
  }),
246
233
  [buttonProp, handleButtonClick, handleButtonKeyDown, handleMouseDown, id, open],
@@ -249,19 +236,10 @@ export const MenuButton = forwardRef(function MenuButton(
249
236
  // Forward button ref to parent
250
237
  useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(
251
238
  forwardedRef,
252
- () => ref.current,
239
+ () => buttonElement,
240
+ [buttonElement],
253
241
  )
254
242
 
255
- // If there's a button then we need to set the reference element to the cloned button ref
256
- // and if button changes we make sure to update or remove the reference element.
257
- useEffect(() => {
258
- if (!button) return undefined
259
-
260
- setButtonElement(ref.current)
261
-
262
- return () => setButtonElement(null)
263
- }, [button])
264
-
265
243
  const popoverProps: MenuButtonProps['popover'] = useMemo(
266
244
  () => ({
267
245
  boundaryElement: deprecated_boundaryElement,
@@ -285,8 +263,15 @@ export const MenuButton = forwardRef(function MenuButton(
285
263
  )
286
264
 
287
265
  return (
288
- <Popover data-ui="MenuButton__popover" {...popoverProps} content={menu} open={open}>
289
- {button || <></>}
290
- </Popover>
266
+ <>
267
+ <Popover
268
+ data-ui="MenuButton__popover"
269
+ referenceElement={buttonElement}
270
+ {...popoverProps}
271
+ content={menu}
272
+ open={open}
273
+ />
274
+ {button}
275
+ </>
291
276
  )
292
277
  })
@@ -1,9 +1,9 @@
1
1
  import {ChevronRightIcon} from '@sanity/icons'
2
- import {isValidElement, useCallback, useEffect, useRef, useState} from 'react'
2
+ import {isValidElement, useCallback, useEffect, useMemo, useRef, useState} from 'react'
3
3
  import {isValidElementType} from 'react-is'
4
- import {useArrayProp} from '../../hooks'
5
4
  import {Box, Flex, Popover, PopoverProps, Text} from '../../primitives'
6
5
  import {Selectable} from '../../primitives/_selectable'
6
+ import {_getArrayProp} from '../../styles'
7
7
  import {useRootTheme} from '../../theme'
8
8
  import {Radius, SelectableTone} from '../../types'
9
9
  import {Menu} from './menu'
@@ -39,7 +39,7 @@ export function MenuGroup(
39
39
  onClick,
40
40
  padding = 3,
41
41
  popover,
42
- radius = 2,
42
+ radius: radiusProp = 2,
43
43
  space = 3,
44
44
  text,
45
45
  tone = 'default',
@@ -53,14 +53,16 @@ export function MenuGroup(
53
53
  onClickOutside,
54
54
  onEscape,
55
55
  onItemClick,
56
- onItemMouseEnter = menu.onMouseEnter,
56
+ onItemMouseEnter: _onItemMouseEnter,
57
57
  registerElement,
58
58
  } = menu
59
+ const onItemMouseEnter = _onItemMouseEnter ?? menu.onMouseEnter
59
60
  const [rootElement, setRootElement] = useState<HTMLButtonElement | HTMLDivElement | null>(null)
60
61
  const [open, setOpen] = useState(false)
61
62
  const shouldFocusRef = useRef<'first' | 'last' | null>(null)
62
63
  const active = Boolean(activeElement) && activeElement === rootElement
63
64
  const [withinMenu, setWithinMenu] = useState(false)
65
+ const radius = useMemo(() => _getArrayProp(radiusProp), [radiusProp])
64
66
 
65
67
  const handleMouseEnter = useCallback(
66
68
  (event: React.MouseEvent<HTMLElement>) => {
@@ -166,7 +168,7 @@ export function MenuGroup(
166
168
  aria-pressed={as === 'button' ? withinMenu : undefined}
167
169
  data-pressed={as !== 'button' ? withinMenu : undefined}
168
170
  data-selected={!withinMenu && active ? '' : undefined}
169
- $radius={useArrayProp(radius)}
171
+ $radius={radius}
170
172
  $tone={tone}
171
173
  $scheme={scheme}
172
174
  onClick={handleClick}
@@ -9,10 +9,10 @@ import {
9
9
  useState,
10
10
  } from 'react'
11
11
  import {isValidElementType} from 'react-is'
12
- import {useArrayProp} from '../../hooks'
13
12
  import {Box, Flex, Text} from '../../primitives'
14
13
  import {Selectable} from '../../primitives/_selectable'
15
14
  import {ResponsivePaddingProps, ResponsiveRadiusProps} from '../../primitives/types'
15
+ import {_getArrayProp} from '../../styles'
16
16
  import {useRootTheme} from '../../theme'
17
17
  import {SelectableTone} from '../../types/selectable'
18
18
  import {Hotkeys} from '../hotkeys'
@@ -72,9 +72,11 @@ export const MenuItem = forwardRef(function MenuItem(
72
72
  activeElement,
73
73
  mount,
74
74
  onItemClick,
75
- onItemMouseEnter = menu.onMouseEnter,
76
- onItemMouseLeave = menu.onMouseLeave,
75
+ onItemMouseEnter: _onItemMouseEnter,
76
+ onItemMouseLeave: _onItemMouseLeave,
77
77
  } = menu
78
+ const onItemMouseEnter = _onItemMouseEnter ?? menu.onMouseEnter
79
+ const onItemMouseLeave = _onItemMouseLeave ?? menu.onMouseLeave
78
80
  const [rootElement, setRootElement] = useState<HTMLDivElement | null>(null)
79
81
  const active = Boolean(activeElement) && activeElement === rootElement
80
82
  const ref = useRef<HTMLDivElement | null>(null)
@@ -105,7 +107,9 @@ export const MenuItem = forwardRef(function MenuItem(
105
107
  [padding, paddingX, paddingY, paddingTop, paddingRight, paddingBottom, paddingLeft],
106
108
  )
107
109
 
108
- const hotkeysFontSize = useArrayProp(fontSize).map((s) => s - 1)
110
+ const hotkeysFontSize = useMemo(() => _getArrayProp(fontSize).map((s) => s - 1), [fontSize])
111
+ const $radius = useMemo(() => _getArrayProp(radius), [radius])
112
+ const $padding = useMemo(() => _getArrayProp(0), [])
109
113
 
110
114
  const setRef = useCallback((el: HTMLDivElement | null) => {
111
115
  ref.current = el
@@ -121,8 +125,8 @@ export const MenuItem = forwardRef(function MenuItem(
121
125
  data-selected={active ? '' : undefined}
122
126
  data-disabled={disabled ? '' : undefined}
123
127
  forwardedAs={as}
124
- $radius={useArrayProp(radius)}
125
- $padding={useArrayProp(0)}
128
+ $radius={$radius}
129
+ $padding={$padding}
126
130
  $tone={disabled ? 'default' : tone}
127
131
  $scheme={scheme}
128
132
  disabled={disabled}
@@ -1,8 +1,8 @@
1
- import {forwardRef, useEffect, useState} from 'react'
1
+ import {forwardRef, useEffect, useMemo, useState} from 'react'
2
2
  import {styled} from 'styled-components'
3
- import {useArrayProp} from '../../hooks'
4
3
  import {Box} from '../../primitives'
5
4
  import {BoxProps, ResponsiveRadiusProps} from '../../primitives'
5
+ import {_getArrayProp} from '../../styles'
6
6
  import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
7
7
  import {skeletonStyle} from './styles'
8
8
 
@@ -45,13 +45,7 @@ export const Skeleton = forwardRef(function Skeleton(
45
45
  }
46
46
  }, [delay])
47
47
 
48
- return (
49
- <Root
50
- {...restProps}
51
- $animated={animated}
52
- $radius={useArrayProp(radius)}
53
- $visible={visible}
54
- ref={ref}
55
- />
56
- )
48
+ const $radius = useMemo(() => _getArrayProp(radius), [radius])
49
+
50
+ return <Root {...restProps} $animated={animated} $radius={$radius} $visible={visible} ref={ref} />
57
51
  })
@@ -1,8 +1,7 @@
1
1
  import {ThemeFontKey, getTheme_v2} from '@sanity/ui/theme'
2
- import {forwardRef} from 'react'
2
+ import {forwardRef, useMemo} from 'react'
3
3
  import {styled} from 'styled-components'
4
- import {useArrayProp} from '../../hooks'
5
- import {ThemeProps, _responsive} from '../../styles'
4
+ import {ThemeProps, _getArrayProp, _responsive} from '../../styles'
6
5
  import {Skeleton, SkeletonProps} from './skeleton'
7
6
 
8
7
  const Root = styled(Skeleton)<{$size: number[]; $style: ThemeFontKey}>((
@@ -67,7 +66,7 @@ export const TextSkeleton = forwardRef(function TextSkeleton(
67
66
  ref: React.Ref<HTMLDivElement>,
68
67
  ) {
69
68
  const {size = 2, ...restProps} = props
70
- const $size = useArrayProp(size)
69
+ const $size = useMemo(() => _getArrayProp(size), [size])
71
70
 
72
71
  return <Root {...restProps} $size={$size} ref={ref} $style="text" />
73
72
  })
@@ -82,7 +81,7 @@ export const LabelSkeleton = forwardRef(function TextSkeleton(
82
81
  ref: React.Ref<HTMLDivElement>,
83
82
  ) {
84
83
  const {size = 2, ...restProps} = props
85
- const $size = useArrayProp(size)
84
+ const $size = useMemo(() => _getArrayProp(size), [size])
86
85
 
87
86
  return <Root {...restProps} $size={$size} ref={ref} $style="label" />
88
87
  })
@@ -97,7 +96,7 @@ export const HeadingSkeleton = forwardRef(function TextSkeleton(
97
96
  ref: React.Ref<HTMLDivElement>,
98
97
  ) {
99
98
  const {size = 2, ...restProps} = props
100
- const $size = useArrayProp(size)
99
+ const $size = useMemo(() => _getArrayProp(size), [size])
101
100
 
102
101
  return <Root {...restProps} $size={$size} ref={ref} $style="heading" />
103
102
  })
@@ -112,7 +111,7 @@ export const CodeSkeleton = forwardRef(function TextSkeleton(
112
111
  ref: React.Ref<HTMLDivElement>,
113
112
  ) {
114
113
  const {size = 2, ...restProps} = props
115
- const $size = useArrayProp(size)
114
+ const $size = useMemo(() => _getArrayProp(size), [size])
116
115
 
117
116
  return <Root {...restProps} $size={$size} ref={ref} $style="code" />
118
117
  })