@sanity/ui 2.3.6-canary.6 → 2.3.6

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