@sanity/ui 2.3.1 → 2.3.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "keywords": [
5
5
  "sanity",
6
6
  "ui",
@@ -1,5 +1,14 @@
1
1
  import {ThemeColorSchemeKey} from '@sanity/ui/theme'
2
- import {cloneElement, forwardRef, useCallback, useMemo, useState, useEffect, useRef} from 'react'
2
+ import {
3
+ cloneElement,
4
+ forwardRef,
5
+ useCallback,
6
+ useMemo,
7
+ useState,
8
+ useEffect,
9
+ useRef,
10
+ useImperativeHandle,
11
+ } from 'react'
3
12
  import {Popover, PopoverProps} from '../../primitives'
4
13
  import {Placement, Radius} from '../../types'
5
14
  import {MenuProps} from './menu'
@@ -52,7 +61,7 @@ export interface MenuButtonProps {
52
61
  */
53
62
  export const MenuButton = forwardRef(function MenuButton(
54
63
  props: MenuButtonProps,
55
- ref: React.ForwardedRef<HTMLButtonElement | null>,
64
+ forwardedRef: React.ForwardedRef<HTMLButtonElement | null>,
56
65
  ) {
57
66
  const {
58
67
  __unstable_disableRestoreFocusOnClose: disableRestoreFocusOnClose = false,
@@ -219,19 +228,7 @@ export const MenuButton = forwardRef(function MenuButton(
219
228
 
220
229
  const menu = menuProp && cloneElement(menuProp, menuProps)
221
230
 
222
- const setButtonRef = useCallback(
223
- (el: HTMLButtonElement | null) => {
224
- if (typeof ref === 'function') {
225
- ref(el)
226
- } else if (ref) {
227
- ref.current = el
228
- }
229
-
230
- setButtonElement(el)
231
- },
232
- [ref],
233
- )
234
-
231
+ const ref = useRef<HTMLButtonElement | null>(null)
235
232
  const button = useMemo(
236
233
  () =>
237
234
  buttonProp &&
@@ -243,12 +240,28 @@ export const MenuButton = forwardRef(function MenuButton(
243
240
  onMouseDown: handleMouseDown,
244
241
  'aria-haspopup': true,
245
242
  'aria-expanded': open,
246
- ref: setButtonRef,
243
+ ref: ref,
247
244
  selected: open,
248
245
  }),
249
- [buttonProp, handleButtonClick, handleButtonKeyDown, handleMouseDown, id, open, setButtonRef],
246
+ [buttonProp, handleButtonClick, handleButtonKeyDown, handleMouseDown, id, open],
250
247
  )
251
248
 
249
+ // Forward button ref to parent
250
+ useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(
251
+ forwardedRef,
252
+ () => ref.current,
253
+ )
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
+
252
265
  const popoverProps: MenuButtonProps['popover'] = useMemo(
253
266
  () => ({
254
267
  boundaryElement: deprecated_boundaryElement,
@@ -1,5 +1,5 @@
1
1
  import {ChevronRightIcon} from '@sanity/icons'
2
- import {createElement, isValidElement, useCallback, useEffect, useRef, useState} from 'react'
2
+ import {isValidElement, useCallback, useEffect, useRef, useState} from 'react'
3
3
  import {isValidElementType} from 'react-is'
4
4
  import {useArrayProp} from '../../hooks'
5
5
  import {Box, Flex, Popover, PopoverProps, Text} from '../../primitives'
@@ -35,7 +35,7 @@ export function MenuGroup(
35
35
  as = 'button',
36
36
  children,
37
37
  fontSize = 1,
38
- icon,
38
+ icon: IconComponent,
39
39
  onClick,
40
40
  padding = 3,
41
41
  popover,
@@ -177,10 +177,10 @@ export function MenuGroup(
177
177
  type={as === 'button' ? 'button' : undefined}
178
178
  >
179
179
  <Flex gap={space} padding={padding}>
180
- {icon && (
180
+ {IconComponent && (
181
181
  <Text size={fontSize}>
182
- {isValidElement(icon) && icon}
183
- {isValidElementType(icon) && createElement(icon)}
182
+ {isValidElement(IconComponent) && IconComponent}
183
+ {isValidElementType(IconComponent) && <IconComponent />}
184
184
  </Text>
185
185
  )}
186
186
 
@@ -1,5 +1,4 @@
1
1
  import {
2
- createElement,
3
2
  forwardRef,
4
3
  isValidElement,
5
4
  useCallback,
@@ -49,8 +48,8 @@ export const MenuItem = forwardRef(function MenuItem(
49
48
  disabled,
50
49
  fontSize = 1,
51
50
  hotkeys,
52
- icon,
53
- iconRight,
51
+ icon: IconComponent,
52
+ iconRight: IconRightComponent,
54
53
  onClick,
55
54
  padding = 3,
56
55
  paddingX,
@@ -135,12 +134,12 @@ export const MenuItem = forwardRef(function MenuItem(
135
134
  tabIndex={-1}
136
135
  type={as === 'button' ? 'button' : undefined}
137
136
  >
138
- {(icon || text || iconRight) && (
137
+ {(IconComponent || text || IconRightComponent) && (
139
138
  <Flex as="span" gap={space} align="center" {...paddingProps}>
140
- {icon && (
139
+ {IconComponent && (
141
140
  <Text size={fontSize}>
142
- {isValidElement(icon) && icon}
143
- {isValidElementType(icon) && createElement(icon)}
141
+ {isValidElement(IconComponent) && IconComponent}
142
+ {isValidElementType(IconComponent) && <IconComponent />}
144
143
  </Text>
145
144
  )}
146
145
 
@@ -160,10 +159,10 @@ export const MenuItem = forwardRef(function MenuItem(
160
159
  />
161
160
  )}
162
161
 
163
- {iconRight && (
162
+ {IconRightComponent && (
164
163
  <Text size={fontSize}>
165
- {isValidElement(iconRight) && iconRight}
166
- {isValidElementType(iconRight) && createElement(iconRight)}
164
+ {isValidElement(IconRightComponent) && IconRightComponent}
165
+ {isValidElementType(IconRightComponent) && <IconRightComponent />}
167
166
  </Text>
168
167
  )}
169
168
  </Flex>
@@ -1,6 +1,6 @@
1
1
  import {ToggleArrowRightIcon} from '@sanity/icons'
2
2
  import {ThemeFontWeightKey} from '@sanity/ui/theme'
3
- import {createElement, memo, useCallback, useEffect, useId, useMemo, useRef} from 'react'
3
+ import {memo, useCallback, useEffect, useId, useMemo, useRef} from 'react'
4
4
  import {styled} from 'styled-components'
5
5
  import {Box, BoxProps, Flex, Text} from '../../primitives'
6
6
  import {
@@ -52,7 +52,7 @@ export const TreeItem = memo(function TreeItem(
52
52
  expanded: expandedProp = false,
53
53
  fontSize = 1,
54
54
  href,
55
- icon,
55
+ icon: IconComponent,
56
56
  id: idProp,
57
57
  linkAs,
58
58
  muted,
@@ -121,14 +121,17 @@ export const TreeItem = memo(function TreeItem(
121
121
  <Flex padding={padding}>
122
122
  <Box
123
123
  marginRight={space}
124
- style={{visibility: icon || children ? 'visible' : 'hidden', pointerEvents: 'none'}}
124
+ style={{
125
+ visibility: IconComponent || children ? 'visible' : 'hidden',
126
+ pointerEvents: 'none',
127
+ }}
125
128
  >
126
- {icon && (
129
+ {IconComponent && (
127
130
  <Text muted={muted} size={fontSize} weight={weight}>
128
- {createElement(icon)}
131
+ <IconComponent />
129
132
  </Text>
130
133
  )}
131
- {!icon && (
134
+ {!IconComponent && (
132
135
  <ToggleArrowText muted={muted} size={fontSize} weight={weight}>
133
136
  <ToggleArrowRightIcon style={{transform: expanded ? 'rotate(90deg)' : undefined}} />
134
137
  </ToggleArrowText>
@@ -8,8 +8,6 @@ export function useCustomValidity(
8
8
  customValidity: string | undefined,
9
9
  ): void {
10
10
  useEffect(() => {
11
- if (ref.current) {
12
- ref.current.setCustomValidity(customValidity || '')
13
- }
11
+ ref.current?.setCustomValidity(customValidity || '')
14
12
  }, [customValidity, ref])
15
13
  }
@@ -7,6 +7,7 @@ describe('useDelayedState', () => {
7
7
  it('should update state immediately if delay is not provided', () => {
8
8
  const {result} = renderHook(() => useDelayedState(false))
9
9
  const [, setState] = result.current
10
+
10
11
  act(() => {
11
12
  setState(true)
12
13
  })
@@ -1,4 +1,4 @@
1
- import {createElement, forwardRef, isValidElement, useMemo} from 'react'
1
+ import {forwardRef, isValidElement, useMemo} from 'react'
2
2
  import {isValidElementType} from 'react-is'
3
3
  import {styled} from 'styled-components'
4
4
  import {useArrayProp} from '../../hooks'
@@ -68,8 +68,8 @@ export const Button = forwardRef(function Button(
68
68
  children,
69
69
  disabled,
70
70
  fontSize = 1,
71
- icon,
72
- iconRight,
71
+ icon: IconComponent,
72
+ iconRight: IconRightComponent,
73
73
  justify: justifyProp = 'center',
74
74
  loading,
75
75
  mode = 'default',
@@ -138,13 +138,13 @@ export const Button = forwardRef(function Button(
138
138
  </LoadingBox>
139
139
  )}
140
140
 
141
- {(icon || text || iconRight) && (
141
+ {(IconComponent || text || IconRightComponent) && (
142
142
  <Box as="span" {...boxProps}>
143
143
  <Flex as="span" justify={justify} gap={space}>
144
- {icon && (
144
+ {IconComponent && (
145
145
  <Text size={fontSize}>
146
- {isValidElement(icon) && icon}
147
- {isValidElementType(icon) && createElement(icon)}
146
+ {isValidElement(IconComponent) && IconComponent}
147
+ {isValidElementType(IconComponent) && <IconComponent />}
148
148
  </Text>
149
149
  )}
150
150
 
@@ -160,10 +160,10 @@ export const Button = forwardRef(function Button(
160
160
  </Text>
161
161
  )}
162
162
 
163
- {iconRight && (
163
+ {IconRightComponent && (
164
164
  <Text size={fontSize}>
165
- {isValidElement(iconRight) && iconRight}
166
- {isValidElementType(iconRight) && createElement(iconRight)}
165
+ {isValidElement(IconRightComponent) && IconRightComponent}
166
+ {isValidElementType(IconRightComponent) && <IconRightComponent />}
167
167
  </Text>
168
168
  )}
169
169
  </Flex>
@@ -1,14 +1,6 @@
1
1
  import {CloseIcon} from '@sanity/icons'
2
2
  import {ThemeFontWeightKey} from '@sanity/ui/theme'
3
- import {
4
- createElement,
5
- forwardRef,
6
- isValidElement,
7
- useCallback,
8
- useImperativeHandle,
9
- useMemo,
10
- useRef,
11
- } from 'react'
3
+ import {forwardRef, isValidElement, useCallback, useImperativeHandle, useMemo, useRef} from 'react'
12
4
  import {isValidElementType} from 'react-is'
13
5
  import {styled} from 'styled-components'
14
6
  import {EMPTY_RECORD} from '../../constants'
@@ -167,8 +159,8 @@ export const TextInput = forwardRef(function TextInput(
167
159
  clearButton,
168
160
  disabled = false,
169
161
  fontSize: fontSizeProp = 2,
170
- icon,
171
- iconRight,
162
+ icon: IconComponent,
163
+ iconRight: IconRightComponent,
172
164
  onClear,
173
165
  padding: paddingProp = 3,
174
166
  prefix,
@@ -192,8 +184,8 @@ export const TextInput = forwardRef(function TextInput(
192
184
 
193
185
  // Transient properties
194
186
  const $hasClearButton = Boolean(clearButton)
195
- const $hasIcon = Boolean(icon)
196
- const $hasIconRight = Boolean(iconRight)
187
+ const $hasIcon = Boolean(IconComponent)
188
+ const $hasIconRight = Boolean(IconRightComponent)
197
189
  const $hasSuffix = Boolean(suffix)
198
190
  const $hasPrefix = Boolean(prefix)
199
191
 
@@ -248,20 +240,20 @@ export const TextInput = forwardRef(function TextInput(
248
240
  data-scheme={rootTheme.scheme}
249
241
  data-tone={rootTheme.tone}
250
242
  >
251
- {icon && (
243
+ {IconComponent && (
252
244
  <LeftBox padding={padding}>
253
245
  <Text size={fontSize}>
254
- {isValidElement(icon) && icon}
255
- {isValidElementType(icon) && createElement(icon)}
246
+ {isValidElement(IconComponent) && IconComponent}
247
+ {isValidElementType(IconComponent) && <IconComponent />}
256
248
  </Text>
257
249
  </LeftBox>
258
250
  )}
259
251
 
260
- {!$hasClearButton && iconRight && (
252
+ {!$hasClearButton && IconRightComponent && (
261
253
  <RightBox padding={padding}>
262
254
  <Text size={fontSize}>
263
- {isValidElement(iconRight) && iconRight}
264
- {isValidElementType(iconRight) && createElement(iconRight)}
255
+ {isValidElement(IconRightComponent) && IconRightComponent}
256
+ {isValidElementType(IconRightComponent) && <IconRightComponent />}
265
257
  </Text>
266
258
  </RightBox>
267
259
  )}
@@ -271,8 +263,8 @@ export const TextInput = forwardRef(function TextInput(
271
263
  __unstable_disableFocusRing,
272
264
  border,
273
265
  fontSize,
274
- icon,
275
- iconRight,
266
+ IconComponent,
267
+ IconRightComponent,
276
268
  padding,
277
269
  radius,
278
270
  rootTheme,
@@ -19,7 +19,6 @@ import {
19
19
  useMemo,
20
20
  useRef,
21
21
  useState,
22
- type ForwardedRef,
23
22
  useId,
24
23
  useSyncExternalStore,
25
24
  useImperativeHandle,
@@ -357,22 +356,7 @@ export const Tooltip = forwardRef(function Tooltip(
357
356
  [refs],
358
357
  )
359
358
 
360
- const childRef: ForwardedRef<HTMLElement | null> = (childProp as any)?.ref
361
-
362
- const setReference = useCallback(
363
- (node: HTMLElement | null) => {
364
- if (typeof childRef === 'function') {
365
- childRef(node)
366
- } else if (childRef) {
367
- childRef.current = node
368
- }
369
-
370
- // childRef.current = node
371
- setReferenceElement(node)
372
- },
373
- [childRef],
374
- )
375
-
359
+ const childRef = useRef<HTMLElement | null>(null)
376
360
  const child = useMemo(() => {
377
361
  if (!childProp) return null
378
362
 
@@ -383,7 +367,7 @@ export const Tooltip = forwardRef(function Tooltip(
383
367
  onMouseLeave: handleMouseLeave,
384
368
  onClick: handleClick,
385
369
  onContextMenu: handleContextMenu,
386
- ref: setReference,
370
+ ref: childRef,
387
371
  })
388
372
  }, [
389
373
  childProp,
@@ -393,9 +377,18 @@ export const Tooltip = forwardRef(function Tooltip(
393
377
  handleFocus,
394
378
  handleMouseEnter,
395
379
  handleMouseLeave,
396
- setReference,
397
380
  ])
398
381
 
382
+ // If there's a child then we need to set the reference element to the cloned child ref
383
+ // and if child changes we make sure to update or remove the reference element.
384
+ useEffect(() => {
385
+ if (!child) return undefined
386
+
387
+ setReferenceElement(childRef.current)
388
+
389
+ return () => setReferenceElement(null)
390
+ }, [child])
391
+
399
392
  if (!child) return <></>
400
393
 
401
394
  if (disabled) return child