@sheinx/hooks 3.9.2-beta.1 → 3.9.2-beta.3
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/cjs/common/use-collapse-animation/use-collapse-animation.d.ts +19 -3
- package/cjs/common/use-collapse-animation/use-collapse-animation.d.ts.map +1 -1
- package/cjs/common/use-collapse-animation/use-collapse-animation.js +64 -9
- package/cjs/components/use-popup/use-popup.d.ts.map +1 -1
- package/cjs/components/use-popup/use-popup.js +4 -3
- package/esm/common/use-collapse-animation/use-collapse-animation.d.ts +19 -3
- package/esm/common/use-collapse-animation/use-collapse-animation.d.ts.map +1 -1
- package/esm/common/use-collapse-animation/use-collapse-animation.js +65 -10
- package/esm/components/use-popup/use-popup.d.ts.map +1 -1
- package/esm/components/use-popup/use-popup.js +4 -3
- package/package.json +1 -1
|
@@ -19,6 +19,21 @@ export interface UseCollapseAnimationOptions {
|
|
|
19
19
|
* @default 'cubic-bezier(.2,0,0,1)'
|
|
20
20
|
*/
|
|
21
21
|
timingFunction?: string;
|
|
22
|
+
/**
|
|
23
|
+
* 父元素的 open class 名称
|
|
24
|
+
* 用于在获取 scrollHeight 时临时添加,确保用户依赖此 class 的样式生效
|
|
25
|
+
*/
|
|
26
|
+
parentOpenClassName?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UseCollapseAnimationResult {
|
|
29
|
+
/**
|
|
30
|
+
* 是否应该隐藏元素(动画结束后且 isOpen 为 false 时返回 true)
|
|
31
|
+
*/
|
|
32
|
+
shouldHide: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 是否应该保持 open 状态(动画进行中时返回 true)
|
|
35
|
+
*/
|
|
36
|
+
shouldKeepOpen: boolean;
|
|
22
37
|
}
|
|
23
38
|
/**
|
|
24
39
|
* 为元素添加折叠/展开动画的 Hook
|
|
@@ -26,10 +41,11 @@ export interface UseCollapseAnimationOptions {
|
|
|
26
41
|
* @example
|
|
27
42
|
* ```tsx
|
|
28
43
|
* const ref = useRef<HTMLDivElement>(null);
|
|
29
|
-
* useCollapseAnimation(ref, { isOpen: true });
|
|
44
|
+
* const { shouldHide, shouldKeepOpen } = useCollapseAnimation(ref, { isOpen: true });
|
|
30
45
|
*
|
|
31
|
-
* return <div ref={ref}>Content</div>;
|
|
46
|
+
* return <div ref={ref} className={shouldHide ? 'hide' : ''}>Content</div>;
|
|
32
47
|
* ```
|
|
48
|
+
* @returns 动画状态对象
|
|
33
49
|
*/
|
|
34
|
-
export declare function useCollapseAnimation<T extends HTMLElement = HTMLElement>(elementRef: React.RefObject<T>, options: UseCollapseAnimationOptions):
|
|
50
|
+
export declare function useCollapseAnimation<T extends HTMLElement = HTMLElement>(elementRef: React.RefObject<T>, options: UseCollapseAnimationOptions): UseCollapseAnimationResult;
|
|
35
51
|
//# sourceMappingURL=use-collapse-animation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-collapse-animation.d.ts","sourceRoot":"","sources":["use-collapse-animation.ts"],"names":[],"mappings":";AAEA,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED
|
|
1
|
+
{"version":3,"file":"use-collapse-animation.d.ts","sourceRoot":"","sources":["use-collapse-animation.ts"],"names":[],"mappings":";AAEA,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACtE,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAC9B,OAAO,EAAE,2BAA2B,GACnC,0BAA0B,CAoI5B"}
|
|
@@ -5,16 +5,23 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.useCollapseAnimation = useCollapseAnimation;
|
|
7
7
|
var _react = require("react");
|
|
8
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
9
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
10
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
11
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
12
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
13
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
8
14
|
/**
|
|
9
15
|
* 为元素添加折叠/展开动画的 Hook
|
|
10
16
|
*
|
|
11
17
|
* @example
|
|
12
18
|
* ```tsx
|
|
13
19
|
* const ref = useRef<HTMLDivElement>(null);
|
|
14
|
-
* useCollapseAnimation(ref, { isOpen: true });
|
|
20
|
+
* const { shouldHide, shouldKeepOpen } = useCollapseAnimation(ref, { isOpen: true });
|
|
15
21
|
*
|
|
16
|
-
* return <div ref={ref}>Content</div>;
|
|
22
|
+
* return <div ref={ref} className={shouldHide ? 'hide' : ''}>Content</div>;
|
|
17
23
|
* ```
|
|
24
|
+
* @returns 动画状态对象
|
|
18
25
|
*/
|
|
19
26
|
function useCollapseAnimation(elementRef, options) {
|
|
20
27
|
var isOpen = options.isOpen,
|
|
@@ -23,8 +30,17 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
23
30
|
_options$disabled = options.disabled,
|
|
24
31
|
disabled = _options$disabled === void 0 ? false : _options$disabled,
|
|
25
32
|
_options$timingFuncti = options.timingFunction,
|
|
26
|
-
timingFunction = _options$timingFuncti === void 0 ? 'cubic-bezier(.2,0,0,1)' : _options$timingFuncti
|
|
33
|
+
timingFunction = _options$timingFuncti === void 0 ? 'cubic-bezier(.2,0,0,1)' : _options$timingFuncti,
|
|
34
|
+
parentOpenClassName = options.parentOpenClassName;
|
|
27
35
|
var isFirstRenderRef = (0, _react.useRef)(true);
|
|
36
|
+
var _useState = (0, _react.useState)(!isOpen),
|
|
37
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
38
|
+
shouldHide = _useState2[0],
|
|
39
|
+
setShouldHide = _useState2[1];
|
|
40
|
+
var _useState3 = (0, _react.useState)(false),
|
|
41
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
42
|
+
isAnimating = _useState4[0],
|
|
43
|
+
setIsAnimating = _useState4[1];
|
|
28
44
|
|
|
29
45
|
// 当 disabled 状态变化时,重置首次渲染标记
|
|
30
46
|
(0, _react.useEffect)(function () {
|
|
@@ -32,6 +48,8 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
32
48
|
isFirstRenderRef.current = true;
|
|
33
49
|
}
|
|
34
50
|
}, [disabled]);
|
|
51
|
+
|
|
52
|
+
// 使用 useLayoutEffect 确保动画状态在 DOM 更新前同步设置
|
|
35
53
|
(0, _react.useEffect)(function () {
|
|
36
54
|
if (!elementRef.current) return;
|
|
37
55
|
var el = elementRef.current;
|
|
@@ -46,9 +64,6 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
46
64
|
}
|
|
47
65
|
var timer = null;
|
|
48
66
|
|
|
49
|
-
// 设置 display: block,让元素始终可见,由高度控制折叠
|
|
50
|
-
el.style.display = 'block';
|
|
51
|
-
|
|
52
67
|
// 首次渲染时,直接设置初始状态,不做动画
|
|
53
68
|
if (isFirstRenderRef.current) {
|
|
54
69
|
isFirstRenderRef.current = false;
|
|
@@ -59,9 +74,13 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
59
74
|
return;
|
|
60
75
|
}
|
|
61
76
|
if (isOpen) {
|
|
62
|
-
// 展开动画
|
|
77
|
+
// 展开动画 - 先显示元素
|
|
78
|
+
setShouldHide(false);
|
|
79
|
+
setIsAnimating(true);
|
|
80
|
+
el.style.display = 'block';
|
|
63
81
|
el.style.height = '0px';
|
|
64
82
|
el.style.overflow = 'hidden';
|
|
83
|
+
el.style.opacity = '0';
|
|
65
84
|
|
|
66
85
|
// 强制重绘
|
|
67
86
|
void el.offsetHeight;
|
|
@@ -71,8 +90,9 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
71
90
|
|
|
72
91
|
// 启动动画
|
|
73
92
|
requestAnimationFrame(function () {
|
|
74
|
-
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction);
|
|
93
|
+
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction, ", opacity ").concat(duration, "ms ").concat(timingFunction);
|
|
75
94
|
el.style.height = "".concat(scrollHeight, "px");
|
|
95
|
+
el.style.opacity = '1';
|
|
76
96
|
|
|
77
97
|
// 动画结束后恢复 auto
|
|
78
98
|
timer = setTimeout(function () {
|
|
@@ -80,20 +100,45 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
80
100
|
el.style.height = '';
|
|
81
101
|
el.style.overflow = '';
|
|
82
102
|
el.style.transition = '';
|
|
103
|
+
el.style.opacity = '';
|
|
104
|
+
setIsAnimating(false);
|
|
83
105
|
}
|
|
84
106
|
}, duration);
|
|
85
107
|
});
|
|
86
108
|
} else {
|
|
87
109
|
// 收起动画
|
|
110
|
+
setIsAnimating(true);
|
|
111
|
+
|
|
112
|
+
// 临时添加父元素的 open class,确保用户依赖此 class 的布局样式在获取高度时生效
|
|
113
|
+
var parentElement = el.parentElement;
|
|
114
|
+
var needTempClass = parentOpenClassName && parentElement;
|
|
115
|
+
if (needTempClass) {
|
|
116
|
+
parentElement.classList.add(parentOpenClassName);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 强制重绘,确保临时 class 生效
|
|
120
|
+
void el.offsetHeight;
|
|
88
121
|
var _scrollHeight = el.scrollHeight;
|
|
89
122
|
el.style.height = "".concat(_scrollHeight, "px");
|
|
90
123
|
el.style.overflow = 'hidden';
|
|
124
|
+
el.style.opacity = '1';
|
|
91
125
|
|
|
92
126
|
// 强制重绘
|
|
93
127
|
void el.offsetHeight;
|
|
94
128
|
requestAnimationFrame(function () {
|
|
95
|
-
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction);
|
|
129
|
+
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction, ", opacity ").concat(duration, "ms ").concat(timingFunction);
|
|
96
130
|
el.style.height = '0px';
|
|
131
|
+
el.style.opacity = '0';
|
|
132
|
+
|
|
133
|
+
// 动画结束后隐藏元素
|
|
134
|
+
timer = setTimeout(function () {
|
|
135
|
+
// 移除临时 class
|
|
136
|
+
if (needTempClass) {
|
|
137
|
+
parentElement.classList.remove(parentOpenClassName);
|
|
138
|
+
}
|
|
139
|
+
setShouldHide(true);
|
|
140
|
+
setIsAnimating(false);
|
|
141
|
+
}, duration);
|
|
97
142
|
});
|
|
98
143
|
}
|
|
99
144
|
|
|
@@ -104,4 +149,14 @@ function useCollapseAnimation(elementRef, options) {
|
|
|
104
149
|
}
|
|
105
150
|
};
|
|
106
151
|
}, [isOpen, disabled, duration, timingFunction]);
|
|
152
|
+
if (disabled) {
|
|
153
|
+
return {
|
|
154
|
+
shouldHide: !isOpen,
|
|
155
|
+
shouldKeepOpen: false
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
shouldHide: shouldHide,
|
|
160
|
+
shouldKeepOpen: isAnimating && !isOpen
|
|
161
|
+
};
|
|
107
162
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popup.d.ts","sourceRoot":"","sources":["use-popup.ts"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhE,QAAA,MAAM,QAAQ,UAAW,cAAc;;;;;;
|
|
1
|
+
{"version":3,"file":"use-popup.d.ts","sourceRoot":"","sources":["use-popup.ts"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhE,QAAA,MAAM,QAAQ,UAAW,cAAc;;;;;;0BAsHK;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;0BAa9B;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;;;;;qBAnC7B;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAxEzC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;8BAOvC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;2BA0JxD,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;6BAMxC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;;CA8BlE,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -64,9 +64,10 @@ var usePopup = function usePopup(props) {
|
|
|
64
64
|
var changeOpen = function changeOpen(openIn, delay) {
|
|
65
65
|
if (context.triggerTimer) clearTimeout(context.triggerTimer);
|
|
66
66
|
context.triggerTimer = setTimeout(function () {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
if (open !== openIn) {
|
|
68
|
+
var _props$onCollapse;
|
|
69
|
+
(_props$onCollapse = props.onCollapse) === null || _props$onCollapse === void 0 || _props$onCollapse.call(props, openIn);
|
|
70
|
+
}
|
|
70
71
|
if (props.open === undefined) {
|
|
71
72
|
setOpenState(openIn);
|
|
72
73
|
}
|
|
@@ -19,6 +19,21 @@ export interface UseCollapseAnimationOptions {
|
|
|
19
19
|
* @default 'cubic-bezier(.2,0,0,1)'
|
|
20
20
|
*/
|
|
21
21
|
timingFunction?: string;
|
|
22
|
+
/**
|
|
23
|
+
* 父元素的 open class 名称
|
|
24
|
+
* 用于在获取 scrollHeight 时临时添加,确保用户依赖此 class 的样式生效
|
|
25
|
+
*/
|
|
26
|
+
parentOpenClassName?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UseCollapseAnimationResult {
|
|
29
|
+
/**
|
|
30
|
+
* 是否应该隐藏元素(动画结束后且 isOpen 为 false 时返回 true)
|
|
31
|
+
*/
|
|
32
|
+
shouldHide: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 是否应该保持 open 状态(动画进行中时返回 true)
|
|
35
|
+
*/
|
|
36
|
+
shouldKeepOpen: boolean;
|
|
22
37
|
}
|
|
23
38
|
/**
|
|
24
39
|
* 为元素添加折叠/展开动画的 Hook
|
|
@@ -26,10 +41,11 @@ export interface UseCollapseAnimationOptions {
|
|
|
26
41
|
* @example
|
|
27
42
|
* ```tsx
|
|
28
43
|
* const ref = useRef<HTMLDivElement>(null);
|
|
29
|
-
* useCollapseAnimation(ref, { isOpen: true });
|
|
44
|
+
* const { shouldHide, shouldKeepOpen } = useCollapseAnimation(ref, { isOpen: true });
|
|
30
45
|
*
|
|
31
|
-
* return <div ref={ref}>Content</div>;
|
|
46
|
+
* return <div ref={ref} className={shouldHide ? 'hide' : ''}>Content</div>;
|
|
32
47
|
* ```
|
|
48
|
+
* @returns 动画状态对象
|
|
33
49
|
*/
|
|
34
|
-
export declare function useCollapseAnimation<T extends HTMLElement = HTMLElement>(elementRef: React.RefObject<T>, options: UseCollapseAnimationOptions):
|
|
50
|
+
export declare function useCollapseAnimation<T extends HTMLElement = HTMLElement>(elementRef: React.RefObject<T>, options: UseCollapseAnimationOptions): UseCollapseAnimationResult;
|
|
35
51
|
//# sourceMappingURL=use-collapse-animation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-collapse-animation.d.ts","sourceRoot":"","sources":["use-collapse-animation.ts"],"names":[],"mappings":";AAEA,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED
|
|
1
|
+
{"version":3,"file":"use-collapse-animation.d.ts","sourceRoot":"","sources":["use-collapse-animation.ts"],"names":[],"mappings":";AAEA,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACtE,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAC9B,OAAO,EAAE,2BAA2B,GACnC,0BAA0B,CAoI5B"}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
8
|
/**
|
|
3
9
|
* 为元素添加折叠/展开动画的 Hook
|
|
4
10
|
*
|
|
5
11
|
* @example
|
|
6
12
|
* ```tsx
|
|
7
13
|
* const ref = useRef<HTMLDivElement>(null);
|
|
8
|
-
* useCollapseAnimation(ref, { isOpen: true });
|
|
14
|
+
* const { shouldHide, shouldKeepOpen } = useCollapseAnimation(ref, { isOpen: true });
|
|
9
15
|
*
|
|
10
|
-
* return <div ref={ref}>Content</div>;
|
|
16
|
+
* return <div ref={ref} className={shouldHide ? 'hide' : ''}>Content</div>;
|
|
11
17
|
* ```
|
|
18
|
+
* @returns 动画状态对象
|
|
12
19
|
*/
|
|
13
20
|
export function useCollapseAnimation(elementRef, options) {
|
|
14
21
|
var isOpen = options.isOpen,
|
|
@@ -17,8 +24,17 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
17
24
|
_options$disabled = options.disabled,
|
|
18
25
|
disabled = _options$disabled === void 0 ? false : _options$disabled,
|
|
19
26
|
_options$timingFuncti = options.timingFunction,
|
|
20
|
-
timingFunction = _options$timingFuncti === void 0 ? 'cubic-bezier(.2,0,0,1)' : _options$timingFuncti
|
|
27
|
+
timingFunction = _options$timingFuncti === void 0 ? 'cubic-bezier(.2,0,0,1)' : _options$timingFuncti,
|
|
28
|
+
parentOpenClassName = options.parentOpenClassName;
|
|
21
29
|
var isFirstRenderRef = useRef(true);
|
|
30
|
+
var _useState = useState(!isOpen),
|
|
31
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
32
|
+
shouldHide = _useState2[0],
|
|
33
|
+
setShouldHide = _useState2[1];
|
|
34
|
+
var _useState3 = useState(false),
|
|
35
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
36
|
+
isAnimating = _useState4[0],
|
|
37
|
+
setIsAnimating = _useState4[1];
|
|
22
38
|
|
|
23
39
|
// 当 disabled 状态变化时,重置首次渲染标记
|
|
24
40
|
useEffect(function () {
|
|
@@ -26,6 +42,8 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
26
42
|
isFirstRenderRef.current = true;
|
|
27
43
|
}
|
|
28
44
|
}, [disabled]);
|
|
45
|
+
|
|
46
|
+
// 使用 useLayoutEffect 确保动画状态在 DOM 更新前同步设置
|
|
29
47
|
useEffect(function () {
|
|
30
48
|
if (!elementRef.current) return;
|
|
31
49
|
var el = elementRef.current;
|
|
@@ -40,9 +58,6 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
40
58
|
}
|
|
41
59
|
var timer = null;
|
|
42
60
|
|
|
43
|
-
// 设置 display: block,让元素始终可见,由高度控制折叠
|
|
44
|
-
el.style.display = 'block';
|
|
45
|
-
|
|
46
61
|
// 首次渲染时,直接设置初始状态,不做动画
|
|
47
62
|
if (isFirstRenderRef.current) {
|
|
48
63
|
isFirstRenderRef.current = false;
|
|
@@ -53,9 +68,13 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
53
68
|
return;
|
|
54
69
|
}
|
|
55
70
|
if (isOpen) {
|
|
56
|
-
// 展开动画
|
|
71
|
+
// 展开动画 - 先显示元素
|
|
72
|
+
setShouldHide(false);
|
|
73
|
+
setIsAnimating(true);
|
|
74
|
+
el.style.display = 'block';
|
|
57
75
|
el.style.height = '0px';
|
|
58
76
|
el.style.overflow = 'hidden';
|
|
77
|
+
el.style.opacity = '0';
|
|
59
78
|
|
|
60
79
|
// 强制重绘
|
|
61
80
|
void el.offsetHeight;
|
|
@@ -65,8 +84,9 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
65
84
|
|
|
66
85
|
// 启动动画
|
|
67
86
|
requestAnimationFrame(function () {
|
|
68
|
-
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction);
|
|
87
|
+
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction, ", opacity ").concat(duration, "ms ").concat(timingFunction);
|
|
69
88
|
el.style.height = "".concat(scrollHeight, "px");
|
|
89
|
+
el.style.opacity = '1';
|
|
70
90
|
|
|
71
91
|
// 动画结束后恢复 auto
|
|
72
92
|
timer = setTimeout(function () {
|
|
@@ -74,20 +94,45 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
74
94
|
el.style.height = '';
|
|
75
95
|
el.style.overflow = '';
|
|
76
96
|
el.style.transition = '';
|
|
97
|
+
el.style.opacity = '';
|
|
98
|
+
setIsAnimating(false);
|
|
77
99
|
}
|
|
78
100
|
}, duration);
|
|
79
101
|
});
|
|
80
102
|
} else {
|
|
81
103
|
// 收起动画
|
|
104
|
+
setIsAnimating(true);
|
|
105
|
+
|
|
106
|
+
// 临时添加父元素的 open class,确保用户依赖此 class 的布局样式在获取高度时生效
|
|
107
|
+
var parentElement = el.parentElement;
|
|
108
|
+
var needTempClass = parentOpenClassName && parentElement;
|
|
109
|
+
if (needTempClass) {
|
|
110
|
+
parentElement.classList.add(parentOpenClassName);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 强制重绘,确保临时 class 生效
|
|
114
|
+
void el.offsetHeight;
|
|
82
115
|
var _scrollHeight = el.scrollHeight;
|
|
83
116
|
el.style.height = "".concat(_scrollHeight, "px");
|
|
84
117
|
el.style.overflow = 'hidden';
|
|
118
|
+
el.style.opacity = '1';
|
|
85
119
|
|
|
86
120
|
// 强制重绘
|
|
87
121
|
void el.offsetHeight;
|
|
88
122
|
requestAnimationFrame(function () {
|
|
89
|
-
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction);
|
|
123
|
+
el.style.transition = "height ".concat(duration, "ms ").concat(timingFunction, ", opacity ").concat(duration, "ms ").concat(timingFunction);
|
|
90
124
|
el.style.height = '0px';
|
|
125
|
+
el.style.opacity = '0';
|
|
126
|
+
|
|
127
|
+
// 动画结束后隐藏元素
|
|
128
|
+
timer = setTimeout(function () {
|
|
129
|
+
// 移除临时 class
|
|
130
|
+
if (needTempClass) {
|
|
131
|
+
parentElement.classList.remove(parentOpenClassName);
|
|
132
|
+
}
|
|
133
|
+
setShouldHide(true);
|
|
134
|
+
setIsAnimating(false);
|
|
135
|
+
}, duration);
|
|
91
136
|
});
|
|
92
137
|
}
|
|
93
138
|
|
|
@@ -98,4 +143,14 @@ export function useCollapseAnimation(elementRef, options) {
|
|
|
98
143
|
}
|
|
99
144
|
};
|
|
100
145
|
}, [isOpen, disabled, duration, timingFunction]);
|
|
146
|
+
if (disabled) {
|
|
147
|
+
return {
|
|
148
|
+
shouldHide: !isOpen,
|
|
149
|
+
shouldKeepOpen: false
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
shouldHide: shouldHide,
|
|
154
|
+
shouldKeepOpen: isAnimating && !isOpen
|
|
155
|
+
};
|
|
101
156
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popup.d.ts","sourceRoot":"","sources":["use-popup.ts"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhE,QAAA,MAAM,QAAQ,UAAW,cAAc;;;;;;
|
|
1
|
+
{"version":3,"file":"use-popup.d.ts","sourceRoot":"","sources":["use-popup.ts"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhE,QAAA,MAAM,QAAQ,UAAW,cAAc;;;;;;0BAsHK;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;0BAa9B;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;;;;;qBAnC7B;YAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;SAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAxEzC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;8BAOvC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;2BA0JxD,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;6BAMxC,MAAM,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC;;CA8BlE,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -57,9 +57,10 @@ var usePopup = function usePopup(props) {
|
|
|
57
57
|
var changeOpen = function changeOpen(openIn, delay) {
|
|
58
58
|
if (context.triggerTimer) clearTimeout(context.triggerTimer);
|
|
59
59
|
context.triggerTimer = setTimeout(function () {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (open !== openIn) {
|
|
61
|
+
var _props$onCollapse;
|
|
62
|
+
(_props$onCollapse = props.onCollapse) === null || _props$onCollapse === void 0 || _props$onCollapse.call(props, openIn);
|
|
63
|
+
}
|
|
63
64
|
if (props.open === undefined) {
|
|
64
65
|
setOpenState(openIn);
|
|
65
66
|
}
|