@ioca/react 1.5.19 → 1.5.20

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 (38) hide show
  1. package/lib/cjs/components/datagrid/virtual.js +129 -102
  2. package/lib/cjs/components/datagrid/virtual.js.map +1 -1
  3. package/lib/cjs/components/form/useForm.js +1 -1
  4. package/lib/cjs/components/form/useForm.js.map +1 -1
  5. package/lib/cjs/components/tabs/tabs.js +8 -17
  6. package/lib/cjs/components/tabs/tabs.js.map +1 -1
  7. package/lib/cjs/components/tree/item.js +44 -56
  8. package/lib/cjs/components/tree/item.js.map +1 -1
  9. package/lib/cjs/components/tree/tree.js +121 -18
  10. package/lib/cjs/components/tree/tree.js.map +1 -1
  11. package/lib/cjs/components/tree/virtual.js +52 -0
  12. package/lib/cjs/components/tree/virtual.js.map +1 -0
  13. package/lib/cjs/js/usePreview/content.js +3 -3
  14. package/lib/cjs/js/usePreview/content.js.map +1 -1
  15. package/lib/cjs/js/usePreview/type.js.map +1 -1
  16. package/lib/css/index.css +1 -1
  17. package/lib/css/index.css.map +1 -1
  18. package/lib/css/input.css +0 -4
  19. package/lib/es/components/datagrid/virtual.js +130 -103
  20. package/lib/es/components/datagrid/virtual.js.map +1 -1
  21. package/lib/es/components/form/useForm.js +1 -1
  22. package/lib/es/components/form/useForm.js.map +1 -1
  23. package/lib/es/components/tabs/tabs.js +8 -17
  24. package/lib/es/components/tabs/tabs.js.map +1 -1
  25. package/lib/es/components/tree/item.js +44 -57
  26. package/lib/es/components/tree/item.js.map +1 -1
  27. package/lib/es/components/tree/tree.js +122 -19
  28. package/lib/es/components/tree/tree.js.map +1 -1
  29. package/lib/es/components/tree/virtual.js +44 -0
  30. package/lib/es/components/tree/virtual.js.map +1 -0
  31. package/lib/es/js/usePreview/content.js +3 -3
  32. package/lib/es/js/usePreview/content.js.map +1 -1
  33. package/lib/es/js/usePreview/type.js.map +1 -1
  34. package/lib/index.js +338 -197
  35. package/lib/types/components/tabs/type.d.ts +1 -1
  36. package/lib/types/components/tree/type.d.ts +8 -5
  37. package/lib/types/js/usePreview/type.d.ts +1 -1
  38. package/package.json +6 -5
package/lib/index.js CHANGED
@@ -5,7 +5,7 @@ import { useState, useRef, useEffect, useCallback, useMemo, Children, cloneEleme
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, KeyboardArrowDownRound, MoveToInboxTwotone, OutboxTwotone, FilePresentOutlined, DriveFolderUploadOutlined } from '@ricons/material';
6
6
  import { createRoot } from 'react-dom/client';
7
7
  import { getScrollbarSize, List as List$2 } from 'react-window';
8
- import { createPortal } from 'react-dom';
8
+ import { createPortal, flushSync } from 'react-dom';
9
9
  import xss from 'xss';
10
10
  import { renderToStaticMarkup } from 'react-dom/server';
11
11
  import PubSub from 'pubsub-js';
@@ -1186,7 +1186,7 @@ function Row(props) {
1186
1186
  }, [data, onRowClick, row]);
1187
1187
  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))) }));
1188
1188
  }
1189
- function Header$1(props) {
1189
+ function Header(props) {
1190
1190
  const { columns, resizable, cellEllipsis, sortBy, sortType, onWidthChange, onHeaderClick, } = props;
1191
1191
  const columnById = useMemo(() => {
1192
1192
  const map = new Map();
@@ -1216,6 +1216,84 @@ function Header$1(props) {
1216
1216
  }) }));
1217
1217
  }
1218
1218
 
1219
+ const VirtualCell = memo(function VirtualCell({ column, data, row, col, isHeader, cellEllipsis, sortBy, sortType, resizable, onWidthChange, }) {
1220
+ const { id, fixed, justify, colSpan, render, title, sorter, renderHeader } = column;
1221
+ const style = useMemo(() => ({
1222
+ "--datagrid-justify": justify,
1223
+ gridColumn: `${col + 1} / span ${colSpan ?? 1}`,
1224
+ insetInline: `var(--datagrid-cell-inset-${col})`,
1225
+ ...(isHeader ? { insetBlockStart: 0 } : null),
1226
+ position: !isHeader && !fixed ? "static" : undefined,
1227
+ }), [col, colSpan, fixed, isHeader, justify]);
1228
+ const order = isHeader && sortBy === id ? sortType : "";
1229
+ return (jsxs("div", { "data-col": id, className: classNames("i-datagrid-cell", {
1230
+ [`i-datagrid-cell-fixed-${fixed}`]: fixed,
1231
+ "i-datagrid-has-sorter": isHeader && sorter,
1232
+ }), style: style, children: [isHeader
1233
+ ? (renderHeader?.(column, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1234
+ "i-datagrid-cell-content-ellipsis": cellEllipsis,
1235
+ }), children: title || id })))
1236
+ : (render?.(data?.[id], data, row, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1237
+ "i-datagrid-cell-content-ellipsis": cellEllipsis,
1238
+ }), children: data?.[id] }))), isHeader && sorter && jsx(Sorter, { type: order }), isHeader && resizable && (jsx(Resize, { index: col, onWidthChange: onWidthChange }))] }));
1239
+ });
1240
+ // ---------------------------------------------------------------------------
1241
+ // VirtualRow — memoised row rendered by react-window
1242
+ // ---------------------------------------------------------------------------
1243
+ const VirtualRow = memo(function VirtualRow({ index, style: itemStyle, ariaAttributes, rows, columns, columnById, columnIndexById, contentWidthPx, virtualRowHeight, header, striped, cellEllipsis, loaderNode, sortBy, sortType, resizable, onWidthChange, onRowClick, onCellClick, onCellDoubleClick, }) {
1244
+ if (index >= rows.length) {
1245
+ return (jsx("div", { ...ariaAttributes, style: {
1246
+ ...itemStyle,
1247
+ width: contentWidthPx,
1248
+ minWidth: "100%",
1249
+ display: "flex",
1250
+ alignItems: "center",
1251
+ justifyContent: "center",
1252
+ }, children: loaderNode }));
1253
+ }
1254
+ const rowData = rows[index];
1255
+ const rowNum = index + (header ? 1 : 0);
1256
+ const bg = striped && index % 2 === 0 ? "var(--background-1)" : undefined;
1257
+ const handleCellClick = useCallback((e) => {
1258
+ if (!onCellClick)
1259
+ return;
1260
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1261
+ const id = el?.dataset?.col;
1262
+ if (!id)
1263
+ return;
1264
+ const column = columnById.get(id);
1265
+ const col = columnIndexById.get(id);
1266
+ if (!column || col == null)
1267
+ return;
1268
+ onCellClick(rowData, column, rowNum, col, e);
1269
+ }, [columnById, columnIndexById, onCellClick, rowData, rowNum]);
1270
+ const handleCellDoubleClick = useCallback((e) => {
1271
+ if (!onCellDoubleClick)
1272
+ return;
1273
+ const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1274
+ const id = el?.dataset?.col;
1275
+ if (!id)
1276
+ return;
1277
+ const column = columnById.get(id);
1278
+ const col = columnIndexById.get(id);
1279
+ if (!column || col == null)
1280
+ return;
1281
+ onCellDoubleClick(rowData, column, rowNum, col, e);
1282
+ }, [columnById, columnIndexById, onCellDoubleClick, rowData, rowNum]);
1283
+ const handleRowClick = useCallback(() => onRowClick?.(rowData, rowNum), [onRowClick, rowData, rowNum]);
1284
+ return (jsx("div", { style: {
1285
+ ...itemStyle,
1286
+ width: contentWidthPx,
1287
+ minWidth: "100%",
1288
+ display: "grid",
1289
+ gridTemplateColumns: "var(--grid-template-columns)",
1290
+ height: virtualRowHeight,
1291
+ "--datagrid-cell-background": bg,
1292
+ }, className: 'i-datagrid-row', onClick: handleRowClick, onClickCapture: handleCellClick, onDoubleClickCapture: handleCellDoubleClick, children: columns.map((c, col) => (jsx(VirtualCell, { column: c, data: rowData, row: rowNum, col: col, cellEllipsis: cellEllipsis, sortBy: sortBy, sortType: sortType, resizable: resizable, onWidthChange: onWidthChange }, c.id))) }));
1293
+ });
1294
+ // ---------------------------------------------------------------------------
1295
+ // VirtualDatagrid
1296
+ // ---------------------------------------------------------------------------
1219
1297
  function VirtualDatagrid(props) {
1220
1298
  const { virtual, columns, rows, header, sortBy, sortType, height, loading, resizable, striped, cellEllipsis, empty, wrapRef, containerRef, onHeaderClick, onWidthChange, onRowClick, onCellClick, onCellDoubleClick, onScroll, } = props;
1221
1299
  const headerRef = useRef(null);
@@ -1228,6 +1306,7 @@ function VirtualDatagrid(props) {
1228
1306
  const rafRef = useRef({
1229
1307
  viewport: 0,
1230
1308
  contentWidth: 0,
1309
+ scrollSync: 0,
1231
1310
  });
1232
1311
  const columnById = useMemo(() => {
1233
1312
  const map = new Map();
@@ -1239,38 +1318,6 @@ function VirtualDatagrid(props) {
1239
1318
  columns.forEach((c, i) => map.set(c.id, i));
1240
1319
  return map;
1241
1320
  }, [columns]);
1242
- const getVirtualCellStyle = useCallback(({ justify, col, colSpan = 1, }) => {
1243
- return {
1244
- "--datagrid-justify": justify,
1245
- gridColumn: `${col + 1} / span ${colSpan}`,
1246
- insetInline: `var(--datagrid-cell-inset-${col})`,
1247
- };
1248
- }, []);
1249
- const renderVirtualCell = useCallback(({ column, data, row, col, isHeader, }) => {
1250
- const { id, fixed, justify, colSpan, render, title, sorter, renderHeader, } = column;
1251
- const style = {
1252
- ...getVirtualCellStyle({ justify, col, colSpan }),
1253
- ...(isHeader ? { insetBlockStart: 0 } : null),
1254
- };
1255
- const order = isHeader && sortBy === id ? sortType : "";
1256
- return (jsxs("div", { "data-col": id, className: classNames("i-datagrid-cell", {
1257
- [`i-datagrid-cell-fixed-${fixed}`]: fixed,
1258
- "i-datagrid-has-sorter": isHeader && sorter,
1259
- }), style: style, children: [isHeader
1260
- ? (renderHeader?.(column, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1261
- "i-datagrid-cell-content-ellipsis": cellEllipsis,
1262
- }), children: title || id })))
1263
- : (render?.(data?.[id], data, row, col) ?? (jsx("div", { className: classNames("i-datagrid-cell-content", {
1264
- "i-datagrid-cell-content-ellipsis": cellEllipsis,
1265
- }), children: data?.[id] }))), isHeader && sorter && jsx(Sorter, { type: order }), isHeader && resizable && (jsx(Resize, { index: col, onWidthChange: onWidthChange }))] }, id));
1266
- }, [
1267
- cellEllipsis,
1268
- getVirtualCellStyle,
1269
- onWidthChange,
1270
- resizable,
1271
- sortBy,
1272
- sortType,
1273
- ]);
1274
1321
  const handleHeaderClick = useCallback((e) => {
1275
1322
  const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1276
1323
  const id = el?.dataset?.col;
@@ -1280,10 +1327,17 @@ function VirtualDatagrid(props) {
1280
1327
  const el = e.currentTarget;
1281
1328
  if (!el)
1282
1329
  return;
1283
- if (headerRef.current &&
1284
- headerRef.current.scrollLeft !== el.scrollLeft) {
1285
- headerRef.current.scrollLeft = el.scrollLeft;
1286
- }
1330
+ if (rafRef.current.scrollSync)
1331
+ return;
1332
+ rafRef.current.scrollSync = requestAnimationFrame(() => {
1333
+ rafRef.current.scrollSync = 0;
1334
+ if (!headerRef.current)
1335
+ return;
1336
+ const target = el.scrollLeft;
1337
+ if (headerRef.current.scrollLeft !== target) {
1338
+ headerRef.current.scrollLeft = target;
1339
+ }
1340
+ });
1287
1341
  }, []);
1288
1342
  const handleReachEnd = useCallback(() => {
1289
1343
  if (virtual.onReachEnd) {
@@ -1313,32 +1367,6 @@ function VirtualDatagrid(props) {
1313
1367
  listEl.scrollLeft = el.scrollLeft;
1314
1368
  }
1315
1369
  }, []);
1316
- const handleBodyClickCapture = useCallback((e, rowData, rowNum) => {
1317
- if (!onCellClick)
1318
- return;
1319
- const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1320
- const id = el?.dataset?.col;
1321
- if (!id)
1322
- return;
1323
- const column = columnById.get(id);
1324
- const col = columnIndexById.get(id);
1325
- if (!column || col == null)
1326
- return;
1327
- onCellClick(rowData, column, rowNum, col, e);
1328
- }, [columnById, columnIndexById, onCellClick]);
1329
- const handleBodyDoubleClickCapture = useCallback((e, rowData, rowNum) => {
1330
- if (!onCellDoubleClick)
1331
- return;
1332
- const el = e.target?.closest?.(".i-datagrid-cell[data-col]");
1333
- const id = el?.dataset?.col;
1334
- if (!id)
1335
- return;
1336
- const column = columnById.get(id);
1337
- const col = columnIndexById.get(id);
1338
- if (!column || col == null)
1339
- return;
1340
- onCellDoubleClick(rowData, column, rowNum, col, e);
1341
- }, [columnById, columnIndexById, onCellDoubleClick]);
1342
1370
  useEffect(() => {
1343
1371
  const el = wrapRef.current;
1344
1372
  if (!el)
@@ -1409,12 +1437,14 @@ function VirtualDatagrid(props) {
1409
1437
  const contentWidthPx = measuredContentWidth
1410
1438
  ? `${measuredContentWidth}px`
1411
1439
  : "fit-content";
1412
- const headerCells = useMemo(() => columns.map((c, col) => renderVirtualCell({
1413
- column: c,
1414
- row: 0,
1415
- col,
1416
- isHeader: true,
1417
- })), [columns, renderVirtualCell]);
1440
+ const headerCells = useMemo(() => columns.map((c, col) => (jsx(VirtualCell, { column: c, row: 0, col: col, isHeader: true, cellEllipsis: cellEllipsis, sortBy: sortBy, sortType: sortType, resizable: resizable, onWidthChange: onWidthChange }, c.id))), [
1441
+ cellEllipsis,
1442
+ columns,
1443
+ onWidthChange,
1444
+ resizable,
1445
+ sortBy,
1446
+ sortType,
1447
+ ]);
1418
1448
  const headerInnerStyle = useMemo(() => ({
1419
1449
  display: "grid",
1420
1450
  gridTemplateColumns: "var(--grid-template-columns)",
@@ -1434,50 +1464,47 @@ function VirtualDatagrid(props) {
1434
1464
  }
1435
1465
  : undefined, [scrollbarSize]);
1436
1466
  const loaderNode = useMemo(() => virtual.loader ?? jsx(Loading, { className: 'my-12' }), [virtual.loader]);
1437
- const rowComponent = useCallback(({ index, style: itemStyle }) => {
1438
- if (index >= rows.length) {
1439
- return (jsx("div", { style: {
1440
- ...itemStyle,
1441
- width: contentWidthPx,
1442
- minWidth: "100%",
1443
- display: "flex",
1444
- alignItems: "center",
1445
- justifyContent: "center",
1446
- }, children: loaderNode }));
1447
- }
1448
- const rowData = rows[index];
1449
- const rowNum = index + (header ? 1 : 0);
1450
- const bg = striped && index % 2 === 0 ? "var(--background-1)" : undefined;
1451
- return (jsx("div", { style: {
1452
- ...itemStyle,
1453
- width: contentWidthPx,
1454
- minWidth: "100%",
1455
- display: "grid",
1456
- gridTemplateColumns: "var(--grid-template-columns)",
1457
- height: virtual.rowHeight,
1458
- "--datagrid-cell-background": bg,
1459
- }, 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({
1460
- column: c,
1461
- data: rowData,
1462
- row: rowNum,
1463
- col,
1464
- })) }));
1465
- }, [
1467
+ // Stable row-component reference so react-window can memoise rows.
1468
+ const rowProps = useMemo(() => ({
1469
+ rows,
1466
1470
  columns,
1471
+ columnById,
1472
+ columnIndexById,
1467
1473
  contentWidthPx,
1468
- handleBodyClickCapture,
1469
- handleBodyDoubleClickCapture,
1474
+ virtualRowHeight: virtual.rowHeight,
1470
1475
  header,
1476
+ striped,
1477
+ cellEllipsis,
1471
1478
  loaderNode,
1479
+ sortBy,
1480
+ sortType,
1481
+ resizable,
1482
+ onWidthChange,
1472
1483
  onRowClick,
1473
- renderVirtualCell,
1484
+ onCellClick,
1485
+ onCellDoubleClick,
1486
+ }), [
1474
1487
  rows,
1475
- striped,
1488
+ columns,
1489
+ columnById,
1490
+ columnIndexById,
1491
+ contentWidthPx,
1476
1492
  virtual.rowHeight,
1493
+ header,
1494
+ striped,
1495
+ cellEllipsis,
1496
+ loaderNode,
1497
+ sortBy,
1498
+ sortType,
1499
+ resizable,
1500
+ onWidthChange,
1501
+ onRowClick,
1502
+ onCellClick,
1503
+ onCellDoubleClick,
1477
1504
  ]);
1478
1505
  return (jsxs("div", { ref: containerRef, className: classNames("i-datagrid", {
1479
1506
  "i-datagrid-loading": loading,
1480
- }), 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] }));
1507
+ }), 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: rowProps, style: listStyle, onScroll: handleBodyScroll, onRowsRendered: handleRowsRendered, rowComponent: VirtualRow }), rows.length < 1 && !virtual.hasMore && empty] }));
1481
1508
  }
1482
1509
 
1483
1510
  const Datagrid = (props) => {
@@ -1675,7 +1702,7 @@ const Datagrid = (props) => {
1675
1702
  "i-datagrid-striped": striped,
1676
1703
  }), 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", {
1677
1704
  "i-datagrid-loading": loading,
1678
- }), 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()] }));
1705
+ }), onWheel: onScroll, children: [header && (jsx(Header, { 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()] }));
1679
1706
  };
1680
1707
 
1681
1708
  const Description = (props) => {
@@ -3142,7 +3169,7 @@ class IFormInstance {
3142
3169
  const { id, rules, data } = this;
3143
3170
  if (!rules)
3144
3171
  return data;
3145
- const names = field ? [field] : Object.keys(this.cacheData);
3172
+ const names = field ? [field] : [...new Set([...Object.keys(this.cacheData), ...Object.keys(rules)])];
3146
3173
  let isAllValid = true;
3147
3174
  names.forEach((name) => {
3148
3175
  const o = rules[name];
@@ -3894,7 +3921,7 @@ function renderFile(props) {
3894
3921
  }
3895
3922
 
3896
3923
  function Content(props) {
3897
- const { items = [], initial = 0, renderFile: renderFile$1 = renderFile, onRotate, onChange, onClose, onZoom, } = props;
3924
+ const { items = [], initial = 0, hideControl, renderFile: renderFile$1 = renderFile, onRotate, onChange, onClose, onZoom, } = props;
3898
3925
  const state = useReactive({
3899
3926
  current: initial,
3900
3927
  rotate: 0,
@@ -4030,9 +4057,9 @@ function Content(props) {
4030
4057
  transform: `translate(${state.translate
4031
4058
  .map((n) => `${n}px`)
4032
4059
  .join(",")}) rotate(${state.rotate}deg) scale(${state.scale})`,
4033
- }, onMouseDown: handleMouseDown, onClick: (e) => e.stopPropagation(), children: content }), jsxs("div", { className: classNames("i-preview-controls", {
4060
+ }, onMouseDown: handleMouseDown, onClick: (e) => e.stopPropagation(), children: content }), !hideControl && (jsxs("div", { className: classNames("i-preview-controls", {
4034
4061
  "i-preview-controls-hidden": state.controlHidden,
4035
- }), children: [jsx(Button, { square: true, flat: true, onClick: onClose, children: jsx(Icon, { icon: jsx(CloseRound, {}) }) }), files.length > 1 && (jsxs("span", { className: 'px-8', children: [state.current + 1, " / ", files.length] })), state.scale !== 1 && (jsxs(Button, { flat: true, onClick: () => (state.scale = 1), children: [jsx(Icon, { icon: jsx(AspectRatioRound, {}) }), jsxs("span", { className: 'mt-2', children: [(state.scale * 100).toFixed(0), "%"] })] })), jsx(Button, { square: true, flat: true, href: file.src, target: '_blank', children: jsx(Icon, { icon: jsx(OpenInNewRound, {}) }) }), jsx(Button, { square: true, flat: true, href: file.src, download: true, target: '_blank', children: jsx(Icon, { icon: jsx(FileDownloadOutlined, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleRotate(90), children: jsx(Icon, { icon: jsx(RotateRightRound, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleRotate(-90), children: jsx(Icon, { icon: jsx(RotateLeftRound, {}) }) }), files.length > 1 && (jsxs(Fragment, { children: [jsx(Button, { square: true, flat: true, onClick: () => handleSwitch(state.current - 1), children: jsx(Icon, { icon: jsx(KeyboardArrowLeftRound, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleSwitch(state.current + 1), children: jsx(Icon, { icon: jsx(KeyboardArrowRightRound, {}) }) })] }))] })] }));
4062
+ }), children: [jsx(Button, { square: true, flat: true, onClick: onClose, children: jsx(Icon, { icon: jsx(CloseRound, {}) }) }), files.length > 1 && (jsxs("span", { className: 'px-8', children: [state.current + 1, " / ", files.length] })), state.scale !== 1 && (jsxs(Button, { flat: true, onClick: () => (state.scale = 1), children: [jsx(Icon, { icon: jsx(AspectRatioRound, {}) }), jsxs("span", { className: 'mt-2', children: [(state.scale * 100).toFixed(0), "%"] })] })), jsx(Button, { square: true, flat: true, href: file.src, target: '_blank', children: jsx(Icon, { icon: jsx(OpenInNewRound, {}) }) }), jsx(Button, { square: true, flat: true, href: file.src, download: true, target: '_blank', children: jsx(Icon, { icon: jsx(FileDownloadOutlined, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleRotate(90), children: jsx(Icon, { icon: jsx(RotateRightRound, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleRotate(-90), children: jsx(Icon, { icon: jsx(RotateLeftRound, {}) }) }), files.length > 1 && (jsxs(Fragment, { children: [jsx(Button, { square: true, flat: true, onClick: () => handleSwitch(state.current - 1), children: jsx(Icon, { icon: jsx(KeyboardArrowLeftRound, {}) }) }), jsx(Button, { square: true, flat: true, onClick: () => handleSwitch(state.current + 1), children: jsx(Icon, { icon: jsx(KeyboardArrowRightRound, {}) }) })] }))] }))] }));
4036
4063
  }
4037
4064
 
4038
4065
  function usePreview() {
@@ -6052,11 +6079,8 @@ const Tabs = ((props) => {
6052
6079
  });
6053
6080
  sourceKeysRef.current = sourceKeys;
6054
6081
  contentsRef.current = nextContents;
6055
- const nextTabs = [
6056
- ...sourceTabs.filter((tab) => !hiddenSourceKeysRef.current.has(String(tab.key))),
6057
- ...dynamicTabs,
6058
- ];
6059
- setTabs((currentTabs) => isSameTabs(currentTabs, nextTabs) ? currentTabs : nextTabs);
6082
+ const nextTabs = [...sourceTabs.filter((tab) => !hiddenSourceKeysRef.current.has(String(tab.key))), ...dynamicTabs];
6083
+ setTabs((currentTabs) => (isSameTabs(currentTabs, nextTabs) ? currentTabs : nextTabs));
6060
6084
  }, [parsedTabs]);
6061
6085
  const add = (tab, position) => {
6062
6086
  const currentTabs = tabsRef.current;
@@ -6070,9 +6094,7 @@ const Tabs = ((props) => {
6070
6094
  const { content, ...rest } = tab;
6071
6095
  setTabs((ts) => {
6072
6096
  const nextTabs = [...ts];
6073
- const index = position === undefined
6074
- ? nextTabs.length
6075
- : Math.max(0, Math.min(position, nextTabs.length));
6097
+ const index = position === undefined ? nextTabs.length : Math.max(0, Math.min(position, nextTabs.length));
6076
6098
  nextTabs.splice(index, 0, { ...rest, key: tkey });
6077
6099
  return nextTabs;
6078
6100
  });
@@ -6154,8 +6176,7 @@ const Tabs = ((props) => {
6154
6176
  setTabs((ts) => {
6155
6177
  let changed = false;
6156
6178
  const next = ts.map((t) => {
6157
- if (t.intersecting === undefined ||
6158
- t.intersecting === true) {
6179
+ if (t.intersecting === undefined || t.intersecting === true) {
6159
6180
  return t;
6160
6181
  }
6161
6182
  changed = true;
@@ -6176,7 +6197,7 @@ const Tabs = ((props) => {
6176
6197
  return ts;
6177
6198
  if (ts[i]?.intersecting === visible)
6178
6199
  return ts;
6179
- return ts.map((t, idx) => idx === i ? { ...t, intersecting: visible } : t);
6200
+ return ts.map((t, idx) => (idx === i ? { ...t, intersecting: visible } : t));
6180
6201
  });
6181
6202
  });
6182
6203
  });
@@ -6201,10 +6222,9 @@ const Tabs = ((props) => {
6201
6222
  });
6202
6223
  }
6203
6224
  const { offsetHeight, offsetLeft, offsetTop, offsetWidth } = nav;
6204
- const isLine = type === "line";
6205
6225
  setBarStyle({
6206
- height: !vertical && isLine ? ".25em" : offsetHeight * 0.5,
6207
- width: vertical && isLine ? ".25em" : offsetWidth,
6226
+ height: offsetHeight * 0.5,
6227
+ width: offsetWidth,
6208
6228
  transform: `translate(${offsetLeft}px, ${offsetTop}px)`,
6209
6229
  });
6210
6230
  }, 16);
@@ -6246,39 +6266,14 @@ const Tabs = ((props) => {
6246
6266
  navs: navsRef,
6247
6267
  }));
6248
6268
  const cachedTabKeySet = useMemo(() => new Set(cachedTabs), [cachedTabs]);
6249
- const moreTabs = useMemo(() => !hideMore && overflow
6250
- ? tabs.filter((tab) => tab.intersecting === false)
6251
- : [], [hideMore, overflow, tabs]);
6269
+ const moreTabs = useMemo(() => (!hideMore && overflow ? tabs.filter((tab) => tab.intersecting === false) : []), [hideMore, overflow, tabs]);
6252
6270
  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", navsClass, {
6253
6271
  "i-tab-navs-vertical": vertical,
6254
6272
  }), children: [prepend, jsx(TabsNavs$1, { tabs: tabs, moreTabs: moreTabs, activeKey: activeKey, vertical: vertical, overflow: overflow, hideMore: hideMore, navsJustify: navsJustify, bar: bar, barClass: barClass, barStyle: barStyle, navsRef: navsRef, renderMore: renderMore, setNavRef: setNavRef, onOpen: open, onClose: close, onMoreTabClick: handleMoreTabClick, onKeyAction: handleKeyAction }), append] }), jsx(TabsContents$1, { tabs: tabs, activeKey: activeKey, cachedTabKeySet: cachedTabKeySet, getContent: getContent })] }));
6255
6273
  });
6256
6274
  Tabs.Item = Item;
6257
6275
 
6258
- function TreeList(props) {
6259
- const { data = [], depth = 0, round, style, className, parent, nodeProps, ...restProps } = props;
6260
- const contents = data.map((item, i) => {
6261
- const { type } = item;
6262
- const title = item[nodeProps.title];
6263
- const itemKey = item[nodeProps.key] ||
6264
- (parent?.key !== undefined ? `${parent.key}-${i}` : `${i}`);
6265
- item.key = itemKey;
6266
- item.parent = parent;
6267
- if (type === "title") {
6268
- return (jsx("div", { className: 'i-tree-group-title', children: title }, i));
6269
- }
6270
- if (type && type !== "item") {
6271
- return (jsx("div", { className: `i-tree-type-${type}`, children: title }, i));
6272
- }
6273
- return (jsx(TreeItem, { index: i, item: item, depth: depth, nodeProps: nodeProps, ...restProps }, itemKey));
6274
- });
6275
- if (depth > 0)
6276
- return jsx(Fragment, { children: contents });
6277
- return (jsx("div", { className: classNames("i-tree", className, {
6278
- "i-tree-round": round,
6279
- }), style: style, children: contents }));
6280
- }
6281
- const Header = (props) => {
6276
+ const TreeItemHeader = (props) => {
6282
6277
  const { as: Tag = "a", href, selected, children, ...restProps } = props;
6283
6278
  const className = classNames("i-tree-item-header", {
6284
6279
  "i-tree-item-selected": selected,
@@ -6288,50 +6283,166 @@ const Header = (props) => {
6288
6283
  }
6289
6284
  return (jsx(Tag, { to: href || "", className: className, ...restProps, children: children }));
6290
6285
  };
6291
- const TreeItem = (props) => {
6292
- const { item, depth = 0, index, selected, checked = [], partofs = {}, checkable, nodeProps, renderExtra, onItemClick, onItemSelect, onItemCheck, ...restProps } = props;
6293
- const { as, key = "", href, icon, title, expanded, disabled } = item;
6294
- const children = item[nodeProps.children];
6295
- const [expand, setExpand] = useState(expanded);
6296
- const handleExpand = (e, fromToggle) => {
6297
- if (fromToggle) {
6298
- e.preventDefault();
6299
- e.stopPropagation();
6300
- }
6301
- if (disabled || !children?.length)
6302
- return;
6303
- setExpand((v) => !v);
6304
- };
6305
- const handleItemClick = (e) => {
6306
- if (disabled) {
6307
- e.preventDefault();
6308
- e.stopPropagation();
6286
+ function TreeRow(props) {
6287
+ const { flatNode, wrapperStyle, virtualMode, selected, checkedSet, partofs = {}, checkable, nodeProps, renderExtra, loadingKeys, onExpand, onItemClick, onItemSelect, onItemCheck, } = props;
6288
+ const { node, depth, isExpanded } = flatNode;
6289
+ const { key = "", as, href, icon, title, disabled, type } = node;
6290
+ const children = node[nodeProps.children];
6291
+ const hasChildren = children instanceof Promise || (Array.isArray(children) && children.length > 0);
6292
+ const loading = loadingKeys?.includes(key);
6293
+ if (type === "title") {
6294
+ return jsx("div", { style: wrapperStyle, className: "i-tree-group-title", children: title });
6295
+ }
6296
+ if (type && type !== "item") {
6297
+ return jsx("div", { style: wrapperStyle, className: `i-tree-type-${type}`, children: title });
6298
+ }
6299
+ return (jsx("div", { className: !virtualMode ? classNames("i-tree-item", { "i-tree-expand": isExpanded }) : undefined, style: wrapperStyle, children: jsxs(TreeItemHeader, { as: as, href: href, style: { paddingLeft: `${depth * 1.5 + 0.5}em` }, selected: selected === key, onClick: (e) => {
6300
+ if (disabled) {
6301
+ e.preventDefault();
6302
+ e.stopPropagation();
6303
+ return;
6304
+ }
6305
+ if (hasChildren)
6306
+ onExpand(key);
6307
+ onItemClick?.(node, e);
6308
+ onItemSelect?.(key, node);
6309
+ }, children: [checkable && (jsx(Checkbox.Item, { value: checkedSet.has(key), partof: !checkedSet.has(key) && partofs[key], className: "i-tree-checkbox", onChange: () => onItemCheck?.(node, !checkedSet.has(key), []), onClick: (e) => e.stopPropagation() })), icon && jsx("span", { className: "i-tree-item-icon", children: icon }), jsx("span", { className: "i-tree-item-title", children: title }), renderExtra?.(node), hasChildren && (jsx(Icon, { icon: loading ? jsx(Loading, { size: ".86em" }) : jsx(KeyboardArrowDownRound, {}), className: classNames("i-tree-toggle", {
6310
+ "i-tree-expand": virtualMode ? isExpanded : false,
6311
+ }), onClick: (e) => {
6312
+ e.preventDefault();
6313
+ e.stopPropagation();
6314
+ onExpand(key);
6315
+ } }))] }) }));
6316
+ }
6317
+ function TreeList(props) {
6318
+ const { flatNodes, onExpand, selected, checkedSet, partofs = {}, checkable, nodeProps, renderExtra, loadingKeys, round, className, style, onItemClick, onItemSelect, onItemCheck } = props;
6319
+ return (jsx("div", { className: classNames("i-tree", className, {
6320
+ "i-tree-round": round,
6321
+ }), style: style, children: flatNodes.map((flatNode) => {
6322
+ const { key = "" } = flatNode.node;
6323
+ return (jsx(TreeRow, { flatNode: flatNode, selected: selected, checkedSet: checkedSet, partofs: partofs, checkable: checkable, nodeProps: nodeProps, renderExtra: renderExtra, loadingKeys: loadingKeys, onExpand: onExpand, onItemClick: onItemClick, onItemSelect: onItemSelect, onItemCheck: onItemCheck }, key));
6324
+ }) }));
6325
+ }
6326
+
6327
+ function VirtualTree(props) {
6328
+ const { flatNodes, onExpand, selected, checkedSet, partofs = {}, checkable, nodeProps, renderExtra, loadingKeys, height, useVirtual, className, style, onItemClick, onItemSelect, onItemCheck, } = props;
6329
+ const listRef = useRef(null);
6330
+ const wrapRef = useRef(null);
6331
+ const ro = useResizeObserver();
6332
+ const [viewportHeight, setViewportHeight] = useState(0);
6333
+ useEffect(() => {
6334
+ const el = wrapRef.current;
6335
+ if (!el)
6309
6336
  return;
6310
- }
6311
- handleExpand(e);
6312
- onItemClick?.(item, e);
6313
- onItemSelect?.(key, item);
6314
- };
6315
- const handleItemCheck = (checked) => onItemCheck?.(item, checked, []);
6316
- const itemChecked = checked.includes(key);
6317
- return (jsxs("div", { className: classNames("i-tree-item", {
6318
- "i-tree-expand": expand,
6319
- }), children: [jsxs(Header, { as: as, href: href, style: { paddingLeft: `${depth * 1.5 + 0.5}em` }, selected: selected === key, onClick: handleItemClick, children: [checkable && (jsx(Checkbox.Item, { value: itemChecked, partof: !itemChecked && partofs[key], className: 'i-tree-checkbox', onChange: handleItemCheck, onClick: (e) => e.stopPropagation() })), icon && jsx("span", { className: 'i-tree-item-icon', children: icon }), jsx("span", { className: 'i-tree-item-title', children: title }), renderExtra?.(item), children && (jsx(Icon, { icon: jsx(KeyboardArrowDownRound, {}), className: 'i-tree-toggle', onClick: (e) => handleExpand(e, true) }))] }), children?.length && (jsx("div", { className: 'i-tree-item-content', children: jsx(TreeList, { data: children, depth: depth + 1, selected: selected, checkable: checkable, parent: item, partofs: partofs, checked: checked, nodeProps: nodeProps, renderExtra: renderExtra, onItemClick: onItemClick, onItemSelect: onItemSelect, onItemCheck: onItemCheck, ...restProps }) }))] }));
6320
- };
6337
+ const update = () => {
6338
+ const r = el.getBoundingClientRect();
6339
+ setViewportHeight((prev) => (prev === r.height ? prev : r.height));
6340
+ };
6341
+ update();
6342
+ ro.observe?.(el, update);
6343
+ return () => ro.unobserve?.(el);
6344
+ }, [ro]);
6345
+ const listHeight = Math.max(0, (typeof height === "number" ? height : viewportHeight || 360));
6346
+ const propsRef = useRef(props);
6347
+ propsRef.current = props;
6348
+ const rowComponent = useCallback(({ index, style, }) => {
6349
+ const p = propsRef.current;
6350
+ const flatNode = p.flatNodes[index];
6351
+ if (!flatNode)
6352
+ return null;
6353
+ return (jsx(TreeRow, { flatNode: flatNode, wrapperStyle: style, virtualMode: true, selected: p.selected, checkedSet: p.checkedSet, partofs: p.partofs, checkable: p.checkable, nodeProps: p.nodeProps, renderExtra: p.renderExtra, loadingKeys: p.loadingKeys, onExpand: p.onExpand, onItemClick: p.onItemClick, onItemSelect: p.onItemSelect, onItemCheck: p.onItemCheck }));
6354
+ }, []);
6355
+ return (jsx("div", { ref: wrapRef, className: classNames("i-tree", className), style: { display: "block", width: "100%", height: "100%", ...style }, children: jsx(List$2, { listRef: listRef, rowCount: flatNodes.length, rowHeight: useVirtual.rowHeight, overscanCount: Math.max(3, useVirtual.threshold ?? 8), rowProps: {}, style: {
6356
+ width: "100%",
6357
+ height: listHeight,
6358
+ overflow: "auto",
6359
+ }, rowComponent: rowComponent }) }));
6360
+ }
6321
6361
 
6322
6362
  const defaultNodeProps = {
6323
6363
  key: "key",
6324
6364
  title: "title",
6325
6365
  children: "children",
6326
6366
  };
6367
+ function flattenTree(nodes, expandedMap, nodeProps, depth = 0, parentItem, asyncChildrenMap = {}) {
6368
+ const result = [];
6369
+ nodes.forEach((item, i) => {
6370
+ const mapKey = item[nodeProps.key];
6371
+ item.key = mapKey || `${parentItem?.key ?? ""}-${i}`;
6372
+ item.parent = parentItem;
6373
+ const isExpanded = !!expandedMap[item.key];
6374
+ result.push({ node: item, depth, isExpanded });
6375
+ const children = asyncChildrenMap[item.key] || item[nodeProps.children];
6376
+ if (Array.isArray(children) && children.length) {
6377
+ const childNodes = flattenTree(children, expandedMap, nodeProps, depth + 1, item, asyncChildrenMap);
6378
+ if (isExpanded)
6379
+ result.push(...childNodes);
6380
+ }
6381
+ });
6382
+ return result;
6383
+ }
6327
6384
  const Tree = (props) => {
6328
- const { data = [], ref, selected, checked = [], disabledRelated, nodeProps, onItemSelect, onItemCheck, ...restProps } = props;
6385
+ const { data = [], ref, selected, checked = [], disabledRelated, nodeProps, height, useVirtual, onItemSelect, onItemCheck, ...restProps } = props;
6329
6386
  const [selectedKey, setSelectedKey] = useState(selected);
6330
6387
  const [checkedKeys, setCheckedKeys] = useState(checked);
6331
6388
  const [partofs, setPartofs] = useState({});
6389
+ const [loadingMap, setLoadingMap] = useState({});
6390
+ const [asyncChildrenMap, setAsyncChildrenMap] = useState({});
6332
6391
  const nodeMapsRef = useRef(new Map());
6333
- const oNodeProps = Object.assign({}, defaultNodeProps, nodeProps);
6334
- const isChecked = (key) => checkedKeys.includes(key || "");
6392
+ const oNodeProps = useMemo(() => ({ ...defaultNodeProps, ...nodeProps }), [nodeProps]);
6393
+ const checkedSet = useMemo(() => new Set(checkedKeys), [checkedKeys]);
6394
+ const [expandedMap, setExpandedMap] = useState(() => {
6395
+ const map = {};
6396
+ const walk = (nodes, parentKey = "") => {
6397
+ nodes.forEach((item, i) => {
6398
+ const mapKey = item[oNodeProps.key];
6399
+ const key = mapKey || `${parentKey}-${i}`;
6400
+ if (item.expanded)
6401
+ map[key] = true;
6402
+ const children = item[oNodeProps.children];
6403
+ if (Array.isArray(children) && children.length)
6404
+ walk(children, key);
6405
+ });
6406
+ };
6407
+ walk(data);
6408
+ return map;
6409
+ });
6410
+ const handleExpand = (key) => {
6411
+ if (loadingMap[key])
6412
+ return;
6413
+ const item = nodeMapsRef.current.get(key);
6414
+ if (!item)
6415
+ return;
6416
+ const rawChildren = item[oNodeProps.children];
6417
+ const isAsync = rawChildren instanceof Promise;
6418
+ const isExpanded = !!expandedMap[key];
6419
+ if (isAsync && !isExpanded) {
6420
+ flushSync(() => {
6421
+ setLoadingMap((prev) => ({ ...prev, [key]: true }));
6422
+ setExpandedMap((prev) => ({ ...prev, [key]: true }));
6423
+ });
6424
+ rawChildren
6425
+ .then((resolved) => {
6426
+ item[oNodeProps.children] = resolved;
6427
+ setAsyncChildrenMap((prev) => ({ ...prev, [key]: resolved }));
6428
+ })
6429
+ .finally(() => {
6430
+ setLoadingMap((prev) => {
6431
+ const next = { ...prev };
6432
+ delete next[key];
6433
+ return next;
6434
+ });
6435
+ });
6436
+ }
6437
+ else {
6438
+ setExpandedMap((prev) => ({
6439
+ ...prev,
6440
+ [key]: !prev[key],
6441
+ }));
6442
+ }
6443
+ };
6444
+ const flatNodes = useMemo(() => flattenTree(data, expandedMap, oNodeProps, 0, undefined, asyncChildrenMap), [data, expandedMap, oNodeProps, asyncChildrenMap]);
6445
+ const loadingKeys = useMemo(() => Object.keys(loadingMap).filter((k) => loadingMap[k]), [loadingMap]);
6335
6446
  const checkItem = (item, checked, direction) => {
6336
6447
  const { key = "", parent, children } = item;
6337
6448
  const shouldChanged = { [key]: checked };
@@ -6340,7 +6451,9 @@ const Tree = (props) => {
6340
6451
  return [shouldChanged];
6341
6452
  if (checked) {
6342
6453
  if (parent && direction !== "leaf") {
6343
- const hasUnchecked = parent.children?.some((o) => o.key !== key && !isChecked(o.key));
6454
+ const hasUnchecked = Array.isArray(parent.children)
6455
+ ? parent.children.some((o) => o.key !== key && !checkedSet.has(o.key))
6456
+ : false;
6344
6457
  const [changes, parts] = checkItem(parent, true, "root");
6345
6458
  if (!hasUnchecked) {
6346
6459
  Object.assign(shouldChanged, changes);
@@ -6349,9 +6462,9 @@ const Tree = (props) => {
6349
6462
  [parent.key]: true,
6350
6463
  });
6351
6464
  }
6352
- if (children?.length && direction !== "root") {
6465
+ if (Array.isArray(children) && children.length && direction !== "root") {
6353
6466
  children.map((o) => {
6354
- if (isChecked(o.key))
6467
+ if (checkedSet.has(o.key))
6355
6468
  return;
6356
6469
  const [changes] = checkItem(o, true, "leaf");
6357
6470
  Object.assign(shouldChanged, changes);
@@ -6363,16 +6476,18 @@ const Tree = (props) => {
6363
6476
  if (parent && direction !== "leaf") {
6364
6477
  const [changes, parts] = checkItem(parent, false, "root");
6365
6478
  Object.assign(shouldChanged, changes);
6366
- const hasChecked = parent.children?.some((o) => isChecked(o.key) && o.key !== key);
6479
+ const hasChecked = Array.isArray(parent.children)
6480
+ ? parent.children.some((o) => checkedSet.has(o.key) && o.key !== key)
6481
+ : false;
6367
6482
  Object.assign(partofs, hasChecked ? {} : parts, {
6368
6483
  [parent.key]: hasChecked,
6369
6484
  [key]: false,
6370
6485
  });
6371
6486
  }
6372
- if (children?.length && direction !== "root") {
6487
+ if (Array.isArray(children) && children.length && direction !== "root") {
6373
6488
  children.map((o) => {
6374
6489
  const [changes] = checkItem(o, false, "leaf");
6375
- if (!isChecked(o.key))
6490
+ if (!checkedSet.has(o.key))
6376
6491
  return;
6377
6492
  Object.assign(shouldChanged, changes);
6378
6493
  partofs[o.key] = false;
@@ -6383,9 +6498,10 @@ const Tree = (props) => {
6383
6498
  const handleCheck = (item, checked) => {
6384
6499
  const [shouldChanged, partofs] = checkItem(item, checked);
6385
6500
  const changedKeys = Object.keys(shouldChanged);
6501
+ const changedKeysSet = new Set(changedKeys);
6386
6502
  const nextChecked = checked
6387
6503
  ? Array.from(new Set([...checkedKeys, ...changedKeys]))
6388
- : checkedKeys.filter((k) => !changedKeys.includes(k));
6504
+ : checkedKeys.filter((k) => !changedKeysSet.has(k));
6389
6505
  setCheckedKeys(nextChecked);
6390
6506
  setPartofs((p) => ({ ...p, ...partofs }));
6391
6507
  onItemCheck?.(item, checked, nextChecked);
@@ -6403,15 +6519,37 @@ const Tree = (props) => {
6403
6519
  }, [selected]);
6404
6520
  useEffect(() => {
6405
6521
  nodeMapsRef.current.clear();
6406
- const { key, children } = oNodeProps;
6407
- const recursive = (nodes) => {
6408
- nodes.map((o) => {
6409
- nodeMapsRef.current.set(o[key], o);
6410
- o[children]?.length > 0 && recursive(o[children]);
6522
+ const { key: keyProp, children: childrenProp } = oNodeProps;
6523
+ const walk = (nodes, parentKey = "") => {
6524
+ nodes.forEach((item, i) => {
6525
+ const mapKey = item[keyProp];
6526
+ const key = (mapKey || `${parentKey}-${i}`);
6527
+ nodeMapsRef.current.set(key, item);
6528
+ const itemChildren = item[childrenProp];
6529
+ if (Array.isArray(itemChildren) && itemChildren.length) {
6530
+ walk(itemChildren, key);
6531
+ }
6411
6532
  });
6412
6533
  };
6413
- recursive(data);
6414
- }, [data]);
6534
+ walk(data);
6535
+ }, [data, oNodeProps, asyncChildrenMap]);
6536
+ useEffect(() => {
6537
+ if (!props.selected)
6538
+ return;
6539
+ const node = nodeMapsRef.current.get(props.selected);
6540
+ if (!node)
6541
+ return;
6542
+ const toExpand = {};
6543
+ let p = node.parent;
6544
+ while (p) {
6545
+ if (p.key)
6546
+ toExpand[p.key] = true;
6547
+ p = p.parent;
6548
+ }
6549
+ if (Object.keys(toExpand).length > 0) {
6550
+ setExpandedMap((prev) => ({ ...prev, ...toExpand }));
6551
+ }
6552
+ }, [props.selected]);
6415
6553
  useImperativeHandle(ref, () => {
6416
6554
  return {
6417
6555
  getChecked: () => {
@@ -6440,7 +6578,10 @@ const Tree = (props) => {
6440
6578
  },
6441
6579
  };
6442
6580
  });
6443
- return (jsx(TreeList, { data: data, selected: selectedKey, checked: checkedKeys, partofs: partofs, nodeProps: oNodeProps, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
6581
+ if (useVirtual) {
6582
+ return (jsx(VirtualTree, { flatNodes: flatNodes, onExpand: handleExpand, height: height, useVirtual: useVirtual, selected: selectedKey, checkedSet: checkedSet, partofs: partofs, nodeProps: oNodeProps, loadingKeys: loadingKeys, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
6583
+ }
6584
+ return (jsx(TreeList, { flatNodes: flatNodes, onExpand: handleExpand, selected: selectedKey, checkedSet: checkedSet, partofs: partofs, nodeProps: oNodeProps, loadingKeys: loadingKeys, onItemCheck: handleCheck, onItemSelect: handleSelect, ...restProps }));
6444
6585
  };
6445
6586
 
6446
6587
  const Dropbox = (props) => {