@ioca/react 1.4.74 → 1.4.75

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 (84) 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/radio/radio.js +4 -7
  32. package/lib/cjs/components/radio/radio.js.map +1 -1
  33. package/lib/cjs/components/select/select.js +19 -24
  34. package/lib/cjs/components/select/select.js.map +1 -1
  35. package/lib/cjs/components/tabs/tabs.js +61 -54
  36. package/lib/cjs/components/tabs/tabs.js.map +1 -1
  37. package/lib/cjs/components/tree/tree.js +24 -26
  38. package/lib/cjs/components/tree/tree.js.map +1 -1
  39. package/lib/cjs/components/upload/upload.js +26 -33
  40. package/lib/cjs/components/upload/upload.js.map +1 -1
  41. package/lib/css/index.css +1 -1
  42. package/lib/css/index.css.map +1 -1
  43. package/lib/es/components/button/toggle.js +12 -19
  44. package/lib/es/components/button/toggle.js.map +1 -1
  45. package/lib/es/components/checkbox/checkbox.js +6 -9
  46. package/lib/es/components/checkbox/checkbox.js.map +1 -1
  47. package/lib/es/components/checkbox/item.js +16 -17
  48. package/lib/es/components/checkbox/item.js.map +1 -1
  49. package/lib/es/components/collapse/collapse.js +12 -14
  50. package/lib/es/components/collapse/collapse.js.map +1 -1
  51. package/lib/es/components/form/field.js +17 -21
  52. package/lib/es/components/form/field.js.map +1 -1
  53. package/lib/es/components/input/input.js +22 -19
  54. package/lib/es/components/input/input.js.map +1 -1
  55. package/lib/es/components/input/number.js +67 -21
  56. package/lib/es/components/input/number.js.map +1 -1
  57. package/lib/es/components/input/range.js +11 -14
  58. package/lib/es/components/input/range.js.map +1 -1
  59. package/lib/es/components/input/textarea.js +5 -8
  60. package/lib/es/components/input/textarea.js.map +1 -1
  61. package/lib/es/components/picker/colors/footer.js +8 -11
  62. package/lib/es/components/picker/colors/footer.js.map +1 -1
  63. package/lib/es/components/picker/colors/index.js +24 -22
  64. package/lib/es/components/picker/colors/index.js.map +1 -1
  65. package/lib/es/components/picker/dates/index.js +9 -12
  66. package/lib/es/components/picker/dates/index.js.map +1 -1
  67. package/lib/es/components/picker/dates/panel.js +30 -36
  68. package/lib/es/components/picker/dates/panel.js.map +1 -1
  69. package/lib/es/components/picker/time/index.js +8 -12
  70. package/lib/es/components/picker/time/index.js.map +1 -1
  71. package/lib/es/components/picker/time/panel.js +39 -22
  72. package/lib/es/components/picker/time/panel.js.map +1 -1
  73. package/lib/es/components/radio/radio.js +5 -8
  74. package/lib/es/components/radio/radio.js.map +1 -1
  75. package/lib/es/components/select/select.js +19 -24
  76. package/lib/es/components/select/select.js.map +1 -1
  77. package/lib/es/components/tabs/tabs.js +63 -56
  78. package/lib/es/components/tabs/tabs.js.map +1 -1
  79. package/lib/es/components/tree/tree.js +25 -27
  80. package/lib/es/components/tree/tree.js.map +1 -1
  81. package/lib/es/components/upload/upload.js +27 -34
  82. package/lib/es/components/upload/upload.js.map +1 -1
  83. package/lib/index.js +406 -368
  84. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -428,25 +428,21 @@ function Group(props) {
428
428
 
429
429
  function Toggle(props) {
430
430
  const { ref, active, activeClass, after, disabled, children, className, toggable, onClick, onToggle, ...restProps } = props;
431
- const state = useReactive({
432
- active,
433
- done: true,
434
- });
431
+ const [isActive, setIsActive] = useState(active);
432
+ const [done, setDone] = useState(true);
435
433
  const toggle = async () => {
436
434
  const hasAfter = !!after;
437
- const nextActive = !state.active;
435
+ const nextActive = !isActive;
438
436
  const canToggle = toggable ? await toggable() : true;
439
437
  if (!canToggle)
440
438
  return;
441
- Object.assign(state, {
442
- active: nextActive,
443
- done: !hasAfter,
444
- });
439
+ setIsActive(nextActive);
440
+ setDone(!hasAfter);
445
441
  onToggle?.(nextActive);
446
442
  if (!hasAfter)
447
443
  return;
448
444
  setTimeout(() => {
449
- state.done = true;
445
+ setDone(true);
450
446
  }, 16);
451
447
  };
452
448
  const handleClick = (e) => {
@@ -454,14 +450,12 @@ function Toggle(props) {
454
450
  !disabled && toggle();
455
451
  };
456
452
  useEffect(() => {
457
- Object.assign(state, {
458
- active,
459
- done: true,
460
- });
453
+ setIsActive(active);
454
+ setDone(true);
461
455
  }, [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 }) }));
456
+ 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", {
457
+ "i-btn-toggle-active": done,
458
+ }), children: isActive ? (after ?? children) : children }) }));
465
459
  }
466
460
 
467
461
  const formatClass = ({ outline, flat, loading, disabled, size = "normal", block, round, square, secondary, className, }) => classNames("i-btn", className, {
@@ -894,41 +888,39 @@ const arrayMove = (array, fromIndex, toIndex) => {
894
888
 
895
889
  function CheckboxItem(props) {
896
890
  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
- });
891
+ const [checked, setChecked] = useState(value);
892
+ const [itemStatus, setItemStatus] = useState(status);
893
+ const [itemMessage, setItemMessage] = useState(message);
902
894
  const isChildrenFn = typeof children === "function";
903
895
  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);
896
+ const next = e.target.checked;
897
+ setChecked(next);
898
+ setItemStatus(status);
899
+ setItemMessage(message);
900
+ onChange?.(next, e);
911
901
  };
912
902
  useEffect(() => {
913
- state.value = value;
903
+ setChecked(value);
914
904
  }, [value]);
905
+ useEffect(() => {
906
+ setItemStatus(status);
907
+ setItemMessage(message);
908
+ }, [status, message]);
915
909
  return (jsxs("label", { className: classNames("i-checkbox-item", {
916
- [`i-checkbox-${state.status}`]: state.status !== "normal",
910
+ [`i-checkbox-${itemStatus}`]: itemStatus !== "normal",
917
911
  disabled,
918
912
  }, className), ...restProps, children: [jsx("input", { type: 'checkbox', name: name, className: classNames("i-checkbox-input", {
919
913
  [`i-checkbox-${type}`]: !partof,
920
914
  "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] }))] }));
915
+ }), 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
916
  }
923
917
 
924
918
  function Checkbox(props) {
925
919
  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
- });
920
+ const [selectedValues, setSelectedValues] = useState(value);
929
921
  const formattedOptions = useMemo(() => formatOption(options), [options]);
930
922
  const handleChange = (checked, opt, e) => {
931
- const group = [...state.value];
923
+ const group = [...selectedValues];
932
924
  const i = group.findIndex((item) => item === opt.value);
933
925
  if (checked && i < 0) {
934
926
  group.push(opt.value);
@@ -936,11 +928,11 @@ function Checkbox(props) {
936
928
  else if (!checked && i > -1) {
937
929
  group.splice(i, 1);
938
930
  }
939
- state.value = group;
931
+ setSelectedValues(group);
940
932
  onChange?.(group, opt, e);
941
933
  };
942
934
  useEffect(() => {
943
- state.value = value;
935
+ setSelectedValues(value);
944
936
  }, [value]);
945
937
  return (jsxs("div", { className: classNames("i-checkbox i-input-label", {
946
938
  [`i-checkbox-${status}`]: status !== "normal",
@@ -949,7 +941,7 @@ function Checkbox(props) {
949
941
  "i-options-block": !optionInline,
950
942
  "i-checkbox-options-button": type === "button",
951
943
  }), 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));
944
+ 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
945
  }) })] }));
954
946
  }
955
947
  Checkbox.Item = CheckboxItem;
@@ -975,9 +967,7 @@ function Item$5(props) {
975
967
 
976
968
  const Collapse = (props) => {
977
969
  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
- });
970
+ const [activeKey, setActiveKey] = useState(active);
981
971
  const collapses = useMemo(() => {
982
972
  if (!items) {
983
973
  if (!children)
@@ -1007,19 +997,20 @@ const Collapse = (props) => {
1007
997
  if (disabled)
1008
998
  return;
1009
999
  if (!multiple) {
1010
- state.active = state.active === key ? undefined : key;
1011
- onCollapse?.(key, state.active !== undefined);
1000
+ const nextActive = activeKey === key ? undefined : key;
1001
+ setActiveKey(nextActive);
1002
+ onCollapse?.(key, nextActive !== undefined);
1012
1003
  return;
1013
1004
  }
1014
- if (!Array.isArray(state.active))
1015
- state.active = [];
1016
- const i = state.active.findIndex((k) => k === key);
1005
+ const group = Array.isArray(activeKey) ? [...activeKey] : [];
1006
+ const i = group.findIndex((k) => k === key);
1017
1007
  if (i > -1) {
1018
- state.active.splice(i, 1);
1008
+ group.splice(i, 1);
1019
1009
  }
1020
1010
  else {
1021
- key !== undefined && state.active.push(key);
1011
+ key !== undefined && group.push(key);
1022
1012
  }
1013
+ setActiveKey(group);
1023
1014
  onCollapse?.(key, i < 0);
1024
1015
  };
1025
1016
  return (jsx("div", { className: classNames("i-collapse", {
@@ -1027,8 +1018,8 @@ const Collapse = (props) => {
1027
1018
  }, className), ...restProps, children: collapses.map((item) => {
1028
1019
  const { key, title, content, disabled, className, ...restProps } = item;
1029
1020
  const isActive = multiple
1030
- ? (state.active || []).includes(key)
1031
- : state.active === key;
1021
+ ? (activeKey || []).includes(key)
1022
+ : activeKey === key;
1032
1023
  return (jsxs("div", { className: classNames("i-collapse-item", className, {
1033
1024
  "i-collapse-active": isActive,
1034
1025
  "i-collapse-disabled": disabled,
@@ -1808,12 +1799,9 @@ const Context = createContext({});
1808
1799
 
1809
1800
  function Field(props) {
1810
1801
  const { name, required, children } = props;
1811
- const state = useReactive({
1812
- value: undefined,
1813
- status: "normal",
1814
- message: undefined,
1815
- update: 0,
1816
- });
1802
+ const [fieldValue, setFieldValue] = useState(undefined);
1803
+ const [fieldStatus, setFieldStatus] = useState("normal");
1804
+ const [fieldMessage, setFieldMessage] = useState(undefined);
1817
1805
  const form = useContext(Context);
1818
1806
  const { id } = form;
1819
1807
  const handleChange = (v) => {
@@ -1830,33 +1818,33 @@ function Field(props) {
1830
1818
  if (!isValidElement(node))
1831
1819
  return null;
1832
1820
  const { onChange } = node.props;
1833
- const { value, status, message } = state;
1834
1821
  return cloneElement(node, {
1835
- value,
1836
- status,
1837
- message,
1822
+ value: fieldValue,
1823
+ status: fieldStatus,
1824
+ message: fieldMessage,
1838
1825
  required,
1839
1826
  onChange: (...args) => {
1840
1827
  handleChange(args[0]);
1841
1828
  onChange?.(...args);
1842
- Object.assign(state, {
1843
- status: "normal",
1844
- message: undefined,
1845
- });
1829
+ setFieldStatus("normal");
1830
+ setFieldMessage(undefined);
1846
1831
  },
1847
1832
  });
1848
1833
  });
1849
- }, [children, state.update]);
1834
+ }, [children, fieldValue, fieldStatus, fieldMessage, required]);
1850
1835
  useEffect(() => {
1851
1836
  if (!name)
1852
1837
  return;
1853
1838
  PubSub.subscribe(`${id}:set:${name}`, (evt, v) => {
1854
- state.value = v;
1855
- state.update += 1;
1839
+ setFieldValue(v);
1856
1840
  });
1857
1841
  PubSub.subscribe(`${id}:invalid:${name}`, (evt, v) => {
1858
- Object.assign(state, v);
1859
- state.update += 1;
1842
+ if (v?.value !== undefined)
1843
+ setFieldValue(v.value);
1844
+ if (v?.status)
1845
+ setFieldStatus(v.status);
1846
+ if ("message" in (v ?? {}))
1847
+ setFieldMessage(v.message);
1860
1848
  });
1861
1849
  Promise.resolve().then(() => {
1862
1850
  form.set(name, form.cacheData[name] ?? undefined);
@@ -2847,11 +2835,33 @@ function InputContainer(props) {
2847
2835
 
2848
2836
  const Number$1 = (props) => {
2849
2837
  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 });
2838
+ const [inputValue, setInputValue] = useState(value === undefined || value === null ? "" : String(value));
2839
+ const formatOut = (num) => {
2840
+ const v = clamp(num, min, max);
2841
+ if (precision !== undefined)
2842
+ return formatNumber(v, { precision, thousand });
2843
+ const s = String(v);
2844
+ if (!thousand)
2845
+ return s;
2846
+ const negative = s.startsWith("-");
2847
+ const body = negative ? s.slice(1) : s;
2848
+ const [integer, decimal] = body.split(".");
2849
+ const withThousand = integer.replace(/\B(?=(\d{3})+(?!\d))/g, thousand);
2850
+ return decimal
2851
+ ? `${negative ? "-" : ""}${withThousand}.${decimal}`
2852
+ : `${negative ? "-" : ""}${withThousand}`;
2853
+ };
2854
+ const sanitizeNumberInput = (raw) => {
2855
+ const hasMinus = raw.startsWith("-");
2856
+ let v = raw.replace(/[^\d.]/g, "");
2857
+ if (hasMinus)
2858
+ v = `-${v}`;
2859
+ const parts = v.split(".");
2860
+ if (parts.length > 1) {
2861
+ v = `${parts.shift()}.${parts.join("")}`;
2862
+ }
2863
+ return v;
2864
+ };
2855
2865
  const formatInputValue = (v) => {
2856
2866
  if (!v)
2857
2867
  return "";
@@ -2863,32 +2873,57 @@ const Number$1 = (props) => {
2863
2873
  };
2864
2874
  const handleChange = (e) => {
2865
2875
  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);
2876
+ const v = sanitizeNumberInput(formatInputValue(value));
2877
+ const isIntermediate = v === "" || v === "-" || v === "." || v === "-." || v.endsWith(".");
2878
+ setInputValue(v);
2879
+ if (isIntermediate)
2880
+ return;
2881
+ const num = parseFloat(v);
2882
+ if (globalThis.Number.isNaN(num))
2883
+ return;
2884
+ onChange?.(clamp(num, min, max), e);
2885
+ if (precision !== undefined)
2886
+ setInputValue(formatOut(num));
2870
2887
  };
2871
2888
  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);
2889
+ const value = parseFloat(formatInputValue(inputValue)) || 0; // 确保值为数字,默认值为 0
2890
+ const result = value + param;
2891
+ setInputValue(formatOut(result));
2892
+ onChange?.(clamp(result, min, max));
2876
2893
  };
2877
2894
  const handleMax = () => {
2878
- const result = getRangeNumber(max);
2879
- state.value = getFormatNumber(result);
2880
- onChange?.(result);
2895
+ setInputValue(formatOut(max));
2896
+ onChange?.(clamp(max, min, max));
2897
+ };
2898
+ const handleBlur = (e) => {
2899
+ onBlur?.(e);
2900
+ const v = sanitizeNumberInput(formatInputValue(inputValue));
2901
+ if (!v || v === "-" || v === "." || v === "-.") {
2902
+ setInputValue("");
2903
+ return;
2904
+ }
2905
+ const num = parseFloat(v);
2906
+ if (globalThis.Number.isNaN(num))
2907
+ return;
2908
+ const numValue = clamp(num, min, max);
2909
+ setInputValue(formatOut(numValue));
2910
+ onChange?.(numValue, e);
2881
2911
  };
2882
2912
  useEffect(() => {
2883
- state.value = value;
2913
+ setInputValue(value === undefined || value === null ? "" : String(value));
2884
2914
  }, [value]);
2885
2915
  const inputProps = {
2886
2916
  ref,
2887
2917
  name,
2888
2918
  disabled,
2889
- value: state.value,
2919
+ value: inputValue,
2890
2920
  className: "i-input i-input-number",
2891
2921
  onChange: handleChange,
2922
+ onKeyDown: (e) => {
2923
+ e.code === "Enter" && onEnter?.(e);
2924
+ },
2925
+ onInput,
2926
+ onBlur: handleBlur,
2892
2927
  ...restProps,
2893
2928
  };
2894
2929
  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 +2934,7 @@ const Number$1 = (props) => {
2899
2934
 
2900
2935
  const Range = (props) => {
2901
2936
  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
- });
2937
+ const [rangeValue, setRangeValue] = useState(value);
2905
2938
  const getRangeNumber = (v) => clamp(v, min, max);
2906
2939
  const getFormatNumber = (v) => formatNumber(v, { precision, thousand });
2907
2940
  const formatInputValue = (v) => {
@@ -2914,31 +2947,31 @@ const Range = (props) => {
2914
2947
  const handleChange = (e, i) => {
2915
2948
  const { value } = e.target;
2916
2949
  const v = formatInputValue(value.replace(/[^\d\.-]/g, ""));
2917
- const range = Array.isArray(state.value) ? state.value : [];
2950
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2918
2951
  range[i] = v;
2919
- state.value = range;
2952
+ setRangeValue(range);
2920
2953
  onChange?.(range, e);
2921
2954
  };
2922
2955
  const handleOperate = (e, param, i) => {
2923
2956
  e.preventDefault();
2924
2957
  e.stopPropagation();
2925
- const range = Array.isArray(state.value) ? state.value : [];
2958
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2926
2959
  const value = formatInputValue(range[i]) ?? 0;
2927
2960
  const result = getRangeNumber(+value + param);
2928
2961
  range[i] = getFormatNumber(result);
2929
- state.value = range;
2962
+ setRangeValue(range);
2930
2963
  onChange?.(range, e);
2931
2964
  };
2932
2965
  const handleSwitch = (e) => {
2933
2966
  e?.preventDefault();
2934
2967
  e?.stopPropagation();
2935
- const range = state.value ? state.value : [];
2968
+ const range = Array.isArray(rangeValue) ? [...rangeValue] : [];
2936
2969
  [range[0], range[1]] = [range[1], range[0]];
2937
- state.value = range;
2970
+ setRangeValue(range);
2938
2971
  onChange?.(range);
2939
2972
  };
2940
2973
  useEffect(() => {
2941
- state.value = value;
2974
+ setRangeValue(value);
2942
2975
  }, [value]);
2943
2976
  const inputProps = {
2944
2977
  name,
@@ -2948,7 +2981,7 @@ const Range = (props) => {
2948
2981
  const handleBlur = () => {
2949
2982
  if (!autoSwitch)
2950
2983
  return;
2951
- const range = Array.isArray(state.value) ? state.value : [];
2984
+ const range = Array.isArray(rangeValue) ? rangeValue : [];
2952
2985
  if (range.length < 2)
2953
2986
  return;
2954
2987
  const [left, right] = range.map(Number);
@@ -2959,18 +2992,16 @@ const Range = (props) => {
2959
2992
  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
2993
  [`i-input-${status}`]: status !== "normal",
2961
2994
  "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 })] }) }));
2995
+ }), 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
2996
  };
2964
2997
 
2965
2998
  const Textarea = (props) => {
2966
2999
  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
- });
3000
+ const [textareaValue, setTextareaValue] = useState(value);
2970
3001
  const refTextarea = useRef(null);
2971
3002
  const handleChange = (e) => {
2972
3003
  const v = e.target.value;
2973
- state.value = v;
3004
+ setTextareaValue(v);
2974
3005
  const ta = refTextarea.current;
2975
3006
  if (autoSize && ta) {
2976
3007
  ta.style.height = `${ta.scrollHeight}px`;
@@ -2984,7 +3015,7 @@ const Textarea = (props) => {
2984
3015
  onEnter?.(e);
2985
3016
  };
2986
3017
  useEffect(() => {
2987
- state.value = value;
3018
+ setTextareaValue(value);
2988
3019
  }, [value]);
2989
3020
  useImperativeHandle(ref, () => {
2990
3021
  return {
@@ -2994,7 +3025,7 @@ const Textarea = (props) => {
2994
3025
  const inputProps = {
2995
3026
  ref: refTextarea,
2996
3027
  name,
2997
- value: state.value,
3028
+ value: textareaValue,
2998
3029
  className: "i-input i-textarea",
2999
3030
  onChange: handleChange,
3000
3031
  onKeyDown: handleKeydown,
@@ -3008,14 +3039,12 @@ const Textarea = (props) => {
3008
3039
 
3009
3040
  const Input = ((props) => {
3010
3041
  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
- });
3042
+ const [inputValue, setInputValue] = useState(value);
3043
+ const [inputType, setInputType] = useState(type);
3044
+ const [visible, setVisible] = useState(false);
3016
3045
  const handleChange = (e) => {
3017
3046
  const v = e.target.value;
3018
- state.value = v;
3047
+ setInputValue(v);
3019
3048
  onChange?.(v, e);
3020
3049
  };
3021
3050
  const handleKeydown = (e) => {
@@ -3023,43 +3052,49 @@ const Input = ((props) => {
3023
3052
  };
3024
3053
  const handleHelperClick = () => {
3025
3054
  if (type === "password" && !hideVisible) {
3026
- Object.assign(state, {
3027
- visible: !state.visible,
3028
- type: !state.visible ? "text" : "password",
3055
+ setVisible((v) => {
3056
+ const next = !v;
3057
+ setInputType(next ? "text" : "password");
3058
+ return next;
3029
3059
  });
3030
3060
  return;
3031
3061
  }
3032
3062
  const v = "";
3063
+ setInputValue(v);
3033
3064
  onChange?.(v);
3034
3065
  onClear?.();
3035
3066
  };
3036
3067
  const HelperIcon = useMemo(() => {
3037
3068
  if (type === "password") {
3038
- return state.visible ? jsx(VisibilityRound, {}) : jsx(VisibilityOffRound, {});
3069
+ return visible ? jsx(VisibilityRound, {}) : jsx(VisibilityOffRound, {});
3039
3070
  }
3040
3071
  return undefined;
3041
- }, [state.visible]);
3072
+ }, [type, visible]);
3042
3073
  useEffect(() => {
3043
- state.value = value;
3074
+ setInputValue(value);
3044
3075
  }, [value]);
3045
3076
  const inputProps = {
3046
3077
  ref,
3047
- type: state.type,
3078
+ type: inputType,
3048
3079
  name,
3049
- value: state.value,
3080
+ value: inputValue,
3050
3081
  maxLength,
3051
3082
  className: classNames("i-input", `i-input-${type}`),
3052
3083
  onChange: handleChange,
3053
3084
  onKeyDown: handleKeydown,
3054
3085
  ...restProps,
3055
3086
  };
3056
- const clearable = clear && state.value;
3057
- const showHelper = type === "password" && !!state.value;
3087
+ useEffect(() => {
3088
+ setInputType(type);
3089
+ setVisible(false);
3090
+ }, [type]);
3091
+ const clearable = clear && inputValue;
3092
+ const showHelper = type === "password" && !!inputValue;
3058
3093
  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
3094
  [`i-input-${status}`]: status !== "normal",
3060
3095
  "i-input-borderless": !border,
3061
3096
  "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 })] }) }));
3097
+ }), 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
3098
  });
3064
3099
  Input.Textarea = Textarea;
3065
3100
  Input.Number = Number$1;
@@ -3347,38 +3382,34 @@ const displayValue = (config) => {
3347
3382
 
3348
3383
  const Select = (props) => {
3349
3384
  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
- });
3385
+ const [filterValue, setFilterValue] = useState("");
3386
+ const [selectedValue, setSelectedValue] = useState(value);
3356
3387
  const [active, setActive] = useState(false);
3357
3388
  const formattedOptions = useMemo(() => formatOption(options), [options]);
3358
3389
  const filterOptions = useMemo(() => {
3359
- const { filterValue: fv } = state;
3390
+ const fv = filterValue;
3360
3391
  if (!fv || !filter)
3361
3392
  return formattedOptions;
3362
3393
  const filterFn = typeof filter === "function"
3363
3394
  ? filter
3364
3395
  : (opt) => opt.value.includes(fv) || opt.label.includes(fv);
3365
3396
  return formattedOptions.filter(filterFn);
3366
- }, [formattedOptions, filter, state.filterValue]);
3397
+ }, [formattedOptions, filter, filterValue]);
3367
3398
  const changeValue = (v) => {
3368
- state.value = v;
3399
+ setSelectedValue(v);
3369
3400
  onChange?.(v);
3370
3401
  };
3371
3402
  const displayLabel = useMemo(() => {
3372
3403
  if (multiple) {
3373
3404
  return "";
3374
3405
  }
3375
- const option = formattedOptions.find((opt) => opt.value === state.value);
3376
- return option ? option.label : state.value;
3377
- }, [state.value, formattedOptions]);
3406
+ const option = formattedOptions.find((opt) => opt.value === selectedValue);
3407
+ return option ? option.label : selectedValue;
3408
+ }, [selectedValue, formattedOptions]);
3378
3409
  const handleSelect = (value, option) => {
3379
3410
  onSelect?.(value, option);
3380
3411
  if (multiple) {
3381
- const values = [...state.value];
3412
+ const values = [...selectedValue];
3382
3413
  const i = values.findIndex((v) => v === value);
3383
3414
  i > -1 ? values.splice(i, 1) : values.push(value);
3384
3415
  changeValue(values);
@@ -3391,7 +3422,7 @@ const Select = (props) => {
3391
3422
  setActive(visible);
3392
3423
  if (!filter)
3393
3424
  return;
3394
- state.filterValue = "";
3425
+ setFilterValue("");
3395
3426
  };
3396
3427
  const handleHelperClick = (e) => {
3397
3428
  e.stopPropagation();
@@ -3402,34 +3433,34 @@ const Select = (props) => {
3402
3433
  };
3403
3434
  const handleFilterChange = debounce({ delay: 400 }, (e) => {
3404
3435
  const v = e.target.value;
3405
- state.filterValue = v;
3436
+ setFilterValue(v);
3406
3437
  });
3407
3438
  const handleInputChange = (e) => {
3408
- state.filterValue = e.target.value;
3439
+ setFilterValue(e.target.value);
3409
3440
  };
3410
3441
  useEffect(() => {
3411
- state.value = value;
3442
+ setSelectedValue(value);
3412
3443
  }, [value]);
3413
3444
  const hasValue = multiple
3414
- ? state.value.length > 0
3415
- : !!state.value;
3445
+ ? selectedValue.length > 0
3446
+ : !!selectedValue;
3416
3447
  const clearable = !hideClear && active && hasValue;
3417
3448
  const text = message ?? tip;
3418
3449
  return (jsxs("label", { className: classNames("i-input-label", className, {
3419
3450
  "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", {
3451
+ }), 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
3452
  [`i-input-${status}`]: status !== "normal",
3422
3453
  "i-input-borderless": !border,
3423
3454
  "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", {
3455
+ }), 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
3456
  "i-select-multiple": multiple,
3426
3457
  }), children: displayValue({
3427
3458
  options: formattedOptions,
3428
- value: state.value,
3459
+ value: selectedValue,
3429
3460
  multiple,
3430
3461
  maxDisplay,
3431
3462
  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 })] }));
3463
+ }) })) : (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
3464
  };
3434
3465
 
3435
3466
  const ColorMethods = {
@@ -3439,23 +3470,21 @@ const ColorMethods = {
3439
3470
  };
3440
3471
  function Footer(props) {
3441
3472
  const { value, type, onTypeChange, onChange, onOk } = props;
3442
- const state = useReactive({
3443
- value,
3444
- type,
3445
- });
3473
+ const [inputValue, setInputValue] = useState(value);
3474
+ const [colorType, setColorType] = useState(type);
3446
3475
  const handleChange = (v) => {
3447
- state.value = v;
3476
+ setInputValue(v);
3448
3477
  onChange(v);
3449
3478
  };
3450
3479
  const handleTypeChange = (t) => {
3451
- state.type = t;
3480
+ setColorType(t);
3452
3481
  onTypeChange(t);
3453
3482
  };
3454
3483
  useEffect(() => {
3455
- state.value = value;
3456
- state.type = type;
3484
+ setInputValue(value);
3485
+ setColorType(type);
3457
3486
  }, [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, {}) }) })] }));
3487
+ 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
3488
  }
3460
3489
 
3461
3490
  const Handle = (props) => {
@@ -3465,48 +3494,51 @@ const Handle = (props) => {
3465
3494
 
3466
3495
  function ColorPicker(props) {
3467
3496
  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
- });
3497
+ const [colorType, setColorType] = useState(type);
3498
+ const [colorValue, setColorValue] = useState(value);
3499
+ const [syncValue, setSyncValue] = useState(value);
3500
+ const [visible, setVisible] = useState(popupProps?.visible);
3474
3501
  const handleChange = (target) => {
3475
- state.syncValue = target;
3502
+ setSyncValue(target);
3476
3503
  };
3477
3504
  const handleComplete = (target) => {
3478
- const method = ColorMethods[state.type];
3505
+ const method = ColorMethods[colorType];
3479
3506
  if (target.a !== 1) {
3480
3507
  target.a = parseFloat(target.a.toFixed(3));
3481
3508
  }
3482
- state.value = target[method]?.();
3509
+ setColorValue(target[method]?.());
3483
3510
  };
3484
3511
  const handleVisibleChange = (v) => {
3485
- state.visible = v;
3512
+ setVisible(v);
3486
3513
  popupProps?.onVisibleChange?.(v);
3487
3514
  };
3488
3515
  const handleTypeChange = (t) => {
3489
3516
  const method = ColorMethods[t];
3490
- state.type = t;
3491
- state.value = state.syncValue[method]?.();
3517
+ setColorType(t);
3518
+ setColorValue(syncValue?.[method]?.());
3492
3519
  };
3493
3520
  const handleValueChange = (v) => {
3494
- state.value = v;
3495
- state.syncValue = v;
3521
+ setColorValue(v);
3522
+ setSyncValue(v);
3496
3523
  };
3497
3524
  const handleOk = () => {
3498
- onChange?.(state.value);
3499
- state.visible = false;
3525
+ onChange?.(colorValue);
3526
+ setVisible(false);
3500
3527
  };
3501
3528
  useEffect(() => {
3502
- state.syncValue = value;
3503
- state.value = value;
3529
+ setSyncValue(value);
3530
+ setColorValue(value);
3504
3531
  }, [value]);
3532
+ useEffect(() => {
3533
+ if (popupProps?.visible !== undefined) {
3534
+ setVisible(popupProps.visible);
3535
+ }
3536
+ }, [popupProps?.visible]);
3505
3537
  if (usePanel) {
3506
3538
  return jsx(ColorsPanel, { ...props });
3507
3539
  }
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 })] }));
3540
+ return (jsx(Popup, { trigger: 'click', touchable: true, position: 'bottom', ...popupProps, visible: visible, content: jsx(ColorsPanel, { value: syncValue, disabledAlpha: disabledAlpha, panelRender: (panel) => {
3541
+ return (jsxs(Fragment, { children: [panel, jsx(Footer, { value: colorValue, type: colorType, onTypeChange: handleTypeChange, onChange: handleValueChange, onOk: handleOk })] }));
3510
3542
  }, onChange: handleChange, onChangeComplete: handleComplete }), onVisibleChange: handleVisibleChange, children: children ?? (jsx(Handle, { color: value, handle: handle, placeholder: placeholder })) }));
3511
3543
  }
3512
3544
 
@@ -3556,61 +3588,56 @@ const YearMonth = (props) => {
3556
3588
  };
3557
3589
  const Panel$1 = (props) => {
3558
3590
  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
- });
3591
+ const [today, setToday] = useState(value);
3592
+ const [month, setMonth] = useState(value || dayjs());
3593
+ const [selectedYear, setSelectedYear] = useState(dayjs());
3594
+ const [years, setYears] = useState([]);
3595
+ const [selectable, setSelectable] = useState(false);
3566
3596
  const $years = useRef(null);
3567
3597
  const handleOperateMonth = (next) => {
3568
- state.month = state.month[next ? "add" : "subtract"](1, "month");
3598
+ setMonth((m) => m[next ? "add" : "subtract"](1, "month"));
3569
3599
  };
3570
3600
  const handleChangeDate = (date) => {
3571
- if (date.isSame(state.today, "day"))
3601
+ if (date.isSame(today, "day"))
3572
3602
  return;
3573
- if (!date.isSame(state.month, "month")) {
3574
- state.month = date;
3603
+ if (!date.isSame(month, "month")) {
3604
+ setMonth(date);
3575
3605
  }
3576
- state.today = date;
3606
+ setToday(date);
3577
3607
  onDateClick?.(date);
3578
3608
  };
3579
3609
  const handleChangeMonth = (month) => {
3580
- state.month = state.month
3581
- .year(state.selectedYear.year())
3582
- .month(month - 1);
3583
- state.selectable = false;
3610
+ setMonth((m) => m.year(selectedYear.year()).month(month - 1));
3611
+ setSelectable(false);
3584
3612
  };
3585
3613
  const getMoreYears = throttle({ interval: 100 }, (e) => {
3586
3614
  const isUp = e.deltaY < 0;
3587
- state.years = state.years.map((y) => (y += isUp ? -1 : 1));
3615
+ setYears((ys) => ys.map((y) => y + (isUp ? -1 : 1)));
3588
3616
  });
3589
3617
  useEffect(() => {
3590
- if (!state.selectable)
3618
+ if (!selectable)
3591
3619
  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]);
3620
+ setSelectedYear(month);
3621
+ const y = month.year();
3622
+ const nextYears = Array.from({ length: 7 }).map((_, i) => y - 3 + i);
3623
+ setYears([...nextYears]);
3624
+ }, [selectable, month]);
3597
3625
  useEffect(() => {
3598
- state.today = value;
3599
- state.month = value || dayjs();
3626
+ setToday(value);
3627
+ setMonth(value || dayjs());
3600
3628
  }, [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,
3629
+ 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", {
3630
+ "i-datepicker-active": selectable,
3603
3631
  }), children: [jsx(Helpericon, { active: true, className: 'i-datepicker-close', onClick: (e) => {
3604
3632
  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) => {
3633
+ setSelectable(false);
3634
+ } }), jsx("div", { ref: $years, className: 'i-datepicker-years', onWheel: getMoreYears, children: years.map((y) => (jsx("a", { className: classNames("i-datepicker-year", {
3635
+ "i-datepicker-active": y === selectedYear.year(),
3636
+ }), onClick: () => setSelectedYear((sy) => sy.year(y)), children: renderYear(y) }, y))) }), jsx("div", { className: 'i-datepicker-months', children: MONTHS.map((m) => {
3610
3637
  return (jsx("a", { className: classNames("i-datepicker-month", {
3611
- "i-datepicker-active": m === state.month.month() + 1,
3638
+ "i-datepicker-active": m === month.month() + 1,
3612
3639
  }), onClick: () => handleChangeMonth(m), children: renderMonth(m) }, m));
3613
- }) })] }), jsx(Dates, { value: state.today, month: state.month, disabledDate: disabledDate, onDateClick: handleChangeDate, renderDate: renderDate })] }));
3640
+ }) })] }), jsx(Dates, { value: today, month: month, disabledDate: disabledDate, onDateClick: handleChangeDate, renderDate: renderDate })] }));
3614
3641
  };
3615
3642
 
3616
3643
  dayjs.extend(customParseFormat);
@@ -3618,29 +3645,27 @@ const FORMATTYPES = ["YYYY-MM-DD", "YYYY-M-D", "YYYY/MM/DD", "YYYY/M/D"];
3618
3645
  const FORMAT$1 = "YYYY-MM-DD";
3619
3646
  const Datepicker = (props) => {
3620
3647
  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
- });
3648
+ const [inputValue, setInputValue] = useState(value);
3624
3649
  const [active, setActive] = useState(false);
3625
3650
  const dayJsValue = useMemo(() => {
3626
- if (!state.value)
3651
+ if (!inputValue)
3627
3652
  return null;
3628
- const date = dayjs(state.value, format, true);
3653
+ const date = dayjs(inputValue, format, true);
3629
3654
  if (date.isValid())
3630
3655
  return date;
3631
3656
  return null;
3632
- }, [state.value]);
3657
+ }, [inputValue, format]);
3633
3658
  const handleDateClick = (date) => {
3634
3659
  handleChange(date.format(format));
3635
3660
  };
3636
3661
  const handleChange = (v) => {
3637
- state.value = v;
3662
+ setInputValue(v);
3638
3663
  onChange?.(v);
3639
3664
  };
3640
3665
  const handleSetDate = () => {
3641
- if (!state.value)
3666
+ if (!inputValue)
3642
3667
  return;
3643
- const date = dayjs(state.value, FORMATTYPES, true);
3668
+ const date = dayjs(inputValue, FORMATTYPES, true);
3644
3669
  if (date.isValid()) {
3645
3670
  handleChange(date.format(format));
3646
3671
  return;
@@ -3656,9 +3681,9 @@ const Datepicker = (props) => {
3656
3681
  setActive(v);
3657
3682
  };
3658
3683
  useEffect(() => {
3659
- state.value = value;
3684
+ setInputValue(value);
3660
3685
  }, [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 }) }));
3686
+ 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: 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
3687
  };
3663
3688
 
3664
3689
  function Items(props) {
@@ -3681,12 +3706,10 @@ const UnitMaps = {
3681
3706
  };
3682
3707
  function Panel(props) {
3683
3708
  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
- });
3709
+ const [period, setPeriod] = useState(undefined);
3710
+ const [hour, setHour] = useState(undefined);
3711
+ const [minute, setMinute] = useState(undefined);
3712
+ const [second, setSecond] = useState(undefined);
3690
3713
  const [hours, minutes, seconds] = useMemo(() => {
3691
3714
  const hasH = format.includes("h");
3692
3715
  const hasM = format.includes("m");
@@ -3702,29 +3725,45 @@ function Panel(props) {
3702
3725
  : [];
3703
3726
  return [hours, minutes, seconds];
3704
3727
  }, [stepH, stepM, stepS, format, periods]);
3705
- const updateValue = () => {
3728
+ const updateValue = (next) => {
3729
+ const nextPeriod = next?.period ?? period;
3730
+ const nextHour = next?.hour ?? hour;
3731
+ const nextMinute = next?.minute ?? minute;
3732
+ const nextSecond = next?.second ?? second;
3706
3733
  const reg = /(hh|h){1}|(mm|m){1}|(ss|s){1}/gi;
3707
3734
  let result = format.replace(reg, (pattern) => {
3708
3735
  const p = pattern.toLowerCase();
3709
3736
  const u = UnitMaps[p];
3710
- const n = state[u] ?? 0;
3737
+ const n = u === "hour"
3738
+ ? (nextHour ?? 0)
3739
+ : u === "minute"
3740
+ ? (nextMinute ?? 0)
3741
+ : (nextSecond ?? 0);
3711
3742
  return p.length > 1 && n < 10 ? `0${n ?? 0}` : n ?? 0;
3712
3743
  });
3713
3744
  if (periods && hours.length > 0) {
3714
- result = `${state.period ?? periods[0]} ${result}`;
3745
+ result = `${nextPeriod ?? periods[0]} ${result}`;
3715
3746
  }
3716
3747
  onChange(result);
3717
3748
  };
3718
3749
  const handleSetTime = (v, unit) => {
3719
- state[unit] = v;
3720
- updateValue();
3750
+ const next = { period, hour, minute, second, [unit]: v };
3751
+ if (unit === "period")
3752
+ setPeriod(v);
3753
+ if (unit === "hour")
3754
+ setHour(v);
3755
+ if (unit === "minute")
3756
+ setMinute(v);
3757
+ if (unit === "second")
3758
+ setSecond(v);
3759
+ updateValue(next);
3721
3760
  };
3722
3761
  useEffect(() => {
3723
3762
  let time = value ?? "";
3724
3763
  if (periods && hours.length > 0 && value) {
3725
3764
  const [p, t] = value.split(" ");
3726
3765
  time = t ?? "";
3727
- state.period = periods.includes(p) ? p : undefined;
3766
+ setPeriod(periods.includes(p) ? p : undefined);
3728
3767
  }
3729
3768
  const nums = time.match(/\d+/g) ?? [];
3730
3769
  if (!nums.length) {
@@ -3732,40 +3771,41 @@ function Panel(props) {
3732
3771
  return;
3733
3772
  }
3734
3773
  let i = 0;
3774
+ const parsed = {
3775
+ hour: undefined,
3776
+ minute: undefined,
3777
+ second: undefined,
3778
+ };
3735
3779
  const r = format.replace(/(hh|h)+|(mm|m)+|(ss|s)+/gi, (p) => {
3736
3780
  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;
3781
+ const o = Math.min(59, n);
3782
+ parsed[UnitMaps[p]] = o;
3743
3783
  return p.length > 1 && o < 10 ? `0${o}` : o;
3744
3784
  });
3785
+ setHour(parsed.hour);
3786
+ setMinute(parsed.minute);
3787
+ setSecond(parsed.second);
3745
3788
  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") }) }))] }));
3789
+ }, [value, format, hours.length, periods]);
3790
+ 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
3791
  }
3749
3792
 
3750
3793
  const FORMAT = "hh:mm:ss";
3751
3794
  function TimePicker(props) {
3752
3795
  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
- });
3796
+ const [timeValue, setTimeValue] = useState(value);
3797
+ const [safeValue, setSafeValue] = useState(undefined);
3757
3798
  const [active, setActive] = useState(false);
3758
3799
  const handleChange = (v) => {
3759
- state.value = v;
3800
+ setTimeValue(v);
3760
3801
  };
3761
3802
  const handleFallback = (v) => {
3762
- state.safeValue = v;
3803
+ setSafeValue(v);
3763
3804
  };
3764
3805
  const handleValidTime = () => {
3765
- if (!state.value)
3806
+ if (!timeValue)
3766
3807
  return;
3767
- state.value = state.safeValue;
3768
- handleChange(state.safeValue);
3808
+ setTimeValue(safeValue);
3769
3809
  };
3770
3810
  const handleBlur = (e) => {
3771
3811
  onBlur?.(e);
@@ -3776,9 +3816,9 @@ function TimePicker(props) {
3776
3816
  setActive(v);
3777
3817
  };
3778
3818
  useEffect(() => {
3779
- state.value = value;
3819
+ setTimeValue(value);
3780
3820
  }, [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 }) }));
3821
+ return (jsx(Popup, { visible: active, trigger: 'click', position: 'bottom', arrow: false, align: 'start', watchResize: true, ...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
3822
  }
3783
3823
 
3784
3824
  const defaultOk = {
@@ -3838,16 +3878,14 @@ function RadioItem(props) {
3838
3878
 
3839
3879
  function Radio(props) {
3840
3880
  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
- });
3881
+ const [selectedValue, setSelectedValue] = useState(value);
3844
3882
  const formattedOptions = useMemo(() => formatOption(options), [options]);
3845
3883
  const handleChange = (value, e) => {
3846
- state.value = value;
3884
+ setSelectedValue(value);
3847
3885
  onChange?.(value, e);
3848
3886
  };
3849
3887
  useEffect(() => {
3850
- state.value = value;
3888
+ setSelectedValue(value);
3851
3889
  }, [value]);
3852
3890
  return (jsxs("div", { className: classNames("i-radio i-input-label", {
3853
3891
  [`i-radio-${status}`]: status !== "normal",
@@ -3856,7 +3894,7 @@ function Radio(props) {
3856
3894
  "i-options-block": !optionInline,
3857
3895
  "i-radio-options-button": type === "button",
3858
3896
  }), children: formattedOptions.map((option) => {
3859
- const checked = state.value === option.value;
3897
+ const checked = selectedValue === option.value;
3860
3898
  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
3899
  }) })] }));
3862
3900
  }
@@ -4313,25 +4351,23 @@ const Tabs = ((props) => {
4313
4351
  const barRef = useRef(null);
4314
4352
  const navsRef = useRef(null);
4315
4353
  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
- });
4354
+ const [activeKey, setActiveKey] = useState(active);
4355
+ const [prevActiveKey, setPrevActiveKey] = useState(undefined);
4356
+ const [barStyle, setBarStyle] = useState({});
4357
+ const [cachedTabs, setCachedTabs] = useState([]);
4358
+ const [overflow, setOverflow] = useState(false);
4359
+ const [moreTabs, setMoreTabs] = useState([]);
4360
+ const [tabs, setTabs] = useState([]);
4325
4361
  const { observe, unobserve } = useIntersectionObserver();
4326
4362
  const size = useSize(navsRef);
4327
4363
  useEffect(() => {
4328
4364
  contentsRef.current.clear();
4329
4365
  if (!items) {
4330
4366
  if (!children) {
4331
- state.tabs = [];
4367
+ setTabs([]);
4332
4368
  return;
4333
4369
  }
4334
- state.tabs = Children.map(children, (node, i) => {
4370
+ setTabs(Children.map(children, (node, i) => {
4335
4371
  const { key, props: nodeProps } = node;
4336
4372
  const { title, children: tabChildren, content, keepDOM, closable, } = nodeProps;
4337
4373
  const tabKey = String(key ?? i);
@@ -4342,10 +4378,10 @@ const Tabs = ((props) => {
4342
4378
  keepDOM,
4343
4379
  closable,
4344
4380
  };
4345
- });
4381
+ }) ?? []);
4346
4382
  return;
4347
4383
  }
4348
- state.tabs = items.map((item, i) => {
4384
+ setTabs(items.map((item, i) => {
4349
4385
  if (["string", "number"].includes(typeof item)) {
4350
4386
  const key = String(item);
4351
4387
  return { key, title: item };
@@ -4357,90 +4393,99 @@ const Tabs = ((props) => {
4357
4393
  ...rest,
4358
4394
  key,
4359
4395
  };
4360
- });
4396
+ }));
4361
4397
  }, [children, items]);
4362
4398
  const add = (tab) => {
4363
- const tkey = String(tab.key ?? state.tabs.length);
4364
- const i = state.tabs.findIndex((t) => t.key === tkey);
4399
+ const tkey = String(tab.key ?? tabs.length);
4400
+ const i = tabs.findIndex((t) => t.key === tkey);
4365
4401
  if (i > -1) {
4366
- open(state.tabs[i].key ?? `${i}`);
4402
+ open(tabs[i].key ?? `${i}`);
4367
4403
  return;
4368
4404
  }
4369
4405
  contentsRef.current.set(tkey, tab.content);
4370
4406
  const { content, ...rest } = tab;
4371
- state.tabs.push({ ...rest, key: tkey });
4407
+ setTabs((ts) => [...ts, { ...rest, key: tkey }]);
4372
4408
  open(tkey);
4373
4409
  };
4374
4410
  const close = (key) => {
4375
- const i = state.tabs.findIndex((t) => t.key === key);
4411
+ const i = tabs.findIndex((t) => t.key === key);
4376
4412
  if (i < 0)
4377
4413
  return;
4378
4414
  contentsRef.current.delete(key);
4379
- state.tabs.splice(i, 1);
4380
- if (state.active !== key)
4415
+ const nextTabs = [...tabs];
4416
+ nextTabs.splice(i, 1);
4417
+ setTabs(nextTabs);
4418
+ if (activeKey !== key)
4381
4419
  return;
4382
- const next = state.tabs[i] || state.tabs[i - 1];
4383
- open(state.prevActive ?? next?.key ?? "");
4420
+ const next = nextTabs[i] || nextTabs[i - 1];
4421
+ open(prevActiveKey ?? next?.key ?? "");
4384
4422
  };
4385
4423
  const open = (key) => {
4386
- if (key === state.active) {
4424
+ if (key === activeKey) {
4387
4425
  if (!toggable)
4388
4426
  return;
4389
4427
  onTabChange?.(undefined, key);
4390
- state.active = undefined;
4391
- state.barStyle = {
4428
+ setActiveKey(undefined);
4429
+ setBarStyle({
4392
4430
  height: 0,
4393
4431
  width: 0,
4394
- };
4432
+ });
4395
4433
  return;
4396
4434
  }
4397
- state.prevActive = state.active;
4398
- onTabChange?.(key, state.active);
4399
- state.active = key;
4435
+ setPrevActiveKey(activeKey);
4436
+ onTabChange?.(key, activeKey);
4437
+ setActiveKey(key);
4400
4438
  };
4401
4439
  useEffect(() => {
4402
4440
  if (!size || hideMore || !observe)
4403
4441
  return;
4404
4442
  const { scrollHeight, scrollWidth } = navsRef.current;
4405
4443
  const { width, height } = size;
4406
- state.overflow = scrollHeight > height || scrollWidth > width;
4407
- if (!state.overflow)
4444
+ const nextOverflow = scrollHeight > height || scrollWidth > width;
4445
+ setOverflow(nextOverflow);
4446
+ if (!nextOverflow)
4408
4447
  return;
4409
4448
  navRefs.current.map((nav, i) => {
4410
4449
  if (!nav)
4411
4450
  return;
4412
4451
  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);
4452
+ setTabs((ts) => {
4453
+ if (!ts[i])
4454
+ return ts;
4455
+ const nextTabs = ts.map((t, idx) => idx === i ? { ...t, intersecting: visible } : t);
4456
+ setMoreTabs(nextTabs.filter((tab) => !tab.intersecting));
4457
+ return nextTabs;
4458
+ });
4417
4459
  });
4418
4460
  });
4419
- }, [size, hideMore, state.tabs.length]);
4461
+ }, [size, hideMore, tabs.length, observe]);
4420
4462
  useEffect(() => {
4421
- if (!bar || type === "pane" || state.active === undefined) {
4463
+ if (!bar || type === "pane" || activeKey === undefined) {
4422
4464
  return;
4423
4465
  }
4424
- const index = state.tabs.findIndex((tab) => tab.key === state.active);
4466
+ const index = tabs.findIndex((tab) => tab.key === activeKey);
4425
4467
  setTimeout(() => {
4426
4468
  const nav = navRefs.current[index];
4427
4469
  if (!nav)
4428
4470
  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);
4471
+ if (tabs[index]?.keepDOM && activeKey) {
4472
+ setCachedTabs((keys) => {
4473
+ if (keys.includes(activeKey))
4474
+ return keys;
4475
+ return [activeKey, ...keys];
4476
+ });
4432
4477
  }
4433
4478
  const { offsetHeight, offsetLeft, offsetTop, offsetWidth } = nav;
4434
4479
  const isLine = type === "line";
4435
- state.barStyle = {
4480
+ setBarStyle({
4436
4481
  height: !vertical && isLine ? ".25em" : offsetHeight,
4437
4482
  width: vertical && isLine ? ".25em" : offsetWidth,
4438
4483
  transform: `translate(${offsetLeft}px, ${offsetTop}px)`,
4439
- };
4484
+ });
4440
4485
  }, 16);
4441
- }, [state.active, bar, size]);
4486
+ }, [activeKey, bar, size, tabs, type, vertical]);
4442
4487
  useEffect(() => {
4443
- if (active === undefined || state.active === active)
4488
+ if (active === undefined || activeKey === active)
4444
4489
  return;
4445
4490
  open(active);
4446
4491
  }, [active]);
@@ -4450,7 +4495,7 @@ const Tabs = ((props) => {
4450
4495
  return () => {
4451
4496
  navRefs.current?.map(unobserve);
4452
4497
  };
4453
- }, [state.tabs.length]);
4498
+ }, [tabs.length, hideMore, unobserve]);
4454
4499
  useEffect(() => {
4455
4500
  if (!navsRef.current || vertical)
4456
4501
  return;
@@ -4480,26 +4525,26 @@ const Tabs = ((props) => {
4480
4525
  }));
4481
4526
  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
4527
  "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) => {
4528
+ }), children: [prepend, jsxs("div", { ref: navsRef, className: classNames("i-tab-navs", `justify-${navsJustify}`), children: [tabs.map((tab, i) => {
4484
4529
  const { title, key = `${i}`, closable } = tab;
4485
4530
  return (jsxs("a", { ref: (ref) => (navRefs.current[i] = ref), className: classNames("i-tab-nav", {
4486
- "i-tab-active": state.active === key,
4531
+ "i-tab-active": activeKey === key,
4487
4532
  }), onClick: () => open(key), children: [title, closable && (jsx(Helpericon, { as: 'i', active: true, className: 'i-tab-nav-close', onClick: (e) => {
4488
4533
  e.stopPropagation();
4489
4534
  close(key);
4490
4535
  } }))] }, 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) => {
4536
+ }), 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
4537
  const { key = `${i}`, title } = tab;
4493
- const isActive = state.active === key;
4538
+ const isActive = activeKey === key;
4494
4539
  return (jsx("a", { className: classNames("i-tab-nav", {
4495
4540
  "i-tab-active": isActive,
4496
4541
  }), onClick: () => open(key), children: title }, key));
4497
- }) }), children: renderMore(state.more) })), append] }), jsx("div", { className: 'i-tab-contents', children: state.tabs.map((tab, i) => {
4542
+ }) }), children: renderMore(moreTabs) })), append] }), jsx("div", { className: 'i-tab-contents', children: tabs.map((tab, i) => {
4498
4543
  const key = tab.key ?? `${i}`;
4499
4544
  const content = contentsRef.current.get(key);
4500
- const isActive = state.active === key;
4545
+ const isActive = activeKey === key;
4501
4546
  const show = isActive ||
4502
- (key !== undefined && state.cachedTabs.includes(key));
4547
+ (key !== undefined && cachedTabs.includes(key));
4503
4548
  return (show && (jsx("div", { className: classNames("i-tab-content", {
4504
4549
  "i-tab-active": isActive,
4505
4550
  }), children: content }, key)));
@@ -4578,14 +4623,12 @@ const defaultNodeProps = {
4578
4623
  };
4579
4624
  const Tree = (props) => {
4580
4625
  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
- });
4626
+ const [selectedKey, setSelectedKey] = useState(selected);
4627
+ const [checkedKeys, setCheckedKeys] = useState(checked);
4628
+ const [partofs, setPartofs] = useState({});
4629
+ const nodeMapsRef = useRef(new Map());
4587
4630
  const oNodeProps = Object.assign({}, defaultNodeProps, nodeProps);
4588
- const isChecked = (key) => state.checked.includes(key || "");
4631
+ const isChecked = (key) => checkedKeys.includes(key || "");
4589
4632
  const checkItem = (item, checked, direction) => {
4590
4633
  const { key = "", parent, children } = item;
4591
4634
  const shouldChanged = { [key]: checked };
@@ -4637,29 +4680,30 @@ const Tree = (props) => {
4637
4680
  const handleCheck = (item, checked) => {
4638
4681
  const [shouldChanged, partofs] = checkItem(item, checked);
4639
4682
  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);
4683
+ const nextChecked = checked
4684
+ ? Array.from(new Set([...checkedKeys, ...changedKeys]))
4685
+ : checkedKeys.filter((k) => !changedKeys.includes(k));
4686
+ setCheckedKeys(nextChecked);
4687
+ setPartofs((p) => ({ ...p, ...partofs }));
4688
+ onItemCheck?.(item, checked, nextChecked);
4645
4689
  };
4646
4690
  const handleSelect = (key, item) => {
4647
4691
  if (!props.selectable)
4648
4692
  return;
4649
- state.selected = key;
4693
+ setSelectedKey(key);
4650
4694
  onItemSelect?.(key, item);
4651
4695
  };
4652
4696
  useEffect(() => {
4653
4697
  if (selected === undefined)
4654
4698
  return;
4655
- state.selected = selected;
4699
+ setSelectedKey(selected);
4656
4700
  }, [selected]);
4657
4701
  useEffect(() => {
4658
- state.nodeMaps.clear();
4702
+ nodeMapsRef.current.clear();
4659
4703
  const { key, children } = oNodeProps;
4660
4704
  const recursive = (nodes) => {
4661
4705
  nodes.map((o) => {
4662
- state.nodeMaps.set(o[key], o);
4706
+ nodeMapsRef.current.set(o[key], o);
4663
4707
  o[children]?.length > 0 && recursive(o[children]);
4664
4708
  });
4665
4709
  };
@@ -4669,22 +4713,22 @@ const Tree = (props) => {
4669
4713
  return {
4670
4714
  getChecked: () => {
4671
4715
  const items = [];
4672
- state.checked.map((k) => {
4673
- const item = state.nodeMaps.get(k);
4716
+ checkedKeys.map((k) => {
4717
+ const item = nodeMapsRef.current.get(k);
4674
4718
  items.push(item);
4675
4719
  });
4676
- return [state.checked, items];
4720
+ return [checkedKeys, items];
4677
4721
  },
4678
4722
  getSelected: () => {
4679
- const item = state.nodeMaps.get(state.selected);
4680
- return [state.selected, item];
4723
+ const item = nodeMapsRef.current.get(selectedKey);
4724
+ return [selectedKey, item];
4681
4725
  },
4682
4726
  getPartofs: () => {
4683
4727
  const items = [];
4684
- const keys = Object.keys(state.partofs).filter((k) => {
4685
- const indeterminate = state.partofs[k];
4728
+ const keys = Object.keys(partofs).filter((k) => {
4729
+ const indeterminate = partofs[k];
4686
4730
  if (indeterminate) {
4687
- const item = state.nodeMaps.get(k);
4731
+ const item = nodeMapsRef.current.get(k);
4688
4732
  items.push(item);
4689
4733
  }
4690
4734
  return indeterminate;
@@ -4693,7 +4737,7 @@ const Tree = (props) => {
4693
4737
  },
4694
4738
  };
4695
4739
  });
4696
- return (jsx(TreeList, { data: data, selected: state.selected, checked: state.checked, partofs: state.partofs, nodeProps: oNodeProps, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
4740
+ return (jsx(TreeList, { data: data, selected: selectedKey, checked: checkedKeys, partofs: partofs, nodeProps: oNodeProps, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
4697
4741
  };
4698
4742
 
4699
4743
  const ListContainer = (props) => {
@@ -4746,12 +4790,8 @@ const FileListItem = (props) => {
4746
4790
 
4747
4791
  const Upload = (props) => {
4748
4792
  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
- });
4793
+ const [fileList, setFileListState] = useState(files);
4794
+ const [uploadMessage, setUploadMessage] = useState(message);
4755
4795
  const inputRef = useRef(null);
4756
4796
  const preview = usePreview();
4757
4797
  const defBtnProps = Object.assign({
@@ -4769,7 +4809,7 @@ const Upload = (props) => {
4769
4809
  }, [mode, children]);
4770
4810
  const handleChange = (e) => {
4771
4811
  const files = Array.from(e.target.files || []);
4772
- const { files: before } = state;
4812
+ const before = fileList;
4773
4813
  const changed = [];
4774
4814
  files.map((f) => {
4775
4815
  const { id, name, size, type } = f;
@@ -4786,21 +4826,20 @@ const Upload = (props) => {
4786
4826
  !same && changed.push(f);
4787
4827
  });
4788
4828
  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);
4829
+ const last = after.at(-1);
4830
+ const nextFiles = multiple ? after.slice(0, limit) : last ? [last] : [];
4831
+ setFileListState(nextFiles);
4832
+ setUploadMessage(message);
4833
+ onFilesChange?.(nextFiles, changed, e);
4834
+ onChange?.(nextFiles, e);
4796
4835
  handleUpload(changed);
4797
4836
  inputRef.current && (inputRef.current.value = "");
4798
4837
  };
4799
4838
  const handleRemove = (i) => {
4800
- const [...files] = state.files;
4839
+ const [...files] = fileList;
4801
4840
  const changed = files.splice(i, 1);
4802
4841
  URL.revokeObjectURL(changed[0]?.src || "");
4803
- state.files = files;
4842
+ setFileListState(files);
4804
4843
  onFilesChange?.(files, changed);
4805
4844
  onChange?.(files);
4806
4845
  inputRef.current && (inputRef.current.value = "");
@@ -4813,44 +4852,43 @@ const Upload = (props) => {
4813
4852
  return onUpload?.(result);
4814
4853
  };
4815
4854
  const handlePreview = (i) => {
4816
- preview({ items: state.files, initial: i });
4855
+ preview({ items: fileList, initial: i });
4817
4856
  };
4818
4857
  const setFileList = (files) => {
4819
4858
  if (!files)
4820
4859
  return;
4821
- state.files = files.map((f) => {
4822
- return { ...f, id: f.id ?? uid(7) };
4823
- });
4860
+ setFileListState(files.map((f) => {
4861
+ const file = f;
4862
+ return { ...file, id: file.id ?? uid(7) };
4863
+ }));
4824
4864
  };
4825
4865
  const handleSortEnd = (before, after) => {
4826
- const [...files] = state.files;
4827
- state.files = arrayMove(files, before, after);
4828
- onChange?.(state.files);
4866
+ const [...files] = fileList;
4867
+ const nextFiles = arrayMove(files, before, after);
4868
+ setFileListState(nextFiles);
4869
+ onChange?.(nextFiles);
4829
4870
  };
4830
4871
  useEffect(() => {
4831
- Object.assign(state, {
4832
- status,
4833
- message,
4834
- });
4872
+ setUploadMessage(message);
4835
4873
  }, [status, message]);
4836
4874
  useEffect(() => {
4837
- state.files = value?.filter?.((file) => !!file.id) ?? [];
4875
+ setFileListState(value?.filter?.((file) => !!file.id) ?? []);
4838
4876
  }, [value]);
4839
4877
  useEffect(() => {
4840
4878
  setFileList(initialFiles);
4841
4879
  }, []);
4842
4880
  useImperativeHandle(ref, () => ({
4843
- getFileList: () => state.files,
4881
+ getFileList: () => fileList,
4844
4882
  setFileList,
4845
- }), []);
4883
+ }), [fileList]);
4846
4884
  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
4885
  [`i-upload-${mode}`]: mode !== "default",
4848
- }), style: { ["--upload-card-size"]: cardSize }, children: [jsx(ListContainer, { sortable: sortable, onSortEnd: handleSortEnd, children: state.files.map((file, i) => {
4886
+ }), style: { ["--upload-card-size"]: cardSize }, children: [jsx(ListContainer, { sortable: sortable, onSortEnd: handleSortEnd, children: fileList.map((file, i) => {
4849
4887
  const node = (jsx(FileListItem, { index: i, file: file, mode: mode, renderItem: renderItem, onRemove: handleRemove, onPreview: handlePreview }, i));
4850
4888
  if (!sortable)
4851
4889
  return node;
4852
4890
  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] }))] }) }));
4891
+ }) }), 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
4892
  };
4855
4893
 
4856
4894
  const useTheme = (props) => {