@hsu-react/ui 2.5.3 → 2.5.5
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/es/components/ChainGraph/_hooks/useChainGraphData.js +29 -8
- package/es/components/ChainGraph/_hooks/useChainGraphLayout.js +14 -3
- package/es/components/Chart/Bar/index.js +49 -19
- package/es/components/Chart/Bubble/index.js +21 -6
- package/es/components/Chart/Common/index.js +7 -2
- package/es/components/Chart/Heatmap/index.js +21 -6
- package/es/components/Chart/Line/index.js +49 -19
- package/es/components/Chart/Pie/Pie3D/index.js +22 -6
- package/es/components/Chart/Pie/index.js +21 -6
- package/es/components/Chart/Sankey/index.js +11 -2
- package/es/components/Chart/Tree/index.js +11 -2
- package/es/components/Chat/ChatInput/index.js +7 -2
- package/es/components/Icon/index.js +8 -2
- package/es/components/Input/Number/index.js +28 -21
- package/es/components/Input/Password/index.js +44 -36
- package/es/components/Input/Search/index.js +44 -36
- package/es/components/Input/TextArea/index.js +64 -42
- package/es/components/Input/index.js +40 -34
- package/es/components/Select/_hooks/useSelectComposition.js +6 -2
- package/es/components/Select/_hooks/useSelectInputOptions.js +8 -2
- package/es/components/Slider/index.js +24 -15
- package/es/components/Table/_hooks/useAutoScrolling.js +16 -7
- package/es/components/Upload/_hooks/useUploadFileList.js +8 -2
- package/es/components/Upload/_hooks/useUploadOperations.js +8 -2
- package/es/hooks/useLatestRef.d.ts +24 -0
- package/es/hooks/useLatestRef.js +29 -0
- package/es/layout/Menu/_hooks/useOnlyLvOneMenu.js +9 -2
- package/lib/components/ChainGraph/_hooks/useChainGraphData.js +24 -7
- package/lib/components/ChainGraph/_hooks/useChainGraphLayout.js +12 -2
- package/lib/components/Chart/Bar/index.js +45 -18
- package/lib/components/Chart/Bubble/index.js +19 -6
- package/lib/components/Chart/Common/index.js +6 -2
- package/lib/components/Chart/Heatmap/index.js +19 -6
- package/lib/components/Chart/Line/index.js +45 -18
- package/lib/components/Chart/Pie/Pie3D/index.js +20 -6
- package/lib/components/Chart/Pie/index.js +19 -6
- package/lib/components/Chart/Sankey/index.js +10 -2
- package/lib/components/Chart/Tree/index.js +10 -2
- package/lib/components/Chat/ChatInput/index.js +6 -2
- package/lib/components/Icon/index.js +7 -2
- package/lib/components/Input/Number/index.js +27 -18
- package/lib/components/Input/Password/index.js +40 -26
- package/lib/components/Input/Search/index.js +42 -26
- package/lib/components/Input/TextArea/index.js +54 -26
- package/lib/components/Input/index.js +37 -24
- package/lib/components/Select/_hooks/useSelectComposition.js +6 -2
- package/lib/components/Select/_hooks/useSelectInputOptions.js +7 -2
- package/lib/components/Slider/index.js +23 -11
- package/lib/components/Table/_hooks/useAutoScrolling.js +16 -7
- package/lib/components/Upload/_hooks/useUploadFileList.js +7 -2
- package/lib/components/Upload/_hooks/useUploadOperations.js +7 -2
- package/lib/hooks/useLatestRef.d.ts +24 -0
- package/lib/hooks/useLatestRef.js +35 -0
- package/lib/layout/Menu/_hooks/useOnlyLvOneMenu.js +8 -2
- package/package.json +9 -3
- package/src/__tests__/callbackDepsGuard.test.ts +119 -0
- package/src/__tests__/setup.ts +26 -0
- package/src/components/ChainGraph/_hooks/callbacks.test.tsx +155 -0
- package/src/components/ChainGraph/_hooks/useChainGraphData.ts +38 -10
- package/src/components/ChainGraph/_hooks/useChainGraphLayout.ts +16 -3
- package/src/components/Chart/Bar/index.tsx +59 -21
- package/src/components/Chart/Bubble/index.tsx +22 -7
- package/src/components/Chart/Common/index.tsx +7 -2
- package/src/components/Chart/Heatmap/index.tsx +25 -6
- package/src/components/Chart/Line/index.tsx +59 -21
- package/src/components/Chart/Pie/Pie3D/index.tsx +22 -7
- package/src/components/Chart/Pie/index.tsx +22 -7
- package/src/components/Chart/Sankey/index.tsx +10 -4
- package/src/components/Chart/Tree/index.tsx +10 -4
- package/src/components/Chart/callbacks.test.tsx +315 -0
- package/src/components/Chat/ChatInput/index.tsx +7 -2
- package/src/components/Icon/index.tsx +7 -2
- package/src/components/Input/Number/index.tsx +25 -23
- package/src/components/Input/Password/index.tsx +37 -26
- package/src/components/Input/Search/index.tsx +39 -26
- package/src/components/Input/TextArea/index.test.tsx +208 -0
- package/src/components/Input/TextArea/index.tsx +56 -30
- package/src/components/Input/index.test.tsx +189 -0
- package/src/components/Input/index.tsx +36 -29
- package/src/components/Select/_hooks/useSelectComposition.test.ts +47 -0
- package/src/components/Select/_hooks/useSelectComposition.ts +6 -2
- package/src/components/Select/_hooks/useSelectInputOptions.ts +6 -9
- package/src/components/Slider/index.tsx +22 -12
- package/src/components/Table/_hooks/useAutoScrolling.test.tsx +95 -0
- package/src/components/Table/_hooks/useAutoScrolling.ts +16 -7
- package/src/components/Upload/_hooks/useUploadFileList.ts +6 -2
- package/src/components/Upload/_hooks/useUploadOperations.ts +7 -2
- package/src/hooks/useLatestRef.ts +31 -0
- package/src/layout/Menu/_hooks/useOnlyLvOneMenu.test.tsx +56 -0
- package/src/layout/Menu/_hooks/useOnlyLvOneMenu.ts +8 -2
|
@@ -19,6 +19,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
|
19
19
|
import { autoScrollLegend } from "../chartUtils";
|
|
20
20
|
import styles from "../index.module.scss";
|
|
21
21
|
import ChartPie3D from "./Pie3D";
|
|
22
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
22
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
23
24
|
var ChartPie = function ChartPie(props) {
|
|
24
25
|
var className = props.className,
|
|
@@ -207,7 +208,16 @@ var ChartPie = function ChartPie(props) {
|
|
|
207
208
|
if (!el || el.clientWidth === 0 || el.clientHeight === 0) return;
|
|
208
209
|
(_chartInstanceRef$cur = chartInstanceRef.current) === null || _chartInstanceRef$cur === void 0 || _chartInstanceRef$cur.resize();
|
|
209
210
|
}, []);
|
|
211
|
+
var onChartRef = useLatestRef(onChart);
|
|
210
212
|
|
|
213
|
+
// onClick 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 跟着重跑就会
|
|
214
|
+
// 再走一遍 setOption(notMerge),动画重播、悬浮/高亮态被清掉。注册与否看布尔量,
|
|
215
|
+
// 这样「从无到有传入 onClick」仍会注册;实际调用取 ref 里的最新引用。
|
|
216
|
+
var onClickRef = useLatestRef(onClick);
|
|
217
|
+
var hasOnClick = !!onClick;
|
|
218
|
+
|
|
219
|
+
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
220
|
+
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
211
221
|
// Initialize the chart
|
|
212
222
|
useEffect(function () {
|
|
213
223
|
if (!chartRef.current || !containerReady) return;
|
|
@@ -215,10 +225,11 @@ var ChartPie = function ChartPie(props) {
|
|
|
215
225
|
// Initialize or reuse the existing instance
|
|
216
226
|
var chart = chartInstanceRef.current;
|
|
217
227
|
if (!chart) {
|
|
228
|
+
var _onChartRef$current;
|
|
218
229
|
chart = echarts.init(chartRef.current);
|
|
219
230
|
chartInstanceRef.current = chart;
|
|
220
231
|
// Call the onChart callback on first initialization
|
|
221
|
-
|
|
232
|
+
(_onChartRef$current = onChartRef.current) === null || _onChartRef$current === void 0 || _onChartRef$current.call(onChartRef, chart);
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
// Apply the option
|
|
@@ -234,9 +245,13 @@ var ChartPie = function ChartPie(props) {
|
|
|
234
245
|
}
|
|
235
246
|
|
|
236
247
|
// Add click event
|
|
237
|
-
|
|
248
|
+
var handleClick = function handleClick(event) {
|
|
249
|
+
var _onClickRef$current;
|
|
250
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
251
|
+
};
|
|
252
|
+
if (hasOnClick) {
|
|
238
253
|
var _chartInstanceRef$cur2;
|
|
239
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
254
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
240
255
|
}
|
|
241
256
|
|
|
242
257
|
// Legend auto-scroll
|
|
@@ -257,9 +272,9 @@ var ChartPie = function ChartPie(props) {
|
|
|
257
272
|
// Cleanup function
|
|
258
273
|
return function () {
|
|
259
274
|
window.removeEventListener("resize", handleResize);
|
|
260
|
-
if (
|
|
275
|
+
if (hasOnClick) {
|
|
261
276
|
var _chartInstanceRef$cur3;
|
|
262
|
-
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click",
|
|
277
|
+
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click", handleClick);
|
|
263
278
|
}
|
|
264
279
|
|
|
265
280
|
// Clean up legend scrolling
|
|
@@ -268,7 +283,7 @@ var ChartPie = function ChartPie(props) {
|
|
|
268
283
|
legendScrollRef.current = null;
|
|
269
284
|
}
|
|
270
285
|
};
|
|
271
|
-
}, [chartOption, handleResize,
|
|
286
|
+
}, [chartOption, handleResize, onChartRef, onClickRef, hasOnClick, enableLegendAutoScroll, seriesData, legendVisibleCount, legendScrollInterval, containerReady]);
|
|
272
287
|
|
|
273
288
|
// Clean up resources when the component unmounts
|
|
274
289
|
useEffect(function () {
|
|
@@ -14,6 +14,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
|
14
14
|
import useContainerReady from "../_hooks/useContainerReady";
|
|
15
15
|
import styles from "../index.module.scss";
|
|
16
16
|
import * as echarts from "echarts";
|
|
17
|
+
import useLatestRef from "../../../hooks/useLatestRef";
|
|
17
18
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
19
|
var Sankey = function Sankey(props) {
|
|
19
20
|
var className = props.className,
|
|
@@ -103,6 +104,13 @@ var Sankey = function Sankey(props) {
|
|
|
103
104
|
return option;
|
|
104
105
|
}, [seriesData, seriesLinks, series]);
|
|
105
106
|
|
|
107
|
+
// getImage 只是「出图后把 dataURL 交出去」的出口,既不决定图怎么画,
|
|
108
|
+
// 也不该决定要不要重画。它进依赖数组会让 effect 跟着重跑 → setOption(notMerge)
|
|
109
|
+
// → 图重绘 → 再触发一次 finished → 再回调;消费方把图存进 state 就是死循环。
|
|
110
|
+
// 而且 finished 监听只在首次 init 时注册,闭包里锁死的是首帧的 getImage,
|
|
111
|
+
// 后续换了引用永远调不到 —— 依赖数组写了它也没用,是条死依赖。走 ref 两个问题一起解决。
|
|
112
|
+
var getImageRef = useLatestRef(getImage);
|
|
113
|
+
|
|
106
114
|
// Callback handling chart resize
|
|
107
115
|
var handleResize = useCallback(function () {
|
|
108
116
|
var _chartInstanceRef$cur;
|
|
@@ -125,7 +133,8 @@ var Sankey = function Sankey(props) {
|
|
|
125
133
|
|
|
126
134
|
// Attach the finished event listener on first initialization
|
|
127
135
|
chart.on("finished", function () {
|
|
128
|
-
|
|
136
|
+
var _getImageRef$current;
|
|
137
|
+
(_getImageRef$current = getImageRef.current) === null || _getImageRef$current === void 0 || _getImageRef$current.call(getImageRef, chart.getDataURL({
|
|
129
138
|
type: "png",
|
|
130
139
|
pixelRatio: 1,
|
|
131
140
|
backgroundColor: "#fff"
|
|
@@ -149,7 +158,7 @@ var Sankey = function Sankey(props) {
|
|
|
149
158
|
return function () {
|
|
150
159
|
window.removeEventListener("resize", handleResize);
|
|
151
160
|
};
|
|
152
|
-
}, [chartOption, handleResize,
|
|
161
|
+
}, [chartOption, handleResize, getImageRef, containerReady]);
|
|
153
162
|
|
|
154
163
|
// Clean up resources on unmount
|
|
155
164
|
useEffect(function () {
|
|
@@ -8,6 +8,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
|
8
8
|
import useContainerReady from "../_hooks/useContainerReady";
|
|
9
9
|
import styles from "../index.module.scss";
|
|
10
10
|
import * as echarts from "echarts";
|
|
11
|
+
import useLatestRef from "../../../hooks/useLatestRef";
|
|
11
12
|
import { deepCopy } from "hsu-utils";
|
|
12
13
|
import { handleTreeData } from "../_utils/tree";
|
|
13
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -38,6 +39,13 @@ var Tree = function Tree(props) {
|
|
|
38
39
|
return option;
|
|
39
40
|
}, [seriesData, series]);
|
|
40
41
|
|
|
42
|
+
// getImage 只是「出图后把 dataURL 交出去」的出口,既不决定图怎么画,
|
|
43
|
+
// 也不该决定要不要重画。它进依赖数组会让 effect 跟着重跑 → setOption(notMerge)
|
|
44
|
+
// → 图重绘 → 再触发一次 finished → 再回调;消费方把图存进 state 就是死循环。
|
|
45
|
+
// 而且 finished 监听只在首次 init 时注册,闭包里锁死的是首帧的 getImage,
|
|
46
|
+
// 后续换了引用永远调不到 —— 依赖数组写了它也没用,是条死依赖。走 ref 两个问题一起解决。
|
|
47
|
+
var getImageRef = useLatestRef(getImage);
|
|
48
|
+
|
|
41
49
|
// Callback handling chart resize
|
|
42
50
|
var handleResize = useCallback(function () {
|
|
43
51
|
var _chartInstanceRef$cur;
|
|
@@ -60,7 +68,8 @@ var Tree = function Tree(props) {
|
|
|
60
68
|
|
|
61
69
|
// Attach the finished event listener on first initialization
|
|
62
70
|
chart.on("finished", function () {
|
|
63
|
-
|
|
71
|
+
var _getImageRef$current;
|
|
72
|
+
(_getImageRef$current = getImageRef.current) === null || _getImageRef$current === void 0 || _getImageRef$current.call(getImageRef, chart.getDataURL({
|
|
64
73
|
type: "png",
|
|
65
74
|
pixelRatio: 1,
|
|
66
75
|
backgroundColor: "#fff"
|
|
@@ -84,7 +93,7 @@ var Tree = function Tree(props) {
|
|
|
84
93
|
return function () {
|
|
85
94
|
window.removeEventListener("resize", handleResize);
|
|
86
95
|
};
|
|
87
|
-
}, [chartOption, handleResize,
|
|
96
|
+
}, [chartOption, handleResize, getImageRef, containerReady]);
|
|
88
97
|
|
|
89
98
|
// Clean up resources on unmount
|
|
90
99
|
useEffect(function () {
|
|
@@ -18,6 +18,7 @@ import { useFileList } from "./_hooks";
|
|
|
18
18
|
import { FileList, AgentToggleButton, SendButton, StopButton, UploadButton } from "./_components";
|
|
19
19
|
import classNames from "classnames";
|
|
20
20
|
import Button from "../../Button";
|
|
21
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
21
22
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
22
23
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
24
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -82,7 +83,10 @@ var ChatInput = function ChatInput(props) {
|
|
|
82
83
|
var isControlled = externalAgentsState !== undefined;
|
|
83
84
|
// Use external state or internal state
|
|
84
85
|
var agentsState = isControlled ? externalAgentsState : internalAgentsState;
|
|
86
|
+
var onAgentsChangeRef = useLatestRef(onAgentsChange);
|
|
85
87
|
|
|
88
|
+
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
89
|
+
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
86
90
|
// When the model switches, sync the agents state (only in uncontrolled mode)
|
|
87
91
|
useEffect(function () {
|
|
88
92
|
if (isControlled) return; // In controlled mode, state is managed externally
|
|
@@ -91,10 +95,11 @@ var ChatInput = function ChatInput(props) {
|
|
|
91
95
|
return m.value === (modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelType);
|
|
92
96
|
});
|
|
93
97
|
if (currentModel !== null && currentModel !== void 0 && currentModel.agents && currentModel.agents.length > 0) {
|
|
98
|
+
var _onAgentsChangeRef$cu;
|
|
94
99
|
setInternalAgentsState(currentModel.agents);
|
|
95
|
-
|
|
100
|
+
(_onAgentsChangeRef$cu = onAgentsChangeRef.current) === null || _onAgentsChangeRef$cu === void 0 || _onAgentsChangeRef$cu.call(onAgentsChangeRef, currentModel.agents);
|
|
96
101
|
}
|
|
97
|
-
}, [modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelType, modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelList,
|
|
102
|
+
}, [modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelType, modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelList, onAgentsChangeRef, isControlled]);
|
|
98
103
|
|
|
99
104
|
// Based on the currently selected model, filter the feature configs supported by that model
|
|
100
105
|
var currentModel = modelConfig === null || modelConfig === void 0 ? void 0 : modelConfig.modelList.find(function (m) {
|
|
@@ -12,6 +12,7 @@ import * as AntdIcons from "@ant-design/icons";
|
|
|
12
12
|
import React, { useCallback, useEffect, useRef } from "react";
|
|
13
13
|
import classNames from "classnames";
|
|
14
14
|
import styles from "./index.module.scss";
|
|
15
|
+
import { useLatestRef } from "../../hooks/useLatestRef";
|
|
15
16
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
16
17
|
/** Check whether it is an AntD icon component name (e.g. "SettingOutlined") and return the corresponding component */
|
|
17
18
|
var getAntdIcon = function getAntdIcon(icon) {
|
|
@@ -46,9 +47,14 @@ var Icon = /*#__PURE__*/React.forwardRef(function (props, forwardedRef) {
|
|
|
46
47
|
forwardedRef.current = node;
|
|
47
48
|
}
|
|
48
49
|
}, [forwardedRef]);
|
|
50
|
+
var onRefRef = useLatestRef(onRef);
|
|
51
|
+
|
|
52
|
+
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
53
|
+
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
49
54
|
useEffect(function () {
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
var _onRefRef$current;
|
|
56
|
+
(_onRefRef$current = onRefRef.current) === null || _onRefRef$current === void 0 || _onRefRef$current.call(onRefRef, ref);
|
|
57
|
+
}, [onRefRef, ref]);
|
|
52
58
|
var mergedStyle = _objectSpread({
|
|
53
59
|
color: color,
|
|
54
60
|
fontSize: typeof fontSize === "number" ? "".concat(fontSize, "px") : fontSize
|
|
@@ -18,7 +18,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
18
18
|
import { CloseCircleFilled } from "@ant-design/icons";
|
|
19
19
|
import classNames from "classnames";
|
|
20
20
|
import styles from "./index.module.scss";
|
|
21
|
-
import {
|
|
21
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
22
22
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
23
23
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
24
24
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -40,6 +40,7 @@ var InputNumber = function InputNumber(props) {
|
|
|
40
40
|
// `getRef` keeps handing consumers an `HTMLInputElement` exactly as before.
|
|
41
41
|
var ref = useRef(null);
|
|
42
42
|
var wrapperRef = useRef(null);
|
|
43
|
+
var getRefRef = useLatestRef(getRef);
|
|
43
44
|
|
|
44
45
|
// On initialization, prefer value, then fall back to defaultValue
|
|
45
46
|
var initialValue = value !== undefined ? typeof value === "number" ? "".concat(value) : (_value$toString = value === null || value === void 0 ? void 0 : value.toString()) !== null && _value$toString !== void 0 ? _value$toString : "" : defaultValue !== undefined ? typeof defaultValue === "number" ? "".concat(defaultValue) : (_defaultValue$toStrin = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()) !== null && _defaultValue$toStrin !== void 0 ? _defaultValue$toStrin : "" : "";
|
|
@@ -47,19 +48,21 @@ var InputNumber = function InputNumber(props) {
|
|
|
47
48
|
_useState2 = _slicedToArray(_useState, 2),
|
|
48
49
|
_value = _useState2[0],
|
|
49
50
|
setValue = _useState2[1];
|
|
50
|
-
var _useState3 = useState(initialValue),
|
|
51
|
-
_useState4 = _slicedToArray(_useState3, 2),
|
|
52
|
-
lastValue = _useState4[0],
|
|
53
|
-
setLastValue = _useState4[1];
|
|
54
51
|
var prevValueRef = useRef(undefined);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
// 最近一次通知出去的文本,代替原来那个用 state 记账的写法
|
|
53
|
+
var notifiedRef = useRef(initialValue);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `onChange` 是「用户改了输入」这个**事件**的通知,不是从 state 推导出来的结果,
|
|
57
|
+
* 所以在事件处理里发,不在 effect 里发。详见 `TextArea/index.tsx` 里那段说明——
|
|
58
|
+
* 旧写法(依赖数组里放 `onChange`、体内又调它、用 state 记「通知过没有」)
|
|
59
|
+
* 会让传内联箭头的消费方死循环。
|
|
60
|
+
*/
|
|
61
|
+
var notify = function notify(next) {
|
|
62
|
+
if (next === notifiedRef.current) return;
|
|
63
|
+
notifiedRef.current = next;
|
|
64
|
+
onChange === null || onChange === void 0 || onChange(next);
|
|
65
|
+
};
|
|
63
66
|
useEffect(function () {
|
|
64
67
|
// Update internal state only when the external value prop actually changes
|
|
65
68
|
if (prevValueRef.current !== value) {
|
|
@@ -76,30 +79,33 @@ var InputNumber = function InputNumber(props) {
|
|
|
76
79
|
// 表示的是同一个数,此时以用户正在敲的那份文本为准。
|
|
77
80
|
var sameNumber = value !== undefined && value !== null && _value !== "" && Number(value) === Number(_value);
|
|
78
81
|
if (sameNumber) {
|
|
79
|
-
//
|
|
80
|
-
|
|
82
|
+
// 只同步「已通知过的值」,不动正在编辑的文本
|
|
83
|
+
notifiedRef.current = _value;
|
|
81
84
|
} else if (value !== undefined && value !== null) {
|
|
82
85
|
var newValue = typeof value === "number" ? "".concat(value) : value === null || value === void 0 ? void 0 : value.toString();
|
|
86
|
+
// 外部把值改了,之前通知过什么就不作数了,重新以外部值为准
|
|
87
|
+
notifiedRef.current = newValue;
|
|
83
88
|
setValue(newValue);
|
|
84
|
-
setLastValue(newValue);
|
|
85
89
|
} else {
|
|
86
90
|
// Clear only on initialization or when explicitly set to undefined/null externally
|
|
91
|
+
notifiedRef.current = "";
|
|
87
92
|
setValue("");
|
|
88
|
-
setLastValue("");
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
// `_value` 是刻意不进依赖的:这个 effect 只该在**外部** value 变化时跑,
|
|
92
96
|
// 把它加进来会让每次键入都重跑一遍,等于绕过上面那个 prevValueRef 判断
|
|
93
97
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94
98
|
}, [value]);
|
|
99
|
+
|
|
100
|
+
// 只在挂载时把 ref 交出去。`getRef` 进依赖数组同样会被内联箭头带着每次渲染重跑
|
|
95
101
|
useEffect(function () {
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
var _getRefRef$current;
|
|
103
|
+
(_getRefRef$current = getRefRef.current) === null || _getRefRef$current === void 0 || _getRefRef$current.call(getRefRef, ref.current);
|
|
104
|
+
}, [getRefRef]);
|
|
98
105
|
var handleClear = function handleClear(e) {
|
|
99
106
|
e.stopPropagation();
|
|
100
107
|
setValue("");
|
|
101
|
-
|
|
102
|
-
onChange === null || onChange === void 0 || onChange("");
|
|
108
|
+
notify("");
|
|
103
109
|
};
|
|
104
110
|
var showClear = allowClear && _value !== "" && _value !== undefined && !disabled;
|
|
105
111
|
var input = /*#__PURE__*/_jsx(AntdInputNumber, _objectSpread(_objectSpread({
|
|
@@ -108,6 +114,7 @@ var InputNumber = function InputNumber(props) {
|
|
|
108
114
|
onChange: function onChange(e) {
|
|
109
115
|
var newValue = e === null || e === undefined ? "" : (typeof e === "number" ? e : e || "").toString();
|
|
110
116
|
setValue(newValue);
|
|
117
|
+
notify(newValue);
|
|
111
118
|
},
|
|
112
119
|
className: classNames(styles.antdInput, className),
|
|
113
120
|
controls: false,
|
|
@@ -17,6 +17,7 @@ import AntdPassword from "antd/es/input/Password";
|
|
|
17
17
|
import React, { useEffect, useRef, useState } from "react";
|
|
18
18
|
import classNames from "classnames";
|
|
19
19
|
import styles from "./index.module.scss";
|
|
20
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
20
21
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
21
22
|
var Password = function Password(props) {
|
|
22
23
|
var _value$toString, _defaultValue$toStrin;
|
|
@@ -26,62 +27,69 @@ var Password = function Password(props) {
|
|
|
26
27
|
defaultValue = props.defaultValue,
|
|
27
28
|
className = props.className,
|
|
28
29
|
inputConfig = _objectWithoutProperties(props, _excluded);
|
|
29
|
-
var _useState = useState(false),
|
|
30
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
31
|
-
isComposing = _useState2[0],
|
|
32
|
-
setComposing = _useState2[1];
|
|
33
30
|
var ref = useRef(null);
|
|
31
|
+
var getRefRef = useLatestRef(getRef);
|
|
32
|
+
// 输入法组字期间不往外通知。放 ref 不放 state:它只决定「要不要发通知」,
|
|
33
|
+
// 不参与渲染,而且必须在同一次事件里立刻生效
|
|
34
|
+
var composingRef = useRef(false);
|
|
34
35
|
|
|
35
36
|
// On initialization, prefer value, then fall back to defaultValue
|
|
36
37
|
var initialValue = value !== undefined ? (_value$toString = value === null || value === void 0 ? void 0 : value.toString()) !== null && _value$toString !== void 0 ? _value$toString : "" : defaultValue !== undefined ? (_defaultValue$toStrin = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()) !== null && _defaultValue$toStrin !== void 0 ? _defaultValue$toStrin : "" : "";
|
|
37
|
-
var
|
|
38
|
-
|
|
39
|
-
_value =
|
|
40
|
-
setValue =
|
|
41
|
-
var _useState5 = useState(initialValue),
|
|
42
|
-
_useState6 = _slicedToArray(_useState5, 2),
|
|
43
|
-
lastValue = _useState6[0],
|
|
44
|
-
setLastValue = _useState6[1];
|
|
38
|
+
var _useState = useState(initialValue),
|
|
39
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
40
|
+
_value = _useState2[0],
|
|
41
|
+
setValue = _useState2[1];
|
|
45
42
|
var prevValueRef = useRef(undefined);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
// 最近一次通知出去的原文。只用来去掉 compositionend 与 input 两个事件的重复通知
|
|
44
|
+
var notifiedRef = useRef(initialValue);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `onChange` 是「用户改了输入」这个**事件**的通知,不是从 state 推导出来的结果,
|
|
48
|
+
* 所以在事件处理里发,不在 effect 里发。详见 `TextArea/index.tsx` 里那段说明——
|
|
49
|
+
* 旧写法(依赖数组里放 `onChange`、体内又调它、用 state 记「通知过没有」)
|
|
50
|
+
* 会让传内联箭头的消费方死循环。
|
|
51
|
+
*/
|
|
52
|
+
var notify = function notify(next) {
|
|
53
|
+
if (next === notifiedRef.current) return;
|
|
54
|
+
notifiedRef.current = next;
|
|
55
|
+
// 全是空白等同于空
|
|
56
|
+
onChange === null || onChange === void 0 || onChange(next.trim() === "" ? "" : next);
|
|
57
|
+
};
|
|
54
58
|
useEffect(function () {
|
|
55
59
|
// Update internal state only when the external value prop actually changes
|
|
56
60
|
if (prevValueRef.current !== value) {
|
|
61
|
+
var _value$toString2;
|
|
57
62
|
prevValueRef.current = value;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
setValue("");
|
|
64
|
-
setLastValue("");
|
|
65
|
-
}
|
|
63
|
+
|
|
64
|
+
// 外部把值改了,之前通知过什么就不作数了,重新以外部值为准
|
|
65
|
+
var next = value !== undefined ? (_value$toString2 = value === null || value === void 0 ? void 0 : value.toString()) !== null && _value$toString2 !== void 0 ? _value$toString2 : "" : "";
|
|
66
|
+
notifiedRef.current = next;
|
|
67
|
+
setValue(next);
|
|
66
68
|
}
|
|
67
69
|
}, [value]);
|
|
70
|
+
|
|
71
|
+
// 只在挂载时把 ref 交出去。`getRef` 进依赖数组同样会被内联箭头带着每次渲染重跑
|
|
68
72
|
useEffect(function () {
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
var _getRefRef$current;
|
|
74
|
+
(_getRefRef$current = getRefRef.current) === null || _getRefRef$current === void 0 || _getRefRef$current.call(getRefRef, ref.current);
|
|
75
|
+
}, [getRefRef]);
|
|
71
76
|
return /*#__PURE__*/_jsx(AntdPassword, _objectSpread({
|
|
72
77
|
className: classNames(styles.antdInput, className),
|
|
73
78
|
ref: ref,
|
|
74
79
|
onCompositionStart: function onCompositionStart() {
|
|
75
|
-
|
|
80
|
+
composingRef.current = true;
|
|
76
81
|
},
|
|
77
|
-
onCompositionEnd: function onCompositionEnd() {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
onCompositionEnd: function onCompositionEnd(e) {
|
|
83
|
+
composingRef.current = false;
|
|
84
|
+
// 组完字的那一下自己发通知。浏览器之间 compositionend 与 input 的先后
|
|
85
|
+
// 不一致,`notify` 里按原文去重,两种顺序都只会发出一次
|
|
86
|
+
notify(e.currentTarget.value);
|
|
81
87
|
},
|
|
82
88
|
value: _value,
|
|
83
89
|
onChange: function onChange(e) {
|
|
84
|
-
|
|
90
|
+
var next = e.target.value;
|
|
91
|
+
setValue(next);
|
|
92
|
+
if (!composingRef.current) notify(next);
|
|
85
93
|
}
|
|
86
94
|
}, inputConfig));
|
|
87
95
|
};
|
|
@@ -17,6 +17,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
17
17
|
import AntdSearch from "antd/es/input/Search";
|
|
18
18
|
import classNames from "classnames";
|
|
19
19
|
import styles from "./index.module.scss";
|
|
20
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
20
21
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
21
22
|
var Search = function Search(props) {
|
|
22
23
|
var _value$toString, _defaultValue$toStrin;
|
|
@@ -26,62 +27,69 @@ var Search = function Search(props) {
|
|
|
26
27
|
defaultValue = props.defaultValue,
|
|
27
28
|
className = props.className,
|
|
28
29
|
inputConfig = _objectWithoutProperties(props, _excluded);
|
|
29
|
-
var _useState = useState(false),
|
|
30
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
31
|
-
isComposing = _useState2[0],
|
|
32
|
-
setComposing = _useState2[1];
|
|
33
30
|
var ref = useRef(null);
|
|
31
|
+
var getRefRef = useLatestRef(getRef);
|
|
32
|
+
// 输入法组字期间不往外通知。放 ref 不放 state:它只决定「要不要发通知」,
|
|
33
|
+
// 不参与渲染,而且必须在同一次事件里立刻生效
|
|
34
|
+
var composingRef = useRef(false);
|
|
34
35
|
|
|
35
36
|
// On initialization, prefer value, then fall back to defaultValue
|
|
36
37
|
var initialValue = value !== undefined ? (_value$toString = value === null || value === void 0 ? void 0 : value.toString()) !== null && _value$toString !== void 0 ? _value$toString : "" : defaultValue !== undefined ? (_defaultValue$toStrin = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()) !== null && _defaultValue$toStrin !== void 0 ? _defaultValue$toStrin : "" : "";
|
|
37
|
-
var
|
|
38
|
-
|
|
39
|
-
_value =
|
|
40
|
-
setValue =
|
|
41
|
-
var _useState5 = useState(initialValue),
|
|
42
|
-
_useState6 = _slicedToArray(_useState5, 2),
|
|
43
|
-
lastValue = _useState6[0],
|
|
44
|
-
setLastValue = _useState6[1];
|
|
38
|
+
var _useState = useState(initialValue),
|
|
39
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
40
|
+
_value = _useState2[0],
|
|
41
|
+
setValue = _useState2[1];
|
|
45
42
|
var prevValueRef = useRef(undefined);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
// 最近一次通知出去的原文。只用来去掉 compositionend 与 input 两个事件的重复通知
|
|
44
|
+
var notifiedRef = useRef(initialValue);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `onChange` 是「用户改了输入」这个**事件**的通知,不是从 state 推导出来的结果,
|
|
48
|
+
* 所以在事件处理里发,不在 effect 里发。详见 `TextArea/index.tsx` 里那段说明——
|
|
49
|
+
* 旧写法(依赖数组里放 `onChange`、体内又调它、用 state 记「通知过没有」)
|
|
50
|
+
* 会让传内联箭头的消费方死循环。
|
|
51
|
+
*/
|
|
52
|
+
var notify = function notify(next) {
|
|
53
|
+
if (next === notifiedRef.current) return;
|
|
54
|
+
notifiedRef.current = next;
|
|
55
|
+
// 全是空白等同于空
|
|
56
|
+
onChange === null || onChange === void 0 || onChange(next.trim() === "" ? "" : next);
|
|
57
|
+
};
|
|
54
58
|
useEffect(function () {
|
|
55
59
|
// Update internal state only when the external value prop actually changes
|
|
56
60
|
if (prevValueRef.current !== value) {
|
|
61
|
+
var _value$toString2;
|
|
57
62
|
prevValueRef.current = value;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
setValue("");
|
|
64
|
-
setLastValue("");
|
|
65
|
-
}
|
|
63
|
+
|
|
64
|
+
// 外部把值改了,之前通知过什么就不作数了,重新以外部值为准
|
|
65
|
+
var next = value !== undefined ? (_value$toString2 = value === null || value === void 0 ? void 0 : value.toString()) !== null && _value$toString2 !== void 0 ? _value$toString2 : "" : "";
|
|
66
|
+
notifiedRef.current = next;
|
|
67
|
+
setValue(next);
|
|
66
68
|
}
|
|
67
69
|
}, [value]);
|
|
70
|
+
|
|
71
|
+
// 只在挂载时把 ref 交出去。`getRef` 进依赖数组同样会被内联箭头带着每次渲染重跑
|
|
68
72
|
useEffect(function () {
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
var _getRefRef$current;
|
|
74
|
+
(_getRefRef$current = getRefRef.current) === null || _getRefRef$current === void 0 || _getRefRef$current.call(getRefRef, ref.current);
|
|
75
|
+
}, [getRefRef]);
|
|
71
76
|
return /*#__PURE__*/_jsx(AntdSearch, _objectSpread({
|
|
72
77
|
ref: ref,
|
|
73
78
|
className: classNames(styles.antdInput, className),
|
|
74
79
|
onCompositionStart: function onCompositionStart() {
|
|
75
|
-
|
|
80
|
+
composingRef.current = true;
|
|
76
81
|
},
|
|
77
|
-
onCompositionEnd: function onCompositionEnd() {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
onCompositionEnd: function onCompositionEnd(e) {
|
|
83
|
+
composingRef.current = false;
|
|
84
|
+
// 组完字的那一下自己发通知。浏览器之间 compositionend 与 input 的先后
|
|
85
|
+
// 不一致,`notify` 里按原文去重,两种顺序都只会发出一次
|
|
86
|
+
notify(e.currentTarget.value);
|
|
81
87
|
},
|
|
82
88
|
value: _value,
|
|
83
89
|
onChange: function onChange(e) {
|
|
84
|
-
|
|
90
|
+
var next = e.target.value;
|
|
91
|
+
setValue(next);
|
|
92
|
+
if (!composingRef.current) notify(next);
|
|
85
93
|
}
|
|
86
94
|
}, inputConfig));
|
|
87
95
|
};
|