@iyulab/flex-table 0.40.2 → 0.40.3
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.
- package/CHANGELOG.md +12 -0
- package/README.md +2 -1
- package/dist/{flex-table-CbIsTvod.js → flex-table-DvETrA1w.js} +10 -7
- package/dist/flex-table.js +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.40.3] - 2026-09-30
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Screen readers get the position of a row and a cell in the whole table, not in the rendered part.**
|
|
8
|
+
The grid renders only the visible rows and columns, so without indices a screen reader announced the
|
|
9
|
+
first rendered row as row 1 after scrolling. Rows now carry `aria-rowindex` and cells, column headers
|
|
10
|
+
and footer cells `aria-colindex` (1-based, in display order). `aria-rowcount` now counts the header
|
|
11
|
+
row and the footer row as the ARIA grid pattern defines it (it counted data rows only, so it is one or
|
|
12
|
+
two higher than before). The footer row's cells now have the grid cell role — the footer was a row
|
|
13
|
+
without cells.
|
|
14
|
+
|
|
3
15
|
## [0.40.2] - 2026-09-30
|
|
4
16
|
|
|
5
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ npm install @iyulab/flex-table
|
|
|
67
67
|
- **Data Mode** — Client-side or server-side sorting/filtering (`dataMode`)
|
|
68
68
|
- **Context Menu** — `context-menu` event for custom right-click menus
|
|
69
69
|
- **React Wrapper** — `@iyulab/flex-table/react` subpath for idiomatic React usage
|
|
70
|
-
- **ARIA** — `role="grid"`, `aria-sort`, `aria-selected`, `aria-readonly`, `aria-invalid`, `aria-rowcount`, `aria-colcount`
|
|
70
|
+
- **ARIA** — `role="grid"`, `aria-sort`, `aria-selected`, `aria-readonly`, `aria-invalid`, `aria-rowcount`, `aria-colcount`, `aria-rowindex`, `aria-colindex`
|
|
71
71
|
|
|
72
72
|
## Sizing
|
|
73
73
|
|
|
@@ -471,6 +471,7 @@ conformance claim for the success criteria it does not list.
|
|
|
471
471
|
| SC 2.5.8 Target Size (Minimum) | Sortable headers, column menu buttons, the open column menu, the open filter dropdown (text and number), the find/replace bar, the cell context menu and row selection checkboxes are at least 24×24 CSS px or meet the spacing exception (24px between centers, counting the neighbouring resize handles), and are actually hit at that position. Two small targets use the equivalent-control exception: the 6px column resize handle (every resize is also in the column menu) and the hidden-column marker (its column menu offers **Show: …**) | `tests/browser/target-size.browser.test.ts` (real Chromium) |
|
|
472
472
|
| SC 2.1.1 Keyboard (pointer-cursor check) | Nothing the grid renders shows a pointer cursor without being an interactive element. Sorting by header click also has a keyboard path — the column menu's **Sort ascending** / **Sort descending** (the check alone cannot see that, because the header cell wraps the menu button) | `tests/browser/target-size.browser.test.ts` · `src/flex-table.test.ts` |
|
|
473
473
|
| SC 2.5.7 Dragging Movements | Resizing never requires a drag — the column menu's **Auto-fit width**, **Wider** and **Narrower** are single clicks | `tests/browser/column-menu.browser.test.ts` |
|
|
474
|
+
| SC 1.3.1 Info and Relationships (virtualized grid) | Only the visible rows and columns are in the DOM, so every row carries `aria-rowindex` and every cell `aria-colindex` (1-based, in display order), and the grid's `aria-rowcount` / `aria-colcount` give the full size — the header row is row 1, data rows start at 2, and the footer row (if any) is last. A screen reader announces "row 621 of 10001" after scrolling instead of counting the rows that happen to be rendered. The footer row's cells are grid cells | `tests/browser/aria-grid-index.browser.test.ts` |
|
|
474
475
|
|
|
475
476
|
Not yet measured: the boolean and date filter dropdowns and the comment popup. Color contrast comes
|
|
476
477
|
from the `@iyulab/components` tokens this package reads.
|
|
@@ -2291,7 +2291,7 @@ var q = {
|
|
|
2291
2291
|
}
|
|
2292
2292
|
updated(e) {
|
|
2293
2293
|
this._focusEditor(), this._adjustFilterDropdown(), e.has("_headerMenu") && this._keepMenuInView(".ft-header-menu"), e.has("_bodyContextMenu") && this._bodyContextMenu && (this._keepMenuInView(".ft-body-context-menu"), this.shadowRoot?.querySelector(".ft-body-context-menu [role=\"menuitem\"]")?.focus()), e.has("stylesheets") && this._syncStylesheets();
|
|
2294
|
-
let t = String(this._visibleRowCount), n = String(this.visibleColumns.length);
|
|
2294
|
+
let t = String(1 + this._visibleRowCount + +!!this.footerData), n = String(this.visibleColumns.length);
|
|
2295
2295
|
if (this.getAttribute("aria-rowcount") !== t && this.setAttribute("aria-rowcount", t), this.getAttribute("aria-colcount") !== n && this.setAttribute("aria-colcount", n), this.loading ? this.getAttribute("aria-busy") !== "true" && this.setAttribute("aria-busy", "true") : this.hasAttribute("aria-busy") && this.removeAttribute("aria-busy"), e.has("_commentPopup") && this._commentPopup) {
|
|
2296
2296
|
let e = this.shadowRoot?.querySelector(".ft-comment-popup textarea");
|
|
2297
2297
|
e && (e.value = this.getComment(this._commentPopup.dataIndex, this._commentPopup.colKey) ?? "", e.focus(), e.select());
|
|
@@ -2992,6 +2992,7 @@ var q = {
|
|
|
2992
2992
|
return i`
|
|
2993
2993
|
<div class=${y}
|
|
2994
2994
|
role="columnheader"
|
|
2995
|
+
aria-colindex=${t + 1}
|
|
2995
2996
|
data-col-index=${t}
|
|
2996
2997
|
style=${_}
|
|
2997
2998
|
aria-sort=${p ?? a}
|
|
@@ -4007,7 +4008,7 @@ var q = {
|
|
|
4007
4008
|
let e = this.data.length === 0 ? this.emptyMessage : this.noMatchingMessage;
|
|
4008
4009
|
return i`
|
|
4009
4010
|
${n}
|
|
4010
|
-
<div class="ft-header" role="row" style="width: ${o}px; height: ${r}px;">
|
|
4011
|
+
<div class="ft-header" role="row" aria-rowindex="1" style="width: ${o}px; height: ${r}px;">
|
|
4011
4012
|
${f}${p}
|
|
4012
4013
|
${m}
|
|
4013
4014
|
${h}
|
|
@@ -4022,7 +4023,7 @@ var q = {
|
|
|
4022
4023
|
${t}
|
|
4023
4024
|
${n}
|
|
4024
4025
|
${this._renderFindPanel()}
|
|
4025
|
-
<div class="ft-header" role="row" style="width: ${o}px; height: ${r}px;">
|
|
4026
|
+
<div class="ft-header" role="row" aria-rowindex="1" style="width: ${o}px; height: ${r}px;">
|
|
4026
4027
|
${f}${p}
|
|
4027
4028
|
${m}
|
|
4028
4029
|
${h}
|
|
@@ -4069,19 +4070,19 @@ var q = {
|
|
|
4069
4070
|
for (let e of n) {
|
|
4070
4071
|
let t = r[e], n = this._getColWidth(t), o = t.pinned === "right" ? `position: absolute; top: 0; left: ${this._getPinnedRightLeft(e)}px; width: ${n}px; height: ${a}px; z-index: 2;` : `position: absolute; top: 0; left: ${s + this._getPinnedLeft(e)}px; width: ${n}px; height: ${a}px; z-index: 2;`;
|
|
4071
4072
|
d.push(i`
|
|
4072
|
-
<div class="ft-footer-cell ft-pinned" style=${o}>
|
|
4073
|
+
<div class="ft-footer-cell ft-pinned" role="gridcell" aria-colindex=${e + 1} style=${o}>
|
|
4073
4074
|
${this.footerData[t.key] ?? ""}</div>
|
|
4074
4075
|
`);
|
|
4075
4076
|
}
|
|
4076
4077
|
for (let n = e; n < t; n++) {
|
|
4077
4078
|
let e = r[n], t = this._getColWidth(e), o = this._colLeftOffsets[n] ?? 0, c = e.pinned === "left", l = e.pinned === "right", u = c || l, f;
|
|
4078
4079
|
f = c ? `position: absolute; top: 0; left: ${s + this._getPinnedLeft(n)}px; width: ${t}px; height: ${a}px; z-index: 2;` : l ? `position: absolute; top: 0; right: ${-s + this._getPinnedRight(n)}px; width: ${t}px; height: ${a}px; z-index: 2;` : `left: ${o}px; width: ${t}px; height: ${a}px;`, d.push(i`
|
|
4079
|
-
<div class="ft-footer-cell ${u ? "ft-pinned" : ""}" style=${f}>
|
|
4080
|
+
<div class="ft-footer-cell ${u ? "ft-pinned" : ""}" role="gridcell" aria-colindex=${n + 1} style=${f}>
|
|
4080
4081
|
${this.footerData[e.key] ?? ""}</div>
|
|
4081
4082
|
`);
|
|
4082
4083
|
}
|
|
4083
4084
|
return i`
|
|
4084
|
-
<div class="ft-footer" role="row" style="width: ${o}px; height: ${a}px;">
|
|
4085
|
+
<div class="ft-footer" role="row" aria-rowindex=${this._visibleRowCount + 2} style="width: ${o}px; height: ${a}px;">
|
|
4085
4086
|
${l}${u}
|
|
4086
4087
|
${d}
|
|
4087
4088
|
</div>
|
|
@@ -4107,7 +4108,7 @@ var q = {
|
|
|
4107
4108
|
for (let t of r) y.push(this._renderCell(c, o[t], e, t));
|
|
4108
4109
|
for (let r = t; r < n; r++) y.push(this._renderCell(c, o[r], e, r));
|
|
4109
4110
|
return i`
|
|
4110
|
-
<div class="ft-row ${f} ${p ? "ft-row-selected" : ""}" role="row"
|
|
4111
|
+
<div class="ft-row ${f} ${p ? "ft-row-selected" : ""}" role="row" aria-rowindex=${e + 2}
|
|
4111
4112
|
style="top: ${l}px; height: ${u}px; width: ${d}px;">
|
|
4112
4113
|
${g}${v}
|
|
4113
4114
|
${y}
|
|
@@ -4126,6 +4127,7 @@ var q = {
|
|
|
4126
4127
|
}
|
|
4127
4128
|
if (s) return i`
|
|
4128
4129
|
<div class="ft-cell ft-editing ft-active ${d ? "ft-pinned" : ""}" role="gridcell"
|
|
4130
|
+
aria-colindex=${r + 1}
|
|
4129
4131
|
data-col-index=${r}
|
|
4130
4132
|
aria-selected="true"
|
|
4131
4133
|
aria-readonly=${g ? "true" : a}
|
|
@@ -4146,6 +4148,7 @@ var q = {
|
|
|
4146
4148
|
return i`
|
|
4147
4149
|
<div class=${E ? C + " ft-has-comment" : C}
|
|
4148
4150
|
role="gridcell"
|
|
4151
|
+
aria-colindex=${r + 1}
|
|
4149
4152
|
data-col-index=${r}
|
|
4150
4153
|
aria-selected=${_ ? "true" : "false"}
|
|
4151
4154
|
aria-readonly=${g ? "true" : a}
|
package/dist/flex-table.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-
|
|
1
|
+
import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-DvETrA1w.js";
|
|
2
2
|
export { o as FlexTable, e as RowSelectionState, t as UndoStack, n as effectiveAlign, i as exportData, r as flexTableLocale, a as renderCell };
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./flex-table-
|
|
1
|
+
import { t as e } from "./flex-table-DvETrA1w.js";
|
|
2
2
|
import { i as t, t as n } from "./query-Dw4iO0ir.js";
|
|
3
3
|
import { t as r } from "./view-DiLr-TdY.js";
|
|
4
4
|
import i, { useCallback as a, useEffect as o, useMemo as s, useRef as c, useState as l } from "react";
|