@sanity/ui 2.0.0-alpha.24 → 2.0.0-alpha.26
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 +21 -2
- package/dist/index.esm.js +292 -238
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +292 -238
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/dialog/dialog.tsx +14 -5
- package/src/components/dialog/styles.ts +39 -0
- package/src/primitives/tooltip/conditionalWrapper.tsx +15 -0
- package/src/primitives/tooltip/constants.ts +12 -12
- package/src/primitives/tooltip/tooltip.tsx +54 -23
- package/src/primitives/tooltip/tooltipDelayGroup/tooltipDelayGroupProvider.tsx +3 -1
package/package.json
CHANGED
|
@@ -16,6 +16,8 @@ import {DialogPosition, Radius} from '../../types'
|
|
|
16
16
|
import {Layer, LayerProps, Portal, useBoundaryElement, useLayer, usePortal} from '../../utils'
|
|
17
17
|
import {BORDER_OFFSET_X} from './constants'
|
|
18
18
|
import {
|
|
19
|
+
animationDialogStyle,
|
|
20
|
+
AnimationDialogStyleProps,
|
|
19
21
|
dialogStyle,
|
|
20
22
|
responsiveDialogPositionStyle,
|
|
21
23
|
ResponsiveDialogPositionStyleProps,
|
|
@@ -48,6 +50,13 @@ export interface DialogProps extends ResponsivePaddingProps, ResponsiveWidthProp
|
|
|
48
50
|
position?: DialogPosition | DialogPosition[]
|
|
49
51
|
scheme?: ThemeColorSchemeKey
|
|
50
52
|
zOffset?: number | number[]
|
|
53
|
+
/**
|
|
54
|
+
* Whether the dialog should animate in on mount.
|
|
55
|
+
*
|
|
56
|
+
* @beta
|
|
57
|
+
* @defaultValue false
|
|
58
|
+
*/
|
|
59
|
+
animate?: boolean
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
interface DialogCardProps extends ResponsiveWidthProps {
|
|
@@ -94,11 +103,9 @@ function isTargetWithinScope(
|
|
|
94
103
|
)
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
const Root = styled(Layer)<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
responsiveDialogPositionStyle,
|
|
101
|
-
)
|
|
106
|
+
const Root = styled(Layer)<
|
|
107
|
+
ResponsiveDialogPositionStyleProps & ResponsivePaddingStyleProps & AnimationDialogStyleProps
|
|
108
|
+
>(responsivePaddingStyle, dialogStyle, responsiveDialogPositionStyle, animationDialogStyle)
|
|
102
109
|
|
|
103
110
|
const DialogContainer = styled(Container)`
|
|
104
111
|
&:not([hidden]) {
|
|
@@ -382,6 +389,7 @@ export const Dialog = forwardRef(function Dialog(
|
|
|
382
389
|
scheme,
|
|
383
390
|
width: widthProp = 0,
|
|
384
391
|
zOffset: zOffsetProp = dialog.zOffset || theme.sanity.layer?.dialog.zOffset,
|
|
392
|
+
animate = false,
|
|
385
393
|
...restProps
|
|
386
394
|
} = props
|
|
387
395
|
const portal = usePortal()
|
|
@@ -470,6 +478,7 @@ export const Dialog = forwardRef(function Dialog(
|
|
|
470
478
|
ref={ref}
|
|
471
479
|
role="dialog"
|
|
472
480
|
zOffset={zOffset}
|
|
481
|
+
animate={animate}
|
|
473
482
|
>
|
|
474
483
|
<div ref={preDivRef} tabIndex={0} />
|
|
475
484
|
<DialogCard
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {css} from 'styled-components'
|
|
1
2
|
import {_responsive, ThemeProps} from '../../styles'
|
|
2
3
|
import {DialogPosition} from '../../types'
|
|
3
4
|
import {CSSObject} from '../../types/styled'
|
|
@@ -36,3 +37,41 @@ export function responsiveDialogPositionStyle(
|
|
|
36
37
|
|
|
37
38
|
return _responsive(media, props.$position, (position) => ({'&&': {position}}))
|
|
38
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export interface AnimationDialogStyleProps {
|
|
45
|
+
animate: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function animationDialogStyle(props: AnimationDialogStyleProps): ReturnType<typeof css> {
|
|
49
|
+
if (!props.animate) return css``
|
|
50
|
+
|
|
51
|
+
return css`
|
|
52
|
+
@keyframes zoomIn {
|
|
53
|
+
from {
|
|
54
|
+
opacity: 0;
|
|
55
|
+
transform: scale(0.95);
|
|
56
|
+
}
|
|
57
|
+
to {
|
|
58
|
+
opacity: 1;
|
|
59
|
+
transform: scale(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
@keyframes fadeIn {
|
|
63
|
+
from {
|
|
64
|
+
opacity: 0;
|
|
65
|
+
}
|
|
66
|
+
to {
|
|
67
|
+
opacity: 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
animation: fadeIn 200ms ease-out;
|
|
72
|
+
// Animates the dialog card.
|
|
73
|
+
& > [data-ui='DialogCard'] {
|
|
74
|
+
animation: zoomIn 200ms ease-out;
|
|
75
|
+
}
|
|
76
|
+
`
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function ConditionalWrapper({
|
|
2
|
+
children,
|
|
3
|
+
condition,
|
|
4
|
+
wrapper,
|
|
5
|
+
}: {
|
|
6
|
+
children: React.ReactNode
|
|
7
|
+
condition: boolean
|
|
8
|
+
wrapper: (children: React.ReactNode) => React.ReactNode
|
|
9
|
+
}): React.ReactNode {
|
|
10
|
+
if (!condition) {
|
|
11
|
+
return children
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return wrapper(children)
|
|
15
|
+
}
|
|
@@ -3,16 +3,16 @@ import {Placement} from '@floating-ui/react-dom'
|
|
|
3
3
|
export const DEFAULT_TOOLTIP_DISTANCE = 4
|
|
4
4
|
export const DEFAULT_TOOLTIP_PADDING = 4
|
|
5
5
|
export const DEFAULT_FALLBACK_PLACEMENTS: Record<Placement, Placement[]> = {
|
|
6
|
-
top: ['bottom', 'left', 'right'],
|
|
7
|
-
'top-start': ['bottom-start', 'left-start', 'right-start'],
|
|
8
|
-
'top-end': ['bottom-end', 'left-end', 'right-end'],
|
|
9
|
-
bottom: ['top', 'left', 'right'],
|
|
10
|
-
'bottom-start': ['top-start', 'left-start', 'right-start'],
|
|
11
|
-
'bottom-end': ['top-end', 'left-end', 'right-end'],
|
|
12
|
-
left: ['right', 'top', 'bottom'],
|
|
13
|
-
'left-start': ['right-start', 'top-start', 'bottom-start'],
|
|
14
|
-
'left-end': ['right-end', 'top-end', 'bottom-end'],
|
|
15
|
-
right: ['left', 'top', 'bottom'],
|
|
16
|
-
'right-start': ['left-start', 'top-start', 'bottom-start'],
|
|
17
|
-
'right-end': ['left-end', 'top-end', 'bottom-end'],
|
|
6
|
+
top: ['top-end', 'top-start', 'bottom', 'left', 'right'],
|
|
7
|
+
'top-start': ['top', 'top-end', 'bottom-start', 'left-start', 'right-start'],
|
|
8
|
+
'top-end': ['top', 'top-start', 'bottom-end', 'left-end', 'right-end'],
|
|
9
|
+
bottom: ['bottom-end', 'bottom-start', 'top', 'left', 'right'],
|
|
10
|
+
'bottom-start': ['bottom', 'bottom-end', 'top-start', 'left-start', 'right-start'],
|
|
11
|
+
'bottom-end': ['bottom', 'bottom-start', 'top-end', 'left-end', 'right-end'],
|
|
12
|
+
left: ['left-end', 'left-start', 'right', 'top', 'bottom'],
|
|
13
|
+
'left-start': ['left', 'left-end', 'right-start', 'top-start', 'bottom-start'],
|
|
14
|
+
'left-end': ['left', 'left-start', 'right-end', 'top-end', 'bottom-end'],
|
|
15
|
+
right: ['right-end', 'right-start', 'left', 'top', 'bottom'],
|
|
16
|
+
'right-start': ['right', 'right-end', 'left-start', 'top-start', 'bottom-start'],
|
|
17
|
+
'right-end': ['right', 'right-start', 'left-end', 'top-end', 'bottom-end'],
|
|
18
18
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Middleware,
|
|
10
10
|
RootBoundary,
|
|
11
11
|
} from '@floating-ui/react-dom'
|
|
12
|
+
import {AnimatePresence, motion} from 'framer-motion'
|
|
12
13
|
import {
|
|
13
14
|
cloneElement,
|
|
14
15
|
forwardRef,
|
|
@@ -30,6 +31,7 @@ import {Placement} from '../../types'
|
|
|
30
31
|
import {Layer, LayerProps, Portal, useBoundaryElement, usePortal} from '../../utils'
|
|
31
32
|
import {Card} from '../card'
|
|
32
33
|
import {Delay} from '../types'
|
|
34
|
+
import {ConditionalWrapper} from './conditionalWrapper'
|
|
33
35
|
import {
|
|
34
36
|
DEFAULT_FALLBACK_PLACEMENTS,
|
|
35
37
|
DEFAULT_TOOLTIP_DISTANCE,
|
|
@@ -57,13 +59,23 @@ export interface TooltipProps extends Omit<LayerProps, 'as'> {
|
|
|
57
59
|
scheme?: ThemeColorSchemeKey
|
|
58
60
|
shadow?: number | number[]
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
62
|
+
* Adds a delay to open or close the tooltip.
|
|
61
63
|
*
|
|
62
64
|
* If only a `number` is passed, it will be used for both opening and closing.
|
|
63
65
|
*
|
|
64
66
|
* If an object `{open: number; close:number}` is passed, it can be used to set different delays for each action.
|
|
67
|
+
*
|
|
68
|
+
* @public
|
|
69
|
+
* @defaultValue 0
|
|
65
70
|
*/
|
|
66
71
|
delay?: Delay
|
|
72
|
+
/**
|
|
73
|
+
* Whether the tooltip should animate in and out.
|
|
74
|
+
*
|
|
75
|
+
* @beta
|
|
76
|
+
* @defaultValue false
|
|
77
|
+
*/
|
|
78
|
+
animate?: boolean
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
const Root = styled(Layer)<{$maxWidth: number}>`
|
|
@@ -97,6 +109,7 @@ export const Tooltip = forwardRef(function Tooltip(
|
|
|
97
109
|
shadow = 2,
|
|
98
110
|
zOffset = theme.sanity.layer?.tooltip.zOffset,
|
|
99
111
|
delay,
|
|
112
|
+
animate = false,
|
|
100
113
|
...restProps
|
|
101
114
|
} = props
|
|
102
115
|
const fallbackPlacements = useArrayProp(fallbackPlacementsProp)
|
|
@@ -383,35 +396,53 @@ export const Tooltip = forwardRef(function Tooltip(
|
|
|
383
396
|
zOffset={zOffset}
|
|
384
397
|
$maxWidth={tooltipWidth}
|
|
385
398
|
>
|
|
386
|
-
<
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
399
|
+
<ConditionalWrapper
|
|
400
|
+
condition={animate} // Add animation wrapper if it should animate
|
|
401
|
+
wrapper={(children) => (
|
|
402
|
+
<motion.div
|
|
403
|
+
initial={{opacity: 0.5, scale: 0.95}}
|
|
404
|
+
animate={{opacity: 1, scale: 1}}
|
|
405
|
+
exit={{opacity: 0, scale: 0.95, transition: {duration: 0.4, type: 'spring'}}}
|
|
406
|
+
>
|
|
407
|
+
{children}
|
|
408
|
+
</motion.div>
|
|
409
|
+
)}
|
|
393
410
|
>
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
411
|
+
<Card
|
|
412
|
+
data-ui="Tooltip__card"
|
|
413
|
+
data-placement={placement}
|
|
414
|
+
padding={padding}
|
|
415
|
+
radius={3}
|
|
416
|
+
scheme={scheme}
|
|
417
|
+
shadow={shadow}
|
|
418
|
+
>
|
|
419
|
+
{content}
|
|
420
|
+
{arrowProp && <TooltipArrow ref={setArrow} style={arrowStyle} />}
|
|
421
|
+
</Card>
|
|
422
|
+
</ConditionalWrapper>
|
|
397
423
|
</Root>
|
|
398
424
|
)
|
|
399
425
|
|
|
400
426
|
return (
|
|
401
427
|
<>
|
|
402
428
|
{child}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
429
|
+
<ConditionalWrapper
|
|
430
|
+
condition={animate}
|
|
431
|
+
wrapper={(children) => <AnimatePresence>{children}</AnimatePresence>} // Add AnimatePresence if it should animate
|
|
432
|
+
>
|
|
433
|
+
{showTooltip && (
|
|
434
|
+
<ConditionalWrapper
|
|
435
|
+
condition={!!portalProp} // Add portal if portalProp is set
|
|
436
|
+
wrapper={(children) => (
|
|
437
|
+
<Portal __unstable_name={typeof portalProp === 'string' ? portalProp : undefined}>
|
|
438
|
+
{children}
|
|
439
|
+
</Portal>
|
|
440
|
+
)}
|
|
441
|
+
>
|
|
442
|
+
{root}
|
|
443
|
+
</ConditionalWrapper>
|
|
444
|
+
)}
|
|
445
|
+
</ConditionalWrapper>
|
|
415
446
|
</>
|
|
416
447
|
)
|
|
417
448
|
})
|
|
@@ -10,11 +10,13 @@ import {TooltipDelayGroupContextValue} from './types'
|
|
|
10
10
|
export interface TooltipDelayGroupProviderProps {
|
|
11
11
|
children?: React.ReactNode
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Handles the delays to open or close a tooltip inside a group
|
|
14
14
|
*
|
|
15
15
|
* If only a `number` is passed, it will be used for both opening and closing.
|
|
16
16
|
*
|
|
17
17
|
* If an object `{open: number; close:number}` is passed, it can be used to set different delays for each action.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
18
20
|
*/
|
|
19
21
|
delay: Delay
|
|
20
22
|
}
|