@nokecy/qc-ui 1.1.87 → 1.1.89

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 (98) hide show
  1. package/dist/cjs/ag-grid-plus/ag-gridPlus.js +151 -145
  2. package/dist/cjs/ag-grid-plus/context/useSchemeDataFlow.js +4 -4
  3. package/dist/cjs/ag-grid-plus/interface.d.ts +8 -0
  4. package/dist/cjs/ag-grid-plus/queryForm/index.d.ts +4 -0
  5. package/dist/cjs/ag-grid-plus/queryForm/index.js +63 -53
  6. package/dist/cjs/ag-grid-plus/queryForm/queryColumns.d.ts +8 -0
  7. package/dist/cjs/ag-grid-plus/queryForm/queryColumns.js +52 -0
  8. package/dist/cjs/ag-grid-plus/queryForm/schemaKey.d.ts +15 -8
  9. package/dist/cjs/ag-grid-plus/queryForm/schemaKey.js +64 -12
  10. package/dist/cjs/ag-grid-plus/setting/ColumnConfigForm.js +3 -0
  11. package/dist/cjs/ag-grid-plus/setting/ColumnSetting.js +69 -106
  12. package/dist/cjs/ag-grid-plus/setting/QuerySchemeManager.js +3 -1
  13. package/dist/cjs/ag-grid-plus/setting/columnGroupTypes.d.ts +2 -0
  14. package/dist/cjs/ag-grid-plus/setting/columnGroupUtils.d.ts +14 -0
  15. package/dist/cjs/ag-grid-plus/setting/columnGroupUtils.js +98 -110
  16. package/dist/cjs/ag-grid-plus/types.d.ts +6 -0
  17. package/dist/cjs/array-table/batchRemove.d.ts +36 -0
  18. package/dist/cjs/array-table/batchRemove.js +299 -0
  19. package/dist/cjs/array-table/cellFocusScope.js +44 -8
  20. package/dist/cjs/array-table/cellInteractionLock.d.ts +13 -0
  21. package/dist/cjs/array-table/cellInteractionLock.js +26 -0
  22. package/dist/cjs/array-table/hooks.d.ts +11 -6
  23. package/dist/cjs/array-table/hooks.js +138 -88
  24. package/dist/cjs/array-table/index.d.ts +8 -2
  25. package/dist/cjs/array-table/index.js +55 -32
  26. package/dist/cjs/array-table/indexColumn.d.ts +1 -1
  27. package/dist/cjs/array-table/indexColumn.js +3 -2
  28. package/dist/cjs/array-table/interface.d.ts +13 -1
  29. package/dist/cjs/array-table/preview.js +8 -0
  30. package/dist/cjs/array-table/readOnlyFormatters.d.ts +9 -1
  31. package/dist/cjs/array-table/readOnlyFormatters.js +41 -13
  32. package/dist/cjs/array-table/rowIdentity.d.ts +17 -0
  33. package/dist/cjs/array-table/rowIdentity.js +43 -0
  34. package/dist/cjs/array-table/sorting.d.ts +3 -0
  35. package/dist/cjs/array-table/sorting.js +46 -0
  36. package/dist/cjs/array-table/utils.js +146 -67
  37. package/dist/cjs/dialogSelect/index.d.ts +3 -0
  38. package/dist/cjs/dialogSelect/index.js +13 -3
  39. package/dist/cjs/editable/index.js +101 -139
  40. package/dist/cjs/index.d.ts +2 -2
  41. package/dist/cjs/index.js +14 -0
  42. package/dist/cjs/readPretty/arrayTable.js +29 -14
  43. package/dist/cjs/readPretty/formily.d.ts +1 -0
  44. package/dist/cjs/readPretty/formily.js +7 -0
  45. package/dist/cjs/readPretty/index.d.ts +1 -0
  46. package/dist/cjs/readPretty/index.js +7 -0
  47. package/dist/cjs/readPretty/schemaScope.d.ts +2 -0
  48. package/dist/cjs/readPretty/schemaScope.js +49 -0
  49. package/dist/esm/ag-grid-plus/ag-gridPlus.js +151 -145
  50. package/dist/esm/ag-grid-plus/context/useSchemeDataFlow.js +4 -4
  51. package/dist/esm/ag-grid-plus/interface.d.ts +8 -0
  52. package/dist/esm/ag-grid-plus/queryForm/index.d.ts +4 -0
  53. package/dist/esm/ag-grid-plus/queryForm/index.js +64 -55
  54. package/dist/esm/ag-grid-plus/queryForm/queryColumns.d.ts +8 -0
  55. package/dist/esm/ag-grid-plus/queryForm/queryColumns.js +46 -0
  56. package/dist/esm/ag-grid-plus/queryForm/schemaKey.d.ts +15 -8
  57. package/dist/esm/ag-grid-plus/queryForm/schemaKey.js +64 -12
  58. package/dist/esm/ag-grid-plus/setting/ColumnConfigForm.js +3 -0
  59. package/dist/esm/ag-grid-plus/setting/ColumnSetting.js +70 -107
  60. package/dist/esm/ag-grid-plus/setting/QuerySchemeManager.js +3 -1
  61. package/dist/esm/ag-grid-plus/setting/columnGroupTypes.d.ts +2 -0
  62. package/dist/esm/ag-grid-plus/setting/columnGroupUtils.d.ts +14 -0
  63. package/dist/esm/ag-grid-plus/setting/columnGroupUtils.js +95 -110
  64. package/dist/esm/ag-grid-plus/types.d.ts +6 -0
  65. package/dist/esm/array-table/batchRemove.d.ts +36 -0
  66. package/dist/esm/array-table/batchRemove.js +289 -0
  67. package/dist/esm/array-table/cellFocusScope.js +45 -9
  68. package/dist/esm/array-table/cellInteractionLock.d.ts +13 -0
  69. package/dist/esm/array-table/cellInteractionLock.js +21 -0
  70. package/dist/esm/array-table/hooks.d.ts +11 -6
  71. package/dist/esm/array-table/hooks.js +139 -89
  72. package/dist/esm/array-table/index.d.ts +8 -2
  73. package/dist/esm/array-table/index.js +55 -32
  74. package/dist/esm/array-table/indexColumn.d.ts +1 -1
  75. package/dist/esm/array-table/indexColumn.js +3 -2
  76. package/dist/esm/array-table/interface.d.ts +13 -1
  77. package/dist/esm/array-table/preview.js +8 -0
  78. package/dist/esm/array-table/readOnlyFormatters.d.ts +9 -1
  79. package/dist/esm/array-table/readOnlyFormatters.js +41 -12
  80. package/dist/esm/array-table/rowIdentity.d.ts +17 -0
  81. package/dist/esm/array-table/rowIdentity.js +37 -0
  82. package/dist/esm/array-table/sorting.d.ts +3 -0
  83. package/dist/esm/array-table/sorting.js +40 -0
  84. package/dist/esm/array-table/utils.js +147 -68
  85. package/dist/esm/dialogSelect/index.d.ts +3 -0
  86. package/dist/esm/dialogSelect/index.js +13 -3
  87. package/dist/esm/editable/index.js +102 -140
  88. package/dist/esm/index.d.ts +2 -2
  89. package/dist/esm/index.js +1 -1
  90. package/dist/esm/readPretty/arrayTable.js +30 -13
  91. package/dist/esm/readPretty/formily.d.ts +1 -0
  92. package/dist/esm/readPretty/formily.js +1 -0
  93. package/dist/esm/readPretty/index.d.ts +1 -0
  94. package/dist/esm/readPretty/index.js +1 -0
  95. package/dist/esm/readPretty/schemaScope.d.ts +2 -0
  96. package/dist/esm/readPretty/schemaScope.js +42 -0
  97. package/dist/umd/qc-ui.min.js +1 -1
  98. package/package.json +1 -1
@@ -13,94 +13,125 @@ var supportsSelectionRange = function supportsSelectionRange(el) {
13
13
  !el.closest('.ant-picker') && (el.tagName === 'TEXTAREA' || /^(text|search|url|tel|password)$/i.test(el.type || 'text'))
14
14
  );
15
15
  };
16
+ /** 点击、键盘导航和字段挂载共用一次聚焦意图,新交互使旧任务失效。@author nokecy */
17
+ var useCellFocusRequests = function useCellFocusRequests() {
18
+ var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
19
+ var generation = (0, _react.useRef)(0);
20
+ var mounted = (0, _react.useRef)(true);
21
+ var timers = (0, _react.useRef)(new Set());
22
+ var pendingCell = (0, _react.useRef)();
23
+ var cancel = (0, _react.useCallback)(function () {
24
+ generation.current += 1;
25
+ pendingCell.current = undefined;
26
+ timers.current.forEach(clearTimeout);
27
+ timers.current.clear();
28
+ }, []);
29
+ (0, _react.useEffect)(function () {
30
+ mounted.current = true;
31
+ if (!enabled) return;
32
+ var onFocus = function onFocus(event) {
33
+ if (!pendingCell.current) return;
34
+ var cell = pendingCell.current();
35
+ if (!(cell !== null && cell !== void 0 && cell.isConnected) || !(event.target instanceof Node) || !cell.contains(event.target)) cancel();
36
+ };
37
+ document.addEventListener('pointerdown', cancel, true);
38
+ document.addEventListener('keydown', cancel, true);
39
+ document.addEventListener('focusin', onFocus, true);
40
+ window.addEventListener('blur', cancel);
41
+ return function () {
42
+ mounted.current = false;
43
+ cancel();
44
+ document.removeEventListener('pointerdown', cancel, true);
45
+ document.removeEventListener('keydown', cancel, true);
46
+ document.removeEventListener('focusin', onFocus, true);
47
+ window.removeEventListener('blur', cancel);
48
+ };
49
+ }, [cancel, enabled]);
50
+ return (0, _react.useCallback)(function (resolveCell) {
51
+ var isTargetCurrent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
52
+ return true;
53
+ };
54
+ cancel();
55
+ var requestGeneration = generation.current;
56
+ pendingCell.current = resolveCell;
57
+ var isCurrent = function isCurrent() {
58
+ return mounted.current && generation.current === requestGeneration && isTargetCurrent();
59
+ };
60
+ return {
61
+ isCurrent: isCurrent,
62
+ schedule: function schedule(callback, delay) {
63
+ if (!isCurrent()) return;
64
+ var timer = setTimeout(function () {
65
+ timers.current.delete(timer);
66
+ if (isCurrent()) callback();
67
+ }, delay);
68
+ timers.current.add(timer);
69
+ }
70
+ };
71
+ }, [cancel]);
72
+ };
16
73
 
17
- /**
18
- * 单元格聚焦 Hook
19
- * 处理 Editable 包装和普通输入框的聚焦逻辑
20
- */
74
+ /** 单元格聚焦;已获得焦点的控件保留用户光标,等待挂载的请求可被新操作取消。@author nokecy */
21
75
  var useCellFocus = exports.useCellFocus = function useCellFocus() {
76
+ var beginFocusRequest = useCellFocusRequests();
22
77
  var focusInputInCell = (0, _react.useCallback)(function (cell) {
23
- // 焦点已经在本格的输入框里:用户直接点进去定位光标、双击选词、按住拖选,这些留下的光标/选区都是他的。
24
- // 不能再 focus() 并把光标挪到末尾——那会把这些操作在 10ms 后全部抹掉。
25
- // 首次点开、键盘导航进来时焦点还不在本格输入框里,不受影响。@author nokecy
78
+ var _ref, _cell$querySelector;
79
+ var isTargetCurrent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
80
+ return true;
81
+ };
82
+ var row = cell.closest('.ag-row');
83
+ var rowId = row === null || row === void 0 ? void 0 : row.getAttribute('row-id');
84
+ var rowIndex = row === null || row === void 0 ? void 0 : row.getAttribute('row-index');
85
+ var colId = cell.getAttribute('col-id');
86
+ var request = beginFocusRequest(function () {
87
+ return cell;
88
+ }, function () {
89
+ return cell.isConnected && isTargetCurrent() && (row === null || row === void 0 ? void 0 : row.getAttribute('row-id')) === rowId && (row === null || row === void 0 ? void 0 : row.getAttribute('row-index')) === rowIndex && cell.getAttribute('col-id') === colId;
90
+ });
91
+ if (!request.isCurrent()) return;
92
+ var focusElement = function focusElement(element) {
93
+ if (!(element !== null && element !== void 0 && element.isConnected) || !cell.contains(element) || !request.isCurrent()) return;
94
+ if (document.activeElement === element) return;
95
+ element.focus();
96
+ // 同步设置首次进入的光标,避免延迟任务覆盖用户随后选择的文字。@author nokecy
97
+ if (document.activeElement === element && element.matches('input, textarea') && supportsSelectionRange(element)) {
98
+ var input = element;
99
+ input.setSelectionRange(input.value.length, input.value.length);
100
+ }
101
+ };
26
102
  var active = document.activeElement;
27
- if (active && cell.contains(active) && active.matches('input, textarea')) return;
28
-
29
- // 首先查找Editable包装的元素
103
+ if (active && cell.contains(active) && active.matches('input, textarea, [contenteditable="true"]')) return;
104
+ var selector = 'input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])';
30
105
  var editableElement = cell.querySelector('.ant-formily-editable');
31
106
  if (editableElement) {
32
- // 检查Editable是否已经处于编辑状态
33
- var isEditing = editableElement.getAttribute('data-editable-state') === 'editing';
34
- if (isEditing) {
35
- // 如果已经处于编辑状态,查找输入框并直接聚焦
36
- var existingInput = editableElement.querySelector('input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])');
37
- if (existingInput) {
38
- existingInput.focus();
39
- if (supportsSelectionRange(existingInput)) {
40
- var _existingInput$value;
41
- var length = ((_existingInput$value = existingInput.value) === null || _existingInput$value === void 0 ? void 0 : _existingInput$value.length) || 0;
42
- setTimeout(function () {
43
- existingInput.setSelectionRange(length, length);
44
- }, 10);
45
- }
46
- }
107
+ var focusEditor = function focusEditor() {
108
+ return focusElement(editableElement.querySelector(selector));
109
+ };
110
+ if (editableElement.dataset.editableState === 'editing') {
111
+ focusEditor();
47
112
  } else {
48
- // 如果还没有进入编辑状态,触发编辑状态
49
113
  editableElement.click();
50
- var focusEvent = new Event('focus', {
114
+ if (!request.isCurrent()) return;
115
+ editableElement.dispatchEvent(new Event('focus', {
51
116
  bubbles: true
52
- });
53
- editableElement.dispatchEvent(focusEvent);
54
-
55
- // 延迟查找输入框并设置光标
56
- setTimeout(function () {
57
- var newInput = editableElement.querySelector('input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])');
58
- if (newInput) {
59
- newInput.focus();
60
- if (supportsSelectionRange(newInput)) {
61
- var _newInput$value;
62
- var _length = ((_newInput$value = newInput.value) === null || _newInput$value === void 0 ? void 0 : _newInput$value.length) || 0;
63
- setTimeout(function () {
64
- newInput.setSelectionRange(_length, _length);
65
- }, 10);
66
- }
67
- }
68
- }, 150);
69
- }
70
- } else {
71
- // 如果没有Editable包装,尝试多种选择器查找输入框
72
- var inputElement = cell.querySelector('input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])');
73
- if (!inputElement) {
74
- // 尝试更宽泛的选择器
75
- inputElement = cell.querySelector('input, textarea');
76
- }
77
- if (!inputElement) {
78
- // 尝试查找Ant Design的输入框
79
- inputElement = cell.querySelector('.ant-input');
80
- }
81
- if (!inputElement) {
82
- // 查找任何可聚焦的元素
83
- inputElement = cell.querySelector('[contenteditable="true"], [tabindex]');
84
- }
85
- if (inputElement) {
86
- inputElement.focus();
87
-
88
- // 将光标定位到末尾
89
- if (supportsSelectionRange(inputElement)) {
90
- var _inputElement$value;
91
- var _length2 = ((_inputElement$value = inputElement.value) === null || _inputElement$value === void 0 ? void 0 : _inputElement$value.length) || 0;
92
- setTimeout(function () {
93
- inputElement.setSelectionRange(_length2, _length2);
94
- }, 10);
95
- }
96
- } else {
97
- // 尝试直接聚焦到单元格本身
98
- cell.focus();
117
+ }));
118
+ request.schedule(focusEditor, 150);
99
119
  }
120
+ return;
100
121
  }
101
- }, []);
122
+ focusElement((_ref = (_cell$querySelector = cell.querySelector(selector)) !== null && _cell$querySelector !== void 0 ? _cell$querySelector : cell.querySelector('input:not([disabled]), textarea:not([disabled]), [contenteditable="true"], [tabindex]:not([disabled])')) !== null && _ref !== void 0 ? _ref : cell);
123
+ }, [beginFocusRequest]);
124
+ var scheduleCellFocus = (0, _react.useCallback)(function (resolveCell, delay, isTargetCurrent) {
125
+ var request = beginFocusRequest(resolveCell, isTargetCurrent);
126
+ request.schedule(function () {
127
+ var cell = resolveCell();
128
+ if (cell !== null && cell !== void 0 && cell.isConnected) focusInputInCell(cell, isTargetCurrent);
129
+ }, delay);
130
+ }, [beginFocusRequest, focusInputInCell]);
102
131
  return {
103
- focusInputInCell: focusInputInCell
132
+ focusInputInCell: focusInputInCell,
133
+ scheduleCellFocus: scheduleCellFocus,
134
+ beginFocusRequest: beginFocusRequest
104
135
  };
105
136
  };
106
137
 
@@ -108,7 +139,9 @@ var useCellFocus = exports.useCellFocus = function useCellFocus() {
108
139
  * 键盘导航 Hook
109
140
  * 处理方向键在表格单元格间的导航
110
141
  */
111
- var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboardNavigation(ref, dataSource, focusInputInCell, activateCell) {
142
+ var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboardNavigation(ref, dataSource, focusInputInCell, activateCell, beginSharedFocusRequest) {
143
+ var beginLocalFocusRequest = useCellFocusRequests(!beginSharedFocusRequest);
144
+ var beginFocusRequest = beginSharedFocusRequest !== null && beginSharedFocusRequest !== void 0 ? beginSharedFocusRequest : beginLocalFocusRequest;
112
145
  var handleCellKeyDown = (0, _react.useCallback)(function (event) {
113
146
  var _nativeKeyDecisions$g;
114
147
  var keyEvent = event.event,
@@ -161,13 +194,31 @@ var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboard
161
194
  // 检查目标位置是否有效
162
195
  var isValidTarget = keyEvent.key === 'ArrowLeft' || keyEvent.key === 'ArrowRight' || targetRowIndex >= 0 && targetRowIndex < dataSource.length;
163
196
  if (isValidTarget) {
197
+ var _api$getDisplayedRowA;
198
+ var targetNode = (_api$getDisplayedRowA = api.getDisplayedRowAtIndex) === null || _api$getDisplayedRowA === void 0 ? void 0 : _api$getDisplayedRowA.call(api, targetRowIndex);
199
+ var navigated = false;
200
+ var resolveTarget = function resolveTarget() {
201
+ var _ref$current;
202
+ return (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.querySelector(".ag-row[row-index=\"".concat(targetRowIndex, "\"] .ag-cell[col-id=\"").concat(targetColId, "\"]"));
203
+ };
204
+ var _isTargetCurrent = function _isTargetCurrent() {
205
+ var _ref$current2, _api$isDestroyed, _api$getDisplayedRowA2;
206
+ if (!((_ref$current2 = ref.current) !== null && _ref$current2 !== void 0 && _ref$current2.isConnected) || (_api$isDestroyed = api.isDestroyed) !== null && _api$isDestroyed !== void 0 && _api$isDestroyed.call(api)) return false;
207
+ if (targetNode && ((_api$getDisplayedRowA2 = api.getDisplayedRowAtIndex) === null || _api$getDisplayedRowA2 === void 0 ? void 0 : _api$getDisplayedRowA2.call(api, targetRowIndex)) !== targetNode) return false;
208
+ if (navigated && api.getFocusedCell) {
209
+ var _focused$column;
210
+ var focused = api.getFocusedCell();
211
+ return (focused === null || focused === void 0 ? void 0 : focused.rowIndex) === targetRowIndex && ((_focused$column = focused.column) === null || _focused$column === void 0 ? void 0 : _focused$column.getColId()) === targetColId;
212
+ }
213
+ return true;
214
+ };
215
+ var request = beginFocusRequest(resolveTarget, _isTargetCurrent);
164
216
  // 延迟执行以确保当前编辑完成
165
- setTimeout(function () {
166
- var _api$getDisplayedRowA;
217
+ request.schedule(function () {
167
218
  api.setFocusedCell(targetRowIndex, targetColId);
219
+ navigated = true;
168
220
 
169
221
  // 懒挂载:目标格若是懒列存量格,先激活挂树(refreshCells),下方 150ms 内完成挂载再聚焦 @author nokecy
170
- var targetNode = (_api$getDisplayedRowA = api.getDisplayedRowAtIndex) === null || _api$getDisplayedRowA === void 0 ? void 0 : _api$getDisplayedRowA.call(api, targetRowIndex);
171
222
  if (activateCell && targetNode) {
172
223
  activateCell(api, targetNode, targetColId);
173
224
  }
@@ -175,11 +226,10 @@ var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboard
175
226
  // 不使用原生startEditingCell,而是手动触发编辑状态
176
227
  // v33 themeQuartz 容器不再有 .ag-theme-alpine 类;且行虚拟化下 DOM 顺序与 rowIndex 不一致,
177
228
  // 改为直接在 ref 容器内按 row-index + col-id 属性定位目标单元格 @author nokecy
178
- setTimeout(function () {
179
- var _ref$current;
180
- var targetCell = (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.querySelector(".ag-row[row-index=\"".concat(targetRowIndex, "\"] .ag-cell[col-id=\"").concat(targetColId, "\"]"));
181
- if (targetCell) {
182
- focusInputInCell(targetCell);
229
+ request.schedule(function () {
230
+ var targetCell = resolveTarget();
231
+ if (targetCell !== null && targetCell !== void 0 && targetCell.isConnected) {
232
+ focusInputInCell(targetCell, _isTargetCurrent);
183
233
  }
184
234
  }, 150);
185
235
  }, 10);
@@ -187,7 +237,7 @@ var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboard
187
237
  keyEvent.preventDefault();
188
238
  keyEvent.stopPropagation();
189
239
  }
190
- }, [dataSource, focusInputInCell, ref, activateCell]);
240
+ }, [dataSource, focusInputInCell, ref, activateCell, beginFocusRequest]);
191
241
  return {
192
242
  handleCellKeyDown: handleCellKeyDown
193
243
  };
@@ -268,8 +318,8 @@ var isNativeInputKey = exports.isNativeInputKey = function isNativeInputKey(even
268
318
  var nativeKeyDecisions = new WeakMap();
269
319
 
270
320
  /** AG-Grid 的 suppressKeyboardEvent:让 AG-Grid 不再拦截输入框自己处理的按键,并记下这次按键的判定 */
271
- var suppressNativeInputKeys = exports.suppressNativeInputKeys = function suppressNativeInputKeys(_ref) {
272
- var event = _ref.event;
321
+ var suppressNativeInputKeys = exports.suppressNativeInputKeys = function suppressNativeInputKeys(_ref2) {
322
+ var event = _ref2.event;
273
323
  var native = isNativeInputKey(event);
274
324
  nativeKeyDecisions.set(event, native);
275
325
  return native;
@@ -1,6 +1,12 @@
1
1
  import React from "react";
2
- import { AgGridReactProps } from "ag-grid-react";
3
- declare const _default: React.ForwardRefExoticComponent<Partial<AgGridReactProps<any> & {
2
+ declare const _default: React.ForwardRefExoticComponent<Partial<import("ag-grid-react").AgGridReactProps<any> & {
3
+ height?: string | number | undefined;
4
+ gridKey: string;
5
+ onRowDrag?: boolean | undefined;
6
+ disabled?: boolean | undefined;
7
+ batchRemove?: boolean | undefined;
8
+ onRemove?: ((index: number) => void) | undefined;
9
+ } & {
4
10
  children?: React.ReactNode;
5
11
  }> & React.RefAttributes<unknown>>;
6
12
  export default _default;
@@ -9,9 +9,11 @@ var _agGridReact = require("ag-grid-react");
9
9
  var _react2 = require("@formily/react");
10
10
  var _uniqueId = _interopRequireDefault(require("lodash/uniqueId"));
11
11
  var _locale = require("../ag-grid-plus/locale");
12
+ var _batchRemove = require("./batchRemove");
12
13
  var _utils = require("./utils");
13
14
  var _columnGroup = require("./columnGroup");
14
15
  var _indexColumn = require("./indexColumn");
16
+ var _rowIdentity = require("./rowIdentity");
15
17
  var _hooks = require("./hooks");
16
18
  var _arrayBase = _interopRequireDefault(require("./arrayBase"));
17
19
  var _arrayAddBtn = _interopRequireDefault(require("./arrayAddBtn"));
@@ -56,7 +58,7 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
56
58
  // 懒挂载激活态:存放当前挂着真控件的单元格 key(`rowId:colId`),供 LazyAgField 经 context 读写:
57
59
  // 点击/导航进来时这里写入,必填且为空的格自己写入,焦点离开且校验通过后自己删除。@author nokecy
58
60
  var activeCellsRef = (0, _react.useRef)(new Set());
59
- // 无 _id/id 的外部数据按对象引用分配稳定 rowId(避免 getRowId 返回 undefined)。@author nokecy
61
+ // 首次渲染先缓存无标识行的 rowId,effect 再补入行数据,供业务克隆时保留。@author nokecy
60
62
  var rowIdMapRef = (0, _react.useRef)(new WeakMap());
61
63
  var ref = (0, _react.useRef)();
62
64
  var field = (0, _react2.useField)();
@@ -98,10 +100,15 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
98
100
  onMoveDown = props.onMoveDown,
99
101
  onMoveUp = props.onMoveUp;
100
102
  var addition = (0, _utils.useAddition)();
103
+ var batchRemove = (0, _batchRemove.useArrayTableBatchRemove)(field, sources, props, apiRef, function (row) {
104
+ return (0, _rowIdentity.getArrayTableRowId)(row, rowIdMapRef.current);
105
+ });
101
106
 
102
107
  // 使用自定义 hooks
103
108
  var _useCellFocus = (0, _hooks.useCellFocus)(),
104
- focusInputInCell = _useCellFocus.focusInputInCell;
109
+ focusInputInCell = _useCellFocus.focusInputInCell,
110
+ scheduleCellFocus = _useCellFocus.scheduleCellFocus,
111
+ beginFocusRequest = _useCellFocus.beginFocusRequest;
105
112
  var _useRowDrag = (0, _hooks.useRowDrag)(field),
106
113
  handleRowDragMove = _useRowDrag.handleRowDragMove;
107
114
 
@@ -138,7 +145,7 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
138
145
  var _buildArrayTableColum;
139
146
  // 只依赖 sources,不依赖 dataSource 和 field.value
140
147
  var cols = (_buildArrayTableColum = (0, _utils.buildArrayTableColumns)([], field, sources)) !== null && _buildArrayTableColum !== void 0 ? _buildArrayTableColum : [];
141
- // 默认在最左加序号列;schema 里已经放了 ArrayTable.Index 的不再加。@author nokecy
148
+ // 默认在业务列之前加序号列,勾选列由网格放在其左侧;schema 自带序号时不重复加。@author nokecy
142
149
  if (cols.length > 0 && !(0, _indexColumn.hasOwnIndexColumn)(sources)) {
143
150
  cols.unshift((0, _indexColumn.makeIndexColumn)());
144
151
  }
@@ -159,6 +166,11 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
159
166
  if (lazyDefaults.length > 0) (0, _utils.applyLazyDefaults)(field, lazyDefaults, defaultedRowsRef.current);
160
167
  });
161
168
 
169
+ // 默认值先补齐,再持久化行身份;覆盖初始行及程序追加行,不在渲染/getRowId 中写表单。@author nokecy
170
+ (0, _react.useEffect)(function () {
171
+ (0, _rowIdentity.ensureArrayTableRowIds)(field, rowIdMapRef.current);
172
+ });
173
+
162
174
  // 交给 AgGridReact 的列定义:按 x-component-props.headerGroup 把相邻同组的列合并成列组(多级表头)。
163
175
  // stableColumnDefs 保持扁平,懒列识别、列方案还原等内部逻辑仍用它;只有喂给 AG-Grid 的这一份带分组。@author nokecy
164
176
  var gridColumnDefs = (0, _react.useMemo)(function () {
@@ -203,7 +215,7 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
203
215
  }, [lazyColIds]);
204
216
 
205
217
  // 键盘导航 hook 需要 activateCell(导航进懒列时先挂载再聚焦),故置于其后。@author nokecy
206
- var _useKeyboardNavigatio = (0, _hooks.useKeyboardNavigation)(ref, dataSource, focusInputInCell, activateCell),
218
+ var _useKeyboardNavigatio = (0, _hooks.useKeyboardNavigation)(ref, dataSource, focusInputInCell, activateCell, beginFocusRequest),
207
219
  handleCellKeyDown = _useKeyboardNavigatio.handleCellKeyDown;
208
220
 
209
221
  /**
@@ -352,13 +364,17 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
352
364
  name: key,
353
365
  onlyRenderProperties: true
354
366
  });
355
- })), /*#__PURE__*/_react.default.createElement(_setting.default, {
367
+ })), /*#__PURE__*/_react.default.createElement(_antd.Space, {
368
+ style: {
369
+ marginBottom: 5
370
+ }
371
+ }, batchRemove.toolbar, /*#__PURE__*/_react.default.createElement(_setting.default, {
356
372
  gridKey: props.gridKey,
357
373
  gridApi: apiRef.current,
358
374
  gridApiState: gridApiState,
359
375
  allColDefs: stableColumnDefs,
360
376
  showQueryScheme: false
361
- })), /*#__PURE__*/_react.default.createElement("div", {
377
+ }))), /*#__PURE__*/_react.default.createElement("div", {
362
378
  style: {
363
379
  flex: 1,
364
380
  minHeight: 0
@@ -368,9 +384,11 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
368
384
  localeText: _locale.localeText,
369
385
  context: gridContext,
370
386
  onGridReady: function onGridReady(params) {
387
+ var _props$onGridReady;
371
388
  params.api.hidePopupMenu();
372
389
  apiRef.current = params.api;
373
390
  setGridApiState(params.api);
391
+ (_props$onGridReady = props.onGridReady) === null || _props$onGridReady === void 0 || _props$onGridReady.call(props, params);
374
392
  },
375
393
  suppressColumnVirtualisation: true,
376
394
  gridOptions: {
@@ -386,23 +404,30 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
386
404
  },
387
405
  onCellKeyDown: handleCellKeyDown,
388
406
  onCellClicked: function onCellClicked(event) {
389
- var _event$colDef;
407
+ var _event$column$getColI, _event$column, _event$colDef, _event$event;
390
408
  // 懒挂载:点击懒列存量格时先激活挂树,等挂载完成再聚焦进编辑;否则沿用原即时聚焦。@author nokecy
391
409
  var node = event.node;
392
- var colId = (_event$colDef = event.colDef) === null || _event$colDef === void 0 ? void 0 : _event$colDef.field;
410
+ var colId = (_event$column$getColI = (_event$column = event.column) === null || _event$column === void 0 ? void 0 : _event$column.getColId()) !== null && _event$column$getColI !== void 0 ? _event$column$getColI : (_event$colDef = event.colDef) === null || _event$colDef === void 0 ? void 0 : _event$colDef.field;
393
411
  var justActivated = activateCell(event.api, node, colId);
394
412
  var rowIndex = node === null || node === void 0 ? void 0 : node.rowIndex;
395
- var focus = function focus() {
396
- var _ref$current, _event$event;
413
+ var clickedCell = (_event$event = event.event) === null || _event$event === void 0 || (_event$event = _event$event.target) === null || _event$event === void 0 ? void 0 : _event$event.closest('.ag-cell');
414
+ var resolveCell = function resolveCell() {
415
+ var _ref$current;
397
416
  // 行虚拟化下 DOM 顺序与 rowIndex 不一致,按 row-index + col-id 属性精确定位刚渲染的格 @author nokecy
398
- var gridCell = justActivated && rowIndex != null ? (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.querySelector(".ag-row[row-index=\"".concat(rowIndex, "\"] .ag-cell[col-id=\"").concat(colId, "\"]")) : (_event$event = event.event) === null || _event$event === void 0 || (_event$event = _event$event.target) === null || _event$event === void 0 ? void 0 : _event$event.closest('.ag-cell');
399
- if (gridCell) focusInputInCell(gridCell);
417
+ return justActivated && rowIndex != null ? (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.querySelector(".ag-row[row-index=\"".concat(rowIndex, "\"] .ag-cell[col-id=\"").concat(colId, "\"]")) : clickedCell;
400
418
  };
401
- // 新激活需等 AgField(RecursionField/Editable) 挂载完成,给足时间;否则原 10ms。@author nokecy
402
- setTimeout(focus, justActivated ? 80 : 10);
419
+ // 点击、导航共用聚焦请求;旧格等待挂载期间用户已转移焦点或行已更新时,取消旧任务。@author nokecy
420
+ scheduleCellFocus(resolveCell, justActivated ? 80 : 10, function () {
421
+ var _ref$current2;
422
+ if (!((_ref$current2 = ref.current) !== null && _ref$current2 !== void 0 && _ref$current2.isConnected) || event.api.isDestroyed() || rowIndex == null) return false;
423
+ if (event.api.getDisplayedRowAtIndex(rowIndex) !== node) return false;
424
+ var focused = event.api.getFocusedCell();
425
+ return (focused === null || focused === void 0 ? void 0 : focused.rowIndex) === rowIndex && (focused === null || focused === void 0 ? void 0 : focused.column.getColId()) === colId;
426
+ });
403
427
  },
404
428
  onRowDragMove: handleRowDragMove,
405
429
  onRowDataUpdated: function onRowDataUpdated(e) {
430
+ var _props$onRowDataUpdat;
406
431
  // 增删行、拖动换行后行位置变了,未改动的行不会自己重算序号,统一刷新序号列 @author nokecy
407
432
  if (stableColumnDefs.some(function (c) {
408
433
  return (c === null || c === void 0 ? void 0 : c.field) === _indexColumn.ARRAY_TABLE_INDEX_FIELD;
@@ -416,8 +441,12 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
416
441
  (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 || _apiRef$current2.ensureIndexVisible(dataSource.length - 1, "bottom");
417
442
  setIsAdd(false);
418
443
  }
444
+ (_props$onRowDataUpdat = props.onRowDataUpdated) === null || _props$onRowDataUpdat === void 0 || _props$onRowDataUpdat.call(props, e);
419
445
  },
420
446
  rowDragManaged: true,
447
+ rowSelection: batchRemove.rowSelection,
448
+ selectionColumnDef: batchRemove.selectionColumnDef,
449
+ onSelectionChanged: batchRemove.onSelectionChanged,
421
450
  suppressClipboardApi: true,
422
451
  suppressClipboardPaste: true,
423
452
  preventDefaultOnContextMenu: true,
@@ -436,32 +465,26 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
436
465
  }
437
466
  },
438
467
  getRowId: function getRowId(_ref2) {
439
- var _data$_id;
440
468
  var data = _ref2.data;
441
- var id = (_data$_id = data === null || data === void 0 ? void 0 : data._id) !== null && _data$_id !== void 0 ? _data$_id : data === null || data === void 0 ? void 0 : data.id;
442
- if (id != null) return String(id);
443
- // 既无 _id 也无 id 的外部数据:按对象引用从 WeakMap 取/分配稳定 id。
444
- // 不能用 uniqueId 直返(每次调用都变会让 AG-Grid 行身份错乱),也不能改写 data(触发 Formily 反应)。@author nokecy
445
- var gen = rowIdMapRef.current.get(data);
446
- if (!gen) {
447
- gen = (0, _uniqueId.default)('row_');
448
- rowIdMapRef.current.set(data, gen);
449
- }
450
- return gen;
469
+ return (0, _rowIdentity.getArrayTableRowId)(data, rowIdMapRef.current);
451
470
  }
452
471
  // rowDragEntireRow={true}
453
472
  // onRowDragEnd={(event) => {
454
473
  // const { overIndex, node } = event;
455
474
  // field.move(node.rowIndex!, overIndex);
456
475
  // }}
457
- // onSortChanged={(event) => {
458
- // const columnStates = event.columnApi.getColumnState();
459
- // if (columnStates.filter((x) => x.sort).length > 0) {
460
- // const columnState = columnStates.filter((x) => x.sort)[0];
461
- // field.value = sortBy(field.value, columnState.colId);
462
- // }
463
- // }}
464
476
  ,
477
+ onSortChanged: function onSortChanged(event) {
478
+ var _props$onSortChanged;
479
+ // 排序只调整显示顺序;表单数组及行身份保持不变,序号按新的显示位置刷新。@author nokecy
480
+ if (stableColumnDefs.some(function (c) {
481
+ return (c === null || c === void 0 ? void 0 : c.field) === _indexColumn.ARRAY_TABLE_INDEX_FIELD;
482
+ })) event.api.refreshCells({
483
+ columns: [_indexColumn.ARRAY_TABLE_INDEX_FIELD],
484
+ force: true
485
+ });
486
+ (_props$onSortChanged = props.onSortChanged) === null || _props$onSortChanged === void 0 || _props$onSortChanged.call(props, event);
487
+ },
465
488
  rowHeight: _theme.ARRAY_TABLE_ROW_HEIGHT,
466
489
  pagination: false,
467
490
  columnDefs: gridColumnDefs,
@@ -11,7 +11,7 @@ export declare const hasOwnIndexColumn: (sources: Array<{
11
11
  }>) => boolean;
12
12
  /**
13
13
  * 默认序号列:按行在表格里的位置编号(1 起),不依赖业务行号或主键,与列表页的序号一致。
14
- * 固定在最左、不可隐藏/拖动/排序;合计等固定行不编号。
14
+ * 固定在左侧、位于勾选列之后,不可隐藏/拖动/排序;合计等固定行不编号。
15
15
  * 增删行、拖动换行后由 ArrayTable 在 onRowDataUpdated 里刷新本列,见 index.tsx。@author nokecy
16
16
  */
17
17
  export declare const makeIndexColumn: () => ColDef;
@@ -31,7 +31,7 @@ var hasOwnIndexColumn = exports.hasOwnIndexColumn = function hasOwnIndexColumn(s
31
31
 
32
32
  /**
33
33
  * 默认序号列:按行在表格里的位置编号(1 起),不依赖业务行号或主键,与列表页的序号一致。
34
- * 固定在最左、不可隐藏/拖动/排序;合计等固定行不编号。
34
+ * 固定在左侧、位于勾选列之后,不可隐藏/拖动/排序;合计等固定行不编号。
35
35
  * 增删行、拖动换行后由 ArrayTable 在 onRowDataUpdated 里刷新本列,见 index.tsx。@author nokecy
36
36
  */
37
37
  var makeIndexColumn = exports.makeIndexColumn = function makeIndexColumn() {
@@ -40,7 +40,8 @@ var makeIndexColumn = exports.makeIndexColumn = function makeIndexColumn() {
40
40
  headerName: '序号',
41
41
  width: 60,
42
42
  pinned: 'left',
43
- lockPosition: 'left',
43
+ // 勾选列拥有最左位置;序号保留固定和禁止拖动,避免恢复旧方案时抢到勾选列之前。@author nokecy
44
+ lockPosition: false,
44
45
  lockPinned: true,
45
46
  lockVisible: true,
46
47
  suppressMovable: true,
@@ -23,13 +23,25 @@ interface ArrayTableColumnProps {
23
23
  defaultHide?: boolean;
24
24
  }
25
25
  interface ObservableColumnSource {
26
+ /** 当前 SchemaField 的组件表,用于读取业务组件的展示规则。@author nokecy */
27
+ components?: Record<string, any>;
26
28
  field: GeneralField;
27
29
  columnProps: ArrayTableColumnProps & Record<string, any>;
28
30
  schema: Schema;
29
31
  display: FieldDisplayTypes;
30
32
  name: string;
31
33
  }
32
- type ComposedArrayTable = React.FC<React.PropsWithChildren<AgGridReactProps>> & ArrayBaseMixins & {
34
+ /** 公共明细表格的业务属性。@author nokecy */
35
+ export type ArrayTableProps = AgGridReactProps & {
36
+ height?: number | string;
37
+ gridKey: string;
38
+ onRowDrag?: boolean;
39
+ disabled?: boolean;
40
+ /** 默认对配置标准删除入口的可编辑明细开放批量删除;false 可显式关闭。 */
41
+ batchRemove?: boolean;
42
+ onRemove?: (index: number) => void;
43
+ };
44
+ type ComposedArrayTable = React.FC<React.PropsWithChildren<ArrayTableProps>> & ArrayBaseMixins & {
33
45
  Column?: any;
34
46
  };
35
47
  export { ComposedArrayTable, ObservableColumnSource, ArrayTableColumnProps };
@@ -43,6 +43,14 @@ var ArrayTable = function ArrayTable(props) {
43
43
  theme: arrayTablePreviewTheme,
44
44
  rowHeight: _theme.ARRAY_TABLE_ROW_HEIGHT,
45
45
  pagination: false,
46
+ onSortChanged: function onSortChanged(event) {
47
+ var _props$onSortChanged;
48
+ if (showDefaultIndex) event.api.refreshCells({
49
+ columns: [_indexColumn.ARRAY_TABLE_INDEX_FIELD],
50
+ force: true
51
+ });
52
+ (_props$onSortChanged = props.onSortChanged) === null || _props$onSortChanged === void 0 || _props$onSortChanged.call(props, event);
53
+ },
46
54
  onRowDataUpdated: function onRowDataUpdated(event) {
47
55
  // 阅读态明细替换或重排后刷新序号,不向表单写入编号。@author nokecy
48
56
  if (showDefaultIndex) {
@@ -1,4 +1,12 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** 选择器的展示字段;只影响回显,不改变 labelInValue 的提交值。@author nokecy */
3
+ export type SelectDisplayField = 'value' | 'label';
4
+ /** 从选择值提取展示文字;编码展示不能因描述为空或过期而改变。@author nokecy */
5
+ export declare const formatSelectDisplay: (value: any, displayField?: SelectDisplayField) => string;
6
+ /** 给选择组件声明与其回显一致的表格格式化器,组件别名和不同页面各自生效。@author nokecy */
7
+ export declare const withReadOnlyFormatter: <T>(component: T, formatter: ReadOnlyFormatter) => T & {
8
+ readOnlyFormatter: ReadOnlyFormatter;
9
+ };
2
10
  export type ReadOnlyFormatterCtx = {
3
11
  /** 列的 x-component-props(headerName/width/options/format 等) */
4
12
  columnProps: any;
@@ -49,4 +57,4 @@ export declare const getReadOnlyRenderer: (component: string | undefined) => Rea
49
57
  /**
50
58
  * 取某组件类型的只读格式化器。命中返回函数,未命中返回 null(调用方回退 AgField)。
51
59
  */
52
- export declare const getReadOnlyFormatter: (component: string | undefined) => ReadOnlyFormatter | null;
60
+ export declare const getReadOnlyFormatter: (component: string | undefined, components?: Record<string, any>) => ReadOnlyFormatter | null;