@iyulab/flex-table 0.55.2 → 0.56.1

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.
@@ -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, for consistency with `clearUndoOnDataChange`. Internal undo/redo
32
- * operations are never affected.
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 _lastCheckboxRowIndex;
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;
@@ -164,6 +175,7 @@ export declare class FlexTable extends LitElement {
164
175
  private _columnWidths;
165
176
  private _hostResizeObserver;
166
177
  /** Keyed by dataIndex → colKey → comment text */
178
+ /** Cell comments by row id (`getRowId`) and column key — they stay on their rows when rows move. */
167
179
  private _comments;
168
180
  private _isDragOver;
169
181
  get visibleColumns(): ColumnDefinition[];
@@ -179,14 +191,29 @@ export declare class FlexTable extends LitElement {
179
191
  get sortCriteria(): SortCriteria[];
180
192
  /** Number of rows after filtering (before pagination). */
181
193
  get filteredRowCount(): number;
182
- /** Get data indices of currently selected rows. */
194
+ /**
195
+ * The row selection. `selectedIds` is every selected row — on every page, including rows not in
196
+ * `data` now. `selectedRows` and `selectedIndices` are the selected rows that `data` holds (in
197
+ * `data` order, filtered-out rows included) and their positions in it.
198
+ */
183
199
  getSelectedRows(): {
200
+ selectedIds: string[];
184
201
  selectedIndices: number[];
185
202
  selectedRows: DataRow[];
186
203
  };
187
- /** Select all visible rows (multi mode only). */
204
+ /** The id row selection keeps for `row` — its `rowKey` value as a string, or `#n` for a row without one. */
205
+ getRowId(row: DataRow): string;
206
+ /** Ids of the selected rows — every page, including rows not in `data` now. A copy. */
207
+ get selectedRowIds(): ReadonlySet<string>;
208
+ /**
209
+ * Replaces the row selection with `ids` (single mode keeps the last). Does nothing — and fires
210
+ * nothing — when the selection already is `ids`, so a host can set it from its own state on
211
+ * every render.
212
+ */
213
+ setSelection(ids: Iterable<string>): void;
214
+ /** Selects every row in view — after filtering (multi mode only). Rows on other pages stay as they are. */
188
215
  selectAll(): void;
189
- /** Deselect all rows. */
216
+ /** Deselects every row — on every page. */
190
217
  deselectAll(): void;
191
218
  /**
192
219
  * Selects every currently-loaded row for which `predicate` returns true, in addition to
@@ -200,6 +227,12 @@ export declare class FlexTable extends LitElement {
200
227
  */
201
228
  selectWhere(predicate: (row: DataRow, dataIndex: number) => boolean): void;
202
229
  private _dispatchRowSelectionEvent;
230
+ /** Ids of the rows in view, top to bottom (after filter and sort). Cached per view and `rowKey`. */
231
+ private _visibleRowIds;
232
+ /** Drops comments on `#n` rows `data` no longer holds — such a row cannot come back. */
233
+ private _pruneGoneUnkeyedComments;
234
+ /** Drops selected `#n` ids whose rows `data` no longer holds. Returns whether anything was dropped. */
235
+ private _pruneGoneUnkeyedRows;
203
236
  /**
204
237
  * Set a filter for a column. Replaces any existing filter on the same key.
205
238
  */
@@ -263,8 +296,9 @@ export declare class FlexTable extends LitElement {
263
296
  */
264
297
  addRow(row?: DataRow, index?: number): DataRow | null;
265
298
  /**
266
- * Delete rows at the specified data indices.
267
- * If no indices provided, deletes the currently selected rows.
299
+ * Delete rows at the specified data indices. Without indices it deletes the selected rows: the
300
+ * checked rows when the grid is `selectable` (none checked — nothing is deleted), otherwise the
301
+ * rows of the cell selection.
268
302
  */
269
303
  deleteRows(indices?: number[]): void;
270
304
  /**
@@ -310,10 +344,11 @@ export declare class FlexTable extends LitElement {
310
344
  */
311
345
  getComment(dataIndex: number, colKey: string): string | null;
312
346
  /**
313
- * Get all comments as a flat array.
347
+ * Every comment on a row `data` holds, in `data` order — with the row's current index and its id.
314
348
  */
315
349
  getAllComments(): Array<{
316
350
  dataIndex: number;
351
+ id: string;
317
352
  colKey: string;
318
353
  text: string;
319
354
  }>;
@@ -375,8 +410,20 @@ export declare class FlexTable extends LitElement {
375
410
  protected updated(changedProps: PropertyValues): void;
376
411
  /** Recompute filter → sort pipeline. */
377
412
  private _recomputeView;
413
+ /**
414
+ * Keeps an open editor on the row it was started on after the view changed under it (a refresh put
415
+ * rows above it, a sort moved it). A row that left `data`, or that a filter hid, ends the edit.
416
+ */
417
+ private _followEditingRow;
378
418
  /** Map visual row index to data row index */
379
419
  private _toDataIndex;
420
+ /** Set while the edited row's editor is drawn again in the row's new place (cleared after that update). */
421
+ private _editorMoving;
422
+ /**
423
+ * Blur commits the edit — except the blur of the editor the update is replacing because its row
424
+ * moved (Chromium fires it while removing the element) or of one already gone.
425
+ */
426
+ private _onEditorBlur;
380
427
  private _focusEditor;
381
428
  private _measureViewport;
382
429
  private _warnedUnconstrained;
@@ -570,6 +617,7 @@ export declare class FlexTable extends LitElement {
570
617
  private _renderNumberFilter;
571
618
  /** 셀 오류 표시 — 우리 문장은 «그릴 때 찾는» 함수로(로캘 전환에 따라오게), 소비자 `validator` 문장은 그대로. */
572
619
  private _invalidCells;
620
+ /** A cell named by its row's id and its column's key — so the mark stays on the cell when the view reorders. */
573
621
  private _cellKey;
574
622
  private _markCellInvalid;
575
623
  private _isCellInvalid;
@@ -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-D3E9npd9.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./flex-table-DKBcfNA4.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
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-D3E9npd9.js";
1
+ import { t as e } from "./flex-table-DKBcfNA4.js";
2
2
  import { i as t } from "./query-Dw4iO0ir.js";
3
3
  import { t as n } from "./source--q5s2Oti.js";
4
4
  import { t as r } from "./view-DiLr-TdY.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.55.2",
3
+ "version": "0.56.1",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -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 index-based.** Enable with `selectable` (`selection-mode="single|multi"`).
82
- There is no row key, so set `clear-selection-on-data-change` when selection drives bulk actions and
83
- `data` can be replaced. `selectWhere(predicate)` selects rows by content.
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 = selected rows |
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` is multi mode only |
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
- | `getSelectedRows()` | `{ selectedIndices, selectedRows }` |
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
 
@@ -143,11 +146,11 @@ cast, and the React `on*` props carry the same types.
143
146
  | `cell-select` | `{ row, col }` (or `null`) |
144
147
  | `cell-edit-start` | `{ row, col, key, value }` |
145
148
  | `cell-edit-commit` | `{ row, col, key, oldValue, newValue }` |
146
- | `cell-edit-cancel` | `{ row, col }` |
149
+ | `cell-edit-cancel` | `{ row, col }` — `row`: data index (`-1` once the row left `data`) |
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,13 +162,13 @@ 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 |
166
169
  | `fill-handle-apply` | `{ sourceRange, targetRange, cells }` |
167
170
  | `find-replace` | `{ type: 'replace' \| 'replace-all', cells }` |
168
- | `comment-change` | `{ dataIndex, colKey, text }` |
171
+ | `comment-change` | `{ dataIndex, id, colKey, text }` |
169
172
  | `data-import` | `{ count }` |
170
173
  | `undo-state-change` | `{ canUndo, canRedo }` |
171
174
  | `context-menu` | `{ x, y, row, col, key, value, rowData }` — cancelable; `preventDefault()` suppresses the built-in menu |
@@ -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>