@iyulab/flex-table 0.49.1 → 0.50.0
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 +24 -0
- package/README.md +9 -3
- package/dist/{flex-table-CpAhHipx.js → flex-table-B64ScsFY.js} +128 -45
- package/dist/flex-table.d.ts +25 -0
- package/dist/flex-table.js +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/skills/iyulab-flex-table/references/styling.md +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.50.0] - 2026-10-06
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Tab no longer traps the focus in the table.** Tab past the last cell (Shift+Tab before the first)
|
|
8
|
+
stayed on that cell, so keyboard focus could never leave the table (WCAG 2.1.2). Tab still walks the
|
|
9
|
+
cells; at either end it now moves on to the next (previous) control on the page.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **The header row is reachable by keyboard.** ArrowUp from the first row moves onto the column's header
|
|
14
|
+
cell; ArrowLeft / ArrowRight / Home / End move along the header and ArrowDown returns to the body. On a
|
|
15
|
+
header cell, Enter or Space sorts (Shift adds the column to the sort), Alt+ArrowDown or the context-menu
|
|
16
|
+
key opens the column menu, and Alt+ArrowLeft / Alt+ArrowRight resize the column. Escape from that menu
|
|
17
|
+
returns to the same header cell. An empty table keeps the header row reachable.
|
|
18
|
+
- Keyboard focus arriving on a table with nothing active activates the first cell, so the first arrow
|
|
19
|
+
key already moves and no Tab is spent entering.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **The column menu buttons are no longer Tab stops** (`tabindex="-1"`, like the row checkboxes) — the
|
|
24
|
+
table is one Tab stop and the header row reaches each column's menu. Pages that relied on tabbing to a
|
|
25
|
+
menu button reach it from the header row instead.
|
|
26
|
+
|
|
3
27
|
## [0.49.1] - 2026-10-06
|
|
4
28
|
|
|
5
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -437,8 +437,8 @@ package dependency; CSS custom properties are resolved at render time, not impor
|
|
|
437
437
|
|
|
438
438
|
| Key | Action |
|
|
439
439
|
|-----|--------|
|
|
440
|
-
| Arrow keys | Navigate cells |
|
|
441
|
-
| Tab / Shift+Tab | Move to next/previous cell |
|
|
440
|
+
| Arrow keys | Navigate cells (ArrowUp from the first row moves onto the header row) |
|
|
441
|
+
| Tab / Shift+Tab | Move to next/previous cell; past the last (before the first) cell, leave the table |
|
|
442
442
|
| Enter / F2 | Start editing (Enter on a non-editable cell fires `row-activate`) |
|
|
443
443
|
| Typing a printable character | Start editing an editable cell with that character |
|
|
444
444
|
| Escape | Cancel edit / clear selection / close the find panel |
|
|
@@ -455,9 +455,15 @@ package dependency; CSS custom properties are resolved at render time, not impor
|
|
|
455
455
|
| Ctrl+Shift+Z / Ctrl+Y | Redo |
|
|
456
456
|
| Alt+ArrowLeft / Alt+ArrowRight | Resize current column (±20px) |
|
|
457
457
|
| Ctrl+Click header | Select entire column |
|
|
458
|
+
| ArrowLeft / ArrowRight / Home / End (header row) | Move along the header; ArrowDown returns to the first row |
|
|
459
|
+
| Enter / Space (header row) | Sort the column (ascending → descending → none); with Shift, add it to the sort |
|
|
460
|
+
| Alt+ArrowDown or the context-menu key (header row) | Open the column menu |
|
|
458
461
|
| Enter / Space on a column menu button | Open the column menu |
|
|
459
462
|
| ArrowUp / ArrowDown / Home / End (column menu) | Move between menu items |
|
|
460
|
-
| Escape (column menu) | Close the menu and return focus to
|
|
463
|
+
| Escape (column menu) | Close the menu and return focus to where it was opened from |
|
|
464
|
+
|
|
465
|
+
The table is one Tab stop: keyboard focus arriving on it activates the first cell (the first header cell
|
|
466
|
+
when there are no rows), and the column menu buttons and row checkboxes are reached by keys, not Tab.
|
|
461
467
|
|
|
462
468
|
## Localization
|
|
463
469
|
|
|
@@ -159,6 +159,11 @@ var x = r`
|
|
|
159
159
|
|
|
160
160
|
.ft-header-cell.ft-sortable { cursor: pointer; }
|
|
161
161
|
.ft-header-cell.ft-sortable:hover { background: var(--ft-header-hover-bg); }
|
|
162
|
+
/* The header cell the keyboard is on (ArrowUp from the first row) — same ring as the active body cell. */
|
|
163
|
+
.ft-header-cell.ft-header-active {
|
|
164
|
+
outline: 2px solid var(--ft-active-color);
|
|
165
|
+
outline-offset: -2px;
|
|
166
|
+
}
|
|
162
167
|
|
|
163
168
|
.ft-header-cell.ft-header-align-center { justify-content: center; }
|
|
164
169
|
.ft-header-cell.ft-header-align-end { justify-content: flex-end; }
|
|
@@ -1887,7 +1892,9 @@ var K = {
|
|
|
1887
1892
|
lte: "≤"
|
|
1888
1893
|
}, q = 120, J = 40, Y = 20, X = 32, Z = 5, Ze = 200, Q = class extends n {
|
|
1889
1894
|
constructor(...e) {
|
|
1890
|
-
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = X, this._targetFloor = 0, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this.stylesheets = [], this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._baseStyleSheets = [], this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new oe(), this._editing = new se(), this._rowSelection = new A(), this._undo = new j(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._commentPopup = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, this._wasHeaderDrag = !1, this._wasRowDrag = !1, this._colDrag = null, this._colDragIndicatorLeft = null, this._fillDrag = null, this._rowDrag = null, this._rowDragIndicatorY = null, this._findState = null, this._columnWidths = /* @__PURE__ */ new Map(), this._hostResizeObserver = null, this._comments = /* @__PURE__ */ new Map(), this._isDragOver = !1, this._warnedUnconstrained = !1, this.
|
|
1895
|
+
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = X, this._targetFloor = 0, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this.stylesheets = [], this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._baseStyleSheets = [], this._activeCell = null, this._headerCol = null, this._editingCell = null, this._sortCriteria = [], this._selection = new oe(), this._editing = new se(), this._rowSelection = new A(), this._undo = new j(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._commentPopup = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, this._wasHeaderDrag = !1, this._wasRowDrag = !1, this._colDrag = null, this._colDragIndicatorLeft = null, this._fillDrag = null, this._rowDrag = null, this._rowDragIndicatorY = null, this._findState = null, this._columnWidths = /* @__PURE__ */ new Map(), this._hostResizeObserver = null, this._comments = /* @__PURE__ */ new Map(), this._isDragOver = !1, this._warnedUnconstrained = !1, this._onHostFocus = (e) => {
|
|
1896
|
+
e.composedPath()[0] !== this || this._activeCell || this._headerCol !== null || this.visibleColumns.length !== 0 && this.matches(":focus-visible") && (this._visibleRowCount > 0 ? (this._selection.setActive(0, 0), this._syncActiveCell()) : this._headerCol = 0);
|
|
1897
|
+
}, this._onCommentPopupOutsideClick = () => {
|
|
1891
1898
|
this._commitCommentPopup();
|
|
1892
1899
|
}, this._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map(), this._emptyFilterState = /* @__PURE__ */ new Map();
|
|
1893
1900
|
}
|
|
@@ -2418,10 +2425,10 @@ var K = {
|
|
|
2418
2425
|
};
|
|
2419
2426
|
}
|
|
2420
2427
|
connectedCallback() {
|
|
2421
|
-
super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this._onDragover = this._onDragover.bind(this), this._onDragleave = this._onDragleave.bind(this), this._onDrop = this._onDrop.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("contextmenu", this._onContextMenu), this.addEventListener("dragover", this._onDragover), this.addEventListener("dragleave", this._onDragleave), this.addEventListener("drop", this._onDrop), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
|
|
2428
|
+
super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this._onDragover = this._onDragover.bind(this), this._onDragleave = this._onDragleave.bind(this), this._onDrop = this._onDrop.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("focus", this._onHostFocus), this.addEventListener("contextmenu", this._onContextMenu), this.addEventListener("dragover", this._onDragover), this.addEventListener("dragleave", this._onDragleave), this.addEventListener("drop", this._onDrop), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
|
|
2422
2429
|
}
|
|
2423
2430
|
disconnectedCallback() {
|
|
2424
|
-
super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("mousedown", this._onCommentPopupOutsideClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
|
|
2431
|
+
super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("focus", this._onHostFocus), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("mousedown", this._onCommentPopupOutsideClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
|
|
2425
2432
|
}
|
|
2426
2433
|
firstUpdated() {
|
|
2427
2434
|
this._readDensityTokens(), this._measureViewport(), this.shadowRoot && Array.isArray(this.shadowRoot.adoptedStyleSheets) && (this._baseStyleSheets = [...this.shadowRoot.adoptedStyleSheets]), this._syncStylesheets();
|
|
@@ -2528,28 +2535,34 @@ var K = {
|
|
|
2528
2535
|
this._openFilterKey &&= null, this._headerMenu &&= null, this._bodyContextMenu &&= null;
|
|
2529
2536
|
}
|
|
2530
2537
|
_onContextMenu(e) {
|
|
2531
|
-
let t = e.composedPath().find((e) => e instanceof HTMLElement && e.classList.contains("ft-cell"));
|
|
2532
|
-
if (!
|
|
2538
|
+
let t = e.composedPath(), n = t.find((e) => e instanceof HTMLElement && e.classList.contains("ft-cell"));
|
|
2539
|
+
if (!n) {
|
|
2540
|
+
if (t[0] === this && this._headerCol !== null) {
|
|
2541
|
+
let t = this.visibleColumns[this._headerCol];
|
|
2542
|
+
t && (e.preventDefault(), this._openColumnMenu(t));
|
|
2543
|
+
}
|
|
2544
|
+
return;
|
|
2545
|
+
}
|
|
2533
2546
|
e.preventDefault();
|
|
2534
|
-
let
|
|
2535
|
-
if (!
|
|
2536
|
-
let
|
|
2537
|
-
if (
|
|
2538
|
-
let
|
|
2539
|
-
if (!
|
|
2540
|
-
let
|
|
2547
|
+
let r = n.parentElement;
|
|
2548
|
+
if (!r || !r.classList.contains("ft-row")) return;
|
|
2549
|
+
let i = parseInt(n.dataset.colIndex ?? "-1", 10), a = r.style.top, o = Math.round(parseInt(a, 10) / this.rowHeight);
|
|
2550
|
+
if (i < 0 || o < 0) return;
|
|
2551
|
+
let s = this._toDataIndex(o), c = this.visibleColumns[i];
|
|
2552
|
+
if (!c) return;
|
|
2553
|
+
let l = this._emit("context-menu", {
|
|
2541
2554
|
x: e.clientX,
|
|
2542
2555
|
y: e.clientY,
|
|
2543
|
-
row:
|
|
2544
|
-
col:
|
|
2545
|
-
key:
|
|
2546
|
-
value: this.data[
|
|
2547
|
-
rowData: this.data[
|
|
2556
|
+
row: s,
|
|
2557
|
+
col: i,
|
|
2558
|
+
key: c.key,
|
|
2559
|
+
value: this.data[s]?.[c.key],
|
|
2560
|
+
rowData: this.data[s]
|
|
2548
2561
|
}, { cancelable: !0 });
|
|
2549
|
-
this._cancelCommentPopup(), this.showContextMenu && !
|
|
2550
|
-
rowIndex:
|
|
2551
|
-
colIndex:
|
|
2552
|
-
dataIndex:
|
|
2562
|
+
this._cancelCommentPopup(), this.showContextMenu && !l.defaultPrevented && (this._bodyContextMenu = {
|
|
2563
|
+
rowIndex: o,
|
|
2564
|
+
colIndex: i,
|
|
2565
|
+
dataIndex: s,
|
|
2553
2566
|
x: e.clientX,
|
|
2554
2567
|
y: e.clientY
|
|
2555
2568
|
}, requestAnimationFrame(() => {
|
|
@@ -2775,7 +2788,7 @@ var K = {
|
|
|
2775
2788
|
this._autocompleteState = null, this._applyEdit(e), this._selection.moveDown(), this._syncActiveCell();
|
|
2776
2789
|
}
|
|
2777
2790
|
_syncActiveCell() {
|
|
2778
|
-
this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._scrollToActiveCell(), this._dispatchSelectionEvent();
|
|
2791
|
+
this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._activeCell && (this._headerCol = null), this._scrollToActiveCell(), this._dispatchSelectionEvent();
|
|
2779
2792
|
}
|
|
2780
2793
|
_onKeyDown(e) {
|
|
2781
2794
|
if (this._editing.current || this._openFilterKey && e.composedPath().some((e) => e instanceof Element && e.classList.contains("ft-filter-dropdown"))) return;
|
|
@@ -2789,7 +2802,22 @@ var K = {
|
|
|
2789
2802
|
"y"
|
|
2790
2803
|
].includes(t) && this._handleCtrlKey(e)) return;
|
|
2791
2804
|
}
|
|
2792
|
-
if (t.length !== 0 &&
|
|
2805
|
+
if (t.length !== 0 && (e.composedPath()[0] === this || e.ctrlKey || e.metaKey)) {
|
|
2806
|
+
if (this._headerCol !== null) {
|
|
2807
|
+
this._onHeaderKeyDown(e, t);
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2810
|
+
if (this._visibleRowCount === 0) {
|
|
2811
|
+
[
|
|
2812
|
+
"ArrowDown",
|
|
2813
|
+
"ArrowUp",
|
|
2814
|
+
"ArrowLeft",
|
|
2815
|
+
"ArrowRight",
|
|
2816
|
+
"Home",
|
|
2817
|
+
"End"
|
|
2818
|
+
].includes(e.key) && (e.preventDefault(), this._headerCol = 0);
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2793
2821
|
if ((e.key === "Enter" || e.key === "F2") && this._activeCell && !_(e)) {
|
|
2794
2822
|
e.preventDefault();
|
|
2795
2823
|
let n = t[this._activeCell.col];
|
|
@@ -2802,7 +2830,6 @@ var K = {
|
|
|
2802
2830
|
"ArrowUp",
|
|
2803
2831
|
"ArrowLeft",
|
|
2804
2832
|
"ArrowRight",
|
|
2805
|
-
"Tab",
|
|
2806
2833
|
"Home",
|
|
2807
2834
|
"End"
|
|
2808
2835
|
].includes(e.key)) {
|
|
@@ -2825,10 +2852,47 @@ var K = {
|
|
|
2825
2852
|
e && this._isCellEditable(e) && this._startEdit();
|
|
2826
2853
|
return;
|
|
2827
2854
|
}
|
|
2855
|
+
if (e.key === "ArrowUp" && !e.shiftKey && !e.altKey && this._activeCell?.row === 0) {
|
|
2856
|
+
e.preventDefault(), this._enterHeader(this._activeCell.col);
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2828
2859
|
this._handleNavigation(e) && (e.preventDefault(), this._syncActiveCell());
|
|
2829
2860
|
}
|
|
2830
2861
|
}
|
|
2831
2862
|
}
|
|
2863
|
+
_onHeaderKeyDown(e, t) {
|
|
2864
|
+
if (e.ctrlKey || e.metaKey) return;
|
|
2865
|
+
let n = Math.min(this._headerCol ?? 0, t.length - 1), r = t[n], i;
|
|
2866
|
+
switch (e.key) {
|
|
2867
|
+
case "ArrowLeft":
|
|
2868
|
+
case "ArrowRight":
|
|
2869
|
+
if (e.altKey) {
|
|
2870
|
+
e.preventDefault(), this._resizeColumnBy(r.key, e.key === "ArrowRight" ? Y : -20);
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
i = e.key === "ArrowLeft" ? Math.max(0, n - 1) : Math.min(t.length - 1, n + 1);
|
|
2874
|
+
break;
|
|
2875
|
+
case "Home":
|
|
2876
|
+
i = 0;
|
|
2877
|
+
break;
|
|
2878
|
+
case "End":
|
|
2879
|
+
i = t.length - 1;
|
|
2880
|
+
break;
|
|
2881
|
+
case "ArrowDown":
|
|
2882
|
+
e.preventDefault(), e.altKey ? this._openColumnMenu(r) : this._visibleRowCount > 0 && (this._selection.setActive(0, n), this._syncActiveCell());
|
|
2883
|
+
return;
|
|
2884
|
+
case "Enter":
|
|
2885
|
+
case " ":
|
|
2886
|
+
if (_(e)) return;
|
|
2887
|
+
e.preventDefault(), r.sortable !== !1 && this._toggleSort(r, e.shiftKey);
|
|
2888
|
+
return;
|
|
2889
|
+
default: return;
|
|
2890
|
+
}
|
|
2891
|
+
e.preventDefault(), this._headerCol = i, this._scrollColumnIntoView(i);
|
|
2892
|
+
}
|
|
2893
|
+
_enterHeader(e) {
|
|
2894
|
+
this._selection.clear(), this._syncActiveCell(), this._headerCol = e, this._scrollColumnIntoView(e);
|
|
2895
|
+
}
|
|
2832
2896
|
_handleCtrlKey(e) {
|
|
2833
2897
|
if (!(e.ctrlKey || e.metaKey) || e.altKey) return !1;
|
|
2834
2898
|
switch (e.key.toLowerCase()) {
|
|
@@ -2874,7 +2938,10 @@ var K = {
|
|
|
2874
2938
|
case "ArrowDown": return e.shiftKey ? this._selection.shiftMoveDown() : this._selection.moveDown(), !0;
|
|
2875
2939
|
case "ArrowLeft": return e.shiftKey ? this._selection.shiftMoveLeft() : this._selection.moveLeft(), !0;
|
|
2876
2940
|
case "ArrowRight": return e.shiftKey ? this._selection.shiftMoveRight() : this._selection.moveRight(), !0;
|
|
2877
|
-
case "Tab":
|
|
2941
|
+
case "Tab": {
|
|
2942
|
+
let t = this._selection.activeCell, n = e.shiftKey ? this._selection.movePrev() : this._selection.moveNext();
|
|
2943
|
+
return !(t && n && t.row === n.row && t.col === n.col);
|
|
2944
|
+
}
|
|
2878
2945
|
case "Home": return e.ctrlKey ? this._selection.moveToStart() : this._selection.moveToRowStart(), !0;
|
|
2879
2946
|
case "End": return e.ctrlKey ? this._selection.moveToEnd() : this._selection.moveToRowEnd(), !0;
|
|
2880
2947
|
case "Escape": return this._findState ? (this._closeFindPanel(), !0) : (this._selection.clear(), !0);
|
|
@@ -3102,24 +3169,29 @@ var K = {
|
|
|
3102
3169
|
_scrollToActiveCell() {
|
|
3103
3170
|
if (!this._activeCell) return;
|
|
3104
3171
|
let e = this._activeCell.row * this.rowHeight + this.headerHeight, t = e + this.rowHeight;
|
|
3105
|
-
this._activeCell.row < this._frozenRowCount || (e < this.scrollTop + this.headerHeight + this.frozenRowsHeight ? this.scrollTop = e - this.headerHeight - this.frozenRowsHeight : t > this.scrollTop + this.clientHeight && (this.scrollTop = t - this.clientHeight));
|
|
3106
|
-
|
|
3107
|
-
|
|
3172
|
+
this._activeCell.row < this._frozenRowCount || (e < this.scrollTop + this.headerHeight + this.frozenRowsHeight ? this.scrollTop = e - this.headerHeight - this.frozenRowsHeight : t > this.scrollTop + this.clientHeight && (this.scrollTop = t - this.clientHeight)), this._scrollColumnIntoView(this._activeCell.col);
|
|
3173
|
+
}
|
|
3174
|
+
_scrollColumnIntoView(e) {
|
|
3175
|
+
let t = this.visibleColumns, n = this._colLeftOffsets[e] ?? 0, r = n + this._getColWidth(t[e]);
|
|
3176
|
+
n < this.scrollLeft ? this.scrollLeft = n : r > this.scrollLeft + this.clientWidth && (this.scrollLeft = r - this.clientWidth);
|
|
3108
3177
|
}
|
|
3109
3178
|
_dispatchSelectionEvent() {
|
|
3110
3179
|
this._emit("cell-select", this._activeCell ? { ...this._activeCell } : null);
|
|
3111
3180
|
}
|
|
3112
|
-
_onHeaderClick(
|
|
3181
|
+
_onHeaderClick(e, t) {
|
|
3113
3182
|
if (this._wasHeaderDrag) {
|
|
3114
3183
|
this._wasHeaderDrag = !1;
|
|
3115
3184
|
return;
|
|
3116
3185
|
}
|
|
3117
|
-
let
|
|
3118
|
-
if (
|
|
3119
|
-
this._selectColumn(
|
|
3186
|
+
let n = this.visibleColumns.indexOf(t);
|
|
3187
|
+
if (e.ctrlKey || e.metaKey) {
|
|
3188
|
+
this._selectColumn(n);
|
|
3120
3189
|
return;
|
|
3121
3190
|
}
|
|
3122
|
-
|
|
3191
|
+
t.sortable !== !1 && this._toggleSort(t, e.shiftKey);
|
|
3192
|
+
}
|
|
3193
|
+
_toggleSort(t, n) {
|
|
3194
|
+
this._sortCriteria = e(this._sortCriteria, t.key, n), this.dataMode !== "server" && this._recomputeView(), this.requestUpdate(), this._emit("sort-change", { criteria: [...this._sortCriteria] });
|
|
3123
3195
|
}
|
|
3124
3196
|
_selectColumn(e) {
|
|
3125
3197
|
let t = this._visibleRowCount;
|
|
@@ -3158,7 +3230,8 @@ var K = {
|
|
|
3158
3230
|
n ? "ft-sortable" : "",
|
|
3159
3231
|
u ? "ft-pinned" : "",
|
|
3160
3232
|
d === "center" ? "ft-header-align-center" : "",
|
|
3161
|
-
d === "end" ? "ft-header-align-end" : ""
|
|
3233
|
+
d === "end" ? "ft-header-align-end" : "",
|
|
3234
|
+
this._headerCol === t ? "ft-header-active" : ""
|
|
3162
3235
|
].filter(Boolean).join(" "), p = n ? r ? r.direction === "asc" ? "ascending" : "descending" : "none" : void 0, m = this._getColWidth(e), h = this.headerHeight, g = this._colLeftOffsets[t] ?? 0, _;
|
|
3163
3236
|
_ = c ? `position: absolute; top: 0; left: ${this._scrollLeft + this._getPinnedLeft(t)}px; width: ${m}px; height: ${h}px; z-index: 4;` : l ? `position: absolute; top: 0; left: ${this._getPinnedRightLeft(t)}px; width: ${m}px; height: ${h}px; z-index: 4;` : `left: ${g}px; width: ${m}px; height: ${h}px;`;
|
|
3164
3237
|
let v = this._colDrag?.active && this._colDrag.colIndex === t, y = [...f.split(" "), v ? "ft-col-dragging" : ""].filter(Boolean).join(" "), b = this.columns, x = b.findIndex((t) => t.key === e.key), S = [];
|
|
@@ -3175,7 +3248,7 @@ var K = {
|
|
|
3175
3248
|
@mousedown=${(n) => this._onHeaderMouseDown(n, e, t)}
|
|
3176
3249
|
@click=${n ? (t) => this._onHeaderClick(t, e) : void 0}>
|
|
3177
3250
|
${C ? i`
|
|
3178
|
-
<button class="ft-hidden-col-indicator"
|
|
3251
|
+
<button class="ft-hidden-col-indicator" tabindex="-1"
|
|
3179
3252
|
title=${k("showHiddenColumns")}
|
|
3180
3253
|
@click=${(t) => {
|
|
3181
3254
|
t.stopPropagation(), this._showHiddenBefore(e);
|
|
@@ -3186,6 +3259,7 @@ var K = {
|
|
|
3186
3259
|
${o >= 0 ? i`<span class="ft-sort-order">${o + 1}</span>` : ""}
|
|
3187
3260
|
<button class="ft-column-menu-btn ${s ? "ft-filter-active" : ""}"
|
|
3188
3261
|
type="button"
|
|
3262
|
+
tabindex="-1"
|
|
3189
3263
|
data-key=${e.key}
|
|
3190
3264
|
title=${k("columnMenu")}
|
|
3191
3265
|
aria-label=${k("columnMenuFor", { header: e.label })}
|
|
@@ -3232,12 +3306,15 @@ var K = {
|
|
|
3232
3306
|
this._headerMenu = null;
|
|
3233
3307
|
return;
|
|
3234
3308
|
}
|
|
3235
|
-
|
|
3309
|
+
this._openColumnMenu(t, e.currentTarget);
|
|
3310
|
+
}
|
|
3311
|
+
_openColumnMenu(e, t = this._columnMenuButton(e.key)) {
|
|
3312
|
+
let n = t?.getBoundingClientRect();
|
|
3236
3313
|
this._openFilterKey = null, this._headerMenu = {
|
|
3237
|
-
key:
|
|
3238
|
-
x: n
|
|
3239
|
-
y: n
|
|
3240
|
-
hiddenNeighbors: this._hiddenNeighbors(
|
|
3314
|
+
key: e.key,
|
|
3315
|
+
x: n?.left ?? 0,
|
|
3316
|
+
y: n?.bottom ?? 0,
|
|
3317
|
+
hiddenNeighbors: this._hiddenNeighbors(e)
|
|
3241
3318
|
}, requestAnimationFrame(() => {
|
|
3242
3319
|
document.addEventListener("click", this._onDocumentClick, { once: !0 });
|
|
3243
3320
|
}), this.updateComplete.then(() => this._menuItems()[0]?.focus());
|
|
@@ -3251,7 +3328,7 @@ var K = {
|
|
|
3251
3328
|
}
|
|
3252
3329
|
_closeHeaderMenu(e) {
|
|
3253
3330
|
let t = this._headerMenu?.key;
|
|
3254
|
-
this._headerMenu = null, e && t && this._columnMenuButton(t)?.focus();
|
|
3331
|
+
this._headerMenu = null, e && t && (this._headerCol === null ? this._columnMenuButton(t)?.focus() : this.focus());
|
|
3255
3332
|
}
|
|
3256
3333
|
_onHeaderMenuKeydown(e) {
|
|
3257
3334
|
this._onMenuKeydown(e, ".ft-header-menu", (e) => this._closeHeaderMenu(e));
|
|
@@ -3427,9 +3504,15 @@ var K = {
|
|
|
3427
3504
|
}
|
|
3428
3505
|
_closeFilterDropdown(e = !0) {
|
|
3429
3506
|
let t = this._openFilterKey;
|
|
3430
|
-
this._openFilterKey = null, e && t !== null
|
|
3431
|
-
|
|
3432
|
-
|
|
3507
|
+
if (this._openFilterKey = null, e && t !== null) {
|
|
3508
|
+
if (this._headerCol !== null) {
|
|
3509
|
+
this.focus();
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
this.updateComplete.then(() => {
|
|
3513
|
+
[...this.shadowRoot?.querySelectorAll(".ft-column-menu-btn") ?? []].find((e) => e.dataset.key === t)?.focus();
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3433
3516
|
}
|
|
3434
3517
|
_onFilterDialogKeydown(e) {
|
|
3435
3518
|
if (e.key !== "Tab") return;
|
|
@@ -4486,7 +4569,7 @@ G([s({ type: Array })], Q.prototype, "columns", void 0), G([s({
|
|
|
4486
4569
|
})], Q.prototype, "footerData", void 0), G([s({ attribute: !1 })], Q.prototype, "stylesheets", void 0), G([s({
|
|
4487
4570
|
type: Number,
|
|
4488
4571
|
attribute: "max-undo-size"
|
|
4489
|
-
})], Q.prototype, "maxUndoSize", null), G([c()], Q.prototype, "_scrollTop", void 0), G([c()], Q.prototype, "_scrollLeft", void 0), G([c()], Q.prototype, "_viewportHeight", void 0), G([c()], Q.prototype, "_viewportWidth", void 0), G([c()], Q.prototype, "_activeCell", void 0), G([c()], Q.prototype, "_editingCell", void 0), G([c()], Q.prototype, "_sortCriteria", void 0), G([c()], Q.prototype, "_openFilterKey", void 0), G([c()], Q.prototype, "_rowSelectionVersion", void 0), G([c()], Q.prototype, "_autocompleteState", void 0), G([c()], Q.prototype, "_headerMenu", void 0), G([c()], Q.prototype, "_bodyContextMenu", void 0), G([c()], Q.prototype, "_commentPopup", void 0), G([c()], Q.prototype, "_isDragOver", void 0), Q = G([o("flex-table")], Q);
|
|
4572
|
+
})], Q.prototype, "maxUndoSize", null), G([c()], Q.prototype, "_scrollTop", void 0), G([c()], Q.prototype, "_scrollLeft", void 0), G([c()], Q.prototype, "_viewportHeight", void 0), G([c()], Q.prototype, "_viewportWidth", void 0), G([c()], Q.prototype, "_activeCell", void 0), G([c()], Q.prototype, "_headerCol", void 0), G([c()], Q.prototype, "_editingCell", void 0), G([c()], Q.prototype, "_sortCriteria", void 0), G([c()], Q.prototype, "_openFilterKey", void 0), G([c()], Q.prototype, "_rowSelectionVersion", void 0), G([c()], Q.prototype, "_autocompleteState", void 0), G([c()], Q.prototype, "_headerMenu", void 0), G([c()], Q.prototype, "_bodyContextMenu", void 0), G([c()], Q.prototype, "_commentPopup", void 0), G([c()], Q.prototype, "_isDragOver", void 0), Q = G([o("flex-table")], Q);
|
|
4490
4573
|
function Qe(e, t) {
|
|
4491
4574
|
if (t) {
|
|
4492
4575
|
let t = fe(e);
|
package/dist/flex-table.d.ts
CHANGED
|
@@ -108,6 +108,11 @@ export declare class FlexTable extends LitElement {
|
|
|
108
108
|
/** The grid's own compiled styles, captured once so `stylesheets` merges without dropping them. */
|
|
109
109
|
private _baseStyleSheets;
|
|
110
110
|
private _activeCell;
|
|
111
|
+
/**
|
|
112
|
+
* The header cell the keyboard is on — the header row sits above the first body row (ArrowUp from
|
|
113
|
+
* it). Exclusive with an active body cell: entering one leaves the other.
|
|
114
|
+
*/
|
|
115
|
+
private _headerCol;
|
|
111
116
|
private _editingCell;
|
|
112
117
|
private _sortCriteria;
|
|
113
118
|
private _selection;
|
|
@@ -394,6 +399,20 @@ export declare class FlexTable extends LitElement {
|
|
|
394
399
|
private _selectAutocompleteCandidate;
|
|
395
400
|
private _syncActiveCell;
|
|
396
401
|
private _onKeyDown;
|
|
402
|
+
/**
|
|
403
|
+
* The keyboard on the header row: arrows / Home / End move along it, ArrowDown returns to the body,
|
|
404
|
+
* Enter or Space sorts (Shift adds to the sort), Alt+ArrowDown opens the column menu, Alt+Arrow
|
|
405
|
+
* resizes. Tab leaves the grid.
|
|
406
|
+
*/
|
|
407
|
+
private _onHeaderKeyDown;
|
|
408
|
+
/** Move the keyboard from the body onto the header cell of visible column `colIndex`. */
|
|
409
|
+
private _enterHeader;
|
|
410
|
+
/**
|
|
411
|
+
* Keyboard focus arriving on a grid with nothing active places it on the first cell (the first header
|
|
412
|
+
* cell when the body is empty), so the first arrow already moves and Tab is not spent entering. A
|
|
413
|
+
* pointer focus places the cell it pressed instead.
|
|
414
|
+
*/
|
|
415
|
+
private _onHostFocus;
|
|
397
416
|
private _handleCtrlKey;
|
|
398
417
|
private _handleAltKey;
|
|
399
418
|
/** Widen (positive) or narrow (negative) a visible column by `delta` px, never below its minimum. */
|
|
@@ -423,8 +442,12 @@ export declare class FlexTable extends LitElement {
|
|
|
423
442
|
private _clearRanges;
|
|
424
443
|
private _clearRange;
|
|
425
444
|
private _scrollToActiveCell;
|
|
445
|
+
/** Scroll horizontally so the visible column at `colIndex` is in view — cached column offsets. */
|
|
446
|
+
private _scrollColumnIntoView;
|
|
426
447
|
private _dispatchSelectionEvent;
|
|
427
448
|
private _onHeaderClick;
|
|
449
|
+
/** Cycle `col`'s sort (asc → desc → none); `multi` adds it to the existing criteria (Shift). */
|
|
450
|
+
private _toggleSort;
|
|
428
451
|
private _selectColumn;
|
|
429
452
|
/** Public API: select an entire column by index. */
|
|
430
453
|
selectColumn(colIndex: number): void;
|
|
@@ -456,6 +479,8 @@ export declare class FlexTable extends LitElement {
|
|
|
456
479
|
* and resizing without dragging the 6px handle (WCAG 2.2 SC 2.5.7 / 2.5.8).
|
|
457
480
|
*/
|
|
458
481
|
private _onColumnMenuBtnClick;
|
|
482
|
+
/** Open `col`'s column menu under `anchor` (its menu button by default) and focus the first item. */
|
|
483
|
+
private _openColumnMenu;
|
|
459
484
|
private _menuItems;
|
|
460
485
|
private _columnMenuButton;
|
|
461
486
|
private _closeHeaderMenu;
|
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-B64ScsFY.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-B64ScsFY.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";
|
package/package.json
CHANGED
|
@@ -68,7 +68,10 @@ flex-table {
|
|
|
68
68
|
|
|
69
69
|
| Key | Action |
|
|
70
70
|
|---|---|
|
|
71
|
-
| Arrows / Tab / Shift+Tab | Move between cells |
|
|
71
|
+
| Arrows / Tab / Shift+Tab | Move between cells; Tab past the last (Shift+Tab before the first) leaves the table |
|
|
72
|
+
| ArrowUp on the first row | Move onto the header row (arrows / Home / End along it, ArrowDown back) |
|
|
73
|
+
| Enter / Space on a header cell | Sort (Shift adds to the sort) |
|
|
74
|
+
| Alt+ArrowDown or context-menu key on a header cell | Open the column menu |
|
|
72
75
|
| Home / End, Ctrl+Home / Ctrl+End | Row start/end, table start/end |
|
|
73
76
|
| Shift+Arrow, Shift+Click | Extend range selection |
|
|
74
77
|
| Shift+Space | Select / deselect the active cell's row (`selectable`; row checkboxes are not Tab stops) |
|
|
@@ -84,6 +87,9 @@ flex-table {
|
|
|
84
87
|
| Alt+ArrowLeft / Alt+ArrowRight | Resize current column |
|
|
85
88
|
| Enter / Space on a column menu button | Open the column menu (arrows, Home/End navigate; Escape closes) |
|
|
86
89
|
|
|
90
|
+
The table is one Tab stop — keyboard focus arriving on it activates the first cell; the column menu
|
|
91
|
+
buttons are not Tab stops (the header row reaches them).
|
|
92
|
+
|
|
87
93
|
Ctrl also matches Cmd on macOS. Editing shortcuts are ignored when `editable` is `false`.
|
|
88
94
|
|
|
89
95
|
## Localization
|