This commit is contained in:
oneao committed 2026-10-16 17:30:17 +08:00
1 parent e7c84a82a2
commit 025d3232c4
65 files changed
+9838 -9111

No files matched your search

@@ -2,24 +2,29 @@
'@g3soft/ui': minor
---
G3Table 键盘:方向键显式分工(左右归输入框、上下给表格导航)、Enter 确认并下移、多行编辑器回车换行。
G3Table 键盘:左右键改为「**输入框先消费、到边界才切格**」,Enter 确认并下移,并**移除 `textarea` 编辑器**。
**单击格仍直接进入编辑** —— 本组件的既有交互不变,这次只调整键盘分工与几处不符习惯的行为。
**单击格仍直接进入编辑** —— 本组件的既有交互不变,这次调整的是键盘分工、横向移动能力与编辑器类型集合。
- **方向键显式分工**。此前方向键**全部**被输入框吃掉(编辑器一挂上就聚焦),想改中间一位时整格跳走、想换行时又只能靠 Tab —— 两个方向都别扭。现在:
- **左右** → 交给输入框移动光标 / `Shift+左右` 选中文本(编辑文本的刚需,不能让出去);
- **上下**(单行)→ **让给表格**导航,切到上 / 下一行的同一列**并进入编辑**(单行输入框里上下键没有任何原生用途,让出去是零损失);
- `Shift+上下` → 仍归输入框(原生语义是「选中到首尾」);
- `textarea` 里的上下 → 仍归输入框(要跨行移动光标)。
- ⚠️ 左右不能让给表格:同一个键不可能既移光标又切格。横向切换用 `Tab`(它还会跳过只读列,比按列 ±1 更贴合录入语境)。
- **Enter(单行)= 确认 + 下移到下一行同列**(Excel / Sheets / AG Grid / Handsontable 的通行约定)。
- **左右键:`input` 先消费,消费不了才切格**(本次最核心的变化)。判据是「输入框还能不能消费这一记按键」:
- 光标在文本中间、或**存在选区** → 归输入框(移光标 / `Shift+左右` 选文本 / 按词跳);
- **值为空**、或**光标已贴在该方向的边界**(`←` 在 0、`→` 在末尾)→ 归表格,切到相邻的**可编辑格**并继续编辑;
- 取不到 `selection`(旧内核的 `number`、焦点还没落到 input 上)→ 也算消费不了,让切格生效,避免出现「按了完全没反应」的死键。
- ⚠️ 此前左右键**无条件**归输入框,结果是编辑态里**永远无法横向换格**:改完金额想去右边那格只能按 `Tab`,而 `Tab` 会跨行回绕、还会跳过只读列,横向连改几列的手感是「跳」而不是「逐格走」。反过来一律给表格则没法改金额中间那一位 —— 按「能不能消费」分档才把两种意图都保住。
- `Shift` / `Ctrl` / `Alt` / `Meta` + 左右**永远**留给输入框(选中到边界是有效操作,按词跳是平台约定)。
- 横向移动**到行边界即停、不跨行**(跨行用 `Tab` / `Enter`):一记水平按键若把人带到下一行开头是纯粹的意外。
- `date` 编辑器按同一套判据,并在切格前显式提交手输草稿。
- **移除 `textarea` 编辑器**:行内编辑的单元格高度就是行高(默认 30px),多行编辑器在里面放不下正文 —— 要么撑着行高不齐、要么内部滚动,两种都不算「在格子里改值」。需要多行文本请用 Input 的 textarea 形态放在表单 / 弹层里。
- `TableEditor.type` 收窄为 `'text' | 'number' | 'password' | 'select' | 'checkbox' | 'date'`(**类型层面即报错**,不会静默降级);`INPUT_TYPE_MAP` 与表格样式里多行相关的分支(footer 定位、外壳 padding 归零)一并删除。
- 顺带简化了键盘语义:**上下键只有一种去向**(一律让给表格切行),不再有「多行要跨行移光标」那一档;Enter 也不再分单行 / 多行两种含义。
- **Enter = 确认 + 下移到下一行同列**(Excel / Sheets / AG Grid / Handsontable 的通行约定)。
- 旧行为是 `preventDefault` + `select()` —— **全选文本,且不提交**。它既不是浏览器行为(单行 `input` 的 Enter 原生是「提交表单 / 无动作」,**不换行**),也不是表格软件的行为,而且「确认」这个动作整个缺失:改完按回车值还没落库。
- 下一行同一列若是只读列、或那一行被按行禁用 → **跳过**,落到下面第一个可编辑格;到表尾 → **停在原地**(不循环回表头:回车一路按到底突然跳回第一行会很意外)。
- ⚠️ 实现上必须**显式提交**当前值:移动会让编辑器 vnode 卸载,而 DOM 元素被移除时浏览器**不派发 blur**(做日期编辑器时踩过这个坑),只靠 `onBlur` 的话敲完按回车值就丢了。
- **Enter(`type: 'textarea'`)= 换行**(浏览器原生语义)。此前多行与单行共用同一段 `onKeydown` 且没按类型分流,导致备注这类多行格**按回车会把整段文本全选掉、根本换不了行**。
- **`Esc` 会退出编辑态并把焦点还给该格**。此前它只让输入框失焦,而编辑态是**行级**的、那一行仍停在编辑态(表现是「Esc 一下没反应」);更要紧的是焦点掉到 `body` —— 之后按方向键完全不经过表格,等于键盘失灵。
- **checkbox 补上 `Space` 切换**(原生 checkbox 的切换键);`Enter` 保留(表格用户的既有期待,连续录入时手不离 Enter)。此前只认 Enter。
- **`date` 编辑器**按同一套分工:左右归输入框(日期是文本,用户会想改其中一段),上下给导航。
- 配套:playground 新增 `table-keys-wrap` 小表(text / number / textarea 三列,行高给足以容纳多行编辑器)作为宿主 —— `table-wrap` 的列序被 Tab 跳格用例逐格锁着,且它里面没有多行编辑器,锁不住「单行 / 多行 Enter 语义不同」这条区分。
- e2e 新增 7 条:方向键分工 5 条(单击即编辑 / 上下切行 / 左右移光标 / `Shift+左右` 选文本 / `textarea` 跨行)、Enter 单行确认下移、Enter 多行换行。方向键那几条断言的是**光标真的动了 / 选区真的变了**,而不只是「没跳格」。
- 文档新增「键盘:单击即编辑,方向键分工」一节。
- 表尾 / 下面全是不可编辑行 → **停在原地**(不循环回表头:回车一路按到底突然跳回第一行会很意外)。
- **移格前一律显式提交**(Enter / 上下键 / 左右键到边界)。三个出口共用同一个 `commitValue`:
- 必须显式,不能依赖随之而来的失焦:移动会让编辑器 vnode 卸载,而 **DOM 元素被移除时浏览器不派发 blur**(做日期编辑器时踩过这个坑),只靠 `onBlur` 的话敲完按一下方向键值就丢了;
- 抽成一个函数是因为四个出口各写一遍已经出过事故(某个出口漏调 `notifyChange`,值落了库却没抛 `change`,「有时候会保存、有时候不会」这种最难查的分叉)。
- **IME 组合态一律不拦**:`event.isComposing || event.keyCode === 229` 时直接返回。修前在候选框上按 `Enter` 确认候选词会被当成「确认并下移」——候选词上不了屏、光标还跳到下一行;候选框里 `↑↓` 选字也会被当成切行。两个判据都要:部分浏览器在「确认候选」那一下 `isComposing` 已置回 false,只剩 `keyCode 229` 可用。
- **`Shift+上下` 必须 `stopPropagation`**:只「不主动放行」是不够的,事件照样冒泡到底座的选区导航上把格子切走 —— 表现是「想选中到开头,结果跳到了上一行」。
- 内部:`findCellBelow` 泛化为 `findAdjacentCell(..., direction)`(四向),新增 `EditableContext.moveToAdjacent`;`moveToCellBelow` 与它共用 G3Table 里同一个 `moveToAdjacentCell`,让鼠标点击 / `Tab` / `Enter` / 方向键四条路径都走「改选区 → 激活编辑」这一条链路,避免各写一套而行为分叉。
- 配套:playground 的 `table-keys-wrap` 三列改为单行(text / number / text),并去掉为其多行编辑器准备的 `row-height`;文档、`editable` 示例与 ERP 的 `table-test` 页同步。
- 单测:`editable.test.ts` 从 63 增至 86 条(新增左右键边界判据一组、四向 `findAdjacentCell` 一组、IME 组合态、`Shift+上下`、Enter 显式提交;删掉两条多行用例),table 包合计 185 条全绿;e2e 方向键一组 9 条(中间移光标 / 两个方向的边界切格 / 值为空切格 / 到行边界不跨行 / `Shift+左右` / 切格前显式提交)与 Enter 一组 2 条,断言的是**焦点真的落到相邻格**而不只是「没跳格」。