@iyulab/flex-table 0.55.2 → 0.56.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 +38 -0
- package/README.md +18 -7
- package/dist/core/row-selection.d.ts +28 -17
- package/dist/events.d.ts +4 -0
- package/dist/{flex-table-D3E9npd9.js → flex-table-M_oC8OXD.js} +108 -62
- package/dist/flex-table.d.ts +45 -14
- package/dist/flex-table.js +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/skills/iyulab-flex-table/SKILL.md +6 -3
- package/skills/iyulab-flex-table/references/api.md +9 -6
- package/skills/iyulab-flex-table/references/react.md +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.56.0] - 2026-10-07
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Row selection stays on its rows.** The checkmarks were kept by screen position, so sorting, filtering, inserting
|
|
8
|
+
or deleting rows moved them onto other rows without a `selection-change` — select a row, sort, and a different row
|
|
9
|
+
was selected (and a bulk action took it). Replacing `data` with other rows of the same length carried the
|
|
10
|
+
checkmarks onto the new rows. Selection is now kept by row id (see `rowKey` below).
|
|
11
|
+
- **`deleteRows()` without indices deletes the checked rows in a `selectable` grid.** It deleted the rows of the
|
|
12
|
+
cell selection (the active cell's row), so a «Delete selected» button removed a row nobody checked. With nothing
|
|
13
|
+
checked it now deletes nothing. A grid without checkboxes keeps deleting the cell selection's rows.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`rowKey`** (`row-key`, default `'_id'` — the field `u-rich-table` reads) — the field, or a function of the row,
|
|
18
|
+
that names a row. A keyed row stays selected when `data` is replaced, so a selection spans server pages. A row
|
|
19
|
+
without a key is named by the row object (a session-local id `#n`) and leaves the selection when `data` no longer
|
|
20
|
+
holds it.
|
|
21
|
+
- `getRowId(row)`, the `selectedRowIds` getter and `setSelection(ids)` (does nothing, and fires nothing, when the
|
|
22
|
+
selection already is `ids`).
|
|
23
|
+
- `selection-change` carries `selectedIds` — every selected row, on every page — next to `selectedRows` and
|
|
24
|
+
`selectedIndices` (the selected rows `data` holds). `row-activate` carries the row's `id`.
|
|
25
|
+
|
|
26
|
+
### Changed (breaking)
|
|
27
|
+
|
|
28
|
+
- The header checkbox and `selectAll()` act on the rows in view: rows selected on another page stay selected, and
|
|
29
|
+
unchecking the header deselects only the rows in view. `deselectAll()` still clears every page. A selected row a
|
|
30
|
+
filter hides stays selected (and in `selectedRows`).
|
|
31
|
+
- `RowSelectionState` (exported) keeps ids: `isSelected(id)`, `toggle(id)`, `select(id)`, `selectAll(ids)`,
|
|
32
|
+
`deselectMany(ids)`, `set(ids)`, `retain(keep)`, `selectRange(orderedIds, from, to)`, `isAllSelected(ids)`,
|
|
33
|
+
`isSomeSelected(ids)`, `selectedIds`. `setRowCount` and `selectedIndices` are gone.
|
|
34
|
+
- `clear-selection-on-data-change` keeps its meaning; it is no longer needed to stop a replacement from moving the
|
|
35
|
+
checkmarks.
|
|
36
|
+
|
|
37
|
+
**Migrating**: give rows a stable key (`_id`, or set `rowKey`) when selection should survive a reload or a page change.
|
|
38
|
+
Read `selectedIds` for «what is selected» across pages, `selectedRows` for the rows on hand. A «Delete selected» button
|
|
39
|
+
on a `selectable` grid can keep calling `deleteRows()`.
|
|
40
|
+
|
|
3
41
|
## [0.55.2] - 2026-10-07
|
|
4
42
|
|
|
5
43
|
### Documentation
|
package/README.md
CHANGED
|
@@ -108,6 +108,7 @@ guarantee about a *constrained* host. `height-model.browser.test.ts` pins both s
|
|
|
108
108
|
| `maxRows` | `max-rows` | `number` | `0` | Max row count (0 = unlimited); blocks `addRow()` and paste expansion |
|
|
109
109
|
| `maxUndoSize` | `max-undo-size` | `number` | `100` | Max undo history stack size |
|
|
110
110
|
| `selectable` | `selectable` | `boolean` | `false` | Enable row-level checkbox selection |
|
|
111
|
+
| `rowKey` | `row-key` | `string \| (row) => unknown` | `'_id'` | What names a row — selection is kept by this id (see [Row Selection](#row-selection)) |
|
|
111
112
|
| `selectionMode` | `selection-mode` | `'single' \| 'multi'` | `'multi'` | Row selection mode |
|
|
112
113
|
| `dataMode` | `data-mode` | `'client' \| 'server'` | `'client'` | Client-side or server-side data processing |
|
|
113
114
|
| `footerData` | `footer-data` | `Record<string, string \| TemplateResult> \| null` | `null` | Footer/summary row data (keys match column keys) |
|
|
@@ -235,7 +236,7 @@ Every row keeps its own value. Sorting, filtering, copying, CSV/XLSX export and
|
|
|
235
236
|
| Method | Returns | Description |
|
|
236
237
|
|--------|---------|-------------|
|
|
237
238
|
| `addRow(row?, index?)` | `DataRow \| null` | Add a row. Returns `null` if `maxRows` reached |
|
|
238
|
-
| `deleteRows(indices?)` | `void` | Delete rows by data index
|
|
239
|
+
| `deleteRows(indices?)` | `void` | Delete rows by data index. Without indices: the checked rows when `selectable` (none checked — nothing), otherwise the rows of the cell selection |
|
|
239
240
|
| `updateRows(changes)` | `void` | Batch update cells as single undo action. `changes: Array<{ row, key, value }>` |
|
|
240
241
|
| `refreshData()` | `void` | Force re-render after in-place data mutation |
|
|
241
242
|
|
|
@@ -253,11 +254,21 @@ Every row keeps its own value. Sorting, filtering, copying, CSV/XLSX export and
|
|
|
253
254
|
|
|
254
255
|
| Method | Returns | Description |
|
|
255
256
|
|--------|---------|-------------|
|
|
256
|
-
| `selectAll()` | `void` | Select
|
|
257
|
-
| `deselectAll()` | `void` | Deselect
|
|
258
|
-
| `
|
|
257
|
+
| `selectAll()` | `void` | Select every row in view, after filtering (multi mode only). Rows on other pages stay as they are |
|
|
258
|
+
| `deselectAll()` | `void` | Deselect every row, on every page |
|
|
259
|
+
| `selectWhere(predicate)` | `void` | Add the rows in view for which `predicate(row, dataIndex)` is true |
|
|
260
|
+
| `setSelection(ids)` | `void` | Replace the selection with these row ids. The same set again does nothing and fires nothing |
|
|
261
|
+
| `getSelectedRows()` | `{ selectedIds, selectedIndices, selectedRows }` | `selectedIds`: every selected row (all pages). `selectedRows` / `selectedIndices`: the selected rows `data` holds, and their positions in it |
|
|
262
|
+
| `getRowId(row)` | `string` | The id selection keeps for a row |
|
|
263
|
+
| `selectedRowIds` (getter) | `ReadonlySet<string>` | Ids of the selected rows, all pages (a copy) |
|
|
259
264
|
|
|
260
|
-
Row selection is
|
|
265
|
+
Row selection is kept by **row id**, not by position, so a checkmark stays on its row through sorting, filtering, inserts and deletes. The id is the row's `row-key` field — `_id` by default, the same field `u-rich-table` reads — or the result of a `rowKey` function:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
table.rowKey = 'orderNo'; // or: table.rowKey = (row) => `${row.site}/${row.no}`
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
A keyed row stays selected when `data` is replaced, so in a server-paged grid the selection spans pages (`selectedIds` names them all; `selectedRows` holds the ones on this page). A row without a key is named by the row object itself (a session-local id `#n`): it follows the row while the same object is in `data` and leaves the selection when it is gone. Set `clear-selection-on-data-change` when every new `data` should start a new selection (a new search):
|
|
261
272
|
|
|
262
273
|
```html
|
|
263
274
|
<flex-table selectable clear-selection-on-data-change></flex-table>
|
|
@@ -304,7 +315,7 @@ type-checks without a cast. The React wrapper's `on*` props carry the same types
|
|
|
304
315
|
|-------|--------|-------------|
|
|
305
316
|
| `row-add` | `{ row, index }` | Row added |
|
|
306
317
|
| `row-delete` | `{ indices, rows }` | Rows deleted |
|
|
307
|
-
| `row-activate` | `{ row, index, col, key }` | Enter pressed on a non-editable cell — the grid's own contract for "activate this row" (e.g. navigate to a detail view), guaranteed even though the internal Enter handler prevents the keystroke from reliably reaching a listener the host attaches to the same element |
|
|
318
|
+
| `row-activate` | `{ row, id, index, col, key }` | Enter pressed on a non-editable cell — the grid's own contract for "activate this row" (e.g. navigate to a detail view), guaranteed even though the internal Enter handler prevents the keystroke from reliably reaching a listener the host attaches to the same element |
|
|
308
319
|
| `batch-update` | `{ changes: [{ row, key, oldValue, newValue }] }` | Batch update applied |
|
|
309
320
|
| `row-reorder` | `{ from, to }` | Row dragged to a new place (data indices) |
|
|
310
321
|
| `data-import` | `{ count }` | Rows imported from a file |
|
|
@@ -336,7 +347,7 @@ type-checks without a cast. The React wrapper's `on*` props carry the same types
|
|
|
336
347
|
|
|
337
348
|
| Event | Detail | Description |
|
|
338
349
|
|-------|--------|-------------|
|
|
339
|
-
| `selection-change` | `{ selectedIndices, selectedRows }` | Row checkbox selection changed |
|
|
350
|
+
| `selection-change` | `{ selectedIds, selectedIndices, selectedRows }` | Row checkbox selection changed — `selectedIds` covers every page, `selectedRows` the rows `data` holds |
|
|
340
351
|
|
|
341
352
|
### Clipboard Events
|
|
342
353
|
|
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
import type { SelectionMode } from '../models/types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Separate from cell-level SelectionState
|
|
3
|
+
* Row-level (checkbox) selection, kept as a set of row ids — see `FlexTable.getRowId`.
|
|
4
|
+
* Separate from the cell-level `SelectionState`.
|
|
5
|
+
*
|
|
6
|
+
* An id names a row, not a position: sorting, filtering, inserting or deleting rows leaves the checkmarks on the
|
|
7
|
+
* rows they were put on. The header checkbox and "select all" act on the rows currently in view (`ids` arguments);
|
|
8
|
+
* ids of rows that are not in view (another server page) stay selected.
|
|
5
9
|
*/
|
|
6
10
|
export declare class RowSelectionState {
|
|
7
11
|
private _selected;
|
|
8
12
|
private _mode;
|
|
9
|
-
private _rowCount;
|
|
10
13
|
get mode(): SelectionMode;
|
|
11
14
|
set mode(value: SelectionMode);
|
|
12
|
-
|
|
13
|
-
get
|
|
15
|
+
/** Selected ids, in the order they were selected. */
|
|
16
|
+
get selectedIds(): string[];
|
|
14
17
|
get selectedCount(): number;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
isSelected(id: string): boolean;
|
|
19
|
+
/** Every one of `ids` (the rows in view) is selected — false when `ids` is empty. */
|
|
20
|
+
isAllSelected(ids: readonly string[]): boolean;
|
|
21
|
+
/** Some but not all of `ids` (the rows in view) are selected. */
|
|
22
|
+
isSomeSelected(ids: readonly string[]): boolean;
|
|
23
|
+
toggle(id: string): void;
|
|
24
|
+
select(id: string): void;
|
|
25
|
+
deselect(id: string): void;
|
|
26
|
+
/** Adds `ids` to the selection (multi mode only — one slot cannot hold a set). */
|
|
27
|
+
selectAll(ids: readonly string[]): void;
|
|
28
|
+
/** Removes `ids` from the selection — the rest stays. */
|
|
29
|
+
deselectMany(ids: readonly string[]): void;
|
|
22
30
|
deselectAll(): void;
|
|
31
|
+
/** Replaces the selection with `ids` (single mode keeps the last). Returns whether it changed. */
|
|
32
|
+
set(ids: Iterable<string>): boolean;
|
|
33
|
+
/** Keeps only the ids `keep` accepts. Returns whether anything was dropped. */
|
|
34
|
+
retain(keep: (id: string) => boolean): boolean;
|
|
23
35
|
/**
|
|
24
|
-
* Selects
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* "one at a time" semantics — a range doesn't make sense with one slot.
|
|
36
|
+
* Selects `ids` between the positions of `from` and `to` in `ordered` (the rows in view, top to bottom), inclusive,
|
|
37
|
+
* in either direction — shift-click range selection anchored at the last toggled row. Single mode selects only
|
|
38
|
+
* `to`, matching `toggle()`'s one-slot semantics. An anchor that is no longer in view selects only `to`.
|
|
28
39
|
*/
|
|
29
|
-
selectRange(from:
|
|
40
|
+
selectRange(ordered: readonly string[], from: string, to: string): void;
|
|
30
41
|
}
|
package/dist/events.d.ts
CHANGED
|
@@ -19,7 +19,9 @@ export interface CellChange {
|
|
|
19
19
|
*/
|
|
20
20
|
export interface FlexTableEventMap {
|
|
21
21
|
/** Row selection changed (`selectable`). Indices are data indices. */
|
|
22
|
+
/** `selectedIds` — every selected row (all pages, see `rowKey`); `selectedRows`/`selectedIndices` — the selected rows `data` holds. */
|
|
22
23
|
'selection-change': CustomEvent<{
|
|
24
|
+
selectedIds: string[];
|
|
23
25
|
selectedIndices: number[];
|
|
24
26
|
selectedRows: DataRow[];
|
|
25
27
|
}>;
|
|
@@ -83,8 +85,10 @@ export interface FlexTableEventMap {
|
|
|
83
85
|
to: number;
|
|
84
86
|
}>;
|
|
85
87
|
/** Enter on a non-editable cell — "activate this row". `index` is the data index, `col` the visible column index. */
|
|
88
|
+
/** `id` — the row's id (`getRowId`); `index` — its position in `data`; `key` — the active column's key. */
|
|
86
89
|
'row-activate': CustomEvent<{
|
|
87
90
|
row: DataRow;
|
|
91
|
+
id: string;
|
|
88
92
|
index: number;
|
|
89
93
|
col: number;
|
|
90
94
|
key: string | undefined;
|
|
@@ -1225,7 +1225,7 @@ var oe = class {
|
|
|
1225
1225
|
}
|
|
1226
1226
|
}, k = class {
|
|
1227
1227
|
constructor() {
|
|
1228
|
-
this._selected = /* @__PURE__ */ new Set(), this._mode = "multi"
|
|
1228
|
+
this._selected = /* @__PURE__ */ new Set(), this._mode = "multi";
|
|
1229
1229
|
}
|
|
1230
1230
|
get mode() {
|
|
1231
1231
|
return this._mode;
|
|
@@ -1236,27 +1236,24 @@ var oe = class {
|
|
|
1236
1236
|
this._selected.clear(), e !== void 0 && this._selected.add(e);
|
|
1237
1237
|
}
|
|
1238
1238
|
}
|
|
1239
|
-
|
|
1240
|
-
this.
|
|
1241
|
-
for (let t of this._selected) t >= e && this._selected.delete(t);
|
|
1242
|
-
}
|
|
1243
|
-
get selectedIndices() {
|
|
1244
|
-
return [...this._selected].sort((e, t) => e - t);
|
|
1239
|
+
get selectedIds() {
|
|
1240
|
+
return [...this._selected];
|
|
1245
1241
|
}
|
|
1246
1242
|
get selectedCount() {
|
|
1247
1243
|
return this._selected.size;
|
|
1248
1244
|
}
|
|
1249
|
-
get isAllSelected() {
|
|
1250
|
-
return this._rowCount > 0 && this._selected.size === this._rowCount;
|
|
1251
|
-
}
|
|
1252
|
-
get isSomeSelected() {
|
|
1253
|
-
return this._selected.size > 0 && this._selected.size < this._rowCount;
|
|
1254
|
-
}
|
|
1255
1245
|
isSelected(e) {
|
|
1256
1246
|
return this._selected.has(e);
|
|
1257
1247
|
}
|
|
1248
|
+
isAllSelected(e) {
|
|
1249
|
+
return e.length > 0 && e.every((e) => this._selected.has(e));
|
|
1250
|
+
}
|
|
1251
|
+
isSomeSelected(e) {
|
|
1252
|
+
let t = e.reduce((e, t) => e + +!!this._selected.has(t), 0);
|
|
1253
|
+
return t > 0 && t < e.length;
|
|
1254
|
+
}
|
|
1258
1255
|
toggle(e) {
|
|
1259
|
-
this.
|
|
1256
|
+
this._selected.has(e) ? this._selected.delete(e) : this.select(e);
|
|
1260
1257
|
}
|
|
1261
1258
|
select(e) {
|
|
1262
1259
|
this._mode === "single" && this._selected.clear(), this._selected.add(e);
|
|
@@ -1264,22 +1261,31 @@ var oe = class {
|
|
|
1264
1261
|
deselect(e) {
|
|
1265
1262
|
this._selected.delete(e);
|
|
1266
1263
|
}
|
|
1267
|
-
selectAll() {
|
|
1268
|
-
if (this._mode !== "single")
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1264
|
+
selectAll(e) {
|
|
1265
|
+
if (this._mode !== "single") for (let t of e) this._selected.add(t);
|
|
1266
|
+
}
|
|
1267
|
+
deselectMany(e) {
|
|
1268
|
+
for (let t of e) this._selected.delete(t);
|
|
1272
1269
|
}
|
|
1273
1270
|
deselectAll() {
|
|
1274
1271
|
this._selected.clear();
|
|
1275
1272
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1273
|
+
set(e) {
|
|
1274
|
+
let t = [...new Set(e)], n = this._mode === "single" ? t.slice(-1) : t;
|
|
1275
|
+
return n.length === this._selected.size && n.every((e) => this._selected.has(e)) ? !1 : (this._selected = new Set(n), !0);
|
|
1276
|
+
}
|
|
1277
|
+
retain(e) {
|
|
1278
|
+
let t = !1;
|
|
1279
|
+
for (let n of this._selected) e(n) || (this._selected.delete(n), t = !0);
|
|
1280
|
+
return t;
|
|
1281
|
+
}
|
|
1282
|
+
selectRange(e, t, n) {
|
|
1283
|
+
let r = e.indexOf(t), i = e.indexOf(n);
|
|
1284
|
+
if (this._mode === "single" || r < 0 || i < 0) {
|
|
1285
|
+
this.select(n);
|
|
1279
1286
|
return;
|
|
1280
1287
|
}
|
|
1281
|
-
let
|
|
1282
|
-
for (let e = n; e <= r; e++) e >= 0 && e < this._rowCount && this._selected.add(e);
|
|
1288
|
+
for (let t = Math.min(r, i); t <= Math.max(r, i); t++) this._selected.add(e[t]);
|
|
1283
1289
|
}
|
|
1284
1290
|
};
|
|
1285
1291
|
//#endregion
|
|
@@ -1756,7 +1762,7 @@ var K = {
|
|
|
1756
1762
|
lte: "≤"
|
|
1757
1763
|
}, q = 120, J = 40, Y = 20, X = 32, Z = 5, Xe = 200, Q = class extends r {
|
|
1758
1764
|
constructor(...e) {
|
|
1759
|
-
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 = "", this.noMatchingMessage = "", this.error = null, 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._focusedCellEl = null, this._editingCell = null, this._sortCriteria = [], this._selection = new oe(), this._editing = new se(), this._rowSelection = new k(), this._undo = new A(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this.
|
|
1765
|
+
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this.rowKey = "_id", 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 = "", this.noMatchingMessage = "", this.error = null, 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._focusedCellEl = null, this._editingCell = null, this._sortCriteria = [], this._selection = new oe(), this._editing = new se(), this._rowSelection = new k(), this._undo = new A(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._lastCheckboxRowId = null, this._unkeyedIds = /* @__PURE__ */ new WeakMap(), this._unkeyedSeq = 0, this._visibleIdsCache = 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) => {
|
|
1760
1766
|
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);
|
|
1761
1767
|
}, this._onFocusIn = (e) => {
|
|
1762
1768
|
let t = e.composedPath()[0];
|
|
@@ -1784,7 +1790,7 @@ var K = {
|
|
|
1784
1790
|
}
|
|
1785
1791
|
set data(e) {
|
|
1786
1792
|
let t = this._data, n = e !== t;
|
|
1787
|
-
this._data = e, n && !this._inUndoRedo && (this.clearUndoOnDataChange && this._undo.clear(), this.
|
|
1793
|
+
this._data = e, n && !this._inUndoRedo && (this.clearUndoOnDataChange && this._undo.clear(), this._rowSelection.selectedCount > 0 && (this.clearSelectionOnDataChange ? (this._rowSelection.deselectAll(), 1) : this._pruneGoneUnkeyedRows()) && (this._rowSelectionVersion++, this._dispatchRowSelectionEvent())), this.requestUpdate("data", t);
|
|
1788
1794
|
}
|
|
1789
1795
|
get rowHeight() {
|
|
1790
1796
|
let e = this._rowHeightExplicit ?? this._rowHeightFromCss ?? X;
|
|
@@ -1835,14 +1841,28 @@ var K = {
|
|
|
1835
1841
|
return this._filteredIndices.length;
|
|
1836
1842
|
}
|
|
1837
1843
|
getSelectedRows() {
|
|
1838
|
-
let e =
|
|
1844
|
+
let e = [];
|
|
1845
|
+
if (this._rowSelection.selectedCount > 0) for (let t = 0; t < this.data.length; t++) this._rowSelection.isSelected(this.getRowId(this.data[t])) && e.push(t);
|
|
1839
1846
|
return {
|
|
1847
|
+
selectedIds: this._rowSelection.selectedIds,
|
|
1840
1848
|
selectedIndices: e,
|
|
1841
1849
|
selectedRows: e.map((e) => this.data[e])
|
|
1842
1850
|
};
|
|
1843
1851
|
}
|
|
1852
|
+
getRowId(e) {
|
|
1853
|
+
let t = this.rowKey, n = typeof t == "function" ? t(e) : e[t];
|
|
1854
|
+
if (n != null && n !== "") return String(n);
|
|
1855
|
+
let r = this._unkeyedIds.get(e);
|
|
1856
|
+
return r === void 0 && (r = `#${++this._unkeyedSeq}`, this._unkeyedIds.set(e, r)), r;
|
|
1857
|
+
}
|
|
1858
|
+
get selectedRowIds() {
|
|
1859
|
+
return new Set(this._rowSelection.selectedIds);
|
|
1860
|
+
}
|
|
1861
|
+
setSelection(e) {
|
|
1862
|
+
this.selectable && this._rowSelection.set(e) && (this._rowSelectionVersion++, this._dispatchRowSelectionEvent(), this.requestUpdate());
|
|
1863
|
+
}
|
|
1844
1864
|
selectAll() {
|
|
1845
|
-
this.selectable && (this._rowSelection.selectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
|
|
1865
|
+
this.selectable && (this._rowSelection.selectAll(this._visibleRowIds()), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
|
|
1846
1866
|
}
|
|
1847
1867
|
deselectAll() {
|
|
1848
1868
|
this.selectable && (this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
|
|
@@ -1851,17 +1871,33 @@ var K = {
|
|
|
1851
1871
|
if (this.selectable) {
|
|
1852
1872
|
for (let t = 0; t < this._visibleRowCount; t++) {
|
|
1853
1873
|
let n = this._toDataIndex(t), r = this.data[n];
|
|
1854
|
-
r !== void 0 && e(r, n) && this._rowSelection.select(
|
|
1874
|
+
r !== void 0 && e(r, n) && this._rowSelection.select(this.getRowId(r));
|
|
1855
1875
|
}
|
|
1856
1876
|
this._rowSelectionVersion++, this._dispatchRowSelectionEvent(), this.requestUpdate();
|
|
1857
1877
|
}
|
|
1858
1878
|
}
|
|
1859
1879
|
_dispatchRowSelectionEvent() {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1880
|
+
this._emit("selection-change", this.getSelectedRows());
|
|
1881
|
+
}
|
|
1882
|
+
_visibleRowIds() {
|
|
1883
|
+
let e = this._visibleIdsCache;
|
|
1884
|
+
if (e && e.order === this._sortedIndices && e.data === this.data && e.key === this.rowKey && e.ids.length === this._visibleRowCount) return e.ids;
|
|
1885
|
+
let t = [];
|
|
1886
|
+
for (let e = 0; e < this._visibleRowCount; e++) {
|
|
1887
|
+
let n = this.data[this._toDataIndex(e)];
|
|
1888
|
+
n !== void 0 && t.push(this.getRowId(n));
|
|
1889
|
+
}
|
|
1890
|
+
return this._visibleIdsCache = {
|
|
1891
|
+
order: this._sortedIndices,
|
|
1892
|
+
data: this.data,
|
|
1893
|
+
key: this.rowKey,
|
|
1894
|
+
ids: t
|
|
1895
|
+
}, t;
|
|
1896
|
+
}
|
|
1897
|
+
_pruneGoneUnkeyedRows() {
|
|
1898
|
+
if (!this._rowSelection.selectedIds.some((e) => e.startsWith("#"))) return !1;
|
|
1899
|
+
let e = new Set(this.data.map((e) => this.getRowId(e)));
|
|
1900
|
+
return this._rowSelection.retain((t) => !t.startsWith("#") || e.has(t));
|
|
1865
1901
|
}
|
|
1866
1902
|
setFilter(e, t) {
|
|
1867
1903
|
this._filters = this._filters.filter((t) => t.key !== e), this._filters.push({
|
|
@@ -2037,34 +2073,35 @@ var K = {
|
|
|
2037
2073
|
}), this._dispatchUndoStateEvent(), n;
|
|
2038
2074
|
}
|
|
2039
2075
|
deleteRows(e) {
|
|
2040
|
-
let t = e ?? this._getSelectedDataRows();
|
|
2076
|
+
let t = e ?? (this.selectable ? this.getSelectedRows().selectedIndices : this._getSelectedDataRows());
|
|
2041
2077
|
if (t.length === 0) return;
|
|
2042
2078
|
let n = [...t].sort((e, t) => t - e), r = [];
|
|
2043
2079
|
for (let e of n) e >= 0 && e < this.data.length && (r.push({
|
|
2044
2080
|
index: e,
|
|
2045
2081
|
row: this.data[e]
|
|
2046
2082
|
}), this.data.splice(e, 1));
|
|
2047
|
-
if (r.length
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
}
|
|
2059
|
-
}), this._activeCell) {
|
|
2060
|
-
let e = this._toDataIndex(this._activeCell.row);
|
|
2061
|
-
t.includes(e) && (this._selection.clear(), this._activeCell = null);
|
|
2083
|
+
if (r.length === 0) return;
|
|
2084
|
+
r.reverse(), this._undo.push({
|
|
2085
|
+
label: "row-delete",
|
|
2086
|
+
undo: () => {
|
|
2087
|
+
for (let { index: e, row: t } of r) this.data.splice(e, 0, t);
|
|
2088
|
+
this.requestUpdate();
|
|
2089
|
+
},
|
|
2090
|
+
redo: () => {
|
|
2091
|
+
let e = [...r].reverse();
|
|
2092
|
+
for (let { index: t } of e) this.data.splice(t, 1);
|
|
2093
|
+
this.requestUpdate();
|
|
2062
2094
|
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2095
|
+
});
|
|
2096
|
+
let i = r.map((e) => this.getRowId(e.row)).filter((e) => this._rowSelection.isSelected(e));
|
|
2097
|
+
if (i.length > 0 && (this._rowSelection.deselectMany(i), this._rowSelectionVersion++, this._dispatchRowSelectionEvent()), this._activeCell) {
|
|
2098
|
+
let e = this._toDataIndex(this._activeCell.row);
|
|
2099
|
+
t.includes(e) && (this._selection.clear(), this._activeCell = null);
|
|
2067
2100
|
}
|
|
2101
|
+
this.requestUpdate(), this._emit("row-delete", {
|
|
2102
|
+
indices: r.map((e) => e.index),
|
|
2103
|
+
rows: r.map((e) => e.row)
|
|
2104
|
+
}), this._dispatchUndoStateEvent();
|
|
2068
2105
|
}
|
|
2069
2106
|
updateRows(e) {
|
|
2070
2107
|
if (e.length === 0) return;
|
|
@@ -2354,7 +2391,7 @@ var K = {
|
|
|
2354
2391
|
};
|
|
2355
2392
|
}
|
|
2356
2393
|
willUpdate(e) {
|
|
2357
|
-
(!(e.size <= 2 && !e.has("data") && !e.has("columns") && !e.has("_openFilterKey") && !e.has("_editingCell") && !e.has("_activeCell") && (e.has("_scrollTop") || e.has("_scrollLeft"))) || this._viewDirty) && (this._recomputeView(), this._viewDirty = !1), this._updateColOffsets(), this._selection.setDimensions(this._visibleRowCount, this.visibleColumns.length)
|
|
2394
|
+
(!(e.size <= 2 && !e.has("data") && !e.has("columns") && !e.has("_openFilterKey") && !e.has("_editingCell") && !e.has("_activeCell") && (e.has("_scrollTop") || e.has("_scrollLeft"))) || this._viewDirty) && (this._recomputeView(), this._viewDirty = !1), this._updateColOffsets(), this._selection.setDimensions(this._visibleRowCount, this.visibleColumns.length);
|
|
2358
2395
|
}
|
|
2359
2396
|
updated(e) {
|
|
2360
2397
|
this._focusEditor(), this._syncGridFocus(), 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();
|
|
@@ -2492,6 +2529,7 @@ var K = {
|
|
|
2492
2529
|
let t = this._toDataIndex(this._activeCell.row), n = this.data[t];
|
|
2493
2530
|
n && this._emit("row-activate", {
|
|
2494
2531
|
row: n,
|
|
2532
|
+
id: this.getRowId(n),
|
|
2495
2533
|
index: t,
|
|
2496
2534
|
col: this._activeCell.col,
|
|
2497
2535
|
key: e?.key
|
|
@@ -2722,7 +2760,11 @@ var K = {
|
|
|
2722
2760
|
}
|
|
2723
2761
|
if (!this._handleCtrlKey(e) && !this._handleAltKey(e, t)) {
|
|
2724
2762
|
if (e.key === " " && e.shiftKey && this.selectable && this._activeCell && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
2725
|
-
e.preventDefault()
|
|
2763
|
+
e.preventDefault();
|
|
2764
|
+
let t = this.data[this._toDataIndex(this._activeCell.row)];
|
|
2765
|
+
if (!t) return;
|
|
2766
|
+
let n = this.getRowId(t);
|
|
2767
|
+
this._rowSelection.toggle(n), this._lastCheckboxRowId = n, this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
|
|
2726
2768
|
return;
|
|
2727
2769
|
}
|
|
2728
2770
|
if (this._activeCell && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
@@ -4146,8 +4188,8 @@ var K = {
|
|
|
4146
4188
|
${this._rowSelection.mode === "multi" ? a`
|
|
4147
4189
|
<!-- 칸 전체가 누르는 자리다(라벨) — 체크 상자는 16px 그대로. -->
|
|
4148
4190
|
<label class="ft-checkbox-hit"><input type="checkbox" tabindex="-1" aria-label=${e("selectAllRows")}
|
|
4149
|
-
.checked=${this._rowSelection.isAllSelected}
|
|
4150
|
-
.indeterminate=${this._rowSelection.isSomeSelected}
|
|
4191
|
+
.checked=${this._rowSelection.isAllSelected(this._visibleRowIds())}
|
|
4192
|
+
.indeterminate=${this._rowSelection.isSomeSelected(this._visibleRowIds())}
|
|
4151
4193
|
@change=${this._onSelectAllChange}></label>
|
|
4152
4194
|
` : ""}
|
|
4153
4195
|
</div>` : "";
|
|
@@ -4194,10 +4236,14 @@ var K = {
|
|
|
4194
4236
|
`;
|
|
4195
4237
|
}
|
|
4196
4238
|
_onSelectAllChange(e) {
|
|
4197
|
-
e.target.checked ? this._rowSelection.selectAll() : this._rowSelection.
|
|
4239
|
+
e.target.checked ? this._rowSelection.selectAll(this._visibleRowIds()) : this._rowSelection.deselectMany(this._visibleRowIds()), this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
|
|
4198
4240
|
}
|
|
4199
4241
|
_onRowCheckboxChange(e, t) {
|
|
4200
|
-
e.stopPropagation()
|
|
4242
|
+
e.stopPropagation();
|
|
4243
|
+
let n = this.data[this._toDataIndex(t)];
|
|
4244
|
+
if (!n) return;
|
|
4245
|
+
let r = this.getRowId(n);
|
|
4246
|
+
this._checkboxShiftPending && this._lastCheckboxRowId !== null ? this._rowSelection.selectRange(this._visibleRowIds(), this._lastCheckboxRowId, r) : this._rowSelection.toggle(r), this._lastCheckboxRowId = r, this._checkboxShiftPending = !1, this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
|
|
4201
4247
|
}
|
|
4202
4248
|
_onRowCheckboxClick(e) {
|
|
4203
4249
|
this._checkboxShiftPending = e.shiftKey;
|
|
@@ -4242,7 +4288,7 @@ var K = {
|
|
|
4242
4288
|
`;
|
|
4243
4289
|
}
|
|
4244
4290
|
_renderRow(t, n, r, i, o) {
|
|
4245
|
-
let s = this.visibleColumns, c = this._toDataIndex(t), l = this.data[c], u = o ?? t * this.rowHeight, d = this.rowHeight, f = this._totalRowWidth, p = t % 2 == 0 ? "ft-row-even" : "ft-row-odd", m = this.selectable && this._rowSelection.isSelected(
|
|
4291
|
+
let s = this.visibleColumns, c = this._toDataIndex(t), l = this.data[c], u = o ?? t * this.rowHeight, d = this.rowHeight, f = this._totalRowWidth, p = t % 2 == 0 ? "ft-row-even" : "ft-row-odd", m = this.selectable && l !== void 0 && this._rowSelection.isSelected(this.getRowId(l)), h = this._scrollLeft, g = 0, _ = this.selectable ? a`
|
|
4246
4292
|
<div class="ft-checkbox-cell"
|
|
4247
4293
|
style="position: absolute; top: 0; left: ${h + g}px; width: ${this._checkboxColWidth}px; height: ${d}px; z-index: 2;">
|
|
4248
4294
|
<!-- 행 체크박스는 Tab 정지점이 아니다 — 그리드(호스트)가 하나의 정지점이고 행 선택은 Shift+Space 다.
|
|
@@ -4426,7 +4472,7 @@ G([c({ type: Array })], Q.prototype, "columns", void 0), G([c({
|
|
|
4426
4472
|
})], Q.prototype, "clearUndoOnDataChange", void 0), G([c({
|
|
4427
4473
|
type: Boolean,
|
|
4428
4474
|
attribute: "clear-selection-on-data-change"
|
|
4429
|
-
})], Q.prototype, "clearSelectionOnDataChange", void 0), G([c({
|
|
4475
|
+
})], Q.prototype, "clearSelectionOnDataChange", void 0), G([c({ attribute: "row-key" })], Q.prototype, "rowKey", void 0), G([c({
|
|
4430
4476
|
type: Number,
|
|
4431
4477
|
attribute: "row-height"
|
|
4432
4478
|
})], Q.prototype, "rowHeight", null), G([c({
|
package/dist/flex-table.d.ts
CHANGED
|
@@ -28,15 +28,22 @@ export declare class FlexTable extends LitElement {
|
|
|
28
28
|
/**
|
|
29
29
|
* When true, replacing `data` externally automatically clears row selection
|
|
30
30
|
* (checkbox selection) and re-dispatches `selection-change` with an empty selection.
|
|
31
|
-
* Default: false
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* Row selection is index-based (no row-key concept), so a full `data` replacement can
|
|
35
|
-
* leave selection pointing at different underlying rows at the same indices —
|
|
36
|
-
* recommended for any `selectable` grid whose selection drives bulk actions
|
|
37
|
-
* (e.g. server-mode grids refreshed via `useODataSource`).
|
|
31
|
+
* Default: false — keyed rows stay selected across a replacement (see `rowKey`), so a
|
|
32
|
+
* selection can span server pages. Set it when a new `data` should start a new selection
|
|
33
|
+
* (a new search). Internal undo/redo operations are never affected.
|
|
38
34
|
*/
|
|
39
35
|
clearSelectionOnDataChange: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* What names a row: the field whose value identifies it (default `'_id'`, as in `u-rich-table`),
|
|
38
|
+
* or a function of the row. Row selection is kept by this id (`getRowId`), so checkmarks stay on
|
|
39
|
+
* their rows through sorting, filtering, inserts and deletes — and, for rows that have a key,
|
|
40
|
+
* across a `data` replacement: another server page keeps the rows selected on the last one.
|
|
41
|
+
*
|
|
42
|
+
* A row whose key is missing (`undefined`, `null` or `''`) is named by the row object itself —
|
|
43
|
+
* a session-local id `#n`. It follows the row while the same object is in `data`, and leaves the
|
|
44
|
+
* selection when `data` no longer holds that object (a replacement with new objects).
|
|
45
|
+
*/
|
|
46
|
+
rowKey: string | ((row: DataRow) => unknown);
|
|
40
47
|
/**
|
|
41
48
|
* 행 높이(px).
|
|
42
49
|
*
|
|
@@ -135,8 +142,12 @@ export declare class FlexTable extends LitElement {
|
|
|
135
142
|
private _sortedIndices;
|
|
136
143
|
private _openFilterKey;
|
|
137
144
|
private _rowSelectionVersion;
|
|
138
|
-
/** Anchor row for shift-click range selection on the row checkbox column. */
|
|
139
|
-
private
|
|
145
|
+
/** Anchor row (its id) for shift-click range selection on the row checkbox column. */
|
|
146
|
+
private _lastCheckboxRowId;
|
|
147
|
+
/** Session-local ids of rows that have no key — by object, so they follow the row and leave with it. */
|
|
148
|
+
private _unkeyedIds;
|
|
149
|
+
private _unkeyedSeq;
|
|
150
|
+
private _visibleIdsCache;
|
|
140
151
|
/** Set by the checkbox's own click (which carries shiftKey) just before its change event fires. */
|
|
141
152
|
private _checkboxShiftPending;
|
|
142
153
|
private _autocompleteState;
|
|
@@ -179,14 +190,29 @@ export declare class FlexTable extends LitElement {
|
|
|
179
190
|
get sortCriteria(): SortCriteria[];
|
|
180
191
|
/** Number of rows after filtering (before pagination). */
|
|
181
192
|
get filteredRowCount(): number;
|
|
182
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* The row selection. `selectedIds` is every selected row — on every page, including rows not in
|
|
195
|
+
* `data` now. `selectedRows` and `selectedIndices` are the selected rows that `data` holds (in
|
|
196
|
+
* `data` order, filtered-out rows included) and their positions in it.
|
|
197
|
+
*/
|
|
183
198
|
getSelectedRows(): {
|
|
199
|
+
selectedIds: string[];
|
|
184
200
|
selectedIndices: number[];
|
|
185
201
|
selectedRows: DataRow[];
|
|
186
202
|
};
|
|
187
|
-
/**
|
|
203
|
+
/** The id row selection keeps for `row` — its `rowKey` value as a string, or `#n` for a row without one. */
|
|
204
|
+
getRowId(row: DataRow): string;
|
|
205
|
+
/** Ids of the selected rows — every page, including rows not in `data` now. A copy. */
|
|
206
|
+
get selectedRowIds(): ReadonlySet<string>;
|
|
207
|
+
/**
|
|
208
|
+
* Replaces the row selection with `ids` (single mode keeps the last). Does nothing — and fires
|
|
209
|
+
* nothing — when the selection already is `ids`, so a host can set it from its own state on
|
|
210
|
+
* every render.
|
|
211
|
+
*/
|
|
212
|
+
setSelection(ids: Iterable<string>): void;
|
|
213
|
+
/** Selects every row in view — after filtering (multi mode only). Rows on other pages stay as they are. */
|
|
188
214
|
selectAll(): void;
|
|
189
|
-
/**
|
|
215
|
+
/** Deselects every row — on every page. */
|
|
190
216
|
deselectAll(): void;
|
|
191
217
|
/**
|
|
192
218
|
* Selects every currently-loaded row for which `predicate` returns true, in addition to
|
|
@@ -200,6 +226,10 @@ export declare class FlexTable extends LitElement {
|
|
|
200
226
|
*/
|
|
201
227
|
selectWhere(predicate: (row: DataRow, dataIndex: number) => boolean): void;
|
|
202
228
|
private _dispatchRowSelectionEvent;
|
|
229
|
+
/** Ids of the rows in view, top to bottom (after filter and sort). Cached per view and `rowKey`. */
|
|
230
|
+
private _visibleRowIds;
|
|
231
|
+
/** Drops selected `#n` ids whose rows `data` no longer holds. Returns whether anything was dropped. */
|
|
232
|
+
private _pruneGoneUnkeyedRows;
|
|
203
233
|
/**
|
|
204
234
|
* Set a filter for a column. Replaces any existing filter on the same key.
|
|
205
235
|
*/
|
|
@@ -263,8 +293,9 @@ export declare class FlexTable extends LitElement {
|
|
|
263
293
|
*/
|
|
264
294
|
addRow(row?: DataRow, index?: number): DataRow | null;
|
|
265
295
|
/**
|
|
266
|
-
* Delete rows at the specified data indices.
|
|
267
|
-
*
|
|
296
|
+
* Delete rows at the specified data indices. Without indices it deletes the selected rows: the
|
|
297
|
+
* checked rows when the grid is `selectable` (none checked — nothing is deleted), otherwise the
|
|
298
|
+
* rows of the cell selection.
|
|
268
299
|
*/
|
|
269
300
|
deleteRows(indices?: number[]): void;
|
|
270
301
|
/**
|
package/dist/flex-table.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as e, i as t, n, o as r, r as i, t as a } from "./flex-table-
|
|
1
|
+
import { a as e, i as t, n, o as r, r as i, t as a } from "./flex-table-M_oC8OXD.js";
|
|
2
2
|
import { t as o } from "./locale-Cfm-vJji.js";
|
|
3
3
|
export { a as FlexTable, e as RowSelectionState, t as UndoStack, n as effectiveAlign, i as exportData, o as flexTableLocale, r as renderCell };
|
package/dist/react.js
CHANGED
package/package.json
CHANGED
|
@@ -78,9 +78,12 @@ Use `updateRows([{ row, key, value }])` for programmatic edits (undoable, fires
|
|
|
78
78
|
`table.editable = false` (a property, since a boolean attribute cannot express `false`) — Enter on a non-editable cell then fires
|
|
79
79
|
`row-activate`, the grid's "open this row" contract.
|
|
80
80
|
|
|
81
|
-
**Row selection is
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
**Row selection is kept by row id.** Enable with `selectable` (`selection-mode="single|multi"`).
|
|
82
|
+
The id is the row's `row-key` field (`_id` by default, as in `u-rich-table`) or a `rowKey` function, so
|
|
83
|
+
checkmarks follow their rows through sort, filter, insert and delete, and keyed rows stay selected
|
|
84
|
+
across server pages (`selectedIds`). A row without a key is named by its object and leaves the selection
|
|
85
|
+
when `data` drops it. `clear-selection-on-data-change` starts a new selection on every `data`.
|
|
86
|
+
`selectWhere(predicate)` selects rows by content; `setSelection(ids)` sets it from host state.
|
|
84
87
|
|
|
85
88
|
**Client vs server mode.** `data-mode="client"` (default) sorts and filters locally.
|
|
86
89
|
`data-mode="server"` only emits `sort-change` / `filter-change`; you supply already-processed rows.
|
|
@@ -27,7 +27,8 @@ All names below are members of the `FlexTable` class (`<flex-table>`).
|
|
|
27
27
|
| `loading` | `loading` | `boolean` | `false` | Loading overlay + `aria-busy` |
|
|
28
28
|
| `importEnabled` | `import-enabled` | `boolean` | `false` | Drag-and-drop `.xlsx` / `.csv` import |
|
|
29
29
|
| `clearUndoOnDataChange` | `clear-undo-on-data-change` | `boolean` | `false` | Replacing `data` clears undo history |
|
|
30
|
-
| `clearSelectionOnDataChange` | `clear-selection-on-data-change` | `boolean` | `false` | Replacing `data` clears row selection |
|
|
30
|
+
| `clearSelectionOnDataChange` | `clear-selection-on-data-change` | `boolean` | `false` | Replacing `data` clears row selection (otherwise keyed rows stay selected across pages) |
|
|
31
|
+
| `rowKey` | `row-key` | `string \| (row) => unknown` | `'_id'` | Names a row; selection is kept by this id. A row without a key gets a session-local `#n` |
|
|
31
32
|
| `stylesheets` | — | `CSSStyleSheet[]` | `[]` | Adopted into the shadow root; styles `render` output |
|
|
32
33
|
|
|
33
34
|
Replacing `data` with the same array reference does not trigger the clear-on-change behaviors.
|
|
@@ -95,7 +96,7 @@ Enter/Escape and blur-to-commit behavior.
|
|
|
95
96
|
| Method | Returns | Notes |
|
|
96
97
|
|---|---|---|
|
|
97
98
|
| `addRow(row?, index?)` | `DataRow \| null` | `null` when `maxRows` reached |
|
|
98
|
-
| `deleteRows(indices?)` | `void` | Data indices; default =
|
|
99
|
+
| `deleteRows(indices?)` | `void` | Data indices; default = the checked rows when `selectable`, else the cell selection's rows |
|
|
99
100
|
| `updateRows(changes)` | `void` | `Array<{ row, key, value }>`, one undo step |
|
|
100
101
|
| `refreshData()` | `void` | Re-render after in-place mutation |
|
|
101
102
|
|
|
@@ -115,9 +116,11 @@ Enter/Escape and blur-to-commit behavior.
|
|
|
115
116
|
|
|
116
117
|
| Method | Notes |
|
|
117
118
|
|---|---|
|
|
118
|
-
| `selectAll()` / `deselectAll()` | `selectAll
|
|
119
|
+
| `selectAll()` / `deselectAll()` | `selectAll`: the rows in view (multi mode only) · `deselectAll`: every page |
|
|
119
120
|
| `selectWhere(predicate)` | `(row, dataIndex) => boolean` over the visible rows |
|
|
120
|
-
| `
|
|
121
|
+
| `setSelection(ids)` | Replace with these row ids; the same set again fires nothing |
|
|
122
|
+
| `getSelectedRows()` | `{ selectedIds, selectedIndices, selectedRows }` — ids: all pages · rows: the ones `data` holds |
|
|
123
|
+
| `getRowId(row)` · `selectedRowIds` | A row's id · the selected ids (all pages) |
|
|
121
124
|
|
|
122
125
|
### Filtering, undo, comments, import/export
|
|
123
126
|
|
|
@@ -147,7 +150,7 @@ cast, and the React `on*` props carry the same types.
|
|
|
147
150
|
| `validation-error` | `{ row, col, key, value, error }` |
|
|
148
151
|
| `row-add` | `{ row, index }` |
|
|
149
152
|
| `row-delete` | `{ indices, rows }` |
|
|
150
|
-
| `row-activate` | `{ row, index, col, key }` — Enter on a non-editable cell |
|
|
153
|
+
| `row-activate` | `{ row, id, index, col, key }` — Enter on a non-editable cell |
|
|
151
154
|
| `row-reorder` | `{ from, to }` |
|
|
152
155
|
| `batch-update` | `{ changes }` |
|
|
153
156
|
| `column-add` | `{ column, index }` |
|
|
@@ -159,7 +162,7 @@ cast, and the React `on*` props carry the same types.
|
|
|
159
162
|
| `sort-change` | `{ criteria }` |
|
|
160
163
|
| `filter-change` | `{ keys, filteredCount }` |
|
|
161
164
|
| `filter-error` | `{ error, row, filterKey }` |
|
|
162
|
-
| `selection-change` | `{ selectedIndices, selectedRows }` |
|
|
165
|
+
| `selection-change` | `{ selectedIds, selectedIndices, selectedRows }` |
|
|
163
166
|
| `clipboard-copy` / `clipboard-cut` | `{ range, text }` (TSV) |
|
|
164
167
|
| `clipboard-paste` | `{ changes, addedRows }` |
|
|
165
168
|
| `clipboard-error` | `{ action: 'copy' \| 'paste', error }` — copy could not put the text on the clipboard (no `clipboard-copy`/`clipboard-cut` follows; a cut clears nothing), or paste could not read it |
|
|
@@ -78,7 +78,6 @@ function Orders() {
|
|
|
78
78
|
loading={source.loading}
|
|
79
79
|
error={source.error}
|
|
80
80
|
onSortChange={source.onSortChange}
|
|
81
|
-
clearSelectionOnDataChange
|
|
82
81
|
/>
|
|
83
82
|
<button disabled={source.page === 0} onClick={() => source.setPage(source.page - 1)}>Prev</button>
|
|
84
83
|
<span>{source.page + 1} / {Math.max(1, Math.ceil(source.totalCount / 20))}</span>
|