u
This commit is contained in:
1 parent
025d3232c4
commit
1d7d75eeba
98 files changed
+4144
-12063
No files matched your search
@@ -1,18 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table:校验态补「左侧语义色竖条」、禁用灰底加深一档 —— 让「格级」与「行级」状态重新分得开。
|
||||
|
||||
- **校验态(`errorStyle: 'cell'`)新增左侧 3px 语义色竖条**(error 红 / warning 琥珀),底色浓度不变(8% / 5%)。
|
||||
- 背景:表体的纵向列线已经去掉(见上一条 changeset)。原来「格级色块被列线围成矩形、行级是一条长带」的**形状差异**没了,校验底色退化成无边界的横带,只剩色相一个通道 —— 「这一格有问题」很容易被读成「这一段行有问题」。左侧竖条把形状还回来:竖条 = 格级,横带 = 行级。
|
||||
- 画在 `background-image` 上,不是 `border`(进盒模型会顶高行高、破坏虚拟滚动 `translateY` 的基准),也不是 `box-shadow`(单值属性,会与库的单元格选区描边、焦点环、固定列叠色互相整条覆盖)。因此 `background-origin` 按层指定:第 1 层用 `border-box` —— 表体纯文本格有 `--cell-padding-x`(12px)内边距,用默认的 `padding-box` 竖条会飘在格子内部 12px 处。
|
||||
- 「正在编辑的那一格让位」的既有行为不变:编辑时既无底色也无竖条,只剩语义色焦点环 + 红字。
|
||||
- **禁用(改不了)灰底从 3% 提到 6%**(暗色 4% → 8%)。灰底与斑马纹同色相、都是一条横带,原来只差约 1% 亮度,肉眼分不出「这行是条纹」还是「这格改不了」;拉开一档后可辨。整列只读 / 整列禁用 / 按行禁用三种情形共用这一套。
|
||||
- **「既禁用又校验不过」的格子仍然只显示灰**(既有决策:改不了就别再提示这里错了)。灰底规则里**显式写回**库那两层格线(`background-image: var(--bg-border-right), var(--bg-border-bottom)`)—— 竖条加在 `background-image` 第 1 层上,而 background-image 不能按层覆盖,只改 `background-color` 的话灰底上会留一条红 / 黄竖条。亮 / 暗两份灰底规则都要写(只写亮色就会出现「亮色纯灰、暗色留红条」)。
|
||||
- **注释修正**:`G3Table.vue` 里「灰底权重 (0,6,1) 高于校验态 (0,4,1)」这句是旧数字 —— 校验态选择器带 `:has()`,特异性取参数中最高者,按行禁用那条与校验态实测同为 `(0,7,1)`,胜负实际由「谁写在后面」决定。已改成准确表述并加了警告。
|
||||
- **失败原因现在有出口了**:`validate` / `validateWarning` 返回的字符串(「金额必须大于 0」)此前在 `resolveEditorStatus` 里**只被取 `.length` 判等级、内容直接丢掉** —— 业务精心写的失败原因没有任何出口,用户只知道「这格红了」。现在该结果归一为 `{ level, message }` 一次带出,挂到内容节点的 `data-validate-message` 上,表格侧 **hover 那一格**时弹一个自绘浮层显示原因(悬停格内任意位置都行,移开 / 滚动即收)。
|
||||
- 浮层是**全表共用一个 DOM**(`v-if` + 根节点上的 `mouseover` 事件委托),常态下定时器 / 监听器 / DOM 全都不存在;落到出错格上只做一次 `getBoundingClientRect()`,且滚动即关闭、不做跟随,所以滚动路径上不会出现逐帧测量。刻意没有给每个出错格挂 Tooltip:那是每个实例两组监听器,虚拟滚动下还要随行反复挂载销毁,再叠上固定列 `sticky` 的定位与层叠,容易写出「只在某个滚动位置下错位」的问题。
|
||||
- 委托的判定单位是**格子**(`td`)而不是事件目标的祖先链:空值格的展示 span **宽度为 0**、右对齐数字格也常只有文字那么宽,鼠标绝大多数位置落在 `td` 的内边距上,按祖先链找会静默弹不出来(实测踩到)。
|
||||
- 有原因时该格的 `title` 会让位(原本它挂的是「值」,用于内容被省略时兜底),避免原生 tooltip 与浮层叠成两个框;`aria-label` 则拼成「金额,金额必须大于 0」供屏幕阅读器。
|
||||
- 文档(`docs/content/ui/data/table.md` 的「展示形态 `errorStyle`」与「不可改的格子」两节)同步更新。
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': patch
|
||||
---
|
||||
|
||||
G3Table:`checkbox` 列点击后与其它单元格**行为一致**(该格成为当前格)。
|
||||
|
||||
- 原先点复选框只切换值:因为 `createCheckbox` 把 `mousedown` 停掉了(换「一次点击就切换」——底座的 mousedown 会先激活行编辑、把节点替换掉,Chromium 因此不派发 `click`,不停就会变成「第一次点击只进编辑、第二次才切换」),底座收不到 mousedown,也就不会像点击其它格那样设选区、激活该行编辑、置当前行。
|
||||
- 后果(实测):值改了、`change` 也抛了,但**整行不高亮、格子没有选中框**,看不出在哪儿改;而且表格里**没有任何选区** —— 接着按 `Tab` / 方向键会从 `(0,0)` 起步、焦点掉到 `body`,键盘用户从复选框出发就走不动。
|
||||
- 现在切换后会走**同一条链路**(移动选区 → 底座的 `area-selection-change` → 激活编辑 + 当前行 + 选中框),不再另写一套行为。`EditableContext` 增加可选钩子 `onEditorInteract?(row, col)`(内部接口,未导出为公开 API;不实现时行为与之前一致)。
|
||||
- 顺带说明:进入编辑后 `Esc` 会回滚整行(含这次勾选),而 `change` 已经抛给父级 —— 这是本组件既有的「即时提交 + Esc 回滚」语义(`select` 编辑器同理),不是本次改动引入的。
|
||||
- 单测锁「切换/键盘 Enter 都通知表格、仅渲染不通知」;真浏览器 e2e 锁「一次点击即切换 + 行高亮 + 选中框 + 能继续 Tab」(关掉同步后用例变红,实测)。
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table 新增日期编辑器(`editor.type: 'date'`),并为 G3DatePicker 补上无缝模式与两个对外方法。
|
||||
|
||||
- **`editor.type: 'date'`**:点格即弹日历(不必先点输入框),也支持手输;值始终是**字符串**,不做 `Date` ↔ string 的隐式转换。
|
||||
- `format` 同时决定面板精度与绑定值格式(默认 `YYYY-MM-DD`;写 `'YYYY-MM-DD HH:mm'` 即变成日期时间,选完要点「确定」才提交)。界面格式与存储格式不同时用 `valueFormat`。
|
||||
- 校验 / 失败原因浮层 / 禁用灰底 / `errorStyle` 与其它编辑器完全一致,没有另开一套。
|
||||
- 它是**唯一「只给当前格挂编辑器」**的类型:切换格时新格是重新挂载,日历才会跟着弹开。若跟着整行挂载,同行内从别的列切到日期格就不会重新挂载、面板不弹,表现为「有时弹、有时不弹」这种最难解释的不一致。顺带也更省 —— 不激活时是纯展示 span,而 DatePicker 是浮层组件。
|
||||
- **`G3DatePicker` 新增 `seamless`**:去掉触发器的 32px 下限 / 内边距 / 描边 / 圆角。与 `G3Select` 的 `seamless` 同因同解 —— 那些盒子在 Popover 内部,从表格侧写后代选择器命中不到(权重相同、顺序不可控),必须在组件自己的样式块里覆盖。不开的话 32 > 30 会把表格行顶高,看着像「格子里浮着一个小卡片」。
|
||||
- **`G3DatePicker` 新增 `defineExpose({ openPanel, commitPending })`**:前者供表格挂载后主动展开面板,后者供表格在编辑器**卸载前**把没提交的手输文本交掉。
|
||||
- **修一个「手输的日期会静默丢失」的真问题**:关闭面板时原先直接清空了内部草稿,而「点到别处」这条路径**不会**经过 `input` 的 `blur` —— 表格在 mousedown 阶段 `preventDefault`(避免点击干扰单元格选区),焦点压根没离开输入框。于是用户敲完日期点别的格,值就地消失。现在**关闭面板时先提交再收尾**;Esc 分支已在 `onKeydown` 里先把草稿清成 null,所以「按 Esc 取消」依然是取消而非提交(那个顺序不能反)。
|
||||
- 配套:playground 新增一张独立的小日期表(`table-date-wrap`)作为 e2e 宿主(没往 `table-wrap` 里加列 —— 那张表的列序被 Tab 跳格用例逐格锁着);erp 的 `table-test` 页面把「开航日 / 截单日」两列从 `text` 换成 `date`(后者带时间精度)。
|
||||
- **手输解析不出来时不再静默丢弃**:`G3DatePicker` 新增 `invalidInput` 事件(默认无监听者,表单行为不变),表格监听它把原文**写进行数据**,再由一条内置的日期校验标红并给出原因「日期格式不正确」—— 与「金额输 0」「数量超精度」同一套立场:值不合法不等于要抹掉它。配套导出 `checkDate(value, format)`,与组件内置判定**是同一个函数**,供业务在保存前拦提交。
|
||||
- 判定口径刻意**跟随 `G3DatePicker` 手输解析的那个 `parseDateInput`**(不是自己写一套):否则会出现「手输时组件接受了、退回展示态又被标红」这种自相矛盾。注意**不要**换成 `parseDate` —— 它是宽松解析、会退到原生 `new Date()` 兜底,把 `2026-13-45` 这类越界文本「救活」(`parseDateInput` 里那道 `DATE_LIKE_TEXT` 保护正是拦这个的)。
|
||||
- 顺带记录的既有口径:分隔符会被规范化(`2026/03/15` 算合法),而配了时间精度的列只给到「日」算不合法。
|
||||
- e2e 新增三条:点格弹面板并选日期写回字符串;必填校验 + 手输失焦后写回;手输非法日期时值原样保留、标红、悬停能看到原因。
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': patch
|
||||
---
|
||||
|
||||
G3Table:修两个编辑态底色/描边的视觉问题(都与「`select` 展开后焦点被移进浮层」有关)。
|
||||
|
||||
- **修复:`select` 编辑格的底色会变成选区色(浅蓝)而不是基色。** 编辑格白底的判据原先写在 CSS 的 `td:focus-within` 上,而 `G3Select` 展开时会把 DOM 焦点移进**下拉浮层**(浮层 `Teleport` 到 `body`),那一刻 `:focus-within` 立刻失效,底色退回库的 `td[data-cs-s] { background-color: var(--cs-bgc) }`。症状是「时白时不白」——取决于此刻焦点在触发器还是浮层里;`input` 没有浮层,所以只有 `select` 会这样。
|
||||
- 判据改为编辑器上的标记类(`is-cell-editing`,由内容节点带出,与「按行禁用的灰底」「校验态」同一套路子),`td:has(> …)` 精确命中该格,与焦点在格内 / 浮层 / 换格瞬间落到 `body` 都无关。
|
||||
- 焦点环同样补上这个标记(`:focus-within` 与标记取并集):编辑格**始终**有环,不再随焦点漂移。
|
||||
- **修复:冻结列上的选中格没有选中描边(蓝色边框)。** 冻结列的「行状态叠色」用的是 `box-shadow`,而库的选区描边(`td[data-cs-s]` 的 4 个方向 inset)**也在 `box-shadow` 上** —— 单值属性,只写叠色就会把选中框整体替换掉。非冻结列没有这条规则,所以只有冻结列会缺,很容易被当成「选中态没生效」。现在叠色规则连同选区描边一起写。
|
||||
- **冻结列的编辑格不再叠行状态色**:与普通列一致地保持「纯基色 + 焦点环」。否则同一行里冻结列的编辑格带行色、普通列的却是纯色,一眼看得出不一致。
|
||||
- 两条都由真浏览器 e2e 锁住(`e2e/table.spec.ts`):`select` 那条必须在**浮层已夺焦**的状态下断言(否则测不出),冻结列那条断言选中格的 `box-shadow` 里确实含有选区描边色、编辑格带 2px 焦点环。摘掉修复后两条都会红(实测)。
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table:序号列固定左侧,并补上 `fixedColShadow`(固定列阴影开关)。
|
||||
|
||||
- **序号列(`seq`)现在固定在左侧**:横向滚动时行号不再跟着滚走 —— 序号是「这一行是哪一行」的锚点,恰恰是最不该丢的信息。它由组件注入,业务侧不用配,与选择列(同样是 `fixed: 'left'`)保持一致。
|
||||
- 这是一个**默认行为变化**。原先 `seq` 列会随内容滚动,只有在表格出现横向溢出时才看得出差别;没有溢出时 sticky 不产生任何位移。
|
||||
- 序号列宽度会参与左固定列的吸附位移计算,所以调用方业务列的 `fixed: 'left'` 会自动接在序号列之后,不会出现重叠或空档。
|
||||
- 新增 `fixedColShadow`(默认 `false`):固定列被滚过去的列遮挡时,在边界画一条 10px 渐变。它对应底座的 `fixedColShadow`,此前只能靠 `$attrs` 透传、没有正式 prop(组件 `inheritAttrs: false`,透传虽然生效但不该是公开用法)。默认关是刻意的:纯观感开关,业务觉得这层渐变糊得脏就可以不开;但有左右冻结列时建议打开,否则冻结列与滚过去的列同为白底、紧贴在一起,看不出边界在哪。
|
||||
- 文档新增「固定列」一节(`docs/content/ui/data/table.md`):`fixed` 的取值与位置约束、为什么固定列必须写 `width`、阴影开关该不该开;`seq` 的 API 说明也标注了「固定左侧」。
|
||||
- **修复:固定列上的校验态格子被推离本列。** 校验态样式为了让绝对定位的角标有基准,给 `td` 写了 `position: relative`,而固定列 td 的 `position` 是库在用的(被遮挡时 `sticky`,吸附位移以**内联** `left` / `right` 写在 td 上)—— 改成 relative 后那条内联 `left` 变成普通相对位移,整个格子被推开「前面所有左固定列宽度之和」。症状极易误判:只有「固定列 + 校验未通过」的格子位移,看上去就是「错误底色跑到了隔壁两列中间」。现在普通格给 `relative`、固定列保持 `sticky`(sticky 本身就是定位值,角标仍以 td 为基准)。(这两条 `position` 规则随后随「角标整体去掉」一起删除了 —— 成因连根消失,详见 `table-validation-editing-yield`。)
|
||||
- 补了真浏览器几何回归:playground 新增 `table-fixed-wrap`(左固定两列 + 一行空名称 + 列宽总和超出视口),`e2e/table.spec.ts` 断言「错误格与本列表头对齐、滚动后随固定列一起吸附」。去掉修复后该用例会红(实测位移 250px)。
|
||||
- **修复:受控调用方「点可编辑格进入编辑」时当前行不高亮**(`:active-row-key` + `@row-click` 那套 fms 写法,点只读格却正常)。根因在浏览器:点可编辑格会挂载编辑器、把 mousedown 命中的 `.cell-display` 替换掉,Chromium 因此**不派发 click**,库的 `row-click` 不触发,调用方那个唯一写入者收不到消息。现在「激活编辑」这条路径(鼠标 / 键盘 / 键盘防抖收尾)**无条件**同步当前行 —— 对这次手势,组件内部是唯一知道发生了什么的代码,不是第二个写入者。同页的 `editRow()` 命令式 API 行为不变。
|
||||
- **已知限制(已写进文档)**:固定列与**横向虚拟**同时开启时,快速横向拖动会出现一帧位移 —— 横向虚拟在表体左侧留的占位是异步更新的,滚动到位而占位还是旧宽度的那一帧,左固定列的静态位置被占位推着走(`sticky` 只能往右收、不能往左拉),实测偏 258 → 1628(占位全长);右固定列偏差 0,所以只有左侧看得见。已试过在 scroll 里提前重算窗口:无效(合成手势下无改善,且表体多出中间态),故不采用。要绝对稳就 `:virtual-x="false"`;根治需上游把左占位挪到固定列之后。
|
||||
- **变更:灰底判据从「编辑行里没有编辑器的格子」改为「这一格现在改不了」+ 常驻。** 现在三种情形统一显示灰底(与行是否在编辑无关):列上没有 `editor`、`editor.disabled === true`、以及 `editor.disabled` 为函数且对该行返回 true(动态条件,如「已放舱后状态不可改」)。前两种走 td 类名(**不注入 customCell**,零运行时开销),第三种由内容节点带标记(只有这些列会被常驻注入)。顺带删掉了旧判据那套「行内是否挂着 input/select 编辑器」的结构性选择器(它只在被点过的那一行可见,且行内有 checkbox 时会误判整行)。「既禁用又校验不过」的格子显示为灰。
|
||||
- **修复:悬停 / 当前行时固定列是半透明的。** 库给固定列的是 `background-color: inherit`,而行的 hover / 当前行底色是 alpha 值(`--tr-hover-bgc` = `rgba(0,0,0,.04)`、`--tr-active-bgc` = 皮肤给的 `hsl(... / .15)`);非固定列继承它没问题(tr 底下是表格基色),冻结列却在**被横滚的列之上**,于是下面的列直接透上来(表现为「编辑行的固定列透字」)。现在冻结列底色写死不透明的 `--td-bgc`,行状态改用**内阴影**叠色(画在背景之上、内容之下,不压库的边框渐变、不需要给 td 加定位),hover 与当前行各一条规则。
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table 键盘:左右键改为「**输入框先消费、到边界才切格**」,Enter 确认并下移,并**移除 `textarea` 编辑器**。
|
||||
|
||||
**单击格仍直接进入编辑** —— 本组件的既有交互不变,这次调整的是键盘分工、横向移动能力与编辑器类型集合。
|
||||
|
||||
- **左右键:`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 原生是「提交表单 / 无动作」,**不换行**),也不是表格软件的行为,而且「确认」这个动作整个缺失:改完按回车值还没落库。
|
||||
- 表尾 / 下面全是不可编辑行 → **停在原地**(不循环回表头:回车一路按到底突然跳回第一行会很意外)。
|
||||
- **移格前一律显式提交**(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 条,断言的是**焦点真的落到相邻格**而不只是「没跳格」。
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table:表体的纵向列线关闭,表头保留一条更轻的「短竖线」列界。
|
||||
|
||||
- **表体去掉纵向格线**:覆盖层把底座的 `--bg-border-right` / `--bg-border-left` 涂成透明渐变 —— 库给每个 `th`/`td` 铺的就是 `background-image: var(--bg-border-right), var(--bg-border-bottom)`,所以关掉这一个变量就够了。横线(`--bg-border-bottom`)与自绘圆角外框**完全不受影响**,它们走的是另外两条路径。
|
||||
- 「按列摘线」那套已整体删除:早先为「最右列外侧线归外框管」写过 `th/td:last-child` 与右固定列的摘线规则,那个假设只在「列宽铺满容器」时成立(列宽不足时表现为「线没了 + 右侧留白」,有右固定列且横滚时更是摘错了对象)。
|
||||
- **表头保留列界,但换成「短竖线」**:`th` 自己接管 `background-image`,画一条高 `calc(100% - 8px)`(上下各留 4px)、宽 1px 的短线,颜色用新增的 `--g3-table-header-divider`(亮 8% 的黑 ≈ #e1e1e1 / 暗 12% 的白,比 `--border-color` 那档格线色轻一档)。列界仍是「认列 / 拖列宽」的落点,但在比数据行更高的表头上不会顶满上下,观感更柔和。
|
||||
- 为什么接管**整个** `background-image` 而不是只改其中一层:`background-image` / `-size` / `-position` 都是**按层一一对应**的列表属性,而库的层数并不固定(表头首行是 top/right/bottom 三层、多级表头的其它行只有两层)——只补 size / position 会把尺寸套到错误的层上(实测把竖线铺成整格色块)。
|
||||
- 无框模式(`bordered: false`)不受影响:规则限定在 `.stk-table.bordered` 下。
|
||||
- 贴住外框内右缘的右固定列用 `:not(.fixed-cell--right)` 排除,避免那条线与外框 `border` 并排成 2px;「DOM 末列」不排除(它是拖拽该列宽度的落点,列宽没铺满容器时也靠它指出末列到哪儿结束)。
|
||||
- **固定列在数据区的边界改由 `fixedColShadow` 承载**:表体既无竖线,冻结列与滚过去的列又同为不透明基色、紧贴在一起,边界只剩那 10px 渐变能表达。用到左右冻结列的页面**务必**打开 `fixedColShadow`(默认仍为 `false`,不改默认值是刻意的:没有固定列的表格开它什么都画不出来;`g3soft-erp` 的订舱页早已显式开着)。
|
||||
- 同步更新:`docs/content/ui/data/table.md` 的「固定列」与「实现说明」两处;`e2e/table.spec.ts` 的两条用例(表体只剩横线一条 / 表头短竖线的尺寸、位置与色值),并顺手抽出一个 `splitCssLayers` —— 按**顶层逗号**切 CSS 列表值,替掉原先 `split(/,(?![^(]*\))/)` 那种在 `rgba(` 前会失灵的写法(它把 `linear-gradient(rgba(...), rgba(...))` 切成两层,把「两条线」数成三条)。
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table:新增 `editor.precision`(数值精度)与列级 `format`(展示格式化),并导出 `checkPrecision` / `formatNumber`。
|
||||
|
||||
- **`editor.precision`:数值精度(小数位数)**,可传函数按行给。它同时驱动两件事,是**一处真源**:
|
||||
- **展示**:非编辑态按精度格式化(`1200.5` → `1200.50`);
|
||||
- **校验**:超出精度即 error(红底 + 左侧竖条),悬停浮层显示「最多 N 位小数」—— 这是**组件内置**的规则,业务不需要写任何与精度有关的 `validate`。
|
||||
- ⚠️ **不静默四舍五入**:用户输了 `123.456` 而精度是 2,值**仍然是** `123.456`,只是这一格被标红,由用户自己改。悄悄改成 `123.46` 会让「屏幕上的」与「落库的」不是一回事 —— 财务对账时就是「我输的不是这个」。
|
||||
- ⚠️ **超精度时不做格式化展示**(原样裸露真实值):按精度格式化成 `123.46` 会让屏幕完全合规、数据却不合规,用户永远发现不了自己错了。
|
||||
- 录入时**不做实时拦截**:实时的精度过滤要与光标位置、输入法组合态、半输入态(`12.` / `-`)搏斗,是公认的坑;「输完再判」既确定又可预测。
|
||||
- 判定用**字符串**数小数位而不是数值运算:`Math.round(v * 100) / 100` 在 `1.005` 上给出的是 `1`(`1.005 * 100 = 100.49999999999999`),而金额最容易撞上这种「看着是两位小数、二进制里不是」的值。
|
||||
- **`checkPrecision(value, precision)` 对外导出**:业务在保存前做提交拦截时必须复用**同一个函数**,否则会出现「格子红了但存档能过」这类两边不一致、又极难排查的问题。
|
||||
- **列级 `format`:展示态格式化**(只影响显示,落库值不变)。传选项对象走底座的 `formatNumber`(千分位 / `¥` 前后缀 / 万-亿缩写 / 百分比);传函数则完全自定义(`Intl.NumberFormat` 的正解 —— 多语言的小数点与千分位符号、会计的括号负数这些 locale 规则,重写一遍必然缺选项)。小数位取 `format.decimals ?? editor.precision`。
|
||||
- **顺带解决一个缺口**:底座的 `createNumberCell` 是**纯展示**单元格,用法是 `customCell: NumberCell()`,而我们的 `resolveCustomCell` 对显式 `customCell` 是直接放行的 —— 业务一旦用它就绕过了整条编辑链路(编辑、校验、灰底、Tab 跳格、Enter/Esc 语义、草稿与失焦提交全没了)。也就是说「**可编辑的金额列**」此前没有任何合法方式做格式化展示。现在 `format` 与 `editor` 正交,两者可同时存在。
|
||||
- **门控(性能)**:`resolveCustomCell` 新增两条常驻判据 —— 配了 `precision` 的 number 列、以及配了 `format` 的**纯展示**列(后者走一个只做格式化的轻量 cell)。代价只落在**显式配了这两样**的列上,普通列照旧走库的原生 td 渲染、零组件开销。
|
||||
- 单测覆盖边界(`utils/precision.test.ts`,13 条):空值/非数字/展示文本/科学计数法一律放行、负数符号不参与位数、`1.005` 这类浮点陷阱、非法精度配置当作没配、格式化与自定义函数的优先级。
|
||||
- **修复:右对齐列一点进编辑,文字就跳到左边。** `text-align` 本是继承属性,但**表单控件**的 UA 样式表把它覆盖成 `start` —— 实测点进金额格后 input 拿到的是 `start`(LTR 下即左对齐),于是文字与光标从右跳到左,进出编辑有明显位移(与「编辑器无缝嵌入、进出零位移」的目标正好相反)。现在表格侧按库的列对齐类(`.text-r` / `.text-c`)把 `input` / `textarea` 接回来。
|
||||
- **没有给 `G3Input` 加 prop**:右对齐是**列**的属性(`align`),只有表格知道该不该右对齐;加在公共组件上只会多一个当前没人用的 API。将来表单里出现真实诉求再加不迟。
|
||||
- 判据依赖库的 `.text-r` / `.text-c` 类名(实测打在 `td` 上);库若改名这层会**静默失效**(表现只是「编辑时又变回左对齐」),代码注释里写明了排查方式。
|
||||
- 只管 `input` / `textarea`:右对齐的 `select` 极少见,且它的对齐由触发器内部的 flex 布局决定,不是一条 `text-align` 能解决的。
|
||||
- 文档新增「数值精度与金额」一节(含保存前拦截的完整示例)。
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': patch
|
||||
---
|
||||
|
||||
G3Table:「不可改的格子」灰底加上前提 —— **这张表里得先有人能编辑**。
|
||||
|
||||
- 灰底的语义是「这一格现在改不了」,它靠「旁边有可改的格子」传达意义。原先的判据是逐格看「有没有 `editor`」,于是**纯展示表**(列上都没写 `editor`,文档 7 张 demo 里有 6 张如此)会把**每一格**都标成只读并铺灰 —— 整张表看上去像「禁用状态」,与实际(这是一张正常展示表)不符。
|
||||
- 现在两种情况不再铺灰:
|
||||
- 表格里**一个可编辑列都没有**(含「唯一有 editor 的那列 `disabled: true`」);
|
||||
- `editable="false"`,编辑功能整体关掉。
|
||||
- 判据取「存在**真的可编辑**的列」:`disabled` 写成**函数**的列算可编辑(总有行能改,灰底正是要表达它)。
|
||||
- 可编辑表里的行为**不变**:没有 `editor` 的列、`editor.disabled: true` 的列、以及按行禁用的格子照旧常驻灰底(不需要先点开某一行)。
|
||||
- 单测锁「按行禁用时展示 span 带 `cell-readonly`」与「总开关关闭时不带」;真浏览器 e2e 用两个新宿主分别锁「纯展示表」与「`editable: false`」都是 0 个灰格,并反向断言可编辑表里仍有灰底(把门控改成恒真时,纯展示表立刻量到 6 个灰格、用例转红,实测)。
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': minor
|
||||
---
|
||||
|
||||
G3Table:`Tab` / `Shift+Tab` 在可编辑格之间跳格(修复「select 编辑器里按 Tab 没选中下一个」)。
|
||||
|
||||
- **新增键盘跳格**:编辑态下 `Tab` / `Shift+Tab` 提交当前格并落到**下一个 / 上一个可编辑格**——没有 `editor` 的列、以及被 `disabled` 按行禁用的格会被跳过;行尾自动接到下一行的第一个可编辑格,到表格两头则**循环**(Excel / AG Grid 的手感)。全表没有任何可编辑格时不接管,Tab 保持浏览器默认行为。规则落在 `utils/editable.ts` 的 `findAdjacentEditableCell()`,与编辑器的「能不能改」判据同源(`editor` 是否存在 + `disabled` 是否对该行为真),单测覆盖跳过只读列 / 跳过按行禁用 / 跨行回绕 / 两端循环 / 无可编辑格。
|
||||
- **修复:`select` 编辑器里按 Tab,焦点跑到页面其它元素上**(表现为「Tab 没有选中下一个」)。根因是 `G3Select` 展开时会把 DOM 焦点移进**下拉浮层**,而浮层 `Teleport` 到 `body` —— 浮层里的 keydown 不经过 `.stk-table`,底座挂在表格容器上的 Tab 导航永远收不到;浏览器只能按文档顺序找下一个可聚焦元素,于是焦点离开表格(实测落到文档开头)。现在表格在 `document` **捕获阶段**接管 Tab,用 ARIA 关联(浮层 id ↔ 触发器 `aria-controls`)把浮层追回它所属的单元格,再经底座的 `setAreaSelection` 移动选区 —— 激活编辑、聚焦编辑器、滚动进视口全部复用既有链路(鼠标点击与键盘跳格走同一条路)。
|
||||
- 顺带修掉同一处暴露的另一个问题:原先 `Tab` 走到行尾会落到**只读格**上(`focusCol` 为 null,编辑器不存在),表现为「按 Tab 后焦点凭空消失」,再按一次就掉出表格。新规则只落在能接收焦点的格上。
|
||||
- **连按 / 长按 Tab 也不会掉队**:跳格是「改选区 → 激活编辑 → 重挂编辑器 → 聚焦」的异步链路,中间焦点会短暂落在 `body`(旧的编辑器已卸载、新的还没聚焦),且编辑态的 `focusCol` 被防抖推迟。接管里因此做了几件事:起点优先取**选区终点**(每次跳格同步更新,连按时才能一格一格往前走,而不是算回同一格)、换格空档期(200ms)内即使焦点在 `body` 也仍认这记 Tab。
|
||||
- **修复:长按 Tab(或从只读列起步连续 Tab)走到第 3 格就掉出表格。** 这一条是用户实测 100% 复现的:点「订舱号」(只读、没有编辑器)那一格,然后一直按着 Tab 往右走,到「起运港」时焦点就跑到页面其它元素上了。成因是底座的导航优化在长按期间调用 `clearActiveEditing()` —— 它**把 `activeEditingRow` 和 `state.editing` 一起置空**,编辑器全卸载、只留一个待激活目标(`pendingEditingTarget`),焦点因此落在 `body`。旧判据要求 `state.editing === true` 且能取到当前行,于是从第 3 下起就把 Tab 当成「不是给表格的」放行了。现在判据接受「待激活目标还在」这一形态(当前行也从它里面取回来),并按「编辑格不在 DOM 里 → 起点取选区」处理:长按期间一格一格继续走,松手后编辑器落到最后一格。
|
||||
- **修复:编辑行被虚拟滚动滚出渲染窗口后,按 Tab 会逃出表格**(与按键速度无关,慢速必现)。编辑行 / 编辑列离开渲染窗口时编辑器被虚拟滚动**卸载**,焦点掉到 `body`,而编辑态与选区其实都还在(滚回来就恢复);此时 Tab 的事件源既不在编辑器也不在浮层,会被判定成「不是给表格的」而放行 → 浏览器按文档顺序把焦点送出表格(实测落到侧边栏菜单上)。现在这种情况会被接管:**把表格滚回编辑行**并继续前进一格。判据严格限定为「编辑格此刻不在 DOM 里」,避免把「点了页面空白再按 Tab」也吞掉。
|
||||
- 接管只针对**本表格自己的编辑器**(含它的浮层):判定靠 DOM 数据属性(`td[data-col-key]`、`tr[data-row-key]`)与编辑态对齐,其余 Tab 一律放行,不影响页面/表单的 Tab 序。
|
||||
- 文档(`docs/content/ui/data/table.md`)补「跳格」一节;`e2e/table.spec.ts` 增加真浏览器回归(覆盖「焦点在 select 浮层里按 Tab」这条路径,摘掉接管后用例会红)。
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@g3soft/ui': patch
|
||||
---
|
||||
|
||||
G3Table:校验态视觉调整 —— **去掉右上角 `!` 角标**、**编辑时底色让位**、底色调淡一档。
|
||||
|
||||
- **右上角 `!` 角标整体去掉**(实际录入反馈):它画的 `!` 会压到文字上 —— **右对齐的数字列**最明显(数字正好顶在角标下面);而为它让位留出的 `padding-right: 14px` 又实打实缩窄了录入区。去掉之后:
|
||||
- 非编辑态的提示只剩**浅底**,编辑态的提示只剩**语义色焦点环 + 红字**;
|
||||
- 顺带删掉三处「给角标让位」的 padding 规则(输入控件 / 展示 span / select 触发器)—— 校验格的内边距现在与普通格完全一致;
|
||||
- 顺带删掉两条「给角标做定位基准」的 `position` 规则(普通格 `relative` / 固定列 `sticky`)。那两条曾把固定列库内联的 `sticky` 偏移变成普通相对位移,是「错误底色跑到隔壁两列中间」那个 bug 的成因 —— 现在连根消失,`td` 上不再由组件写 `position`。
|
||||
- **编辑格不再铺校验底色**:底色回到基色,校验信号只留**语义色焦点环 + 红字**(铺着底色时输入区被染色、对比度下降,录入时「看不清」)。判据是编辑器上的 `is-cell-editing` 标记,不是 `:focus-within` —— select 展开时焦点被移进 Teleport 到 body 的浮层,`:focus-within` 会时有时无(焦点环那一节踩过同一个坑)。暗色那两条只覆写 `background-color` 的规则也补上了同一个守卫,避免「亮色下编辑时干净、暗色下仍然染色」。
|
||||
- **底色比例调淡一档**(编辑态已不铺底,非编辑态只需够看出差异):亮色 error 12% → 8%、warning 8% → 5%;暗色 error 8% → 6%、warning 6% → 4%。
|
||||
- 真浏览器 e2e 锁三态:未编辑(铺底、`::after` 无内容)→ 编辑(基色底、2px 语义色焦点环)→ 换格后恢复;并断言**校验格与同列普通格的内边距一致**(不再为角标留位)。关掉编辑态守卫该用例会红(实测)。
|
||||
Reference in new issue
Block a user