@sanity/ui 3.0.11 → 3.0.12-canary.1

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/_chunks-cjs/_visual-editing.js +1124 -628
  2. package/dist/_chunks-cjs/_visual-editing.js.map +1 -1
  3. package/dist/_chunks-es/_visual-editing.mjs +1127 -631
  4. package/dist/_chunks-es/_visual-editing.mjs.map +1 -1
  5. package/dist/_visual-editing.d.mts +3 -7
  6. package/dist/_visual-editing.d.ts +3 -7
  7. package/dist/index.d.mts +11 -12
  8. package/dist/index.d.ts +11 -12
  9. package/dist/index.js +252 -295
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +254 -297
  12. package/dist/index.mjs.map +1 -1
  13. package/package.json +26 -40
  14. package/src/core/components/autocomplete/autocomplete.tsx +2 -2
  15. package/src/core/components/breadcrumbs/breadcrumbs.tsx +70 -40
  16. package/src/core/components/dialog/dialog.tsx +10 -14
  17. package/src/core/components/hotkeys/hotkeys.tsx +2 -2
  18. package/src/core/components/menu/menuGroup.tsx +2 -2
  19. package/src/core/components/menu/menuItem.tsx +4 -4
  20. package/src/core/components/skeleton/skeleton.tsx +2 -2
  21. package/src/core/components/skeleton/textSkeleton.tsx +5 -5
  22. package/src/core/components/tree/tree.tsx +176 -182
  23. package/src/core/components/tree/treeGroup.tsx +2 -4
  24. package/src/core/components/tree/treeItem.tsx +5 -5
  25. package/src/core/hooks/index.ts +1 -1
  26. package/src/core/hooks/useArrayProp.ts +5 -17
  27. package/src/core/primitives/avatar/avatar.tsx +14 -16
  28. package/src/core/primitives/avatar/avatarCounter.tsx +14 -16
  29. package/src/core/primitives/avatar/avatarStack.tsx +2 -2
  30. package/src/core/primitives/badge/badge.tsx +3 -3
  31. package/src/core/primitives/box/box.tsx +26 -26
  32. package/src/core/primitives/button/button.tsx +11 -11
  33. package/src/core/primitives/card/card.tsx +8 -8
  34. package/src/core/primitives/code/code.tsx +2 -2
  35. package/src/core/primitives/container/container.tsx +2 -2
  36. package/src/core/primitives/flex/flex.tsx +6 -6
  37. package/src/core/primitives/grid/grid.tsx +9 -9
  38. package/src/core/primitives/heading/heading.tsx +3 -3
  39. package/src/core/primitives/inline/inline.tsx +2 -2
  40. package/src/core/primitives/kbd/kbd.tsx +2 -2
  41. package/src/core/primitives/label/label.tsx +3 -3
  42. package/src/core/primitives/popover/floating-ui/size.ts +32 -16
  43. package/src/core/primitives/popover/popover.tsx +355 -328
  44. package/src/core/primitives/popover/popoverCard.tsx +123 -125
  45. package/src/core/primitives/select/select.tsx +6 -5
  46. package/src/core/primitives/stack/stack.tsx +2 -2
  47. package/src/core/primitives/text/text.tsx +3 -3
  48. package/src/core/primitives/textArea/textArea.tsx +6 -5
  49. package/src/core/primitives/textInput/textInput.tsx +6 -5
  50. package/src/core/primitives/tooltip/tooltip.tsx +73 -44
  51. package/src/core/primitives/tooltip/tooltipCard.tsx +83 -85
  52. package/src/core/utils/layer/layerProvider.tsx +3 -2
  53. package/src/core/utils/virtualList/virtualList.tsx +48 -23
@@ -15,17 +15,17 @@ import {AnimatePresence} from 'framer-motion'
15
15
  import {
16
16
  cloneElement,
17
17
  forwardRef,
18
- memo,
19
- MutableRefObject,
20
- RefCallback,
18
+ type Ref,
21
19
  useCallback,
22
20
  useEffect,
23
21
  useImperativeHandle,
24
22
  useMemo,
25
23
  useRef,
24
+ useState,
26
25
  } from 'react'
27
26
 
28
- import {useArrayProp, useElementSize, useMediaIndex, usePrefersReducedMotion} from '../../hooks'
27
+ import {useElementSize, useMediaIndex, usePrefersReducedMotion} from '../../hooks'
28
+ import {getArrayProp} from '../../hooks/useArrayProp'
29
29
  import {origin} from '../../middleware/origin'
30
30
  import {useTheme_v2} from '../../theme'
31
31
  import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types'
@@ -119,9 +119,7 @@ export interface PopoverProps
119
119
  scheme?: ThemeColorSchemeKey
120
120
  tone?: CardTone
121
121
  /** @beta */
122
- updateRef?:
123
- | MutableRefObject<PopoverUpdateCallback | undefined>
124
- | RefCallback<PopoverUpdateCallback | undefined>
122
+ updateRef?: Ref<PopoverUpdateCallback | undefined>
125
123
  width?: PopoverWidth | PopoverWidth[]
126
124
  }
127
125
 
@@ -136,349 +134,378 @@ const ViewportOverlay = () => {
136
134
  *
137
135
  * @public
138
136
  */
139
- export const Popover = memo(
140
- forwardRef(function Popover(
141
- props: PopoverProps &
142
- Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'children' | 'content' | 'width'>,
143
- forwardedRef: React.ForwardedRef<HTMLDivElement>,
144
- ): React.JSX.Element {
145
- const {container, layer} = useTheme_v2()
146
- const boundaryElementContext = useBoundaryElement()
147
-
148
- const {
149
- __unstable_margins: margins = DEFAULT_POPOVER_MARGINS,
150
- animate: _animate = false,
151
- arrow: arrowProp = false,
152
- boundaryElement = boundaryElementContext.element,
153
- children: childProp,
154
- constrainSize = false,
155
- content,
156
- disabled,
157
- fallbackPlacements = props.fallbackPlacements ??
158
- DEFAULT_FALLBACK_PLACEMENTS[props.placement ?? 'bottom'],
159
- matchReferenceWidth,
160
- floatingBoundary = props.boundaryElement ?? boundaryElementContext.element,
161
- modal,
162
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
163
- onActivate,
164
- open,
165
- overflow = 'hidden',
166
- padding: paddingProp,
167
- placement: placementProp = 'bottom',
168
- placementStrategy = 'flip',
169
- portal,
170
- preventOverflow = true,
171
- radius: radiusProp = 3,
172
- referenceBoundary = props.boundaryElement ?? boundaryElementContext.element,
173
- referenceElement,
174
- scheme,
175
- shadow: shadowProp = 3,
176
- tone = 'inherit',
177
- width: widthProp = 'auto',
178
- zOffset: zOffsetProp = layer.popover.zOffset,
179
- updateRef,
180
- ...restProps
181
- } = props
182
- const prefersReducedMotion = usePrefersReducedMotion()
183
- const animate = prefersReducedMotion ? false : _animate
184
- const boundarySize = useElementSize(boundaryElement)?.border
185
- const padding = useArrayProp(paddingProp)
186
- const radius = useArrayProp(radiusProp)
187
- const shadow = useArrayProp(shadowProp)
188
- const widthArrayProp = useArrayProp(widthProp)
189
- const zOffset = useArrayProp(zOffsetProp)
190
- const ref = useRef<HTMLDivElement | null>(null)
191
- const arrowRef = useRef<HTMLDivElement | null>(null)
192
- const rootBoundary: RootBoundary = 'viewport'
193
-
194
- useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(
195
- forwardedRef,
196
- () => ref.current,
197
- )
198
-
199
- const mediaIndex = useMediaIndex()
200
- const boundaryWidth = constrainSize || preventOverflow ? boundarySize?.width : undefined
201
-
202
- // Update width when
203
- // - media index changes
204
- // - `width` property changes
205
- const width = calcCurrentWidth({
206
- container,
207
- mediaIndex,
208
- width: widthArrayProp,
209
- })
210
- const widthRef = useRef(width)
211
-
212
- useEffect(() => {
213
- widthRef.current = width
214
- }, [width])
215
-
216
- // Update max width when
217
- // - boundary width changes
218
- // - `width` property changes
219
- const maxWidth = calcMaxWidth({boundaryWidth, currentWidth: width})
220
- const maxWidthRef = useRef(maxWidth)
221
-
222
- useEffect(() => {
223
- maxWidthRef.current = maxWidth
224
- }, [maxWidth])
225
-
226
- // Keep track of reference element width (see `size` middleware below)
227
- const referenceWidthRef = useRef<number>(undefined)
228
-
229
- // Force apply width & max width to floating element
230
- useEffect(() => {
231
- const floatingElement = ref.current
232
-
233
- if (!open || !floatingElement) return
234
-
235
- const referenceWidth = referenceWidthRef.current
236
-
237
- if (matchReferenceWidth) {
238
- if (referenceWidth !== undefined) {
239
- floatingElement.style.width = `${referenceWidth}px`
240
- }
241
- } else if (width !== undefined) {
242
- floatingElement.style.width = `${width}px`
137
+ export const Popover = forwardRef(function Popover(
138
+ props: PopoverProps &
139
+ Omit<React.HTMLProps<HTMLDivElement>, 'as' | 'children' | 'content' | 'width'>,
140
+ forwardedRef: React.ForwardedRef<HTMLDivElement>,
141
+ ): React.JSX.Element {
142
+ const {container, layer} = useTheme_v2()
143
+ const boundaryElementContext = useBoundaryElement()
144
+
145
+ const {
146
+ __unstable_margins: margins = DEFAULT_POPOVER_MARGINS,
147
+ animate: _animate = false,
148
+ arrow: arrowProp = false,
149
+ boundaryElement: _boundaryElement,
150
+ children: childProp,
151
+ constrainSize = false,
152
+ content,
153
+ disabled,
154
+ fallbackPlacements: _fallbackPlacements,
155
+ matchReferenceWidth,
156
+ floatingBoundary: _floatingBoundary,
157
+ modal,
158
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
+ onActivate,
160
+ open,
161
+ overflow = 'hidden',
162
+ padding: paddingProp,
163
+ placement: placementProp = 'bottom',
164
+ placementStrategy = 'flip',
165
+ portal,
166
+ preventOverflow = true,
167
+ radius: radiusProp = 3,
168
+ referenceBoundary: _referenceBoundary,
169
+ referenceElement,
170
+ scheme,
171
+ shadow: shadowProp = 3,
172
+ tone = 'inherit',
173
+ width: widthProp = 'auto',
174
+ zOffset: _zOffsetProp,
175
+ updateRef,
176
+ ...restProps
177
+ } = props
178
+ const boundaryElement = _boundaryElement ?? boundaryElementContext?.element
179
+ const fallbackPlacements =
180
+ _fallbackPlacements ?? DEFAULT_FALLBACK_PLACEMENTS[props.placement ?? 'bottom']
181
+ const floatingBoundary =
182
+ _floatingBoundary ?? props.boundaryElement ?? boundaryElementContext.element
183
+ const referenceBoundary =
184
+ _referenceBoundary ?? props.boundaryElement ?? boundaryElementContext.element
185
+ const zOffsetProp = _zOffsetProp ?? layer.popover.zOffset
186
+ const prefersReducedMotion = usePrefersReducedMotion()
187
+ const animate = prefersReducedMotion ? false : _animate
188
+ const boundarySize = useElementSize(boundaryElement)?.border
189
+ const padding = getArrayProp(paddingProp)
190
+ const radius = getArrayProp(radiusProp)
191
+ const shadow = getArrayProp(shadowProp)
192
+ const widthArrayProp = getArrayProp(widthProp)
193
+ const zOffset = getArrayProp(zOffsetProp)
194
+ const ref = useRef<HTMLDivElement | null>(null)
195
+ const arrowRef = useRef<HTMLDivElement | null>(null)
196
+ const rootBoundary: RootBoundary = 'viewport'
197
+
198
+ useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(forwardedRef, () => ref.current)
199
+
200
+ const mediaIndex = useMediaIndex()
201
+ const boundaryWidth = constrainSize || preventOverflow ? boundarySize?.width : undefined
202
+
203
+ // Update width when
204
+ // - media index changes
205
+ // - `width` property changes
206
+ const width = calcCurrentWidth({
207
+ container,
208
+ mediaIndex,
209
+ width: widthArrayProp,
210
+ })
211
+ const widthRef = useRef(width)
212
+
213
+ useEffect(() => {
214
+ widthRef.current = width
215
+ }, [width])
216
+
217
+ // Update max width when
218
+ // - boundary width changes
219
+ // - `width` property changes
220
+ const maxWidth = calcMaxWidth({boundaryWidth, currentWidth: width})
221
+ const maxWidthRef = useRef(maxWidth)
222
+
223
+ useEffect(() => {
224
+ maxWidthRef.current = maxWidth
225
+ }, [maxWidth])
226
+
227
+ // Keep track of reference element width (see `size` middleware below)
228
+ const referenceWidthRef = useRef<number>(undefined)
229
+
230
+ // Force apply width & max width to floating element
231
+ useEffect(() => {
232
+ const floatingElement = ref.current
233
+
234
+ if (!open || !floatingElement) return
235
+
236
+ const referenceWidth = referenceWidthRef.current
237
+
238
+ if (matchReferenceWidth) {
239
+ if (referenceWidth !== undefined) {
240
+ floatingElement.style.width = `${referenceWidth}px`
243
241
  }
242
+ } else if (width !== undefined) {
243
+ floatingElement.style.width = `${width}px`
244
+ }
244
245
 
245
- if (typeof maxWidth === 'number') {
246
- floatingElement.style.maxWidth = `${maxWidth}px`
247
- }
248
- }, [width, matchReferenceWidth, maxWidth, open])
249
-
250
- const middleware = useMemo(() => {
251
- const ret: Middleware[] = []
252
-
253
- // Flip the floating element when leaving the boundary box
254
- if (constrainSize || preventOverflow) {
255
- if (placementStrategy === 'autoPlacement') {
256
- ret.push(
257
- autoPlacement({
258
- allowedPlacements: [placementProp].concat(fallbackPlacements),
259
- }),
260
- )
261
- } else {
262
- ret.push(
263
- flip({
264
- boundary: floatingBoundary || undefined,
265
- fallbackPlacements,
266
- padding: DEFAULT_POPOVER_PADDING,
267
- rootBoundary,
268
- }),
269
- )
246
+ if (typeof maxWidth === 'number') {
247
+ floatingElement.style.maxWidth = `${maxWidth}px`
248
+ }
249
+ }, [width, matchReferenceWidth, maxWidth, open])
250
+
251
+ const [referenceWidth, setReferenceWidth] = useState<number | undefined>(undefined)
252
+ const middleware = useMiddleware({
253
+ animate,
254
+ arrowProp,
255
+ arrowRef,
256
+ constrainSize,
257
+ fallbackPlacements,
258
+ floatingBoundary,
259
+ margins,
260
+ matchReferenceWidth,
261
+ maxWidthRef,
262
+ placementProp,
263
+ placementStrategy,
264
+ preventOverflow,
265
+ referenceBoundary,
266
+ referenceWidthRef,
267
+ rootBoundary,
268
+ setReferenceWidth,
269
+ widthRef,
270
+ })
271
+
272
+ const {x, y, middlewareData, placement, refs, strategy, update} = useFloating({
273
+ middleware,
274
+ placement: placementProp,
275
+ whileElementsMounted: autoUpdate,
276
+ elements: referenceElement
277
+ ? {
278
+ reference: referenceElement,
270
279
  }
271
- }
272
-
273
- // Define distance between reference and floating element
274
- ret.push(offset({mainAxis: DEFAULT_POPOVER_DISTANCE}))
275
-
276
- // Track sizes
277
- if (constrainSize || matchReferenceWidth) {
280
+ : undefined,
281
+ })
282
+
283
+ const referenceHidden = middlewareData.hide?.referenceHidden
284
+
285
+ const arrowX = middlewareData.arrow?.x
286
+ const arrowY = middlewareData.arrow?.y
287
+
288
+ const originX = middlewareData['@sanity/ui/origin']?.originX
289
+ const originY = middlewareData['@sanity/ui/origin']?.originY
290
+
291
+ const setArrow = useCallback((arrowEl: HTMLDivElement | null) => {
292
+ arrowRef.current = arrowEl
293
+ }, [])
294
+
295
+ const setFloating = useCallback(
296
+ (node: HTMLDivElement | null) => {
297
+ ref.current = node
298
+ refs.setFloating(node)
299
+ },
300
+ [refs],
301
+ )
302
+
303
+ // If there's a child then we need to set the reference element to the cloned child ref
304
+ // and if child changes we make sure to update or remove the reference element.
305
+ useImperativeHandle(childProp ? getElementRef(childProp) : null, () => refs.reference.current)
306
+
307
+ const child = useMemo(() => {
308
+ // If a reference element is defined, we don't need to clone the child
309
+ if (referenceElement) return childProp
310
+
311
+ if (!childProp) return null
312
+
313
+ return cloneElement(childProp, {ref: refs.setReference})
314
+ }, [childProp, referenceElement, refs.setReference])
315
+
316
+ useImperativeHandle(updateRef, () => update, [update])
317
+
318
+ if (disabled) {
319
+ return childProp || <></>
320
+ }
321
+
322
+ const popover = (
323
+ <LayerProvider zOffset={zOffset}>
324
+ {/* Optional transparent blocking overlay at the top-most z-index layer. Must be positioned before the below popover card. */}
325
+ {modal && <ViewportOverlay />}
326
+
327
+ <PopoverCard
328
+ {...restProps}
329
+ __unstable_margins={margins}
330
+ animate={animate}
331
+ arrow={arrowProp}
332
+ arrowRef={setArrow}
333
+ arrowX={arrowX}
334
+ arrowY={arrowY}
335
+ hidden={referenceHidden}
336
+ overflow={overflow}
337
+ padding={padding}
338
+ placement={placement}
339
+ radius={radius}
340
+ ref={setFloating}
341
+ scheme={scheme}
342
+ shadow={shadow}
343
+ originX={originX}
344
+ originY={originY}
345
+ strategy={strategy}
346
+ tone={tone}
347
+ width={matchReferenceWidth ? referenceWidth : width}
348
+ x={x}
349
+ y={y}
350
+ >
351
+ {content}
352
+ </PopoverCard>
353
+ </LayerProvider>
354
+ )
355
+
356
+ const children =
357
+ open &&
358
+ (portal ? (
359
+ <Portal __unstable_name={typeof portal === 'string' ? portal : undefined}>{popover}</Portal>
360
+ ) : (
361
+ popover
362
+ ))
363
+
364
+ return (
365
+ <>
366
+ {/* the popover */}
367
+ {animate ? <AnimatePresence>{children}</AnimatePresence> : children}
368
+
369
+ {/* the referred element */}
370
+ {child}
371
+ </>
372
+ )
373
+ })
374
+ Popover.displayName = 'ForwardRef(Popover)'
375
+
376
+ function useMiddleware({
377
+ animate,
378
+ arrowProp,
379
+ arrowRef,
380
+ constrainSize,
381
+ fallbackPlacements,
382
+ floatingBoundary,
383
+ margins,
384
+ matchReferenceWidth,
385
+ maxWidthRef,
386
+ placementProp,
387
+ placementStrategy,
388
+ preventOverflow,
389
+ referenceBoundary,
390
+ referenceWidthRef,
391
+ rootBoundary,
392
+ setReferenceWidth,
393
+ widthRef,
394
+ }: {
395
+ animate: boolean
396
+ arrowProp: boolean
397
+ arrowRef: React.RefObject<HTMLDivElement | null>
398
+ constrainSize: boolean
399
+ fallbackPlacements: Placement[]
400
+ floatingBoundary: HTMLElement | null
401
+ margins: PopoverMargins
402
+ matchReferenceWidth: boolean | undefined
403
+ maxWidthRef: React.RefObject<number | undefined>
404
+ placementProp: Placement
405
+ placementStrategy: 'flip' | 'autoPlacement'
406
+ preventOverflow: boolean
407
+ referenceBoundary: HTMLElement | null
408
+ referenceWidthRef: React.RefObject<number | undefined>
409
+ rootBoundary: RootBoundary
410
+ setReferenceWidth: (referenceWidth: number) => void
411
+ widthRef: React.RefObject<number | undefined>
412
+ }) {
413
+ return useMemo(() => {
414
+ const ret: Middleware[] = []
415
+
416
+ // Flip the floating element when leaving the boundary box
417
+ if (constrainSize || preventOverflow) {
418
+ if (placementStrategy === 'autoPlacement') {
278
419
  ret.push(
279
- size({
280
- apply({availableWidth, availableHeight, elements, referenceWidth}) {
281
- // not fresh, so use refs
282
-
283
- referenceWidthRef.current = referenceWidth
284
-
285
- const _currentWidth = widthRef.current
286
- const _maxWidth = maxWidthRef.current
287
-
288
- if (matchReferenceWidth) {
289
- elements.floating.style.width = `${referenceWidth}px`
290
- } else if (_currentWidth !== undefined) {
291
- elements.floating.style.width = `${_currentWidth}px`
292
- }
293
-
294
- if (constrainSize) {
295
- elements.floating.style.maxWidth = `${Math.min(
296
- availableWidth,
297
- _maxWidth ?? Infinity,
298
- )}px`
299
-
300
- elements.floating.style.maxHeight = `${availableHeight}px`
301
- }
302
- },
303
- boundaryElement: floatingBoundary || undefined,
304
- constrainSize,
305
- margins,
306
- matchReferenceWidth,
307
- padding: DEFAULT_POPOVER_PADDING,
420
+ autoPlacement({
421
+ allowedPlacements: [placementProp].concat(fallbackPlacements),
308
422
  }),
309
423
  )
310
- }
311
-
312
- // Shift the popover so its sits within the boundary element
313
- if (preventOverflow) {
424
+ } else {
314
425
  ret.push(
315
- shift({
426
+ flip({
316
427
  boundary: floatingBoundary || undefined,
317
- rootBoundary,
318
- padding: DEFAULT_POPOVER_PADDING,
319
- }),
320
- )
321
- }
322
-
323
- // Place arrow
324
- if (arrowProp) {
325
- ret.push(
326
- arrow({
327
- element: arrowRef,
428
+ fallbackPlacements,
328
429
  padding: DEFAULT_POPOVER_PADDING,
430
+ rootBoundary,
329
431
  }),
330
432
  )
331
433
  }
434
+ }
332
435
 
333
- // Determine the origin to scale from.
334
- // Must be placed after `@sanity/ui/size` and `shift` middleware.
335
- if (animate) {
336
- ret.push(origin)
337
- }
436
+ // Define distance between reference and floating element
437
+ ret.push(offset({mainAxis: DEFAULT_POPOVER_DISTANCE}))
338
438
 
439
+ // Track sizes
440
+ if (constrainSize || matchReferenceWidth) {
339
441
  ret.push(
340
- hide({
341
- boundary: referenceBoundary || undefined,
442
+ size({
443
+ boundaryElement: floatingBoundary || undefined,
444
+ constrainSize,
445
+ margins,
446
+ matchReferenceWidth,
447
+ maxWidthRef,
342
448
  padding: DEFAULT_POPOVER_PADDING,
343
- strategy: 'referenceHidden',
449
+ referenceWidthRef,
450
+ setReferenceWidth,
451
+ widthRef,
344
452
  }),
345
453
  )
454
+ }
346
455
 
347
- return ret
348
- }, [
349
- animate,
350
- arrowProp,
351
- constrainSize,
352
- fallbackPlacements,
353
- placementProp,
354
- placementStrategy,
355
- floatingBoundary,
356
- margins,
357
- matchReferenceWidth,
358
- preventOverflow,
359
- referenceBoundary,
360
- ])
361
-
362
- const {x, y, middlewareData, placement, refs, strategy, update} = useFloating({
363
- middleware,
364
- placement: placementProp,
365
- whileElementsMounted: autoUpdate,
366
- elements: referenceElement
367
- ? {
368
- reference: referenceElement,
369
- }
370
- : undefined,
371
- })
372
-
373
- const referenceHidden = middlewareData.hide?.referenceHidden
374
-
375
- const arrowX = middlewareData.arrow?.x
376
- const arrowY = middlewareData.arrow?.y
377
-
378
- const originX = middlewareData['@sanity/ui/origin']?.originX
379
- const originY = middlewareData['@sanity/ui/origin']?.originY
380
-
381
- const setArrow = useCallback((arrowEl: HTMLDivElement | null) => {
382
- arrowRef.current = arrowEl
383
- }, [])
384
-
385
- const setFloating = useCallback(
386
- (node: HTMLDivElement | null) => {
387
- ref.current = node
388
- refs.setFloating(node)
389
- },
390
- [refs],
391
- )
392
-
393
- const setReference = useCallback(
394
- (node: HTMLElement | null) => {
395
- refs.setReference(node)
396
-
397
- const childRef = getElementRef(childProp as any)
398
-
399
- if (typeof childRef === 'function') {
400
- childRef(node)
401
- } else if (childRef) {
402
- childRef.current = node
403
- }
404
- },
405
- [childProp, refs],
406
- )
407
-
408
- const child = useMemo(() => {
409
- // If a reference element is defined, we don't need to clone the child
410
- if (referenceElement) return childProp
411
-
412
- if (!childProp) return null
413
-
414
- return cloneElement(childProp, {ref: setReference})
415
- }, [childProp, referenceElement, setReference])
456
+ // Shift the popover so its sits within the boundary element
457
+ if (preventOverflow) {
458
+ ret.push(
459
+ shift({
460
+ boundary: floatingBoundary || undefined,
461
+ rootBoundary,
462
+ padding: DEFAULT_POPOVER_PADDING,
463
+ }),
464
+ )
465
+ }
416
466
 
417
- useEffect(() => {
418
- if (updateRef) {
419
- if (typeof updateRef === 'function') {
420
- updateRef(update)
421
- } else if (updateRef) {
422
- updateRef.current = update
423
- }
424
- }
425
- }, [update, updateRef])
467
+ // Place arrow
468
+ if (arrowProp) {
469
+ ret.push(
470
+ arrow({
471
+ element: arrowRef,
472
+ padding: DEFAULT_POPOVER_PADDING,
473
+ }),
474
+ )
475
+ }
426
476
 
427
- if (disabled) {
428
- return childProp || <></>
477
+ // Determine the origin to scale from.
478
+ // Must be placed after `@sanity/ui/size` and `shift` middleware.
479
+ if (animate) {
480
+ ret.push(origin)
429
481
  }
430
482
 
431
- const popover = (
432
- <LayerProvider zOffset={zOffset}>
433
- {/* Optional transparent blocking overlay at the top-most z-index layer. Must be positioned before the below popover card. */}
434
- {modal && <ViewportOverlay />}
435
-
436
- <PopoverCard
437
- {...restProps}
438
- __unstable_margins={margins}
439
- animate={animate}
440
- arrow={arrowProp}
441
- arrowRef={setArrow}
442
- arrowX={arrowX}
443
- arrowY={arrowY}
444
- hidden={referenceHidden}
445
- overflow={overflow}
446
- padding={padding}
447
- placement={placement}
448
- radius={radius}
449
- ref={setFloating}
450
- scheme={scheme}
451
- shadow={shadow}
452
- originX={originX}
453
- originY={originY}
454
- strategy={strategy}
455
- tone={tone}
456
- width={matchReferenceWidth ? referenceWidthRef.current : width}
457
- x={x}
458
- y={y}
459
- >
460
- {content}
461
- </PopoverCard>
462
- </LayerProvider>
483
+ ret.push(
484
+ hide({
485
+ boundary: referenceBoundary || undefined,
486
+ padding: DEFAULT_POPOVER_PADDING,
487
+ strategy: 'referenceHidden',
488
+ }),
463
489
  )
464
490
 
465
- const children =
466
- open &&
467
- (portal ? (
468
- <Portal __unstable_name={typeof portal === 'string' ? portal : undefined}>{popover}</Portal>
469
- ) : (
470
- popover
471
- ))
472
-
473
- return (
474
- <>
475
- {/* the popover */}
476
- {animate ? <AnimatePresence>{children}</AnimatePresence> : children}
477
-
478
- {/* the referred element */}
479
- {child}
480
- </>
481
- )
482
- }),
483
- )
484
- Popover.displayName = 'Memo(ForwardRef(Popover))'
491
+ return ret
492
+ }, [
493
+ animate,
494
+ arrowProp,
495
+ arrowRef,
496
+ constrainSize,
497
+ fallbackPlacements,
498
+ floatingBoundary,
499
+ margins,
500
+ matchReferenceWidth,
501
+ maxWidthRef,
502
+ placementProp,
503
+ placementStrategy,
504
+ preventOverflow,
505
+ referenceBoundary,
506
+ referenceWidthRef,
507
+ rootBoundary,
508
+ setReferenceWidth,
509
+ widthRef,
510
+ ])
511
+ }