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.
Files changed (89) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +768 -35
  3. package/build/Ago/index.d.ts +0 -1
  4. package/build/Alert/Wrapper.d.ts +0 -1
  5. package/build/Alert/Wrapper.js +12 -12
  6. package/build/Alert/index.js +2 -2
  7. package/build/AutoGrid/index.js +16 -21
  8. package/build/AutoGrid/style.d.ts +5 -5
  9. package/build/CarouselNotice/index.d.ts +0 -1
  10. package/build/CarouselNotice/index.js +6 -6
  11. package/build/CarouselNotice/style.d.ts +6 -1
  12. package/build/CarouselNotice/style.js +7 -7
  13. package/build/Clickable/index.d.ts +5 -5
  14. package/build/Clickable/index.js +11 -8
  15. package/build/Container/index.d.ts +2 -2
  16. package/build/Container/index.js +85 -60
  17. package/build/Countdowner/index.d.ts +3 -3
  18. package/build/Countdowner/index.js +18 -11
  19. package/build/Dialog/Wrapper.d.ts +0 -1
  20. package/build/Dialog/Wrapper.js +7 -10
  21. package/build/Dialog/style.d.ts +15 -10
  22. package/build/Dialog/style.js +88 -88
  23. package/build/Effect/useInterval.d.ts +1 -1
  24. package/build/Effect/useInterval.js +1 -1
  25. package/build/Effect/useUpdate.d.ts +1 -1
  26. package/build/Effect/useUpdate.js +1 -1
  27. package/build/Effect/useWindowResize.d.ts +4 -2
  28. package/build/Effect/useWindowResize.js +28 -11
  29. package/build/Flex/index.d.ts +0 -1
  30. package/build/Indicator/index.js +22 -23
  31. package/build/Indicator/style.d.ts +6 -1
  32. package/build/Indicator/style.js +7 -7
  33. package/build/Loading/Wrapper.js +2 -2
  34. package/build/Loading/style.d.ts +12 -2
  35. package/build/Loading/style.js +14 -14
  36. package/build/Overlay/index.d.ts +1 -1
  37. package/build/Overlay/index.js +41 -37
  38. package/build/SafeArea/index.d.ts +1 -2
  39. package/build/SafeArea/index.js +6 -6
  40. package/build/ScrollView/index.d.ts +1 -1
  41. package/build/ScrollView/index.js +111 -27
  42. package/build/Toast/Toast.js +4 -4
  43. package/build/Toast/style.d.ts +42 -12
  44. package/build/Toast/style.js +54 -54
  45. package/build/index.d.ts +3 -0
  46. package/build/index.js +3 -0
  47. package/build/utils/Countdown.d.ts +3 -1
  48. package/build/utils/Countdown.js +5 -2
  49. package/build/utils/createApp.d.ts +14 -13
  50. package/build/utils/createApp.js +58 -42
  51. package/build/utils/cssUtil.d.ts +2 -2
  52. package/build/utils/cssUtil.js +24 -13
  53. package/build/utils/defaultScroll.d.ts +0 -1
  54. package/build/utils/defaultScroll.js +8 -5
  55. package/build/utils/is.d.ts +23 -4
  56. package/build/utils/is.js +97 -15
  57. package/build/utils/jsonp.js +2 -2
  58. package/build/utils/request.js +12 -2
  59. package/package.json +15 -12
  60. package/test/README.md +16 -0
  61. package/test/eslint.config.js +29 -0
  62. package/test/index.html +13 -0
  63. package/test/jsconfig.json +8 -0
  64. package/test/package.json +27 -0
  65. package/test/public/vite.svg +1 -0
  66. package/test/src/ago/index.jsx +30 -0
  67. package/test/src/alert/index.jsx +111 -0
  68. package/test/src/autogrid/index.css +0 -0
  69. package/test/src/autogrid/index.jsx +26 -0
  70. package/test/src/carouse-notice/index.jsx +59 -0
  71. package/test/src/clickable/index.css +21 -0
  72. package/test/src/clickable/index.jsx +39 -0
  73. package/test/src/countdown/index.jsx +95 -0
  74. package/test/src/dialog/index.jsx +104 -0
  75. package/test/src/dialog/index.module.css +5 -0
  76. package/test/src/image-picker/index.css +0 -0
  77. package/test/src/image-picker/index.jsx +88 -0
  78. package/test/src/index/index.jsx +46 -0
  79. package/test/src/index.css +49 -0
  80. package/test/src/index.jsx +31 -0
  81. package/test/src/indicator/index.jsx +25 -0
  82. package/test/src/loading/index.jsx +36 -0
  83. package/test/src/overlay/index.jsx +31 -0
  84. package/test/src/privacy/index.css +13 -0
  85. package/test/src/privacy/index.jsx +34 -0
  86. package/test/src/scrollview/index.css +10 -0
  87. package/test/src/scrollview/index.jsx +52 -0
  88. package/test/src/toast/index.jsx +86 -0
  89. package/test/vite.config.js +15 -0
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import dayjs from 'dayjs';
3
2
  import { AgoValue } from '../utils/ago';
4
3
  export interface AgoProps extends React.HTMLProps<HTMLSpanElement | HTMLDivElement> {
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { Interpolation, Theme } from '@emotion/react';
3
2
  import * as CSS from 'csstype';
4
3
  export interface AlertWrapperProps {
@@ -7,19 +7,19 @@ export function AlertWrapper(props) {
7
7
  // 可定制的样式
8
8
  titleStyle, descStyle, btnStyle, cancelStyle, confirmStyle, } = props;
9
9
  // 标题样式
10
- let titleCss = [style.title];
11
- if (description) {
12
- titleCss.push({ paddingBottom: 0 });
13
- }
14
- titleCss.push(titleStyle);
10
+ let titleCss = [
11
+ style.title,
12
+ description ? { paddingBottom: 0 } : {},
13
+ titleStyle
14
+ ];
15
15
  // 展示按钮组
16
- let btnBoxCss = [style.btnBox];
17
- if (showCancel) {
18
- btnBoxCss.push(style.btnBoxWithCancel);
19
- }
20
- return (_jsxs("div", Object.assign({ css: style.container }, { children: [_jsxs("div", Object.assign({ css: style.content }, { children: [_jsx("div", Object.assign({ css: titleCss }, { children: title })), description && _jsx("div", Object.assign({ css: [style.desc, descStyle] }, { children: description }))] })), _jsxs(Row, Object.assign({ alignItems: "stretch", css: btnBoxCss }, { children: [showCancel && (_jsx(Clickable, Object.assign({ css: [style.btn, btnStyle, cancelStyle, { color: cancelColor }], onClick: onCancel, activeStyle: {
16
+ let btnBoxCss = [
17
+ style.btnBox,
18
+ showCancel ? style.btnBoxWithCancel : {}
19
+ ];
20
+ return (_jsxs("div", { css: style.container, children: [_jsxs("div", { css: style.content, children: [_jsx("div", { css: titleCss, children: title }), description && _jsx("div", { css: [style.desc, descStyle], children: description })] }), _jsxs(Row, { alignItems: "stretch", css: btnBoxCss, children: [showCancel && (_jsx(Clickable, { css: [style.btn, btnStyle, cancelStyle, { color: cancelColor }], onClick: onCancel, activeStyle: {
21
21
  backgroundColor: `#c0c0c022`,
22
- } }, { children: cancel }))), _jsx(Clickable, Object.assign({ css: [style.btn, btnStyle, confirmStyle, { color: confirmColor }], onClick: onConfirm, activeStyle: {
22
+ }, children: cancel })), _jsx(Clickable, { css: [style.btn, btnStyle, confirmStyle, { color: confirmColor }], onClick: onConfirm, activeStyle: {
23
23
  backgroundColor: `#c0c0c022`,
24
- } }, { children: confirm }))] }))] })));
24
+ }, children: confirm })] })] }));
25
25
  }
@@ -35,9 +35,9 @@ export function showAlert(option) {
35
35
  (_a = config.onCancel) === null || _a === void 0 ? void 0 : _a.call(config);
36
36
  });
37
37
  props.onConfirm = () => __awaiter(this, void 0, void 0, function* () {
38
- var _b;
38
+ var _a;
39
39
  yield closeDialog();
40
- (_b = config.onConfirm) === null || _b === void 0 ? void 0 : _b.call(config);
40
+ (_a = config.onConfirm) === null || _a === void 0 ? void 0 : _a.call(config);
41
41
  });
42
42
  // 创建对话框
43
43
  const closeDialog = showDialog({
@@ -18,10 +18,10 @@ import { normalizeUnit } from '../utils/cssUtil';
18
18
  * @param props
19
19
  */
20
20
  export function AutoGrid(props) {
21
- let { children, cols = 1, gap = 0, isSquare = false, itemStyle, containerStyle } = props, extra = __rest(props, ["children", "cols", "gap", "isSquare", "itemStyle", "containerStyle"]);
21
+ const { children, cols: rawCols = 1, gap: rawGap = 0, isSquare = false, itemStyle, containerStyle } = props, extra = __rest(props, ["children", "cols", "gap", "isSquare", "itemStyle", "containerStyle"]);
22
22
  // 规范化数字单位
23
- cols = +cols;
24
- gap = normalizeUnit(gap);
23
+ const cols = +rawCols;
24
+ const gap = normalizeUnit(rawGap);
25
25
  // 获取表格数据
26
26
  const getGridData = useCallback(() => {
27
27
  // 生成一个能创建表格的二维数组
@@ -51,28 +51,23 @@ export function AutoGrid(props) {
51
51
  const gridData = getGridData();
52
52
  return gridData.map((row, rowIndex) => {
53
53
  // 每行的槽样式,最后一行没有
54
- let finalRowStyle = [style.rowStyle];
55
- if (rowIndex !== gridData.length - 1) {
56
- // 最后一行不需要marginBottom
57
- finalRowStyle.push({
58
- marginBottom: gap,
59
- });
60
- }
61
- return (_jsx("div", Object.assign({ css: finalRowStyle }, { children: row.map((item, colIndex) => {
62
- let finalCss = [...finalItemBoxStyle];
63
- // 如果是方形的,加入方形相关的样式
64
- if (isSquare) {
65
- finalCss.push(style.itemBoxSquare);
66
- }
67
- finalCss.push(itemStyle);
54
+ let finalRowStyle = [
55
+ style.rowStyle,
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
+ ];
68
63
  if (isSquare) {
69
- return (_jsx("div", Object.assign({ css: finalCss }, { children: _jsx("div", Object.assign({ css: style.itemInnerStyle }, { children: item })) }), colIndex));
64
+ return (_jsx("div", { css: [...finalCss, style.itemBoxSquare], children: _jsx("div", { css: style.itemInnerStyle, children: item }) }, colIndex));
70
65
  }
71
66
  else {
72
- return (_jsx("div", Object.assign({ css: finalItemBoxStyle }, { children: item }), colIndex));
67
+ return (_jsx("div", { css: finalCss, children: item }, colIndex));
73
68
  }
74
- }) }), rowIndex));
69
+ }) }, rowIndex));
75
70
  });
76
71
  };
77
- return (_jsx("div", Object.assign({}, extra, { css: [containerStyle] }, { children: showContent() })));
72
+ return (_jsx("div", Object.assign({}, extra, { css: [containerStyle], children: showContent() })));
78
73
  }
@@ -1,7 +1,7 @@
1
1
  export declare const style: {
2
- itemBoxStyle: import("@emotion/utils").SerializedStyles;
3
- itemBoxSquare: import("@emotion/utils").SerializedStyles;
4
- itemNull: import("@emotion/utils").SerializedStyles;
5
- itemInnerStyle: import("@emotion/utils").SerializedStyles;
6
- rowStyle: import("@emotion/utils").SerializedStyles;
2
+ itemBoxStyle: import("@emotion/react").SerializedStyles;
3
+ itemBoxSquare: import("@emotion/react").SerializedStyles;
4
+ itemNull: import("@emotion/react").SerializedStyles;
5
+ itemInnerStyle: import("@emotion/react").SerializedStyles;
6
+ rowStyle: import("@emotion/react").SerializedStyles;
7
7
  };
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { Interpolation, Theme } from '@emotion/react';
3
2
  import * as CSS from 'csstype';
4
3
  export interface CarouselNoticeOption extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
@@ -54,16 +54,16 @@ export function CarouselNotice(props) {
54
54
  }
55
55
  const itemCss = [style.item, justifyStyle];
56
56
  if (list.length === 1) {
57
- return (_jsx("div", Object.assign({ css: [itemCss, itemStyle] }, { children: list[0] }), 0));
57
+ return (_jsx("div", { css: [itemCss, itemStyle], children: list[0] }, 0));
58
58
  }
59
59
  const showList = [];
60
60
  if (current === list.length - 1) {
61
- showList.push(_jsx("div", Object.assign({ css: [itemCss, itemStyle] }, { children: list[list.length - 1] }), current));
62
- showList.push(_jsx("div", Object.assign({ css: [itemCss, itemStyle] }, { children: list[0] }), 0));
61
+ showList.push(_jsx("div", { css: [itemCss, itemStyle], children: list[list.length - 1] }, current));
62
+ showList.push(_jsx("div", { css: [itemCss, itemStyle], children: list[0] }, 0));
63
63
  }
64
64
  else {
65
- showList.push(_jsx("div", Object.assign({ css: [itemCss, itemStyle] }, { children: list[current] }), current));
66
- showList.push(_jsx("div", Object.assign({ css: [itemCss, itemStyle] }, { children: list[current + 1] }), current + 1));
65
+ showList.push(_jsx("div", { css: [itemCss, itemStyle], children: list[current] }, current));
66
+ showList.push(_jsx("div", { css: [itemCss, itemStyle], children: list[current + 1] }, current + 1));
67
67
  }
68
68
  return showList;
69
69
  };
@@ -92,5 +92,5 @@ export function CarouselNotice(props) {
92
92
  setAnimation(false);
93
93
  };
94
94
  return (Array.isArray(list) &&
95
- list.length > 0 && (_jsx("div", Object.assign({}, attrs, { css: [style.box, { width, height }, containerStyle] }, { children: _jsx("div", Object.assign({ onAnimationEnd: animationEnd, css: [style.wrapper, getAnimation(), wrapperStyle] }, { children: showContent() })) }))));
95
+ list.length > 0 && (_jsx("div", Object.assign({}, attrs, { css: [style.box, { width, height }, containerStyle], children: _jsx("div", { onAnimationEnd: animationEnd, css: [style.wrapper, getAnimation(), wrapperStyle], children: showContent() }) }))));
96
96
  }
@@ -1,3 +1,8 @@
1
1
  import { Interpolation, Theme } from "@emotion/react";
2
- export declare const Bubble: import("@emotion/serialize").Keyframes;
2
+ export declare const Bubble: {
3
+ name: string;
4
+ styles: string;
5
+ anim: 1;
6
+ toString: () => string;
7
+ } & string;
3
8
  export declare const style: Record<string, Interpolation<Theme>>;
@@ -1,12 +1,12 @@
1
1
  import { keyframes } from "@emotion/react";
2
2
  import { adaptive } from "../utils/cssUtil";
3
- export const Bubble = keyframes `
4
- from {
5
- transform: translateY(0);
6
- }
7
- to {
8
- transform: translateY(-50%);
9
- }
3
+ export const Bubble = keyframes `
4
+ from {
5
+ transform: translateY(0);
6
+ }
7
+ to {
8
+ transform: translateY(-50%);
9
+ }
10
10
  `;
11
11
  export const style = {
12
12
  box: [
@@ -3,10 +3,10 @@ import React from 'react';
3
3
  * 可触摸元素的属性,兼容PC
4
4
  */
5
5
  export interface ClickableProps extends React.HTMLProps<HTMLDivElement> {
6
- children: React.ReactNode;
7
- bubble: boolean;
8
- activeClassName: string;
9
- activeStyle: React.CSSProperties;
10
- disable: boolean;
6
+ children?: React.ReactNode;
7
+ bubble?: boolean;
8
+ activeClassName?: string;
9
+ activeStyle?: React.CSSProperties;
10
+ disable?: boolean;
11
11
  }
12
12
  export declare function Clickable(props: Partial<ClickableProps>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -10,16 +10,19 @@ 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 { useCallback, useRef, useState, useEffect, } from 'react';
13
+ import React, { useCallback, useRef, useState, useEffect, } from 'react';
14
14
  import { is } from '../utils/is';
15
15
  export function Clickable(props) {
16
16
  let { children, bubble = true, className, activeClassName, style, activeStyle, disable = false } = props, attrs = __rest(props, ["children", "bubble", "className", "activeClassName", "style", "activeStyle", "disable"]);
17
17
  // 如果激活样式和激活类都不存在,则设置激活默认样式
18
- if (!activeClassName && !activeStyle) {
19
- activeStyle = {
20
- opacity: 0.6,
21
- };
22
- }
18
+ // 使用 useMemo 避免每次渲染都创建新对象
19
+ const defaultActiveStyle = React.useMemo(() => {
20
+ if (!activeClassName && !activeStyle) {
21
+ return { opacity: 0.6 };
22
+ }
23
+ return activeStyle;
24
+ }, [activeClassName, activeStyle]);
25
+ const finalActiveStyle = defaultActiveStyle || activeStyle;
23
26
  const touchable = is('touchable');
24
27
  const [boxClass, setBoxClass] = useState(className);
25
28
  const [boxStyle, setBoxStyle] = useState(style);
@@ -43,9 +46,9 @@ export function Clickable(props) {
43
46
  ? `${boxClass} ${activeClassName}`
44
47
  : activeClassName);
45
48
  }
46
- if (typeof activeStyle === 'object') {
49
+ if (typeof finalActiveStyle === 'object') {
47
50
  setBoxStyle(typeof boxStyle === 'object'
48
- ? Object.assign(Object.assign({}, boxStyle), activeStyle) : activeStyle);
51
+ ? Object.assign(Object.assign({}, boxStyle), finalActiveStyle) : finalActiveStyle);
49
52
  }
50
53
  }
51
54
  };
@@ -1,5 +1,5 @@
1
- import { Interpolation, Theme } from '@emotion/react';
2
- import React from 'react';
1
+ import { Interpolation, Theme } from "@emotion/react";
2
+ import React from "react";
3
3
  export interface ContainerProps {
4
4
  globalStyle?: Interpolation<Theme>;
5
5
  children?: React.ReactNode;
@@ -1,10 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- import { Global } from '@emotion/react';
3
- import React, { useCallback, useEffect, useState } from 'react';
4
- import { getContextValue } from '../context';
5
- import { useWindowResize } from '../Effect/useWindowResize';
6
- import round from 'lodash/round';
7
- import { useViewport } from '../Effect/useViewport';
2
+ import { Global } from "@emotion/react";
3
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
4
+ import { getContextValue } from "../context";
5
+ import { useWindowResize } from "../Effect/useWindowResize";
6
+ import { useViewport } from "../Effect/useViewport";
8
7
  /**
9
8
  * 自适应容器
10
9
  * @param props
@@ -14,74 +13,100 @@ export function Container(props) {
14
13
  const { minDocWidth, maxDocWidth } = getContextValue();
15
14
  // 获取环境变量
16
15
  const { designWidth = 750, globalStyle, children } = props;
17
- // 获取期待的根字体尺寸,采用rem布局
18
- const expectFontSize = useCallback(() => {
19
- const winWidth = window.innerWidth;
20
- let expectFontSize;
21
- if (winWidth >= maxDocWidth) {
22
- expectFontSize = (maxDocWidth * 100) / designWidth;
16
+ // 计算根字体尺寸的函数(使用 useCallback 避免重复创建)
17
+ const calculateFontSize = useCallback((width) => {
18
+ let targetWidth = width;
19
+ if (width >= maxDocWidth) {
20
+ targetWidth = maxDocWidth;
23
21
  }
24
- else if (winWidth <= minDocWidth) {
25
- expectFontSize = (minDocWidth * 100) / designWidth;
22
+ else if (width <= minDocWidth) {
23
+ targetWidth = minDocWidth;
26
24
  }
27
- else {
28
- expectFontSize = (winWidth * 100) / designWidth;
29
- }
30
- return expectFontSize;
25
+ return (targetWidth * 100) / designWidth;
31
26
  }, [designWidth, minDocWidth, maxDocWidth]);
32
- // 基准字体尺寸
33
- const [baseFontSize, setBaseFontSize] = useState(expectFontSize());
27
+ // 基准字体尺寸(初始化时计算一次)
28
+ const [baseFontSize, setBaseFontSize] = useState(() => calculateFontSize(window.innerWidth));
29
+ // 是否已完成初始化(包括字体缩放修正)
30
+ const [isInitialized, setIsInitialized] = useState(false);
31
+ // 字体缩放修正逻辑(处理浏览器字体设置影响)
32
+ // 使用 useLayoutEffect 在 DOM 更新后立即同步执行,避免闪烁
33
+ useEffect(() => {
34
+ // 只在未初始化时检查一次
35
+ if (isInitialized)
36
+ return;
37
+ // 延迟到下一帧检查,确保 DOM 已经应用了 baseFontSize
38
+ requestAnimationFrame(() => {
39
+ const computedSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
40
+ // 如果计算出的字体大小与期望不符(说明被浏览器字体设置影响了)
41
+ // 使用较大的容差值,避免浮点数精度问题导致的无限循环
42
+ if (typeof computedSize === "number" &&
43
+ computedSize > 0 &&
44
+ Math.abs(computedSize - baseFontSize) > 1 // 容差 1px,避免过度敏感
45
+ ) {
46
+ // 计算浏览器的字体缩放比例
47
+ const scaleFactor = computedSize / baseFontSize;
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]);
34
61
  // 页面大小变化时,基准字体同步变化
35
- useWindowResize(() => setBaseFontSize(() => expectFontSize()));
36
- // 字体缩放逻辑
37
- const scaleFont = useCallback(() => {
38
- let computeSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
39
- if (typeof computeSize === 'number' && computeSize !== baseFontSize) {
40
- setBaseFontSize(round(Math.pow(baseFontSize, 2) / computeSize, 1));
41
- }
42
- }, [baseFontSize]);
43
- // 字体更新时,同步更新缩放逻辑
44
- useEffect(scaleFont, [scaleFont]);
62
+ // 使用 requestAnimationFrame 批量处理,避免频繁更新
63
+ useWindowResize(() => {
64
+ requestAnimationFrame(() => {
65
+ const newFontSize = calculateFontSize(window.innerWidth);
66
+ if (newFontSize !== baseFontSize) {
67
+ setBaseFontSize(newFontSize);
68
+ }
69
+ });
70
+ });
45
71
  // 设置meta, 确保viewport的合法逻辑
46
72
  useViewport();
47
- // 一些页面的初始化逻辑
73
+ // 页面初始化逻辑
48
74
  useEffect(() => {
49
- // 激活iOS上的:active
75
+ // 激活iOS上的:active伪类
50
76
  const activable = () => { };
51
- document.body.addEventListener('touchstart', activable);
77
+ document.body.addEventListener("touchstart", activable, { passive: true });
52
78
  return () => {
53
- document.body.removeEventListener('touchstart', activable);
79
+ document.body.removeEventListener("touchstart", activable);
54
80
  };
55
81
  }, []);
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]);
56
95
  return (_jsxs(React.Fragment, { children: [_jsx(Global, { styles: [
57
- {
58
- '*': {
59
- boxSizing: 'border-box',
60
- },
61
- html: {
62
- WebkitTapHighlightColor: 'transparent',
63
- WebkitOverflowScrolling: 'touch',
64
- WebkitTextSizeAdjust: '100%',
96
+ Object.assign({ "*": {
97
+ boxSizing: "border-box",
98
+ }, html: {
99
+ WebkitTapHighlightColor: "transparent",
100
+ WebkitOverflowScrolling: "touch",
101
+ WebkitTextSizeAdjust: "100%",
65
102
  fontSize: `${baseFontSize}px`,
66
- touchAction: 'manipulation',
67
- },
68
- body: {
69
- fontSize: '16px',
70
- margin: '0 auto',
103
+ touchAction: "manipulation",
104
+ }, body: {
105
+ fontSize: "16px",
106
+ margin: "0 auto",
71
107
  maxWidth: `${maxDocWidth}px`,
72
108
  minWidth: `${minDocWidth}px`,
73
- },
74
- [`@media (min-width: ${maxDocWidth}px)`]: {
75
- html: {
76
- fontSize: `${(100 * maxDocWidth) / designWidth}px`,
77
- },
78
- },
79
- [`@media (max-width: ${minDocWidth}px)`]: {
80
- html: {
81
- fontSize: `${(100 * minDocWidth) / designWidth}px`,
82
- },
83
- },
84
- },
109
+ } }, mediaQueryStyles),
85
110
  globalStyle,
86
- ] }), children] }));
111
+ ] }), isInitialized ? children : null] }));
87
112
  }
@@ -2,11 +2,11 @@ import React from 'react';
2
2
  import { Interpolation, Theme } from '@emotion/react';
3
3
  import { CountdownOption } from '../utils/Countdown';
4
4
  export interface CountdownerOption extends CountdownOption, React.HTMLProps<HTMLDivElement> {
5
- seperator?: React.ReactNode;
6
- seperatorStyle?: Interpolation<Theme>;
5
+ separator?: React.ReactNode;
6
+ separatorStyle?: Interpolation<Theme>;
7
7
  containerStyle?: Interpolation<Theme>;
8
8
  numberStyle?: Interpolation<Theme>;
9
9
  renderNumber?: (value: number, key?: string) => React.ReactNode;
10
- renderSeperator?: (value: number, key?: string) => React.ReactNode;
10
+ renderSeparator?: (value: number, key?: string) => React.ReactNode;
11
11
  }
12
12
  export declare function Countdowner(props: CountdownerOption): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -14,8 +14,11 @@ import React, { useEffect, useState } from 'react';
14
14
  import { Countdown, } from '../utils/Countdown';
15
15
  import { RowStart } from '../Flex/Row';
16
16
  export function Countdowner(props) {
17
- let { remain = 0, seperator = ':', format = 'his', onUpdate, onEnd, seperatorStyle, containerStyle, numberStyle, renderNumber, renderSeperator } = props, extra = __rest(props, ["remain", "seperator", "format", "onUpdate", "onEnd", "seperatorStyle", "containerStyle", "numberStyle", "renderNumber", "renderSeperator"]);
17
+ let { remain = 0, separator = ':', format = 'his', onUpdate, onEnd, separatorStyle, containerStyle, numberStyle, renderNumber, renderSeparator } = props, extra = __rest(props, ["remain", "separator", "format", "onUpdate", "onEnd", "separatorStyle", "containerStyle", "numberStyle", "renderNumber", "renderSeparator"]);
18
18
  const [value, setValue] = useState(null);
19
+ // 使用 ref 保存最新的回调,避免频繁重建倒计时实例
20
+ const callbacksRef = React.useRef({ onUpdate, onEnd });
21
+ callbacksRef.current = { onUpdate, onEnd };
19
22
  let content = [];
20
23
  if (value && typeof value === 'object') {
21
24
  for (let i = 0; i < format.length; i++) {
@@ -28,19 +31,19 @@ export function Countdowner(props) {
28
31
  }
29
32
  else {
30
33
  // 默认以span包围,且数字不足10的时候有前置0
31
- numberComponent = (_jsx("span", Object.assign({ css: numberStyle }, { children: num < 10 ? `0${num}` : num })));
34
+ numberComponent = (_jsx("span", { css: numberStyle, children: num < 10 ? `0${num}` : num }));
32
35
  }
33
36
  content.push(_jsx(React.Fragment, { children: numberComponent }, i));
34
37
  // 添加分隔符,最后一个数字不需要分隔符
35
38
  if (i !== format.length - 1) {
36
- let seperatorComponent;
37
- if (typeof renderSeperator === 'function') {
38
- seperatorComponent = renderSeperator(num, key);
39
+ let separatorComponent;
40
+ if (typeof renderSeparator === 'function') {
41
+ separatorComponent = renderSeparator(num, key);
39
42
  }
40
43
  else {
41
- seperatorComponent = seperator ? (_jsx("span", Object.assign({ css: seperatorStyle }, { children: seperator }))) : null;
44
+ separatorComponent = separator ? (_jsx("span", { css: separatorStyle, children: separator })) : null;
42
45
  }
43
- content.push(_jsx(React.Fragment, { children: seperatorComponent }, `s${i}`));
46
+ content.push(_jsx(React.Fragment, { children: separatorComponent }, `s${i}`));
44
47
  }
45
48
  }
46
49
  }
@@ -49,11 +52,15 @@ export function Countdowner(props) {
49
52
  format,
50
53
  remain,
51
54
  onUpdate(current) {
55
+ var _a, _b;
52
56
  setValue(current);
53
- onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(current);
57
+ // 使用 ref 中的最新回调
58
+ (_b = (_a = callbacksRef.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, current);
54
59
  },
55
60
  onEnd() {
56
- onEnd === null || onEnd === void 0 ? void 0 : onEnd();
61
+ var _a, _b;
62
+ // 使用 ref 中的最新回调
63
+ (_b = (_a = callbacksRef.current).onEnd) === null || _b === void 0 ? void 0 : _b.call(_a);
57
64
  },
58
65
  });
59
66
  instance.start();
@@ -62,6 +69,6 @@ export function Countdowner(props) {
62
69
  instance.stop();
63
70
  instance = null;
64
71
  };
65
- }, [format, remain]);
66
- return (_jsx(RowStart, Object.assign({}, extra, { css: containerStyle }, { children: content })));
72
+ }, [format, remain]); // ← 移除 onUpdate 和 onEnd 依赖
73
+ return (_jsx(RowStart, Object.assign({}, extra, { css: containerStyle, children: content })));
67
74
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  /** @jsx jsx */
3
2
  import { Theme, Interpolation } from "@emotion/react";
4
3
  import { DialogType, AnimationStatus } from "./style";
@@ -5,20 +5,17 @@ export function Wrapper(props) {
5
5
  const { type = "center", status = "show", children, onHide, showMask = true, maskColor, maskStyle, boxStyle, onBlankClick, } = props;
6
6
  const { animation, keyframes } = getAnimation(type, status);
7
7
  // 选取特定的类型对应的样式
8
- let boxCss = [style.boxCss];
9
- if (["pullUp", "pullDown", "pullLeft", "pullRight"].includes(type)) {
10
- boxCss.push(style[type]);
11
- }
8
+ let boxCss = [
9
+ style.boxCss,
10
+ ["pullUp", "pullDown", "pullLeft", "pullRight"].includes(type) ? style[type] : {}
11
+ ];
12
12
  // 遮罩的样式
13
13
  let maskCss = [
14
14
  style.mask,
15
15
  status === "show" ? style.maskShow : style.maskHide,
16
16
  maskStyle,
17
+ maskColor ? { backgroundColor: maskColor } : {}
17
18
  ];
18
- // 遮罩颜色
19
- if (maskColor) {
20
- maskCss.push({ backgroundColor: maskColor });
21
- }
22
19
  // 空白处点击
23
20
  const blankClick = (event) => {
24
21
  if (event.target === event.currentTarget) {
@@ -26,9 +23,9 @@ export function Wrapper(props) {
26
23
  onBlankClick === null || onBlankClick === void 0 ? void 0 : onBlankClick(event);
27
24
  }
28
25
  };
29
- return (_jsxs(Overlay, Object.assign({ css: { overflow: "hidden" }, centerContent: type === "center", maskColor: "transparent", fullScreen: true, onClick: showMask ? undefined : blankClick }, { children: [showMask && _jsx("div", { css: maskCss, onClick: blankClick }), _jsx("div", Object.assign({ css: [boxCss, boxStyle, animation], onAnimationEnd: (event) => {
26
+ return (_jsxs(Overlay, { css: { overflow: "hidden" }, centerContent: type === "center", maskColor: "transparent", fullScreen: true, onClick: showMask ? undefined : blankClick, children: [showMask && _jsx("div", { css: maskCss, onClick: blankClick }), _jsx("div", { css: [boxCss, boxStyle, animation], onAnimationEnd: (event) => {
30
27
  if (status === "hide" && event.animationName === keyframes.name) {
31
28
  onHide === null || onHide === void 0 ? void 0 : onHide();
32
29
  }
33
- } }, { children: children }))] })));
30
+ }, children: children })] }));
34
31
  }
@@ -1,18 +1,23 @@
1
1
  import { Keyframes } from "@emotion/serialize";
2
- export declare const maskHide: Keyframes;
2
+ export declare const maskHide: {
3
+ name: string;
4
+ styles: string;
5
+ anim: 1;
6
+ toString: () => string;
7
+ } & string;
3
8
  export type DialogType = "center" | "pullUp" | "pullDown" | "pullLeft" | "pullRight";
4
9
  export type AnimationStatus = "show" | "hide";
5
10
  export declare function getAnimation(type: DialogType, status: AnimationStatus): {
6
11
  keyframes: Keyframes;
7
- animation: import("@emotion/utils").SerializedStyles;
12
+ animation: import("@emotion/react").SerializedStyles;
8
13
  };
9
14
  export declare const style: {
10
- maskShow: import("@emotion/utils").SerializedStyles;
11
- maskHide: import("@emotion/utils").SerializedStyles;
12
- mask: import("@emotion/utils").SerializedStyles;
13
- boxCss: import("@emotion/utils").SerializedStyles;
14
- pullUp: import("@emotion/utils").SerializedStyles;
15
- pullDown: import("@emotion/utils").SerializedStyles;
16
- pullLeft: import("@emotion/utils").SerializedStyles;
17
- pullRight: import("@emotion/utils").SerializedStyles;
15
+ maskShow: import("@emotion/react").SerializedStyles;
16
+ maskHide: import("@emotion/react").SerializedStyles;
17
+ mask: import("@emotion/react").SerializedStyles;
18
+ boxCss: import("@emotion/react").SerializedStyles;
19
+ pullUp: import("@emotion/react").SerializedStyles;
20
+ pullDown: import("@emotion/react").SerializedStyles;
21
+ pullLeft: import("@emotion/react").SerializedStyles;
22
+ pullRight: import("@emotion/react").SerializedStyles;
18
23
  };