@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
@@ -4,6 +4,17 @@ export interface MoveInfo {
4
4
  dragKey: string | number;
5
5
  dropKey: string | number;
6
6
  position: DragPosition;
7
+ /**
8
+ * Full key path from root to the dragged node (inclusive).
9
+ * When provided, enables precise matching even with non-unique keys.
10
+ * Example: ['root', 'parent', 'child']
11
+ */
12
+ dragPath?: Array<string | number>;
13
+ /**
14
+ * Full key path from root to the drop target node (inclusive).
15
+ * When provided, enables precise matching even with non-unique keys.
16
+ */
17
+ dropPath?: Array<string | number>;
7
18
  }
8
19
  /**
9
20
  * Reorder the nested dataSource immutably after a drag.
@@ -13,6 +24,10 @@ export interface MoveInfo {
13
24
  * nodes are reused by reference (data may carry non-cloneable values like
14
25
  * React elements / functions in `icon`).
15
26
  *
27
+ * When `dragPath` / `dropPath` are provided in `info`, matching is done by
28
+ * walking the exact path (supports non-unique keys). Otherwise falls back to
29
+ * first-match by key (backward compatible).
30
+ *
16
31
  * Returns a brand-new root array; returns the input unchanged if dragKey is
17
32
  * not found or drag and drop resolve to the same location.
18
33
  */
@@ -20,20 +35,38 @@ export declare function moveTreeNode<T extends Record<string, unknown>>(tree: T
20
35
  key: keyof T;
21
36
  children: keyof T;
22
37
  }): T[];
23
- export declare function getChildKeys<T extends Record<string, unknown>>(data: T, fieldNames: {
24
- key: keyof T;
25
- children: keyof T;
26
- }): Array<string | number>;
38
+ /**
39
+ * Flatten tree into a flat array with rich metadata.
40
+ *
41
+ * Key design decisions:
42
+ * - Uses `uid` (built from the key path) as the internal identifier, because
43
+ * user-provided `key` values may NOT be globally unique across the tree.
44
+ * - The returned Map is keyed by `uid` for O(1) lookups.
45
+ * - `childUids` is collected bottom-up in a single pass (O(n) total) instead
46
+ * of per-node recursive enumeration (which was O(n²)).
47
+ */
27
48
  export declare function tree2array<T extends Record<string, unknown>>(tree: T | T[], fieldNames: {
28
49
  key: keyof T;
29
50
  label: keyof T;
30
51
  children: keyof T;
31
52
  }): [TreeNode<T>[], Map<string, TreeNode<T>>];
32
- export declare function containsAll<T>(a: Array<T>, b: Array<T>): boolean;
33
- export declare function removeContainsAll<T>(a: Array<T>, b: Array<T>): T[];
34
- export declare function getCheckedKeys({ checked, keys, key, map, }: {
53
+ /**
54
+ * Check whether array `a` contains every element in `b`.
55
+ */
56
+ export declare function containsAll<T>(a: Set<T>, b: Array<T>): boolean;
57
+ /**
58
+ * Remove all elements in `b` from `a`.
59
+ */
60
+ export declare function removeAll<T>(a: Set<T>, b: Array<T>): Set<T>;
61
+ /**
62
+ * Compute new checked uids when a node is toggled.
63
+ * Uses Set-based operations for O(1) membership checks.
64
+ * Disabled nodes are NOT affected by parent/child propagation — their checked
65
+ * state remains unchanged unless they are the directly toggled node.
66
+ */
67
+ export declare function getCheckedKeys({ checked, keys, uid, map, }: {
35
68
  checked: boolean;
36
- keys: Array<string | number>;
37
- key: string | number;
69
+ keys: Set<string>;
70
+ uid: string;
38
71
  map: Map<string, TreeNode<unknown>>;
39
- }): (string | number)[];
72
+ }): Set<string>;
@@ -38,9 +38,8 @@ var tree_tools_exports = {};
38
38
  __export(tree_tools_exports, {
39
39
  containsAll: () => containsAll,
40
40
  getCheckedKeys: () => getCheckedKeys,
41
- getChildKeys: () => getChildKeys,
42
41
  moveTreeNode: () => moveTreeNode,
43
- removeContainsAll: () => removeContainsAll,
42
+ removeAll: () => removeAll,
44
43
  tree2array: () => tree2array
45
44
  });
46
45
  module.exports = __toCommonJS(tree_tools_exports);
@@ -48,19 +47,32 @@ function moveTreeNode(tree, info, fieldNames) {
48
47
  if (!tree || Array.isArray(tree) && tree.length === 0)
49
48
  return [];
50
49
  const { key: K, children: C } = fieldNames;
51
- const { dragKey, dropKey, position } = info;
50
+ const { dragKey, dropKey, position, dragPath, dropPath } = info;
52
51
  const root = Array.isArray(tree) ? tree : [tree];
53
- const detach = (nodes) => {
52
+ const matchNode = (node, targetKey, path, depth) => {
53
+ if (path) {
54
+ return String(node[K]) === String(path[depth]);
55
+ }
56
+ return node[K] === targetKey;
57
+ };
58
+ const isTargetDepth = (path, depth) => {
59
+ if (!path)
60
+ return true;
61
+ return depth === path.length - 1;
62
+ };
63
+ const detach = (nodes, depth) => {
54
64
  let found = null;
55
65
  const next = [];
56
66
  for (const n of nodes) {
57
- if (n[K] === dragKey) {
67
+ if (!found && matchNode(n, dragKey, dragPath, depth) && isTargetDepth(dragPath, depth)) {
58
68
  found = n;
59
69
  continue;
60
70
  }
61
71
  const kids = n[C];
62
- if (Array.isArray(kids)) {
63
- const r = detach(kids);
72
+ if (!found && dragPath && Array.isArray(kids) && !matchNode(n, dragKey, dragPath, depth)) {
73
+ next.push(n);
74
+ } else if (!found && Array.isArray(kids)) {
75
+ const r = detach(kids, depth + 1);
64
76
  if (r.found) {
65
77
  found = r.found;
66
78
  next.push(__spreadProps(__spreadValues({}, n), { [C]: r.nodes }));
@@ -73,25 +85,26 @@ function moveTreeNode(tree, info, fieldNames) {
73
85
  }
74
86
  return { found, nodes: next };
75
87
  };
76
- const { found: dragNode, nodes: withoutDrag } = detach(root);
88
+ const { found: dragNode, nodes: withoutDrag } = detach(root, 0);
77
89
  if (!dragNode)
78
90
  return root;
79
- const insert = (nodes) => {
91
+ const insert = (nodes, depth) => {
80
92
  const next = [];
81
93
  let inserted2 = false;
82
94
  for (const n of nodes) {
83
- if (!inserted2 && position === "inside" && n[K] === dropKey) {
95
+ const isTarget = !inserted2 && matchNode(n, dropKey, dropPath, depth) && isTargetDepth(dropPath, depth);
96
+ if (isTarget && position === "inside") {
84
97
  const oldKids = Array.isArray(n[C]) ? n[C] : [];
85
98
  next.push(__spreadProps(__spreadValues({}, n), { [C]: [...oldKids, dragNode] }));
86
99
  inserted2 = true;
87
100
  continue;
88
101
  }
89
- if (!inserted2 && position === "before" && n[K] === dropKey) {
102
+ if (isTarget && position === "before") {
90
103
  next.push(dragNode, n);
91
104
  inserted2 = true;
92
105
  continue;
93
106
  }
94
- if (!inserted2 && position === "after" && n[K] === dropKey) {
107
+ if (isTarget && position === "after") {
95
108
  next.push(n, dragNode);
96
109
  inserted2 = true;
97
110
  continue;
@@ -99,8 +112,10 @@ function moveTreeNode(tree, info, fieldNames) {
99
112
  const kids = n[C];
100
113
  if (inserted2 || !Array.isArray(kids)) {
101
114
  next.push(n);
115
+ } else if (dropPath && !matchNode(n, dropKey, dropPath, depth)) {
116
+ next.push(n);
102
117
  } else {
103
- const r = insert(kids);
118
+ const r = insert(kids, depth + 1);
104
119
  if (r.inserted) {
105
120
  next.push(__spreadProps(__spreadValues({}, n), { [C]: r.nodes }));
106
121
  inserted2 = true;
@@ -111,23 +126,9 @@ function moveTreeNode(tree, info, fieldNames) {
111
126
  }
112
127
  return { inserted: inserted2, nodes: next };
113
128
  };
114
- const { inserted, nodes: result } = insert(withoutDrag);
129
+ const { inserted, nodes: result } = insert(withoutDrag, 0);
115
130
  return inserted ? result : root;
116
131
  }
117
- function getChildKeys(data, fieldNames) {
118
- const { key, children } = fieldNames;
119
- const _children = data[children];
120
- const keys = [];
121
- if (Array.isArray(_children) && _children.length) {
122
- _children.forEach((node) => {
123
- keys.push(node[key]);
124
- if (Array.isArray(node[children])) {
125
- keys.push(...getChildKeys(node, fieldNames));
126
- }
127
- });
128
- }
129
- return keys;
130
- }
131
132
  function tree2array(tree, fieldNames) {
132
133
  if (!tree || Array.isArray(tree) && tree.length === 0)
133
134
  return [[], /* @__PURE__ */ new Map()];
@@ -136,108 +137,145 @@ function tree2array(tree, fieldNames) {
136
137
  const map = /* @__PURE__ */ new Map();
137
138
  const { key, label, children } = fieldNames;
138
139
  function walk({
139
- data: data2,
140
- pKey,
140
+ data: node,
141
+ pUid,
141
142
  depth,
142
143
  path,
143
144
  isLast,
144
145
  lines
145
146
  }) {
146
- const _key = data2[key];
147
- const _label = data2[label];
148
- const _children = data2[children];
149
- const nextPath = [...path, _key];
150
- const uid = nextPath.join("_");
151
- const isParent = !!(Array.isArray(_children) && _children.length);
147
+ const rawKey = node[key];
148
+ const _label = node[label];
149
+ const _children = node[children];
150
+ const nextPath = [...path, rawKey];
151
+ const uid = pUid ? `${pUid}\0${String(rawKey)}` : String(rawKey);
152
+ const isParent = Array.isArray(_children) && _children.length > 0;
152
153
  const wrapperData = {
153
154
  uid,
154
- key: _key,
155
+ key: rawKey,
155
156
  label: _label,
157
+ title: node.title,
156
158
  path,
157
- pKey,
159
+ pUid,
158
160
  depth,
159
161
  isLeaf: !isParent,
160
162
  isLast,
161
163
  lines,
162
- disabled: data2.disabled,
163
- icon: data2.icon,
164
- childKeys: getChildKeys(data2, fieldNames),
165
- original: data2
164
+ disabled: node.disabled,
165
+ icon: node.icon,
166
+ childUids: void 0,
167
+ // will be filled after recursion
168
+ original: node
166
169
  };
167
170
  res.push(wrapperData);
168
- map.set(_key, wrapperData);
169
- const total2 = Array.isArray(_children) ? _children.length : 0;
170
- _children == null ? void 0 : _children.forEach(
171
- (node, index) => walk({
172
- data: node,
173
- pKey: _key,
174
- depth: depth + 1,
175
- path: nextPath,
176
- isLast: index + 1 === total2,
177
- lines: isLast ? lines : [...lines, depth]
178
- })
179
- );
171
+ map.set(uid, wrapperData);
172
+ const childTotal = isParent ? _children.length : 0;
173
+ const allDescendantUids = [];
174
+ if (isParent) {
175
+ _children.forEach((child, index) => {
176
+ const childIsLast = index + 1 === childTotal;
177
+ const descendantUids = walk({
178
+ data: child,
179
+ pUid: uid,
180
+ depth: depth + 1,
181
+ path: nextPath,
182
+ isLast: childIsLast,
183
+ lines: isLast ? lines : [...lines, depth]
184
+ });
185
+ allDescendantUids.push(...descendantUids);
186
+ });
187
+ }
188
+ if (allDescendantUids.length > 0) {
189
+ wrapperData.childUids = allDescendantUids;
190
+ }
191
+ return [uid, ...allDescendantUids];
180
192
  }
181
- const total = Array.isArray(data) ? data.length : 0;
182
- data.forEach(
183
- (node, index) => walk({
193
+ const rootTotal = data.length;
194
+ data.forEach((node, index) => {
195
+ walk({
184
196
  data: node,
185
- pKey: null,
197
+ pUid: null,
186
198
  depth: 0,
187
199
  path: [],
188
- isLast: index + 1 === total,
189
- lines: index + 1 === total ? [] : [0]
190
- })
191
- );
200
+ isLast: index + 1 === rootTotal,
201
+ lines: index + 1 === rootTotal ? [] : [0]
202
+ });
203
+ });
192
204
  return [res, map];
193
205
  }
194
206
  function containsAll(a, b) {
195
- if (b.length > a.length) {
196
- return false;
197
- }
198
- return b.every((i) => a.includes(i));
199
- }
200
- function removeContainsAll(a, b) {
201
207
  if (!b || b.length === 0)
202
- return a;
203
- const toRemove = new Set(b);
204
- return a.filter((i) => !toRemove.has(i));
208
+ return true;
209
+ return b.every((i) => a.has(i));
210
+ }
211
+ function removeAll(a, b) {
212
+ const result = /* @__PURE__ */ new Set();
213
+ a.forEach((item) => result.add(item));
214
+ for (const item of b) {
215
+ result.delete(item);
216
+ }
217
+ return result;
205
218
  }
206
219
  function getCheckedKeys({
207
220
  checked,
208
221
  keys,
209
- key,
222
+ uid,
210
223
  map
211
224
  }) {
212
- let newKeys = [...keys];
213
- const item = map.get(key);
214
- const childKeys = (item == null ? void 0 : item.childKeys) || [];
215
- let pKey = item == null ? void 0 : item.pKey;
225
+ const item = map.get(uid);
226
+ if (!item)
227
+ return keys;
228
+ const childUids = item.childUids || [];
229
+ const newKeys = /* @__PURE__ */ new Set();
230
+ keys.forEach((k) => newKeys.add(k));
216
231
  if (checked) {
217
- newKeys = [...newKeys, ...childKeys, key];
218
- while (pKey) {
219
- const parent = map.get(pKey);
232
+ newKeys.add(uid);
233
+ for (const cuid of childUids) {
234
+ const child = map.get(cuid);
235
+ if (child && !child.disabled) {
236
+ newKeys.add(cuid);
237
+ }
238
+ }
239
+ let pUid = item.pUid;
240
+ while (pUid) {
241
+ const parent = map.get(pUid);
220
242
  if (parent) {
221
- if (!newKeys.includes(parent.key) && containsAll(newKeys, parent.childKeys)) {
222
- newKeys.push(parent.key);
243
+ if (parent.disabled) {
244
+ break;
245
+ }
246
+ if (!newKeys.has(parent.uid) && parent.childUids) {
247
+ const allNonDisabledChecked = parent.childUids.every((cuid) => {
248
+ const child = map.get(cuid);
249
+ return child && child.disabled || newKeys.has(cuid);
250
+ });
251
+ if (allNonDisabledChecked) {
252
+ newKeys.add(parent.uid);
253
+ }
223
254
  }
224
- pKey = parent.pKey;
255
+ pUid = parent.pUid;
225
256
  } else {
226
- pKey = null;
257
+ pUid = null;
227
258
  }
228
259
  }
229
260
  } else {
230
- newKeys = newKeys.filter((k) => k !== key);
231
- newKeys = removeContainsAll(newKeys, childKeys);
232
- while (pKey) {
233
- const parent = map.get(pKey);
261
+ newKeys.delete(uid);
262
+ for (const cuid of childUids) {
263
+ const child = map.get(cuid);
264
+ if (child && !child.disabled) {
265
+ newKeys.delete(cuid);
266
+ }
267
+ }
268
+ let pUid = item.pUid;
269
+ while (pUid) {
270
+ const parent = map.get(pUid);
234
271
  if (parent) {
235
- if (newKeys.includes(parent.key)) {
236
- newKeys = newKeys.filter((k) => k !== parent.key);
272
+ if (parent.disabled) {
273
+ break;
237
274
  }
238
- pKey = parent.pKey;
275
+ newKeys.delete(parent.uid);
276
+ pUid = parent.pUid;
239
277
  } else {
240
- pKey = null;
278
+ pUid = null;
241
279
  }
242
280
  }
243
281
  }
@@ -1,16 +1,17 @@
1
1
  import React from 'react';
2
- import type { Locale, TFunction } from './interface';
2
+ import type { Locale, LocaleConfigInput, TFunction } from './interface';
3
3
  interface LocaleContextType {
4
4
  locale: Locale;
5
5
  lang: string;
6
- setLocale: (locale: Locale | string) => void;
6
+ setLocale: (locale: LocaleConfigInput) => void;
7
7
  t: TFunction;
8
8
  }
9
9
  export declare const LocaleContext: React.Context<LocaleContextType>;
10
10
  interface LocaleProviderProps {
11
11
  children: React.ReactNode;
12
- /** Initial locale pack or language code */
13
- defaultLocale?: Locale | string;
12
+ /** Initial locale: a language code, or a full/partial locale object.
13
+ * Partial objects are merged onto the matching built-in pack. */
14
+ defaultLocale?: LocaleConfigInput;
14
15
  /** Async locale loader function */
15
16
  loadLocale?: (lang: string) => Promise<Locale>;
16
17
  /** Whether to auto-fallback to default for missing fields */
@@ -72,6 +72,16 @@ var createDefaultValue = () => {
72
72
  };
73
73
  };
74
74
  var defaultValue = createDefaultValue();
75
+ function resolveLocaleConfigInput(input) {
76
+ if (typeof input === "string") {
77
+ return import_constants.LOCALE_CONFIGS[input] || import_en_US.default;
78
+ }
79
+ if (input && typeof input.locale === "string") {
80
+ const base = import_constants.LOCALE_CONFIGS[input.locale] || import_constants.DEFAULT_LOCALE_CONFIG;
81
+ return (0, import_util.deepMerge)(base, input);
82
+ }
83
+ return import_en_US.default;
84
+ }
75
85
  var LocaleContext = (0, import_react.createContext)(defaultValue);
76
86
  function LocaleProvider({
77
87
  children,
@@ -79,12 +89,9 @@ function LocaleProvider({
79
89
  loadLocale,
80
90
  fallbackToDefault = true
81
91
  }) {
82
- const [locale, setLocaleState] = (0, import_react.useState)(() => {
83
- if (typeof initialLocale === "string") {
84
- return import_constants.LOCALE_CONFIGS[initialLocale] || import_en_US.default;
85
- }
86
- return (0, import_util.isValidLocale)(initialLocale) ? initialLocale : import_en_US.default;
87
- });
92
+ const [locale, setLocaleState] = (0, import_react.useState)(
93
+ () => resolveLocaleConfigInput(initialLocale)
94
+ );
88
95
  const [lang, setLang] = (0, import_react.useState)(
89
96
  typeof initialLocale === "string" ? initialLocale : initialLocale.locale
90
97
  );
@@ -145,8 +152,8 @@ function LocaleProvider({
145
152
  return;
146
153
  }
147
154
  loadAndSetLocale(target);
148
- } else if ((0, import_util.isValidLocale)(target)) {
149
- setLocaleState(target);
155
+ } else if (target && typeof target.locale === "string") {
156
+ setLocaleState(resolveLocaleConfigInput(target));
150
157
  setLang(target.locale);
151
158
  }
152
159
  },
@@ -126,4 +126,24 @@ type ExtractParams<T extends string> = T extends `${infer Pre}{${infer P}}${infe
126
126
  } : Record<string, never>;
127
127
  export type LocaleParams<K extends LocaleKey> = ExtractParams<K extends keyof Locale ? Locale[K] : K extends `${infer A}.${infer B}` ? A extends keyof Locale ? B extends keyof Locale[A] ? Locale[A][B] : never : never : never>;
128
128
  export type TFunction = <K extends LocaleKey>(key: K, params?: LocaleParams<K>) => string;
129
+ /**
130
+ * Recursively-optional version of T. Every level is optional; arrays are kept
131
+ * as-is (replaced wholesale rather than element-merged).
132
+ *
133
+ * Used so a locale override only needs to specify the keys it changes:
134
+ * `{ datepicker: { now: 'Now' } }` is a valid `DeepPartial<Locale>`.
135
+ */
136
+ export type DeepPartial<T> = T extends (...args: any[]) => any ? T : T extends object ? T extends readonly any[] ? T : {
137
+ [K in keyof T]?: DeepPartial<T[K]>;
138
+ } : T;
139
+ /**
140
+ * Locale input accepted by `LocaleProvider` / `useLocale().setLocale`:
141
+ * - a language code string (`'zh_CN'`), resolved from the built-in packs, or
142
+ * - a (possibly partial) locale object. A partial object MUST carry `locale`
143
+ * so the provider knows which built-in pack to merge the overrides onto;
144
+ * only the keys you specify are overridden, everything else is inherited.
145
+ */
146
+ export type LocaleConfigInput = string | (DeepPartial<Locale> & {
147
+ locale: string;
148
+ });
129
149
  export {};
@@ -1,4 +1,4 @@
1
- import type { Locale } from './interface';
1
+ import type { DeepPartial, Locale } from './interface';
2
2
  /**
3
3
  * Deep get object value
4
4
  * get(obj, 'a.b.c') => obj.a.b.c
@@ -16,11 +16,11 @@ export declare function isValidLocale(obj: any): obj is Locale;
16
16
  * Deep merge two objects
17
17
  * Used to merge custom config with default config
18
18
  */
19
- export declare function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T;
19
+ export declare function deepMerge<T extends Record<string, any>>(target: T, source: DeepPartial<NoInfer<T>>): T;
20
20
  /**
21
21
  * Ensure locale pack completeness, fill missing fields with default values
22
22
  */
23
- export declare function normalizeLocale(locale: Partial<Locale>): Locale;
23
+ export declare function normalizeLocale(locale: DeepPartial<Locale>): Locale;
24
24
  /**
25
25
  * Get translation text from locale, supports fallback
26
26
  * @param locale Current locale pack
@@ -2,6 +2,7 @@
2
2
  --yee-primary-color: #777af2;
3
3
  --yee-primary-color-hover: #39364e;
4
4
  --yee-primary-color-active: #39364e;
5
+ --yee-primary-color-border: #bbbcfb;
5
6
  --yee-link-color: #777af2;
6
7
  --yee-link-color-hover: #39364e;
7
8
  --yee-link-color-active: #39364e;
@@ -847,6 +848,7 @@
847
848
  --yee-table-thead-stripe-borderbottom-color: var(
848
849
  --yee-table-thead-borderbottom-color
849
850
  );
851
+ --yee-table-row-bg-color: var(--yee-color-bg-container);
850
852
  --yee-table-odd-row-bg-color: var(--yee-color-bg-container);
851
853
  --yee-table-even-row-bg-color: var(--yee-color-bg-head);
852
854
  --yee-table-elevated-thead-stripe-borderbottom-color: var(
@@ -869,6 +871,7 @@
869
871
  --yee-table-head-filter-active-color: var(--yee-primary-color);
870
872
  --yee-table-fixed-left-after-bs-color: var(--yee-box-shadow-color);
871
873
  --yee-table-fixed-right-after-bs-color: var(--yee-box-shadow-color);
874
+ --yee-table-fixed-column-bg-color: inherit;
872
875
  --yee-table-filter-list-bg-color: var(--yee-color-bg-elevated);
873
876
  --yee-table-tbody-tr-expanded-bg-color: var(--yee-color-bg-container);
874
877
  --yee-table-elevated-tbody-tr-expanded-bg-color: var(
@@ -248,7 +248,8 @@
248
248
  --yee-drawer-body-padding: 20px 24px;
249
249
  --yee-drawer-close-top: 20px;
250
250
  --yee-drawer-close-right: 20px;
251
- --yee-drawer-title-font-weight: 500;
251
+ --yee-drawer-title-font-weight: 600;
252
+ --yee-drawer-title-font-size: 18px;
252
253
 
253
254
  /* --Field-- */
254
255
  --yee-field-gap: 8px;
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * @rainbow-oh/yee-c CSS Variables
3
3
  * Auto-generated, do not edit manually
4
- * Generated on 2026-07-20T03:12:00.311Z
4
+ * Generated on 2026-07-22T03:22:12.652Z
5
5
  */
6
6
 
7
7
  /* ========== color.blue.css ========== */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * @rainbow-oh/yee-c CSS Variables
3
3
  * Auto-generated, do not edit manually
4
- * Generated on 2026-07-20T03:12:00.311Z
4
+ * Generated on 2026-07-22T03:22:12.652Z
5
5
  */
6
6
 
7
7
  /* ========== color.css ========== */
@@ -9,6 +9,7 @@
9
9
  --yee-primary-color: #777af2;
10
10
  --yee-primary-color-hover: #39364e;
11
11
  --yee-primary-color-active: #39364e;
12
+ --yee-primary-color-border: #bbbcfb;
12
13
  --yee-link-color: #777af2;
13
14
  --yee-link-color-hover: #39364e;
14
15
  --yee-link-color-active: #39364e;
@@ -854,6 +855,7 @@
854
855
  --yee-table-thead-stripe-borderbottom-color: var(
855
856
  --yee-table-thead-borderbottom-color
856
857
  );
858
+ --yee-table-row-bg-color: var(--yee-color-bg-container);
857
859
  --yee-table-odd-row-bg-color: var(--yee-color-bg-container);
858
860
  --yee-table-even-row-bg-color: var(--yee-color-bg-head);
859
861
  --yee-table-elevated-thead-stripe-borderbottom-color: var(
@@ -876,6 +878,7 @@
876
878
  --yee-table-head-filter-active-color: var(--yee-primary-color);
877
879
  --yee-table-fixed-left-after-bs-color: var(--yee-box-shadow-color);
878
880
  --yee-table-fixed-right-after-bs-color: var(--yee-box-shadow-color);
881
+ --yee-table-fixed-column-bg-color: inherit;
879
882
  --yee-table-filter-list-bg-color: var(--yee-color-bg-elevated);
880
883
  --yee-table-tbody-tr-expanded-bg-color: var(--yee-color-bg-container);
881
884
  --yee-table-elevated-tbody-tr-expanded-bg-color: var(
@@ -1367,7 +1370,8 @@
1367
1370
  --yee-drawer-body-padding: 20px 24px;
1368
1371
  --yee-drawer-close-top: 20px;
1369
1372
  --yee-drawer-close-right: 20px;
1370
- --yee-drawer-title-font-weight: 500;
1373
+ --yee-drawer-title-font-weight: 600;
1374
+ --yee-drawer-title-font-size: 18px;
1371
1375
 
1372
1376
  /* --Field-- */
1373
1377
  --yee-field-gap: 8px;
@@ -39,15 +39,13 @@ function isEqual(a, b, seen) {
39
39
  return a.toString() === b.toString();
40
40
  }
41
41
  if (typeof a === "object" && typeof b === "object") {
42
- if (!seen) {
43
- seen = /* @__PURE__ */ new Map();
44
- }
45
- const seenForA = seen.get(a);
42
+ const seenMap = seen || /* @__PURE__ */ new Map();
43
+ const seenForA = seenMap.get(a);
46
44
  if (seenForA && seenForA.has(b)) {
47
45
  return true;
48
46
  }
49
47
  if (!seenForA) {
50
- seen.set(a, /* @__PURE__ */ new Set([b]));
48
+ seenMap.set(a, /* @__PURE__ */ new Set([b]));
51
49
  } else {
52
50
  seenForA.add(b);
53
51
  }
@@ -55,7 +53,7 @@ function isEqual(a, b, seen) {
55
53
  if (a.length !== b.length)
56
54
  return false;
57
55
  for (let i = 0; i < a.length; i++) {
58
- if (!isEqual(a[i], b[i], seen))
56
+ if (!isEqual(a[i], b[i], seenMap))
59
57
  return false;
60
58
  }
61
59
  return true;
@@ -68,7 +66,7 @@ function isEqual(a, b, seen) {
68
66
  if (!keysB.includes(key) || !isEqual(
69
67
  a[key],
70
68
  b[key],
71
- seen
69
+ seenMap
72
70
  ))
73
71
  return false;
74
72
  }
@@ -3,4 +3,4 @@ declare global {
3
3
  __yee_c_version__: string;
4
4
  }
5
5
  }
6
- export declare const version = "0.6.4";
6
+ export declare const version = "0.8.0";
@@ -22,7 +22,7 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- var version = "0.6.4";
25
+ var version = "0.8.0";
26
26
  if (typeof window !== "undefined") {
27
27
  window.__yee_c_version__ = version;
28
28
  }