@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.
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +75 -44
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +74 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/autocomplete/autocomplete.tsx +1 -1
- package/src/components/toast/toast.tsx +8 -3
- package/src/primitives/badge/styles.ts +3 -1
- package/src/primitives/tooltip/__workshop__/customPortal.tsx +99 -0
- package/src/primitives/tooltip/__workshop__/index.ts +15 -0
- package/src/primitives/tooltip/__workshop__/overflowingBoundary.tsx +73 -0
- package/src/primitives/tooltip/__workshop__/resizableBoundary.tsx +85 -0
- package/src/primitives/tooltip/constants.ts +2 -0
- package/src/primitives/tooltip/tooltip.test.tsx +125 -0
- package/src/primitives/tooltip/tooltip.tsx +93 -32
|
@@ -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 {
|
|
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:
|
|
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:
|
|
138
|
+
ret.push(offset({mainAxis: DEFAULT_TOOLTIP_DISTANCE}))
|
|
118
139
|
|
|
119
|
-
//
|
|
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:
|
|
145
|
+
padding: DEFAULT_TOOLTIP_PADDING,
|
|
137
146
|
}),
|
|
138
147
|
)
|
|
139
148
|
|
|
140
149
|
// Place arrow
|
|
141
|
-
|
|
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(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
}, [
|
|
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
|
-
{
|
|
346
|
-
<Portal __unstable_name={typeof
|
|
406
|
+
{portalProp ? (
|
|
407
|
+
<Portal __unstable_name={typeof portalProp === 'string' ? portalProp : undefined}>
|
|
347
408
|
{root}
|
|
348
409
|
</Portal>
|
|
349
410
|
) : (
|