@sanity/ui 2.9.0-canary.4 → 2.9.0-canary.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "2.9.0-canary.4",
3
+ "version": "2.9.0-canary.6",
4
4
  "keywords": [
5
5
  "sanity",
6
6
  "ui",
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import {
3
- Middleware,
4
3
  RootBoundary,
5
4
  arrow,
6
5
  autoUpdate,
@@ -182,94 +181,70 @@ export const Popover = memo(
182
181
  const mediaIndex = useMediaIndex()
183
182
  const boundaryWidth = constrainSize || preventOverflow ? boundarySize?.width : undefined
184
183
 
185
- // Update width when
186
- // - media index changes
187
- // - `width` property changes
188
- const width = calcCurrentWidth({
189
- container,
190
- mediaIndex,
191
- width: widthArrayProp,
192
- })
193
- const widthRef = useRef(width)
194
-
195
- useEffect(() => {
196
- widthRef.current = width
197
- }, [width])
198
-
199
- // Update max width when
200
- // - boundary width changes
201
- // - `width` property changes
202
- const maxWidth = calcMaxWidth({boundaryWidth, currentWidth: width})
203
- const maxWidthRef = useRef(maxWidth)
204
-
205
- useEffect(() => {
206
- maxWidthRef.current = maxWidth
207
- }, [maxWidth])
208
-
209
- // Keep track of reference element width (see `size` middleware below)
210
- const referenceWidthRef = useRef<number>()
211
-
212
184
  // Force apply width & max width to floating element
213
185
  useLayoutEffect(() => {
214
186
  const floatingElement = ref.current
215
187
 
216
- if (!open || !floatingElement) return
188
+ // If constrainSize or matchReferenceWidth is true, then the styles are set by the `size` middleware
189
+ if (!open || !floatingElement || constrainSize || matchReferenceWidth) return
217
190
 
218
- const referenceWidth = referenceWidthRef.current
191
+ const currentWidth = calcCurrentWidth({
192
+ container,
193
+ mediaIndex,
194
+ width: widthArrayProp,
195
+ })
196
+ const maxWidth = calcMaxWidth({boundaryWidth, currentWidth})
219
197
 
220
- if (matchReferenceWidth) {
221
- if (referenceWidthRef.current !== undefined) {
222
- floatingElement.style.width = `${referenceWidth}px`
223
- }
224
- } else if (width !== undefined) {
225
- floatingElement.style.width = `${width}px`
198
+ if (currentWidth !== undefined) {
199
+ floatingElement.style.width = `${currentWidth}px`
226
200
  }
227
201
 
228
202
  if (typeof maxWidth === 'number') {
229
203
  floatingElement.style.maxWidth = `${maxWidth}px`
230
204
  }
231
- }, [width, matchReferenceWidth, maxWidth, open])
232
-
233
- const middleware = useMemo(() => {
234
- const ret: Middleware[] = []
205
+ }, [
206
+ boundaryWidth,
207
+ constrainSize,
208
+ container,
209
+ matchReferenceWidth,
210
+ mediaIndex,
211
+ open,
212
+ widthArrayProp,
213
+ ])
235
214
 
236
- // Flip the floating element when leaving the boundary box
237
- if (constrainSize || preventOverflow) {
238
- ret.push(
215
+ const {x, y, middlewareData, placement, refs, strategy, update} = useFloating({
216
+ middleware: [
217
+ // Flip the floating element when leaving the boundary box
218
+ (constrainSize || preventOverflow) &&
239
219
  flip({
240
220
  boundary: floatingBoundary || undefined,
241
221
  fallbackPlacements,
242
222
  padding: DEFAULT_POPOVER_PADDING,
243
223
  rootBoundary,
244
224
  }),
245
- )
246
- }
247
-
248
- // Define distance between reference and floating element
249
- ret.push(offset({mainAxis: DEFAULT_POPOVER_DISTANCE}))
250
-
251
- // Track sizes
252
- if (constrainSize || matchReferenceWidth) {
253
- ret.push(
225
+ // Define distance between reference and floating element
226
+ offset({mainAxis: DEFAULT_POPOVER_DISTANCE}),
227
+ // Track sizes
228
+ (constrainSize || matchReferenceWidth) &&
254
229
  size({
255
230
  apply({availableWidth, availableHeight, elements, referenceWidth}) {
256
- // not fresh, so use refs
257
-
258
- referenceWidthRef.current = referenceWidth
259
-
260
- const _currentWidth = widthRef.current
261
- const _maxWidth = maxWidthRef.current
231
+ const currentWidth = calcCurrentWidth({
232
+ container,
233
+ mediaIndex,
234
+ width: widthArrayProp,
235
+ })
236
+ const maxWidth = calcMaxWidth({boundaryWidth, currentWidth})
262
237
 
263
238
  if (matchReferenceWidth) {
264
239
  elements.floating.style.width = `${referenceWidth}px`
265
- } else if (_currentWidth !== undefined) {
266
- elements.floating.style.width = `${_currentWidth}px`
240
+ } else if (currentWidth !== undefined) {
241
+ elements.floating.style.width = `${currentWidth}px`
267
242
  }
268
243
 
269
244
  if (constrainSize) {
270
245
  elements.floating.style.maxWidth = `${Math.min(
271
246
  availableWidth,
272
- _maxWidth ?? Infinity,
247
+ maxWidth ?? Infinity,
273
248
  )}px`
274
249
 
275
250
  elements.floating.style.maxHeight = `${availableHeight}px`
@@ -281,60 +256,28 @@ export const Popover = memo(
281
256
  matchReferenceWidth,
282
257
  padding: DEFAULT_POPOVER_PADDING,
283
258
  }),
284
- )
285
- }
286
-
287
- // Shift the popover so its sits within the boundary element
288
- if (preventOverflow) {
289
- ret.push(
259
+ // Shift the popover so its sits within the boundary element
260
+ preventOverflow &&
290
261
  shift({
291
262
  boundary: floatingBoundary || undefined,
292
263
  rootBoundary,
293
264
  padding: DEFAULT_POPOVER_PADDING,
294
265
  }),
295
- )
296
- }
297
-
298
- // Place arrow
299
- if (arrowProp) {
300
- ret.push(
266
+ // Place arrow
267
+ arrowProp &&
301
268
  arrow({
302
269
  element: arrowElement,
303
270
  padding: DEFAULT_POPOVER_PADDING,
304
271
  }),
305
- )
306
- }
307
-
308
- // Determine the origin to scale from.
309
- // Must be placed after `@sanity/ui/size` and `shift` middleware.
310
- if (animate) {
311
- ret.push(origin)
312
- }
313
-
314
- ret.push(
272
+ // Determine the origin to scale from.
273
+ // Must be placed after `@sanity/ui/size` and `shift` middleware.
274
+ animate && origin,
315
275
  hide({
316
276
  boundary: referenceBoundary || undefined,
317
277
  padding: DEFAULT_POPOVER_PADDING,
318
278
  strategy: 'referenceHidden',
319
279
  }),
320
- )
321
-
322
- return ret
323
- }, [
324
- animate,
325
- arrowElement,
326
- arrowProp,
327
- constrainSize,
328
- fallbackPlacements,
329
- floatingBoundary,
330
- margins,
331
- matchReferenceWidth,
332
- preventOverflow,
333
- referenceBoundary,
334
- ])
335
-
336
- const {x, y, middlewareData, placement, refs, strategy, update} = useFloating({
337
- middleware,
280
+ ],
338
281
  placement: placementProp,
339
282
  whileElementsMounted: autoUpdate,
340
283
  })
@@ -405,7 +348,6 @@ export const Popover = memo(
405
348
  originY={originY}
406
349
  strategy={strategy}
407
350
  tone={tone}
408
- width={matchReferenceWidth ? referenceWidthRef.current : width}
409
351
  x={x}
410
352
  y={y}
411
353
  >
@@ -51,7 +51,6 @@ export const PopoverCard = memo(
51
51
  shadow?: number | number[]
52
52
  strategy: Strategy
53
53
  tone: CardTone
54
- width: number | undefined
55
54
  x: number | null
56
55
  y: number | null
57
56
  } & Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'height' | 'width'>,
@@ -76,7 +75,6 @@ export const PopoverCard = memo(
76
75
  strategy,
77
76
  style,
78
77
  tone,
79
- width,
80
78
  x: xProp,
81
79
  y: yProp,
82
80
  ...restProps
@@ -101,12 +99,11 @@ export const PopoverCard = memo(
101
99
  originY,
102
100
  position: strategy,
103
101
  top: y,
104
- width,
105
102
  zIndex,
106
103
  willChange: animate ? 'transform' : undefined,
107
104
  ...style,
108
105
  }),
109
- [animate, originX, originY, strategy, style, width, x, y, zIndex],
106
+ [animate, originX, originY, strategy, style, x, y, zIndex],
110
107
  )
111
108
 
112
109
  const arrowStyle: CSSProperties = useMemo(
@@ -121,7 +121,7 @@ export const Tooltip = forwardRef(function Tooltip(
121
121
  const fallbackPlacements = useArrayProp(fallbackPlacementsProp)
122
122
  const ref = useRef<HTMLDivElement | null>(null)
123
123
  const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null)
124
- const arrowRef = useRef<HTMLDivElement | null>(null)
124
+ const [arrowElement, setArrowElement] = useState<HTMLDivElement | null>(null)
125
125
  const rootBoundary: RootBoundary = 'viewport'
126
126
  const [tooltipMaxWidth, setTooltipMaxWidth] = useState(0)
127
127
 
@@ -158,7 +158,7 @@ export const Tooltip = forwardRef(function Tooltip(
158
158
 
159
159
  // Place arrow
160
160
  if (arrowProp) {
161
- ret.push(arrow({element: arrowRef, padding: DEFAULT_TOOLTIP_PADDING}))
161
+ ret.push(arrow({element: arrowElement, padding: DEFAULT_TOOLTIP_PADDING}))
162
162
  }
163
163
 
164
164
  // Determine the origin to scale from.
@@ -168,7 +168,7 @@ export const Tooltip = forwardRef(function Tooltip(
168
168
  }
169
169
 
170
170
  return ret
171
- }, [animate, arrowProp, boundaryElement, fallbackPlacements])
171
+ }, [animate, arrowElement, arrowProp, boundaryElement, fallbackPlacements])
172
172
 
173
173
  const {floatingStyles, placement, middlewareData, refs, update} = useFloating({
174
174
  middleware,
@@ -226,42 +226,42 @@ export const Tooltip = forwardRef(function Tooltip(
226
226
  handleIsOpenChange(false)
227
227
  childProp?.props?.onBlur?.(e)
228
228
  },
229
- [childProp?.props, handleIsOpenChange],
229
+ [childProp, handleIsOpenChange],
230
230
  )
231
231
  const handleClick = useCallback(
232
232
  (e: MouseEvent) => {
233
233
  handleIsOpenChange(false, true)
234
234
  childProp?.props.onClick?.(e)
235
235
  },
236
- [childProp?.props, handleIsOpenChange],
236
+ [childProp, handleIsOpenChange],
237
237
  )
238
238
  const handleContextMenu = useCallback(
239
239
  (e: MouseEvent) => {
240
240
  handleIsOpenChange(false, true)
241
241
  childProp?.props.onContextMenu?.(e)
242
242
  },
243
- [childProp?.props, handleIsOpenChange],
243
+ [childProp, handleIsOpenChange],
244
244
  )
245
245
  const handleFocus = useCallback(
246
246
  (e: FocusEvent) => {
247
247
  handleIsOpenChange(true)
248
248
  childProp?.props?.onFocus?.(e)
249
249
  },
250
- [childProp?.props, handleIsOpenChange],
250
+ [childProp, handleIsOpenChange],
251
251
  )
252
252
  const handleMouseEnter = useCallback(
253
253
  (e: MouseEvent) => {
254
254
  handleIsOpenChange(true)
255
255
  childProp?.props?.onMouseEnter?.(e)
256
256
  },
257
- [childProp?.props, handleIsOpenChange],
257
+ [childProp, handleIsOpenChange],
258
258
  )
259
259
  const handleMouseLeave = useCallback(
260
260
  (e: MouseEvent) => {
261
261
  handleIsOpenChange(false)
262
262
  childProp?.props?.onMouseLeave?.(e)
263
263
  },
264
- [childProp?.props, handleIsOpenChange],
264
+ [childProp, handleIsOpenChange],
265
265
  )
266
266
 
267
267
  // Handle closing the tooltip when the mouse leaves the referenceElement
@@ -312,7 +312,7 @@ export const Tooltip = forwardRef(function Tooltip(
312
312
 
313
313
  const setArrow = useCallback(
314
314
  (arrowEl: HTMLDivElement | null) => {
315
- arrowRef.current = arrowEl
315
+ setArrowElement(arrowEl)
316
316
  update()
317
317
  },
318
318
  [update],
@@ -327,9 +327,9 @@ export const Tooltip = forwardRef(function Tooltip(
327
327
  )
328
328
 
329
329
  const childRef = useRef<HTMLElement | null>(null)
330
+ const [childElement, setChildElement] = useState<HTMLElement | null>(null)
330
331
 
331
- // Merge refs so that any ref we are overriding is called as well
332
- useImperativeHandle((childProp as any)?.ref, () => childRef.current)
332
+ useImperativeHandle(getElementRef(childProp as any), () => childElement, [childElement])
333
333
 
334
334
  const child = useMemo(() => {
335
335
  if (!childProp) return null
@@ -341,7 +341,7 @@ export const Tooltip = forwardRef(function Tooltip(
341
341
  onMouseLeave: handleMouseLeave,
342
342
  onClick: handleClick,
343
343
  onContextMenu: handleContextMenu,
344
- ref: childRef,
344
+ ref: setChildElement,
345
345
  })
346
346
  }, [
347
347
  childProp,
@@ -465,3 +465,30 @@ function useCloseOnMouseLeave({
465
465
  return () => window.removeEventListener('mousemove', handleMouseMove)
466
466
  }, [onMouseMove, showTooltip])
467
467
  }
468
+
469
+ // Before React 19 accessing `element.props.ref` will throw a warning and suggest using `element.ref`
470
+ // After React 19 accessing `element.ref` does the opposite.
471
+ // https://github.com/facebook/react/pull/28348
472
+ //
473
+ // Access the ref using the method that doesn't yield a warning.
474
+ function getElementRef(element?: React.ReactElement) {
475
+ if (!element) return null
476
+ // React <=18 in DEV
477
+ let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get
478
+ let mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning
479
+
480
+ if (mayWarn) {
481
+ return (element as any).ref
482
+ }
483
+
484
+ // React 19 in DEV
485
+ getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get
486
+ mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning
487
+
488
+ if (mayWarn) {
489
+ return element.props.ref
490
+ }
491
+
492
+ // Not DEV
493
+ return element.props.ref || (element as any).ref
494
+ }