clxx 2.1.2 → 2.1.4
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/LICENSE +20 -20
- package/README.md +768 -35
- package/build/Ago/index.d.ts +0 -1
- package/build/Alert/Wrapper.d.ts +0 -1
- package/build/Alert/Wrapper.js +12 -12
- package/build/Alert/index.js +2 -2
- package/build/AutoGrid/index.js +16 -21
- package/build/AutoGrid/style.d.ts +5 -5
- package/build/CarouselNotice/index.d.ts +0 -1
- package/build/CarouselNotice/index.js +6 -6
- package/build/CarouselNotice/style.d.ts +6 -1
- package/build/CarouselNotice/style.js +7 -7
- package/build/Clickable/index.d.ts +5 -5
- package/build/Clickable/index.js +11 -8
- package/build/Container/index.d.ts +2 -2
- package/build/Container/index.js +85 -60
- package/build/Countdowner/index.d.ts +3 -3
- package/build/Countdowner/index.js +18 -11
- package/build/Dialog/Wrapper.d.ts +0 -1
- package/build/Dialog/Wrapper.js +7 -10
- package/build/Dialog/style.d.ts +15 -10
- package/build/Dialog/style.js +88 -88
- package/build/Effect/useInterval.d.ts +1 -1
- package/build/Effect/useInterval.js +1 -1
- package/build/Effect/useUpdate.d.ts +1 -1
- package/build/Effect/useUpdate.js +1 -1
- package/build/Effect/useWindowResize.d.ts +4 -2
- package/build/Effect/useWindowResize.js +28 -11
- package/build/Flex/index.d.ts +0 -1
- package/build/Indicator/index.js +22 -23
- package/build/Indicator/style.d.ts +6 -1
- package/build/Indicator/style.js +7 -7
- package/build/Loading/Wrapper.js +2 -2
- package/build/Loading/style.d.ts +12 -2
- package/build/Loading/style.js +14 -14
- package/build/Overlay/index.d.ts +1 -1
- package/build/Overlay/index.js +41 -37
- package/build/SafeArea/index.d.ts +1 -2
- package/build/SafeArea/index.js +6 -6
- package/build/ScrollView/index.d.ts +1 -1
- package/build/ScrollView/index.js +111 -27
- package/build/Toast/Toast.js +4 -4
- package/build/Toast/style.d.ts +42 -12
- package/build/Toast/style.js +54 -54
- package/build/index.d.ts +3 -0
- package/build/index.js +3 -0
- package/build/utils/Countdown.d.ts +3 -1
- package/build/utils/Countdown.js +5 -2
- package/build/utils/createApp.d.ts +14 -13
- package/build/utils/createApp.js +58 -42
- package/build/utils/cssUtil.d.ts +2 -2
- package/build/utils/cssUtil.js +24 -13
- package/build/utils/defaultScroll.d.ts +0 -1
- package/build/utils/defaultScroll.js +8 -5
- package/build/utils/is.d.ts +23 -4
- package/build/utils/is.js +97 -15
- package/build/utils/jsonp.js +2 -2
- package/build/utils/request.js +12 -2
- package/package.json +15 -12
- package/test/README.md +16 -0
- package/test/eslint.config.js +29 -0
- package/test/index.html +13 -0
- package/test/jsconfig.json +8 -0
- package/test/package.json +27 -0
- package/test/public/vite.svg +1 -0
- package/test/src/ago/index.jsx +30 -0
- package/test/src/alert/index.jsx +111 -0
- package/test/src/autogrid/index.css +0 -0
- package/test/src/autogrid/index.jsx +26 -0
- package/test/src/carouse-notice/index.jsx +59 -0
- package/test/src/clickable/index.css +21 -0
- package/test/src/clickable/index.jsx +39 -0
- package/test/src/countdown/index.jsx +95 -0
- package/test/src/dialog/index.jsx +104 -0
- package/test/src/dialog/index.module.css +5 -0
- package/test/src/image-picker/index.css +0 -0
- package/test/src/image-picker/index.jsx +88 -0
- package/test/src/index/index.jsx +46 -0
- package/test/src/index.css +49 -0
- package/test/src/index.jsx +31 -0
- package/test/src/indicator/index.jsx +25 -0
- package/test/src/loading/index.jsx +36 -0
- package/test/src/overlay/index.jsx +31 -0
- package/test/src/privacy/index.css +13 -0
- package/test/src/privacy/index.jsx +34 -0
- package/test/src/scrollview/index.css +10 -0
- package/test/src/scrollview/index.jsx +52 -0
- package/test/src/toast/index.jsx +86 -0
- package/test/vite.config.js +15 -0
|
@@ -10,12 +10,12 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
14
14
|
import { Indicator } from "../Indicator";
|
|
15
15
|
import { RowCenter } from "../Flex/Row";
|
|
16
16
|
import { style } from "./style";
|
|
17
17
|
export function ScrollView(props) {
|
|
18
|
-
const { children, height, reachTopThreshold = 50, onReachTop, reachBottomThreshold = 50, onReachBottom, showLoading = true, loadingContent, onScroll, containerStyle, wrapperStyle, loadingStyle } = props, attrs = __rest(props, ["children", "height", "reachTopThreshold", "onReachTop", "reachBottomThreshold", "onReachBottom", "showLoading", "loadingContent", "onScroll", "containerStyle", "wrapperStyle", "loadingStyle"]);
|
|
18
|
+
const { children, height, reachTopThreshold = 50, onReachTop, reachBottomThreshold = 50, onReachBottom, showLoading = true, loadingContent, onScroll, scrollThrottle = 16, containerStyle, wrapperStyle, loadingStyle } = props, attrs = __rest(props, ["children", "height", "reachTopThreshold", "onReachTop", "reachBottomThreshold", "onReachBottom", "showLoading", "loadingContent", "onScroll", "scrollThrottle", "containerStyle", "wrapperStyle", "loadingStyle"]);
|
|
19
19
|
// 容器高度
|
|
20
20
|
const heightStyle = {};
|
|
21
21
|
if (height) {
|
|
@@ -23,58 +23,142 @@ export function ScrollView(props) {
|
|
|
23
23
|
}
|
|
24
24
|
// 滚动容器
|
|
25
25
|
const container = useRef(null);
|
|
26
|
-
const child = useRef(null);
|
|
27
26
|
// 当前滚动到顶部的距离
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const lastScrollTop = useRef(0);
|
|
28
|
+
// 防止重复触发的标记
|
|
29
|
+
const hasReachedTop = useRef(false);
|
|
30
|
+
const hasReachedBottom = useRef(false);
|
|
31
|
+
// 节流控制
|
|
32
|
+
const throttleTimer = useRef(undefined);
|
|
33
|
+
const lastCallTime = useRef(0);
|
|
34
|
+
// 使用 ref 保存最新的回调函数,避免闭包陈旧
|
|
35
|
+
const callbacksRef = useRef({
|
|
36
|
+
onScroll,
|
|
37
|
+
onReachTop,
|
|
38
|
+
onReachBottom,
|
|
39
|
+
});
|
|
40
|
+
// 每次渲染都更新 ref 中的回调
|
|
41
|
+
callbacksRef.current = {
|
|
42
|
+
onScroll,
|
|
43
|
+
onReachTop,
|
|
44
|
+
onReachBottom,
|
|
45
|
+
};
|
|
46
|
+
// container是否有滚动条
|
|
47
|
+
const [hasScrollBar, setHasScrollBar] = useState(false);
|
|
48
|
+
// 检查是否有滚动条
|
|
49
|
+
const checkScrollBar = useCallback(() => {
|
|
50
|
+
if (container.current) {
|
|
51
|
+
const hasScroll = container.current.scrollHeight > container.current.clientHeight;
|
|
52
|
+
setHasScrollBar(hasScroll);
|
|
53
|
+
}
|
|
54
|
+
}, []);
|
|
55
|
+
// 使用 ResizeObserver 监听内容高度变化
|
|
56
|
+
useLayoutEffect(() => {
|
|
57
|
+
const containerEl = container.current;
|
|
58
|
+
if (!containerEl)
|
|
59
|
+
return;
|
|
60
|
+
// 初始检查
|
|
61
|
+
checkScrollBar();
|
|
62
|
+
// 使用 ResizeObserver 监听尺寸变化
|
|
63
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
64
|
+
checkScrollBar();
|
|
65
|
+
});
|
|
66
|
+
// 观察容器和内容
|
|
67
|
+
resizeObserver.observe(containerEl);
|
|
68
|
+
if (containerEl.firstElementChild) {
|
|
69
|
+
resizeObserver.observe(containerEl.firstElementChild);
|
|
70
|
+
}
|
|
71
|
+
return () => {
|
|
72
|
+
resizeObserver.disconnect();
|
|
73
|
+
};
|
|
74
|
+
}, [checkScrollBar]);
|
|
75
|
+
// 滚动回调(带节流)
|
|
76
|
+
const scrollCallback = useCallback((rawEvent) => {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
// 节流控制
|
|
79
|
+
if (scrollThrottle > 0 && now - lastCallTime.current < scrollThrottle) {
|
|
80
|
+
// 清除之前的定时器
|
|
81
|
+
if (throttleTimer.current) {
|
|
82
|
+
clearTimeout(throttleTimer.current);
|
|
83
|
+
}
|
|
84
|
+
// 设置新的定时器,确保最后一次调用会被执行
|
|
85
|
+
throttleTimer.current = window.setTimeout(() => {
|
|
86
|
+
handleScroll(rawEvent);
|
|
87
|
+
}, scrollThrottle);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
lastCallTime.current = now;
|
|
91
|
+
handleScroll(rawEvent);
|
|
92
|
+
}, [scrollThrottle, reachTopThreshold, reachBottomThreshold]);
|
|
93
|
+
// 实际的滚动处理逻辑
|
|
94
|
+
const handleScroll = useCallback((rawEvent) => {
|
|
95
|
+
var _a, _b, _c, _d, _e, _f;
|
|
31
96
|
const box = container.current;
|
|
97
|
+
if (!box)
|
|
98
|
+
return;
|
|
32
99
|
// 已经滚动的距离
|
|
33
100
|
const scrollTop = box.scrollTop;
|
|
34
101
|
// 滚动容器的包含滚动内容的高度
|
|
35
102
|
const contentHeight = box.scrollHeight;
|
|
36
103
|
// 滚动容器的视口高度
|
|
37
104
|
const containerHeight = Math.min(box.clientHeight, box.offsetHeight);
|
|
38
|
-
//
|
|
39
|
-
const loadingHeight = (_b = (_a = box.children.item(1)) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0;
|
|
105
|
+
// 最大可滚动距离
|
|
40
106
|
const maxScroll = contentHeight - containerHeight;
|
|
107
|
+
// 计算滚动方向
|
|
108
|
+
const direction = scrollTop > lastScrollTop.current ? "downward" : "upward";
|
|
41
109
|
// 生成滚动事件参数
|
|
42
110
|
const event = {
|
|
43
111
|
containerHeight,
|
|
44
112
|
contentHeight,
|
|
45
113
|
maxScroll,
|
|
46
114
|
scrollTop,
|
|
47
|
-
direction
|
|
115
|
+
direction,
|
|
48
116
|
rawEvent,
|
|
49
117
|
};
|
|
50
|
-
//
|
|
51
|
-
onScroll === null ||
|
|
52
|
-
//
|
|
53
|
-
if (
|
|
54
|
-
|
|
118
|
+
// 调用通用滚动事件(使用 ref 中的最新回调)
|
|
119
|
+
(_b = (_a = callbacksRef.current).onScroll) === null || _b === void 0 ? void 0 : _b.call(_a, event);
|
|
120
|
+
// 触顶逻辑(防止重复触发)
|
|
121
|
+
if (direction === "upward" && scrollTop <= reachTopThreshold) {
|
|
122
|
+
if (!hasReachedTop.current) {
|
|
123
|
+
hasReachedTop.current = true;
|
|
124
|
+
hasReachedBottom.current = false; // 重置触底标记
|
|
125
|
+
(_d = (_c = callbacksRef.current).onReachTop) === null || _d === void 0 ? void 0 : _d.call(_c, event);
|
|
126
|
+
}
|
|
55
127
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
128
|
+
else if (scrollTop > reachTopThreshold) {
|
|
129
|
+
hasReachedTop.current = false;
|
|
130
|
+
}
|
|
131
|
+
// 触底逻辑(防止重复触发)
|
|
132
|
+
if (direction === "downward" && scrollTop >= maxScroll - reachBottomThreshold) {
|
|
133
|
+
if (!hasReachedBottom.current) {
|
|
134
|
+
hasReachedBottom.current = true;
|
|
135
|
+
hasReachedTop.current = false; // 重置触顶标记
|
|
136
|
+
(_f = (_e = callbacksRef.current).onReachBottom) === null || _f === void 0 ? void 0 : _f.call(_e, event);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (scrollTop < maxScroll - reachBottomThreshold) {
|
|
140
|
+
hasReachedBottom.current = false;
|
|
59
141
|
}
|
|
60
142
|
// 更新scrollTop上次的值
|
|
61
|
-
|
|
62
|
-
};
|
|
143
|
+
lastScrollTop.current = scrollTop;
|
|
144
|
+
}, [reachTopThreshold, reachBottomThreshold]);
|
|
145
|
+
// 清理节流定时器
|
|
146
|
+
useLayoutEffect(() => {
|
|
147
|
+
return () => {
|
|
148
|
+
if (throttleTimer.current) {
|
|
149
|
+
clearTimeout(throttleTimer.current);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}, []);
|
|
63
153
|
// loading内容
|
|
64
154
|
let showLoadingContent = null;
|
|
65
155
|
if (showLoading) {
|
|
66
156
|
if (!loadingContent) {
|
|
67
|
-
showLoadingContent = (_jsxs(RowCenter,
|
|
157
|
+
showLoadingContent = (_jsxs(RowCenter, { css: [style.loading, loadingStyle], children: [_jsx(Indicator, { barColor: "#333", barCount: 12 }), _jsx("p", { children: "\u6570\u636E\u52A0\u8F7D\u4E2D..." })] }));
|
|
68
158
|
}
|
|
69
159
|
else {
|
|
70
160
|
showLoadingContent = loadingContent;
|
|
71
161
|
}
|
|
72
162
|
}
|
|
73
|
-
|
|
74
|
-
const [hasScrollBar, setHasScrollBar] = useState(false);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
let hasScrollBar = container.current.scrollHeight > container.current.clientHeight;
|
|
77
|
-
setHasScrollBar(hasScrollBar);
|
|
78
|
-
});
|
|
79
|
-
return (_jsxs("div", Object.assign({ css: [style.container, heightStyle, containerStyle], onScroll: scrollCallback, ref: container }, attrs, { children: [_jsx("div", Object.assign({ css: wrapperStyle, ref: child }, { children: children })), hasScrollBar && showLoadingContent] })));
|
|
163
|
+
return (_jsxs("div", Object.assign({ css: [style.container, heightStyle, containerStyle], onScroll: scrollCallback, ref: container }, attrs, { children: [_jsx("div", { css: wrapperStyle, children: children }), hasScrollBar && showLoadingContent] })));
|
|
80
164
|
}
|
package/build/Toast/Toast.js
CHANGED
|
@@ -23,16 +23,16 @@ export function Toast(props) {
|
|
|
23
23
|
setAnimation(animation);
|
|
24
24
|
}, duration);
|
|
25
25
|
return () => {
|
|
26
|
-
window.
|
|
26
|
+
window.clearTimeout(timer);
|
|
27
27
|
};
|
|
28
|
-
}, [position]);
|
|
28
|
+
}, [position, duration]);
|
|
29
29
|
let showContent;
|
|
30
30
|
const middleStyle = position === "middle" ? style.contentMiddle : undefined;
|
|
31
31
|
if (React.isValidElement(content)) {
|
|
32
|
-
showContent = _jsx("div",
|
|
32
|
+
showContent = _jsx("div", { css: [middleStyle, contentStyle], children: content });
|
|
33
33
|
}
|
|
34
34
|
else {
|
|
35
|
-
showContent = (_jsx("p",
|
|
35
|
+
showContent = (_jsx("p", { css: [style.content(radius), middleStyle, contentStyle], children: content }));
|
|
36
36
|
}
|
|
37
37
|
// toast消失动画结束触发
|
|
38
38
|
const animationEnd = (event) => {
|
package/build/Toast/style.d.ts
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { Keyframes } from "@emotion/serialize";
|
|
2
|
-
export declare const middleShowAnimation:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
export declare const middleShowAnimation: {
|
|
3
|
+
name: string;
|
|
4
|
+
styles: string;
|
|
5
|
+
anim: 1;
|
|
6
|
+
toString: () => string;
|
|
7
|
+
} & string;
|
|
8
|
+
export declare const middleHideAnimation: {
|
|
9
|
+
name: string;
|
|
10
|
+
styles: string;
|
|
11
|
+
anim: 1;
|
|
12
|
+
toString: () => string;
|
|
13
|
+
} & string;
|
|
14
|
+
export declare const topShowAnimation: {
|
|
15
|
+
name: string;
|
|
16
|
+
styles: string;
|
|
17
|
+
anim: 1;
|
|
18
|
+
toString: () => string;
|
|
19
|
+
} & string;
|
|
20
|
+
export declare const topHideAnimation: {
|
|
21
|
+
name: string;
|
|
22
|
+
styles: string;
|
|
23
|
+
anim: 1;
|
|
24
|
+
toString: () => string;
|
|
25
|
+
} & string;
|
|
26
|
+
export declare const bottomShowAnimation: {
|
|
27
|
+
name: string;
|
|
28
|
+
styles: string;
|
|
29
|
+
anim: 1;
|
|
30
|
+
toString: () => string;
|
|
31
|
+
} & string;
|
|
32
|
+
export declare const bottomHideAnimation: {
|
|
33
|
+
name: string;
|
|
34
|
+
styles: string;
|
|
35
|
+
anim: 1;
|
|
36
|
+
toString: () => string;
|
|
37
|
+
} & string;
|
|
8
38
|
/**
|
|
9
39
|
* 根据位置和类型获取动画
|
|
10
40
|
* @param position
|
|
@@ -13,14 +43,14 @@ export declare const bottomHideAnimation: Keyframes;
|
|
|
13
43
|
*/
|
|
14
44
|
export declare function getAnimation(position: "top" | "middle" | "bottom", type: "show" | "hide"): {
|
|
15
45
|
keyframes: Keyframes;
|
|
16
|
-
animation: import("@emotion/
|
|
46
|
+
animation: import("@emotion/react").SerializedStyles;
|
|
17
47
|
};
|
|
18
48
|
export declare const style: {
|
|
19
|
-
container(): import("@emotion/
|
|
20
|
-
top(offset: number): import("@emotion/
|
|
21
|
-
middle: import("@emotion/
|
|
22
|
-
bottom(offset: number): import("@emotion/
|
|
23
|
-
content: (radius?: number) => import("@emotion/
|
|
49
|
+
container(): import("@emotion/react").SerializedStyles;
|
|
50
|
+
top(offset: number): import("@emotion/react").SerializedStyles;
|
|
51
|
+
middle: import("@emotion/react").SerializedStyles;
|
|
52
|
+
bottom(offset: number): import("@emotion/react").SerializedStyles;
|
|
53
|
+
content: (radius?: number) => import("@emotion/react").SerializedStyles;
|
|
24
54
|
contentMiddle: {
|
|
25
55
|
transform: string;
|
|
26
56
|
};
|
package/build/Toast/style.js
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
import { css, keyframes } from "@emotion/react";
|
|
2
2
|
import { adaptive } from "../utils/cssUtil";
|
|
3
|
-
export const middleShowAnimation = keyframes `
|
|
4
|
-
from {
|
|
5
|
-
opacity: 0;
|
|
6
|
-
transform: translateX(-50%) scale(0.9);
|
|
7
|
-
}
|
|
8
|
-
to {
|
|
9
|
-
opacity: 1;
|
|
10
|
-
transform: translateX(-50%) scale(1);
|
|
11
|
-
}
|
|
3
|
+
export const middleShowAnimation = keyframes `
|
|
4
|
+
from {
|
|
5
|
+
opacity: 0;
|
|
6
|
+
transform: translateX(-50%) scale(0.9);
|
|
7
|
+
}
|
|
8
|
+
to {
|
|
9
|
+
opacity: 1;
|
|
10
|
+
transform: translateX(-50%) scale(1);
|
|
11
|
+
}
|
|
12
12
|
`;
|
|
13
|
-
export const middleHideAnimation = keyframes `
|
|
14
|
-
from {
|
|
15
|
-
opacity: 1;
|
|
16
|
-
transform: translateX(-50%) scale(1);
|
|
17
|
-
}
|
|
18
|
-
to {
|
|
19
|
-
opacity: 0;
|
|
20
|
-
transform: translateX(-50%) scale(0.9);
|
|
21
|
-
}
|
|
13
|
+
export const middleHideAnimation = keyframes `
|
|
14
|
+
from {
|
|
15
|
+
opacity: 1;
|
|
16
|
+
transform: translateX(-50%) scale(1);
|
|
17
|
+
}
|
|
18
|
+
to {
|
|
19
|
+
opacity: 0;
|
|
20
|
+
transform: translateX(-50%) scale(0.9);
|
|
21
|
+
}
|
|
22
22
|
`;
|
|
23
|
-
export const topShowAnimation = keyframes `
|
|
24
|
-
from {
|
|
25
|
-
opacity: 0;
|
|
26
|
-
transform: translate(-50%, -100%);
|
|
27
|
-
}
|
|
28
|
-
to {
|
|
29
|
-
opacity: 1;
|
|
30
|
-
transform: translate(-50%, 0);
|
|
31
|
-
}
|
|
23
|
+
export const topShowAnimation = keyframes `
|
|
24
|
+
from {
|
|
25
|
+
opacity: 0;
|
|
26
|
+
transform: translate(-50%, -100%);
|
|
27
|
+
}
|
|
28
|
+
to {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
transform: translate(-50%, 0);
|
|
31
|
+
}
|
|
32
32
|
`;
|
|
33
|
-
export const topHideAnimation = keyframes `
|
|
34
|
-
from {
|
|
35
|
-
opacity: 1;
|
|
36
|
-
transform: translate(-50%, 0);
|
|
37
|
-
}
|
|
38
|
-
to {
|
|
39
|
-
opacity: 0;
|
|
40
|
-
transform: translate(-50%, -100%);
|
|
41
|
-
}
|
|
33
|
+
export const topHideAnimation = keyframes `
|
|
34
|
+
from {
|
|
35
|
+
opacity: 1;
|
|
36
|
+
transform: translate(-50%, 0);
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
opacity: 0;
|
|
40
|
+
transform: translate(-50%, -100%);
|
|
41
|
+
}
|
|
42
42
|
`;
|
|
43
|
-
export const bottomShowAnimation = keyframes `
|
|
44
|
-
from {
|
|
45
|
-
opacity: 0;
|
|
46
|
-
transform: translate(-50%, 100%);
|
|
47
|
-
}
|
|
48
|
-
to {
|
|
49
|
-
opacity: 1;
|
|
50
|
-
transform: translate(-50%, 0);
|
|
51
|
-
}
|
|
43
|
+
export const bottomShowAnimation = keyframes `
|
|
44
|
+
from {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transform: translate(-50%, 100%);
|
|
47
|
+
}
|
|
48
|
+
to {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
transform: translate(-50%, 0);
|
|
51
|
+
}
|
|
52
52
|
`;
|
|
53
|
-
export const bottomHideAnimation = keyframes `
|
|
54
|
-
from {
|
|
55
|
-
opacity: 1;
|
|
56
|
-
transform: translate(-50%, 0);
|
|
57
|
-
}
|
|
58
|
-
to {
|
|
59
|
-
opacity: 0;
|
|
60
|
-
transform: translate(-50%, 100%);
|
|
61
|
-
}
|
|
53
|
+
export const bottomHideAnimation = keyframes `
|
|
54
|
+
from {
|
|
55
|
+
opacity: 1;
|
|
56
|
+
transform: translate(-50%, 0);
|
|
57
|
+
}
|
|
58
|
+
to {
|
|
59
|
+
opacity: 0;
|
|
60
|
+
transform: translate(-50%, 100%);
|
|
61
|
+
}
|
|
62
62
|
`;
|
|
63
63
|
/**
|
|
64
64
|
* 根据位置和类型获取动画
|
package/build/index.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ export { createApp, history, getHistory } from './utils/createApp';
|
|
|
14
14
|
export { createPortalDOM } from './utils/dom';
|
|
15
15
|
export { useInterval } from './Effect/useInterval';
|
|
16
16
|
export { useTick } from './Effect/useTick';
|
|
17
|
+
export { useUpdate } from './Effect/useUpdate';
|
|
18
|
+
export { useWindowResize } from './Effect/useWindowResize';
|
|
19
|
+
export { useViewport } from './Effect/useViewport';
|
|
17
20
|
export { Ago } from './Ago';
|
|
18
21
|
export { Container } from './Container';
|
|
19
22
|
export { Flex, FlexItem } from './Flex';
|
package/build/index.js
CHANGED
|
@@ -14,6 +14,9 @@ export { createApp, history, getHistory } from './utils/createApp';
|
|
|
14
14
|
export { createPortalDOM } from './utils/dom';
|
|
15
15
|
export { useInterval } from './Effect/useInterval';
|
|
16
16
|
export { useTick } from './Effect/useTick';
|
|
17
|
+
export { useUpdate } from './Effect/useUpdate';
|
|
18
|
+
export { useWindowResize } from './Effect/useWindowResize';
|
|
19
|
+
export { useViewport } from './Effect/useViewport';
|
|
17
20
|
export { Ago } from './Ago';
|
|
18
21
|
export { Container } from './Container';
|
|
19
22
|
export { Flex, FlexItem } from './Flex';
|
package/build/utils/Countdown.js
CHANGED
|
@@ -54,6 +54,7 @@ export class Countdown {
|
|
|
54
54
|
(_d = this._onUpdate) === null || _d === void 0 ? void 0 : _d.call(this, this.formatValue());
|
|
55
55
|
// 记录倒计时开启时的时间
|
|
56
56
|
const start = Date.now();
|
|
57
|
+
// 使用 1000ms 间隔,避免每帧都执行(性能优化)
|
|
57
58
|
this._stopTick = tick(() => {
|
|
58
59
|
var _a, _b, _c, _d;
|
|
59
60
|
// 获取倒计时已经持续的时间
|
|
@@ -72,7 +73,7 @@ export class Countdown {
|
|
|
72
73
|
this.remain = currentRemain;
|
|
73
74
|
(_d = this._onUpdate) === null || _d === void 0 ? void 0 : _d.call(this, this.formatValue());
|
|
74
75
|
}
|
|
75
|
-
});
|
|
76
|
+
}, 1000); // ← 添加 1000ms 间隔
|
|
76
77
|
}
|
|
77
78
|
// 停止倒计时
|
|
78
79
|
stop() {
|
|
@@ -82,7 +83,9 @@ export class Countdown {
|
|
|
82
83
|
}
|
|
83
84
|
/**
|
|
84
85
|
* 格式化每次更新的值
|
|
85
|
-
*
|
|
86
|
+
* 注意:format 的顺序决定了如何分配时间
|
|
87
|
+
* 例如:format='his' 时,72小时会显示为 72:00:00
|
|
88
|
+
* format='dhis' 时,72小时会显示为 3:0:00:00(3天)
|
|
86
89
|
*/
|
|
87
90
|
formatValue() {
|
|
88
91
|
let remainTime = this.remain;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { History } from
|
|
3
|
-
import { ContainerProps } from
|
|
4
|
-
import { ContextValue } from
|
|
5
|
-
export type
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { History } from "history";
|
|
3
|
+
import { ContainerProps } from "../Container";
|
|
4
|
+
import { ContextValue } from "../context";
|
|
5
|
+
export type RouterMode = "browser" | "hash" | "memory";
|
|
6
6
|
export type AwaitValue<T> = T | Promise<T>;
|
|
7
|
-
export interface CreateAppOption extends Omit<ContainerProps,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
export interface CreateAppOption extends Omit<ContainerProps, "children">, ContextValue {
|
|
8
|
+
onBefore?: (pathname: string) => AwaitValue<void>;
|
|
9
|
+
onAfter?: (pathname: string) => AwaitValue<void>;
|
|
10
|
+
loading?: (pathname: string) => AwaitValue<React.ReactNode>;
|
|
11
|
+
render?: (pathname: string) => AwaitValue<React.ReactNode>;
|
|
12
|
+
notFound?: (pathname: string) => AwaitValue<React.ReactNode>;
|
|
13
|
+
mode?: RouterMode;
|
|
14
|
+
default?: string;
|
|
14
15
|
target: string | HTMLElement;
|
|
15
16
|
}
|
|
16
17
|
export declare let history: null | History;
|
|
17
|
-
export declare function getHistory(
|
|
18
|
+
export declare function getHistory(mode?: RouterMode): History;
|
|
18
19
|
/**
|
|
19
20
|
* 创建带路由的APP对象,全局对象,绝大部分情况下只需要调用一次
|
|
20
21
|
* @param option CreateAppOption
|
package/build/utils/createApp.js
CHANGED
|
@@ -7,24 +7,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
11
|
-
import { useCallback, useEffect, useState } from
|
|
12
|
-
import { createRoot } from
|
|
13
|
-
import { createBrowserHistory, createHashHistory, createMemoryHistory, } from
|
|
14
|
-
import { Container } from
|
|
15
|
-
import { setContextValue } from
|
|
16
|
-
import pick from
|
|
10
|
+
import { jsxs as _jsxs, jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
11
|
+
import { useCallback, useEffect, useState } from "react";
|
|
12
|
+
import { createRoot } from "react-dom/client";
|
|
13
|
+
import { createBrowserHistory, createHashHistory, createMemoryHistory, } from "history";
|
|
14
|
+
import { Container } from "../Container";
|
|
15
|
+
import { setContextValue } from "../context";
|
|
16
|
+
import pick from "lodash/pick";
|
|
17
17
|
// 存储历史记录对象
|
|
18
18
|
export let history = null;
|
|
19
19
|
// 获取历史记录对象
|
|
20
|
-
export function getHistory(
|
|
20
|
+
export function getHistory(mode = "browser") {
|
|
21
21
|
if (history === null) {
|
|
22
22
|
const createMap = {
|
|
23
23
|
browser: createBrowserHistory,
|
|
24
24
|
hash: createHashHistory,
|
|
25
25
|
memory: createMemoryHistory,
|
|
26
26
|
};
|
|
27
|
-
history = createMap[
|
|
27
|
+
history = createMap[mode]();
|
|
28
28
|
}
|
|
29
29
|
return history;
|
|
30
30
|
}
|
|
@@ -35,25 +35,31 @@ export function getHistory(routeMethod = 'browser') {
|
|
|
35
35
|
export function createApp(option) {
|
|
36
36
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
37
|
// 设置默认的路由方式
|
|
38
|
-
if (!option.
|
|
39
|
-
[
|
|
40
|
-
option.
|
|
38
|
+
if (!option.mode ||
|
|
39
|
+
["browser", "hash", "memory"].indexOf(option.mode) === -1) {
|
|
40
|
+
option.mode = "browser";
|
|
41
41
|
}
|
|
42
42
|
// 设置默认路由路径
|
|
43
|
-
if (!option.
|
|
44
|
-
option.
|
|
43
|
+
if (!option.default) {
|
|
44
|
+
option.default = "/index";
|
|
45
45
|
}
|
|
46
46
|
// 这里是为了确保历史记录对象在组件渲染之前一定存在
|
|
47
|
-
history = getHistory(option.
|
|
47
|
+
history = getHistory(option.mode);
|
|
48
48
|
// 提取关键数据
|
|
49
|
-
const context = pick(option, [
|
|
49
|
+
const context = pick(option, ["minDocWidth", "maxDocWidth"]);
|
|
50
50
|
const containerProps = pick(option, [
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
"designWidth",
|
|
52
|
+
"globalStyle",
|
|
53
53
|
]);
|
|
54
|
-
const {
|
|
54
|
+
const { onBefore, onAfter, loading, render, notFound } = option;
|
|
55
55
|
// 设置上下文属性
|
|
56
56
|
setContextValue(context);
|
|
57
|
+
// 规范化路径:移除首尾斜杠
|
|
58
|
+
const PATH_TRIM_REGEX = /^\/*|\/*$/g;
|
|
59
|
+
const normalizePath = (path) => {
|
|
60
|
+
const normalized = path.replace(PATH_TRIM_REGEX, "");
|
|
61
|
+
return normalized || option.default.replace(PATH_TRIM_REGEX, "");
|
|
62
|
+
};
|
|
57
63
|
/**
|
|
58
64
|
* 全局APP组件对象
|
|
59
65
|
* @returns
|
|
@@ -61,50 +67,60 @@ export function createApp(option) {
|
|
|
61
67
|
const App = () => {
|
|
62
68
|
const [page, setPage] = useState(null);
|
|
63
69
|
/**
|
|
64
|
-
*
|
|
70
|
+
* 加载并渲染页面
|
|
65
71
|
*/
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
// 如果有loading,要先显示loading
|
|
73
|
-
if (typeof onLoadingPage === 'function') {
|
|
74
|
-
setPage(yield (onLoadingPage === null || onLoadingPage === void 0 ? void 0 : onLoadingPage(pathname)));
|
|
72
|
+
const loadAndRenderPage = useCallback((pathname) => __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
const normalizedPath = normalizePath(pathname);
|
|
74
|
+
// 如果有 loading 占位符,先显示
|
|
75
|
+
if (typeof loading === "function") {
|
|
76
|
+
setPage(yield loading(normalizedPath));
|
|
75
77
|
}
|
|
76
|
-
//
|
|
77
|
-
yield (
|
|
78
|
+
// 页面加载前钩子
|
|
79
|
+
yield (onBefore === null || onBefore === void 0 ? void 0 : onBefore(normalizedPath));
|
|
78
80
|
// 加载并显示页面
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
if (typeof render === "function") {
|
|
82
|
+
const pageContent = yield render(normalizedPath);
|
|
83
|
+
// 如果返回 null/undefined,视为页面未找到
|
|
84
|
+
if (pageContent === null || pageContent === undefined) {
|
|
85
|
+
if (typeof notFound === "function") {
|
|
86
|
+
setPage(yield notFound(normalizedPath));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// 默认 404 页面
|
|
90
|
+
setPage(_jsxs("div", { children: ["Not Found: ", normalizedPath] }));
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
setPage(pageContent);
|
|
95
|
+
}
|
|
96
|
+
// 页面加载后钩子
|
|
97
|
+
yield (onAfter === null || onAfter === void 0 ? void 0 : onAfter(normalizedPath));
|
|
98
|
+
}), [onBefore, onAfter, loading, render, notFound]);
|
|
83
99
|
/**
|
|
84
|
-
*
|
|
100
|
+
* 监听路由变化
|
|
85
101
|
*/
|
|
86
102
|
useEffect(() => {
|
|
87
103
|
// 监听页面变化,一旦变化渲染新页面
|
|
88
104
|
const unlisten = history.listen(({ location }) => {
|
|
89
|
-
|
|
105
|
+
loadAndRenderPage(location.pathname);
|
|
90
106
|
});
|
|
91
|
-
//
|
|
92
|
-
|
|
107
|
+
// 初始化时渲染当前路径对应的页面
|
|
108
|
+
loadAndRenderPage(history.location.pathname);
|
|
93
109
|
// 卸载时,取消监听
|
|
94
110
|
return unlisten;
|
|
95
|
-
}, []);
|
|
111
|
+
}, [loadAndRenderPage]);
|
|
96
112
|
return _jsx(Container, Object.assign({}, containerProps, { children: page }));
|
|
97
113
|
};
|
|
98
114
|
// 获取挂载对象
|
|
99
115
|
let mount = null;
|
|
100
|
-
if (typeof option.target ===
|
|
116
|
+
if (typeof option.target === "string") {
|
|
101
117
|
mount = document.querySelector(option.target);
|
|
102
118
|
}
|
|
103
119
|
else if (option.target instanceof HTMLElement) {
|
|
104
120
|
mount = option.target;
|
|
105
121
|
}
|
|
106
122
|
else {
|
|
107
|
-
throw new Error(
|
|
123
|
+
throw new Error("No mounted object is specified");
|
|
108
124
|
}
|
|
109
125
|
const root = createRoot(mount);
|
|
110
126
|
root.render(_jsx(App, {}));
|