@ioca/react 1.4.74 → 1.4.76

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 (101) hide show
  1. package/lib/cjs/components/button/toggle.js +11 -18
  2. package/lib/cjs/components/button/toggle.js.map +1 -1
  3. package/lib/cjs/components/checkbox/checkbox.js +5 -8
  4. package/lib/cjs/components/checkbox/checkbox.js.map +1 -1
  5. package/lib/cjs/components/checkbox/item.js +15 -16
  6. package/lib/cjs/components/checkbox/item.js.map +1 -1
  7. package/lib/cjs/components/collapse/collapse.js +11 -13
  8. package/lib/cjs/components/collapse/collapse.js.map +1 -1
  9. package/lib/cjs/components/form/field.js +16 -20
  10. package/lib/cjs/components/form/field.js.map +1 -1
  11. package/lib/cjs/components/input/input.js +21 -18
  12. package/lib/cjs/components/input/input.js.map +1 -1
  13. package/lib/cjs/components/input/number.js +65 -19
  14. package/lib/cjs/components/input/number.js.map +1 -1
  15. package/lib/cjs/components/input/range.js +10 -13
  16. package/lib/cjs/components/input/range.js.map +1 -1
  17. package/lib/cjs/components/input/textarea.js +4 -7
  18. package/lib/cjs/components/input/textarea.js.map +1 -1
  19. package/lib/cjs/components/picker/colors/footer.js +7 -10
  20. package/lib/cjs/components/picker/colors/footer.js.map +1 -1
  21. package/lib/cjs/components/picker/colors/index.js +23 -21
  22. package/lib/cjs/components/picker/colors/index.js.map +1 -1
  23. package/lib/cjs/components/picker/dates/index.js +9 -12
  24. package/lib/cjs/components/picker/dates/index.js.map +1 -1
  25. package/lib/cjs/components/picker/dates/panel.js +29 -35
  26. package/lib/cjs/components/picker/dates/panel.js.map +1 -1
  27. package/lib/cjs/components/picker/time/index.js +8 -12
  28. package/lib/cjs/components/picker/time/index.js.map +1 -1
  29. package/lib/cjs/components/picker/time/panel.js +38 -21
  30. package/lib/cjs/components/picker/time/panel.js.map +1 -1
  31. package/lib/cjs/components/popconfirm/popconfirm.js +1 -1
  32. package/lib/cjs/components/popconfirm/popconfirm.js.map +1 -1
  33. package/lib/cjs/components/popup/content.js +5 -9
  34. package/lib/cjs/components/popup/content.js.map +1 -1
  35. package/lib/cjs/components/popup/popup.js +388 -157
  36. package/lib/cjs/components/popup/popup.js.map +1 -1
  37. package/lib/cjs/components/radio/radio.js +4 -7
  38. package/lib/cjs/components/radio/radio.js.map +1 -1
  39. package/lib/cjs/components/select/select.js +19 -24
  40. package/lib/cjs/components/select/select.js.map +1 -1
  41. package/lib/cjs/components/tabs/tabs.js +61 -54
  42. package/lib/cjs/components/tabs/tabs.js.map +1 -1
  43. package/lib/cjs/components/tree/tree.js +24 -26
  44. package/lib/cjs/components/tree/tree.js.map +1 -1
  45. package/lib/cjs/components/upload/upload.js +26 -33
  46. package/lib/cjs/components/upload/upload.js.map +1 -1
  47. package/lib/cjs/js/hooks.js +0 -4
  48. package/lib/cjs/js/hooks.js.map +1 -1
  49. package/lib/css/index.css +1 -1
  50. package/lib/css/index.css.map +1 -1
  51. package/lib/es/components/button/toggle.js +12 -19
  52. package/lib/es/components/button/toggle.js.map +1 -1
  53. package/lib/es/components/checkbox/checkbox.js +6 -9
  54. package/lib/es/components/checkbox/checkbox.js.map +1 -1
  55. package/lib/es/components/checkbox/item.js +16 -17
  56. package/lib/es/components/checkbox/item.js.map +1 -1
  57. package/lib/es/components/collapse/collapse.js +12 -14
  58. package/lib/es/components/collapse/collapse.js.map +1 -1
  59. package/lib/es/components/form/field.js +17 -21
  60. package/lib/es/components/form/field.js.map +1 -1
  61. package/lib/es/components/input/input.js +22 -19
  62. package/lib/es/components/input/input.js.map +1 -1
  63. package/lib/es/components/input/number.js +67 -21
  64. package/lib/es/components/input/number.js.map +1 -1
  65. package/lib/es/components/input/range.js +11 -14
  66. package/lib/es/components/input/range.js.map +1 -1
  67. package/lib/es/components/input/textarea.js +5 -8
  68. package/lib/es/components/input/textarea.js.map +1 -1
  69. package/lib/es/components/picker/colors/footer.js +8 -11
  70. package/lib/es/components/picker/colors/footer.js.map +1 -1
  71. package/lib/es/components/picker/colors/index.js +24 -22
  72. package/lib/es/components/picker/colors/index.js.map +1 -1
  73. package/lib/es/components/picker/dates/index.js +9 -12
  74. package/lib/es/components/picker/dates/index.js.map +1 -1
  75. package/lib/es/components/picker/dates/panel.js +30 -36
  76. package/lib/es/components/picker/dates/panel.js.map +1 -1
  77. package/lib/es/components/picker/time/index.js +8 -12
  78. package/lib/es/components/picker/time/index.js.map +1 -1
  79. package/lib/es/components/picker/time/panel.js +39 -22
  80. package/lib/es/components/picker/time/panel.js.map +1 -1
  81. package/lib/es/components/popconfirm/popconfirm.js +1 -1
  82. package/lib/es/components/popconfirm/popconfirm.js.map +1 -1
  83. package/lib/es/components/popup/content.js +6 -10
  84. package/lib/es/components/popup/content.js.map +1 -1
  85. package/lib/es/components/popup/popup.js +390 -159
  86. package/lib/es/components/popup/popup.js.map +1 -1
  87. package/lib/es/components/radio/radio.js +5 -8
  88. package/lib/es/components/radio/radio.js.map +1 -1
  89. package/lib/es/components/select/select.js +19 -24
  90. package/lib/es/components/select/select.js.map +1 -1
  91. package/lib/es/components/tabs/tabs.js +63 -56
  92. package/lib/es/components/tabs/tabs.js.map +1 -1
  93. package/lib/es/components/tree/tree.js +25 -27
  94. package/lib/es/components/tree/tree.js.map +1 -1
  95. package/lib/es/components/upload/upload.js +27 -34
  96. package/lib/es/components/upload/upload.js.map +1 -1
  97. package/lib/es/js/hooks.js +2 -5
  98. package/lib/es/js/hooks.js.map +1 -1
  99. package/lib/index.js +803 -541
  100. package/lib/types/components/popup/type.d.ts +0 -4
  101. package/package.json +100 -99
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import classNames from 'classnames';
3
3
  import { debounce, uid, throttle, title } from 'radash';
4
- import { useState, useRef, useEffect, useMemo, Children, cloneElement, createElement, isValidElement, Fragment as Fragment$1, useTransition, createContext, useContext, useLayoutEffect, useImperativeHandle } from 'react';
4
+ import { useState, useRef, useEffect, useMemo, Children, cloneElement, createElement, isValidElement, Fragment as Fragment$1, useTransition, forwardRef, useLayoutEffect, useImperativeHandle, createContext, useContext } from 'react';
5
5
  import { SkipPreviousRound, CloseRound, MinusRound, PlusRound, InboxTwotone, ClearAllRound, UndoRound, RedoRound, StrikethroughSRound, FormatUnderlinedRound, FormatItalicRound, FormatBoldRound, PlayArrowRound, PauseRound, StopRound, VolumeDownRound, VolumeOffRound, FullscreenRound, FullscreenExitRound, FeedOutlined, AspectRatioRound, OpenInNewRound, FileDownloadOutlined, RotateRightRound, RotateLeftRound, KeyboardArrowLeftRound, KeyboardArrowRightRound, KeyboardDoubleArrowUpRound, SyncAltRound, VisibilityRound, VisibilityOffRound, MoreHorizRound, SearchRound, CheckRound, UnfoldMoreRound, CalendarMonthTwotone, AccessTimeRound, InfoOutlined, KeyboardArrowDownRound, ListAltRound, DriveFolderUploadOutlined, PlusSharp } from '@ricons/material';
6
6
  import { createRoot } from 'react-dom/client';
7
7
  import { createPortal } from 'react-dom';
@@ -132,9 +132,6 @@ function useKeydown(listener, options) {
132
132
  };
133
133
  }, []);
134
134
  }
135
- function useCreation(factory, deps) {
136
- return useMemo(factory, deps);
137
- }
138
135
  function useReactive(initialState) {
139
136
  const [, setFlag] = useState(0);
140
137
  const scheduledRef = useRef(false);
@@ -428,25 +425,21 @@ function Group(props) {
428
425
 
429
426
  function Toggle(props) {
430
427
  const { ref, active, activeClass, after, disabled, children, className, toggable, onClick, onToggle, ...restProps } = props;
431
- const state = useReactive({
432
- active,
433
- done: true,
434
- });
428
+ const [isActive, setIsActive] = useState(active);
429
+ const [done, setDone] = useState(true);
435
430
  const toggle = async () => {
436
431
  const hasAfter = !!after;
437
- const nextActive = !state.active;
432
+ const nextActive = !isActive;
438
433
  const canToggle = toggable ? await toggable() : true;
439
434
  if (!canToggle)
440
435
  return;
441
- Object.assign(state, {
442
- active: nextActive,
443
- done: !hasAfter,
444
- });
436
+ setIsActive(nextActive);
437
+ setDone(!hasAfter);
445
438
  onToggle?.(nextActive);
446
439
  if (!hasAfter)
447
440
  return;
448
441
  setTimeout(() => {
449
- state.done = true;
442
+ setDone(true);
450
443
  }, 16);
451
444
  };
452
445
  const handleClick = (e) => {
@@ -454,14 +447,12 @@ function Toggle(props) {
454
447
  !disabled && toggle();
455
448
  };
456
449
  useEffect(() => {
457
- Object.assign(state, {
458
- active,
459
- done: true,
460
- });
450
+ setIsActive(active);
451
+ setDone(true);
461
452
  }, [active]);
462
- return (jsx(Button, { ref: ref, className: classNames(className, { [activeClass || ""]: state.active }, "i-btn-toggle"), ...restProps, onClick: handleClick, children: jsx("div", { className: classNames("i-btn-toggle-content", {
463
- "i-btn-toggle-active": state.done,
464
- }), children: state.active ? (after ?? children) : children }) }));
453
+ return (jsx(Button, { ref: ref, className: classNames(className, { [activeClass || ""]: isActive }, "i-btn-toggle"), ...restProps, onClick: handleClick, children: jsx("div", { className: classNames("i-btn-toggle-content", {
454
+ "i-btn-toggle-active": done,
455
+ }), children: isActive ? (after ?? children) : children }) }));
465
456
  }
466
457
 
467
458
  const formatClass = ({ outline, flat, loading, disabled, size = "normal", block, round, square, secondary, className, }) => classNames("i-btn", className, {
@@ -894,41 +885,39 @@ const arrayMove = (array, fromIndex, toIndex) => {
894
885
 
895
886
  function CheckboxItem(props) {
896
887
  const { type = "default", label, name, value = false, className, status = "normal", message, disabled, partof, optionValue, children, onChange, ...restProps } = props;
897
- const state = useReactive({
898
- value,
899
- status,
900
- message,
901
- });
888
+ const [checked, setChecked] = useState(value);
889
+ const [itemStatus, setItemStatus] = useState(status);
890
+ const [itemMessage, setItemMessage] = useState(message);
902
891
  const isChildrenFn = typeof children === "function";
903
892
  const handleChange = (e) => {
904
- const checked = e.target.checked;
905
- Object.assign(state, {
906
- value: checked,
907
- status,
908
- message,
909
- });
910
- onChange?.(checked, e);
893
+ const next = e.target.checked;
894
+ setChecked(next);
895
+ setItemStatus(status);
896
+ setItemMessage(message);
897
+ onChange?.(next, e);
911
898
  };
912
899
  useEffect(() => {
913
- state.value = value;
900
+ setChecked(value);
914
901
  }, [value]);
902
+ useEffect(() => {
903
+ setItemStatus(status);
904
+ setItemMessage(message);
905
+ }, [status, message]);
915
906
  return (jsxs("label", { className: classNames("i-checkbox-item", {
916
- [`i-checkbox-${state.status}`]: state.status !== "normal",
907
+ [`i-checkbox-${itemStatus}`]: itemStatus !== "normal",
917
908
  disabled,
918
909
  }, className), ...restProps, children: [jsx("input", { type: 'checkbox', name: name, className: classNames("i-checkbox-input", {
919
910
  [`i-checkbox-${type}`]: !partof,
920
911
  "i-checkbox-partof": partof,
921
- }), checked: state.value, disabled: disabled, onChange: handleChange }), isChildrenFn ? (children(state.value, optionValue)) : (jsx("span", { className: 'i-checkbox-text', children: children || label })), state.message && (jsxs("span", { className: 'i-checkbox-message', children: ["*", state.message] }))] }));
912
+ }), checked: checked, disabled: disabled, onChange: handleChange }), isChildrenFn ? (children(checked, optionValue)) : (jsx("span", { className: 'i-checkbox-text', children: children || label })), itemMessage && (jsxs("span", { className: 'i-checkbox-message', children: ["*", itemMessage] }))] }));
922
913
  }
923
914
 
924
915
  function Checkbox(props) {
925
916
  const { label, name, options = [], value = "", type = "default", optionInline = true, labelInline, disabled, status = "normal", message, required, className, renderItem, onChange, ...restProps } = props;
926
- const state = useReactive({
927
- value,
928
- });
917
+ const [selectedValues, setSelectedValues] = useState(value);
929
918
  const formattedOptions = useMemo(() => formatOption(options), [options]);
930
919
  const handleChange = (checked, opt, e) => {
931
- const group = [...state.value];
920
+ const group = [...selectedValues];
932
921
  const i = group.findIndex((item) => item === opt.value);
933
922
  if (checked && i < 0) {
934
923
  group.push(opt.value);
@@ -936,11 +925,11 @@ function Checkbox(props) {
936
925
  else if (!checked && i > -1) {
937
926
  group.splice(i, 1);
938
927
  }
939
- state.value = group;
928
+ setSelectedValues(group);
940
929
  onChange?.(group, opt, e);
941
930
  };
942
931
  useEffect(() => {
943
- state.value = value;
932
+ setSelectedValues(value);
944
933
  }, [value]);
945
934
  return (jsxs("div", { className: classNames("i-checkbox i-input-label", {
946
935
  [`i-checkbox-${status}`]: status !== "normal",
@@ -949,7 +938,7 @@ function Checkbox(props) {
949
938
  "i-options-block": !optionInline,
950
939
  "i-checkbox-options-button": type === "button",
951
940
  }), children: formattedOptions.map((option) => {
952
- return (jsx(CheckboxItem, { name: name, value: state.value.includes(option.value), optionValue: option.value, type: type, disabled: disabled || option.disabled, onChange: (checked, e) => handleChange(checked, option, e), children: renderItem ?? option.label }, option.value));
941
+ return (jsx(CheckboxItem, { name: name, value: selectedValues.includes(option.value), optionValue: option.value, type: type, disabled: disabled || option.disabled, onChange: (checked, e) => handleChange(checked, option, e), children: renderItem ?? option.label }, option.value));
953
942
  }) })] }));
954
943
  }
955
944
  Checkbox.Item = CheckboxItem;
@@ -975,9 +964,7 @@ function Item$5(props) {
975
964
 
976
965
  const Collapse = (props) => {
977
966
  const { active, items, multiple, border, headerClickable, className, children, renderToggle = (active) => active ? jsx(MinusRound, {}) : jsx(PlusRound, {}), onCollapse, ...restProps } = props;
978
- const state = useReactive({
979
- active,
980
- });
967
+ const [activeKey, setActiveKey] = useState(active);
981
968
  const collapses = useMemo(() => {
982
969
  if (!items) {
983
970
  if (!children)
@@ -1007,19 +994,20 @@ const Collapse = (props) => {
1007
994
  if (disabled)
1008
995
  return;
1009
996
  if (!multiple) {
1010
- state.active = state.active === key ? undefined : key;
1011
- onCollapse?.(key, state.active !== undefined);
997
+ const nextActive = activeKey === key ? undefined : key;
998
+ setActiveKey(nextActive);
999
+ onCollapse?.(key, nextActive !== undefined);
1012
1000
  return;
1013
1001
  }
1014
- if (!Array.isArray(state.active))
1015
- state.active = [];
1016
- const i = state.active.findIndex((k) => k === key);
1002
+ const group = Array.isArray(activeKey) ? [...activeKey] : [];
1003
+ const i = group.findIndex((k) => k === key);
1017
1004
  if (i > -1) {
1018
- state.active.splice(i, 1);
1005
+ group.splice(i, 1);
1019
1006
  }
1020
1007
  else {
1021
- key !== undefined && state.active.push(key);
1008
+ key !== undefined && group.push(key);
1022
1009
  }
1010
+ setActiveKey(group);
1023
1011
  onCollapse?.(key, i < 0);
1024
1012
  };
1025
1013
  return (jsx("div", { className: classNames("i-collapse", {
@@ -1027,8 +1015,8 @@ const Collapse = (props) => {
1027
1015
  }, className), ...restProps, children: collapses.map((item) => {
1028
1016
  const { key, title, content, disabled, className, ...restProps } = item;
1029
1017
  const isActive = multiple
1030
- ? (state.active || []).includes(key)
1031
- : state.active === key;
1018
+ ? (activeKey || []).includes(key)
1019
+ : activeKey === key;
1032
1020
  return (jsxs("div", { className: classNames("i-collapse-item", className, {
1033
1021
  "i-collapse-active": isActive,
1034
1022
  "i-collapse-disabled": disabled,
@@ -1337,16 +1325,10 @@ const List$1 = (props) => {
1337
1325
  };
1338
1326
  List$1.Item = Item$4;
1339
1327
 
1340
- const ModalContext = createContext(false);
1341
-
1342
- const Content$2 = (props) => {
1343
- const { ref, getContainer = (trigger) => {
1344
- if (typeof document === "undefined")
1345
- return null;
1346
- return trigger?.offsetParent ?? document.body;
1347
- }, trigger, arrow, arrowProps = {}, className, children, ...restProps } = props;
1328
+ const Content$2 = forwardRef((props, ref) => {
1329
+ const { arrow, arrowProps = {}, className, children, ...restProps } = props;
1348
1330
  const arrowCSS = useMemo(() => {
1349
- let { left, top, pos } = arrowProps;
1331
+ let { left = 0, top = 0, pos } = arrowProps;
1350
1332
  let transform = "";
1351
1333
  switch (pos) {
1352
1334
  case "left":
@@ -1373,153 +1355,324 @@ const Content$2 = (props) => {
1373
1355
  };
1374
1356
  }, [arrowProps]);
1375
1357
  const content = (jsxs("div", { ref: ref, className: classNames("i-popup", className), ...restProps, children: [arrow && (jsx("svg", { xmlns: 'http://www.w3.org/2000/svg', className: 'i-popup-arrow', style: arrowCSS, children: jsx("path", { d: 'M0.5 0L1.5 0C1.5 4, 3 5.5, 5 7.5S8,10 8,12S7 14.5, 5 16.5S1.5,20 1.5,24L0.5 24L0.5 0z' }) })), children] }));
1376
- const container = getContainer(trigger);
1358
+ const container = typeof document === "undefined" ? null : document.body;
1377
1359
  if (!container)
1378
1360
  return null;
1379
1361
  return createPortal(content, container);
1380
- };
1362
+ });
1381
1363
 
1382
1364
  function Popup(props) {
1383
- const { visible = false, content, trigger = "hover", gap = 12, offset = 8, fixed, position = "top", showDelay = 16, hideDelay = 12, touchable, arrow = true, align, fitSize, watchResize, clickOutside = true, disabled, style, className, getContainer, children, onVisibleChange, } = props;
1365
+ const { visible = false, content, trigger = "hover", gap = 12, offset = 8, position = "top", showDelay = 16, hideDelay = 12, touchable, arrow = true, align = "center", fitSize, disabled, style, className, children, onVisibleChange, } = props;
1384
1366
  const triggerRef = useRef(null);
1385
1367
  const contentRef = useRef(null);
1386
1368
  const timerRef = useRef(null);
1387
- const statusRef = useRef("");
1388
- const isInModal = useContext(ModalContext);
1389
- const refWindow = isInModal || fixed;
1390
- const state = useReactive({
1391
- show: false,
1392
- style: { position: refWindow ? "fixed" : "absolute" },
1393
- arrowProps: {},
1394
- });
1395
- useMouseUp((e) => {
1396
- if (!triggerRef.current || !contentRef.current || !clickOutside)
1397
- return;
1398
- const tar = e.target;
1399
- const isContain = triggerRef.current.contains(tar) ||
1400
- contentRef.current.contains(tar);
1401
- if (!state.show || isContain)
1402
- return;
1403
- handleToggle(false);
1369
+ const afterHideTimerRef = useRef(null);
1370
+ const rafRef = useRef(null);
1371
+ const [show, setShow] = useState(false);
1372
+ const showRef = useRef(false);
1373
+ showRef.current = show;
1374
+ const latestRef = useRef({
1375
+ disabled,
1376
+ trigger,
1377
+ touchable,
1378
+ showDelay,
1379
+ hideDelay,
1380
+ position,
1381
+ gap,
1382
+ offset,
1383
+ align,
1384
+ fitSize,
1385
+ onVisibleChange,
1404
1386
  });
1387
+ latestRef.current = {
1388
+ disabled,
1389
+ trigger,
1390
+ touchable,
1391
+ showDelay,
1392
+ hideDelay,
1393
+ position,
1394
+ gap,
1395
+ offset,
1396
+ align,
1397
+ fitSize,
1398
+ onVisibleChange,
1399
+ };
1400
+ const phaseRef = useRef("");
1401
+ const lastPosRef = useRef(null);
1402
+ const lastArrowRef = useRef(null);
1403
+ const arrowElRef = useRef(null);
1404
+ const pointRef = useRef(null);
1405
1405
  const clearTimer = () => {
1406
1406
  if (!timerRef.current)
1407
1407
  return;
1408
1408
  clearTimeout(timerRef.current);
1409
1409
  timerRef.current = null;
1410
- statusRef.current = "";
1410
+ phaseRef.current = "";
1411
+ };
1412
+ const clearAllTimers = () => {
1413
+ clearTimer();
1414
+ if (afterHideTimerRef.current) {
1415
+ clearTimeout(afterHideTimerRef.current);
1416
+ afterHideTimerRef.current = null;
1417
+ }
1418
+ if (rafRef.current !== null) {
1419
+ cancelAnimationFrame(rafRef.current);
1420
+ rafRef.current = null;
1421
+ }
1422
+ };
1423
+ const setContentVisible = (visible) => {
1424
+ const el = contentRef.current;
1425
+ if (!el)
1426
+ return;
1427
+ el.style.opacity = visible ? "1" : "0";
1428
+ el.style.transform = visible ? "none" : "translate(0, 2px)";
1429
+ };
1430
+ const ensureBaseStyle = () => {
1431
+ const el = contentRef.current;
1432
+ if (!el)
1433
+ return;
1434
+ const pos = "fixed";
1435
+ if (el.style.position !== pos)
1436
+ el.style.position = pos;
1437
+ };
1438
+ const applyFitSize = () => {
1439
+ const o = latestRef.current;
1440
+ const triggerEl = triggerRef.current;
1441
+ const contentEl = contentRef.current;
1442
+ if (!triggerEl || !contentEl)
1443
+ return;
1444
+ const vertical = ["top", "bottom"].includes(o.position);
1445
+ const key = vertical ? "width" : "height";
1446
+ if (!o.fitSize) {
1447
+ contentEl.style[key] = "";
1448
+ return;
1449
+ }
1450
+ const size = triggerEl[vertical ? "offsetWidth" : "offsetHeight"];
1451
+ contentEl.style[key] =
1452
+ typeof size === "number" ? `${size}px` : "";
1453
+ };
1454
+ const applyArrow = (arrowX, arrowY, arrowPos) => {
1455
+ const contentEl = contentRef.current;
1456
+ if (!contentEl)
1457
+ return;
1458
+ const arrowEl = arrowElRef.current ??
1459
+ contentEl.querySelector(".i-popup-arrow");
1460
+ arrowElRef.current = arrowEl;
1461
+ if (!arrowEl)
1462
+ return;
1463
+ let left = arrowX ?? 0;
1464
+ let top = arrowY ?? 0;
1465
+ let transform = "";
1466
+ switch (arrowPos) {
1467
+ case "left":
1468
+ left += 2;
1469
+ transform = `translate(-100%, -50%) rotate(180deg)`;
1470
+ break;
1471
+ case "right":
1472
+ left -= 2;
1473
+ transform = `translate(0, -50%)`;
1474
+ break;
1475
+ case "top":
1476
+ top -= 2;
1477
+ transform = `translate(-50%, -50%) rotate(-90deg)`;
1478
+ break;
1479
+ case "bottom":
1480
+ top += 2;
1481
+ transform = `translate(-50%, -50%) rotate(90deg)`;
1482
+ break;
1483
+ }
1484
+ const prev = lastArrowRef.current;
1485
+ if (prev &&
1486
+ prev.left === left &&
1487
+ prev.top === top &&
1488
+ prev.transform === transform) {
1489
+ return;
1490
+ }
1491
+ lastArrowRef.current = { left, top, transform };
1492
+ arrowEl.style.left = `${left}px`;
1493
+ arrowEl.style.top = `${top}px`;
1494
+ arrowEl.style.transform = transform;
1495
+ };
1496
+ const applyLeftTop = (left, top) => {
1497
+ const contentEl = contentRef.current;
1498
+ if (!contentEl)
1499
+ return;
1500
+ const prev = lastPosRef.current;
1501
+ if (prev && prev.left === left && prev.top === top)
1502
+ return;
1503
+ lastPosRef.current = { left, top };
1504
+ contentEl.style.left = `${left}px`;
1505
+ contentEl.style.top = `${top}px`;
1506
+ };
1507
+ const computeRelativePosition = () => {
1508
+ const triggerEl = triggerRef.current;
1509
+ const contentEl = contentRef.current;
1510
+ if (!triggerEl || !contentEl)
1511
+ return;
1512
+ const o = latestRef.current;
1513
+ applyFitSize();
1514
+ const [left, top, { arrowX, arrowY, arrowPos }] = getPosition(triggerEl, contentEl, {
1515
+ position: o.position,
1516
+ gap: o.gap,
1517
+ offset: o.offset,
1518
+ align: o.align,
1519
+ refWindow: true,
1520
+ });
1521
+ applyLeftTop(left, top);
1522
+ applyArrow(arrowX, arrowY, arrowPos);
1523
+ };
1524
+ const computePointPosition = () => {
1525
+ const contentEl = contentRef.current;
1526
+ if (!contentEl)
1527
+ return;
1528
+ const point = pointRef.current;
1529
+ if (!point)
1530
+ return;
1531
+ const [left, top] = getPointPosition(point, contentEl);
1532
+ applyLeftTop(left, top);
1533
+ };
1534
+ const scheduleComputePosition = () => {
1535
+ if (!showRef.current)
1536
+ return;
1537
+ if (rafRef.current !== null)
1538
+ return;
1539
+ rafRef.current = requestAnimationFrame(() => {
1540
+ rafRef.current = null;
1541
+ if (!showRef.current)
1542
+ return;
1543
+ ensureBaseStyle();
1544
+ if (latestRef.current.trigger === "contextmenu") {
1545
+ computePointPosition();
1546
+ return;
1547
+ }
1548
+ computeRelativePosition();
1549
+ });
1411
1550
  };
1412
1551
  const handleShow = () => {
1413
- if (disabled)
1552
+ const opts = latestRef.current;
1553
+ if (opts.disabled)
1414
1554
  return;
1415
- if (state.show &&
1416
- (trigger !== "hover" || (trigger === "hover" && !touchable))) {
1555
+ clearAllTimers();
1556
+ if (showRef.current &&
1557
+ (opts.trigger !== "hover" ||
1558
+ (opts.trigger === "hover" && !opts.touchable))) {
1559
+ ensureBaseStyle();
1560
+ computeRelativePosition();
1561
+ setContentVisible(true);
1417
1562
  return;
1418
1563
  }
1419
- statusRef.current = "showing";
1420
- state.show = true;
1564
+ phaseRef.current = "showing";
1565
+ if (!showRef.current) {
1566
+ lastPosRef.current = null;
1567
+ lastArrowRef.current = null;
1568
+ arrowElRef.current = null;
1569
+ setShow(true);
1570
+ }
1421
1571
  timerRef.current = setTimeout(() => {
1422
- if (statusRef.current !== "showing")
1572
+ if (phaseRef.current !== "showing")
1423
1573
  return;
1424
- requestAnimationFrame(() => {
1425
- if (statusRef.current !== "showing")
1574
+ rafRef.current = requestAnimationFrame(() => {
1575
+ rafRef.current = null;
1576
+ if (phaseRef.current !== "showing")
1426
1577
  return;
1427
- const [left, top, { arrowX, arrowY, arrowPos }] = getPosition(triggerRef.current, contentRef.current, {
1428
- position,
1429
- gap,
1430
- offset,
1431
- align,
1432
- refWindow,
1433
- });
1434
- state.style = {
1435
- ...state.style,
1436
- opacity: 1,
1437
- transform: "none",
1438
- left,
1439
- top,
1440
- };
1441
- state.arrowProps = {
1442
- left: arrowX,
1443
- top: arrowY,
1444
- pos: arrowPos,
1445
- };
1446
- onVisibleChange?.(true);
1578
+ if (!contentRef.current)
1579
+ return;
1580
+ ensureBaseStyle();
1581
+ if (opts.trigger === "contextmenu") {
1582
+ computePointPosition();
1583
+ }
1584
+ else {
1585
+ computeRelativePosition();
1586
+ }
1587
+ setContentVisible(true);
1588
+ opts.onVisibleChange?.(true);
1447
1589
  clearTimer();
1448
- statusRef.current = "";
1590
+ phaseRef.current = "";
1449
1591
  });
1450
- }, showDelay);
1592
+ }, opts.showDelay);
1451
1593
  };
1452
1594
  const handleHide = () => {
1453
- if (!state.show)
1595
+ if (!showRef.current)
1454
1596
  return;
1455
- statusRef.current = "hiding";
1597
+ clearAllTimers();
1598
+ phaseRef.current = "hiding";
1456
1599
  timerRef.current = setTimeout(() => {
1457
- if (statusRef.current !== "hiding") {
1600
+ if (phaseRef.current !== "hiding") {
1458
1601
  clearTimer();
1459
1602
  return;
1460
1603
  }
1461
- state.style = {
1462
- ...state.style,
1463
- opacity: 0,
1464
- transform: "translate(0, 2px)",
1465
- };
1466
- setTimeout(() => {
1467
- state.show = false;
1468
- clearTimer();
1469
- onVisibleChange?.(false);
1470
- statusRef.current = "";
1604
+ setContentVisible(false);
1605
+ afterHideTimerRef.current = setTimeout(() => {
1606
+ afterHideTimerRef.current = null;
1607
+ setShow(false);
1608
+ clearAllTimers();
1609
+ latestRef.current.onVisibleChange?.(false);
1610
+ phaseRef.current = "";
1471
1611
  }, 160);
1472
- }, hideDelay);
1612
+ }, latestRef.current.hideDelay);
1473
1613
  };
1474
1614
  const handleToggle = (action) => {
1475
1615
  if (action !== undefined) {
1476
1616
  action ? handleShow() : handleHide();
1477
1617
  return;
1478
1618
  }
1479
- state.show ? handleHide() : handleShow();
1480
- };
1481
- const eventMaps = useCreation(() => ({
1482
- click: {
1483
- onClick: () => handleToggle(true),
1484
- },
1485
- hover: {
1486
- onMouseEnter: () => handleToggle(true),
1487
- onMouseLeave: () => handleToggle(false),
1488
- },
1489
- focus: {
1490
- onFocus: () => handleToggle(true),
1491
- onBlur: () => handleToggle(false),
1492
- },
1493
- contextmenu: {
1494
- onContextMenu: (e) => {
1495
- e.preventDefault();
1496
- e.stopPropagation();
1497
- if (state.show) {
1498
- const [left, top] = getPointPosition(e, contentRef.current);
1499
- state.style = {
1500
- ...state.style,
1501
- left,
1502
- top,
1503
- };
1504
- return;
1505
- }
1506
- state.show = true;
1507
- timerRef.current = setTimeout(() => {
1508
- const [left, top] = getPointPosition(e, contentRef.current);
1509
- state.style = {
1510
- ...state.style,
1511
- opacity: 1,
1512
- transform: "none",
1513
- left,
1514
- top,
1619
+ showRef.current ? handleHide() : handleShow();
1620
+ };
1621
+ const hideRef = useRef(handleHide);
1622
+ const toggleRef = useRef(handleToggle);
1623
+ hideRef.current = handleHide;
1624
+ toggleRef.current = handleToggle;
1625
+ const doHide = useMemo(() => () => hideRef.current(), []);
1626
+ const doToggle = useMemo(() => (action) => toggleRef.current(action), []);
1627
+ const eventMaps = useMemo(() => {
1628
+ return {
1629
+ click: {
1630
+ onClick: () => doToggle(true),
1631
+ },
1632
+ hover: {
1633
+ onMouseEnter: () => doToggle(true),
1634
+ onMouseLeave: () => doToggle(false),
1635
+ },
1636
+ focus: {
1637
+ onFocus: () => doToggle(true),
1638
+ onBlur: () => doToggle(false),
1639
+ },
1640
+ contextmenu: {
1641
+ onContextMenu: (e) => {
1642
+ e.preventDefault();
1643
+ e.stopPropagation();
1644
+ pointRef.current = {
1645
+ pageX: e.pageX,
1646
+ pageY: e.pageY,
1515
1647
  };
1516
- clearTimer();
1517
- onVisibleChange?.(true);
1518
- }, showDelay);
1648
+ if (showRef.current) {
1649
+ ensureBaseStyle();
1650
+ computePointPosition();
1651
+ return;
1652
+ }
1653
+ clearAllTimers();
1654
+ phaseRef.current = "showing";
1655
+ lastPosRef.current = null;
1656
+ lastArrowRef.current = null;
1657
+ arrowElRef.current = null;
1658
+ setShow(true);
1659
+ timerRef.current = setTimeout(() => {
1660
+ if (phaseRef.current !== "showing")
1661
+ return;
1662
+ if (!contentRef.current)
1663
+ return;
1664
+ ensureBaseStyle();
1665
+ computePointPosition();
1666
+ setContentVisible(true);
1667
+ clearTimer();
1668
+ latestRef.current.onVisibleChange?.(true);
1669
+ phaseRef.current = "";
1670
+ }, latestRef.current.showDelay);
1671
+ },
1519
1672
  },
1520
- },
1521
- none: {},
1522
- }), []);
1673
+ none: {},
1674
+ };
1675
+ }, [doToggle]);
1523
1676
  const contentTouch = useMemo(() => {
1524
1677
  if (!touchable)
1525
1678
  return {};
@@ -1532,72 +1685,132 @@ function Popup(props) {
1532
1685
  }
1533
1686
  return events;
1534
1687
  }, [touchable, trigger]);
1535
- const computePosition = () => {
1536
- if (!state.show)
1537
- return;
1538
- const [left, top, { arrowX, arrowY, arrowPos }] = getPosition(triggerRef.current, contentRef.current, {
1539
- position,
1540
- gap,
1541
- offset,
1542
- align,
1543
- refWindow,
1544
- });
1545
- Object.assign(state, {
1546
- style: { ...state.style, left, top },
1547
- arrowProps: { left: arrowX, top: arrowY, pos: arrowPos },
1548
- });
1549
- };
1550
1688
  const { observe, unobserve, disconnect } = useResizeObserver();
1551
1689
  useEffect(() => {
1552
- if (trigger === "contextmenu" || !observe)
1553
- return;
1554
- triggerRef.current && observe(triggerRef.current, computePosition);
1555
- if (!watchResize || !contentRef.current)
1556
- return;
1557
- observe(contentRef.current, computePosition);
1690
+ if (!observe)
1691
+ return;
1692
+ const triggerEl = triggerRef.current;
1693
+ const contentEl = contentRef.current;
1694
+ if (triggerEl)
1695
+ observe(triggerEl, scheduleComputePosition);
1696
+ if (contentEl)
1697
+ observe(contentEl, scheduleComputePosition);
1558
1698
  return () => {
1559
- if (!watchResize || !contentRef.current)
1560
- return;
1561
- unobserve(contentRef.current);
1562
- triggerRef.current && unobserve(triggerRef.current);
1699
+ if (contentEl)
1700
+ unobserve(contentEl);
1701
+ if (triggerEl)
1702
+ unobserve(triggerEl);
1563
1703
  disconnect();
1564
1704
  };
1565
- }, [watchResize, contentRef.current, triggerRef.current]);
1705
+ }, [trigger, observe, unobserve, disconnect, show]);
1566
1706
  useLayoutEffect(() => {
1567
- if (!fitSize || !state.show)
1707
+ if (!show)
1568
1708
  return;
1569
- const vertical = ["top", "bottom"].includes(position);
1570
- const size = triggerRef.current?.[vertical ? "offsetWidth" : "offsetHeight"];
1571
- state.style = { ...state.style, [vertical ? "width" : "height"]: size };
1572
- }, [state.show, fitSize]);
1709
+ ensureBaseStyle();
1710
+ if (latestRef.current.trigger === "contextmenu") {
1711
+ computePointPosition();
1712
+ }
1713
+ else {
1714
+ computeRelativePosition();
1715
+ }
1716
+ }, [show]);
1573
1717
  useLayoutEffect(() => {
1574
- handleToggle(visible);
1718
+ doToggle(visible);
1575
1719
  }, [visible]);
1576
1720
  useEffect(() => {
1577
1721
  return () => {
1578
- clearTimer();
1722
+ clearAllTimers();
1579
1723
  };
1580
1724
  }, []);
1581
- return (jsxs(Fragment, { children: [Children.map(children, (child) => {
1582
- if (!isValidElement(child))
1583
- return;
1584
- const { className, ...restProps } = child.props;
1585
- Object.keys(eventMaps[trigger]).map((evt) => {
1586
- if (!restProps[evt])
1587
- return;
1588
- const fn = eventMaps[trigger][evt];
1589
- eventMaps[trigger][evt] = (e) => {
1590
- fn();
1591
- restProps[evt](e);
1592
- };
1593
- });
1594
- return cloneElement(child, {
1595
- ref: triggerRef,
1596
- className,
1597
- ...restProps,
1598
- ...eventMaps[trigger],
1725
+ const mouseUpHandlerRef = useRef(() => { });
1726
+ mouseUpHandlerRef.current = (e) => {
1727
+ if (!showRef.current)
1728
+ return;
1729
+ const triggerEl = triggerRef.current;
1730
+ const contentEl = contentRef.current;
1731
+ if (!triggerEl || !contentEl)
1732
+ return;
1733
+ const tar = e.target;
1734
+ if (triggerEl.contains(tar) || contentEl.contains(tar))
1735
+ return;
1736
+ doHide();
1737
+ };
1738
+ const onGlobalMouseUp = useMemo(() => (e) => mouseUpHandlerRef.current(e), []);
1739
+ useMouseUp(onGlobalMouseUp);
1740
+ useEffect(() => {
1741
+ if (!show)
1742
+ return;
1743
+ if (typeof window === "undefined")
1744
+ return;
1745
+ const onScrollOrResize = debounce({ delay: 160 }, () => {
1746
+ scheduleComputePosition();
1747
+ });
1748
+ window.addEventListener("scroll", onScrollOrResize, {
1749
+ passive: true,
1750
+ capture: true,
1751
+ });
1752
+ return () => {
1753
+ window.removeEventListener("scroll", onScrollOrResize, true);
1754
+ };
1755
+ }, [show]);
1756
+ const mergeRefs = (...refs) => {
1757
+ return (node) => {
1758
+ for (const ref of refs) {
1759
+ if (!ref)
1760
+ continue;
1761
+ if (typeof ref === "function") {
1762
+ ref(node);
1763
+ }
1764
+ else {
1765
+ ref.current = node;
1766
+ }
1767
+ }
1768
+ };
1769
+ };
1770
+ return (jsxs(Fragment, { children: [(() => {
1771
+ const events = eventMaps[trigger];
1772
+ const items = Children.toArray(children);
1773
+ const canAttachRef = (el) => {
1774
+ if (!isValidElement(el))
1775
+ return false;
1776
+ const t = el.type;
1777
+ if (typeof t === "string")
1778
+ return true;
1779
+ if (t?.prototype?.isReactComponent)
1780
+ return true;
1781
+ if (t?.$$typeof === Symbol.for("react.forward_ref"))
1782
+ return true;
1783
+ return false;
1784
+ };
1785
+ if (items.length !== 1) {
1786
+ return (jsx("div", { ref: triggerRef, ...events, className: 'i-popup-trigger', style: { display: "inline-block" }, children: children }));
1787
+ }
1788
+ const only = items[0];
1789
+ if (!isValidElement(only) || !canAttachRef(only)) {
1790
+ return (jsx("div", { ref: triggerRef, ...events, className: 'i-popup-trigger', style: { display: "inline-block" }, children: only }));
1791
+ }
1792
+ const { className: childClassName, ...restProps } = only.props;
1793
+ const nextProps = { ...restProps };
1794
+ for (const evt of Object.keys(events)) {
1795
+ const theirs = restProps[evt];
1796
+ const ours = events[evt];
1797
+ nextProps[evt] =
1798
+ typeof theirs === "function"
1799
+ ? (e) => {
1800
+ ours(e);
1801
+ theirs(e);
1802
+ }
1803
+ : ours;
1804
+ }
1805
+ return cloneElement(only, {
1806
+ ref: mergeRefs(only.ref, triggerRef),
1807
+ className: childClassName,
1808
+ ...nextProps,
1599
1809
  });
1600
- }), state.show && (jsx(Content$2, { ref: contentRef, arrow: arrow && trigger !== "contextmenu", style: { ...style, ...state.style }, arrowProps: state.arrowProps, className: className, ...contentTouch, trigger: triggerRef.current, getContainer: getContainer, children: content }))] }));
1810
+ })(), show && (jsx(Content$2, { ref: contentRef, arrow: arrow && trigger !== "contextmenu", style: {
1811
+ ...style,
1812
+ position: "fixed",
1813
+ }, className: className, ...contentTouch, trigger: triggerRef.current, children: content }))] }));
1601
1814
  }
1602
1815
 
1603
1816
  const { Item: ListItem } = List$1;
@@ -1808,12 +2021,9 @@ const Context = createContext({});
1808
2021
 
1809
2022
  function Field(props) {
1810
2023
  const { name, required, children } = props;
1811
- const state = useReactive({
1812
- value: undefined,
1813
- status: "normal",
1814
- message: undefined,
1815
- update: 0,
1816
- });
2024
+ const [fieldValue, setFieldValue] = useState(undefined);
2025
+ const [fieldStatus, setFieldStatus] = useState("normal");
2026
+ const [fieldMessage, setFieldMessage] = useState(undefined);
1817
2027
  const form = useContext(Context);
1818
2028
  const { id } = form;
1819
2029
  const handleChange = (v) => {
@@ -1830,33 +2040,33 @@ function Field(props) {
1830
2040
  if (!isValidElement(node))
1831
2041
  return null;
1832
2042
  const { onChange } = node.props;
1833
- const { value, status, message } = state;
1834
2043
  return cloneElement(node, {
1835
- value,
1836
- status,
1837
- message,
2044
+ value: fieldValue,
2045
+ status: fieldStatus,
2046
+ message: fieldMessage,
1838
2047
  required,
1839
2048
  onChange: (...args) => {
1840
2049
  handleChange(args[0]);
1841
2050
  onChange?.(...args);
1842
- Object.assign(state, {
1843
- status: "normal",
1844
- message: undefined,
1845
- });
2051
+ setFieldStatus("normal");
2052
+ setFieldMessage(undefined);
1846
2053
  },
1847
2054
  });
1848
2055
  });
1849
- }, [children, state.update]);
2056
+ }, [children, fieldValue, fieldStatus, fieldMessage, required]);
1850
2057
  useEffect(() => {
1851
2058
  if (!name)
1852
2059
  return;
1853
2060
  PubSub.subscribe(`${id}:set:${name}`, (evt, v) => {
1854
- state.value = v;
1855
- state.update += 1;
2061
+ setFieldValue(v);
1856
2062
  });
1857
2063
  PubSub.subscribe(`${id}:invalid:${name}`, (evt, v) => {
1858
- Object.assign(state, v);
1859
- state.update += 1;
2064
+ if (v?.value !== undefined)
2065
+ setFieldValue(v.value);
2066
+ if (v?.status)
2067
+ setFieldStatus(v.status);
2068
+ if ("message" in (v ?? {}))
2069
+ setFieldMessage(v.message);
1860
2070
  });
1861
2071
  Promise.resolve().then(() => {
1862
2072
  form.set(name, form.cacheData[name] ?? undefined);
@@ -2099,6 +2309,8 @@ function Content$1(props) {
2099
2309
  return (jsxs(Fragment, { children: [showHeader && (jsxs("header", { className: 'i-modal-header', children: [title && jsx("b", { children: title }), jsx(Helpericon, { active: !hideCloseButton, className: 'i-modal-close', onClick: onClose })] })), jsx("div", { className: 'i-modal-content', children: children }), jsx("footer", { className: 'i-modal-footer', children: renderFooter })] }));
2100
2310
  }
2101
2311
 
2312
+ const ModalContext = createContext(false);
2313
+
2102
2314
  function useModal() {
2103
2315
  const ref = useRef(null);
2104
2316
  const handleOpen = (props) => {
@@ -2847,11 +3059,33 @@ function InputContainer(props) {
2847
3059
 
2848
3060
  const Number$1 = (props) => {
2849
3061
  const { ref, label, name, value = "", labelInline, step = 1, min = -Infinity, max = Infinity, thousand, precision, type, className, width, status = "normal", append, border, prepend, disabled, message, tip, hideControl, showMax, style, onChange, onEnter, onInput, onBlur, ...restProps } = props;
2850
- const state = useReactive({
2851
- value,
2852
- });
2853
- const getRangeNumber = (v) => clamp(v, min, max);
2854
- const getFormatNumber = (v) => formatNumber(v, { precision, thousand });
3062
+ const [inputValue, setInputValue] = useState(value === undefined || value === null ? "" : String(value));
3063
+ const formatOut = (num) => {
3064
+ const v = clamp(num, min, max);
3065
+ if (precision !== undefined)
3066
+ return formatNumber(v, { precision, thousand });
3067
+ const s = String(v);
3068
+ if (!thousand)
3069
+ return s;
3070
+ const negative = s.startsWith("-");
3071
+ const body = negative ? s.slice(1) : s;
3072
+ const [integer, decimal] = body.split(".");
3073
+ const withThousand = integer.replace(/\B(?=(\d{3})+(?!\d))/g, thousand);
3074
+ return decimal
3075
+ ? `${negative ? "-" : ""}${withThousand}.${decimal}`
3076
+ : `${negative ? "-" : ""}${withThousand}`;
3077
+ };
3078
+ const sanitizeNumberInput = (raw) => {
3079
+ const hasMinus = raw.startsWith("-");
3080
+ let v = raw.replace(/[^\d.]/g, "");
3081
+ if (hasMinus)
3082
+ v = `-${v}`;
3083
+ const parts = v.split(".");
3084
+ if (parts.length > 1) {
3085
+ v = `${parts.shift()}.${parts.join("")}`;
3086
+ }
3087
+ return v;
3088
+ };
2855
3089
  const formatInputValue = (v) => {
2856
3090
  if (!v)
2857
3091
  return "";
@@ -2863,32 +3097,57 @@ const Number$1 = (props) => {
2863
3097
  };
2864
3098
  const handleChange = (e) => {
2865
3099
  const { value } = e.target;
2866
- const v = formatInputValue(value.replace(/[^\d\.-]/g, "")); // 保留负号和小数点
2867
- const numValue = clamp(+v, min, max); // 确保值在范围内
2868
- state.value = getFormatNumber(numValue); // 修复 thousand 格式化
2869
- onChange?.(numValue, e);
3100
+ const v = sanitizeNumberInput(formatInputValue(value));
3101
+ const isIntermediate = v === "" || v === "-" || v === "." || v === "-." || v.endsWith(".");
3102
+ setInputValue(v);
3103
+ if (isIntermediate)
3104
+ return;
3105
+ const num = parseFloat(v);
3106
+ if (globalThis.Number.isNaN(num))
3107
+ return;
3108
+ onChange?.(clamp(num, min, max), e);
3109
+ if (precision !== undefined)
3110
+ setInputValue(formatOut(num));
2870
3111
  };
2871
3112
  const handleOperate = (param) => {
2872
- const value = parseFloat(formatInputValue(state.value)) || 0; // 确保值为数字,默认值为 0
2873
- const result = getRangeNumber(value + param);
2874
- state.value = getFormatNumber(result);
2875
- onChange?.(result);
3113
+ const value = parseFloat(formatInputValue(inputValue)) || 0; // 确保值为数字,默认值为 0
3114
+ const result = value + param;
3115
+ setInputValue(formatOut(result));
3116
+ onChange?.(clamp(result, min, max));
2876
3117
  };
2877
3118
  const handleMax = () => {
2878
- const result = getRangeNumber(max);
2879
- state.value = getFormatNumber(result);
2880
- onChange?.(result);
3119
+ setInputValue(formatOut(max));
3120
+ onChange?.(clamp(max, min, max));
3121
+ };
3122
+ const handleBlur = (e) => {
3123
+ onBlur?.(e);
3124
+ const v = sanitizeNumberInput(formatInputValue(inputValue));
3125
+ if (!v || v === "-" || v === "." || v === "-.") {
3126
+ setInputValue("");
3127
+ return;
3128
+ }
3129
+ const num = parseFloat(v);
3130
+ if (globalThis.Number.isNaN(num))
3131
+ return;
3132
+ const numValue = clamp(num, min, max);
3133
+ setInputValue(formatOut(numValue));
3134
+ onChange?.(numValue, e);
2881
3135
  };
2882
3136
  useEffect(() => {
2883
- state.value = value;
3137
+ setInputValue(value === undefined || value === null ? "" : String(value));
2884
3138
  }, [value]);
2885
3139
  const inputProps = {
2886
3140
  ref,
2887
3141
  name,
2888
3142
  disabled,
2889
- value: state.value,
3143
+ value: inputValue,
2890
3144
  className: "i-input i-input-number",
2891
3145
  onChange: handleChange,
3146
+ onKeyDown: (e) => {
3147
+ e.code === "Enter" && onEnter?.(e);
3148
+ },
3149
+ onInput,
3150
+ onBlur: handleBlur,
2892
3151
  ...restProps,
2893
3152
  };
2894
3153
  return (jsx(InputContainer, { label: label, labelInline: labelInline, className: className, style: { width, ...style }, tip: message ?? tip, status: status, children: jsxs("div", { className: classNames("i-input-item", {
@@ -2899,9 +3158,7 @@ const Number$1 = (props) => {
2899
3158
 
2900
3159
  const Range = (props) => {
2901
3160
  const { label, name, value, labelInline, min = -Infinity, max = Infinity, type, className, status = "normal", message, tip, append, prepend, step = 1, width, thousand, precision, hideControl, placeholder, border, autoSwitch, onChange, onBlur, style, ...restProps } = props;
2902
- const state = useReactive({
2903
- value,
2904
- });
3161
+ const [rangeValue, setRangeValue] = useState(value);
2905
3162
  const getRangeNumber = (v) => clamp(v, min, max);
2906
3163
  const getFormatNumber = (v) => formatNumber(v, { precision, thousand });
2907
3164
  const formatInputValue = (v) => {
@@ -2914,31 +3171,31 @@ const Range = (props) => {
2914
3171
  const handleChange = (e, i) => {
2915
3172
  const { value } = e.target;
2916
3173
  const v = formatInputValue(value.replace(/[^\d\.-]/g, ""));
2917
- const range = Array.isArray(state.value) ? state.value : [];
3174
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2918
3175
  range[i] = v;
2919
- state.value = range;
3176
+ setRangeValue(range);
2920
3177
  onChange?.(range, e);
2921
3178
  };
2922
3179
  const handleOperate = (e, param, i) => {
2923
3180
  e.preventDefault();
2924
3181
  e.stopPropagation();
2925
- const range = Array.isArray(state.value) ? state.value : [];
3182
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2926
3183
  const value = formatInputValue(range[i]) ?? 0;
2927
3184
  const result = getRangeNumber(+value + param);
2928
3185
  range[i] = getFormatNumber(result);
2929
- state.value = range;
3186
+ setRangeValue(range);
2930
3187
  onChange?.(range, e);
2931
3188
  };
2932
3189
  const handleSwitch = (e) => {
2933
3190
  e?.preventDefault();
2934
3191
  e?.stopPropagation();
2935
- const range = state.value ? state.value : [];
3192
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2936
3193
  [range[0], range[1]] = [range[1], range[0]];
2937
- state.value = range;
3194
+ setRangeValue(range);
2938
3195
  onChange?.(range);
2939
3196
  };
2940
3197
  useEffect(() => {
2941
- state.value = value;
3198
+ setRangeValue(value);
2942
3199
  }, [value]);
2943
3200
  const inputProps = {
2944
3201
  name,
@@ -2948,7 +3205,7 @@ const Range = (props) => {
2948
3205
  const handleBlur = () => {
2949
3206
  if (!autoSwitch)
2950
3207
  return;
2951
- const range = Array.isArray(state.value) ? state.value : [];
3208
+ const range = Array.isArray(rangeValue) ? rangeValue : [];
2952
3209
  if (range.length < 2)
2953
3210
  return;
2954
3211
  const [left, right] = range.map(Number);
@@ -2959,18 +3216,16 @@ const Range = (props) => {
2959
3216
  return (jsx(InputContainer, { label: label, labelInline: labelInline, className: className, style: { width, ...style }, tip: message ?? tip, status: status, children: jsxs("div", { className: classNames("i-input-item", {
2960
3217
  [`i-input-${status}`]: status !== "normal",
2961
3218
  "i-input-borderless": !border,
2962
- }), children: [prepend && jsx("div", { className: 'i-input-prepend', children: prepend }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(MinusRound, {}), onClick: (e) => handleOperate(e, -step, 0) })), jsx("input", { value: state.value?.[0] || "", placeholder: placeholder?.[0], ...inputProps, onBlur: handleBlur, onChange: (e) => handleChange(e, 0) }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(PlusRound, {}), onClick: (e) => handleOperate(e, step, 0) })), jsx(Helpericon, { active: true, icon: jsx(SyncAltRound, {}), style: { margin: 0 }, onClick: handleSwitch }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(MinusRound, {}), onClick: (e) => handleOperate(e, -step, 1) })), jsx("input", { value: state.value?.[1] || "", placeholder: placeholder?.[1], ...inputProps, onBlur: handleBlur, onChange: (e) => handleChange(e, 1) }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(PlusRound, {}), onClick: (e) => handleOperate(e, step, 1) })), append && jsx("div", { className: 'i-input-append', children: append })] }) }));
3219
+ }), children: [prepend && jsx("div", { className: 'i-input-prepend', children: prepend }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(MinusRound, {}), onClick: (e) => handleOperate(e, -step, 0) })), jsx("input", { value: rangeValue?.[0] || "", placeholder: placeholder?.[0], ...inputProps, onBlur: handleBlur, onChange: (e) => handleChange(e, 0) }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(PlusRound, {}), onClick: (e) => handleOperate(e, step, 0) })), jsx(Helpericon, { active: true, icon: jsx(SyncAltRound, {}), style: { margin: 0 }, onClick: handleSwitch }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(MinusRound, {}), onClick: (e) => handleOperate(e, -step, 1) })), jsx("input", { value: rangeValue?.[1] || "", placeholder: placeholder?.[1], ...inputProps, onBlur: handleBlur, onChange: (e) => handleChange(e, 1) }), !hideControl && (jsx(Helpericon, { active: true, icon: jsx(PlusRound, {}), onClick: (e) => handleOperate(e, step, 1) })), append && jsx("div", { className: 'i-input-append', children: append })] }) }));
2963
3220
  };
2964
3221
 
2965
3222
  const Textarea = (props) => {
2966
3223
  const { ref, label, name, value = "", labelInline, className, status = "normal", message, tip, autoSize, border, width, style, onChange, onEnter, ...restProps } = props;
2967
- const state = useReactive({
2968
- value,
2969
- });
3224
+ const [textareaValue, setTextareaValue] = useState(value);
2970
3225
  const refTextarea = useRef(null);
2971
3226
  const handleChange = (e) => {
2972
3227
  const v = e.target.value;
2973
- state.value = v;
3228
+ setTextareaValue(v);
2974
3229
  const ta = refTextarea.current;
2975
3230
  if (autoSize && ta) {
2976
3231
  ta.style.height = `${ta.scrollHeight}px`;
@@ -2984,7 +3239,7 @@ const Textarea = (props) => {
2984
3239
  onEnter?.(e);
2985
3240
  };
2986
3241
  useEffect(() => {
2987
- state.value = value;
3242
+ setTextareaValue(value);
2988
3243
  }, [value]);
2989
3244
  useImperativeHandle(ref, () => {
2990
3245
  return {
@@ -2994,7 +3249,7 @@ const Textarea = (props) => {
2994
3249
  const inputProps = {
2995
3250
  ref: refTextarea,
2996
3251
  name,
2997
- value: state.value,
3252
+ value: textareaValue,
2998
3253
  className: "i-input i-textarea",
2999
3254
  onChange: handleChange,
3000
3255
  onKeyDown: handleKeydown,
@@ -3008,14 +3263,12 @@ const Textarea = (props) => {
3008
3263
 
3009
3264
  const Input = ((props) => {
3010
3265
  const { ref, type = "text", label, name, value = "", prepend, append, labelInline, className, status = "normal", message, tip, clear, width, hideVisible, border, underline, required, maxLength, onChange, onEnter, onClear, style, ...restProps } = props;
3011
- const state = useReactive({
3012
- value,
3013
- type,
3014
- visible: false,
3015
- });
3266
+ const [inputValue, setInputValue] = useState(value);
3267
+ const [inputType, setInputType] = useState(type);
3268
+ const [visible, setVisible] = useState(false);
3016
3269
  const handleChange = (e) => {
3017
3270
  const v = e.target.value;
3018
- state.value = v;
3271
+ setInputValue(v);
3019
3272
  onChange?.(v, e);
3020
3273
  };
3021
3274
  const handleKeydown = (e) => {
@@ -3023,43 +3276,49 @@ const Input = ((props) => {
3023
3276
  };
3024
3277
  const handleHelperClick = () => {
3025
3278
  if (type === "password" && !hideVisible) {
3026
- Object.assign(state, {
3027
- visible: !state.visible,
3028
- type: !state.visible ? "text" : "password",
3279
+ setVisible((v) => {
3280
+ const next = !v;
3281
+ setInputType(next ? "text" : "password");
3282
+ return next;
3029
3283
  });
3030
3284
  return;
3031
3285
  }
3032
3286
  const v = "";
3287
+ setInputValue(v);
3033
3288
  onChange?.(v);
3034
3289
  onClear?.();
3035
3290
  };
3036
3291
  const HelperIcon = useMemo(() => {
3037
3292
  if (type === "password") {
3038
- return state.visible ? jsx(VisibilityRound, {}) : jsx(VisibilityOffRound, {});
3293
+ return visible ? jsx(VisibilityRound, {}) : jsx(VisibilityOffRound, {});
3039
3294
  }
3040
3295
  return undefined;
3041
- }, [state.visible]);
3296
+ }, [type, visible]);
3042
3297
  useEffect(() => {
3043
- state.value = value;
3298
+ setInputValue(value);
3044
3299
  }, [value]);
3045
3300
  const inputProps = {
3046
3301
  ref,
3047
- type: state.type,
3302
+ type: inputType,
3048
3303
  name,
3049
- value: state.value,
3304
+ value: inputValue,
3050
3305
  maxLength,
3051
3306
  className: classNames("i-input", `i-input-${type}`),
3052
3307
  onChange: handleChange,
3053
3308
  onKeyDown: handleKeydown,
3054
3309
  ...restProps,
3055
3310
  };
3056
- const clearable = clear && state.value;
3057
- const showHelper = type === "password" && !!state.value;
3311
+ useEffect(() => {
3312
+ setInputType(type);
3313
+ setVisible(false);
3314
+ }, [type]);
3315
+ const clearable = clear && inputValue;
3316
+ const showHelper = type === "password" && !!inputValue;
3058
3317
  return (jsx(InputContainer, { label: label, labelInline: labelInline, className: className, style: { width, ...style }, tip: message ?? tip, status: status, required: required, children: jsxs("div", { className: classNames("i-input-item", {
3059
3318
  [`i-input-${status}`]: status !== "normal",
3060
3319
  "i-input-borderless": !border,
3061
3320
  "i-input-underline": underline,
3062
- }), children: [prepend && jsx("div", { className: 'i-input-prepend', children: prepend }), jsx("input", { ...inputProps }), maxLength && state.value?.length > 0 && (jsxs("span", { className: 'color-8 pr-4 font-sm', children: [state.value.length, " / ", maxLength] })), jsx(Helpericon, { active: !!clearable || showHelper, icon: HelperIcon, onClick: handleHelperClick }), append && jsx("div", { className: 'i-input-append', children: append })] }) }));
3321
+ }), children: [prepend && jsx("div", { className: 'i-input-prepend', children: prepend }), jsx("input", { ...inputProps }), maxLength && inputValue?.length > 0 && (jsxs("span", { className: 'color-8 pr-4 font-sm', children: [inputValue.length, " / ", maxLength] })), jsx(Helpericon, { active: !!clearable || showHelper, icon: HelperIcon, onClick: handleHelperClick }), append && jsx("div", { className: 'i-input-append', children: append })] }) }));
3063
3322
  });
3064
3323
  Input.Textarea = Textarea;
3065
3324
  Input.Number = Number$1;
@@ -3347,38 +3606,34 @@ const displayValue = (config) => {
3347
3606
 
3348
3607
  const Select = (props) => {
3349
3608
  const { ref, type = "text", name, label, value = "", placeholder, options = [], multiple, prepend, append, labelInline, style, className, message, status = "normal", hideClear, hideArrow, maxDisplay, border, filter, tip, filterPlaceholder = "...", popupProps, onSelect, onChange, ...restProps } = props;
3350
- const state = useReactive({
3351
- inputValue: "",
3352
- filterValue: "",
3353
- value,
3354
- loading: false,
3355
- });
3609
+ const [filterValue, setFilterValue] = useState("");
3610
+ const [selectedValue, setSelectedValue] = useState(value);
3356
3611
  const [active, setActive] = useState(false);
3357
3612
  const formattedOptions = useMemo(() => formatOption(options), [options]);
3358
3613
  const filterOptions = useMemo(() => {
3359
- const { filterValue: fv } = state;
3614
+ const fv = filterValue;
3360
3615
  if (!fv || !filter)
3361
3616
  return formattedOptions;
3362
3617
  const filterFn = typeof filter === "function"
3363
3618
  ? filter
3364
3619
  : (opt) => opt.value.includes(fv) || opt.label.includes(fv);
3365
3620
  return formattedOptions.filter(filterFn);
3366
- }, [formattedOptions, filter, state.filterValue]);
3621
+ }, [formattedOptions, filter, filterValue]);
3367
3622
  const changeValue = (v) => {
3368
- state.value = v;
3623
+ setSelectedValue(v);
3369
3624
  onChange?.(v);
3370
3625
  };
3371
3626
  const displayLabel = useMemo(() => {
3372
3627
  if (multiple) {
3373
3628
  return "";
3374
3629
  }
3375
- const option = formattedOptions.find((opt) => opt.value === state.value);
3376
- return option ? option.label : state.value;
3377
- }, [state.value, formattedOptions]);
3630
+ const option = formattedOptions.find((opt) => opt.value === selectedValue);
3631
+ return option ? option.label : selectedValue;
3632
+ }, [selectedValue, formattedOptions]);
3378
3633
  const handleSelect = (value, option) => {
3379
3634
  onSelect?.(value, option);
3380
3635
  if (multiple) {
3381
- const values = [...state.value];
3636
+ const values = [...selectedValue];
3382
3637
  const i = values.findIndex((v) => v === value);
3383
3638
  i > -1 ? values.splice(i, 1) : values.push(value);
3384
3639
  changeValue(values);
@@ -3391,7 +3646,7 @@ const Select = (props) => {
3391
3646
  setActive(visible);
3392
3647
  if (!filter)
3393
3648
  return;
3394
- state.filterValue = "";
3649
+ setFilterValue("");
3395
3650
  };
3396
3651
  const handleHelperClick = (e) => {
3397
3652
  e.stopPropagation();
@@ -3402,34 +3657,34 @@ const Select = (props) => {
3402
3657
  };
3403
3658
  const handleFilterChange = debounce({ delay: 400 }, (e) => {
3404
3659
  const v = e.target.value;
3405
- state.filterValue = v;
3660
+ setFilterValue(v);
3406
3661
  });
3407
3662
  const handleInputChange = (e) => {
3408
- state.filterValue = e.target.value;
3663
+ setFilterValue(e.target.value);
3409
3664
  };
3410
3665
  useEffect(() => {
3411
- state.value = value;
3666
+ setSelectedValue(value);
3412
3667
  }, [value]);
3413
3668
  const hasValue = multiple
3414
- ? state.value.length > 0
3415
- : !!state.value;
3669
+ ? selectedValue.length > 0
3670
+ : !!selectedValue;
3416
3671
  const clearable = !hideClear && active && hasValue;
3417
3672
  const text = message ?? tip;
3418
3673
  return (jsxs("label", { className: classNames("i-input-label", className, {
3419
3674
  "i-input-inline": labelInline,
3420
- }), style: style, children: [label && jsx("span", { className: 'i-input-label-text', children: label }), jsx(Popup, { position: 'bottom', arrow: false, fitSize: true, offset: 0, ...popupProps, visible: active, trigger: 'none', onVisibleChange: handleVisibleChange, content: jsx(Options, { options: filterOptions, value: state.value, multiple: multiple, filter: !!filter, filterPlaceholder: filterPlaceholder, onSelect: handleSelect, onFilter: handleFilterChange }), children: jsxs("div", { className: classNames("i-input-item", {
3675
+ }), style: style, children: [label && jsx("span", { className: 'i-input-label-text', children: label }), jsx(Popup, { position: 'bottom', arrow: false, fitSize: true, offset: 0, ...popupProps, visible: active, trigger: 'none', onVisibleChange: handleVisibleChange, content: jsx(Options, { options: filterOptions, value: selectedValue, multiple: multiple, filter: !!filter, filterPlaceholder: filterPlaceholder, onSelect: handleSelect, onFilter: handleFilterChange }), children: jsxs("div", { className: classNames("i-input-item", {
3421
3676
  [`i-input-${status}`]: status !== "normal",
3422
3677
  "i-input-borderless": !border,
3423
3678
  "i-input-focus": active,
3424
- }), onClick: () => setActive(true), children: [prepend, jsx("input", { ref: ref, type: 'hidden', value: state.value, ...restProps }), multiple ? (hasValue ? (jsx("div", { className: classNames("i-input i-select", {
3679
+ }), onClick: () => setActive(true), children: [prepend, jsx("input", { ref: ref, type: 'hidden', value: selectedValue, ...restProps }), multiple ? (hasValue ? (jsx("div", { className: classNames("i-input i-select", {
3425
3680
  "i-select-multiple": multiple,
3426
3681
  }), children: displayValue({
3427
3682
  options: formattedOptions,
3428
- value: state.value,
3683
+ value: selectedValue,
3429
3684
  multiple,
3430
3685
  maxDisplay,
3431
3686
  onSelect: handleSelect,
3432
- }) })) : (jsx("input", { className: 'i-input i-select', placeholder: placeholder, readOnly: true }))) : null, !multiple && (jsx("input", { value: active ? state.filterValue : displayLabel, className: 'i-input i-select', placeholder: displayLabel || placeholder, onChange: handleInputChange, readOnly: !filter })), jsx(Helpericon, { active: !hideArrow, icon: clearable ? undefined : jsx(UnfoldMoreRound, {}), onClick: handleHelperClick }), append] }) }), text && jsx("span", { className: 'i-input-message', children: text })] }));
3687
+ }) })) : (jsx("input", { className: 'i-input i-select', placeholder: placeholder, readOnly: true }))) : null, !multiple && (jsx("input", { value: active ? filterValue : displayLabel, className: 'i-input i-select', placeholder: displayLabel || placeholder, onChange: handleInputChange, readOnly: !filter })), jsx(Helpericon, { active: !hideArrow, icon: clearable ? undefined : jsx(UnfoldMoreRound, {}), onClick: handleHelperClick }), append] }) }), text && jsx("span", { className: 'i-input-message', children: text })] }));
3433
3688
  };
3434
3689
 
3435
3690
  const ColorMethods = {
@@ -3439,23 +3694,21 @@ const ColorMethods = {
3439
3694
  };
3440
3695
  function Footer(props) {
3441
3696
  const { value, type, onTypeChange, onChange, onOk } = props;
3442
- const state = useReactive({
3443
- value,
3444
- type,
3445
- });
3697
+ const [inputValue, setInputValue] = useState(value);
3698
+ const [colorType, setColorType] = useState(type);
3446
3699
  const handleChange = (v) => {
3447
- state.value = v;
3700
+ setInputValue(v);
3448
3701
  onChange(v);
3449
3702
  };
3450
3703
  const handleTypeChange = (t) => {
3451
- state.type = t;
3704
+ setColorType(t);
3452
3705
  onTypeChange(t);
3453
3706
  };
3454
3707
  useEffect(() => {
3455
- state.value = value;
3456
- state.type = type;
3708
+ setInputValue(value);
3709
+ setColorType(type);
3457
3710
  }, [value, type]);
3458
- return (jsxs("div", { className: 'i-colorpicker-footer', children: [jsx(Select, { readOnly: true, hideClear: true, hideArrow: true, style: { width: "5.6em" }, options: ["RGB", "HEX", "HSB"], value: state.type, onChange: handleTypeChange }), jsx(Input, { placeholder: 'color', value: state.value, onChange: handleChange }), jsx(Button, { square: true, onClick: onOk, children: jsx(Icon, { icon: jsx(CheckRound, {}) }) })] }));
3711
+ return (jsxs("div", { className: 'i-colorpicker-footer', children: [jsx(Select, { readOnly: true, hideClear: true, hideArrow: true, style: { width: "5.6em" }, options: ["RGB", "HEX", "HSB"], value: colorType, onChange: handleTypeChange }), jsx(Input, { placeholder: 'color', value: inputValue, onChange: handleChange }), jsx(Button, { square: true, onClick: onOk, children: jsx(Icon, { icon: jsx(CheckRound, {}) }) })] }));
3459
3712
  }
3460
3713
 
3461
3714
  const Handle = (props) => {
@@ -3465,48 +3718,51 @@ const Handle = (props) => {
3465
3718
 
3466
3719
  function ColorPicker(props) {
3467
3720
  const { value, type = "HEX", disabledAlpha, children, usePanel, handle = "both", placeholder = "Colors", popupProps, onChange, } = props;
3468
- const state = useReactive({
3469
- type,
3470
- value,
3471
- syncValue: value,
3472
- visible: popupProps?.visible,
3473
- });
3721
+ const [colorType, setColorType] = useState(type);
3722
+ const [colorValue, setColorValue] = useState(value);
3723
+ const [syncValue, setSyncValue] = useState(value);
3724
+ const [visible, setVisible] = useState(popupProps?.visible);
3474
3725
  const handleChange = (target) => {
3475
- state.syncValue = target;
3726
+ setSyncValue(target);
3476
3727
  };
3477
3728
  const handleComplete = (target) => {
3478
- const method = ColorMethods[state.type];
3729
+ const method = ColorMethods[colorType];
3479
3730
  if (target.a !== 1) {
3480
3731
  target.a = parseFloat(target.a.toFixed(3));
3481
3732
  }
3482
- state.value = target[method]?.();
3733
+ setColorValue(target[method]?.());
3483
3734
  };
3484
3735
  const handleVisibleChange = (v) => {
3485
- state.visible = v;
3736
+ setVisible(v);
3486
3737
  popupProps?.onVisibleChange?.(v);
3487
3738
  };
3488
3739
  const handleTypeChange = (t) => {
3489
3740
  const method = ColorMethods[t];
3490
- state.type = t;
3491
- state.value = state.syncValue[method]?.();
3741
+ setColorType(t);
3742
+ setColorValue(syncValue?.[method]?.());
3492
3743
  };
3493
3744
  const handleValueChange = (v) => {
3494
- state.value = v;
3495
- state.syncValue = v;
3745
+ setColorValue(v);
3746
+ setSyncValue(v);
3496
3747
  };
3497
3748
  const handleOk = () => {
3498
- onChange?.(state.value);
3499
- state.visible = false;
3749
+ onChange?.(colorValue);
3750
+ setVisible(false);
3500
3751
  };
3501
3752
  useEffect(() => {
3502
- state.syncValue = value;
3503
- state.value = value;
3753
+ setSyncValue(value);
3754
+ setColorValue(value);
3504
3755
  }, [value]);
3756
+ useEffect(() => {
3757
+ if (popupProps?.visible !== undefined) {
3758
+ setVisible(popupProps.visible);
3759
+ }
3760
+ }, [popupProps?.visible]);
3505
3761
  if (usePanel) {
3506
3762
  return jsx(ColorsPanel, { ...props });
3507
3763
  }
3508
- return (jsx(Popup, { trigger: 'click', touchable: true, position: 'bottom', ...popupProps, visible: state.visible, content: jsx(ColorsPanel, { value: state.syncValue, disabledAlpha: disabledAlpha, panelRender: (panel) => {
3509
- return (jsxs(Fragment, { children: [panel, jsx(Footer, { value: state.value, type: state.type, onTypeChange: handleTypeChange, onChange: handleValueChange, onOk: handleOk })] }));
3764
+ return (jsx(Popup, { trigger: 'click', touchable: true, position: 'bottom', ...popupProps, visible: visible, content: jsx(ColorsPanel, { value: syncValue, disabledAlpha: disabledAlpha, panelRender: (panel) => {
3765
+ return (jsxs(Fragment, { children: [panel, jsx(Footer, { value: colorValue, type: colorType, onTypeChange: handleTypeChange, onChange: handleValueChange, onOk: handleOk })] }));
3510
3766
  }, onChange: handleChange, onChangeComplete: handleComplete }), onVisibleChange: handleVisibleChange, children: children ?? (jsx(Handle, { color: value, handle: handle, placeholder: placeholder })) }));
3511
3767
  }
3512
3768
 
@@ -3556,61 +3812,56 @@ const YearMonth = (props) => {
3556
3812
  };
3557
3813
  const Panel$1 = (props) => {
3558
3814
  const { value, unitYear, unitMonth, renderDate, renderMonth = (m) => m, renderYear = (y) => y, disabledDate, onDateClick, } = props;
3559
- const state = useReactive({
3560
- today: value,
3561
- month: value || dayjs(),
3562
- selectedYear: dayjs(),
3563
- years: [],
3564
- selectable: false,
3565
- });
3815
+ const [today, setToday] = useState(value);
3816
+ const [month, setMonth] = useState(value || dayjs());
3817
+ const [selectedYear, setSelectedYear] = useState(dayjs());
3818
+ const [years, setYears] = useState([]);
3819
+ const [selectable, setSelectable] = useState(false);
3566
3820
  const $years = useRef(null);
3567
3821
  const handleOperateMonth = (next) => {
3568
- state.month = state.month[next ? "add" : "subtract"](1, "month");
3822
+ setMonth((m) => m[next ? "add" : "subtract"](1, "month"));
3569
3823
  };
3570
3824
  const handleChangeDate = (date) => {
3571
- if (date.isSame(state.today, "day"))
3825
+ if (date.isSame(today, "day"))
3572
3826
  return;
3573
- if (!date.isSame(state.month, "month")) {
3574
- state.month = date;
3827
+ if (!date.isSame(month, "month")) {
3828
+ setMonth(date);
3575
3829
  }
3576
- state.today = date;
3830
+ setToday(date);
3577
3831
  onDateClick?.(date);
3578
3832
  };
3579
3833
  const handleChangeMonth = (month) => {
3580
- state.month = state.month
3581
- .year(state.selectedYear.year())
3582
- .month(month - 1);
3583
- state.selectable = false;
3834
+ setMonth((m) => m.year(selectedYear.year()).month(month - 1));
3835
+ setSelectable(false);
3584
3836
  };
3585
3837
  const getMoreYears = throttle({ interval: 100 }, (e) => {
3586
3838
  const isUp = e.deltaY < 0;
3587
- state.years = state.years.map((y) => (y += isUp ? -1 : 1));
3839
+ setYears((ys) => ys.map((y) => y + (isUp ? -1 : 1)));
3588
3840
  });
3589
3841
  useEffect(() => {
3590
- if (!state.selectable)
3842
+ if (!selectable)
3591
3843
  return;
3592
- state.selectedYear = state.month;
3593
- const y = state.selectedYear.year();
3594
- const years = Array.from({ length: 7 }).map((_, i) => y - 3 + i);
3595
- state.years = [...years];
3596
- }, [state.selectable]);
3844
+ setSelectedYear(month);
3845
+ const y = month.year();
3846
+ const nextYears = Array.from({ length: 7 }).map((_, i) => y - 3 + i);
3847
+ setYears([...nextYears]);
3848
+ }, [selectable, month]);
3597
3849
  useEffect(() => {
3598
- state.today = value;
3599
- state.month = value || dayjs();
3850
+ setToday(value);
3851
+ setMonth(value || dayjs());
3600
3852
  }, [value]);
3601
- return (jsxs("div", { className: 'i-datepicker', children: [jsxs("div", { className: 'i-datepicker-units', children: [jsx(YearMonth, { value: state.month, unitYear: unitYear, unitMonth: unitMonth, renderMonth: renderMonth, renderYear: renderYear, onClick: () => (state.selectable = true) }), jsx("a", { className: 'ml-auto i-datepicker-action', "data-ripple": true, onClick: () => handleOperateMonth(false), children: jsx(Icon, { icon: jsx(KeyboardArrowLeftRound, {}) }) }), jsx("a", { className: 'i-datepicker-action', "data-ripple": true, onClick: () => handleOperateMonth(true), children: jsx(Icon, { icon: jsx(KeyboardArrowRightRound, {}) }) })] }), jsxs("div", { className: classNames("i-datepicker-ym", {
3602
- "i-datepicker-active": state.selectable,
3853
+ return (jsxs("div", { className: 'i-datepicker', children: [jsxs("div", { className: 'i-datepicker-units', children: [jsx(YearMonth, { value: month, unitYear: unitYear, unitMonth: unitMonth, renderMonth: renderMonth, renderYear: renderYear, onClick: () => setSelectable(true) }), jsx("a", { className: 'ml-auto i-datepicker-action', "data-ripple": true, onClick: () => handleOperateMonth(false), children: jsx(Icon, { icon: jsx(KeyboardArrowLeftRound, {}) }) }), jsx("a", { className: 'i-datepicker-action', "data-ripple": true, onClick: () => handleOperateMonth(true), children: jsx(Icon, { icon: jsx(KeyboardArrowRightRound, {}) }) })] }), jsxs("div", { className: classNames("i-datepicker-ym", {
3854
+ "i-datepicker-active": selectable,
3603
3855
  }), children: [jsx(Helpericon, { active: true, className: 'i-datepicker-close', onClick: (e) => {
3604
3856
  e.stopPropagation();
3605
- state.selectable = false;
3606
- } }), jsx("div", { ref: $years, className: 'i-datepicker-years', onWheel: getMoreYears, children: state.years.map((y) => (jsx("a", { className: classNames("i-datepicker-year", {
3607
- "i-datepicker-active": y === state.selectedYear.year(),
3608
- }), onClick: () => (state.selectedYear =
3609
- state.selectedYear.year(y)), children: renderYear(y) }, y))) }), jsx("div", { className: 'i-datepicker-months', children: MONTHS.map((m) => {
3857
+ setSelectable(false);
3858
+ } }), jsx("div", { ref: $years, className: 'i-datepicker-years', onWheel: getMoreYears, children: years.map((y) => (jsx("a", { className: classNames("i-datepicker-year", {
3859
+ "i-datepicker-active": y === selectedYear.year(),
3860
+ }), onClick: () => setSelectedYear((sy) => sy.year(y)), children: renderYear(y) }, y))) }), jsx("div", { className: 'i-datepicker-months', children: MONTHS.map((m) => {
3610
3861
  return (jsx("a", { className: classNames("i-datepicker-month", {
3611
- "i-datepicker-active": m === state.month.month() + 1,
3862
+ "i-datepicker-active": m === month.month() + 1,
3612
3863
  }), onClick: () => handleChangeMonth(m), children: renderMonth(m) }, m));
3613
- }) })] }), jsx(Dates, { value: state.today, month: state.month, disabledDate: disabledDate, onDateClick: handleChangeDate, renderDate: renderDate })] }));
3864
+ }) })] }), jsx(Dates, { value: today, month: month, disabledDate: disabledDate, onDateClick: handleChangeDate, renderDate: renderDate })] }));
3614
3865
  };
3615
3866
 
3616
3867
  dayjs.extend(customParseFormat);
@@ -3618,29 +3869,27 @@ const FORMATTYPES = ["YYYY-MM-DD", "YYYY-M-D", "YYYY/MM/DD", "YYYY/M/D"];
3618
3869
  const FORMAT$1 = "YYYY-MM-DD";
3619
3870
  const Datepicker = (props) => {
3620
3871
  const { name, value, weeks, format = FORMAT$1, placeholder = props.format ?? FORMAT$1, className, renderDate, renderMonth, renderYear, popupProps, disabledDate, onDateClick, onChange, onBlur, ...restProps } = props;
3621
- const state = useReactive({
3622
- value,
3623
- });
3872
+ const [inputValue, setInputValue] = useState(value);
3624
3873
  const [active, setActive] = useState(false);
3625
3874
  const dayJsValue = useMemo(() => {
3626
- if (!state.value)
3875
+ if (!inputValue)
3627
3876
  return null;
3628
- const date = dayjs(state.value, format, true);
3877
+ const date = dayjs(inputValue, format, true);
3629
3878
  if (date.isValid())
3630
3879
  return date;
3631
3880
  return null;
3632
- }, [state.value]);
3881
+ }, [inputValue, format]);
3633
3882
  const handleDateClick = (date) => {
3634
3883
  handleChange(date.format(format));
3635
3884
  };
3636
3885
  const handleChange = (v) => {
3637
- state.value = v;
3886
+ setInputValue(v);
3638
3887
  onChange?.(v);
3639
3888
  };
3640
3889
  const handleSetDate = () => {
3641
- if (!state.value)
3890
+ if (!inputValue)
3642
3891
  return;
3643
- const date = dayjs(state.value, FORMATTYPES, true);
3892
+ const date = dayjs(inputValue, FORMATTYPES, true);
3644
3893
  if (date.isValid()) {
3645
3894
  handleChange(date.format(format));
3646
3895
  return;
@@ -3656,9 +3905,9 @@ const Datepicker = (props) => {
3656
3905
  setActive(v);
3657
3906
  };
3658
3907
  useEffect(() => {
3659
- state.value = value;
3908
+ setInputValue(value);
3660
3909
  }, [value]);
3661
- return (jsx(Popup, { visible: active, trigger: 'click', position: 'bottom', arrow: false, align: 'start', onVisibleChange: handleVisibleChange, watchResize: true, content: jsx(Panel$1, { value: dayJsValue, weeks: weeks, renderDate: renderDate, renderMonth: renderMonth, renderYear: renderYear, disabledDate: disabledDate, onDateClick: handleDateClick }), ...popupProps, children: jsx(Input, { value: state.value, append: jsx(Icon, { icon: jsx(CalendarMonthTwotone, {}), className: 'i-datepicker-icon', size: '1em' }), placeholder: placeholder, onChange: handleChange, onBlur: handleBlur, onEnter: handleSetDate, className: classNames("i-datepicker-label", className), ...restProps }) }));
3910
+ return (jsx(Popup, { visible: active, trigger: 'click', position: 'bottom', arrow: false, align: 'start', onVisibleChange: handleVisibleChange, content: jsx(Panel$1, { value: dayJsValue, weeks: weeks, renderDate: renderDate, renderMonth: renderMonth, renderYear: renderYear, disabledDate: disabledDate, onDateClick: handleDateClick }), ...popupProps, children: jsx(Input, { value: inputValue, append: jsx(Icon, { icon: jsx(CalendarMonthTwotone, {}), className: 'i-datepicker-icon', size: '1em' }), placeholder: placeholder, onChange: handleChange, onBlur: handleBlur, onEnter: handleSetDate, className: classNames("i-datepicker-label", className), ...restProps }) }));
3662
3911
  };
3663
3912
 
3664
3913
  function Items(props) {
@@ -3681,12 +3930,10 @@ const UnitMaps = {
3681
3930
  };
3682
3931
  function Panel(props) {
3683
3932
  const { value, stepH = 1, stepM = 1, stepS = 1, format, periods, renderItem, onChange, onFallback, } = props;
3684
- const state = useReactive({
3685
- period: undefined,
3686
- hour: undefined,
3687
- minute: undefined,
3688
- second: undefined,
3689
- });
3933
+ const [period, setPeriod] = useState(undefined);
3934
+ const [hour, setHour] = useState(undefined);
3935
+ const [minute, setMinute] = useState(undefined);
3936
+ const [second, setSecond] = useState(undefined);
3690
3937
  const [hours, minutes, seconds] = useMemo(() => {
3691
3938
  const hasH = format.includes("h");
3692
3939
  const hasM = format.includes("m");
@@ -3702,29 +3949,45 @@ function Panel(props) {
3702
3949
  : [];
3703
3950
  return [hours, minutes, seconds];
3704
3951
  }, [stepH, stepM, stepS, format, periods]);
3705
- const updateValue = () => {
3952
+ const updateValue = (next) => {
3953
+ const nextPeriod = next?.period ?? period;
3954
+ const nextHour = next?.hour ?? hour;
3955
+ const nextMinute = next?.minute ?? minute;
3956
+ const nextSecond = next?.second ?? second;
3706
3957
  const reg = /(hh|h){1}|(mm|m){1}|(ss|s){1}/gi;
3707
3958
  let result = format.replace(reg, (pattern) => {
3708
3959
  const p = pattern.toLowerCase();
3709
3960
  const u = UnitMaps[p];
3710
- const n = state[u] ?? 0;
3961
+ const n = u === "hour"
3962
+ ? (nextHour ?? 0)
3963
+ : u === "minute"
3964
+ ? (nextMinute ?? 0)
3965
+ : (nextSecond ?? 0);
3711
3966
  return p.length > 1 && n < 10 ? `0${n ?? 0}` : n ?? 0;
3712
3967
  });
3713
3968
  if (periods && hours.length > 0) {
3714
- result = `${state.period ?? periods[0]} ${result}`;
3969
+ result = `${nextPeriod ?? periods[0]} ${result}`;
3715
3970
  }
3716
3971
  onChange(result);
3717
3972
  };
3718
3973
  const handleSetTime = (v, unit) => {
3719
- state[unit] = v;
3720
- updateValue();
3974
+ const next = { period, hour, minute, second, [unit]: v };
3975
+ if (unit === "period")
3976
+ setPeriod(v);
3977
+ if (unit === "hour")
3978
+ setHour(v);
3979
+ if (unit === "minute")
3980
+ setMinute(v);
3981
+ if (unit === "second")
3982
+ setSecond(v);
3983
+ updateValue(next);
3721
3984
  };
3722
3985
  useEffect(() => {
3723
3986
  let time = value ?? "";
3724
3987
  if (periods && hours.length > 0 && value) {
3725
3988
  const [p, t] = value.split(" ");
3726
3989
  time = t ?? "";
3727
- state.period = periods.includes(p) ? p : undefined;
3990
+ setPeriod(periods.includes(p) ? p : undefined);
3728
3991
  }
3729
3992
  const nums = time.match(/\d+/g) ?? [];
3730
3993
  if (!nums.length) {
@@ -3732,40 +3995,41 @@ function Panel(props) {
3732
3995
  return;
3733
3996
  }
3734
3997
  let i = 0;
3998
+ const parsed = {
3999
+ hour: undefined,
4000
+ minute: undefined,
4001
+ second: undefined,
4002
+ };
3735
4003
  const r = format.replace(/(hh|h)+|(mm|m)+|(ss|s)+/gi, (p) => {
3736
4004
  const n = nums[i++] ?? 0;
3737
- let o = p;
3738
- if (UnitMaps[p] === "hour") {
3739
- o = Math.min(periods ? 11 : 23, n);
3740
- }
3741
- o = Math.min(59, n);
3742
- state[UnitMaps[p]] = o;
4005
+ const o = Math.min(59, n);
4006
+ parsed[UnitMaps[p]] = o;
3743
4007
  return p.length > 1 && o < 10 ? `0${o}` : o;
3744
4008
  });
4009
+ setHour(parsed.hour);
4010
+ setMinute(parsed.minute);
4011
+ setSecond(parsed.second);
3745
4012
  onFallback(r);
3746
- }, [value]);
3747
- return (jsxs("div", { className: 'i-timepicker', children: [hours.length > 0 && (jsxs(Fragment, { children: [periods && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: periods, active: state.period, onClick: (p) => handleSetTime(p, "period") }) })), jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: hours, active: state.hour, unit: 'hour', renderItem: renderItem, onClick: (h) => handleSetTime(h, "hour") }) })] })), minutes.length > 0 && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: minutes, active: state.minute, unit: 'minute', renderItem: renderItem, onClick: (m) => handleSetTime(m, "minute") }) })), seconds.length > 0 && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: seconds, active: state.second, unit: 'second', renderItem: renderItem, onClick: (s) => handleSetTime(s, "second") }) }))] }));
4013
+ }, [value, format, hours.length, periods]);
4014
+ return (jsxs("div", { className: 'i-timepicker', children: [hours.length > 0 && (jsxs(Fragment, { children: [periods && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: periods, active: period, onClick: (p) => handleSetTime(p, "period") }) })), jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: hours, active: hour, unit: 'hour', renderItem: renderItem, onClick: (h) => handleSetTime(h, "hour") }) })] })), minutes.length > 0 && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: minutes, active: minute, unit: 'minute', renderItem: renderItem, onClick: (m) => handleSetTime(m, "minute") }) })), seconds.length > 0 && (jsx("div", { className: 'i-timepicker-list', children: jsx(Items, { items: seconds, active: second, unit: 'second', renderItem: renderItem, onClick: (s) => handleSetTime(s, "second") }) }))] }));
3748
4015
  }
3749
4016
 
3750
4017
  const FORMAT = "hh:mm:ss";
3751
4018
  function TimePicker(props) {
3752
4019
  const { name, value, format = FORMAT, periods, placeholder = props.format ?? FORMAT, className, renderItem, onChange, onBlur, popupProps, ...restProps } = props;
3753
- const state = useReactive({
3754
- value,
3755
- safeValue: undefined,
3756
- });
4020
+ const [timeValue, setTimeValue] = useState(value);
4021
+ const [safeValue, setSafeValue] = useState(undefined);
3757
4022
  const [active, setActive] = useState(false);
3758
4023
  const handleChange = (v) => {
3759
- state.value = v;
4024
+ setTimeValue(v);
3760
4025
  };
3761
4026
  const handleFallback = (v) => {
3762
- state.safeValue = v;
4027
+ setSafeValue(v);
3763
4028
  };
3764
4029
  const handleValidTime = () => {
3765
- if (!state.value)
4030
+ if (!timeValue)
3766
4031
  return;
3767
- state.value = state.safeValue;
3768
- handleChange(state.safeValue);
4032
+ setTimeValue(safeValue);
3769
4033
  };
3770
4034
  const handleBlur = (e) => {
3771
4035
  onBlur?.(e);
@@ -3776,9 +4040,9 @@ function TimePicker(props) {
3776
4040
  setActive(v);
3777
4041
  };
3778
4042
  useEffect(() => {
3779
- state.value = value;
4043
+ setTimeValue(value);
3780
4044
  }, [value]);
3781
- return (jsx(Popup, { visible: active, trigger: 'click', position: 'bottom', arrow: false, align: 'start', watchResize: true, ...popupProps, onVisibleChange: handleVisibleChange, content: jsx(Panel, { value: state.value, format: format, periods: periods, renderItem: renderItem, onChange: handleChange, onFallback: handleFallback }), children: jsx(Input, { value: state.value, placeholder: placeholder, append: jsx(Icon, { icon: jsx(AccessTimeRound, {}), className: 'i-timepicker-icon', size: '1em' }), onChange: handleChange, onBlur: handleBlur, className: classNames("i-timepicker-label", className), ...restProps }) }));
4045
+ return (jsx(Popup, { visible: active, trigger: 'click', position: 'bottom', arrow: false, align: 'start', ...popupProps, onVisibleChange: handleVisibleChange, content: jsx(Panel, { value: timeValue, format: format, periods: periods, renderItem: renderItem, onChange: handleChange, onFallback: handleFallback }), children: jsx(Input, { value: timeValue, placeholder: placeholder, append: jsx(Icon, { icon: jsx(AccessTimeRound, {}), className: 'i-timepicker-icon', size: '1em' }), onChange: handleChange, onBlur: handleBlur, className: classNames("i-timepicker-label", className), ...restProps }) }));
3782
4046
  }
3783
4047
 
3784
4048
  const defaultOk = {
@@ -3789,7 +4053,7 @@ const defaultCancel = {
3789
4053
  secondary: true,
3790
4054
  };
3791
4055
  const Popconfirm = (props) => {
3792
- const { trigger = "click", visible, icon = jsx(Icon, { icon: jsx(InfoOutlined, {}), className: 'error', size: '1.2em' }), content, okButtonProps, cancelButtonProps, children, align = "end", position = "top", offset = 12, extra, onOk, onClose, ...restProps } = props;
4056
+ const { trigger = "click", visible, icon = jsx(Icon, { icon: jsx(InfoOutlined, {}), className: 'error', size: '1.2em' }), content, okButtonProps, cancelButtonProps, children, align, position = "top", offset = 12, extra, onOk, onClose, ...restProps } = props;
3793
4057
  const state = useReactive({
3794
4058
  loading: false,
3795
4059
  visible,
@@ -3838,16 +4102,14 @@ function RadioItem(props) {
3838
4102
 
3839
4103
  function Radio(props) {
3840
4104
  const { label, name, options, value, type = "default", status = "normal", message, optionInline = true, labelInline, disabled, required, className, renderItem, onChange, } = props;
3841
- const state = useReactive({
3842
- value,
3843
- });
4105
+ const [selectedValue, setSelectedValue] = useState(value);
3844
4106
  const formattedOptions = useMemo(() => formatOption(options), [options]);
3845
4107
  const handleChange = (value, e) => {
3846
- state.value = value;
4108
+ setSelectedValue(value);
3847
4109
  onChange?.(value, e);
3848
4110
  };
3849
4111
  useEffect(() => {
3850
- state.value = value;
4112
+ setSelectedValue(value);
3851
4113
  }, [value]);
3852
4114
  return (jsxs("div", { className: classNames("i-radio i-input-label", {
3853
4115
  [`i-radio-${status}`]: status !== "normal",
@@ -3856,7 +4118,7 @@ function Radio(props) {
3856
4118
  "i-options-block": !optionInline,
3857
4119
  "i-radio-options-button": type === "button",
3858
4120
  }), children: formattedOptions.map((option) => {
3859
- const checked = state.value === option.value;
4121
+ const checked = selectedValue === option.value;
3860
4122
  return (jsx(RadioItem, { name: name, value: option.value, checked: checked, type: type, disabled: disabled || option.disabled, onChange: handleChange, children: renderItem ?? option.label }, option.value));
3861
4123
  }) })] }));
3862
4124
  }
@@ -4313,25 +4575,23 @@ const Tabs = ((props) => {
4313
4575
  const barRef = useRef(null);
4314
4576
  const navsRef = useRef(null);
4315
4577
  const contentsRef = useRef(new Map());
4316
- const state = useReactive({
4317
- active,
4318
- prevActive: undefined,
4319
- barStyle: {},
4320
- cachedTabs: [],
4321
- overflow: false,
4322
- more: [],
4323
- tabs: [],
4324
- });
4578
+ const [activeKey, setActiveKey] = useState(active);
4579
+ const [prevActiveKey, setPrevActiveKey] = useState(undefined);
4580
+ const [barStyle, setBarStyle] = useState({});
4581
+ const [cachedTabs, setCachedTabs] = useState([]);
4582
+ const [overflow, setOverflow] = useState(false);
4583
+ const [moreTabs, setMoreTabs] = useState([]);
4584
+ const [tabs, setTabs] = useState([]);
4325
4585
  const { observe, unobserve } = useIntersectionObserver();
4326
4586
  const size = useSize(navsRef);
4327
4587
  useEffect(() => {
4328
4588
  contentsRef.current.clear();
4329
4589
  if (!items) {
4330
4590
  if (!children) {
4331
- state.tabs = [];
4591
+ setTabs([]);
4332
4592
  return;
4333
4593
  }
4334
- state.tabs = Children.map(children, (node, i) => {
4594
+ setTabs(Children.map(children, (node, i) => {
4335
4595
  const { key, props: nodeProps } = node;
4336
4596
  const { title, children: tabChildren, content, keepDOM, closable, } = nodeProps;
4337
4597
  const tabKey = String(key ?? i);
@@ -4342,10 +4602,10 @@ const Tabs = ((props) => {
4342
4602
  keepDOM,
4343
4603
  closable,
4344
4604
  };
4345
- });
4605
+ }) ?? []);
4346
4606
  return;
4347
4607
  }
4348
- state.tabs = items.map((item, i) => {
4608
+ setTabs(items.map((item, i) => {
4349
4609
  if (["string", "number"].includes(typeof item)) {
4350
4610
  const key = String(item);
4351
4611
  return { key, title: item };
@@ -4357,90 +4617,99 @@ const Tabs = ((props) => {
4357
4617
  ...rest,
4358
4618
  key,
4359
4619
  };
4360
- });
4620
+ }));
4361
4621
  }, [children, items]);
4362
4622
  const add = (tab) => {
4363
- const tkey = String(tab.key ?? state.tabs.length);
4364
- const i = state.tabs.findIndex((t) => t.key === tkey);
4623
+ const tkey = String(tab.key ?? tabs.length);
4624
+ const i = tabs.findIndex((t) => t.key === tkey);
4365
4625
  if (i > -1) {
4366
- open(state.tabs[i].key ?? `${i}`);
4626
+ open(tabs[i].key ?? `${i}`);
4367
4627
  return;
4368
4628
  }
4369
4629
  contentsRef.current.set(tkey, tab.content);
4370
4630
  const { content, ...rest } = tab;
4371
- state.tabs.push({ ...rest, key: tkey });
4631
+ setTabs((ts) => [...ts, { ...rest, key: tkey }]);
4372
4632
  open(tkey);
4373
4633
  };
4374
4634
  const close = (key) => {
4375
- const i = state.tabs.findIndex((t) => t.key === key);
4635
+ const i = tabs.findIndex((t) => t.key === key);
4376
4636
  if (i < 0)
4377
4637
  return;
4378
4638
  contentsRef.current.delete(key);
4379
- state.tabs.splice(i, 1);
4380
- if (state.active !== key)
4639
+ const nextTabs = [...tabs];
4640
+ nextTabs.splice(i, 1);
4641
+ setTabs(nextTabs);
4642
+ if (activeKey !== key)
4381
4643
  return;
4382
- const next = state.tabs[i] || state.tabs[i - 1];
4383
- open(state.prevActive ?? next?.key ?? "");
4644
+ const next = nextTabs[i] || nextTabs[i - 1];
4645
+ open(prevActiveKey ?? next?.key ?? "");
4384
4646
  };
4385
4647
  const open = (key) => {
4386
- if (key === state.active) {
4648
+ if (key === activeKey) {
4387
4649
  if (!toggable)
4388
4650
  return;
4389
4651
  onTabChange?.(undefined, key);
4390
- state.active = undefined;
4391
- state.barStyle = {
4652
+ setActiveKey(undefined);
4653
+ setBarStyle({
4392
4654
  height: 0,
4393
4655
  width: 0,
4394
- };
4656
+ });
4395
4657
  return;
4396
4658
  }
4397
- state.prevActive = state.active;
4398
- onTabChange?.(key, state.active);
4399
- state.active = key;
4659
+ setPrevActiveKey(activeKey);
4660
+ onTabChange?.(key, activeKey);
4661
+ setActiveKey(key);
4400
4662
  };
4401
4663
  useEffect(() => {
4402
4664
  if (!size || hideMore || !observe)
4403
4665
  return;
4404
4666
  const { scrollHeight, scrollWidth } = navsRef.current;
4405
4667
  const { width, height } = size;
4406
- state.overflow = scrollHeight > height || scrollWidth > width;
4407
- if (!state.overflow)
4668
+ const nextOverflow = scrollHeight > height || scrollWidth > width;
4669
+ setOverflow(nextOverflow);
4670
+ if (!nextOverflow)
4408
4671
  return;
4409
4672
  navRefs.current.map((nav, i) => {
4410
4673
  if (!nav)
4411
4674
  return;
4412
4675
  observe(nav, (tar, visible) => {
4413
- if (!state.tabs[i])
4414
- return;
4415
- state.tabs[i].intersecting = visible;
4416
- state.more = state.tabs.filter((tab) => !tab.intersecting);
4676
+ setTabs((ts) => {
4677
+ if (!ts[i])
4678
+ return ts;
4679
+ const nextTabs = ts.map((t, idx) => idx === i ? { ...t, intersecting: visible } : t);
4680
+ setMoreTabs(nextTabs.filter((tab) => !tab.intersecting));
4681
+ return nextTabs;
4682
+ });
4417
4683
  });
4418
4684
  });
4419
- }, [size, hideMore, state.tabs.length]);
4685
+ }, [size, hideMore, tabs.length, observe]);
4420
4686
  useEffect(() => {
4421
- if (!bar || type === "pane" || state.active === undefined) {
4687
+ if (!bar || type === "pane" || activeKey === undefined) {
4422
4688
  return;
4423
4689
  }
4424
- const index = state.tabs.findIndex((tab) => tab.key === state.active);
4690
+ const index = tabs.findIndex((tab) => tab.key === activeKey);
4425
4691
  setTimeout(() => {
4426
4692
  const nav = navRefs.current[index];
4427
4693
  if (!nav)
4428
4694
  return;
4429
- if (state.tabs[index].keepDOM && state.active) {
4430
- const i = state.cachedTabs.findIndex((k) => k === state.active);
4431
- i < 0 && state.cachedTabs.unshift(state.active);
4695
+ if (tabs[index]?.keepDOM && activeKey) {
4696
+ setCachedTabs((keys) => {
4697
+ if (keys.includes(activeKey))
4698
+ return keys;
4699
+ return [activeKey, ...keys];
4700
+ });
4432
4701
  }
4433
4702
  const { offsetHeight, offsetLeft, offsetTop, offsetWidth } = nav;
4434
4703
  const isLine = type === "line";
4435
- state.barStyle = {
4704
+ setBarStyle({
4436
4705
  height: !vertical && isLine ? ".25em" : offsetHeight,
4437
4706
  width: vertical && isLine ? ".25em" : offsetWidth,
4438
4707
  transform: `translate(${offsetLeft}px, ${offsetTop}px)`,
4439
- };
4708
+ });
4440
4709
  }, 16);
4441
- }, [state.active, bar, size]);
4710
+ }, [activeKey, bar, size, tabs, type, vertical]);
4442
4711
  useEffect(() => {
4443
- if (active === undefined || state.active === active)
4712
+ if (active === undefined || activeKey === active)
4444
4713
  return;
4445
4714
  open(active);
4446
4715
  }, [active]);
@@ -4450,7 +4719,7 @@ const Tabs = ((props) => {
4450
4719
  return () => {
4451
4720
  navRefs.current?.map(unobserve);
4452
4721
  };
4453
- }, [state.tabs.length]);
4722
+ }, [tabs.length, hideMore, unobserve]);
4454
4723
  useEffect(() => {
4455
4724
  if (!navsRef.current || vertical)
4456
4725
  return;
@@ -4480,26 +4749,26 @@ const Tabs = ((props) => {
4480
4749
  }));
4481
4750
  return (jsxs("div", { className: classNames("i-tabs", { flex: vertical, [`i-tabs-${type}`]: type !== "default" }, className), ...rest, children: [jsxs("div", { className: classNames("i-tab-navs-container", {
4482
4751
  "i-tab-navs-vertical": vertical,
4483
- }), children: [prepend, jsxs("div", { ref: navsRef, className: classNames("i-tab-navs", `justify-${navsJustify}`), children: [state.tabs.map((tab, i) => {
4752
+ }), children: [prepend, jsxs("div", { ref: navsRef, className: classNames("i-tab-navs", `justify-${navsJustify}`), children: [tabs.map((tab, i) => {
4484
4753
  const { title, key = `${i}`, closable } = tab;
4485
4754
  return (jsxs("a", { ref: (ref) => (navRefs.current[i] = ref), className: classNames("i-tab-nav", {
4486
- "i-tab-active": state.active === key,
4755
+ "i-tab-active": activeKey === key,
4487
4756
  }), onClick: () => open(key), children: [title, closable && (jsx(Helpericon, { as: 'i', active: true, className: 'i-tab-nav-close', onClick: (e) => {
4488
4757
  e.stopPropagation();
4489
4758
  close(key);
4490
4759
  } }))] }, key));
4491
- }), bar && (jsx("span", { ref: barRef, className: classNames("i-tab-navs-bar", barClass), style: state.barStyle }))] }), !hideMore && state.overflow && state.more.length > 0 && (jsx(Popup, { arrow: false, position: vertical ? "right" : "bottom", align: 'end', touchable: true, hideDelay: 500, content: jsx("div", { className: 'i-tabs-morelist pd-4', children: state.more.map((tab, i) => {
4760
+ }), bar && (jsx("span", { ref: barRef, className: classNames("i-tab-navs-bar", barClass), style: barStyle }))] }), !hideMore && overflow && moreTabs.length > 0 && (jsx(Popup, { arrow: false, position: vertical ? "right" : "bottom", align: 'end', touchable: true, hideDelay: 500, content: jsx("div", { className: 'i-tabs-morelist pd-4', children: moreTabs.map((tab, i) => {
4492
4761
  const { key = `${i}`, title } = tab;
4493
- const isActive = state.active === key;
4762
+ const isActive = activeKey === key;
4494
4763
  return (jsx("a", { className: classNames("i-tab-nav", {
4495
4764
  "i-tab-active": isActive,
4496
4765
  }), onClick: () => open(key), children: title }, key));
4497
- }) }), children: renderMore(state.more) })), append] }), jsx("div", { className: 'i-tab-contents', children: state.tabs.map((tab, i) => {
4766
+ }) }), children: renderMore(moreTabs) })), append] }), jsx("div", { className: 'i-tab-contents', children: tabs.map((tab, i) => {
4498
4767
  const key = tab.key ?? `${i}`;
4499
4768
  const content = contentsRef.current.get(key);
4500
- const isActive = state.active === key;
4769
+ const isActive = activeKey === key;
4501
4770
  const show = isActive ||
4502
- (key !== undefined && state.cachedTabs.includes(key));
4771
+ (key !== undefined && cachedTabs.includes(key));
4503
4772
  return (show && (jsx("div", { className: classNames("i-tab-content", {
4504
4773
  "i-tab-active": isActive,
4505
4774
  }), children: content }, key)));
@@ -4578,14 +4847,12 @@ const defaultNodeProps = {
4578
4847
  };
4579
4848
  const Tree = (props) => {
4580
4849
  const { data = [], ref, selected, checked = [], disabledRelated, nodeProps, onItemSelect, onItemCheck, ...restProps } = props;
4581
- const state = useReactive({
4582
- selected,
4583
- checked,
4584
- partofs: {},
4585
- nodeMaps: new Map(),
4586
- });
4850
+ const [selectedKey, setSelectedKey] = useState(selected);
4851
+ const [checkedKeys, setCheckedKeys] = useState(checked);
4852
+ const [partofs, setPartofs] = useState({});
4853
+ const nodeMapsRef = useRef(new Map());
4587
4854
  const oNodeProps = Object.assign({}, defaultNodeProps, nodeProps);
4588
- const isChecked = (key) => state.checked.includes(key || "");
4855
+ const isChecked = (key) => checkedKeys.includes(key || "");
4589
4856
  const checkItem = (item, checked, direction) => {
4590
4857
  const { key = "", parent, children } = item;
4591
4858
  const shouldChanged = { [key]: checked };
@@ -4637,29 +4904,30 @@ const Tree = (props) => {
4637
4904
  const handleCheck = (item, checked) => {
4638
4905
  const [shouldChanged, partofs] = checkItem(item, checked);
4639
4906
  const changedKeys = Object.keys(shouldChanged);
4640
- state.checked = checked
4641
- ? Array.from(new Set([...state.checked, ...changedKeys]))
4642
- : state.checked.filter((k) => !changedKeys.includes(k));
4643
- Object.assign(state.partofs, partofs);
4644
- onItemCheck?.(item, checked, state.checked);
4907
+ const nextChecked = checked
4908
+ ? Array.from(new Set([...checkedKeys, ...changedKeys]))
4909
+ : checkedKeys.filter((k) => !changedKeys.includes(k));
4910
+ setCheckedKeys(nextChecked);
4911
+ setPartofs((p) => ({ ...p, ...partofs }));
4912
+ onItemCheck?.(item, checked, nextChecked);
4645
4913
  };
4646
4914
  const handleSelect = (key, item) => {
4647
4915
  if (!props.selectable)
4648
4916
  return;
4649
- state.selected = key;
4917
+ setSelectedKey(key);
4650
4918
  onItemSelect?.(key, item);
4651
4919
  };
4652
4920
  useEffect(() => {
4653
4921
  if (selected === undefined)
4654
4922
  return;
4655
- state.selected = selected;
4923
+ setSelectedKey(selected);
4656
4924
  }, [selected]);
4657
4925
  useEffect(() => {
4658
- state.nodeMaps.clear();
4926
+ nodeMapsRef.current.clear();
4659
4927
  const { key, children } = oNodeProps;
4660
4928
  const recursive = (nodes) => {
4661
4929
  nodes.map((o) => {
4662
- state.nodeMaps.set(o[key], o);
4930
+ nodeMapsRef.current.set(o[key], o);
4663
4931
  o[children]?.length > 0 && recursive(o[children]);
4664
4932
  });
4665
4933
  };
@@ -4669,22 +4937,22 @@ const Tree = (props) => {
4669
4937
  return {
4670
4938
  getChecked: () => {
4671
4939
  const items = [];
4672
- state.checked.map((k) => {
4673
- const item = state.nodeMaps.get(k);
4940
+ checkedKeys.map((k) => {
4941
+ const item = nodeMapsRef.current.get(k);
4674
4942
  items.push(item);
4675
4943
  });
4676
- return [state.checked, items];
4944
+ return [checkedKeys, items];
4677
4945
  },
4678
4946
  getSelected: () => {
4679
- const item = state.nodeMaps.get(state.selected);
4680
- return [state.selected, item];
4947
+ const item = nodeMapsRef.current.get(selectedKey);
4948
+ return [selectedKey, item];
4681
4949
  },
4682
4950
  getPartofs: () => {
4683
4951
  const items = [];
4684
- const keys = Object.keys(state.partofs).filter((k) => {
4685
- const indeterminate = state.partofs[k];
4952
+ const keys = Object.keys(partofs).filter((k) => {
4953
+ const indeterminate = partofs[k];
4686
4954
  if (indeterminate) {
4687
- const item = state.nodeMaps.get(k);
4955
+ const item = nodeMapsRef.current.get(k);
4688
4956
  items.push(item);
4689
4957
  }
4690
4958
  return indeterminate;
@@ -4693,7 +4961,7 @@ const Tree = (props) => {
4693
4961
  },
4694
4962
  };
4695
4963
  });
4696
- return (jsx(TreeList, { data: data, selected: state.selected, checked: state.checked, partofs: state.partofs, nodeProps: oNodeProps, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
4964
+ return (jsx(TreeList, { data: data, selected: selectedKey, checked: checkedKeys, partofs: partofs, nodeProps: oNodeProps, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
4697
4965
  };
4698
4966
 
4699
4967
  const ListContainer = (props) => {
@@ -4746,12 +5014,8 @@ const FileListItem = (props) => {
4746
5014
 
4747
5015
  const Upload = (props) => {
4748
5016
  const { ref, label, labelInline, value, files = [], initialFiles, placeholder, status = "normal", message, className, style, children, defaultButtonProps, mode = "default", cardSize = "4em", disabled, sortable, limit = props.multiple ? Infinity : 1, multiple, renderItem, shouldUpload = () => true, uploader, onChange, onFilesChange, onUpload, ...restProps } = props;
4749
- const state = useReactive({
4750
- files,
4751
- value,
4752
- status,
4753
- message,
4754
- });
5017
+ const [fileList, setFileListState] = useState(files);
5018
+ const [uploadMessage, setUploadMessage] = useState(message);
4755
5019
  const inputRef = useRef(null);
4756
5020
  const preview = usePreview();
4757
5021
  const defBtnProps = Object.assign({
@@ -4769,7 +5033,7 @@ const Upload = (props) => {
4769
5033
  }, [mode, children]);
4770
5034
  const handleChange = (e) => {
4771
5035
  const files = Array.from(e.target.files || []);
4772
- const { files: before } = state;
5036
+ const before = fileList;
4773
5037
  const changed = [];
4774
5038
  files.map((f) => {
4775
5039
  const { id, name, size, type } = f;
@@ -4786,21 +5050,20 @@ const Upload = (props) => {
4786
5050
  !same && changed.push(f);
4787
5051
  });
4788
5052
  const after = [...before, ...changed];
4789
- Object.assign(state, {
4790
- files: multiple ? after.slice(0, limit) : [after.at(-1)],
4791
- status,
4792
- message,
4793
- });
4794
- onFilesChange?.(state.files, changed, e);
4795
- onChange?.(state.files, e);
5053
+ const last = after.at(-1);
5054
+ const nextFiles = multiple ? after.slice(0, limit) : last ? [last] : [];
5055
+ setFileListState(nextFiles);
5056
+ setUploadMessage(message);
5057
+ onFilesChange?.(nextFiles, changed, e);
5058
+ onChange?.(nextFiles, e);
4796
5059
  handleUpload(changed);
4797
5060
  inputRef.current && (inputRef.current.value = "");
4798
5061
  };
4799
5062
  const handleRemove = (i) => {
4800
- const [...files] = state.files;
5063
+ const [...files] = fileList;
4801
5064
  const changed = files.splice(i, 1);
4802
5065
  URL.revokeObjectURL(changed[0]?.src || "");
4803
- state.files = files;
5066
+ setFileListState(files);
4804
5067
  onFilesChange?.(files, changed);
4805
5068
  onChange?.(files);
4806
5069
  inputRef.current && (inputRef.current.value = "");
@@ -4813,44 +5076,43 @@ const Upload = (props) => {
4813
5076
  return onUpload?.(result);
4814
5077
  };
4815
5078
  const handlePreview = (i) => {
4816
- preview({ items: state.files, initial: i });
5079
+ preview({ items: fileList, initial: i });
4817
5080
  };
4818
5081
  const setFileList = (files) => {
4819
5082
  if (!files)
4820
5083
  return;
4821
- state.files = files.map((f) => {
4822
- return { ...f, id: f.id ?? uid(7) };
4823
- });
5084
+ setFileListState(files.map((f) => {
5085
+ const file = f;
5086
+ return { ...file, id: file.id ?? uid(7) };
5087
+ }));
4824
5088
  };
4825
5089
  const handleSortEnd = (before, after) => {
4826
- const [...files] = state.files;
4827
- state.files = arrayMove(files, before, after);
4828
- onChange?.(state.files);
5090
+ const [...files] = fileList;
5091
+ const nextFiles = arrayMove(files, before, after);
5092
+ setFileListState(nextFiles);
5093
+ onChange?.(nextFiles);
4829
5094
  };
4830
5095
  useEffect(() => {
4831
- Object.assign(state, {
4832
- status,
4833
- message,
4834
- });
5096
+ setUploadMessage(message);
4835
5097
  }, [status, message]);
4836
5098
  useEffect(() => {
4837
- state.files = value?.filter?.((file) => !!file.id) ?? [];
5099
+ setFileListState(value?.filter?.((file) => !!file.id) ?? []);
4838
5100
  }, [value]);
4839
5101
  useEffect(() => {
4840
5102
  setFileList(initialFiles);
4841
5103
  }, []);
4842
5104
  useImperativeHandle(ref, () => ({
4843
- getFileList: () => state.files,
5105
+ getFileList: () => fileList,
4844
5106
  setFileList,
4845
- }), []);
5107
+ }), [fileList]);
4846
5108
  return (jsx(InputContainer, { as: 'div', label: label, labelInline: labelInline, className: classNames("i-input-label-file", className), style: style, children: jsxs("div", { className: classNames("i-upload-inner", {
4847
5109
  [`i-upload-${mode}`]: mode !== "default",
4848
- }), style: { ["--upload-card-size"]: cardSize }, children: [jsx(ListContainer, { sortable: sortable, onSortEnd: handleSortEnd, children: state.files.map((file, i) => {
5110
+ }), style: { ["--upload-card-size"]: cardSize }, children: [jsx(ListContainer, { sortable: sortable, onSortEnd: handleSortEnd, children: fileList.map((file, i) => {
4849
5111
  const node = (jsx(FileListItem, { index: i, file: file, mode: mode, renderItem: renderItem, onRemove: handleRemove, onPreview: handlePreview }, i));
4850
5112
  if (!sortable)
4851
5113
  return node;
4852
5114
  return jsx(SortableItem, { children: node }, i);
4853
- }) }), state.message && (jsx("span", { className: 'i-upload-message', children: state.message })), state.files.length < limit && (jsxs("label", { children: [jsx("input", { ...restProps, disabled: disabled, ref: inputRef, type: 'file', className: 'i-input-file-hidden', multiple: multiple, onChange: handleChange }), trigger] }))] }) }));
5115
+ }) }), uploadMessage && (jsx("span", { className: 'i-upload-message', children: uploadMessage })), fileList.length < limit && (jsxs("label", { children: [jsx("input", { ...restProps, disabled: disabled, ref: inputRef, type: 'file', className: 'i-input-file-hidden', multiple: multiple, onChange: handleChange }), trigger] }))] }) }));
4854
5116
  };
4855
5117
 
4856
5118
  const useTheme = (props) => {