@ioca/react 1.5.9 → 1.5.10

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 (229) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +33 -31
  3. package/lib/cjs/components/affix/affix.js.map +1 -1
  4. package/lib/cjs/components/affix/totop.js.map +1 -1
  5. package/lib/cjs/components/badge/badge.js.map +1 -1
  6. package/lib/cjs/components/button/button.js.map +1 -1
  7. package/lib/cjs/components/button/confirm.js.map +1 -1
  8. package/lib/cjs/components/button/group.js.map +1 -1
  9. package/lib/cjs/components/button/toggle.js.map +1 -1
  10. package/lib/cjs/components/card/card.js.map +1 -1
  11. package/lib/cjs/components/checkbox/checkbox.js +1 -1
  12. package/lib/cjs/components/checkbox/checkbox.js.map +1 -1
  13. package/lib/cjs/components/checkbox/item.js.map +1 -1
  14. package/lib/cjs/components/collapse/collapse.js.map +1 -1
  15. package/lib/cjs/components/collapse/item.js.map +1 -1
  16. package/lib/cjs/components/datagrid/cell.js +5 -2
  17. package/lib/cjs/components/datagrid/cell.js.map +1 -1
  18. package/lib/cjs/components/datagrid/datagrid.js +148 -50
  19. package/lib/cjs/components/datagrid/datagrid.js.map +1 -1
  20. package/lib/cjs/components/datagrid/helper.js +83 -0
  21. package/lib/cjs/components/datagrid/helper.js.map +1 -0
  22. package/lib/cjs/components/datagrid/resize.js +35 -7
  23. package/lib/cjs/components/datagrid/resize.js.map +1 -1
  24. package/lib/cjs/components/datagrid/row.js +17 -3
  25. package/lib/cjs/components/datagrid/row.js.map +1 -1
  26. package/lib/cjs/components/datagrid/sorter.js.map +1 -1
  27. package/lib/cjs/components/datagrid/virtual.js +283 -0
  28. package/lib/cjs/components/datagrid/virtual.js.map +1 -0
  29. package/lib/cjs/components/description/description.js.map +1 -1
  30. package/lib/cjs/components/drawer/drawer.js.map +1 -1
  31. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  32. package/lib/cjs/components/dropdown/item.js.map +1 -1
  33. package/lib/cjs/components/editor/controls.js.map +1 -1
  34. package/lib/cjs/components/editor/editor.js +5 -0
  35. package/lib/cjs/components/editor/editor.js.map +1 -1
  36. package/lib/cjs/components/editor/memtion.js.map +1 -1
  37. package/lib/cjs/components/flex/flex.js.map +1 -1
  38. package/lib/cjs/components/form/context.js.map +1 -1
  39. package/lib/cjs/components/form/field.js.map +1 -1
  40. package/lib/cjs/components/form/form.js.map +1 -1
  41. package/lib/cjs/components/form/useConfig.js.map +1 -1
  42. package/lib/cjs/components/form/useForm.js.map +1 -1
  43. package/lib/cjs/components/icon/icon.js.map +1 -1
  44. package/lib/cjs/components/image/image.js.map +1 -1
  45. package/lib/cjs/components/image/list.js.map +1 -1
  46. package/lib/cjs/components/input/container.js.map +1 -1
  47. package/lib/cjs/components/input/input.js.map +1 -1
  48. package/lib/cjs/components/input/number.js.map +1 -1
  49. package/lib/cjs/components/input/range.js.map +1 -1
  50. package/lib/cjs/components/input/textarea.js.map +1 -1
  51. package/lib/cjs/components/list/item.js.map +1 -1
  52. package/lib/cjs/components/list/list.js.map +1 -1
  53. package/lib/cjs/components/loading/loading.js.map +1 -1
  54. package/lib/cjs/components/message/message.js.map +1 -1
  55. package/lib/cjs/components/modal/content.js.map +1 -1
  56. package/lib/cjs/components/modal/context.js.map +1 -1
  57. package/lib/cjs/components/modal/hookModal.js.map +1 -1
  58. package/lib/cjs/components/modal/modal.js.map +1 -1
  59. package/lib/cjs/components/modal/useModal.js.map +1 -1
  60. package/lib/cjs/components/pagination/page.js.map +1 -1
  61. package/lib/cjs/components/pagination/pagination.js.map +1 -1
  62. package/lib/cjs/components/picker/colors/footer.js.map +1 -1
  63. package/lib/cjs/components/picker/colors/handle.js.map +1 -1
  64. package/lib/cjs/components/picker/colors/index.js.map +1 -1
  65. package/lib/cjs/components/picker/dates/dates.js.map +1 -1
  66. package/lib/cjs/components/picker/dates/index.js.map +1 -1
  67. package/lib/cjs/components/picker/dates/panel.js.map +1 -1
  68. package/lib/cjs/components/picker/time/index.js.map +1 -1
  69. package/lib/cjs/components/picker/time/item.js.map +1 -1
  70. package/lib/cjs/components/picker/time/panel.js.map +1 -1
  71. package/lib/cjs/components/popconfirm/popconfirm.js.map +1 -1
  72. package/lib/cjs/components/popup/content.js.map +1 -1
  73. package/lib/cjs/components/popup/popup.js.map +1 -1
  74. package/lib/cjs/components/progress/circle.js.map +1 -1
  75. package/lib/cjs/components/progress/line.js.map +1 -1
  76. package/lib/cjs/components/progress/progress.js.map +1 -1
  77. package/lib/cjs/components/radio/item.js.map +1 -1
  78. package/lib/cjs/components/radio/radio.js +2 -2
  79. package/lib/cjs/components/radio/radio.js.map +1 -1
  80. package/lib/cjs/components/resizable/resizable.js.map +1 -1
  81. package/lib/cjs/components/river/river.js.map +1 -1
  82. package/lib/cjs/components/select/options.js.map +1 -1
  83. package/lib/cjs/components/select/select.js.map +1 -1
  84. package/lib/cjs/components/step/divider.js.map +1 -1
  85. package/lib/cjs/components/step/item.js.map +1 -1
  86. package/lib/cjs/components/step/step.js.map +1 -1
  87. package/lib/cjs/components/swiper/item.js.map +1 -1
  88. package/lib/cjs/components/swiper/swiper.js.map +1 -1
  89. package/lib/cjs/components/tabs/item.js.map +1 -1
  90. package/lib/cjs/components/tabs/tabs.js.map +1 -1
  91. package/lib/cjs/components/tag/tag.js.map +1 -1
  92. package/lib/cjs/components/text/highlight.js.map +1 -1
  93. package/lib/cjs/components/text/number.js.map +1 -1
  94. package/lib/cjs/components/text/text.js.map +1 -1
  95. package/lib/cjs/components/text/time.js.map +1 -1
  96. package/lib/cjs/components/tree/item.js.map +1 -1
  97. package/lib/cjs/components/tree/tree.js.map +1 -1
  98. package/lib/cjs/components/upload/renderFile.js.map +1 -1
  99. package/lib/cjs/components/upload/upload.js.map +1 -1
  100. package/lib/cjs/components/utils/empty/index.js.map +1 -1
  101. package/lib/cjs/components/utils/helpericon/helpericon.js.map +1 -1
  102. package/lib/cjs/components/video/video.js.map +1 -1
  103. package/lib/cjs/js/hooks.js +7 -0
  104. package/lib/cjs/js/hooks.js.map +1 -1
  105. package/lib/cjs/js/usePreview/content.js.map +1 -1
  106. package/lib/cjs/js/usePreview/index.js.map +1 -1
  107. package/lib/cjs/js/usePreview/renderFile.js.map +1 -1
  108. package/lib/cjs/js/usePreview/type.js.map +1 -1
  109. package/lib/cjs/js/useRipple/index.js +6 -6
  110. package/lib/cjs/js/useRipple/index.js.map +1 -1
  111. package/lib/cjs/js/useTheme/index.js.map +1 -1
  112. package/lib/cjs/js/utils.js.map +1 -1
  113. package/lib/css/colors.css +784 -779
  114. package/lib/css/index.css +1 -2
  115. package/lib/css/index.css.map +1 -1
  116. package/lib/css/reset.css +59 -69
  117. package/lib/es/components/affix/affix.js.map +1 -1
  118. package/lib/es/components/affix/totop.js.map +1 -1
  119. package/lib/es/components/badge/badge.js.map +1 -1
  120. package/lib/es/components/button/button.js.map +1 -1
  121. package/lib/es/components/button/confirm.js.map +1 -1
  122. package/lib/es/components/button/group.js.map +1 -1
  123. package/lib/es/components/button/toggle.js.map +1 -1
  124. package/lib/es/components/card/card.js.map +1 -1
  125. package/lib/es/components/checkbox/checkbox.js +1 -1
  126. package/lib/es/components/checkbox/checkbox.js.map +1 -1
  127. package/lib/es/components/checkbox/item.js.map +1 -1
  128. package/lib/es/components/collapse/collapse.js.map +1 -1
  129. package/lib/es/components/collapse/item.js.map +1 -1
  130. package/lib/es/components/datagrid/cell.js +5 -2
  131. package/lib/es/components/datagrid/cell.js.map +1 -1
  132. package/lib/es/components/datagrid/datagrid.js +149 -51
  133. package/lib/es/components/datagrid/datagrid.js.map +1 -1
  134. package/lib/es/components/datagrid/helper.js +79 -0
  135. package/lib/es/components/datagrid/helper.js.map +1 -0
  136. package/lib/es/components/datagrid/resize.js +35 -7
  137. package/lib/es/components/datagrid/resize.js.map +1 -1
  138. package/lib/es/components/datagrid/row.js +17 -3
  139. package/lib/es/components/datagrid/row.js.map +1 -1
  140. package/lib/es/components/datagrid/sorter.js.map +1 -1
  141. package/lib/es/components/datagrid/virtual.js +275 -0
  142. package/lib/es/components/datagrid/virtual.js.map +1 -0
  143. package/lib/es/components/description/description.js.map +1 -1
  144. package/lib/es/components/drawer/drawer.js.map +1 -1
  145. package/lib/es/components/dropdown/dropdown.js.map +1 -1
  146. package/lib/es/components/dropdown/item.js.map +1 -1
  147. package/lib/es/components/editor/controls.js.map +1 -1
  148. package/lib/es/components/editor/editor.js +5 -0
  149. package/lib/es/components/editor/editor.js.map +1 -1
  150. package/lib/es/components/editor/memtion.js.map +1 -1
  151. package/lib/es/components/flex/flex.js.map +1 -1
  152. package/lib/es/components/form/context.js.map +1 -1
  153. package/lib/es/components/form/field.js.map +1 -1
  154. package/lib/es/components/form/form.js.map +1 -1
  155. package/lib/es/components/form/useConfig.js.map +1 -1
  156. package/lib/es/components/form/useForm.js.map +1 -1
  157. package/lib/es/components/icon/icon.js.map +1 -1
  158. package/lib/es/components/image/image.js.map +1 -1
  159. package/lib/es/components/image/list.js.map +1 -1
  160. package/lib/es/components/input/container.js.map +1 -1
  161. package/lib/es/components/input/input.js.map +1 -1
  162. package/lib/es/components/input/number.js.map +1 -1
  163. package/lib/es/components/input/range.js.map +1 -1
  164. package/lib/es/components/input/textarea.js.map +1 -1
  165. package/lib/es/components/list/item.js.map +1 -1
  166. package/lib/es/components/list/list.js.map +1 -1
  167. package/lib/es/components/loading/loading.js.map +1 -1
  168. package/lib/es/components/message/message.js.map +1 -1
  169. package/lib/es/components/modal/content.js.map +1 -1
  170. package/lib/es/components/modal/context.js.map +1 -1
  171. package/lib/es/components/modal/hookModal.js.map +1 -1
  172. package/lib/es/components/modal/modal.js.map +1 -1
  173. package/lib/es/components/modal/useModal.js.map +1 -1
  174. package/lib/es/components/pagination/page.js.map +1 -1
  175. package/lib/es/components/pagination/pagination.js.map +1 -1
  176. package/lib/es/components/picker/colors/footer.js.map +1 -1
  177. package/lib/es/components/picker/colors/handle.js.map +1 -1
  178. package/lib/es/components/picker/colors/index.js.map +1 -1
  179. package/lib/es/components/picker/dates/dates.js.map +1 -1
  180. package/lib/es/components/picker/dates/index.js.map +1 -1
  181. package/lib/es/components/picker/dates/panel.js.map +1 -1
  182. package/lib/es/components/picker/time/index.js.map +1 -1
  183. package/lib/es/components/picker/time/item.js.map +1 -1
  184. package/lib/es/components/picker/time/panel.js.map +1 -1
  185. package/lib/es/components/popconfirm/popconfirm.js.map +1 -1
  186. package/lib/es/components/popup/content.js.map +1 -1
  187. package/lib/es/components/popup/popup.js.map +1 -1
  188. package/lib/es/components/progress/circle.js.map +1 -1
  189. package/lib/es/components/progress/line.js.map +1 -1
  190. package/lib/es/components/progress/progress.js.map +1 -1
  191. package/lib/es/components/radio/item.js.map +1 -1
  192. package/lib/es/components/radio/radio.js +2 -2
  193. package/lib/es/components/radio/radio.js.map +1 -1
  194. package/lib/es/components/resizable/resizable.js.map +1 -1
  195. package/lib/es/components/river/river.js.map +1 -1
  196. package/lib/es/components/select/options.js.map +1 -1
  197. package/lib/es/components/select/select.js.map +1 -1
  198. package/lib/es/components/step/divider.js.map +1 -1
  199. package/lib/es/components/step/item.js.map +1 -1
  200. package/lib/es/components/step/step.js.map +1 -1
  201. package/lib/es/components/swiper/item.js.map +1 -1
  202. package/lib/es/components/swiper/swiper.js.map +1 -1
  203. package/lib/es/components/tabs/item.js.map +1 -1
  204. package/lib/es/components/tabs/tabs.js.map +1 -1
  205. package/lib/es/components/tag/tag.js.map +1 -1
  206. package/lib/es/components/text/highlight.js.map +1 -1
  207. package/lib/es/components/text/number.js.map +1 -1
  208. package/lib/es/components/text/text.js.map +1 -1
  209. package/lib/es/components/text/time.js.map +1 -1
  210. package/lib/es/components/tree/item.js.map +1 -1
  211. package/lib/es/components/tree/tree.js.map +1 -1
  212. package/lib/es/components/upload/renderFile.js.map +1 -1
  213. package/lib/es/components/upload/upload.js.map +1 -1
  214. package/lib/es/components/utils/empty/index.js.map +1 -1
  215. package/lib/es/components/utils/helpericon/helpericon.js.map +1 -1
  216. package/lib/es/components/video/video.js.map +1 -1
  217. package/lib/es/js/hooks.js +8 -1
  218. package/lib/es/js/hooks.js.map +1 -1
  219. package/lib/es/js/usePreview/content.js.map +1 -1
  220. package/lib/es/js/usePreview/index.js.map +1 -1
  221. package/lib/es/js/usePreview/renderFile.js.map +1 -1
  222. package/lib/es/js/usePreview/type.js.map +1 -1
  223. package/lib/es/js/useRipple/index.js +6 -6
  224. package/lib/es/js/useRipple/index.js.map +1 -1
  225. package/lib/es/js/useTheme/index.js.map +1 -1
  226. package/lib/es/js/utils.js.map +1 -1
  227. package/lib/index.js +563 -71
  228. package/lib/types/components/datagrid/type.d.ts +10 -1
  229. package/package.json +97 -98
package/lib/index.js CHANGED
@@ -1,9 +1,10 @@
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, useCallback, useEffect, useMemo, Children, cloneElement, createElement, isValidElement, Fragment as Fragment$1, useTransition, forwardRef, useLayoutEffect, memo, createContext, useContext, useImperativeHandle } from 'react';
4
+ import { useState, useRef, useEffect, useCallback, useMemo, Children, cloneElement, createElement, isValidElement, memo, Fragment as Fragment$1, useTransition, forwardRef, useLayoutEffect, createContext, useContext, useImperativeHandle } from 'react';
5
5
  import { SkipPreviousRound, CloseRound, MinusRound, PlusRound, InboxTwotone, UndoRound, RedoRound, FormatBoldRound, FormatItalicRound, FormatUnderlinedRound, StrikethroughSRound, ClearAllRound, 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
+ import { getScrollbarSize, List as List$2 } from 'react-window';
7
8
  import { createPortal } from 'react-dom';
8
9
  import xss from 'xss';
9
10
  import { renderToStaticMarkup } from 'react-dom/server';
@@ -36,12 +37,12 @@ function triggerRipple(target, e) {
36
37
  const [$box, $ripple] = createRipple();
37
38
  const rect = target.getBoundingClientRect();
38
39
  const size = Math.max(rect.width, rect.height) * 2;
39
- $ripple.style.cssText = `
40
- left: ${e.pageX - rect.left}px;
41
- top: ${e.pageY - rect.top}px;
42
- width: ${size}px;
43
- height: ${size}px;
44
- transition: all ${TIMEOUT / 1000}s;
40
+ $ripple.style.cssText = `
41
+ left: ${e.pageX - rect.left}px;
42
+ top: ${e.pageY - rect.top}px;
43
+ width: ${size}px;
44
+ height: ${size}px;
45
+ transition: all ${TIMEOUT / 1000}s;
45
46
  `;
46
47
  target.insertAdjacentElement("afterbegin", $box);
47
48
  target.offsetHeight;
@@ -71,6 +72,13 @@ const Loading = (props) => {
71
72
  }, children: jsx("circle", { cx: '12', cy: '12', r: '9.5', fill: 'none', strokeWidth: '3', strokeLinecap: 'round', strokeDasharray: 40, strokeDashoffset: 0 }) })), text] }));
72
73
  };
73
74
 
75
+ const os = window.navigator.platform;
76
+ if (os.toLowerCase().includes("mac")) {
77
+ document.documentElement.classList.add("os-mac");
78
+ }
79
+ else if (os.toLowerCase().includes("win")) {
80
+ document.documentElement.classList.add("os-windows");
81
+ }
74
82
  const MouseMoveEvents = new Set();
75
83
  const MouseUpEvents = new Set();
76
84
  const KeydownEvents = new Set();
@@ -892,7 +900,7 @@ function Checkbox(props) {
892
900
  return (jsxs("div", { className: classNames("i-checkbox i-input-label", {
893
901
  [`i-checkbox-${status}`]: status !== "normal",
894
902
  "i-input-inline": labelInline,
895
- }, className), ...restProps, children: [label && (jsxs("span", { className: 'i-input-label-text', children: [required && jsx("span", { className: 'error', children: "*" }), label, message && jsx("p", { className: 'i-checkbox-message', children: message })] })), jsx("div", { className: classNames("i-checkbox-options", {
903
+ }, className), ...restProps, children: [label && (jsxs("span", { className: "i-input-label-text", children: [required && jsx("span", { className: "error", children: "*" }), label, message && jsx("p", { className: "i-checkbox-message", children: message })] })), jsx("div", { className: classNames("i-checkbox-options", {
896
904
  "i-options-block": !optionInline,
897
905
  "i-checkbox-options-button": type === "button",
898
906
  }), children: formattedOptions.map((option) => {
@@ -988,6 +996,83 @@ function Empty(props) {
988
996
  return (jsx(InboxTwotone, { className: classNames("i-empty", className), ...restProps }));
989
997
  }
990
998
 
999
+ const lengthRe = /^-?\d+(\.\d+)?(px|em|rem|%|vw|vh|vmin|vmax|ch|ex|cm|mm|in|pt|pc)$/;
1000
+ const isLength = (v) => {
1001
+ if (v === "0")
1002
+ return true;
1003
+ if (v.startsWith("var(") || v.startsWith("calc("))
1004
+ return true;
1005
+ return lengthRe.test(v);
1006
+ };
1007
+ const sumLengths = (parts) => {
1008
+ let out = null;
1009
+ for (let i = 0; i < parts.length; i++) {
1010
+ const v = parts[i];
1011
+ if (!v || !isLength(v))
1012
+ continue;
1013
+ if (out == null)
1014
+ out = [v];
1015
+ else
1016
+ out.push(v);
1017
+ }
1018
+ if (out == null || out.length < 1)
1019
+ return "0";
1020
+ if (out.length === 1)
1021
+ return out[0];
1022
+ return `calc(${out.join(" + ")})`;
1023
+ };
1024
+ const toCssWidth = (w) => typeof w === "number" ? `${w}px` : w;
1025
+ const buildGridTemplateColumns = (widths, overrideIndex, overrideWidth) => {
1026
+ let out = "";
1027
+ for (let i = 0; i < widths.length; i++) {
1028
+ const w = i === overrideIndex && overrideWidth != null
1029
+ ? overrideWidth
1030
+ : widths[i];
1031
+ out += (i ? " " : "") + toCssWidth(w);
1032
+ }
1033
+ return out;
1034
+ };
1035
+ const buildCssWidths = (widths, overrideIndex, overrideWidth) => {
1036
+ const out = new Array(widths.length);
1037
+ for (let i = 0; i < widths.length; i++) {
1038
+ const w = i === overrideIndex && overrideWidth != null
1039
+ ? overrideWidth
1040
+ : widths[i];
1041
+ out[i] = toCssWidth(w);
1042
+ }
1043
+ return out;
1044
+ };
1045
+ const applyFixedInsets = (setVar, columns, cssWidths) => {
1046
+ for (let i = 0; i < columns.length; i++) {
1047
+ const fixed = columns[i]?.fixed;
1048
+ if (!fixed)
1049
+ continue;
1050
+ if (fixed === "left" && i === 0) {
1051
+ setVar(`--datagrid-cell-inset-0`, "0");
1052
+ continue;
1053
+ }
1054
+ if (fixed === "right" && i === columns.length - 1) {
1055
+ setVar(`--datagrid-cell-inset-${columns.length - 1}`, "auto 0");
1056
+ continue;
1057
+ }
1058
+ if (fixed === "left") {
1059
+ const parts = [];
1060
+ for (let j = 0; j < i; j++) {
1061
+ if (columns[j]?.fixed === "left")
1062
+ parts.push(cssWidths[j]);
1063
+ }
1064
+ setVar(`--datagrid-cell-inset-${i}`, `${sumLengths(parts)} auto`);
1065
+ continue;
1066
+ }
1067
+ const parts = [];
1068
+ for (let j = i + 1; j < columns.length; j++) {
1069
+ if (columns[j]?.fixed === "right")
1070
+ parts.push(cssWidths[j]);
1071
+ }
1072
+ setVar(`--datagrid-cell-inset-${i}`, `auto ${sumLengths(parts)}`);
1073
+ }
1074
+ };
1075
+
991
1076
  function getCellStyle({ justify, col, row, colSpan = 1, rowSpan = 1, }) {
992
1077
  const style = {
993
1078
  "--datagrid-justify": justify,
@@ -999,21 +1084,43 @@ function getCellStyle({ justify, col, row, colSpan = 1, rowSpan = 1, }) {
999
1084
  function Cell(props) {
1000
1085
  const { column, row, col, data, cellEllipsis, onCellClick, onCellDoubleClick, } = props;
1001
1086
  const { id, fixed, justify, rowSpan, render } = column;
1002
- const style = getCellStyle({ justify, col, row, rowSpan });
1087
+ const style = useMemo(() => getCellStyle({ justify, col, row, rowSpan }), [col, fixed, justify, row, rowSpan]);
1088
+ const handleClick = useCallback((e) => onCellClick?.(data, column, row, col, e), [col, column, data, onCellClick, row]);
1089
+ const handleDoubleClick = useCallback((e) => onCellDoubleClick?.(data, column, row, col, e), [col, column, data, onCellDoubleClick, row]);
1003
1090
  return (jsx("div", { className: classNames("i-datagrid-cell", {
1004
1091
  [`i-datagrid-cell-fixed-${fixed}`]: fixed,
1005
- }), "data-col": id, style: style, onClick: (e) => onCellClick?.(data, column, row, col, e), onDoubleClick: (e) => onCellDoubleClick?.(data, column, row, col, e), children: render?.(data[id], data, row, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1092
+ }), "data-col": id, style: style, onClick: handleClick, onDoubleClick: handleDoubleClick, children: render?.(data[id], data, row, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1006
1093
  "i-datagrid-cell-content-ellipsis": cellEllipsis,
1007
1094
  }), children: data[id] })) }));
1008
1095
  }
1009
1096
 
1010
- function Resize(props) {
1097
+ const Resize = memo(function Resize(props) {
1011
1098
  const { index, onWidthChange } = props;
1012
1099
  const state = useReactive({
1013
1100
  resizing: false,
1014
1101
  x: 0,
1015
1102
  width: 0,
1016
1103
  });
1104
+ const rafId = useRef(null);
1105
+ const nextWidth = useRef(null);
1106
+ useEffect(() => {
1107
+ return () => {
1108
+ if (rafId.current != null)
1109
+ cancelAnimationFrame(rafId.current);
1110
+ };
1111
+ }, []);
1112
+ const flush = useCallback(() => {
1113
+ rafId.current = null;
1114
+ if (nextWidth.current == null)
1115
+ return;
1116
+ onWidthChange(index, nextWidth.current, "preview");
1117
+ }, [index, onWidthChange]);
1118
+ const schedule = useCallback((w) => {
1119
+ nextWidth.current = w;
1120
+ if (rafId.current != null)
1121
+ return;
1122
+ rafId.current = requestAnimationFrame(flush);
1123
+ }, [flush]);
1017
1124
  const handleMouseDown = (e) => {
1018
1125
  const tar = e.target;
1019
1126
  const width = tar.offsetParent.offsetWidth;
@@ -1023,24 +1130,31 @@ function Resize(props) {
1023
1130
  width,
1024
1131
  });
1025
1132
  };
1026
- const handleMouseMove = (e) => {
1133
+ const handleMouseMove = useCallback((e) => {
1027
1134
  if (!state.resizing)
1028
1135
  return;
1029
1136
  e.preventDefault();
1030
1137
  const after = state.width + e.pageX - state.x;
1031
1138
  if (after <= 24)
1032
1139
  return;
1033
- onWidthChange(index, after);
1034
- };
1035
- const handleMouseUp = () => {
1140
+ schedule(after);
1141
+ }, [index, schedule, state]);
1142
+ const handleMouseUp = useCallback(() => {
1036
1143
  if (!state.resizing)
1037
1144
  return;
1038
1145
  state.resizing = false;
1039
- };
1146
+ const w = nextWidth.current;
1147
+ if (rafId.current != null)
1148
+ cancelAnimationFrame(rafId.current);
1149
+ rafId.current = null;
1150
+ if (w != null)
1151
+ onWidthChange(index, w, "commit");
1152
+ nextWidth.current = null;
1153
+ }, [index, onWidthChange, state]);
1040
1154
  useMouseMove(handleMouseMove);
1041
1155
  useMouseUp(handleMouseUp);
1042
1156
  return (jsx("i", { className: 'i-datagrid-resizor', onMouseDown: handleMouseDown, onClick: (e) => e.stopPropagation() }));
1043
- }
1157
+ });
1044
1158
 
1045
1159
  const Arrow = (props) => (jsx("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', ...props, children: jsx("g", { fill: 'none', children: jsx("path", { d: 'M9 17.898c0 1.074 1.265 1.648 2.073.941l6.31-5.522a1.75 1.75 0 0 0 0-2.634l-6.31-5.522C10.265 4.454 9 5.028 9 6.102v11.796z', fill: 'currentColor' }) }) }));
1046
1160
  function Sorter(props) {
@@ -1052,11 +1166,24 @@ function Sorter(props) {
1052
1166
 
1053
1167
  function Row(props) {
1054
1168
  const { row, data, columns, cellEllipsis, onRowClick, onCellClick, onCellDoubleClick, } = props;
1055
- return (jsx("div", { className: 'i-datagrid-row', onClick: () => onRowClick?.(data, row), children: columns.map((col, i) => (jsx(Cell, { column: col, col: i, row: row, data: data, cellEllipsis: cellEllipsis, onCellClick: onCellClick, onCellDoubleClick: onCellDoubleClick }, i))) }));
1169
+ const handleRowClick = useCallback(() => {
1170
+ onRowClick?.(data, row);
1171
+ }, [data, onRowClick, row]);
1172
+ return (jsx("div", { className: 'i-datagrid-row', onClick: handleRowClick, children: columns.map((col, i) => (jsx(Cell, { column: col, col: i, row: row, data: data, cellEllipsis: cellEllipsis, onCellClick: onCellClick, onCellDoubleClick: onCellDoubleClick }, i))) }));
1056
1173
  }
1057
1174
  function Header$1(props) {
1058
1175
  const { columns, resizable, cellEllipsis, sortBy, sortType, onWidthChange, onHeaderClick, } = props;
1059
- return (jsx("div", { className: 'i-datagrid-header i-datagrid-row', children: columns.map((column, col) => {
1176
+ const columnById = useMemo(() => {
1177
+ const map = new Map();
1178
+ columns.forEach((c) => map.set(c.id, c));
1179
+ return map;
1180
+ }, [columns]);
1181
+ const handleClick = useCallback((e) => {
1182
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1183
+ const id = el?.dataset?.col;
1184
+ onHeaderClick?.(id ? columnById.get(id) : undefined, e);
1185
+ }, [columnById, onHeaderClick]);
1186
+ return (jsx("div", { className: 'i-datagrid-header i-datagrid-row', onClick: handleClick, children: columns.map((column, col) => {
1060
1187
  const { id, title, fixed, colSpan, sorter, justify, renderHeader, } = column;
1061
1188
  const style = getCellStyle({
1062
1189
  justify,
@@ -1068,68 +1195,352 @@ function Header$1(props) {
1068
1195
  return (jsxs("div", { "data-col": id, className: classNames("i-datagrid-cell", {
1069
1196
  "i-datagrid-has-sorter": sorter,
1070
1197
  "i-datagrid-cell-fixed": fixed,
1071
- }), style: { ...style, insetBlockStart: 0 }, onClick: (e) => onHeaderClick?.(column, e), children: [renderHeader?.(column, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1198
+ }), style: { ...style, insetBlockStart: 0 }, children: [renderHeader?.(column, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1072
1199
  "i-datagrid-cell-content-ellipsis": cellEllipsis,
1073
1200
  }), children: title || id })), sorter && jsx(Sorter, { type: order }), resizable && (jsx(Resize, { index: col, onWidthChange: onWidthChange }))] }, col));
1074
1201
  }) }));
1075
1202
  }
1076
1203
 
1204
+ function VirtualDatagrid(props) {
1205
+ const { virtual, columns, rows, header, sortBy, sortType, height, loading, resizable, striped, cellEllipsis, empty, wrapRef, containerRef, onHeaderClick, onWidthChange, onRowClick, onCellClick, onCellDoubleClick, onScroll, } = props;
1206
+ const headerRef = useRef(null);
1207
+ const headerInnerRef = useRef(null);
1208
+ const listRef = useRef(null);
1209
+ const ro = useResizeObserver();
1210
+ const triggerRef = useRef({ rowCount: -1 });
1211
+ const [viewport, setViewport] = useState({ width: 0, height: 0 });
1212
+ const [contentWidth, setContentWidth] = useState(0);
1213
+ const rafRef = useRef({
1214
+ viewport: 0,
1215
+ contentWidth: 0,
1216
+ });
1217
+ const columnById = useMemo(() => {
1218
+ const map = new Map();
1219
+ columns.forEach((c) => map.set(c.id, c));
1220
+ return map;
1221
+ }, [columns]);
1222
+ const columnIndexById = useMemo(() => {
1223
+ const map = new Map();
1224
+ columns.forEach((c, i) => map.set(c.id, i));
1225
+ return map;
1226
+ }, [columns]);
1227
+ const getVirtualCellStyle = useCallback(({ justify, col, colSpan = 1, }) => {
1228
+ return {
1229
+ "--datagrid-justify": justify,
1230
+ gridColumn: `${col + 1} / span ${colSpan}`,
1231
+ insetInline: `var(--datagrid-cell-inset-${col})`,
1232
+ };
1233
+ }, []);
1234
+ const renderVirtualCell = useCallback(({ column, data, row, col, isHeader, }) => {
1235
+ const { id, fixed, justify, colSpan, render, title, sorter, renderHeader, } = column;
1236
+ const style = {
1237
+ ...getVirtualCellStyle({ justify, col, colSpan }),
1238
+ ...(isHeader ? { insetBlockStart: 0 } : null),
1239
+ };
1240
+ const order = isHeader && sortBy === id ? sortType : "";
1241
+ return (jsxs("div", { "data-col": id, className: classNames("i-datagrid-cell", {
1242
+ [`i-datagrid-cell-fixed-${fixed}`]: fixed,
1243
+ "i-datagrid-has-sorter": isHeader && sorter,
1244
+ }), style: style, children: [isHeader
1245
+ ? (renderHeader?.(column, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1246
+ "i-datagrid-cell-content-ellipsis": cellEllipsis,
1247
+ }), children: title || id })))
1248
+ : (render?.(data?.[id], data, row, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1249
+ "i-datagrid-cell-content-ellipsis": cellEllipsis,
1250
+ }), children: data?.[id] }))), isHeader && sorter && jsx(Sorter, { type: order }), isHeader && resizable && (jsx(Resize, { index: col, onWidthChange: onWidthChange }))] }, id));
1251
+ }, [
1252
+ cellEllipsis,
1253
+ getVirtualCellStyle,
1254
+ onWidthChange,
1255
+ resizable,
1256
+ sortBy,
1257
+ sortType,
1258
+ ]);
1259
+ const handleHeaderClick = useCallback((e) => {
1260
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1261
+ const id = el?.dataset?.col;
1262
+ onHeaderClick(id ? columnById.get(id) : undefined, e);
1263
+ }, [columnById, onHeaderClick]);
1264
+ const handleBodyScroll = useCallback((e) => {
1265
+ const el = e.currentTarget;
1266
+ if (!el)
1267
+ return;
1268
+ if (headerRef.current &&
1269
+ headerRef.current.scrollLeft !== el.scrollLeft) {
1270
+ headerRef.current.scrollLeft = el.scrollLeft;
1271
+ }
1272
+ }, []);
1273
+ const handleReachEnd = useCallback(() => {
1274
+ if (virtual.onReachEnd) {
1275
+ virtual.onReachEnd();
1276
+ return;
1277
+ }
1278
+ onScroll?.(undefined);
1279
+ }, [onScroll, virtual.onReachEnd]);
1280
+ const handleRowsRendered = useCallback((_visible, overscan) => {
1281
+ if (!virtual.hasMore)
1282
+ return;
1283
+ const threshold = virtual.threshold ?? 8;
1284
+ const stopIndex = overscan?.stopIndex ?? -1;
1285
+ if (stopIndex < rows.length - 1 - threshold)
1286
+ return;
1287
+ if (triggerRef.current.rowCount === rows.length)
1288
+ return;
1289
+ triggerRef.current.rowCount = rows.length;
1290
+ handleReachEnd();
1291
+ }, [handleReachEnd, rows.length, virtual.hasMore, virtual.threshold]);
1292
+ const handleHeaderScroll = useCallback((e) => {
1293
+ const el = e.currentTarget;
1294
+ if (!el)
1295
+ return;
1296
+ const listEl = listRef.current?.element;
1297
+ if (listEl && listEl.scrollLeft !== el.scrollLeft) {
1298
+ listEl.scrollLeft = el.scrollLeft;
1299
+ }
1300
+ }, []);
1301
+ const handleBodyClickCapture = useCallback((e, rowData, rowNum) => {
1302
+ if (!onCellClick)
1303
+ return;
1304
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1305
+ const id = el?.dataset?.col;
1306
+ if (!id)
1307
+ return;
1308
+ const column = columnById.get(id);
1309
+ const col = columnIndexById.get(id);
1310
+ if (!column || col == null)
1311
+ return;
1312
+ onCellClick(rowData, column, rowNum, col, e);
1313
+ }, [columnById, columnIndexById, onCellClick]);
1314
+ const handleBodyDoubleClickCapture = useCallback((e, rowData, rowNum) => {
1315
+ if (!onCellDoubleClick)
1316
+ return;
1317
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1318
+ const id = el?.dataset?.col;
1319
+ if (!id)
1320
+ return;
1321
+ const column = columnById.get(id);
1322
+ const col = columnIndexById.get(id);
1323
+ if (!column || col == null)
1324
+ return;
1325
+ onCellDoubleClick(rowData, column, rowNum, col, e);
1326
+ }, [columnById, columnIndexById, onCellDoubleClick]);
1327
+ useEffect(() => {
1328
+ const el = wrapRef.current;
1329
+ if (!el)
1330
+ return;
1331
+ const update = () => {
1332
+ if (rafRef.current.viewport)
1333
+ cancelAnimationFrame(rafRef.current.viewport);
1334
+ rafRef.current.viewport = requestAnimationFrame(() => {
1335
+ rafRef.current.viewport = 0;
1336
+ const r = el.getBoundingClientRect();
1337
+ const w = Math.round(r.width);
1338
+ const h = Math.round(r.height);
1339
+ setViewport((prev) => {
1340
+ if (prev.width === w && prev.height === h)
1341
+ return prev;
1342
+ return { width: w, height: h };
1343
+ });
1344
+ });
1345
+ };
1346
+ update();
1347
+ ro.observe?.(el, update);
1348
+ return () => {
1349
+ ro.unobserve?.(el);
1350
+ if (rafRef.current.viewport)
1351
+ cancelAnimationFrame(rafRef.current.viewport);
1352
+ rafRef.current.viewport = 0;
1353
+ };
1354
+ }, [ro, wrapRef]);
1355
+ useEffect(() => {
1356
+ const el = headerInnerRef.current;
1357
+ if (!el)
1358
+ return;
1359
+ const update = () => {
1360
+ if (rafRef.current.contentWidth) {
1361
+ cancelAnimationFrame(rafRef.current.contentWidth);
1362
+ }
1363
+ rafRef.current.contentWidth = requestAnimationFrame(() => {
1364
+ rafRef.current.contentWidth = 0;
1365
+ const w = Math.ceil(el.scrollWidth);
1366
+ setContentWidth((prev) => (prev === w ? prev : w));
1367
+ });
1368
+ };
1369
+ update();
1370
+ ro.observe?.(el, update);
1371
+ return () => {
1372
+ ro.unobserve?.(el);
1373
+ if (rafRef.current.contentWidth) {
1374
+ cancelAnimationFrame(rafRef.current.contentWidth);
1375
+ }
1376
+ rafRef.current.contentWidth = 0;
1377
+ };
1378
+ }, [ro]);
1379
+ useEffect(() => {
1380
+ triggerRef.current.rowCount = -1;
1381
+ }, [rows.length, virtual.hasMore]);
1382
+ useEffect(() => {
1383
+ if (!loading)
1384
+ return;
1385
+ const listEl = listRef.current?.element;
1386
+ listEl?.scrollTo({ top: 0, left: 0 });
1387
+ headerRef.current?.scrollTo({ top: 0, left: 0 });
1388
+ }, [loading]);
1389
+ const listHeight = Math.max(0, (typeof height === "number" ? height : viewport.height || 360) -
1390
+ (header ? virtual.rowHeight : 0));
1391
+ const hasVerticalScrollbar = rows.length * virtual.rowHeight > listHeight + 1;
1392
+ const scrollbarSize = hasVerticalScrollbar ? getScrollbarSize() : 0;
1393
+ const measuredContentWidth = Math.max(contentWidth, viewport.width || 0);
1394
+ const contentWidthPx = measuredContentWidth
1395
+ ? `${measuredContentWidth}px`
1396
+ : "fit-content";
1397
+ const headerCells = useMemo(() => columns.map((c, col) => renderVirtualCell({
1398
+ column: c,
1399
+ row: 0,
1400
+ col,
1401
+ isHeader: true,
1402
+ })), [columns, renderVirtualCell]);
1403
+ const headerInnerStyle = useMemo(() => ({
1404
+ display: "grid",
1405
+ gridTemplateColumns: "var(--grid-template-columns)",
1406
+ height: virtual.rowHeight,
1407
+ width: contentWidthPx,
1408
+ minWidth: "100%",
1409
+ }), [contentWidthPx, virtual.rowHeight]);
1410
+ const listStyle = useMemo(() => ({
1411
+ height: listHeight,
1412
+ width: "100%",
1413
+ overflow: "auto",
1414
+ }), [listHeight]);
1415
+ const headerWrapStyle = useMemo(() => scrollbarSize > 0
1416
+ ? {
1417
+ paddingRight: scrollbarSize,
1418
+ boxSizing: "content-box",
1419
+ }
1420
+ : undefined, [scrollbarSize]);
1421
+ const loaderNode = useMemo(() => virtual.loader ?? jsx(Loading, { className: 'my-12' }), [virtual.loader]);
1422
+ const rowComponent = useCallback(({ index, style: itemStyle }) => {
1423
+ if (index >= rows.length) {
1424
+ return (jsx("div", { style: {
1425
+ ...itemStyle,
1426
+ width: contentWidthPx,
1427
+ minWidth: "100%",
1428
+ display: "flex",
1429
+ alignItems: "center",
1430
+ justifyContent: "center",
1431
+ }, children: loaderNode }));
1432
+ }
1433
+ const rowData = rows[index];
1434
+ const rowNum = index + (header ? 1 : 0);
1435
+ const bg = striped && index % 2 === 0 ? "var(--background-1)" : undefined;
1436
+ return (jsx("div", { style: {
1437
+ ...itemStyle,
1438
+ width: contentWidthPx,
1439
+ minWidth: "100%",
1440
+ display: "grid",
1441
+ gridTemplateColumns: "var(--grid-template-columns)",
1442
+ height: virtual.rowHeight,
1443
+ "--datagrid-cell-background": bg,
1444
+ }, className: 'i-datagrid-row', onClickCapture: (e) => handleBodyClickCapture(e, rowData, rowNum), onDoubleClickCapture: (e) => handleBodyDoubleClickCapture(e, rowData, rowNum), onClick: () => onRowClick?.(rowData, rowNum), children: columns.map((c, col) => renderVirtualCell({
1445
+ column: c,
1446
+ data: rowData,
1447
+ row: rowNum,
1448
+ col,
1449
+ })) }));
1450
+ }, [
1451
+ columns,
1452
+ contentWidthPx,
1453
+ handleBodyClickCapture,
1454
+ handleBodyDoubleClickCapture,
1455
+ header,
1456
+ loaderNode,
1457
+ onRowClick,
1458
+ renderVirtualCell,
1459
+ rows,
1460
+ striped,
1461
+ virtual.rowHeight,
1462
+ ]);
1463
+ return (jsxs("div", { ref: containerRef, className: classNames("i-datagrid", {
1464
+ "i-datagrid-loading": loading,
1465
+ }), style: { display: "block", width: "100%", maxWidth: "100%" }, children: [header && (jsx("div", { ref: headerRef, className: 'i-datagrid-virtual-header', onScroll: handleHeaderScroll, style: headerWrapStyle, children: jsx("div", { ref: headerInnerRef, className: 'i-datagrid-header i-datagrid-row', style: headerInnerStyle, onClick: handleHeaderClick, children: headerCells }) })), jsx(List$2, { listRef: listRef, rowCount: rows.length + (virtual.hasMore ? 1 : 0), rowHeight: virtual.rowHeight, overscanCount: Math.max(3, virtual.threshold ?? 8), rowProps: {}, style: listStyle, onScroll: handleBodyScroll, onRowsRendered: handleRowsRendered, rowComponent: rowComponent }), rows.length < 1 && !virtual.hasMore && empty] }));
1466
+ }
1467
+
1077
1468
  const Datagrid = (props) => {
1078
- const { data = [], columns = [], border, striped, header = true, resizable, cellPadding = ".5em", cellEllipsis, empty = jsx(Empty, {}), loading, height = "unset", style, className, renderLoading = () => (jsx(Loading, { size: '1.5em', className: 'color-3', absolute: true })), onCellClick, onRowClick, onCellDoubleClick, onHeaderClick, onSort, onScroll, onResize, } = props;
1469
+ const { data = [], columns = [], border, striped, header = true, resizable, cellPadding = ".5em", cellEllipsis, empty = jsx(Empty, {}), loading, height = "unset", style, className, rowKey, virtual, renderLoading = () => (jsx(Loading, { size: '1.5em', className: 'color-3', absolute: true })), onCellClick, onRowClick, onCellDoubleClick, onHeaderClick, onSort, onScroll, onResize, } = props;
1079
1470
  const container = useRef(null);
1471
+ const wrapRef = useRef(null);
1080
1472
  const state = useReactive({
1081
1473
  rows: data,
1082
1474
  widths: columns.map((col) => col.width ?? "min-content"),
1083
1475
  sortBy: "",
1084
1476
  sortType: "",
1085
1477
  });
1478
+ const previewRef = useRef({ index: -1, width: -1, template: "" });
1479
+ useEffect(() => {
1480
+ const next = columns.map((col, i) => {
1481
+ if (col.width != null)
1482
+ return col.width;
1483
+ return state.widths[i] ?? "min-content";
1484
+ });
1485
+ let changed = next.length !== state.widths.length;
1486
+ if (!changed) {
1487
+ for (let i = 0; i < next.length; i++) {
1488
+ if (next[i] !== state.widths[i]) {
1489
+ changed = true;
1490
+ break;
1491
+ }
1492
+ }
1493
+ }
1494
+ if (changed)
1495
+ state.widths = next;
1496
+ }, [columns, state]);
1086
1497
  const styles = useMemo(() => {
1087
1498
  const { widths } = state;
1088
1499
  const o = {
1089
1500
  ...style,
1090
- "--grid-template-columns": widths
1091
- .map((w) => {
1092
- return typeof w === "number" ? `${w}px` : w;
1093
- })
1094
- .join(" "),
1501
+ "--grid-template-columns": buildGridTemplateColumns(widths),
1095
1502
  };
1096
1503
  if (!resizable)
1097
1504
  return o;
1098
- const fws = columns.map((col, i) => {
1099
- const { fixed } = col;
1100
- if (!fixed)
1101
- return 0;
1102
- return widths[i];
1103
- });
1104
- columns.map((col, i) => {
1105
- const { fixed } = col;
1106
- if (!fixed)
1505
+ const cssWidths = buildCssWidths(widths);
1506
+ applyFixedInsets((k, v) => {
1507
+ o[k] = v;
1508
+ }, columns, cssWidths);
1509
+ return o;
1510
+ }, [columns, resizable, state.widths, style]);
1511
+ const handleWidthChange = useCallback((i, w, phase = "commit") => {
1512
+ if (!resizable)
1513
+ return;
1514
+ if (phase === "preview") {
1515
+ const el = wrapRef.current;
1516
+ if (!el)
1517
+ return;
1518
+ if (previewRef.current.index === i &&
1519
+ previewRef.current.width === w) {
1107
1520
  return;
1108
- if (i === 0) {
1109
- o[`--datagrid-cell-inset-0`] = 0;
1110
1521
  }
1111
- else if (i === fws.length - 1) {
1112
- o[`--datagrid-cell-inset-${fws.length - 1}`] = "auto 0";
1522
+ const template = buildGridTemplateColumns(state.widths, i, w);
1523
+ if (previewRef.current.template !== template) {
1524
+ el.style.setProperty("--grid-template-columns", template);
1525
+ const cssWidths = buildCssWidths(state.widths, i, w);
1526
+ applyFixedInsets((k, v) => el.style.setProperty(k, v), columns, cssWidths);
1527
+ previewRef.current.template = template;
1113
1528
  }
1114
- else {
1115
- const isLeft = fixed === "left";
1116
- const before = isLeft ? fws.slice(0, i) : fws.slice(i + 1);
1117
- const sum = before.reduce((pre, cur) => pre + cur) + "px";
1118
- const result = isLeft ? `${sum} auto` : `auto ${sum}`;
1119
- o[`--datagrid-cell-inset-${i}`] = result;
1120
- }
1121
- });
1122
- return o;
1123
- }, [state.widths, resizable]);
1124
- const handleWidthChange = (i, w) => {
1125
- if (!resizable)
1529
+ previewRef.current.index = i;
1530
+ previewRef.current.width = w;
1126
1531
  return;
1127
- const [...ws] = state.widths;
1128
- ws[i] = w;
1129
- state.widths = ws;
1532
+ }
1533
+ previewRef.current.index = -1;
1534
+ previewRef.current.width = -1;
1535
+ previewRef.current.template = "";
1536
+ if (state.widths[i] === w)
1537
+ return;
1538
+ const next = [...state.widths];
1539
+ next[i] = w;
1540
+ state.widths = next;
1130
1541
  onResize?.(columns[i], w);
1131
- };
1132
- const handleHeaderClick = (column, e) => {
1542
+ }, [columns, onResize, resizable, state, wrapRef]);
1543
+ const handleHeaderClick = useCallback((column, e) => {
1133
1544
  if (column?.sorter) {
1134
1545
  const [sortBy, sortType] = getNextSorter(state.sortBy, state.sortType, column.id);
1135
1546
  Object.assign(state, {
@@ -1139,7 +1550,7 @@ const Datagrid = (props) => {
1139
1550
  onSort?.(sortBy, sortType);
1140
1551
  }
1141
1552
  onHeaderClick?.(column, e);
1142
- };
1553
+ }, [onHeaderClick, onSort, state]);
1143
1554
  const rows = useMemo(() => {
1144
1555
  const { sortBy, sortType } = state;
1145
1556
  if (sortBy && !onSort) {
@@ -1152,28 +1563,104 @@ const Datagrid = (props) => {
1152
1563
  }
1153
1564
  return data;
1154
1565
  }, [data, columns, state.sortBy, state.sortType]);
1566
+ const useVirtual = useMemo(() => {
1567
+ if (!virtual)
1568
+ return false;
1569
+ const rowHeight = virtual.rowHeight;
1570
+ return !!rowHeight && rowHeight > 0;
1571
+ }, [virtual]);
1155
1572
  useEffect(() => {
1573
+ if (!resizable)
1574
+ return;
1156
1575
  if (!container.current)
1157
1576
  return;
1158
- const { current: div } = container;
1159
- const tds = div.querySelector(".i-datagrid-row")?.children;
1160
- if (!tds?.length)
1577
+ if (!columns.some((col, i) => col.width == null && typeof state.widths[i] !== "number")) {
1161
1578
  return;
1162
- state.widths = Array.from(tds).map((node) => node.offsetWidth);
1163
- }, [columns, resizable]);
1579
+ }
1580
+ let rafId = null;
1581
+ let tries = 0;
1582
+ const run = () => {
1583
+ rafId = null;
1584
+ const div = container.current;
1585
+ if (!div)
1586
+ return;
1587
+ const headerRow = div.querySelector(".i-datagrid-header.i-datagrid-row");
1588
+ const bodyRow = div.querySelector(".i-datagrid-row:not(.i-datagrid-header)");
1589
+ const headerCells = headerRow ? Array.from(headerRow.children) : [];
1590
+ const bodyCells = bodyRow ? Array.from(bodyRow.children) : [];
1591
+ const cellCount = Math.max(headerCells.length, bodyCells.length);
1592
+ if (cellCount < 1) {
1593
+ tries++;
1594
+ if (tries < 10)
1595
+ rafId = requestAnimationFrame(run);
1596
+ return;
1597
+ }
1598
+ const measured = new Array(cellCount).fill(null);
1599
+ for (let i = 0; i < cellCount; i++) {
1600
+ const hw = headerCells[i]
1601
+ ?.offsetWidth;
1602
+ const bw = bodyCells[i]
1603
+ ?.offsetWidth;
1604
+ const w = Math.max(hw ?? 0, bw ?? 0);
1605
+ measured[i] = w > 0 ? w : null;
1606
+ }
1607
+ const next = columns.map((col, i) => {
1608
+ if (col.width != null)
1609
+ return col.width;
1610
+ const cur = state.widths[i];
1611
+ if (typeof cur === "number")
1612
+ return cur;
1613
+ return measured[i] ?? cur ?? "min-content";
1614
+ });
1615
+ let changed = next.length !== state.widths.length;
1616
+ if (!changed) {
1617
+ for (let i = 0; i < next.length; i++) {
1618
+ if (next[i] !== state.widths[i]) {
1619
+ changed = true;
1620
+ break;
1621
+ }
1622
+ }
1623
+ }
1624
+ if (changed)
1625
+ state.widths = next;
1626
+ };
1627
+ rafId = requestAnimationFrame(run);
1628
+ return () => {
1629
+ if (rafId != null)
1630
+ cancelAnimationFrame(rafId);
1631
+ };
1632
+ }, [columns, resizable, state, useVirtual]);
1164
1633
  useEffect(() => {
1165
- loading && container.current?.scrollTo({ top: 0, left: 0 });
1166
- }, [loading]);
1167
- const mergedStyle = {
1634
+ if (!loading)
1635
+ return;
1636
+ if (useVirtual)
1637
+ return;
1638
+ container.current?.scrollTo({ top: 0, left: 0 });
1639
+ }, [loading, useVirtual]);
1640
+ const mergedStyle = useMemo(() => ({
1168
1641
  "--cell-padding": cellPadding,
1169
1642
  ...styles,
1170
- };
1171
- return (jsxs("div", { style: { maxHeight: height, ...mergedStyle }, className: classNames("i-datagrid-container", className, {
1643
+ }), [cellPadding, styles]);
1644
+ const getRowKey = useMemo(() => {
1645
+ if (typeof rowKey === "function")
1646
+ return rowKey;
1647
+ if (typeof rowKey === "string") {
1648
+ return (row) => row?.[rowKey];
1649
+ }
1650
+ return (_row, index) => index;
1651
+ }, [rowKey]);
1652
+ return (jsxs("div", { ref: wrapRef, style: {
1653
+ maxHeight: height,
1654
+ ...(useVirtual
1655
+ ? { overflowX: "visible", overflowY: "hidden" }
1656
+ : null),
1657
+ ...mergedStyle,
1658
+ }, className: classNames("i-datagrid-container", className, {
1172
1659
  "i-datagrid-bordered": border,
1173
1660
  "i-datagrid-striped": striped,
1174
- }), children: [jsxs("div", { ref: container, className: classNames("i-datagrid", {
1661
+ }), children: [useVirtual && virtual ? (jsx(VirtualDatagrid, { virtual: virtual, columns: columns, rows: rows, header: header, sortBy: state.sortBy, sortType: state.sortType, height: height, loading: loading, resizable: resizable, striped: striped, cellEllipsis: cellEllipsis, empty: empty, wrapRef: wrapRef, containerRef: container, getRowKey: getRowKey, onHeaderClick: handleHeaderClick, onWidthChange: handleWidthChange, onRowClick: onRowClick, onCellClick: onCellClick, onCellDoubleClick: onCellDoubleClick, onScroll: onScroll })) : (jsxs("div", { ref: container, className: classNames("i-datagrid", {
1175
1662
  "i-datagrid-loading": loading,
1176
- }), onWheel: onScroll, children: [header && (jsx(Header$1, { columns: columns, resizable: resizable, sortType: state.sortType, sortBy: state.sortBy, cellEllipsis: cellEllipsis, onWidthChange: handleWidthChange, onHeaderClick: handleHeaderClick })), rows.map((row, i) => (jsx(Row, { row: i + (header ? 1 : 0), data: row, cellEllipsis: cellEllipsis, columns: columns, onCellClick: onCellClick, onRowClick: onRowClick, onCellDoubleClick: onCellDoubleClick }, i))), rows.length < 1 && empty] }), loading && renderLoading()] }));
1663
+ }), onWheel: onScroll, children: [header && (jsx(Header$1, { columns: columns, resizable: resizable, sortType: state.sortType, sortBy: state.sortBy, cellEllipsis: cellEllipsis, onWidthChange: handleWidthChange, onHeaderClick: handleHeaderClick })), rows.map((row, i) => (jsx(Row, { row: i + (header ? 1 : 0), data: row, cellEllipsis: cellEllipsis, columns: columns, onCellClick: onCellClick, onRowClick: onRowClick, onCellDoubleClick: onCellDoubleClick }, getRowKey(row, i) ?? i))), rows.length < 1 && empty] })), loading && renderLoading()] }));
1177
1664
  };
1178
1665
 
1179
1666
  const Description = (props) => {
@@ -2209,6 +2696,10 @@ const Editor = (props) => {
2209
2696
  setMemtionKeyword("");
2210
2697
  setMemtionActiveIndex(0);
2211
2698
  };
2699
+ const syncEditorState = () => {
2700
+ selectionRef.current = null;
2701
+ hideMemtion();
2702
+ };
2212
2703
  const insertMemtion = (option) => {
2213
2704
  const replaceRange = getMemtionReplaceRange(memtionTriggerRangeRef.current, selectionRef.current);
2214
2705
  const range = insertMemtionOption({
@@ -2295,6 +2786,7 @@ const Editor = (props) => {
2295
2786
  if (getEditorValue(true) === nextValue)
2296
2787
  return;
2297
2788
  setEditorValue(nextValue);
2789
+ syncEditorState();
2298
2790
  syncHeight();
2299
2791
  }, [autosize, mode, value]);
2300
2792
  useEffect(() => {
@@ -4507,7 +4999,7 @@ function RadioItem(props) {
4507
4999
  }
4508
5000
 
4509
5001
  function Radio(props) {
4510
- const { label, name, options, value, type = "default", status = "normal", message, optionInline = true, labelInline, disabled, required, className, renderItem, onChange, } = props;
5002
+ const { label, name, options, value, type = "default", status = "normal", message, optionInline = true, labelInline, disabled, required, className, style, renderItem, onChange, } = props;
4511
5003
  const [selectedValue, setSelectedValue] = useState(value);
4512
5004
  const formattedOptions = useMemo(() => formatOption(options), [options]);
4513
5005
  const handleChange = (value, e) => {
@@ -4520,7 +5012,7 @@ function Radio(props) {
4520
5012
  return (jsxs("div", { className: classNames("i-radio i-input-label", {
4521
5013
  [`i-radio-${status}`]: status !== "normal",
4522
5014
  "i-input-inline": labelInline,
4523
- }, className), children: [label && (jsxs("span", { className: 'i-input-label-text', children: [required && jsx("span", { className: 'error', children: "*" }), label, message && jsx("p", { className: 'i-radio-message', children: message })] })), jsx("div", { className: classNames("i-radio-options", {
5015
+ }, className), style: style, children: [label && (jsxs("span", { className: "i-input-label-text", children: [required && jsx("span", { className: "error", children: "*" }), label, message && jsx("p", { className: "i-radio-message", children: message })] })), jsx("div", { className: classNames("i-radio-options", {
4524
5016
  "i-options-block": !optionInline,
4525
5017
  "i-radio-options-button": type === "button",
4526
5018
  }), children: formattedOptions.map((option) => {