@iyulab/flex-table 0.49.0 → 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 +34 -0
- package/README.md +10 -3
- package/dist/{flex-table-BsxF9Q3O.js → flex-table-B64ScsFY.js} +153 -52
- package/dist/flex-table.d.ts +37 -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,39 @@
|
|
|
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
|
+
|
|
27
|
+
## [0.49.1] - 2026-10-06
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **The column filter is a dialog with a keyboard contract.** It is announced as a dialog named for its
|
|
32
|
+
column ("Filter Customer"); Tab and Shift+Tab stay inside it (it floats over the table, so focus that
|
|
33
|
+
left it would leave it open behind the next control); Escape closes it and returns focus to that
|
|
34
|
+
column's menu button — before, focus dropped to the page. A click outside still closes it without
|
|
35
|
+
moving focus.
|
|
36
|
+
|
|
3
37
|
## [0.49.0] - 2026-10-06
|
|
4
38
|
|
|
5
39
|
### Added
|
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
|
|
|
@@ -519,6 +525,7 @@ conformance claim for the success criteria it does not list.
|
|
|
519
525
|
|---|---|---|
|
|
520
526
|
| 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) |
|
|
521
527
|
| 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` |
|
|
528
|
+
| SC 2.4.3 Focus Order · SC 2.1.2 No Keyboard Trap | The column filter is a dialog named for its column: opening it from the column menu moves focus into it, Tab and Shift+Tab cycle inside it, and Escape closes it and returns focus to that column's menu button (Escape is the way out) | `tests/browser/column-menu.browser.test.ts` |
|
|
522
529
|
| 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` |
|
|
523
530
|
| 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` |
|
|
524
531
|
|
|
@@ -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,8 @@ 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"
|
|
3263
|
+
data-key=${e.key}
|
|
3189
3264
|
title=${k("columnMenu")}
|
|
3190
3265
|
aria-label=${k("columnMenuFor", { header: e.label })}
|
|
3191
3266
|
aria-haspopup="menu"
|
|
@@ -3231,12 +3306,15 @@ var K = {
|
|
|
3231
3306
|
this._headerMenu = null;
|
|
3232
3307
|
return;
|
|
3233
3308
|
}
|
|
3234
|
-
|
|
3309
|
+
this._openColumnMenu(t, e.currentTarget);
|
|
3310
|
+
}
|
|
3311
|
+
_openColumnMenu(e, t = this._columnMenuButton(e.key)) {
|
|
3312
|
+
let n = t?.getBoundingClientRect();
|
|
3235
3313
|
this._openFilterKey = null, this._headerMenu = {
|
|
3236
|
-
key:
|
|
3237
|
-
x: n
|
|
3238
|
-
y: n
|
|
3239
|
-
hiddenNeighbors: this._hiddenNeighbors(
|
|
3314
|
+
key: e.key,
|
|
3315
|
+
x: n?.left ?? 0,
|
|
3316
|
+
y: n?.bottom ?? 0,
|
|
3317
|
+
hiddenNeighbors: this._hiddenNeighbors(e)
|
|
3240
3318
|
}, requestAnimationFrame(() => {
|
|
3241
3319
|
document.addEventListener("click", this._onDocumentClick, { once: !0 });
|
|
3242
3320
|
}), this.updateComplete.then(() => this._menuItems()[0]?.focus());
|
|
@@ -3250,7 +3328,7 @@ var K = {
|
|
|
3250
3328
|
}
|
|
3251
3329
|
_closeHeaderMenu(e) {
|
|
3252
3330
|
let t = this._headerMenu?.key;
|
|
3253
|
-
this._headerMenu = null, e && t && this._columnMenuButton(t)?.focus();
|
|
3331
|
+
this._headerMenu = null, e && t && (this._headerCol === null ? this._columnMenuButton(t)?.focus() : this.focus());
|
|
3254
3332
|
}
|
|
3255
3333
|
_onHeaderMenuKeydown(e) {
|
|
3256
3334
|
this._onMenuKeydown(e, ".ft-header-menu", (e) => this._closeHeaderMenu(e));
|
|
@@ -3424,11 +3502,34 @@ var K = {
|
|
|
3424
3502
|
let s = Math.max(4, Math.min(n.left, i - r.width - 4));
|
|
3425
3503
|
e.style.left = `${s}px`, e.style.top = `${o}px`;
|
|
3426
3504
|
}
|
|
3505
|
+
_closeFilterDropdown(e = !0) {
|
|
3506
|
+
let t = this._openFilterKey;
|
|
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
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
_onFilterDialogKeydown(e) {
|
|
3518
|
+
if (e.key !== "Tab") return;
|
|
3519
|
+
let t = [...e.currentTarget.querySelectorAll("input, select, textarea, button, u-date-picker")].filter((e) => !e.disabled && e.getClientRects().length > 0);
|
|
3520
|
+
if (t.length === 0) return;
|
|
3521
|
+
let n = e.composedPath(), r = t.findIndex((e) => n.includes(e)), i = t.length - 1;
|
|
3522
|
+
e.shiftKey && r <= 0 ? (e.preventDefault(), t[i].focus()) : !e.shiftKey && (r === i || r === -1) && (e.preventDefault(), t[0].focus());
|
|
3523
|
+
}
|
|
3427
3524
|
_renderFilterDropdown(e) {
|
|
3428
3525
|
let t = e.type ?? "text";
|
|
3429
3526
|
return i`
|
|
3430
|
-
<div class="ft-filter-dropdown" role="
|
|
3431
|
-
@click=${(e) => e.stopPropagation()}
|
|
3527
|
+
<div class="ft-filter-dropdown" role="dialog" aria-label=${k("filterFor", { header: e.label })}
|
|
3528
|
+
@click=${(e) => e.stopPropagation()}
|
|
3529
|
+
@keydown=${{
|
|
3530
|
+
handleEvent: (e) => this._onFilterDialogKeydown(e),
|
|
3531
|
+
capture: !0
|
|
3532
|
+
}}>
|
|
3432
3533
|
${t === "boolean" ? this._renderBooleanFilter(e) : t === "number" ? this._renderNumberFilter(e) : t === "date" || t === "datetime" ? this._renderDateFilter(e) : this._renderTextFilter(e)}
|
|
3433
3534
|
<div class="ft-filter-actions">
|
|
3434
3535
|
<button class="ft-filter-clear" @click=${() => this._clearColumnFilter(e.key)}>${k("clear")}</button>
|
|
@@ -3472,7 +3573,7 @@ var K = {
|
|
|
3472
3573
|
(r === "" || r === "empty" || r === "non-empty") && (r ? this._emptyFilterState.set(e, r) : this._emptyFilterState.delete(e), t?.(), this._applyFilterForKey(e));
|
|
3473
3574
|
}}
|
|
3474
3575
|
@keydown=${(e) => {
|
|
3475
|
-
e.key === "Escape" &&
|
|
3576
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3476
3577
|
}}>
|
|
3477
3578
|
<option value="">${k("blankAll")}</option>
|
|
3478
3579
|
<option value="empty">${k("emptyOnly")}</option>
|
|
@@ -3550,7 +3651,7 @@ var K = {
|
|
|
3550
3651
|
}), this._applyTextFilter(e.key);
|
|
3551
3652
|
}}
|
|
3552
3653
|
@keydown=${(e) => {
|
|
3553
|
-
e.key === "Escape" &&
|
|
3654
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3554
3655
|
}}>
|
|
3555
3656
|
<option value="contains">${k("contains")}</option>
|
|
3556
3657
|
<option value="starts">${k("startsWith")}</option>
|
|
@@ -3571,7 +3672,7 @@ var K = {
|
|
|
3571
3672
|
}), this._emptyFilterState.delete(e.key), this._applyTextFilter(e.key);
|
|
3572
3673
|
}}
|
|
3573
3674
|
@keydown=${(e) => {
|
|
3574
|
-
e.key === "Escape" &&
|
|
3675
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3575
3676
|
}}>
|
|
3576
3677
|
${this._renderEmptyFilterRow(e.key, () => {
|
|
3577
3678
|
this._textFilterState.delete(e.key);
|
|
@@ -3605,7 +3706,7 @@ var K = {
|
|
|
3605
3706
|
}, this._numberFilterState.set(e, i), this._emptyFilterState.delete(e), this._applyFilterForKey(e);
|
|
3606
3707
|
}}
|
|
3607
3708
|
@keydown=${(e) => {
|
|
3608
|
-
e.key === "Escape" &&
|
|
3709
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3609
3710
|
}}>
|
|
3610
3711
|
${Object.keys(K).map((e) => i`<option value=${e}>${K[e]}</option>`)}
|
|
3611
3712
|
</select>
|
|
@@ -3622,7 +3723,7 @@ var K = {
|
|
|
3622
3723
|
}, this._numberFilterState.set(e, i), this._emptyFilterState.delete(e), this._applyFilterForKey(e);
|
|
3623
3724
|
}}
|
|
3624
3725
|
@keydown=${(e) => {
|
|
3625
|
-
e.key === "Escape" &&
|
|
3726
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3626
3727
|
}}>
|
|
3627
3728
|
</div>
|
|
3628
3729
|
`;
|
|
@@ -3639,7 +3740,7 @@ var K = {
|
|
|
3639
3740
|
r.join = n, this._numberFilterState.set(e.key, r), this._emptyFilterState.delete(e.key), this._applyFilterForKey(e.key);
|
|
3640
3741
|
}}
|
|
3641
3742
|
@keydown=${(e) => {
|
|
3642
|
-
e.key === "Escape" &&
|
|
3743
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3643
3744
|
}}>
|
|
3644
3745
|
<option value="and">AND</option>
|
|
3645
3746
|
<option value="or">OR</option>
|
|
@@ -3671,7 +3772,7 @@ var K = {
|
|
|
3671
3772
|
}
|
|
3672
3773
|
_renderDateFilter(e) {
|
|
3673
3774
|
let t = e.type === "datetime", n = this._dateFilterState.get(e.key) ?? {}, r = (e) => e?.slice(0, 10), o = (e) => {
|
|
3674
|
-
e.key === "Escape" && $(e.currentTarget) || (e.stopPropagation(), e.key === "Escape" &&
|
|
3775
|
+
e.key === "Escape" && $(e.currentTarget) || (e.stopPropagation(), e.key === "Escape" && this._closeFilterDropdown());
|
|
3675
3776
|
};
|
|
3676
3777
|
return i`
|
|
3677
3778
|
<div class="ft-filter-range ft-filter-range-dates">
|
|
@@ -3703,7 +3804,7 @@ var K = {
|
|
|
3703
3804
|
n === "all" ? this.removeFilter(e.key) : this.setFilter(e.key, (e) => !!e == (n === "true"));
|
|
3704
3805
|
}}
|
|
3705
3806
|
@keydown=${(e) => {
|
|
3706
|
-
e.key === "Escape" &&
|
|
3807
|
+
e.key === "Escape" && this._closeFilterDropdown(), e.stopPropagation();
|
|
3707
3808
|
}}>
|
|
3708
3809
|
<option value="all">${k("all")}</option>
|
|
3709
3810
|
<option value="true">\u2714 ${k("booleanTrue")}</option>
|
|
@@ -4468,7 +4569,7 @@ G([s({ type: Array })], Q.prototype, "columns", void 0), G([s({
|
|
|
4468
4569
|
})], Q.prototype, "footerData", void 0), G([s({ attribute: !1 })], Q.prototype, "stylesheets", void 0), G([s({
|
|
4469
4570
|
type: Number,
|
|
4470
4571
|
attribute: "max-undo-size"
|
|
4471
|
-
})], 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);
|
|
4472
4573
|
function Qe(e, t) {
|
|
4473
4574
|
if (t) {
|
|
4474
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;
|
|
@@ -484,6 +509,18 @@ export declare class FlexTable extends LitElement {
|
|
|
484
509
|
/** Keep a fixed-position menu inside the viewport — a menu opened near the right or bottom edge would spill off-screen. */
|
|
485
510
|
private _keepMenuInView;
|
|
486
511
|
private _adjustFilterDropdown;
|
|
512
|
+
/**
|
|
513
|
+
* Close the filter dialog. From the keyboard (Escape) focus goes back to the column's menu button — the
|
|
514
|
+
* dialog leaves the DOM, and focus inside it would otherwise drop to the page (APG dialog). A click
|
|
515
|
+
* outside closes it without moving focus: the click already put focus where the user meant.
|
|
516
|
+
*/
|
|
517
|
+
private _closeFilterDropdown;
|
|
518
|
+
/**
|
|
519
|
+
* Tab stays inside the filter dialog (it floats over the table, fixed to the header — a focus that left
|
|
520
|
+
* it would leave it open and unreachable behind the next control). Capture phase: the controls stop
|
|
521
|
+
* their own keydowns from reaching the grid.
|
|
522
|
+
*/
|
|
523
|
+
private _onFilterDialogKeydown;
|
|
487
524
|
private _renderFilterDropdown;
|
|
488
525
|
private _buildTextPredicate;
|
|
489
526
|
private _applyTextFilter;
|
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
|