@nokecy/qc-ui 1.1.52 → 1.1.53

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.
@@ -23,12 +23,19 @@ export declare const useRowDrag: (field: ArrayField) => {
23
23
  handleRowDragMove: (event: any) => void;
24
24
  };
25
25
  /**
26
- * AG-Grid 的 suppressKeyboardEvent:单元格里的输入框按 Ctrl/Cmd+A 时,让浏览器自己全选文字。
26
+ * 这个按键该不该交给单元格里的输入框自己处理(浏览器原生行为),而不是当成表格的快捷键/单元格导航。
27
27
  *
28
- * AG-Grid 把 Ctrl+A 当成「选中所有单元格」并 preventDefault,输入框(文本框、数字框都一样)
29
- * 就选不中里面的文字。这里只放行这一个组合;方向键等其余按键仍归 handleCellKeyDown 做单元格导航。
28
+ * AG-Grid 把 Ctrl+A 当成「选中所有单元格」、Home/End 当成「跳到行首/行尾单元格」并 preventDefault;
29
+ * 我们的 handleCellKeyDown 又把方向键一律当成「跳到相邻单元格」——输入框里全选、用方向键移动光标、
30
+ * Shift+方向键扩选文字就全都做不了。规则:
31
+ * - Ctrl/Cmd+A、Home/End、带 Shift/Ctrl/Alt/Cmd 的方向键、输入法组字期间的按键 -> 输入框自己处理;
32
+ * - 左右方向键:光标还能动就移动光标(有选区时先收起选区),已经在最左/最右再按才跳到相邻单元格;
33
+ * - 上下方向键:单行输入框没有纵向光标,照旧在行间导航;多行文本域在首行/末行才导航;
34
+ * - 焦点不在输入框里(在单元格本身)、只读输入框(如下拉选择)、不支持光标的输入框:照旧导航。
30
35
  * 复制/粘贴/剪切/撤销 AG-Grid 本来就没拦,不必处理。@author nokecy
31
36
  */
32
- export declare const suppressSelectAllInInput: ({ event }: {
37
+ export declare const isNativeInputKey: (event: KeyboardEvent) => boolean;
38
+ /** AG-Grid 的 suppressKeyboardEvent:让 AG-Grid 不再拦截输入框自己处理的按键,并记下这次按键的判定 */
39
+ export declare const suppressNativeInputKeys: ({ event }: {
33
40
  event: KeyboardEvent;
34
41
  }) => boolean;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.useRowDrag = exports.useKeyboardNavigation = exports.useCellFocus = exports.suppressSelectAllInInput = void 0;
6
+ exports.useRowDrag = exports.useKeyboardNavigation = exports.useCellFocus = exports.suppressNativeInputKeys = exports.isNativeInputKey = void 0;
7
7
  var _react = require("react");
8
8
  // setSelectionRange 仅 textarea 与 text/search/url/tel/password 类型 input 支持;
9
9
  // checkbox/number/date 等调用会抛 InvalidStateError,故用白名单守卫。@author nokecy
@@ -17,6 +17,12 @@ var supportsSelectionRange = function supportsSelectionRange(el) {
17
17
  */
18
18
  var useCellFocus = exports.useCellFocus = function useCellFocus() {
19
19
  var focusInputInCell = (0, _react.useCallback)(function (cell) {
20
+ // 焦点已经在本格的输入框里:用户直接点进去定位光标、双击选词、按住拖选,这些留下的光标/选区都是他的。
21
+ // 不能再 focus() 并把光标挪到末尾——那会把这些操作在 10ms 后全部抹掉。
22
+ // 首次点开、键盘导航进来时焦点还不在本格输入框里,不受影响。@author nokecy
23
+ var active = document.activeElement;
24
+ if (active && cell.contains(active) && active.matches('input, textarea')) return;
25
+
20
26
  // 首先查找Editable包装的元素
21
27
  var editableElement = cell.querySelector('.ant-formily-editable');
22
28
  if (editableElement) {
@@ -101,11 +107,15 @@ var useCellFocus = exports.useCellFocus = function useCellFocus() {
101
107
  */
102
108
  var useKeyboardNavigation = exports.useKeyboardNavigation = function useKeyboardNavigation(ref, dataSource, focusInputInCell, activateCell) {
103
109
  var handleCellKeyDown = (0, _react.useCallback)(function (event) {
110
+ var _nativeKeyDecisions$g;
104
111
  var keyEvent = event.event,
105
112
  node = event.node,
106
113
  colDef = event.colDef,
107
114
  api = event.api;
108
115
  if (!keyEvent) return;
116
+ // 输入框里移动光标/扩选/全选的按键归输入框,表格不导航(见 isNativeInputKey)。
117
+ // 判定用 keydown 当时记下的(见 suppressNativeInputKeys);没记过(不是 AG-Grid 触发的)才现算。
118
+ if ((_nativeKeyDecisions$g = nativeKeyDecisions.get(keyEvent)) !== null && _nativeKeyDecisions$g !== void 0 ? _nativeKeyDecisions$g : isNativeInputKey(keyEvent)) return;
109
119
 
110
120
  // 处理上下左右键导航
111
121
  if (keyEvent.key === 'ArrowDown' || keyEvent.key === 'ArrowUp' || keyEvent.key === 'ArrowLeft' || keyEvent.key === 'ArrowRight') {
@@ -212,16 +222,52 @@ var useRowDrag = exports.useRowDrag = function useRowDrag(field) {
212
222
  };
213
223
 
214
224
  /**
215
- * AG-Grid 的 suppressKeyboardEvent:单元格里的输入框按 Ctrl/Cmd+A 时,让浏览器自己全选文字。
225
+ * 这个按键该不该交给单元格里的输入框自己处理(浏览器原生行为),而不是当成表格的快捷键/单元格导航。
216
226
  *
217
- * AG-Grid 把 Ctrl+A 当成「选中所有单元格」并 preventDefault,输入框(文本框、数字框都一样)
218
- * 就选不中里面的文字。这里只放行这一个组合;方向键等其余按键仍归 handleCellKeyDown 做单元格导航。
227
+ * AG-Grid 把 Ctrl+A 当成「选中所有单元格」、Home/End 当成「跳到行首/行尾单元格」并 preventDefault;
228
+ * 我们的 handleCellKeyDown 又把方向键一律当成「跳到相邻单元格」——输入框里全选、用方向键移动光标、
229
+ * Shift+方向键扩选文字就全都做不了。规则:
230
+ * - Ctrl/Cmd+A、Home/End、带 Shift/Ctrl/Alt/Cmd 的方向键、输入法组字期间的按键 -> 输入框自己处理;
231
+ * - 左右方向键:光标还能动就移动光标(有选区时先收起选区),已经在最左/最右再按才跳到相邻单元格;
232
+ * - 上下方向键:单行输入框没有纵向光标,照旧在行间导航;多行文本域在首行/末行才导航;
233
+ * - 焦点不在输入框里(在单元格本身)、只读输入框(如下拉选择)、不支持光标的输入框:照旧导航。
219
234
  * 复制/粘贴/剪切/撤销 AG-Grid 本来就没拦,不必处理。@author nokecy
220
235
  */
221
- var suppressSelectAllInInput = exports.suppressSelectAllInInput = function suppressSelectAllInInput(_ref) {
236
+ var isNativeInputKey = exports.isNativeInputKey = function isNativeInputKey(event) {
222
237
  var _target$matches;
223
- var event = _ref.event;
224
- if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== 'a') return false;
225
238
  var target = event.target;
226
- return !!(target !== null && target !== void 0 && (_target$matches = target.matches) !== null && _target$matches !== void 0 && _target$matches.call(target, 'input, textarea, [contenteditable="true"]'));
239
+ if (!(target !== null && target !== void 0 && (_target$matches = target.matches) !== null && _target$matches !== void 0 && _target$matches.call(target, 'input, textarea, [contenteditable="true"]'))) return false;
240
+ var key = event.key;
241
+ if (event.isComposing) return true;
242
+ if ((event.ctrlKey || event.metaKey) && key.toLowerCase() === 'a') return true;
243
+ if (key === 'Home' || key === 'End') return true;
244
+ if (!key.startsWith('Arrow')) return false;
245
+ if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) return true;
246
+ var el = target;
247
+ var start = el.selectionStart,
248
+ end = el.selectionEnd,
249
+ value = el.value;
250
+ // 不支持光标的输入框(如 checkbox)、只读输入框:没有光标可动,方向键用来导航
251
+ if (start == null || end == null || el.readOnly || el.disabled) return false;
252
+ var collapsed = start === end;
253
+ if (key === 'ArrowLeft') return !(collapsed && start === 0);
254
+ if (key === 'ArrowRight') return !(collapsed && end === value.length);
255
+ if (el.tagName !== 'TEXTAREA') return false;
256
+ // 多行文本域:光标不在首行才能往上移,不在末行才能往下移
257
+ return key === 'ArrowUp' ? value.slice(0, start).includes('\n') : value.slice(end).includes('\n');
258
+ };
259
+
260
+ /**
261
+ * keydown 当时的判定。AG-Grid 的 onCellKeyDown 回调是在 setTimeout(0) 里才触发的,那时浏览器已经执行完默认动作、
262
+ * 光标被挪过了:光标从 1 挪到最左、选区收起到末尾之后再算,会误当成「本来就在边缘」而跳格。
263
+ * suppressKeyboardEvent 是 keydown 时同步调用的,状态还没变,所以在那里记下,回调里直接用。
264
+ */
265
+ var nativeKeyDecisions = new WeakMap();
266
+
267
+ /** AG-Grid 的 suppressKeyboardEvent:让 AG-Grid 不再拦截输入框自己处理的按键,并记下这次按键的判定 */
268
+ var suppressNativeInputKeys = exports.suppressNativeInputKeys = function suppressNativeInputKeys(_ref) {
269
+ var event = _ref.event;
270
+ var native = isNativeInputKey(event);
271
+ nativeKeyDecisions.set(event, native);
272
+ return native;
227
273
  };
@@ -18,7 +18,7 @@ var _preview = _interopRequireDefault(require("./preview"));
18
18
  var _antd = require("antd");
19
19
  var _setting = _interopRequireDefault(require("../ag-grid-plus/setting"));
20
20
  var _columnGroupUtils = require("../ag-grid-plus/setting/columnGroupUtils");
21
- var _theme = require("../ag-grid-plus/theme");
21
+ var _theme = require("./theme");
22
22
  var _agGridPlus = require("../ag-grid-plus");
23
23
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
24
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
@@ -34,18 +34,7 @@ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructur
34
34
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
35
35
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
36
36
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
37
- function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // 导入 AG-Grid v33 主题
38
- // array-table 派生主题:去掉单元格聚焦/选区视觉(行内编辑更干净)。
39
- // focusShadow -> 聚焦光环
40
- // rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
41
- // rangeSelectionBackground -> 选区淡蓝填充
42
- // 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。共用主题不受影响。@author nokecy
43
- var arrayTableTheme = _theme.agGridTheme.withParams({
44
- focusShadow: 'none',
45
- rangeSelectionBorderColor: 'transparent',
46
- rangeSelectionBackgroundColor: 'transparent'
47
- });
48
-
37
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // AG-Grid v33 主题:行高、单元格居中、去聚焦/选区视觉(编辑态与阅读态共用一份,见 theme.ts)
49
38
  //@ts-ignore
50
39
  var ArrayTableInner = (0, _react2.observer)(function (props) {
51
40
  var _addition$props;
@@ -341,7 +330,7 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
341
330
  minHeight: 0
342
331
  }
343
332
  }, /*#__PURE__*/_react.default.createElement(_agGridReact.AgGridReact, {
344
- theme: arrayTableTheme,
333
+ theme: _theme.arrayTableTheme,
345
334
  context: gridContext,
346
335
  onGridReady: function onGridReady(params) {
347
336
  params.api.hidePopupMenu();
@@ -392,8 +381,8 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
392
381
  enableCellTextSelection: true,
393
382
  defaultColDef: {
394
383
  resizable: true,
395
- // 输入框里的 Ctrl/Cmd+A 交给浏览器全选文字,不让 AG-Grid 当成「选中所有单元格」拦走
396
- suppressKeyboardEvent: _hooks.suppressSelectAllInInput,
384
+ // 输入框里全选、移动光标、扩选等文字编辑按键交给输入框,不让 AG-Grid 当成表格快捷键拦走
385
+ suppressKeyboardEvent: _hooks.suppressNativeInputKeys,
397
386
  headerComponentParams: {
398
387
  template: '<div class="ag-cell-label-container" role="presentation">' +
399
388
  // ' <span data-ref="eMenu" class="ag-header-icon ag-header-cell-menu-button" aria-hidden="true"></span>' +
@@ -430,7 +419,7 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
430
419
  // }
431
420
  // }}
432
421
  ,
433
- rowHeight: 38,
422
+ rowHeight: _theme.ARRAY_TABLE_ROW_HEIGHT,
434
423
  pagination: false,
435
424
  columnDefs: gridColumnDefs,
436
425
  rowData: dataSource
@@ -8,6 +8,7 @@ var _react = _interopRequireDefault(require("react"));
8
8
  var _react2 = require("@formily/react");
9
9
  var _utils = require("./utils");
10
10
  var _agGridPlus = require("../ag-grid-plus");
11
+ var _theme = require("./theme");
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13
  //@ts-ignore
13
14
  var ArrayTable = function ArrayTable(props) {
@@ -31,7 +32,8 @@ var ArrayTable = function ArrayTable(props) {
31
32
  },
32
33
  hideTool: true,
33
34
  search: false,
34
- rowHeight: 38,
35
+ theme: _theme.arrayTablePreviewTheme,
36
+ rowHeight: _theme.ARRAY_TABLE_ROW_HEIGHT,
35
37
  pagination: false,
36
38
  columnDefs: columns,
37
39
  rowData: dataSource
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 行高 38:放得下 32px 高的输入框。网格选项 rowHeight 与主题参数 rowHeight 必须同值——
3
+ * AG-Grid 单元格文字的行高(--ag-internal-content-line-height)是从主题的 --ag-row-height 算的,
4
+ * 只设网格选项会让文字的行盒仍是主题默认行高(29.6-3=26.6px),顶在 37px 的格子上方(偏上约 4.5px)。
5
+ */
6
+ export declare const ARRAY_TABLE_ROW_HEIGHT = 38;
7
+ /** 阅读态主题:共用主题 + 行高 + 单元格居中 */
8
+ export declare const arrayTablePreviewTheme: import("ag-grid-community").Theme<import("ag-grid-community").CoreParams & import("ag-grid-community").ButtonStyleParams & import("ag-grid-community").CheckboxStyleParams & import("ag-grid-community").TabStyleParams & import("ag-grid-community").InputStyleParams & {}>;
9
+ /**
10
+ * 编辑态主题:在阅读态主题上去掉单元格聚焦/选区视觉(行内编辑更干净)。
11
+ * focusShadow -> 聚焦光环
12
+ * rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
13
+ * rangeSelectionBackground -> 选区淡蓝填充
14
+ * 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。
15
+ */
16
+ export declare const arrayTableTheme: import("ag-grid-community").Theme<import("ag-grid-community").CoreParams & import("ag-grid-community").ButtonStyleParams & import("ag-grid-community").CheckboxStyleParams & import("ag-grid-community").TabStyleParams & import("ag-grid-community").InputStyleParams & {}>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.arrayTableTheme = exports.arrayTablePreviewTheme = exports.ARRAY_TABLE_ROW_HEIGHT = void 0;
7
+ var _agGridCommunity = require("ag-grid-community");
8
+ var _theme = require("../ag-grid-plus/theme");
9
+ /**
10
+ * ArrayTable(明细表格)的 AG-Grid 主题:编辑态(index.tsx)与阅读态(preview.tsx)共用。
11
+ *
12
+ * @author nokecy
13
+ */
14
+
15
+ /**
16
+ * 行高 38:放得下 32px 高的输入框。网格选项 rowHeight 与主题参数 rowHeight 必须同值——
17
+ * AG-Grid 单元格文字的行高(--ag-internal-content-line-height)是从主题的 --ag-row-height 算的,
18
+ * 只设网格选项会让文字的行盒仍是主题默认行高(29.6-3=26.6px),顶在 37px 的格子上方(偏上约 4.5px)。
19
+ */
20
+ var ARRAY_TABLE_ROW_HEIGHT = exports.ARRAY_TABLE_ROW_HEIGHT = 38;
21
+
22
+ /**
23
+ * 单元格里的表单项与内容区垂直居中(只对使用本主题的网格生效,共用主题不受影响):
24
+ * - .ag-cell-wrapper 撑满格子,align-items:center 才起作用(默认只有内容高,贴在格子顶部);
25
+ * - FormItem 默认 margin-bottom:24px(loose 反馈布局给错误文字预留的位置),会把 Editable 外壳撑到 56px、
26
+ * 输入框偏上、还超出 37px 的格子,归零;
27
+ * - 错误提示文字移出文档流(位置仍在输入框下方),出错时输入框不会被挤得上下跳。
28
+ */
29
+ var arrayTableCellFit = (0, _agGridCommunity.createPart)({
30
+ feature: 'arrayTableCellFit',
31
+ css: "\n .ag-cell .ag-cell-wrapper { height: 100%; }\n .ag-cell .ant-formily-item { margin-bottom: 0; }\n .ag-cell .ant-formily-item-help { position: absolute; }\n "
32
+ });
33
+
34
+ /** 阅读态主题:共用主题 + 行高 + 单元格居中 */
35
+ var arrayTablePreviewTheme = exports.arrayTablePreviewTheme = _theme.agGridTheme.withParams({
36
+ rowHeight: ARRAY_TABLE_ROW_HEIGHT
37
+ }).withPart(arrayTableCellFit);
38
+
39
+ /**
40
+ * 编辑态主题:在阅读态主题上去掉单元格聚焦/选区视觉(行内编辑更干净)。
41
+ * focusShadow -> 聚焦光环
42
+ * rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
43
+ * rangeSelectionBackground -> 选区淡蓝填充
44
+ * 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。
45
+ */
46
+ var arrayTableTheme = exports.arrayTableTheme = arrayTablePreviewTheme.withParams({
47
+ focusShadow: 'none',
48
+ rangeSelectionBorderColor: 'transparent',
49
+ rangeSelectionBackgroundColor: 'transparent'
50
+ });
@@ -23,12 +23,19 @@ export declare const useRowDrag: (field: ArrayField) => {
23
23
  handleRowDragMove: (event: any) => void;
24
24
  };
25
25
  /**
26
- * AG-Grid 的 suppressKeyboardEvent:单元格里的输入框按 Ctrl/Cmd+A 时,让浏览器自己全选文字。
26
+ * 这个按键该不该交给单元格里的输入框自己处理(浏览器原生行为),而不是当成表格的快捷键/单元格导航。
27
27
  *
28
- * AG-Grid 把 Ctrl+A 当成「选中所有单元格」并 preventDefault,输入框(文本框、数字框都一样)
29
- * 就选不中里面的文字。这里只放行这一个组合;方向键等其余按键仍归 handleCellKeyDown 做单元格导航。
28
+ * AG-Grid 把 Ctrl+A 当成「选中所有单元格」、Home/End 当成「跳到行首/行尾单元格」并 preventDefault;
29
+ * 我们的 handleCellKeyDown 又把方向键一律当成「跳到相邻单元格」——输入框里全选、用方向键移动光标、
30
+ * Shift+方向键扩选文字就全都做不了。规则:
31
+ * - Ctrl/Cmd+A、Home/End、带 Shift/Ctrl/Alt/Cmd 的方向键、输入法组字期间的按键 -> 输入框自己处理;
32
+ * - 左右方向键:光标还能动就移动光标(有选区时先收起选区),已经在最左/最右再按才跳到相邻单元格;
33
+ * - 上下方向键:单行输入框没有纵向光标,照旧在行间导航;多行文本域在首行/末行才导航;
34
+ * - 焦点不在输入框里(在单元格本身)、只读输入框(如下拉选择)、不支持光标的输入框:照旧导航。
30
35
  * 复制/粘贴/剪切/撤销 AG-Grid 本来就没拦,不必处理。@author nokecy
31
36
  */
32
- export declare const suppressSelectAllInInput: ({ event }: {
37
+ export declare const isNativeInputKey: (event: KeyboardEvent) => boolean;
38
+ /** AG-Grid 的 suppressKeyboardEvent:让 AG-Grid 不再拦截输入框自己处理的按键,并记下这次按键的判定 */
39
+ export declare const suppressNativeInputKeys: ({ event }: {
33
40
  event: KeyboardEvent;
34
41
  }) => boolean;
@@ -11,6 +11,12 @@ var supportsSelectionRange = function supportsSelectionRange(el) {
11
11
  */
12
12
  export var useCellFocus = function useCellFocus() {
13
13
  var focusInputInCell = useCallback(function (cell) {
14
+ // 焦点已经在本格的输入框里:用户直接点进去定位光标、双击选词、按住拖选,这些留下的光标/选区都是他的。
15
+ // 不能再 focus() 并把光标挪到末尾——那会把这些操作在 10ms 后全部抹掉。
16
+ // 首次点开、键盘导航进来时焦点还不在本格输入框里,不受影响。@author nokecy
17
+ var active = document.activeElement;
18
+ if (active && cell.contains(active) && active.matches('input, textarea')) return;
19
+
14
20
  // 首先查找Editable包装的元素
15
21
  var editableElement = cell.querySelector('.ant-formily-editable');
16
22
  if (editableElement) {
@@ -95,11 +101,15 @@ export var useCellFocus = function useCellFocus() {
95
101
  */
96
102
  export var useKeyboardNavigation = function useKeyboardNavigation(ref, dataSource, focusInputInCell, activateCell) {
97
103
  var handleCellKeyDown = useCallback(function (event) {
104
+ var _nativeKeyDecisions$g;
98
105
  var keyEvent = event.event,
99
106
  node = event.node,
100
107
  colDef = event.colDef,
101
108
  api = event.api;
102
109
  if (!keyEvent) return;
110
+ // 输入框里移动光标/扩选/全选的按键归输入框,表格不导航(见 isNativeInputKey)。
111
+ // 判定用 keydown 当时记下的(见 suppressNativeInputKeys);没记过(不是 AG-Grid 触发的)才现算。
112
+ if ((_nativeKeyDecisions$g = nativeKeyDecisions.get(keyEvent)) !== null && _nativeKeyDecisions$g !== void 0 ? _nativeKeyDecisions$g : isNativeInputKey(keyEvent)) return;
103
113
 
104
114
  // 处理上下左右键导航
105
115
  if (keyEvent.key === 'ArrowDown' || keyEvent.key === 'ArrowUp' || keyEvent.key === 'ArrowLeft' || keyEvent.key === 'ArrowRight') {
@@ -206,16 +216,52 @@ export var useRowDrag = function useRowDrag(field) {
206
216
  };
207
217
 
208
218
  /**
209
- * AG-Grid 的 suppressKeyboardEvent:单元格里的输入框按 Ctrl/Cmd+A 时,让浏览器自己全选文字。
219
+ * 这个按键该不该交给单元格里的输入框自己处理(浏览器原生行为),而不是当成表格的快捷键/单元格导航。
210
220
  *
211
- * AG-Grid 把 Ctrl+A 当成「选中所有单元格」并 preventDefault,输入框(文本框、数字框都一样)
212
- * 就选不中里面的文字。这里只放行这一个组合;方向键等其余按键仍归 handleCellKeyDown 做单元格导航。
221
+ * AG-Grid 把 Ctrl+A 当成「选中所有单元格」、Home/End 当成「跳到行首/行尾单元格」并 preventDefault;
222
+ * 我们的 handleCellKeyDown 又把方向键一律当成「跳到相邻单元格」——输入框里全选、用方向键移动光标、
223
+ * Shift+方向键扩选文字就全都做不了。规则:
224
+ * - Ctrl/Cmd+A、Home/End、带 Shift/Ctrl/Alt/Cmd 的方向键、输入法组字期间的按键 -> 输入框自己处理;
225
+ * - 左右方向键:光标还能动就移动光标(有选区时先收起选区),已经在最左/最右再按才跳到相邻单元格;
226
+ * - 上下方向键:单行输入框没有纵向光标,照旧在行间导航;多行文本域在首行/末行才导航;
227
+ * - 焦点不在输入框里(在单元格本身)、只读输入框(如下拉选择)、不支持光标的输入框:照旧导航。
213
228
  * 复制/粘贴/剪切/撤销 AG-Grid 本来就没拦,不必处理。@author nokecy
214
229
  */
215
- export var suppressSelectAllInInput = function suppressSelectAllInInput(_ref) {
230
+ export var isNativeInputKey = function isNativeInputKey(event) {
216
231
  var _target$matches;
217
- var event = _ref.event;
218
- if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== 'a') return false;
219
232
  var target = event.target;
220
- return !!(target !== null && target !== void 0 && (_target$matches = target.matches) !== null && _target$matches !== void 0 && _target$matches.call(target, 'input, textarea, [contenteditable="true"]'));
233
+ if (!(target !== null && target !== void 0 && (_target$matches = target.matches) !== null && _target$matches !== void 0 && _target$matches.call(target, 'input, textarea, [contenteditable="true"]'))) return false;
234
+ var key = event.key;
235
+ if (event.isComposing) return true;
236
+ if ((event.ctrlKey || event.metaKey) && key.toLowerCase() === 'a') return true;
237
+ if (key === 'Home' || key === 'End') return true;
238
+ if (!key.startsWith('Arrow')) return false;
239
+ if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) return true;
240
+ var el = target;
241
+ var start = el.selectionStart,
242
+ end = el.selectionEnd,
243
+ value = el.value;
244
+ // 不支持光标的输入框(如 checkbox)、只读输入框:没有光标可动,方向键用来导航
245
+ if (start == null || end == null || el.readOnly || el.disabled) return false;
246
+ var collapsed = start === end;
247
+ if (key === 'ArrowLeft') return !(collapsed && start === 0);
248
+ if (key === 'ArrowRight') return !(collapsed && end === value.length);
249
+ if (el.tagName !== 'TEXTAREA') return false;
250
+ // 多行文本域:光标不在首行才能往上移,不在末行才能往下移
251
+ return key === 'ArrowUp' ? value.slice(0, start).includes('\n') : value.slice(end).includes('\n');
252
+ };
253
+
254
+ /**
255
+ * keydown 当时的判定。AG-Grid 的 onCellKeyDown 回调是在 setTimeout(0) 里才触发的,那时浏览器已经执行完默认动作、
256
+ * 光标被挪过了:光标从 1 挪到最左、选区收起到末尾之后再算,会误当成「本来就在边缘」而跳格。
257
+ * suppressKeyboardEvent 是 keydown 时同步调用的,状态还没变,所以在那里记下,回调里直接用。
258
+ */
259
+ var nativeKeyDecisions = new WeakMap();
260
+
261
+ /** AG-Grid 的 suppressKeyboardEvent:让 AG-Grid 不再拦截输入框自己处理的按键,并记下这次按键的判定 */
262
+ export var suppressNativeInputKeys = function suppressNativeInputKeys(_ref) {
263
+ var event = _ref.event;
264
+ var native = isNativeInputKey(event);
265
+ nativeKeyDecisions.set(event, native);
266
+ return native;
221
267
  };
@@ -19,7 +19,7 @@ import { connect, mapProps, mapReadPretty } from "@formily/react";
19
19
  import uniqueId from "lodash/uniqueId";
20
20
  import { useAddition, buildArrayTableColumns, useArrayTableSources, useArrayTableActions, isColumnComponent } from "./utils";
21
21
  import { groupColumnDefs } from "./columnGroup";
22
- import { useCellFocus, useKeyboardNavigation, useRowDrag, suppressSelectAllInInput } from "./hooks";
22
+ import { useCellFocus, useKeyboardNavigation, useRowDrag, suppressNativeInputKeys } from "./hooks";
23
23
  import ArrayBase from "./arrayBase";
24
24
  import ArrayAddBtn from "./arrayAddBtn";
25
25
  import PreviewArrayTable from "./preview";
@@ -27,21 +27,10 @@ import { Space } from "antd";
27
27
  import Setting from "../ag-grid-plus/setting";
28
28
  import { flatConfigToColumnState, flatConfigToGridState } from "../ag-grid-plus/setting/columnGroupUtils";
29
29
 
30
- // 导入 AG-Grid v33 主题
31
- import { agGridTheme } from "../ag-grid-plus/theme";
30
+ // AG-Grid v33 主题:行高、单元格居中、去聚焦/选区视觉(编辑态与阅读态共用一份,见 theme.ts)
31
+ import { arrayTableTheme, ARRAY_TABLE_ROW_HEIGHT } from "./theme";
32
32
  import { useGridSchemes } from "../ag-grid-plus";
33
33
 
34
- // array-table 派生主题:去掉单元格聚焦/选区视觉(行内编辑更干净)。
35
- // focusShadow -> 聚焦光环
36
- // rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
37
- // rangeSelectionBackground -> 选区淡蓝填充
38
- // 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。共用主题不受影响。@author nokecy
39
- var arrayTableTheme = agGridTheme.withParams({
40
- focusShadow: 'none',
41
- rangeSelectionBorderColor: 'transparent',
42
- rangeSelectionBackgroundColor: 'transparent'
43
- });
44
-
45
34
  //@ts-ignore
46
35
  var ArrayTableInner = observer(function (props) {
47
36
  var _addition$props;
@@ -388,8 +377,8 @@ var ArrayTableInner = observer(function (props) {
388
377
  enableCellTextSelection: true,
389
378
  defaultColDef: {
390
379
  resizable: true,
391
- // 输入框里的 Ctrl/Cmd+A 交给浏览器全选文字,不让 AG-Grid 当成「选中所有单元格」拦走
392
- suppressKeyboardEvent: suppressSelectAllInInput,
380
+ // 输入框里全选、移动光标、扩选等文字编辑按键交给输入框,不让 AG-Grid 当成表格快捷键拦走
381
+ suppressKeyboardEvent: suppressNativeInputKeys,
393
382
  headerComponentParams: {
394
383
  template: '<div class="ag-cell-label-container" role="presentation">' +
395
384
  // ' <span data-ref="eMenu" class="ag-header-icon ag-header-cell-menu-button" aria-hidden="true"></span>' +
@@ -426,7 +415,7 @@ var ArrayTableInner = observer(function (props) {
426
415
  // }
427
416
  // }}
428
417
  ,
429
- rowHeight: 38,
418
+ rowHeight: ARRAY_TABLE_ROW_HEIGHT,
430
419
  pagination: false,
431
420
  columnDefs: gridColumnDefs,
432
421
  rowData: dataSource
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import { useField } from "@formily/react";
3
3
  import { buildArrayTableColumns, useArrayTableSources } from "./utils";
4
4
  import { AgGridPlus } from "../ag-grid-plus";
5
+ import { arrayTablePreviewTheme, ARRAY_TABLE_ROW_HEIGHT } from "./theme";
5
6
  //@ts-ignore
6
7
  var ArrayTable = function ArrayTable(props) {
7
8
  var height = props.height;
@@ -24,7 +25,8 @@ var ArrayTable = function ArrayTable(props) {
24
25
  },
25
26
  hideTool: true,
26
27
  search: false,
27
- rowHeight: 38,
28
+ theme: arrayTablePreviewTheme,
29
+ rowHeight: ARRAY_TABLE_ROW_HEIGHT,
28
30
  pagination: false,
29
31
  columnDefs: columns,
30
32
  rowData: dataSource
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 行高 38:放得下 32px 高的输入框。网格选项 rowHeight 与主题参数 rowHeight 必须同值——
3
+ * AG-Grid 单元格文字的行高(--ag-internal-content-line-height)是从主题的 --ag-row-height 算的,
4
+ * 只设网格选项会让文字的行盒仍是主题默认行高(29.6-3=26.6px),顶在 37px 的格子上方(偏上约 4.5px)。
5
+ */
6
+ export declare const ARRAY_TABLE_ROW_HEIGHT = 38;
7
+ /** 阅读态主题:共用主题 + 行高 + 单元格居中 */
8
+ export declare const arrayTablePreviewTheme: import("ag-grid-community").Theme<import("ag-grid-community").CoreParams & import("ag-grid-community").ButtonStyleParams & import("ag-grid-community").CheckboxStyleParams & import("ag-grid-community").TabStyleParams & import("ag-grid-community").InputStyleParams & {}>;
9
+ /**
10
+ * 编辑态主题:在阅读态主题上去掉单元格聚焦/选区视觉(行内编辑更干净)。
11
+ * focusShadow -> 聚焦光环
12
+ * rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
13
+ * rangeSelectionBackground -> 选区淡蓝填充
14
+ * 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。
15
+ */
16
+ export declare const arrayTableTheme: import("ag-grid-community").Theme<import("ag-grid-community").CoreParams & import("ag-grid-community").ButtonStyleParams & import("ag-grid-community").CheckboxStyleParams & import("ag-grid-community").TabStyleParams & import("ag-grid-community").InputStyleParams & {}>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ArrayTable(明细表格)的 AG-Grid 主题:编辑态(index.tsx)与阅读态(preview.tsx)共用。
3
+ *
4
+ * @author nokecy
5
+ */
6
+ import { createPart } from 'ag-grid-community';
7
+ import { agGridTheme } from "../ag-grid-plus/theme";
8
+
9
+ /**
10
+ * 行高 38:放得下 32px 高的输入框。网格选项 rowHeight 与主题参数 rowHeight 必须同值——
11
+ * AG-Grid 单元格文字的行高(--ag-internal-content-line-height)是从主题的 --ag-row-height 算的,
12
+ * 只设网格选项会让文字的行盒仍是主题默认行高(29.6-3=26.6px),顶在 37px 的格子上方(偏上约 4.5px)。
13
+ */
14
+ export var ARRAY_TABLE_ROW_HEIGHT = 38;
15
+
16
+ /**
17
+ * 单元格里的表单项与内容区垂直居中(只对使用本主题的网格生效,共用主题不受影响):
18
+ * - .ag-cell-wrapper 撑满格子,align-items:center 才起作用(默认只有内容高,贴在格子顶部);
19
+ * - FormItem 默认 margin-bottom:24px(loose 反馈布局给错误文字预留的位置),会把 Editable 外壳撑到 56px、
20
+ * 输入框偏上、还超出 37px 的格子,归零;
21
+ * - 错误提示文字移出文档流(位置仍在输入框下方),出错时输入框不会被挤得上下跳。
22
+ */
23
+ var arrayTableCellFit = createPart({
24
+ feature: 'arrayTableCellFit',
25
+ css: "\n .ag-cell .ag-cell-wrapper { height: 100%; }\n .ag-cell .ant-formily-item { margin-bottom: 0; }\n .ag-cell .ant-formily-item-help { position: absolute; }\n "
26
+ });
27
+
28
+ /** 阅读态主题:共用主题 + 行高 + 单元格居中 */
29
+ export var arrayTablePreviewTheme = agGridTheme.withParams({
30
+ rowHeight: ARRAY_TABLE_ROW_HEIGHT
31
+ }).withPart(arrayTableCellFit);
32
+
33
+ /**
34
+ * 编辑态主题:在阅读态主题上去掉单元格聚焦/选区视觉(行内编辑更干净)。
35
+ * focusShadow -> 聚焦光环
36
+ * rangeSelectionBorder -> 单格点击形成的 1×1 选区蓝边
37
+ * rangeSelectionBackground -> 选区淡蓝填充
38
+ * 仅去视觉,不动焦点功能——键盘导航/点击进编辑仍依赖 cell focus。
39
+ */
40
+ export var arrayTableTheme = arrayTablePreviewTheme.withParams({
41
+ focusShadow: 'none',
42
+ rangeSelectionBorderColor: 'transparent',
43
+ rangeSelectionBackgroundColor: 'transparent'
44
+ });