@sanity/ui 4.0.0-static.44 → 4.0.0-static.45
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.js +30 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/primitives/popover/Popover.tsx +10 -3
- package/src/core/primitives/tooltip/Tooltip.test.tsx +42 -42
- package/src/core/primitives/tooltip/Tooltip.tsx +10 -3
- package/src/core/utils/AnimateActivity.tsx +78 -0
package/package.json
CHANGED
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
useFloating,
|
|
12
12
|
} from '@floating-ui/react-dom'
|
|
13
13
|
import {type MaxWidth, popover as popoverCss, type ResponsiveProp} from '@sanity/ui/css'
|
|
14
|
-
import {AnimatePresence} from 'motion/react'
|
|
15
14
|
import {
|
|
15
|
+
Activity,
|
|
16
16
|
cloneElement,
|
|
17
17
|
type ForwardedRef,
|
|
18
18
|
type ReactElement,
|
|
@@ -30,6 +30,7 @@ import {_getResponsiveProp} from '../../helpers/props'
|
|
|
30
30
|
import {usePrefersReducedMotion} from '../../hooks/usePrefersReducedMotion'
|
|
31
31
|
import {origin} from '../../middleware/origin'
|
|
32
32
|
import type {ComponentType, Placement, Props} from '../../types'
|
|
33
|
+
import {AnimateActivity} from '../../utils/AnimateActivity'
|
|
33
34
|
import {BoundaryElementContext} from '../../utils/boundaryElement/BoundaryElementContext'
|
|
34
35
|
import {getElementRef} from '../../utils/getElementRef'
|
|
35
36
|
import {Portal} from '../../utils/portal/Portal'
|
|
@@ -307,7 +308,7 @@ export function Popover<E extends PopoverElementType = typeof DEFAULT_POPOVER_EL
|
|
|
307
308
|
</>
|
|
308
309
|
)
|
|
309
310
|
|
|
310
|
-
let children =
|
|
311
|
+
let children = node
|
|
311
312
|
|
|
312
313
|
if (open && portal) {
|
|
313
314
|
let resolvedTone = tone as Exclude<typeof tone, 'inherit'>
|
|
@@ -329,7 +330,13 @@ export function Popover<E extends PopoverElementType = typeof DEFAULT_POPOVER_EL
|
|
|
329
330
|
return (
|
|
330
331
|
<>
|
|
331
332
|
{/* the popover */}
|
|
332
|
-
{animate ?
|
|
333
|
+
{animate ? (
|
|
334
|
+
<AnimateActivity mode={open ? 'visible' : 'hidden'} layoutMode="default">
|
|
335
|
+
{children}
|
|
336
|
+
</AnimateActivity>
|
|
337
|
+
) : (
|
|
338
|
+
<Activity mode={open ? 'visible' : 'hidden'}>{children}</Activity>
|
|
339
|
+
)}
|
|
333
340
|
|
|
334
341
|
{/* the referred element */}
|
|
335
342
|
{child}
|
|
@@ -31,7 +31,7 @@ describe('Tooltip', () => {
|
|
|
31
31
|
const button = screen.getByText('Hover me')
|
|
32
32
|
|
|
33
33
|
// Validate tooltip content is not rendered
|
|
34
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
34
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
35
35
|
|
|
36
36
|
fireEvent.mouseEnter(button)
|
|
37
37
|
|
|
@@ -40,7 +40,7 @@ describe('Tooltip', () => {
|
|
|
40
40
|
|
|
41
41
|
fireEvent.mouseOut(button)
|
|
42
42
|
// Validate tooltip content is not rendered anymore
|
|
43
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
43
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
44
44
|
})
|
|
45
45
|
it('should support delays to show and hide the tooltip.', () => {
|
|
46
46
|
vi.useFakeTimers()
|
|
@@ -59,13 +59,13 @@ describe('Tooltip', () => {
|
|
|
59
59
|
const button = screen.getByText('Hover me')
|
|
60
60
|
|
|
61
61
|
// Validate tooltip content is not rendered
|
|
62
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
62
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
63
63
|
|
|
64
64
|
fireEvent.mouseEnter(button)
|
|
65
65
|
|
|
66
66
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
67
67
|
// Content should not be rendered yet
|
|
68
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
68
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
69
69
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
70
70
|
|
|
71
71
|
// Validate tooltip content is rendered
|
|
@@ -76,7 +76,7 @@ describe('Tooltip', () => {
|
|
|
76
76
|
screen.getByText('Tooltip content')
|
|
77
77
|
act(() => vi.advanceTimersByTime(delay))
|
|
78
78
|
// Validate tooltip content is not rendered anymore
|
|
79
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
79
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
80
80
|
})
|
|
81
81
|
it('should support different open and close delays to show and hide the tooltip.', () => {
|
|
82
82
|
vi.useFakeTimers()
|
|
@@ -99,13 +99,13 @@ describe('Tooltip', () => {
|
|
|
99
99
|
const button = screen.getByText('Hover me')
|
|
100
100
|
|
|
101
101
|
// Validate tooltip content is not rendered
|
|
102
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
102
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
103
103
|
|
|
104
104
|
fireEvent.mouseEnter(button)
|
|
105
105
|
|
|
106
106
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
107
107
|
// Content should not be rendered yet
|
|
108
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
108
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
109
109
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
110
110
|
|
|
111
111
|
// Validate tooltip content is rendered
|
|
@@ -116,7 +116,7 @@ describe('Tooltip', () => {
|
|
|
116
116
|
screen.getByText('Tooltip content')
|
|
117
117
|
act(() => vi.advanceTimersByTime(closeDelay))
|
|
118
118
|
// Validate tooltip content is not rendered anymore
|
|
119
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
119
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
120
120
|
})
|
|
121
121
|
})
|
|
122
122
|
|
|
@@ -144,20 +144,20 @@ describe('Tooltip', () => {
|
|
|
144
144
|
const button2 = screen.getByText('Button 2')
|
|
145
145
|
|
|
146
146
|
// Validate tooltip content is not rendered
|
|
147
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
148
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
147
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
148
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
149
149
|
|
|
150
150
|
// Hovers on first button, it should show first tooltip only
|
|
151
151
|
fireEvent.mouseEnter(button1)
|
|
152
152
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
153
153
|
// Content should not be rendered yet, we have a delay of 150ms
|
|
154
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
155
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
154
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
155
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
156
156
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
157
157
|
|
|
158
158
|
// Validate Tooltip 1 is rendered
|
|
159
159
|
screen.getByText('Tooltip 1')
|
|
160
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
160
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
161
161
|
|
|
162
162
|
// Hovers on second button.
|
|
163
163
|
fireEvent.mouseOut(button1)
|
|
@@ -165,13 +165,13 @@ describe('Tooltip', () => {
|
|
|
165
165
|
|
|
166
166
|
// Validate Tooltip 1 is not rendered, now tooltip 2 is open.
|
|
167
167
|
act(() => vi.advanceTimersByTime(1))
|
|
168
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
168
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
169
169
|
screen.getByText('Tooltip 2')
|
|
170
170
|
|
|
171
171
|
// Validate tooltip content is not rendered anymore
|
|
172
172
|
fireEvent.mouseOut(button2)
|
|
173
173
|
act(() => vi.advanceTimersByTime(delay + 1))
|
|
174
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
174
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
175
175
|
|
|
176
176
|
// Hovering again, should trigger the tooltip to show immediately, as the group is not deactivated yet
|
|
177
177
|
fireEvent.mouseEnter(button2)
|
|
@@ -181,13 +181,13 @@ describe('Tooltip', () => {
|
|
|
181
181
|
// Validate tooltip content is not rendered anymore
|
|
182
182
|
fireEvent.mouseOut(button2)
|
|
183
183
|
act(() => vi.advanceTimersByTime(delay + 1))
|
|
184
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
184
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
185
185
|
|
|
186
186
|
// Wait 200ms, the group is deactivated, hovering again should trigger the delay
|
|
187
187
|
act(() => vi.advanceTimersByTime(200))
|
|
188
188
|
fireEvent.mouseEnter(button2)
|
|
189
189
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
190
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
190
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
191
191
|
act(() => vi.advanceTimersByTime(delay / 2))
|
|
192
192
|
screen.getByText('Tooltip 2')
|
|
193
193
|
})
|
|
@@ -220,20 +220,20 @@ describe('Tooltip', () => {
|
|
|
220
220
|
const button2 = screen.getByText('Button 2')
|
|
221
221
|
|
|
222
222
|
// Validate tooltip content is not rendered
|
|
223
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
224
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
223
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
224
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
225
225
|
|
|
226
226
|
// Hovers on first button, it should show first tooltip only
|
|
227
227
|
fireEvent.mouseEnter(button1)
|
|
228
228
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
229
229
|
// Content should not be rendered yet, we have a delay of2150ms
|
|
230
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
231
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
230
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
231
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
232
232
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
233
233
|
|
|
234
234
|
// Validate Tooltip 1 is rendered
|
|
235
235
|
screen.getByText('Tooltip 1')
|
|
236
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
236
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
237
237
|
|
|
238
238
|
// Hovers on second button.
|
|
239
239
|
fireEvent.mouseOut(button1)
|
|
@@ -241,13 +241,13 @@ describe('Tooltip', () => {
|
|
|
241
241
|
|
|
242
242
|
// Validate Tooltip 1 is not rendered, now tooltip 2 is open.
|
|
243
243
|
act(() => vi.advanceTimersByTime(1))
|
|
244
|
-
expect(screen.queryByText('Tooltip 1')).not.
|
|
244
|
+
expect(screen.queryByText('Tooltip 1')).not.toBeVisible()
|
|
245
245
|
screen.getByText('Tooltip 2')
|
|
246
246
|
|
|
247
247
|
// Validate tooltip content is not rendered anymore
|
|
248
248
|
fireEvent.mouseOut(button2)
|
|
249
249
|
act(() => vi.advanceTimersByTime(closeDelay + 1))
|
|
250
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
250
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
251
251
|
|
|
252
252
|
// Hovering again, should trigger the tooltip to show immediately, as the group is not deactivated yet
|
|
253
253
|
fireEvent.mouseEnter(button2)
|
|
@@ -257,13 +257,13 @@ describe('Tooltip', () => {
|
|
|
257
257
|
// Validate tooltip content is not rendered anymore
|
|
258
258
|
fireEvent.mouseOut(button2)
|
|
259
259
|
act(() => vi.advanceTimersByTime(closeDelay + 1))
|
|
260
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
260
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
261
261
|
|
|
262
262
|
// Wait 200ms, the group is deactivated, hovering again should trigger the delay
|
|
263
263
|
act(() => vi.advanceTimersByTime(200))
|
|
264
264
|
fireEvent.mouseEnter(button2)
|
|
265
265
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
266
|
-
expect(screen.queryByText('Tooltip 2')).not.
|
|
266
|
+
expect(screen.queryByText('Tooltip 2')).not.toBeVisible()
|
|
267
267
|
act(() => vi.advanceTimersByTime(openDelay / 2))
|
|
268
268
|
screen.getByText('Tooltip 2')
|
|
269
269
|
})
|
|
@@ -288,7 +288,7 @@ describe('Tooltip', () => {
|
|
|
288
288
|
const button = screen.getByText('Hover me')
|
|
289
289
|
|
|
290
290
|
// Validate tooltip content is not rendered
|
|
291
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
291
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
292
292
|
act(() => fireEvent.focus(button))
|
|
293
293
|
act(() => vi.advanceTimersByTime(delay))
|
|
294
294
|
|
|
@@ -299,7 +299,7 @@ describe('Tooltip', () => {
|
|
|
299
299
|
fireEvent.keyDown(button, {key: 'Escape', code: 'Escape'})
|
|
300
300
|
})
|
|
301
301
|
// Validate tooltip content is not rendered anymore
|
|
302
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
302
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
303
303
|
})
|
|
304
304
|
it('With <TooltipDelayGroupProvider /> closes immediately with Escape key', () => {
|
|
305
305
|
const delay = 150
|
|
@@ -320,8 +320,8 @@ describe('Tooltip', () => {
|
|
|
320
320
|
|
|
321
321
|
const button = screen.getByText('Hover me')
|
|
322
322
|
|
|
323
|
-
// Validate tooltip content is not
|
|
324
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
323
|
+
// Validate tooltip content is not visible
|
|
324
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
325
325
|
act(() => fireEvent.focus(button))
|
|
326
326
|
|
|
327
327
|
act(() => vi.advanceTimersByTime(delay))
|
|
@@ -332,8 +332,8 @@ describe('Tooltip', () => {
|
|
|
332
332
|
act(() => {
|
|
333
333
|
fireEvent.keyDown(button, {key: 'Escape', code: 'Escape'})
|
|
334
334
|
})
|
|
335
|
-
// Validate tooltip content is not
|
|
336
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
335
|
+
// Validate tooltip content is not visible anymore
|
|
336
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
337
337
|
})
|
|
338
338
|
})
|
|
339
339
|
|
|
@@ -349,19 +349,19 @@ describe('Tooltip', () => {
|
|
|
349
349
|
|
|
350
350
|
const button = screen.getByText('Hover me')
|
|
351
351
|
|
|
352
|
-
// Assertion: tooltip
|
|
353
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
352
|
+
// Assertion: the tooltip is not visible
|
|
353
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
354
354
|
act(() => fireEvent.focus(button))
|
|
355
355
|
|
|
356
356
|
act(() => vi.advanceTimersByTime(delay))
|
|
357
357
|
|
|
358
|
-
// Assertion: the tooltip is
|
|
358
|
+
// Assertion: the tooltip is visible
|
|
359
359
|
expect(screen.queryByText('Tooltip content')).toBeVisible()
|
|
360
360
|
|
|
361
361
|
act(() => fireEvent.click(button))
|
|
362
362
|
|
|
363
|
-
// Assertion: tooltip
|
|
364
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
363
|
+
// Assertion: the tooltip is not visible
|
|
364
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
365
365
|
})
|
|
366
366
|
|
|
367
367
|
it('Should close the tooltip when the context menu is opened (right click)', () => {
|
|
@@ -375,19 +375,19 @@ describe('Tooltip', () => {
|
|
|
375
375
|
|
|
376
376
|
const button = screen.getByText('Hover me')
|
|
377
377
|
|
|
378
|
-
// Assertion: tooltip
|
|
379
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
378
|
+
// Assertion: the tooltip is not visible
|
|
379
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
380
380
|
act(() => fireEvent.focus(button))
|
|
381
381
|
|
|
382
382
|
act(() => vi.advanceTimersByTime(delay))
|
|
383
383
|
|
|
384
|
-
// Assertion: the tooltip is
|
|
384
|
+
// Assertion: the tooltip is visible
|
|
385
385
|
expect(screen.queryByText('Tooltip content')).toBeVisible()
|
|
386
386
|
|
|
387
387
|
act(() => fireEvent.contextMenu(button))
|
|
388
388
|
|
|
389
|
-
// Assertion: tooltip
|
|
390
|
-
expect(screen.queryByText('Tooltip content')).not.
|
|
389
|
+
// Assertion: the tooltip is not visible
|
|
390
|
+
expect(screen.queryByText('Tooltip content')).not.toBeVisible()
|
|
391
391
|
})
|
|
392
392
|
})
|
|
393
393
|
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
} from '@floating-ui/react-dom'
|
|
11
11
|
import {type RadiusStyleProps, type ShadowStyleProps, tooltip} from '@sanity/ui/css'
|
|
12
12
|
import type {CardTone, ColorScheme} from '@sanity/ui/theme'
|
|
13
|
-
import {AnimatePresence} from 'motion/react'
|
|
14
13
|
import {
|
|
14
|
+
Activity,
|
|
15
15
|
cloneElement,
|
|
16
16
|
type FocusEvent,
|
|
17
17
|
type HTMLAttributes,
|
|
@@ -36,6 +36,7 @@ import {useDelayedState} from '../../hooks/useDelayedState'
|
|
|
36
36
|
import {usePrefersReducedMotion} from '../../hooks/usePrefersReducedMotion'
|
|
37
37
|
import {origin} from '../../middleware/origin'
|
|
38
38
|
import type {ComponentType, Delay, Placement, Props} from '../../types'
|
|
39
|
+
import {AnimateActivity} from '../../utils/AnimateActivity'
|
|
39
40
|
import {BoundaryElementContext} from '../../utils/boundaryElement/BoundaryElementContext'
|
|
40
41
|
import {getElementRef} from '../../utils/getElementRef'
|
|
41
42
|
import {Portal} from '../../utils/portal/Portal'
|
|
@@ -388,7 +389,7 @@ export function Tooltip<E extends TooltipElementType = typeof DEFAULT_TOOLTIP_EL
|
|
|
388
389
|
</TooltipLayer>
|
|
389
390
|
)
|
|
390
391
|
|
|
391
|
-
let children =
|
|
392
|
+
let children = node
|
|
392
393
|
|
|
393
394
|
if (showTooltip && portalProp) {
|
|
394
395
|
let resolvedTone = tone as Exclude<typeof tone, 'inherit'>
|
|
@@ -410,7 +411,13 @@ export function Tooltip<E extends TooltipElementType = typeof DEFAULT_TOOLTIP_EL
|
|
|
410
411
|
return (
|
|
411
412
|
<>
|
|
412
413
|
{/* the tooltip */}
|
|
413
|
-
{animate ?
|
|
414
|
+
{animate ? (
|
|
415
|
+
<AnimateActivity mode={showTooltip ? 'visible' : 'hidden'} layoutMode="default">
|
|
416
|
+
{children}
|
|
417
|
+
</AnimateActivity>
|
|
418
|
+
) : (
|
|
419
|
+
<Activity mode={showTooltip ? 'visible' : 'hidden'}>{children}</Activity>
|
|
420
|
+
)}
|
|
414
421
|
|
|
415
422
|
{/* the referred element */}
|
|
416
423
|
{child}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIT License
|
|
3
|
+
* Copyright (c) 2024 Motion One
|
|
4
|
+
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
* in the Software without restriction, including without limitation the rights
|
|
8
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
* furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
* copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
* SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {invariant, PresenceChild} from 'motion/react'
|
|
25
|
+
import {Activity, useState} from 'react'
|
|
26
|
+
|
|
27
|
+
export interface AnimateActivityProps {
|
|
28
|
+
mode: 'visible' | 'hidden'
|
|
29
|
+
layoutMode: 'default' | 'pop'
|
|
30
|
+
children: React.ReactNode
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* This component will become available on `motion/react` in the future, this "fork" is temporary
|
|
35
|
+
*/
|
|
36
|
+
export function AnimateActivity({mode: modeFromProps, layoutMode, children}: AnimateActivityProps) {
|
|
37
|
+
/**
|
|
38
|
+
* This is the mode that we'll render.
|
|
39
|
+
*/
|
|
40
|
+
const [mode, setMode] = useState(modeFromProps)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* This is the goal state as defined by props.
|
|
44
|
+
*/
|
|
45
|
+
const isPresent = modeFromProps === 'visible'
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Immediately switch to mode="visible" when the user
|
|
49
|
+
* changes the mode prop.
|
|
50
|
+
*/
|
|
51
|
+
if (isPresent && mode !== 'visible') {
|
|
52
|
+
setMode('visible')
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Set mode to "hidden" only when the exit animation is complete.
|
|
58
|
+
*/
|
|
59
|
+
const onExitComplete = () => setMode('hidden')
|
|
60
|
+
|
|
61
|
+
invariant(Boolean(Activity), 'Activity component not found - upgrade to React 19.2.0 or higher')
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Activity mode={mode}>
|
|
65
|
+
<PresenceChild
|
|
66
|
+
isPresent={isPresent}
|
|
67
|
+
onExitComplete={!isPresent ? onExitComplete : undefined}
|
|
68
|
+
presenceAffectsLayout={false}
|
|
69
|
+
mode={layoutMode === 'pop' ? 'popLayout' : 'sync'}
|
|
70
|
+
>
|
|
71
|
+
{
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
children as any
|
|
74
|
+
}
|
|
75
|
+
</PresenceChild>
|
|
76
|
+
</Activity>
|
|
77
|
+
)
|
|
78
|
+
}
|