@toptal/picasso-collapse 2.0.0 → 2.0.1
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-package/src/Collapse/Collapse.d.ts.map +1 -1
- package/dist-package/src/Collapse/Collapse.js +41 -28
- package/dist-package/src/Collapse/Collapse.js.map +1 -1
- package/package.json +1 -1
- package/src/Collapse/Collapse.tsx +60 -37
- package/src/Collapse/story/AppearOnRender.example.tsx +25 -0
- package/src/Collapse/story/index.jsx +18 -8
- package/src/Collapse/test.tsx +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collapse.d.ts","sourceRoot":"","sources":["../../../src/Collapse/Collapse.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"Collapse.d.ts","sourceRoot":"","sources":["../../../src/Collapse/Collapse.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAwC,MAAM,OAAO,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAGxE,MAAM,WAAW,KAAM,SAAQ,eAAe,EAAE,SAAS;IAEvD,QAAQ,EAAE,SAAS,CAAA;IAEnB,EAAE,CAAC,EAAE,OAAO,CAAA;IAEZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5D;AAoBD,eAAO,MAAM,QAAQ,8EAsFpB,CAAA;AAED,eAAe,QAAQ,CAAA"}
|
|
@@ -9,41 +9,54 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import React, {
|
|
12
|
+
import React, { forwardRef, useMemo, useState } from 'react';
|
|
13
13
|
import { Transition } from 'react-transition-group';
|
|
14
|
-
import { useMultipleForwardRefs } from '@toptal/picasso-utils';
|
|
15
14
|
import { twJoin } from '@toptal/picasso-tailwind-merge';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
const useCollapseLogic = (inProps) => {
|
|
16
|
+
const [height, setHeight] = useState(inProps ? 'auto' : '0px');
|
|
17
|
+
const wrapperRef = React.useRef(null);
|
|
18
|
+
const getCurrentHeight = () => { var _a; return (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight; };
|
|
19
|
+
const setHeightToCurrent = () => setHeight(`${getCurrentHeight()}px`);
|
|
20
|
+
const setHeightToZero = () => setHeight('0px');
|
|
21
|
+
const setHeightToAuto = () => setHeight('auto');
|
|
22
|
+
return {
|
|
23
|
+
height,
|
|
24
|
+
wrapperRef,
|
|
25
|
+
setHeightToCurrent,
|
|
26
|
+
setHeightToZero,
|
|
27
|
+
setHeightToAuto,
|
|
25
28
|
};
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
};
|
|
30
|
+
export const Collapse = forwardRef((_a, ref) => {
|
|
31
|
+
var { children, className, in: inProps = false, timeout = 350, unmountOnExit, style, appear, 'data-testid': dataTestId, onEnter, onExited } = _a, rest = __rest(_a, ["children", "className", "in", "timeout", "unmountOnExit", "style", "appear", 'data-testid', "onEnter", "onExited"]);
|
|
32
|
+
const { height, wrapperRef, setHeightToZero, setHeightToAuto, setHeightToCurrent, } = useCollapseLogic(inProps);
|
|
33
|
+
// we need to add small delay as 'enter', 'entering' and 'exit', 'exiting'
|
|
34
|
+
// are triggered in the same time and React is batching them
|
|
35
|
+
const handleEntering = () => setTimeout(setHeightToCurrent, 50);
|
|
36
|
+
const handleExiting = () => setTimeout(setHeightToZero, 50);
|
|
37
|
+
const handleEnter = (node, isAppearing) => {
|
|
38
|
+
setHeightToZero();
|
|
39
|
+
onEnter === null || onEnter === void 0 ? void 0 : onEnter(node, isAppearing);
|
|
28
40
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
onExitedProp(node);
|
|
33
|
-
}
|
|
41
|
+
const handleExited = (node) => {
|
|
42
|
+
setHeightToZero();
|
|
43
|
+
onExited === null || onExited === void 0 ? void 0 : onExited(node);
|
|
34
44
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
const memoStyles = useMemo(() => {
|
|
46
|
+
return Object.assign(Object.assign({}, style), { transitionDuration: `${timeout}ms`, height });
|
|
47
|
+
}, [timeout, height, style]);
|
|
48
|
+
return (React.createElement(Transition, Object.assign({ in: inProps, appear: appear, onEnter: handleEnter, onEntering: handleEntering,
|
|
49
|
+
// we need to set height to 'auto' after transition is finished
|
|
50
|
+
// to support dynamic content inside Collapse
|
|
51
|
+
onEntered: setHeightToAuto, onExit: setHeightToCurrent, onExiting: handleExiting, onExited: handleExited, unmountOnExit: unmountOnExit, timeout: timeout }, rest), state => {
|
|
38
52
|
return (React.createElement("div", { className: twJoin([
|
|
39
|
-
'
|
|
40
|
-
|
|
41
|
-
state === '
|
|
53
|
+
'transition-[height] ease-in-out min-h-0',
|
|
54
|
+
state === 'exited' && !inProps && 'invisible',
|
|
55
|
+
state === 'entered' ? 'overflow-visible' : 'overflow-hidden',
|
|
42
56
|
className,
|
|
43
|
-
]), style:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
React.createElement("div", { className: 'w-full' }, children)));
|
|
57
|
+
]), style: memoStyles, "data-testid": dataTestId, ref: ref },
|
|
58
|
+
React.createElement("div", { className: 'flex', ref: wrapperRef },
|
|
59
|
+
React.createElement("div", { className: 'w-full' }, children))));
|
|
47
60
|
}));
|
|
48
61
|
});
|
|
49
62
|
export default Collapse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collapse.js","sourceRoot":"","sources":["../../../src/Collapse/Collapse.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"Collapse.js","sourceRoot":"","sources":["../../../src/Collapse/Collapse.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { forwardRef, useMemo, useState } from 'react'
|
|
3
3
|
import { Transition } from 'react-transition-group'
|
|
4
4
|
import type { BaseProps, TransitionProps } from '@toptal/picasso-shared'
|
|
5
|
-
import { useMultipleForwardRefs } from '@toptal/picasso-utils'
|
|
6
5
|
import { twJoin } from '@toptal/picasso-tailwind-merge'
|
|
7
6
|
|
|
8
7
|
export interface Props extends TransitionProps, BaseProps {
|
|
@@ -18,6 +17,24 @@ export interface Props extends TransitionProps, BaseProps {
|
|
|
18
17
|
onEnter?: (node: HTMLElement, isAppearing: boolean) => void
|
|
19
18
|
}
|
|
20
19
|
|
|
20
|
+
const useCollapseLogic = (inProps: boolean) => {
|
|
21
|
+
const [height, setHeight] = useState<string>(inProps ? 'auto' : '0px')
|
|
22
|
+
const wrapperRef = React.useRef<HTMLDivElement>(null)
|
|
23
|
+
|
|
24
|
+
const getCurrentHeight = () => wrapperRef.current?.clientHeight
|
|
25
|
+
const setHeightToCurrent = () => setHeight(`${getCurrentHeight()}px`)
|
|
26
|
+
const setHeightToZero = () => setHeight('0px')
|
|
27
|
+
const setHeightToAuto = () => setHeight('auto')
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
height,
|
|
31
|
+
wrapperRef,
|
|
32
|
+
setHeightToCurrent,
|
|
33
|
+
setHeightToZero,
|
|
34
|
+
setHeightToAuto,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
export const Collapse = forwardRef<HTMLDivElement, Props>(
|
|
22
39
|
(
|
|
23
40
|
{
|
|
@@ -28,70 +45,76 @@ export const Collapse = forwardRef<HTMLDivElement, Props>(
|
|
|
28
45
|
unmountOnExit,
|
|
29
46
|
style,
|
|
30
47
|
appear,
|
|
31
|
-
onExited: onExitedProp,
|
|
32
48
|
'data-testid': dataTestId,
|
|
49
|
+
onEnter,
|
|
50
|
+
onExited,
|
|
33
51
|
...rest
|
|
34
52
|
},
|
|
35
53
|
ref
|
|
36
54
|
) => {
|
|
37
|
-
const
|
|
38
|
-
|
|
55
|
+
const {
|
|
56
|
+
height,
|
|
57
|
+
wrapperRef,
|
|
58
|
+
setHeightToZero,
|
|
59
|
+
setHeightToAuto,
|
|
60
|
+
setHeightToCurrent,
|
|
61
|
+
} = useCollapseLogic(inProps)
|
|
39
62
|
|
|
40
|
-
|
|
63
|
+
// we need to add small delay as 'enter', 'entering' and 'exit', 'exiting'
|
|
64
|
+
// are triggered in the same time and React is batching them
|
|
65
|
+
const handleEntering = () => setTimeout(setHeightToCurrent, 50)
|
|
66
|
+
const handleExiting = () => setTimeout(setHeightToZero, 50)
|
|
41
67
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
68
|
+
const handleEnter = (node: HTMLElement, isAppearing: boolean) => {
|
|
69
|
+
setHeightToZero()
|
|
70
|
+
onEnter?.(node, isAppearing)
|
|
46
71
|
}
|
|
47
72
|
|
|
48
|
-
const
|
|
49
|
-
|
|
73
|
+
const handleExited = (node: HTMLElement) => {
|
|
74
|
+
setHeightToZero()
|
|
75
|
+
onExited?.(node)
|
|
50
76
|
}
|
|
51
77
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
78
|
+
const memoStyles = useMemo(() => {
|
|
79
|
+
return {
|
|
80
|
+
...style,
|
|
81
|
+
transitionDuration: `${timeout}ms`,
|
|
82
|
+
height,
|
|
56
83
|
}
|
|
57
|
-
}
|
|
84
|
+
}, [timeout, height, style])
|
|
58
85
|
|
|
59
86
|
return (
|
|
60
87
|
<Transition
|
|
61
88
|
in={inProps}
|
|
62
89
|
appear={appear}
|
|
63
|
-
|
|
64
|
-
onEntering={
|
|
90
|
+
onEnter={handleEnter}
|
|
91
|
+
onEntering={handleEntering}
|
|
92
|
+
// we need to set height to 'auto' after transition is finished
|
|
93
|
+
// to support dynamic content inside Collapse
|
|
94
|
+
onEntered={setHeightToAuto}
|
|
95
|
+
onExit={setHeightToCurrent}
|
|
96
|
+
onExiting={handleExiting}
|
|
97
|
+
onExited={handleExited}
|
|
65
98
|
unmountOnExit={unmountOnExit}
|
|
66
|
-
onExit={setToCurrentHeight}
|
|
67
|
-
onExiting={resetHeight}
|
|
68
|
-
onExited={onExited}
|
|
69
99
|
timeout={timeout}
|
|
70
100
|
{...rest}
|
|
71
101
|
>
|
|
72
102
|
{state => {
|
|
73
|
-
const currentHeight = height === 0 ? null : { maxHeight: height }
|
|
74
|
-
const isAnimating = state === 'entering' || state === 'exiting'
|
|
75
|
-
|
|
76
103
|
return (
|
|
77
104
|
<div
|
|
78
105
|
className={twJoin([
|
|
79
|
-
'
|
|
80
|
-
|
|
81
|
-
state === '
|
|
106
|
+
'transition-[height] ease-in-out min-h-0',
|
|
107
|
+
state === 'exited' && !inProps && 'invisible',
|
|
108
|
+
state === 'entered' ? 'overflow-visible' : 'overflow-hidden',
|
|
82
109
|
className,
|
|
83
110
|
])}
|
|
84
|
-
style={
|
|
85
|
-
...style,
|
|
86
|
-
...currentHeight,
|
|
87
|
-
transition: isAnimating
|
|
88
|
-
? `max-height ${timeout}ms ease`
|
|
89
|
-
: undefined,
|
|
90
|
-
}}
|
|
111
|
+
style={memoStyles}
|
|
91
112
|
data-testid={dataTestId}
|
|
92
|
-
ref={
|
|
113
|
+
ref={ref}
|
|
93
114
|
>
|
|
94
|
-
<div className='
|
|
115
|
+
<div className='flex' ref={wrapperRef}>
|
|
116
|
+
<div className='w-full'>{children}</div>
|
|
117
|
+
</div>
|
|
95
118
|
</div>
|
|
96
119
|
)
|
|
97
120
|
}}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Container, Button } from '@toptal/picasso'
|
|
2
|
+
import { Collapse } from '@toptal/picasso-collapse'
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
|
+
|
|
5
|
+
const Example = () => {
|
|
6
|
+
const [faded, setFaded] = useState(false)
|
|
7
|
+
|
|
8
|
+
const handleOnClick = () => setFaded(prevFaded => !prevFaded)
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<Container>
|
|
12
|
+
<Button onClick={handleOnClick} className='mb-4'>
|
|
13
|
+
{faded ? 'Unmount Collapse' : 'Render Collapse'}
|
|
14
|
+
</Button>
|
|
15
|
+
|
|
16
|
+
{faded && (
|
|
17
|
+
<Collapse appear in timeout={400}>
|
|
18
|
+
<div className='bg-gray-100 p-4 rounded-md'>Collapse content</div>
|
|
19
|
+
</Collapse>
|
|
20
|
+
)}
|
|
21
|
+
</Container>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default Example
|
|
@@ -8,11 +8,21 @@ page.createTabChapter('Props').addComponentDocs({
|
|
|
8
8
|
name: 'Collapse',
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
page
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
page
|
|
12
|
+
.createChapter()
|
|
13
|
+
.addExample(
|
|
14
|
+
'Collapse/story/Default.example.tsx',
|
|
15
|
+
{
|
|
16
|
+
title: 'Default',
|
|
17
|
+
takeScreenshot: false,
|
|
18
|
+
},
|
|
19
|
+
'base/Collapse'
|
|
20
|
+
)
|
|
21
|
+
.addExample(
|
|
22
|
+
'Collapse/story/AppearOnRender.example.tsx',
|
|
23
|
+
{
|
|
24
|
+
title: 'Appear on render',
|
|
25
|
+
takeScreenshot: false,
|
|
26
|
+
},
|
|
27
|
+
'base/Collapse'
|
|
28
|
+
)
|