@sanity/ui 2.0.0-alpha.20 → 2.0.0-alpha.22

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.
@@ -8,7 +8,6 @@ import {
8
8
  useFloating,
9
9
  Middleware,
10
10
  RootBoundary,
11
- size,
12
11
  } from '@floating-ui/react-dom'
13
12
  import {
14
13
  cloneElement,
@@ -28,10 +27,14 @@ import {useArrayProp, useForwardedRef} from '../../hooks'
28
27
  import {useDelayedState} from '../../hooks/useDelayedState'
29
28
  import {ThemeColorSchemeKey, useTheme} from '../../theme'
30
29
  import {Placement} from '../../types'
31
- import {Layer, LayerProps, Portal, useBoundaryElement} from '../../utils'
30
+ import {Layer, LayerProps, Portal, useBoundaryElement, usePortal} from '../../utils'
32
31
  import {Card} from '../card'
33
32
  import {Delay} from '../types'
34
- import {DEFAULT_FALLBACK_PLACEMENTS} from './constants'
33
+ import {
34
+ DEFAULT_FALLBACK_PLACEMENTS,
35
+ DEFAULT_TOOLTIP_DISTANCE,
36
+ DEFAULT_TOOLTIP_PADDING,
37
+ } from './constants'
35
38
  import {TooltipArrow} from './tooltipArrow'
36
39
  import {useTooltipDelayGroup} from './tooltipDelayGroup'
37
40
 
@@ -41,6 +44,7 @@ import {useTooltipDelayGroup} from './tooltipDelayGroup'
41
44
  export interface TooltipProps extends Omit<LayerProps, 'as'> {
42
45
  /** @deprecated Use `fallbackPlacements` instead. */
43
46
  allowedAutoPlacements?: Placement[]
47
+ arrow?: boolean
44
48
  boundaryElement?: HTMLElement | null
45
49
  children?: React.ReactElement
46
50
  content?: React.ReactNode
@@ -62,8 +66,9 @@ export interface TooltipProps extends Omit<LayerProps, 'as'> {
62
66
  delay?: Delay
63
67
  }
64
68
 
65
- const Root = styled(Layer)`
69
+ const Root = styled(Layer)<{$maxWidth: number}>`
66
70
  pointer-events: none;
71
+ max-width: ${({$maxWidth}) => $maxWidth}px;
67
72
  `
68
73
 
69
74
  /**
@@ -78,6 +83,7 @@ export const Tooltip = forwardRef(function Tooltip(
78
83
  const boundaryElementContext = useBoundaryElement()
79
84
  const theme = useTheme()
80
85
  const {
86
+ arrow: arrowProp = true,
81
87
  boundaryElement = boundaryElementContext?.element,
82
88
  children: childProp,
83
89
  content,
@@ -86,7 +92,7 @@ export const Tooltip = forwardRef(function Tooltip(
86
92
  DEFAULT_FALLBACK_PLACEMENTS[props.placement ?? 'bottom'],
87
93
  padding = 3,
88
94
  placement: placementProp = 'bottom',
89
- portal,
95
+ portal: portalProp,
90
96
  scheme,
91
97
  shadow = 2,
92
98
  zOffset = theme.sanity.layer?.tooltip.zOffset,
@@ -99,6 +105,22 @@ export const Tooltip = forwardRef(function Tooltip(
99
105
  const arrowRef = useRef<HTMLDivElement | null>(null)
100
106
  const rootBoundary: RootBoundary = 'viewport'
101
107
 
108
+ const portal = usePortal()
109
+ const portalElement =
110
+ typeof portalProp === 'string' ? portal.elements?.[portalProp] || null : portal.element
111
+
112
+ // Get the maximum tooltip width (sans tooltip padding)
113
+ // Tooltip width should never exceed the width of either any supplied boundary or portal element.
114
+ // If both portal and boundary elements are provided, use the smaller width of the two.
115
+ const tooltipWidth = useMemo(() => {
116
+ const availableWidths = [
117
+ ...(boundaryElement ? [boundaryElement.offsetWidth] : []),
118
+ portalElement?.offsetWidth || document.body.offsetWidth,
119
+ ]
120
+
121
+ return Math.min(...availableWidths) - DEFAULT_TOOLTIP_PADDING * 2
122
+ }, [boundaryElement, portalElement?.offsetWidth])
123
+
102
124
  const middleware = useMemo(() => {
103
125
  const ret: Middleware[] = []
104
126
 
@@ -107,41 +129,30 @@ export const Tooltip = forwardRef(function Tooltip(
107
129
  flip({
108
130
  boundary: boundaryElement || undefined,
109
131
  fallbackPlacements,
110
- padding: 4,
132
+ padding: DEFAULT_TOOLTIP_PADDING,
111
133
  rootBoundary,
112
- mainAxis: false,
113
134
  }),
114
135
  )
115
136
 
116
137
  // Define distance between reference and floating element
117
- ret.push(offset({mainAxis: 3}))
138
+ ret.push(offset({mainAxis: DEFAULT_TOOLTIP_DISTANCE}))
118
139
 
119
- // Set width and height on the floating element
120
- ret.push(
121
- size({
122
- apply({availableWidth, availableHeight, elements}) {
123
- Object.assign(elements.floating.style, {
124
- maxWidth: `${availableWidth - 4 * 2}px`, // the padding is `4px`
125
- maxHeight: `${availableHeight - 4 * 2}px`, // the padding is `4px`
126
- })
127
- },
128
- }),
129
- )
130
-
131
- // Shift the tooltip so its sits with the boundary eleement
140
+ // Shift the tooltip so its sits with the boundary element
132
141
  ret.push(
133
142
  shift({
134
143
  boundary: boundaryElement || undefined,
135
144
  rootBoundary,
136
- padding: 4,
145
+ padding: DEFAULT_TOOLTIP_PADDING,
137
146
  }),
138
147
  )
139
148
 
140
149
  // Place arrow
141
- ret.push(arrow({element: arrowRef, padding: 2}))
150
+ if (arrowProp) {
151
+ ret.push(arrow({element: arrowRef, padding: 2}))
152
+ }
142
153
 
143
154
  return ret
144
- }, [boundaryElement, fallbackPlacements])
155
+ }, [arrowProp, boundaryElement, fallbackPlacements])
145
156
 
146
157
  const {floatingStyles, placement, middlewareData, refs, update} = useFloating({
147
158
  middleware,
@@ -206,10 +217,48 @@ export const Tooltip = forwardRef(function Tooltip(
206
217
  [isInsideGroup, delayGroupContext, openDelay, tooltipId, closeDelay, setIsOpen],
207
218
  )
208
219
 
209
- const handleBlur = useCallback(() => handleIsOpenChange(false), [handleIsOpenChange])
210
- const handleFocus = useCallback(() => handleIsOpenChange(true), [handleIsOpenChange])
211
- const handleMouseEnter = useCallback(() => handleIsOpenChange(true), [handleIsOpenChange])
212
- const handleMouseLeave = useCallback(() => handleIsOpenChange(false), [handleIsOpenChange])
220
+ const handleBlur = useCallback(
221
+ (e: FocusEvent) => {
222
+ handleIsOpenChange(false)
223
+ childProp?.props?.onBlur?.(e)
224
+ },
225
+ [childProp?.props, handleIsOpenChange],
226
+ )
227
+ const handleClick = useCallback(
228
+ (e: MouseEvent) => {
229
+ handleIsOpenChange(false, true), [handleIsOpenChange]
230
+ childProp?.props.onClick?.(e)
231
+ },
232
+ [childProp?.props, handleIsOpenChange],
233
+ )
234
+ const handleContextMenu = useCallback(
235
+ (e: MouseEvent) => {
236
+ handleIsOpenChange(false, true), [handleIsOpenChange]
237
+ childProp?.props.onContextMenu?.(e)
238
+ },
239
+ [childProp?.props, handleIsOpenChange],
240
+ )
241
+ const handleFocus = useCallback(
242
+ (e: FocusEvent) => {
243
+ handleIsOpenChange(true)
244
+ childProp?.props?.onFocus?.(e)
245
+ },
246
+ [childProp?.props, handleIsOpenChange],
247
+ )
248
+ const handleMouseEnter = useCallback(
249
+ (e: MouseEvent) => {
250
+ handleIsOpenChange(true)
251
+ childProp?.props?.onMouseEnter?.(e)
252
+ },
253
+ [childProp?.props, handleIsOpenChange],
254
+ )
255
+ const handleMouseLeave = useCallback(
256
+ (e: MouseEvent) => {
257
+ handleIsOpenChange(false)
258
+ childProp?.props?.onMouseLeave?.(e)
259
+ },
260
+ [childProp?.props, handleIsOpenChange],
261
+ )
213
262
 
214
263
  // Detect whether the mouse is moving outside of the reference element. This is sometimes
215
264
  // necessary, because the tooltip might not always close as it should (e.g. when clicking
@@ -306,9 +355,20 @@ export const Tooltip = forwardRef(function Tooltip(
306
355
  onFocus: handleFocus,
307
356
  onMouseEnter: handleMouseEnter,
308
357
  onMouseLeave: handleMouseLeave,
358
+ onClick: handleClick,
359
+ onContextMenu: handleContextMenu,
309
360
  ref: setReference,
310
361
  })
311
- }, [childProp, handleBlur, handleFocus, handleMouseEnter, handleMouseLeave, setReference])
362
+ }, [
363
+ childProp,
364
+ handleBlur,
365
+ handleClick,
366
+ handleContextMenu,
367
+ handleFocus,
368
+ handleMouseEnter,
369
+ handleMouseLeave,
370
+ setReference,
371
+ ])
312
372
 
313
373
  if (!child) return <></>
314
374
 
@@ -321,6 +381,7 @@ export const Tooltip = forwardRef(function Tooltip(
321
381
  ref={setFloating}
322
382
  style={floatingStyles}
323
383
  zOffset={zOffset}
384
+ $maxWidth={tooltipWidth}
324
385
  >
325
386
  <Card
326
387
  data-ui="Tooltip__card"
@@ -331,7 +392,7 @@ export const Tooltip = forwardRef(function Tooltip(
331
392
  shadow={shadow}
332
393
  >
333
394
  {content}
334
- <TooltipArrow ref={setArrow} style={arrowStyle} />
395
+ {arrowProp && <TooltipArrow ref={setArrow} style={arrowStyle} />}
335
396
  </Card>
336
397
  </Root>
337
398
  )
@@ -342,8 +403,8 @@ export const Tooltip = forwardRef(function Tooltip(
342
403
 
343
404
  {showTooltip && (
344
405
  <>
345
- {portal ? (
346
- <Portal __unstable_name={typeof portal === 'string' ? portal : undefined}>
406
+ {portalProp ? (
407
+ <Portal __unstable_name={typeof portalProp === 'string' ? portalProp : undefined}>
347
408
  {root}
348
409
  </Portal>
349
410
  ) : (