clxx 2.1.4 → 2.1.6
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/README.md +766 -422
- package/build/Alert/style.js +41 -58
- package/build/AutoGrid/index.js +32 -43
- package/build/AutoGrid/style.d.ts +3 -4
- package/build/AutoGrid/style.js +7 -19
- package/build/CarouselNotice/style.js +6 -11
- package/build/Clickable/index.d.ts +1 -0
- package/build/Clickable/index.js +77 -41
- package/build/Container/index.js +46 -80
- package/build/Dialog/style.js +2 -2
- package/build/Fixed/index.d.ts +5 -0
- package/build/Fixed/index.js +37 -0
- package/build/Indicator/index.js +5 -5
- package/build/Loading/style.js +16 -17
- package/build/Overlay/index.js +4 -32
- package/build/ScrollView/index.js +65 -47
- package/build/ScrollView/style.js +12 -13
- package/build/Toast/index.js +5 -3
- package/build/Toast/style.js +11 -14
- package/build/context.d.ts +2 -3
- package/build/context.js +1 -4
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/utils/Countdown.js +11 -4
- package/build/utils/ago.js +39 -52
- package/build/utils/createApp.d.ts +1 -2
- package/build/utils/createApp.js +23 -12
- package/build/utils/cssUtil.d.ts +0 -9
- package/build/utils/cssUtil.js +0 -38
- package/build/utils/defaultScroll.d.ts +4 -4
- package/build/utils/defaultScroll.js +6 -15
- package/build/utils/dom.js +5 -8
- package/build/utils/jsonp.js +7 -4
- package/build/utils/request.js +23 -33
- package/build/utils/tick.js +7 -14
- package/build/utils/uniqKey.js +7 -7
- package/build/utils/wait.js +1 -1
- package/package.json +10 -10
- package/test/eslint.config.js +5 -2
- package/test/package.json +11 -11
- package/test/src/ago/index.jsx +3 -1
- package/test/src/dialog/index.module.css +1 -1
- package/test/src/index.jsx +3 -2
package/build/Alert/style.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import { adaptive } from "../utils/cssUtil";
|
|
2
1
|
export const style = {
|
|
3
|
-
container:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
borderRadius: 16,
|
|
12
|
-
width: 750 * 0.84,
|
|
13
|
-
}),
|
|
14
|
-
],
|
|
2
|
+
container: {
|
|
3
|
+
position: "relative",
|
|
4
|
+
overflow: "hidden",
|
|
5
|
+
backgroundColor: "#fff",
|
|
6
|
+
boxShadow: "0 0 2px 0 #00000055",
|
|
7
|
+
borderRadius: '.16rem',
|
|
8
|
+
width: 750 * 0.84 / 100 + 'rem',
|
|
9
|
+
},
|
|
15
10
|
content: {
|
|
16
11
|
position: "relative",
|
|
17
12
|
"&:after,&::after": {
|
|
@@ -25,38 +20,30 @@ export const style = {
|
|
|
25
20
|
transform: `scale(1, ${1 / window.devicePixelRatio})`,
|
|
26
21
|
},
|
|
27
22
|
},
|
|
28
|
-
title:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
paddingTop: 20,
|
|
50
|
-
paddingLeft: 40,
|
|
51
|
-
paddingRight: 40,
|
|
52
|
-
paddingBottom: 50,
|
|
53
|
-
fontSize: 29,
|
|
54
|
-
}),
|
|
55
|
-
],
|
|
56
|
-
btnBox: adaptive({
|
|
23
|
+
title: {
|
|
24
|
+
textAlign: "center",
|
|
25
|
+
lineHeight: 1.4,
|
|
26
|
+
color: "#000",
|
|
27
|
+
paddingTop: '.5rem',
|
|
28
|
+
paddingLeft: '.4rem',
|
|
29
|
+
paddingRight: '.4rem',
|
|
30
|
+
paddingBottom: '.5rem',
|
|
31
|
+
fontSize: '.33rem',
|
|
32
|
+
},
|
|
33
|
+
desc: {
|
|
34
|
+
textAlign: "center",
|
|
35
|
+
lineHeight: 1.4,
|
|
36
|
+
color: "#666",
|
|
37
|
+
paddingTop: '.2rem',
|
|
38
|
+
paddingLeft: '.4rem',
|
|
39
|
+
paddingRight: '.4rem',
|
|
40
|
+
paddingBottom: '.5rem',
|
|
41
|
+
fontSize: '.29rem',
|
|
42
|
+
},
|
|
43
|
+
btnBox: {
|
|
57
44
|
position: "relative",
|
|
58
|
-
height:
|
|
59
|
-
}
|
|
45
|
+
height: '.9rem',
|
|
46
|
+
},
|
|
60
47
|
btnBoxWithCancel: {
|
|
61
48
|
"&:after,&::after": {
|
|
62
49
|
content: "''",
|
|
@@ -67,20 +54,16 @@ export const style = {
|
|
|
67
54
|
marginLeft: "-.5px",
|
|
68
55
|
width: "1px",
|
|
69
56
|
backgroundColor: "#c0c0c0",
|
|
70
|
-
transform: `scale(${1 / devicePixelRatio}, 1)`,
|
|
57
|
+
transform: `scale(${1 / window.devicePixelRatio}, 1)`,
|
|
71
58
|
},
|
|
72
59
|
},
|
|
73
|
-
btn:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
adaptive({
|
|
83
|
-
fontSize: 33,
|
|
84
|
-
}),
|
|
85
|
-
],
|
|
60
|
+
btn: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
display: "flex",
|
|
63
|
+
alignItems: "center",
|
|
64
|
+
justifyContent: "center",
|
|
65
|
+
userSelect: "none",
|
|
66
|
+
letterSpacing: "1px",
|
|
67
|
+
fontSize: '.33rem',
|
|
68
|
+
},
|
|
86
69
|
};
|
package/build/AutoGrid/index.js
CHANGED
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
13
|
-
import React, {
|
|
13
|
+
import React, { useMemo } from 'react';
|
|
14
14
|
import { style } from './style';
|
|
15
15
|
import { normalizeUnit } from '../utils/cssUtil';
|
|
16
16
|
/**
|
|
@@ -19,55 +19,44 @@ import { normalizeUnit } from '../utils/cssUtil';
|
|
|
19
19
|
*/
|
|
20
20
|
export function AutoGrid(props) {
|
|
21
21
|
const { children, cols: rawCols = 1, gap: rawGap = 0, isSquare = false, itemStyle, containerStyle } = props, extra = __rest(props, ["children", "cols", "gap", "isSquare", "itemStyle", "containerStyle"]);
|
|
22
|
-
//
|
|
23
|
-
const cols = +rawCols;
|
|
22
|
+
// 规范化,确保 cols >= 1
|
|
23
|
+
const cols = Math.max(1, Math.floor(+rawCols) || 1);
|
|
24
24
|
const gap = normalizeUnit(rawGap);
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
let list = [];
|
|
25
|
+
// 将 children 分组为二维数组
|
|
26
|
+
const gridData = useMemo(() => {
|
|
27
|
+
const list = [];
|
|
29
28
|
React.Children.forEach(children, (child) => {
|
|
30
|
-
if (child !== null) {
|
|
29
|
+
if (child !== null && child !== undefined) {
|
|
31
30
|
if (list.length === 0 || list[list.length - 1].length >= cols) {
|
|
32
31
|
list.push([]);
|
|
33
32
|
}
|
|
34
33
|
list[list.length - 1].push(child);
|
|
35
34
|
}
|
|
36
35
|
});
|
|
36
|
+
// 用空占位符补齐最后一行,避免最后一行元素宽度不一致
|
|
37
|
+
if (list.length > 0) {
|
|
38
|
+
const lastRow = list[list.length - 1];
|
|
39
|
+
while (lastRow.length < cols) {
|
|
40
|
+
lastRow.push(null);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
37
43
|
return list;
|
|
38
|
-
}, [children]);
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
rowIndex !== gridData.length - 1 ? { marginBottom: gap } : {}
|
|
57
|
-
];
|
|
58
|
-
return (_jsx("div", { css: finalRowStyle, children: row.map((item, colIndex) => {
|
|
59
|
-
let finalCss = [
|
|
60
|
-
...finalItemBoxStyle,
|
|
61
|
-
itemStyle
|
|
62
|
-
];
|
|
63
|
-
if (isSquare) {
|
|
64
|
-
return (_jsx("div", { css: [...finalCss, style.itemBoxSquare], children: _jsx("div", { css: style.itemInnerStyle, children: item }) }, colIndex));
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
return (_jsx("div", { css: finalCss, children: item }, colIndex));
|
|
68
|
-
}
|
|
69
|
-
}) }, rowIndex));
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
|
-
return (_jsx("div", Object.assign({}, extra, { css: [containerStyle], children: showContent() })));
|
|
44
|
+
}, [children, cols]);
|
|
45
|
+
// 缓存 item 宽度计算
|
|
46
|
+
const itemWidth = useMemo(() => `calc((100% - ${cols - 1} * ${gap}) / ${cols})`, [cols, gap]);
|
|
47
|
+
return (_jsx("div", Object.assign({}, extra, { css: containerStyle, children: gridData.map((row, rowIndex) => (_jsx("div", { css: [
|
|
48
|
+
style.row,
|
|
49
|
+
{ gap },
|
|
50
|
+
rowIndex !== gridData.length - 1 ? { marginBottom: gap } : undefined,
|
|
51
|
+
], children: row.map((item, colIndex) => {
|
|
52
|
+
const isPlaceholder = item === null;
|
|
53
|
+
const boxCss = [
|
|
54
|
+
style.itemBox,
|
|
55
|
+
{ width: itemWidth },
|
|
56
|
+
isPlaceholder ? { visibility: 'hidden' } : undefined,
|
|
57
|
+
isSquare ? style.itemBoxSquare : undefined,
|
|
58
|
+
itemStyle,
|
|
59
|
+
];
|
|
60
|
+
return isSquare ? (_jsx("div", { css: boxCss, children: _jsx("div", { css: style.itemInner, children: item }) }, colIndex)) : (_jsx("div", { css: boxCss, children: item }, colIndex));
|
|
61
|
+
}) }, rowIndex))) })));
|
|
73
62
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export declare const style: {
|
|
2
|
-
|
|
2
|
+
row: import("@emotion/react").SerializedStyles;
|
|
3
|
+
itemBox: import("@emotion/react").SerializedStyles;
|
|
3
4
|
itemBoxSquare: import("@emotion/react").SerializedStyles;
|
|
4
|
-
|
|
5
|
-
itemInnerStyle: import("@emotion/react").SerializedStyles;
|
|
6
|
-
rowStyle: import("@emotion/react").SerializedStyles;
|
|
5
|
+
itemInner: import("@emotion/react").SerializedStyles;
|
|
7
6
|
};
|
package/build/AutoGrid/style.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { css } from "@emotion/react";
|
|
2
2
|
export const style = {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
row: css({
|
|
4
|
+
display: "flex",
|
|
5
|
+
width: "100%",
|
|
6
|
+
}),
|
|
7
|
+
itemBox: css({
|
|
5
8
|
position: "relative",
|
|
6
|
-
|
|
7
|
-
marginRight: 0,
|
|
8
|
-
},
|
|
9
|
+
minWidth: 0,
|
|
9
10
|
}),
|
|
10
11
|
itemBoxSquare: css({
|
|
11
12
|
"&:after,&::after": {
|
|
@@ -16,24 +17,11 @@ export const style = {
|
|
|
16
17
|
paddingBottom: "100%",
|
|
17
18
|
},
|
|
18
19
|
}),
|
|
19
|
-
|
|
20
|
-
visibility: "hidden",
|
|
21
|
-
}),
|
|
22
|
-
itemInnerStyle: css({
|
|
20
|
+
itemInner: css({
|
|
23
21
|
position: "absolute",
|
|
24
22
|
left: 0,
|
|
25
23
|
right: 0,
|
|
26
24
|
bottom: 0,
|
|
27
25
|
top: 0,
|
|
28
26
|
}),
|
|
29
|
-
// 行样式
|
|
30
|
-
rowStyle: css({
|
|
31
|
-
width: "100%",
|
|
32
|
-
"&:after,&::after": {
|
|
33
|
-
content: "''",
|
|
34
|
-
display: "table",
|
|
35
|
-
height: 0,
|
|
36
|
-
clear: "both"
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
27
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { keyframes } from "@emotion/react";
|
|
2
|
-
import { adaptive } from "../utils/cssUtil";
|
|
3
2
|
export const Bubble = keyframes `
|
|
4
3
|
from {
|
|
5
4
|
transform: translateY(0);
|
|
@@ -9,16 +8,12 @@ export const Bubble = keyframes `
|
|
|
9
8
|
}
|
|
10
9
|
`;
|
|
11
10
|
export const style = {
|
|
12
|
-
box:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
adaptive({
|
|
19
|
-
height: 80,
|
|
20
|
-
}),
|
|
21
|
-
],
|
|
11
|
+
box: {
|
|
12
|
+
position: "relative",
|
|
13
|
+
overflow: "hidden",
|
|
14
|
+
transition: "all 200ms",
|
|
15
|
+
height: '.8rem',
|
|
16
|
+
},
|
|
22
17
|
wrapper: {
|
|
23
18
|
position: "absolute",
|
|
24
19
|
left: 0,
|
|
@@ -8,5 +8,6 @@ export interface ClickableProps extends React.HTMLProps<HTMLDivElement> {
|
|
|
8
8
|
activeClassName?: string;
|
|
9
9
|
activeStyle?: React.CSSProperties;
|
|
10
10
|
disable?: boolean;
|
|
11
|
+
moveThreshold?: number;
|
|
11
12
|
}
|
|
12
13
|
export declare function Clickable(props: Partial<ClickableProps>): import("@emotion/react/jsx-runtime").JSX.Element;
|
package/build/Clickable/index.js
CHANGED
|
@@ -13,74 +13,110 @@ import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
|
13
13
|
import React, { useCallback, useRef, useState, useEffect, } from 'react';
|
|
14
14
|
import { is } from '../utils/is';
|
|
15
15
|
export function Clickable(props) {
|
|
16
|
-
let { children, bubble = true, className, activeClassName, style, activeStyle, disable = false } = props, attrs = __rest(props, ["children", "bubble", "className", "activeClassName", "style", "activeStyle", "disable"]);
|
|
16
|
+
let { children, bubble = true, className, activeClassName, style, activeStyle, disable = false, moveThreshold = 10 } = props, attrs = __rest(props, ["children", "bubble", "className", "activeClassName", "style", "activeStyle", "disable", "moveThreshold"]);
|
|
17
17
|
// 如果激活样式和激活类都不存在,则设置激活默认样式
|
|
18
|
-
|
|
19
|
-
const defaultActiveStyle = React.useMemo(() => {
|
|
18
|
+
const finalActiveStyle = React.useMemo(() => {
|
|
20
19
|
if (!activeClassName && !activeStyle) {
|
|
21
20
|
return { opacity: 0.6 };
|
|
22
21
|
}
|
|
23
22
|
return activeStyle;
|
|
24
23
|
}, [activeClassName, activeStyle]);
|
|
25
|
-
const finalActiveStyle = defaultActiveStyle || activeStyle;
|
|
26
24
|
const touchable = is('touchable');
|
|
27
|
-
const [
|
|
28
|
-
|
|
29
|
-
// 监控属性的更新
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
setBoxClass(className);
|
|
32
|
-
setBoxStyle(style);
|
|
33
|
-
}, [className, style]);
|
|
34
|
-
// 标记是否正处于触摸状态
|
|
25
|
+
const [isActive, setIsActive] = useState(false);
|
|
26
|
+
// 标记是否正处于触摸/按下状态
|
|
35
27
|
const touchRef = useRef(false);
|
|
36
|
-
|
|
28
|
+
// 是否已挂载(防止卸载后更新 state)
|
|
29
|
+
const mountedRef = useRef(true);
|
|
30
|
+
// 记录触摸起始坐标,用于 touchmove 取消
|
|
31
|
+
const startPos = useRef({ x: 0, y: 0 });
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
mountedRef.current = true;
|
|
34
|
+
return () => {
|
|
35
|
+
mountedRef.current = false;
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
const activate = useCallback(() => {
|
|
39
|
+
if (mountedRef.current)
|
|
40
|
+
setIsActive(true);
|
|
41
|
+
}, []);
|
|
42
|
+
const deactivate = useCallback(() => {
|
|
43
|
+
if (mountedRef.current)
|
|
44
|
+
setIsActive(false);
|
|
45
|
+
}, []);
|
|
46
|
+
const onTouchStart = useCallback((event) => {
|
|
37
47
|
if (!touchRef.current) {
|
|
38
48
|
touchRef.current = true;
|
|
39
|
-
|
|
40
|
-
if (!bubble) {
|
|
49
|
+
if (!bubble)
|
|
41
50
|
event.stopPropagation();
|
|
51
|
+
const touch = event.touches[0];
|
|
52
|
+
startPos.current = { x: touch.clientX, y: touch.clientY };
|
|
53
|
+
activate();
|
|
54
|
+
}
|
|
55
|
+
}, [bubble, activate]);
|
|
56
|
+
const onTouchMove = useCallback((event) => {
|
|
57
|
+
if (touchRef.current) {
|
|
58
|
+
const touch = event.touches[0];
|
|
59
|
+
const dx = touch.clientX - startPos.current.x;
|
|
60
|
+
const dy = touch.clientY - startPos.current.y;
|
|
61
|
+
if (dx * dx + dy * dy > moveThreshold * moveThreshold) {
|
|
62
|
+
touchRef.current = false;
|
|
63
|
+
deactivate();
|
|
42
64
|
}
|
|
43
|
-
// 激活目标样式
|
|
44
|
-
if (typeof activeClassName === 'string') {
|
|
45
|
-
setBoxClass(typeof boxClass === 'string'
|
|
46
|
-
? `${boxClass} ${activeClassName}`
|
|
47
|
-
: activeClassName);
|
|
48
|
-
}
|
|
49
|
-
if (typeof finalActiveStyle === 'object') {
|
|
50
|
-
setBoxStyle(typeof boxStyle === 'object'
|
|
51
|
-
? Object.assign(Object.assign({}, boxStyle), finalActiveStyle) : finalActiveStyle);
|
|
52
|
-
}
|
|
53
65
|
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
}, [moveThreshold, deactivate]);
|
|
67
|
+
const onTouchEnd = useCallback((event) => {
|
|
68
|
+
if (touchRef.current) {
|
|
69
|
+
touchRef.current = false;
|
|
70
|
+
if (!bubble)
|
|
71
|
+
event.stopPropagation();
|
|
72
|
+
deactivate();
|
|
73
|
+
}
|
|
74
|
+
}, [bubble, deactivate]);
|
|
75
|
+
const onMouseDown = useCallback((event) => {
|
|
76
|
+
// 只响应鼠标左键
|
|
77
|
+
if (event.button !== 0)
|
|
78
|
+
return;
|
|
79
|
+
if (!touchRef.current) {
|
|
80
|
+
touchRef.current = true;
|
|
81
|
+
if (!bubble)
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
activate();
|
|
84
|
+
}
|
|
85
|
+
}, [bubble, activate]);
|
|
86
|
+
const onMouseUp = useCallback(() => {
|
|
57
87
|
if (touchRef.current) {
|
|
58
88
|
touchRef.current = false;
|
|
59
|
-
|
|
60
|
-
setBoxStyle(style);
|
|
89
|
+
deactivate();
|
|
61
90
|
}
|
|
62
|
-
}, [
|
|
63
|
-
// PC
|
|
91
|
+
}, [deactivate]);
|
|
92
|
+
// PC 环境:在 document 上监听 mouseup,处理鼠标移出元素后释放的场景
|
|
64
93
|
useEffect(() => {
|
|
65
94
|
if (!disable && !touchable) {
|
|
66
95
|
const doc = document.documentElement;
|
|
67
|
-
doc.addEventListener('mouseup',
|
|
96
|
+
doc.addEventListener('mouseup', onMouseUp);
|
|
68
97
|
return () => {
|
|
69
|
-
doc.removeEventListener('mouseup',
|
|
98
|
+
doc.removeEventListener('mouseup', onMouseUp);
|
|
70
99
|
};
|
|
71
100
|
}
|
|
72
|
-
}, [disable, touchable,
|
|
73
|
-
|
|
101
|
+
}, [disable, touchable, onMouseUp]);
|
|
102
|
+
// 根据激活状态计算最终的 className 和 style
|
|
103
|
+
const finalClassName = isActive && typeof activeClassName === 'string'
|
|
104
|
+
? (typeof className === 'string' ? `${className} ${activeClassName}` : activeClassName)
|
|
105
|
+
: className;
|
|
106
|
+
const finalStyle = isActive && typeof finalActiveStyle === 'object'
|
|
107
|
+
? (typeof style === 'object' ? Object.assign(Object.assign({}, style), finalActiveStyle) : finalActiveStyle)
|
|
108
|
+
: style;
|
|
109
|
+
const fullAttrs = Object.assign(Object.assign({}, attrs), { className: finalClassName, style: finalStyle });
|
|
74
110
|
// 非禁用状态有点击态行为
|
|
75
111
|
if (!disable) {
|
|
76
112
|
if (touchable) {
|
|
77
|
-
|
|
78
|
-
fullAttrs.
|
|
79
|
-
fullAttrs.onTouchEnd =
|
|
80
|
-
fullAttrs.onTouchCancel =
|
|
113
|
+
fullAttrs.onTouchStart = onTouchStart;
|
|
114
|
+
fullAttrs.onTouchMove = onTouchMove;
|
|
115
|
+
fullAttrs.onTouchEnd = onTouchEnd;
|
|
116
|
+
fullAttrs.onTouchCancel = onTouchEnd;
|
|
81
117
|
}
|
|
82
118
|
else {
|
|
83
|
-
fullAttrs.onMouseDown =
|
|
119
|
+
fullAttrs.onMouseDown = onMouseDown;
|
|
84
120
|
}
|
|
85
121
|
}
|
|
86
122
|
return _jsx("div", Object.assign({}, fullAttrs, { children: children }));
|
package/build/Container/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { Global } from "@emotion/react";
|
|
3
|
-
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { getContextValue } from "../context";
|
|
3
|
+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState, } from "react";
|
|
5
4
|
import { useWindowResize } from "../Effect/useWindowResize";
|
|
6
5
|
import { useViewport } from "../Effect/useViewport";
|
|
7
6
|
/**
|
|
@@ -9,104 +8,71 @@ import { useViewport } from "../Effect/useViewport";
|
|
|
9
8
|
* @param props
|
|
10
9
|
*/
|
|
11
10
|
export function Container(props) {
|
|
12
|
-
// 来自全局的环境变量
|
|
13
|
-
const { minDocWidth, maxDocWidth } = getContextValue();
|
|
14
|
-
// 获取环境变量
|
|
15
11
|
const { designWidth = 750, globalStyle, children } = props;
|
|
16
|
-
//
|
|
12
|
+
// 计算理论根字体大小(未经浏览器缩放修正)
|
|
17
13
|
const calculateFontSize = useCallback((width) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}, [designWidth, minDocWidth, maxDocWidth]);
|
|
27
|
-
// 基准字体尺寸(初始化时计算一次)
|
|
28
|
-
const [baseFontSize, setBaseFontSize] = useState(() => calculateFontSize(window.innerWidth));
|
|
29
|
-
// 是否已完成初始化(包括字体缩放修正)
|
|
14
|
+
return (width * 100) / designWidth;
|
|
15
|
+
}, [designWidth]);
|
|
16
|
+
// 理论基准字体大小(跟随窗口尺寸变化)
|
|
17
|
+
const [rawFontSize, setRawFontSize] = useState(() => calculateFontSize(window.innerWidth));
|
|
18
|
+
// 浏览器字体缩放因子(>1 表示用户放大了系统字体,<1 表示缩小)
|
|
19
|
+
// 独立存储,使得 resize 后缩放修正依然生效
|
|
20
|
+
const [scaleFactor, setScaleFactor] = useState(1);
|
|
21
|
+
// 是否已完成字体缩放检测
|
|
30
22
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
// 修正后的字体大小:统一对所有字体计算应用缩放修正
|
|
24
|
+
const correctedFontSize = useMemo(() => scaleFactor === 1
|
|
25
|
+
? rawFontSize
|
|
26
|
+
: Math.round((rawFontSize / scaleFactor) * 10) / 10, [rawFontSize, scaleFactor]);
|
|
27
|
+
// 字体缩放检测
|
|
28
|
+
// Emotion 的 <Global> 通过 useInsertionEffect 注入样式,早于 useLayoutEffect
|
|
29
|
+
// 因此 useLayoutEffect 内 getComputedStyle 可正确读取已注入的字体大小
|
|
30
|
+
// 检测和修正均在浏览器绘制前同步完成,避免闪烁
|
|
31
|
+
useLayoutEffect(() => {
|
|
32
|
+
// 缩放因子在页面生命周期内不变,只需检测一次
|
|
35
33
|
if (isInitialized)
|
|
36
34
|
return;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// 通过反向缩放修正字体大小
|
|
49
|
-
// 例如:期望 50px,实际 60px(1.2倍),则设置 50/1.2 ≈ 41.67px
|
|
50
|
-
const correctedSize = Math.round((baseFontSize / scaleFactor) * 10) / 10;
|
|
51
|
-
// 只修正一次,然后标记为已初始化
|
|
52
|
-
setBaseFontSize(correctedSize);
|
|
53
|
-
setIsInitialized(true);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
// 字体大小正确,直接标记为已初始化
|
|
57
|
-
setIsInitialized(true);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}, [baseFontSize, isInitialized]);
|
|
61
|
-
// 页面大小变化时,基准字体同步变化
|
|
62
|
-
// 使用 requestAnimationFrame 批量处理,避免频繁更新
|
|
35
|
+
const computedSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
|
|
36
|
+
// 如果计算出的字体大小与期望不符(说明被浏览器字体设置影响了)
|
|
37
|
+
// 容差 1px,避免浮点精度导致误判
|
|
38
|
+
if (computedSize > 0 && Math.abs(computedSize - rawFontSize) > 1) {
|
|
39
|
+
// 记录缩放因子,后续所有字体计算(包括 resize)都会自动应用
|
|
40
|
+
setScaleFactor(computedSize / rawFontSize);
|
|
41
|
+
}
|
|
42
|
+
setIsInitialized(true);
|
|
43
|
+
}, [rawFontSize, isInitialized]);
|
|
44
|
+
// 窗口大小变化时更新理论字体大小
|
|
45
|
+
// correctedFontSize 通过 useMemo 自动应用 scaleFactor 修正
|
|
63
46
|
useWindowResize(() => {
|
|
64
|
-
|
|
65
|
-
const newFontSize = calculateFontSize(window.innerWidth);
|
|
66
|
-
if (newFontSize !== baseFontSize) {
|
|
67
|
-
setBaseFontSize(newFontSize);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
47
|
+
setRawFontSize(calculateFontSize(window.innerWidth));
|
|
70
48
|
});
|
|
71
|
-
// 设置
|
|
49
|
+
// 设置 viewport meta
|
|
72
50
|
useViewport();
|
|
73
|
-
//
|
|
51
|
+
// 激活 iOS 上的 :active 伪类
|
|
74
52
|
useEffect(() => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
document.body.addEventListener("touchstart", activable, { passive: true });
|
|
53
|
+
const noop = () => { };
|
|
54
|
+
document.body.addEventListener("touchstart", noop, { passive: true });
|
|
78
55
|
return () => {
|
|
79
|
-
document.body.removeEventListener("touchstart",
|
|
56
|
+
document.body.removeEventListener("touchstart", noop);
|
|
80
57
|
};
|
|
81
58
|
}, []);
|
|
82
|
-
// 使用 useMemo 缓存媒体查询样式,避免每次渲染都重新计算
|
|
83
|
-
const mediaQueryStyles = useMemo(() => ({
|
|
84
|
-
[`@media (min-width: ${maxDocWidth}px)`]: {
|
|
85
|
-
html: {
|
|
86
|
-
fontSize: `${(100 * maxDocWidth) / designWidth}px`,
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
[`@media (max-width: ${minDocWidth}px)`]: {
|
|
90
|
-
html: {
|
|
91
|
-
fontSize: `${(100 * minDocWidth) / designWidth}px`,
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
}), [designWidth, minDocWidth, maxDocWidth]);
|
|
95
59
|
return (_jsxs(React.Fragment, { children: [_jsx(Global, { styles: [
|
|
96
|
-
|
|
60
|
+
{
|
|
61
|
+
"*": {
|
|
97
62
|
boxSizing: "border-box",
|
|
98
|
-
},
|
|
63
|
+
},
|
|
64
|
+
html: {
|
|
99
65
|
WebkitTapHighlightColor: "transparent",
|
|
100
66
|
WebkitOverflowScrolling: "touch",
|
|
101
67
|
WebkitTextSizeAdjust: "100%",
|
|
102
|
-
fontSize: `${
|
|
68
|
+
fontSize: `${correctedFontSize}px`,
|
|
103
69
|
touchAction: "manipulation",
|
|
104
|
-
},
|
|
70
|
+
},
|
|
71
|
+
body: {
|
|
105
72
|
fontSize: "16px",
|
|
106
73
|
margin: "0 auto",
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
} }, mediaQueryStyles),
|
|
74
|
+
},
|
|
75
|
+
},
|
|
110
76
|
globalStyle,
|
|
111
77
|
] }), isInitialized ? children : null] }));
|
|
112
78
|
}
|
package/build/Dialog/style.js
CHANGED
|
@@ -117,7 +117,7 @@ export function getAnimation(type, status) {
|
|
|
117
117
|
return {
|
|
118
118
|
keyframes,
|
|
119
119
|
animation: css({
|
|
120
|
-
animation: `${keyframes} 300ms ease`,
|
|
120
|
+
animation: `${keyframes} 300ms ease forwards`,
|
|
121
121
|
}),
|
|
122
122
|
};
|
|
123
123
|
}
|
|
@@ -126,7 +126,7 @@ export const style = {
|
|
|
126
126
|
animation: `${maskShow} 300ms ease`,
|
|
127
127
|
}),
|
|
128
128
|
maskHide: css({
|
|
129
|
-
animation: `${maskHide} 300ms ease`,
|
|
129
|
+
animation: `${maskHide} 300ms ease forwards`,
|
|
130
130
|
}),
|
|
131
131
|
mask: css({
|
|
132
132
|
zIndex: 1,
|