@sanity/ui 2.6.4 → 2.6.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.6.4",
3
+ "version": "2.6.6",
4
4
  "keywords": [
5
5
  "sanity",
6
6
  "ui",
@@ -21,12 +21,12 @@ import {
21
21
  useState,
22
22
  useId,
23
23
  useImperativeHandle,
24
+ useLayoutEffect,
24
25
  } from 'react'
25
26
  import {styled} from 'styled-components'
26
27
  import {useEffectEvent} from 'use-effect-event'
27
28
  import {useArrayProp, usePrefersReducedMotion} from '../../hooks'
28
29
  import {useDelayedState} from '../../hooks/useDelayedState'
29
- import {useMounted} from '../../hooks/useMounted'
30
30
  import {origin} from '../../middleware/origin'
31
31
  import {useTheme_v2} from '../../theme'
32
32
  import type {Placement} from '../../types'
@@ -86,9 +86,8 @@ export interface TooltipProps extends Omit<LayerProps, 'as'> {
86
86
  animate?: boolean
87
87
  }
88
88
 
89
- const Root = styled(Layer)<{$maxWidth: number}>`
89
+ const Root = styled(Layer)`
90
90
  pointer-events: none;
91
- max-width: ${({$maxWidth}) => $maxWidth}px;
92
91
  `
93
92
 
94
93
  /**
@@ -128,6 +127,7 @@ export const Tooltip = forwardRef(function Tooltip(
128
127
  const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null)
129
128
  const arrowRef = useRef<HTMLDivElement | null>(null)
130
129
  const rootBoundary: RootBoundary = 'viewport'
130
+ const [tooltipMaxWidth, setTooltipMaxWidth] = useState(0)
131
131
 
132
132
  useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(forwardedRef, () => ref.current)
133
133
 
@@ -135,22 +135,6 @@ export const Tooltip = forwardRef(function Tooltip(
135
135
  const portalElement =
136
136
  typeof portalProp === 'string' ? portal.elements?.[portalProp] || null : portal.element
137
137
 
138
- const mounted = useMounted()
139
- // Get the maximum tooltip width (sans tooltip padding)
140
- // Tooltip width should never exceed the width of either any supplied boundary or portal element.
141
- // If both portal and boundary elements are provided, use the smaller width of the two.
142
- const tooltipWidth = useMemo(() => {
143
- const availableWidths = [
144
- ...(boundaryElement ? [boundaryElement.offsetWidth] : []),
145
- portalElement?.offsetWidth || mounted
146
- ? document.body.offsetWidth
147
- : // We don't actually know what the width of the body is during SSR, so we'll just assume it's 800px or larger
148
- 800,
149
- ]
150
-
151
- return Math.min(...availableWidths) - DEFAULT_TOOLTIP_PADDING * 2
152
- }, [boundaryElement, mounted, portalElement])
153
-
154
138
  const middleware = useMemo(() => {
155
139
  const ret: Middleware[] = []
156
140
 
@@ -284,6 +268,9 @@ export const Tooltip = forwardRef(function Tooltip(
284
268
  [childProp?.props, handleIsOpenChange],
285
269
  )
286
270
 
271
+ // Handle closing the tooltip when the mouse leaves the referenceElement
272
+ useCloseOnMouseLeave({handleIsOpenChange, referenceElement, showTooltip})
273
+
287
274
  // Close when `disabled` changes to `true`
288
275
  useEffect(() => {
289
276
  if (disabled && showTooltip) handleIsOpenChange(false)
@@ -314,8 +301,18 @@ export const Tooltip = forwardRef(function Tooltip(
314
301
  }
315
302
  }, [handleIsOpenChange, showTooltip])
316
303
 
317
- // Handle closing the tooltip when the mouse leaves the referenceElement
318
- useCloseOnMouseLeave({handleIsOpenChange, referenceElement, showTooltip})
304
+ // // Set the max width of the tooltip based on boundaries and portals
305
+ useLayoutEffect(() => {
306
+ // Get the maximum tooltip width (sans tooltip padding)
307
+ // Tooltip width should never exceed the width of either any supplied boundary or portal element.
308
+ // If both portal and boundary elements are provided, use the smaller width of the two.
309
+ const availableWidths = [
310
+ ...(boundaryElement ? [boundaryElement.offsetWidth] : []),
311
+ portalElement?.offsetWidth || document.body.offsetWidth,
312
+ ]
313
+
314
+ setTooltipMaxWidth(Math.min(...availableWidths) - DEFAULT_TOOLTIP_PADDING * 2)
315
+ }, [boundaryElement, portalElement])
319
316
 
320
317
  const setArrow = useCallback(
321
318
  (arrowEl: HTMLDivElement | null) => {
@@ -379,9 +376,11 @@ export const Tooltip = forwardRef(function Tooltip(
379
376
  data-ui="Tooltip"
380
377
  {...restProps}
381
378
  ref={setFloating}
382
- style={floatingStyles}
379
+ style={{
380
+ ...floatingStyles,
381
+ maxWidth: tooltipMaxWidth > 0 ? `${tooltipMaxWidth}px` : undefined,
382
+ }}
383
383
  zOffset={zOffset}
384
- $maxWidth={tooltipWidth}
385
384
  >
386
385
  <TooltipCard
387
386
  {...restProps}
@@ -447,15 +446,16 @@ function useCloseOnMouseLeave({
447
446
  // Since we don't want the `mouseevent` events to be attached and removed if the `referenceElement` is changed
448
447
  // we use a "effect event" (https://19.react.dev/learn/separating-events-from-effects#reading-latest-props-and-state-with-effect-events)
449
448
  // in order to always see the latest `referenceElement` value inside the event handler itself.
450
- const handleWindowMouseMove = useEffectEvent((event: MouseEvent) => {
449
+ const onMouseMove = useEffectEvent((target: EventTarget | null, teardown: () => void) => {
451
450
  if (!referenceElement) return
452
451
 
453
452
  const isHoveringReference =
454
- referenceElement === event.target ||
455
- (event.target instanceof Node && referenceElement.contains(event.target))
453
+ referenceElement === target || (target instanceof Node && referenceElement.contains(target))
456
454
 
457
455
  if (!isHoveringReference) {
458
456
  handleIsOpenChange(false)
457
+ // Allow removing the event listener eagerly, to avoid race conditions
458
+ teardown()
459
459
  }
460
460
  })
461
461
 
@@ -465,8 +465,12 @@ function useCloseOnMouseLeave({
465
465
  useEffect(() => {
466
466
  if (!showTooltip) return
467
467
 
468
- window.addEventListener('mousemove', handleWindowMouseMove)
468
+ const handleMouseMove = (event: MouseEvent) => {
469
+ onMouseMove(event.target, () => window.removeEventListener('mousemove', handleMouseMove))
470
+ }
471
+
472
+ window.addEventListener('mousemove', handleMouseMove)
469
473
 
470
- return () => window.removeEventListener('mousemove', handleWindowMouseMove)
471
- }, [handleWindowMouseMove, showTooltip])
474
+ return () => window.removeEventListener('mousemove', handleMouseMove)
475
+ }, [onMouseMove, showTooltip])
472
476
  }