@rainbow-oh/yee-c 0.6.4 → 0.8.0

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 (145) hide show
  1. package/dist/cjs/Button/style/index.less +5 -4
  2. package/dist/cjs/Drawer/drawer.js +1 -1
  3. package/dist/cjs/Drawer/interface.d.ts +1 -1
  4. package/dist/cjs/Drawer/style/index.less +1 -0
  5. package/dist/cjs/Form/form-store.d.ts +2 -1
  6. package/dist/cjs/Form/form-store.js +32 -17
  7. package/dist/cjs/List/demo/virtual.d.ts +3 -0
  8. package/dist/cjs/List/demo/virtual.js +53 -0
  9. package/dist/cjs/List/hooks/useListKeyboard.d.ts +28 -0
  10. package/dist/cjs/List/hooks/useListKeyboard.js +188 -0
  11. package/dist/cjs/List/interface.d.ts +29 -2
  12. package/dist/cjs/List/list.js +141 -21
  13. package/dist/cjs/List/style/index.less +24 -0
  14. package/dist/cjs/Select/demo/columns.d.ts +3 -0
  15. package/dist/cjs/Select/demo/columns.js +62 -0
  16. package/dist/cjs/Select/hooks/useSelectKeyboard.d.ts +13 -1
  17. package/dist/cjs/Select/hooks/useSelectKeyboard.js +81 -10
  18. package/dist/cjs/Select/interface.d.ts +30 -3
  19. package/dist/cjs/Select/option.js +4 -3
  20. package/dist/cjs/Select/options.js +90 -8
  21. package/dist/cjs/Select/select.js +32 -8
  22. package/dist/cjs/Select/style/index.less +14 -0
  23. package/dist/cjs/Selector/interface.d.ts +4 -0
  24. package/dist/cjs/Selector/selector.js +5 -3
  25. package/dist/cjs/Table/hooks/useColumns.js +1 -1
  26. package/dist/cjs/Table/interface.d.ts +1 -1
  27. package/dist/cjs/Table/style/index.less +35 -11
  28. package/dist/cjs/Table/table.js +57 -7
  29. package/dist/cjs/Table/tbody/cell.js +1 -1
  30. package/dist/cjs/Table/util/header.d.ts +3 -1
  31. package/dist/cjs/Table/util/header.js +30 -3
  32. package/dist/cjs/Tree/demo/draggable.js +2 -0
  33. package/dist/cjs/Tree/interface.d.ts +46 -23
  34. package/dist/cjs/Tree/tree-node.d.ts +1 -1
  35. package/dist/cjs/Tree/tree-node.js +30 -23
  36. package/dist/cjs/Tree/tree.d.ts +13 -12
  37. package/dist/cjs/Tree/tree.js +452 -227
  38. package/dist/cjs/Tree/utils/tree-tools.d.ts +43 -10
  39. package/dist/cjs/Tree/utils/tree-tools.js +129 -91
  40. package/dist/cjs/locale/context.d.ts +5 -4
  41. package/dist/cjs/locale/context.js +15 -8
  42. package/dist/cjs/locale/interface.d.ts +20 -0
  43. package/dist/cjs/locale/util.d.ts +3 -3
  44. package/dist/cjs/style/color.css +3 -0
  45. package/dist/cjs/style/size.css +2 -1
  46. package/dist/cjs/style/themes.css +1 -1
  47. package/dist/cjs/style/variables.css +6 -2
  48. package/dist/cjs/utils/isEqual.js +5 -7
  49. package/dist/cjs/version.d.ts +1 -1
  50. package/dist/cjs/version.js +1 -1
  51. package/dist/esm/Button/style/index.less +5 -4
  52. package/dist/esm/Drawer/drawer.js +2 -1
  53. package/dist/esm/Drawer/interface.d.ts +1 -1
  54. package/dist/esm/Drawer/style/index.less +1 -0
  55. package/dist/esm/Form/form-store.d.ts +2 -1
  56. package/dist/esm/Form/form-store.js +40 -19
  57. package/dist/esm/List/demo/virtual.d.ts +3 -0
  58. package/dist/esm/List/demo/virtual.js +22 -0
  59. package/dist/esm/List/hooks/useListKeyboard.d.ts +28 -0
  60. package/dist/esm/List/hooks/useListKeyboard.js +173 -0
  61. package/dist/esm/List/interface.d.ts +29 -2
  62. package/dist/esm/List/list.js +171 -14
  63. package/dist/esm/List/style/index.less +24 -0
  64. package/dist/esm/Select/demo/columns.d.ts +3 -0
  65. package/dist/esm/Select/demo/columns.js +36 -0
  66. package/dist/esm/Select/hooks/useSelectKeyboard.d.ts +13 -1
  67. package/dist/esm/Select/hooks/useSelectKeyboard.js +91 -14
  68. package/dist/esm/Select/interface.d.ts +30 -3
  69. package/dist/esm/Select/option.js +6 -2
  70. package/dist/esm/Select/options.js +114 -32
  71. package/dist/esm/Select/select.js +40 -11
  72. package/dist/esm/Select/style/index.less +14 -0
  73. package/dist/esm/Selector/interface.d.ts +4 -0
  74. package/dist/esm/Selector/selector.js +10 -4
  75. package/dist/esm/Table/hooks/useColumns.js +1 -1
  76. package/dist/esm/Table/interface.d.ts +1 -1
  77. package/dist/esm/Table/style/index.less +35 -11
  78. package/dist/esm/Table/table.js +54 -2
  79. package/dist/esm/Table/tbody/cell.js +1 -1
  80. package/dist/esm/Table/util/header.d.ts +3 -1
  81. package/dist/esm/Table/util/header.js +30 -2
  82. package/dist/esm/Tree/demo/draggable.js +2 -0
  83. package/dist/esm/Tree/interface.d.ts +46 -23
  84. package/dist/esm/Tree/tree-node.d.ts +1 -1
  85. package/dist/esm/Tree/tree-node.js +26 -31
  86. package/dist/esm/Tree/tree.d.ts +13 -12
  87. package/dist/esm/Tree/tree.js +572 -163
  88. package/dist/esm/Tree/utils/tree-tools.d.ts +43 -10
  89. package/dist/esm/Tree/utils/tree-tools.js +219 -104
  90. package/dist/esm/locale/context.d.ts +5 -4
  91. package/dist/esm/locale/context.js +25 -9
  92. package/dist/esm/locale/interface.d.ts +20 -0
  93. package/dist/esm/locale/util.d.ts +3 -3
  94. package/dist/esm/style/color.css +3 -0
  95. package/dist/esm/style/size.css +2 -1
  96. package/dist/esm/style/themes.css +1 -1
  97. package/dist/esm/style/variables.css +6 -2
  98. package/dist/esm/utils/isEqual.js +5 -7
  99. package/dist/esm/version.d.ts +1 -1
  100. package/dist/esm/version.js +1 -1
  101. package/dist/umd/yee-c.min.css +4 -4
  102. package/dist/umd/yee-c.min.js +1 -1
  103. package/package.json +1 -1
  104. package/src/Button/style/index.less +5 -4
  105. package/src/Drawer/drawer.tsx +1 -1
  106. package/src/Drawer/interface.ts +1 -0
  107. package/src/Drawer/style/index.less +1 -0
  108. package/src/Form/form-store.ts +42 -15
  109. package/src/List/demo/virtual.tsx +20 -0
  110. package/src/List/hooks/useListKeyboard.ts +235 -0
  111. package/src/List/index.en-US.md +6 -0
  112. package/src/List/index.zh-CN.md +6 -0
  113. package/src/List/interface.ts +29 -2
  114. package/src/List/list.tsx +157 -19
  115. package/src/List/style/index.less +24 -0
  116. package/src/Select/demo/columns.tsx +35 -0
  117. package/src/Select/hooks/useSelectKeyboard.ts +112 -15
  118. package/src/Select/index.en-US.md +4 -0
  119. package/src/Select/index.zh-CN.md +4 -0
  120. package/src/Select/interface.ts +31 -4
  121. package/src/Select/option.tsx +9 -3
  122. package/src/Select/options.tsx +119 -26
  123. package/src/Select/select.tsx +41 -8
  124. package/src/Select/style/index.less +14 -0
  125. package/src/Selector/interface.ts +4 -0
  126. package/src/Selector/selector.tsx +8 -3
  127. package/src/Table/hooks/useColumns.ts +1 -1
  128. package/src/Table/interface.ts +1 -1
  129. package/src/Table/style/index.less +35 -11
  130. package/src/Table/table.tsx +60 -1
  131. package/src/Table/tbody/cell.tsx +1 -1
  132. package/src/Table/util/header.ts +48 -2
  133. package/src/Tree/demo/draggable.tsx +2 -0
  134. package/src/Tree/interface.ts +46 -23
  135. package/src/Tree/tree-node.tsx +26 -29
  136. package/src/Tree/tree.tsx +573 -274
  137. package/src/Tree/utils/tree-tools.ts +231 -125
  138. package/src/locale/_README.md +22 -13
  139. package/src/locale/context.tsx +33 -16
  140. package/src/locale/interface.ts +24 -0
  141. package/src/locale/util.ts +6 -6
  142. package/src/style/color.css +3 -0
  143. package/src/style/size.css +2 -1
  144. package/src/utils/isEqual.ts +5 -7
  145. package/src/version.ts +1 -1
@@ -98,6 +98,7 @@ var Selector = import_react.default.forwardRef(
98
98
  disabled,
99
99
  options = [],
100
100
  selectedKeys,
101
+ looseMatch = false,
101
102
  orphanClassName,
102
103
  orphanStyle,
103
104
  allowClear = true,
@@ -123,6 +124,7 @@ var Selector = import_react.default.forwardRef(
123
124
  "disabled",
124
125
  "options",
125
126
  "selectedKeys",
127
+ "looseMatch",
126
128
  "orphanClassName",
127
129
  "orphanStyle",
128
130
  "allowClear",
@@ -149,7 +151,7 @@ var Selector = import_react.default.forwardRef(
149
151
  return [];
150
152
  }
151
153
  return selectedKeys.map((key) => {
152
- const opt = options.find((o) => o.value === key);
154
+ const opt = looseMatch ? options.find((o) => String(o.value) === String(key)) : options.find((o) => o.value === key);
153
155
  if (opt) {
154
156
  return __spreadProps(__spreadValues({}, opt), {
155
157
  children: typeof optionLabelProp === "function" ? optionLabelProp(opt) : opt[optionLabelProp],
@@ -163,7 +165,7 @@ var Selector = import_react.default.forwardRef(
163
165
  _orphan: true
164
166
  };
165
167
  });
166
- }, [options, selectedKeys, optionLabelProp]);
168
+ }, [options, selectedKeys, optionLabelProp, looseMatch]);
167
169
  const handleClick = () => {
168
170
  if (inputRef.current && !disabled) {
169
171
  inputRef.current.focus();
@@ -247,7 +249,7 @@ var Selector = import_react.default.forwardRef(
247
249
  );
248
250
  }
249
251
  const key = selectedKeys.length ? selectedKeys[0] : "";
250
- const opt = Array.isArray(options) ? options.find((opt2) => opt2.value === key) : null;
252
+ const opt = Array.isArray(options) ? looseMatch ? options.find((opt2) => String(opt2.value) === String(key)) : options.find((opt2) => opt2.value === key) : null;
251
253
  const isOrphan = !opt && key !== "";
252
254
  const label = opt ? typeof optionLabelProp === "function" ? optionLabelProp(opt) : opt[optionLabelProp] : isOrphan ? String(key) : null;
253
255
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, renderSearch(), label && /* @__PURE__ */ import_react.default.createElement(
@@ -76,7 +76,7 @@ function useColumns({
76
76
  const tree = (0, import_header.injectSelectionExpand)(base, rowSelection, expandable);
77
77
  const leaves = (0, import_header.flattenLeafColumns)(tree);
78
78
  const wraped = (0, import_util.handleColumns)(leaves);
79
- const rows = (0, import_header.parseHeaderRows)(tree);
79
+ const rows = (0, import_header.parseHeaderRows)(tree, wraped);
80
80
  return { wrapedColumns: wraped, headerRows: rows };
81
81
  }, [childColumns, columns, shouldRenderSelection, shouldRenderExpand]);
82
82
  return {
@@ -498,7 +498,7 @@ export interface TableProps extends FooterProps, Omit<HeaderProps, 'pageData'>,
498
498
  /**
499
499
  * Row class name, unlike classNames, this prop can be set dynamically via a function
500
500
  */
501
- rowClassName?: (record: object) => string | undefined;
501
+ rowClassName?: (record: Record<string, any>) => string | undefined;
502
502
  /**
503
503
  * Row style, unlike styles, this prop can be set dynamically via a function
504
504
  */
@@ -49,6 +49,12 @@
49
49
  background-color: var(--yee-table-head-cell-split-line-color, #eee);
50
50
  }
51
51
  }
52
+
53
+ &-fixed-left,
54
+ &-fixed-right {
55
+ position: sticky;
56
+ z-index: 1;
57
+ }
52
58
  }
53
59
 
54
60
  &-cell {
@@ -84,6 +90,16 @@
84
90
  &-wrapper {
85
91
  overflow: auto;
86
92
  width: 100%;
93
+
94
+ &-scroll-left @{pls}-cell-fixed-left-last {
95
+ box-shadow: 6px 0 6px -4px
96
+ var(--yee-table-fixed-left-after-bs-color);
97
+ }
98
+
99
+ &-scroll-right @{pls}-cell-fixed-right-first {
100
+ box-shadow: -6px 0 6px -4px
101
+ var(--yee-table-fixed-right-after-bs-color);
102
+ }
87
103
  }
88
104
 
89
105
  > table {
@@ -101,10 +117,18 @@
101
117
  }
102
118
  }
103
119
 
120
+ &-row {
121
+ background-color: var(--yee-table-row-bg-color);
122
+ }
123
+
104
124
  &-even-row {
105
125
  background-color: var(--yee-table-even-row-bg-color);
106
126
  }
107
127
 
128
+ &-odd-row {
129
+ background-color: var(--yee-table-odd-row-bg-color);
130
+ }
131
+
108
132
  &-column-sorters {
109
133
  display: inline-flex;
110
134
  align-items: center;
@@ -137,7 +161,7 @@
137
161
  &-fixed-left,
138
162
  &-fixed-right {
139
163
  position: sticky;
140
- background-color: inherit;
164
+ background-color: var(--yee-table-fixed-column-bg-color);
141
165
  }
142
166
  }
143
167
 
@@ -163,17 +187,17 @@
163
187
  }
164
188
  }
165
189
 
166
- &-odd-row {
167
- > @{pls}-cell {
168
- background-color: var(--yee-table-odd-row-bg-color);
169
- }
170
- }
190
+ // &-odd-row {
191
+ // > @{pls}-cell {
192
+ // background-color: var(--yee-table-odd-row-bg-color);
193
+ // }
194
+ // }
171
195
 
172
- &-even-row {
173
- > @{pls}-cell {
174
- background-color: var(--yee-table-even-row-bg-color);
175
- }
176
- }
196
+ // &-even-row {
197
+ // > @{pls}-cell {
198
+ // background-color: var(--yee-table-even-row-bg-color);
199
+ // }
200
+ // }
177
201
 
178
202
  &-footer {
179
203
  display: flex;
@@ -189,6 +189,28 @@ var Table = import_react.default.forwardRef((baseprops, ref) => {
189
189
  onChange: onSelectionChange
190
190
  } = (0, import_useSelection.default)({ pageData, dataSource, getRowKey, rowSelection, allKeys });
191
191
  const prevSortersRef = (0, import_react.useRef)({});
192
+ const contentWrapperRef = (0, import_react.useRef)(null);
193
+ const contentRef = (0, import_react.useRef)(null);
194
+ const [horizontalScroll, setHorizontalScroll] = import_react.default.useState({
195
+ left: false,
196
+ right: false
197
+ });
198
+ const updateHorizontalScroll = import_react.default.useCallback(() => {
199
+ const wrapper = contentWrapperRef.current;
200
+ const content = contentRef.current;
201
+ if (!wrapper || !content)
202
+ return;
203
+ const scrollContainer = content.scrollWidth - content.clientWidth > 1 ? content : wrapper;
204
+ const maxScrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;
205
+ const hasHorizontalScroll = maxScrollLeft > 1;
206
+ const next = {
207
+ left: hasHorizontalScroll && scrollContainer.scrollLeft > 1,
208
+ right: hasHorizontalScroll && scrollContainer.scrollLeft < maxScrollLeft - 1
209
+ };
210
+ setHorizontalScroll(
211
+ (current2) => current2.left === next.left && current2.right === next.right ? current2 : next
212
+ );
213
+ }, []);
192
214
  const onFilter = import_react.default.useCallback(
193
215
  (...args) => {
194
216
  onFilterInternal(...args);
@@ -229,6 +251,21 @@ var Table = import_react.default.forwardRef((baseprops, ref) => {
229
251
  return;
230
252
  }
231
253
  }, [sorters, current, pageSize, pageData, sortedData, onChange]);
254
+ (0, import_react.useEffect)(() => {
255
+ updateHorizontalScroll();
256
+ const wrapper = contentWrapperRef.current;
257
+ const content = contentRef.current;
258
+ if (!wrapper || !content)
259
+ return void 0;
260
+ if (typeof ResizeObserver === "undefined") {
261
+ window.addEventListener("resize", updateHorizontalScroll);
262
+ return () => window.removeEventListener("resize", updateHorizontalScroll);
263
+ }
264
+ const resizeObserver = new ResizeObserver(updateHorizontalScroll);
265
+ resizeObserver.observe(wrapper);
266
+ resizeObserver.observe(content);
267
+ return () => resizeObserver.disconnect();
268
+ }, [updateHorizontalScroll, wrapedColumns, pageData, scroll == null ? void 0 : scroll.x]);
232
269
  const renderHeader = () => {
233
270
  return /* @__PURE__ */ import_react.default.createElement(
234
271
  import_header.default,
@@ -305,17 +342,30 @@ var Table = import_react.default.forwardRef((baseprops, ref) => {
305
342
  },
306
343
  /* @__PURE__ */ import_react.default.createElement("table", __spreadValues({}, tableProps), /* @__PURE__ */ import_react.default.createElement(import_col_group.default, { columns: wrapedColumns }), renderTHeader(), renderTBody(), renderTFooter())
307
344
  );
308
- return /* @__PURE__ */ import_react.default.createElement("div", { className: `${prefixCls}-content-wrapper` }, /* @__PURE__ */ import_react.default.createElement(
345
+ return /* @__PURE__ */ import_react.default.createElement(
309
346
  "div",
310
347
  {
311
- className: (0, import_clsx.default)(`${prefixCls}-content`, {
312
- [`${prefixCls}-${size}-size`]: size,
313
- [`${prefixCls}-fixed-header`]: scroll == null ? void 0 : scroll.y
348
+ ref: contentWrapperRef,
349
+ className: (0, import_clsx.default)(`${prefixCls}-content-wrapper`, {
350
+ [`${prefixCls}-content-wrapper-scroll-left`]: horizontalScroll.left,
351
+ [`${prefixCls}-content-wrapper-scroll-right`]: horizontalScroll.right
314
352
  }),
315
- style: { height: scroll == null ? void 0 : scroll.y, width: scroll == null ? void 0 : scroll.x }
353
+ onScroll: updateHorizontalScroll
316
354
  },
317
- table2
318
- ));
355
+ /* @__PURE__ */ import_react.default.createElement(
356
+ "div",
357
+ {
358
+ ref: contentRef,
359
+ className: (0, import_clsx.default)(`${prefixCls}-content`, {
360
+ [`${prefixCls}-${size}-size`]: size,
361
+ [`${prefixCls}-fixed-header`]: scroll == null ? void 0 : scroll.y
362
+ }),
363
+ style: { height: scroll == null ? void 0 : scroll.y, width: scroll == null ? void 0 : scroll.x },
364
+ onScroll: updateHorizontalScroll
365
+ },
366
+ table2
367
+ )
368
+ );
319
369
  };
320
370
  const renderFooter = () => {
321
371
  return /* @__PURE__ */ import_react.default.createElement(
@@ -95,7 +95,7 @@ var TableCell = (props) => {
95
95
  {
96
96
  [`${prefixCls}-cell-fixed-${fixed}`]: fixed,
97
97
  [`${prefixCls}-cell-fixed-${fixed}-first`]: isFixedRightFirst,
98
- [`${prefixCls}-fixed-${fixed}-last`]: isFixedLeftLast
98
+ [`${prefixCls}-cell-fixed-${fixed}-last`]: isFixedLeftLast
99
99
  },
100
100
  className
101
101
  );
@@ -11,10 +11,12 @@ export declare function flattenLeafColumns(columns: WrapedColumnProps[], parentF
11
11
  *
12
12
  * - Pass 1 (DFS): place each column into the row matching its depth; a group's
13
13
  * colSpan equals the sum of its children's colSpans.
14
+ * - Fixed metadata from the resolved leaf columns is reused by leaf cells and
15
+ * aggregated for group cells whose descendants share the same fixed side.
14
16
  * - Pass 2: leaf cells (no sub-columns) get rowSpan = rowCount - rowIndex so
15
17
  * they stretch down to the last header row; group cells keep rowSpan = 1.
16
18
  */
17
- export declare function parseHeaderRows(rootColumns: WrapedColumnProps[]): HeaderCell[][];
19
+ export declare function parseHeaderRows(rootColumns: WrapedColumnProps[], resolvedLeafColumns?: WrapedColumnProps[]): HeaderCell[][];
18
20
  /**
19
21
  * Inject selection / expand columns into the top level of the column tree.
20
22
  * `index` is a 1-based position among the top-level columns.
@@ -52,21 +52,48 @@ function flattenLeafColumns(columns, parentFixed) {
52
52
  return [...list, __spreadProps(__spreadValues({}, column), { fixed })];
53
53
  }, []);
54
54
  }
55
- function parseHeaderRows(rootColumns) {
55
+ function parseHeaderRows(rootColumns, resolvedLeafColumns = flattenLeafColumns(rootColumns)) {
56
56
  const rows = [];
57
+ let leafIndex = 0;
57
58
  const fillRowCells = (columns, rowIndex) => {
58
59
  rows[rowIndex] = rows[rowIndex] || [];
59
60
  let colSpanTotal = 0;
60
- columns.filter(Boolean).forEach((column) => {
61
+ columns.filter(Boolean).forEach((sourceColumn) => {
62
+ var _a, _b;
63
+ let column = sourceColumn;
64
+ const subColumns = sourceColumn.children;
65
+ const leafStartIndex = leafIndex;
61
66
  const cell = {
62
67
  column,
63
68
  colSpan: 1,
64
69
  rowSpan: 1
65
70
  };
66
- const subColumns = column.children;
67
71
  if (subColumns && subColumns.length > 0) {
68
72
  cell.colSpan = fillRowCells(subColumns, rowIndex + 1);
69
73
  cell.hasSubColumns = true;
74
+ const groupLeaves = resolvedLeafColumns.slice(
75
+ leafStartIndex,
76
+ leafIndex
77
+ );
78
+ const fixed = (_a = groupLeaves[0]) == null ? void 0 : _a.fixed;
79
+ const isFixedGroup = (fixed === "left" || fixed === "right") && groupLeaves.every((leaf) => leaf.fixed === fixed);
80
+ if (isFixedGroup) {
81
+ const offsetLeaf = fixed === "left" ? groupLeaves[0] : groupLeaves[groupLeaves.length - 1];
82
+ const boundaryLeaf = fixed === "left" ? groupLeaves[groupLeaves.length - 1] : groupLeaves[0];
83
+ column = __spreadProps(__spreadValues({}, sourceColumn), {
84
+ fixed,
85
+ style: __spreadProps(__spreadValues({}, sourceColumn.style), {
86
+ [fixed]: (_b = offsetLeaf.style) == null ? void 0 : _b[fixed]
87
+ }),
88
+ isFixedLeftLast: fixed === "left" && boundaryLeaf.isFixedLeftLast,
89
+ isFixedRightFirst: fixed === "right" && boundaryLeaf.isFixedRightFirst
90
+ });
91
+ cell.column = column;
92
+ }
93
+ } else {
94
+ column = resolvedLeafColumns[leafIndex] || sourceColumn;
95
+ cell.column = column;
96
+ leafIndex += 1;
70
97
  }
71
98
  rows[rowIndex].push(cell);
72
99
  colSpanTotal += cell.colSpan;
@@ -78,6 +78,8 @@ var draggable_default = () => {
78
78
  {
79
79
  dragKey: info.dragKey,
80
80
  dropKey: info.dropKey,
81
+ dragPath: info.dragPath,
82
+ dropPath: info.dropPath,
81
83
  position: info.position
82
84
  },
83
85
  FIELD_NAMES
@@ -4,13 +4,14 @@ export type DragPosition = 'before' | 'after' | 'inside';
4
4
  export type { MoveInfo } from './utils/tree-tools';
5
5
  export type TreeNode<T> = {
6
6
  /**
7
- * uid
7
+ * Unique internal identifier built from key path joined by '\x00'.
8
+ * Guaranteed unique even when user-provided `key` values repeat across branches.
8
9
  */
9
10
  uid: string;
10
11
  /**
11
- * Unique key
12
- * */
13
- key: string;
12
+ * User-provided key (may not be globally unique)
13
+ */
14
+ key: string | number;
14
15
  /**
15
16
  * Display node text
16
17
  */
@@ -20,7 +21,7 @@ export type TreeNode<T> = {
20
21
  */
21
22
  title?: string;
22
23
  /**
23
- * Child nodes
24
+ * Child nodes (only present in raw tree; not used in flat list)
24
25
  */
25
26
  children?: Array<TreeNode<T>>;
26
27
  /**
@@ -28,16 +29,16 @@ export type TreeNode<T> = {
28
29
  */
29
30
  depth: number;
30
31
  /**
31
- * Parent node key
32
- * */
33
- pKey: string | null;
32
+ * Parent node uid (null for root nodes)
33
+ */
34
+ pUid: string | null;
34
35
  /**
35
36
  * Whether this is a leaf node
36
- * */
37
+ */
37
38
  isLeaf: boolean;
38
39
  /**
39
40
  * Whether this is the last node at its level
40
- * */
41
+ */
41
42
  isLast: boolean;
42
43
  /**
43
44
  * Whether disabled
@@ -48,17 +49,17 @@ export type TreeNode<T> = {
48
49
  */
49
50
  icon?: React.ReactNode | (() => React.ReactNode);
50
51
  /**
51
- * Ancestor keys
52
+ * Ancestor keys (user-provided keys, for building uid path)
52
53
  */
53
- path: string[];
54
+ path: Array<string | number>;
54
55
  /**
55
- * Whether to show connecting lines
56
+ * Whether to show connecting lines at given depth levels
56
57
  */
57
58
  lines: number[];
58
59
  /**
59
- * List of child node keys
60
+ * All descendant uids (collected bottom-up). Used for check/uncheck propagation.
60
61
  */
61
- childKeys?: Array<string | number>;
62
+ childUids?: Array<string>;
62
63
  /**
63
64
  * Original data
64
65
  */
@@ -66,6 +67,7 @@ export type TreeNode<T> = {
66
67
  };
67
68
  export interface TreeNodeProps<T> {
68
69
  node: TreeNode<T>;
70
+ style?: React.CSSProperties;
69
71
  }
70
72
  export interface TreeProps<T> {
71
73
  /**
@@ -89,11 +91,11 @@ export interface TreeProps<T> {
89
91
  */
90
92
  defaultExpandAll?: boolean;
91
93
  /**
92
- * Specify which tree nodes to expand by default
94
+ * Specify which tree nodes to expand by default (user keys)
93
95
  */
94
96
  defaultExpandedKeys?: string[];
95
97
  /**
96
- * Controlled expanded tree nodes
98
+ * Controlled expanded tree nodes (user keys)
97
99
  */
98
100
  expandedKeys?: string[];
99
101
  /**
@@ -124,6 +126,10 @@ export interface TreeProps<T> {
124
126
  dropNode: T;
125
127
  dragKey: string | number;
126
128
  dropKey: string | number;
129
+ /** Full key path from root to the dragged node (for non-unique key support) */
130
+ dragPath: Array<string | number>;
131
+ /** Full key path from root to the drop target (for non-unique key support) */
132
+ dropPath: Array<string | number>;
127
133
  position: DragPosition;
128
134
  /** Convenience flag: true when position is 'before' or 'after' */
129
135
  dropToGap: boolean;
@@ -164,22 +170,39 @@ export interface TreeProps<T> {
164
170
  loadData?: () => void;
165
171
  /**
166
172
  * Data source
167
- * */
173
+ */
168
174
  dataSource?: Array<T> | T;
169
175
  /**
170
- * Checked tree nodes (controlled)
176
+ * Enable virtual scrolling for large datasets.
177
+ * Requires `height` to be set.
178
+ * @default false
179
+ */
180
+ virtual?: boolean;
181
+ /**
182
+ * Height of the scrollable container in pixels.
183
+ * Required when `virtual` is true.
184
+ */
185
+ height?: number;
186
+ /**
187
+ * Fixed height of each tree node row in pixels.
188
+ * Used for virtual scroll calculation.
189
+ * @default 28
190
+ */
191
+ itemHeight?: number;
192
+ /**
193
+ * Checked tree nodes (controlled, user keys)
171
194
  */
172
195
  checkedKeys?: Array<string | number>;
173
196
  /**
174
- * Checked tree nodes (uncontrolled)
197
+ * Checked tree nodes (uncontrolled, user keys)
175
198
  */
176
199
  defaultCheckedKeys?: Array<string | number>;
177
200
  /**
178
- * Set selected tree nodes, set multiple to true for multi-select
201
+ * Set selected tree nodes, set multiple to true for multi-select (user keys)
179
202
  */
180
203
  selectedKeys?: Array<string | number>;
181
204
  /**
182
- * Set default selected tree nodes, set multiple to true for multi-select
205
+ * Set default selected tree nodes (user keys)
183
206
  */
184
207
  defaultSelectedKeys?: Array<string | number>;
185
208
  /**
@@ -204,6 +227,6 @@ export interface TreeProps<T> {
204
227
  onExpand?: (expandedKeys: Array<string | number>, params: {
205
228
  expanded: boolean;
206
229
  expandedNodes: T[];
207
- node: T[];
230
+ node: T;
208
231
  }) => void;
209
232
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import type { TreeNodeProps } from './interface';
3
3
  import './style/index.less';
4
- declare const Node: <T extends Record<string, unknown> = any>(props: TreeNodeProps<T>) => React.JSX.Element | null;
4
+ declare const Node: <T extends Record<string, unknown> = any>(props: TreeNodeProps<T>) => React.JSX.Element;
5
5
  export default Node;
@@ -54,12 +54,11 @@ var import_Checkbox = __toESM(require("../Checkbox"));
54
54
  var import_tree = require("./tree");
55
55
  var import_style = require("./style/index.less");
56
56
  var Node = (props) => {
57
- const { node } = props;
57
+ const { node, style: nodeStyle } = props;
58
58
  const {
59
- key,
59
+ uid,
60
60
  isLeaf,
61
61
  isLast,
62
- path,
63
62
  label,
64
63
  title,
65
64
  disabled,
@@ -74,12 +73,13 @@ var Node = (props) => {
74
73
  showIcon,
75
74
  icon: contextIcon,
76
75
  showLine,
77
- selectedKeys,
78
- checkedKeys,
79
- expandedKeys,
76
+ selectedUids,
77
+ checkedUids,
78
+ indeterminateUids,
79
+ expandedUids,
80
80
  switcherIcon,
81
81
  draggable,
82
- draggingKey,
82
+ draggingUid,
83
83
  dropState,
84
84
  onCheck,
85
85
  onSelect,
@@ -89,12 +89,10 @@ var Node = (props) => {
89
89
  onNodeDragLeave,
90
90
  onNodeDrop
91
91
  } = (0, import_react.useContext)(import_tree.TreeContext);
92
- const expanded = expandedKeys.includes(key);
93
- const checked = checkedKeys.includes(key);
94
- const selected = selectedKeys.includes(key);
95
- const visible = path.every((p) => expandedKeys.includes(p));
96
- if (!visible)
97
- return null;
92
+ const expanded = expandedUids.has(uid);
93
+ const checked = checkedUids.has(uid);
94
+ const indeterminate = indeterminateUids.has(uid);
95
+ const selected = selectedUids.has(uid);
98
96
  const renderExpandedIcon = () => {
99
97
  const expandedIcon = switcherIcon ? switcherIcon[0] : /* @__PURE__ */ import_react.default.createElement(import_lucide_react.ChevronDown, { strokeWidth: 1 });
100
98
  const collapseIcon = switcherIcon ? switcherIcon[1] : /* @__PURE__ */ import_react.default.createElement(import_lucide_react.ChevronRight, { strokeWidth: 1 });
@@ -113,14 +111,22 @@ var Node = (props) => {
113
111
  size: "small",
114
112
  type: "text",
115
113
  icon: expanded ? expandedIcon : collapseIcon,
116
- onClick: () => onExpand(key)
114
+ onClick: () => onExpand(uid)
117
115
  }
118
116
  ));
119
117
  };
120
118
  const renderCheckbox = () => {
121
119
  if (!checkable)
122
120
  return null;
123
- return /* @__PURE__ */ import_react.default.createElement("span", { className: `${prefixCls}-node-checkbox` }, /* @__PURE__ */ import_react.default.createElement(import_Checkbox.default, { value: key, checked, onChange: onCheck }));
121
+ return /* @__PURE__ */ import_react.default.createElement("span", { className: `${prefixCls}-node-checkbox` }, /* @__PURE__ */ import_react.default.createElement(
122
+ import_Checkbox.default,
123
+ {
124
+ value: uid,
125
+ checked,
126
+ indeterminate,
127
+ onChange: (e) => onCheck(e, uid)
128
+ }
129
+ ));
124
130
  };
125
131
  const renderLabel = () => {
126
132
  const _title = title || (typeof label === "string" ? label : void 0);
@@ -136,7 +142,7 @@ var Node = (props) => {
136
142
  type: "text",
137
143
  title: _title,
138
144
  icon: showIcon ? _icon : void 0,
139
- onClick: disabled ? void 0 : () => onSelect(key)
145
+ onClick: disabled ? void 0 : () => onSelect(uid)
140
146
  },
141
147
  label
142
148
  );
@@ -164,14 +170,14 @@ var Node = (props) => {
164
170
  }
165
171
  ));
166
172
  };
167
- const isDropTarget = (dropState == null ? void 0 : dropState.key) === key;
173
+ const isDropTarget = (dropState == null ? void 0 : dropState.uid) === uid;
168
174
  const dropPosition = isDropTarget ? dropState.position : null;
169
175
  const dragProps = draggable && !disabled ? {
170
176
  draggable: true,
171
- onDragStart: (e) => onNodeDragStart(key, e),
172
- onDragOver: (e) => onNodeDragOver(key, e),
173
- onDragLeave: (e) => onNodeDragLeave(key, e),
174
- onDrop: (e) => onNodeDrop(key, e)
177
+ onDragStart: (e) => onNodeDragStart(uid, e),
178
+ onDragOver: (e) => onNodeDragOver(uid, e),
179
+ onDragLeave: (e) => onNodeDragLeave(uid, e),
180
+ onDrop: (e) => onNodeDrop(uid, e)
175
181
  } : {};
176
182
  return /* @__PURE__ */ import_react.default.createElement(
177
183
  "div",
@@ -180,11 +186,12 @@ var Node = (props) => {
180
186
  [`${prefixCls}-node-with-line`]: showLine,
181
187
  [`${prefixCls}-leaf-node`]: isLeaf,
182
188
  [`${prefixCls}-last-node`]: isLast,
183
- [`${prefixCls}-node-dragging`]: draggingKey === key,
189
+ [`${prefixCls}-node-dragging`]: draggingUid === uid,
184
190
  [`${prefixCls}-node-drag-over-before`]: dropPosition === "before",
185
191
  [`${prefixCls}-node-drag-over-after`]: dropPosition === "after",
186
192
  [`${prefixCls}-node-drag-over-inside`]: dropPosition === "inside"
187
- })
193
+ }),
194
+ style: nodeStyle
188
195
  }, dragProps),
189
196
  renderEmptyNodes(depth),
190
197
  renderExpandedIcon(),
@@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react';
2
2
  import type { DragPosition, TreeProps } from './interface';
3
3
  import './style/index.less';
4
4
  type DropState = {
5
- key: string | number;
5
+ uid: string;
6
6
  position: DragPosition;
7
7
  } | null;
8
8
  export declare const TreeContext: React.Context<{
@@ -12,19 +12,20 @@ export declare const TreeContext: React.Context<{
12
12
  icon?: React.ReactNode | ((props: any) => React.ReactNode);
13
13
  showLine?: boolean | undefined;
14
14
  switcherIcon?: [React.ReactNode, React.ReactNode] | undefined;
15
- selectedKeys: Array<string | number>;
16
- checkedKeys: Array<string | number>;
17
- expandedKeys: Array<string | number>;
15
+ selectedUids: Set<string>;
16
+ checkedUids: Set<string>;
17
+ indeterminateUids: Set<string>;
18
+ expandedUids: Set<string>;
18
19
  draggable?: boolean | undefined;
19
- draggingKey: string | number | null;
20
+ draggingUid: string | null;
20
21
  dropState: DropState;
21
- onCheck: (event: ChangeEvent<HTMLInputElement>) => void;
22
- onSelect: (key: string | number) => void;
23
- onExpand: (key: string | number) => void;
24
- onNodeDragStart: (key: string | number, e: React.DragEvent) => void;
25
- onNodeDragOver: (key: string | number, e: React.DragEvent) => void;
26
- onNodeDragLeave: (key: string | number, e: React.DragEvent) => void;
27
- onNodeDrop: (key: string | number, e: React.DragEvent) => void;
22
+ onCheck: (event: ChangeEvent<HTMLInputElement>, uid: string) => void;
23
+ onSelect: (uid: string) => void;
24
+ onExpand: (uid: string) => void;
25
+ onNodeDragStart: (uid: string, e: React.DragEvent) => void;
26
+ onNodeDragOver: (uid: string, e: React.DragEvent) => void;
27
+ onNodeDragLeave: (uid: string, e: React.DragEvent) => void;
28
+ onNodeDrop: (uid: string, e: React.DragEvent) => void;
28
29
  }>;
29
30
  declare const Tree: <T extends Record<string, unknown> = any>(baseprops: TreeProps<T>) => React.JSX.Element;
30
31
  export default Tree;