@ixfx/components 0.7.3 → 0.7.5
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/bundle/index.d.ts +1355 -526
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +3277 -384
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.d.ts +1 -1
- package/dist/ac-text.js +1 -1
- package/dist/{ac-token-TCLAZeVg.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
- package/dist/{ac-token-TCLAZeVg.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
- package/dist/ac-token.d.ts +1 -1
- package/dist/ac-token.js +2 -2
- package/dist/button.d.ts +1 -1
- package/dist/button.d.ts.map +1 -1
- package/dist/colour-picker.d.ts +1 -1
- package/dist/crumbs.d.ts +6 -2
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +13 -3
- package/dist/crumbs.js.map +1 -1
- package/dist/{data-grid-Db4QpnII.d.ts → data-grid-CtJ35v8L.d.ts} +59 -2
- package/dist/data-grid-CtJ35v8L.d.ts.map +1 -0
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +268 -14
- package/dist/data-grid.js.map +1 -1
- package/dist/detail-list-BS5dRDda.d.ts +175 -0
- package/dist/detail-list-BS5dRDda.d.ts.map +1 -0
- package/dist/detail-list.d.ts +3 -0
- package/dist/detail-list.js +1031 -0
- package/dist/detail-list.js.map +1 -0
- package/dist/grid-list-D-GbghSH.d.ts +321 -0
- package/dist/grid-list-D-GbghSH.d.ts.map +1 -0
- package/dist/grid-list.d.ts +3 -0
- package/dist/grid-list.js +994 -0
- package/dist/grid-list.js.map +1 -0
- package/dist/{grouped-item-lister-BWlC9S4e.d.ts → grouped-item-lister-fdZHVxFM.d.ts} +3 -3
- package/dist/{grouped-item-lister-BWlC9S4e.d.ts.map → grouped-item-lister-fdZHVxFM.d.ts.map} +1 -1
- package/dist/grouped-item-lister.d.ts +1 -1
- package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +2 -2
- package/dist/icon-CDGprSdE.d.ts.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/incr-search-DpbSJtgj.js +962 -0
- package/dist/incr-search-DpbSJtgj.js.map +1 -0
- package/dist/incr-search.d.ts +2 -2
- package/dist/incr-search.js +2 -3
- package/dist/{index-C59-JEPl.d.ts → index-9AhaHIT2.d.ts} +3 -3
- package/dist/{index-C59-JEPl.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
- package/dist/index-CBS4z1v-.d.ts +365 -0
- package/dist/index-CBS4z1v-.d.ts.map +1 -0
- package/dist/{index-DsjpDksO.d.ts → index-CS9yM8L-.d.ts} +2 -2
- package/dist/{index-DsjpDksO.d.ts.map → index-CS9yM8L-.d.ts.map} +1 -1
- package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +2 -2
- package/dist/{index-BUB5SICW.d.ts.map → index-CoqtMSd9.d.ts.map} +1 -1
- package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +2 -2
- package/dist/{index-CJ5fshD3.d.ts.map → index-UvnoZUAo.d.ts.map} +1 -1
- package/dist/{index-BOUaDIW-.d.ts → index-tq6f8007.d.ts} +2 -2
- package/dist/{index-BOUaDIW-.d.ts.map → index-tq6f8007.d.ts.map} +1 -1
- package/dist/index.d.ts +188 -243
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +376 -1004
- package/dist/index.js.map +1 -1
- package/dist/interaction-Cr13azbM.js +3 -0
- package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -2
- package/dist/{labelled-input-base-Dp_9KP0G.d.ts.map → labelled-input-base-DiTme1JO.d.ts.map} +1 -1
- package/dist/labelled-radial-input.d.ts +2 -2
- package/dist/labelled-radial-input.d.ts.map +1 -1
- package/dist/labelled-range-input.d.ts +1 -1
- package/dist/labelled-slider-input.d.ts +1 -1
- package/dist/list-item-animation-DuiwgN3l.js +112 -0
- package/dist/list-item-animation-DuiwgN3l.js.map +1 -0
- package/dist/list-selection-controller-DTFI40li.js +264 -0
- package/dist/list-selection-controller-DTFI40li.js.map +1 -0
- package/dist/{list-selection-types-DSuRNWpx.d.ts → list-selection-types-B5ioL-dG.d.ts} +6 -1
- package/dist/list-selection-types-B5ioL-dG.d.ts.map +1 -0
- package/dist/{menu-DMzjkVnK.js → menu-Bg90Qr0B.js} +3 -3
- package/dist/{menu-DMzjkVnK.js.map → menu-Bg90Qr0B.js.map} +1 -1
- package/dist/{menu-item-D2S4i8u1.js → menu-item-Bx-Fs7jq.js} +3 -3
- package/dist/{menu-item-D2S4i8u1.js.map → menu-item-Bx-Fs7jq.js.map} +1 -1
- package/dist/{menu-item-ZmkXNjek.d.ts → menu-item-CZi9vy5O.d.ts} +2 -2
- package/dist/{menu-item-ZmkXNjek.d.ts.map → menu-item-CZi9vy5O.d.ts.map} +1 -1
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +82 -4
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +329 -70
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.js +3 -4
- package/dist/narrowed-text.js.map +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/plots.js +1 -1
- package/dist/select-horiz.js +2 -2
- package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-JK3xWVX2.d.ts} +2 -2
- package/dist/{split-layout-C5SYbDrq.d.ts.map → split-layout-JK3xWVX2.d.ts.map} +1 -1
- package/dist/split-layout.d.ts +1 -1
- package/dist/{tab-list-DbMIL520.d.ts → tab-list-CGyPt07Z.d.ts} +2 -2
- package/dist/{tab-list-DbMIL520.d.ts.map → tab-list-CGyPt07Z.d.ts.map} +1 -1
- package/dist/tabs.d.ts +1 -1
- package/dist/{tickled-controller-Ds1DMyG7.d.ts → tickled-controller-Bn3YdQsM.d.ts} +12 -1
- package/dist/{tickled-controller-Ds1DMyG7.d.ts.map → tickled-controller-Bn3YdQsM.d.ts.map} +1 -1
- package/dist/{tickled-controller-h9GmJ_bU.js → tickled-controller-C66DgJHl.js} +16 -1
- package/dist/tickled-controller-C66DgJHl.js.map +1 -0
- package/dist/{titlebar-B23MrIbI.d.ts → titlebar-Bj5pfdw_.d.ts} +2 -2
- package/dist/{titlebar-B23MrIbI.d.ts.map → titlebar-Bj5pfdw_.d.ts.map} +1 -1
- package/dist/titlebar.d.ts +1 -1
- package/dist/{tree-Ch4W8qXQ.js → tree-DAii2A1g.js} +190 -29
- package/dist/tree-DAii2A1g.js.map +1 -0
- package/dist/{tree-component-BvV4muxx.d.ts → tree-component-F6qZ0Gdv.d.ts} +9 -1
- package/dist/{tree-component-BvV4muxx.d.ts.map → tree-component-F6qZ0Gdv.d.ts.map} +1 -1
- package/dist/tree.d.ts +28 -4
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/vertical-list-DwtCPy1b.d.ts +143 -0
- package/dist/vertical-list-DwtCPy1b.d.ts.map +1 -0
- package/dist/vertical-list.d.ts +3 -121
- package/dist/vertical-list.js +642 -1
- package/dist/vertical-list.js.map +1 -0
- package/dist/{xy-axis-DWizs0bt.js → xy-axis-VrX8dmvS.js} +2 -2
- package/dist/{xy-axis-DWizs0bt.js.map → xy-axis-VrX8dmvS.js.map} +1 -1
- package/docs-user/README.md +1 -0
- package/docs-user/data-grid.md +70 -2
- package/docs-user/detail-list.md +39 -1
- package/docs-user/grid-list.md +298 -0
- package/docs-user/incr-search.md +12 -2
- package/docs-user/index.json +7 -2
- package/docs-user/llms.txt +1 -0
- package/docs-user/tree.md +35 -1
- package/docs-user/vertical-list.md +58 -2
- package/llms.txt +1 -0
- package/package.json +17 -2
- package/dist/data-grid-Db4QpnII.d.ts.map +0 -1
- package/dist/element-search-Y8SRfPGM.js +0 -185
- package/dist/element-search-Y8SRfPGM.js.map +0 -1
- package/dist/icon-DR_3rSyZ.d.ts.map +0 -1
- package/dist/incr-search-vCzuao-2.js +0 -137
- package/dist/incr-search-vCzuao-2.js.map +0 -1
- package/dist/index-Cu5i8zZY.d.ts +0 -160
- package/dist/index-Cu5i8zZY.d.ts.map +0 -1
- package/dist/interaction-D5XdKzbR.js +0 -2
- package/dist/list-selection-types-DSuRNWpx.d.ts.map +0 -1
- package/dist/tickled-controller-h9GmJ_bU.js.map +0 -1
- package/dist/tree-Ch4W8qXQ.js.map +0 -1
- package/dist/vertical-list-B4w_ksJk.js +0 -814
- package/dist/vertical-list-B4w_ksJk.js.map +0 -1
- package/dist/vertical-list.d.ts.map +0 -1
package/dist/data-grid.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { t as TickledController } from "./tickled-controller-
|
|
1
|
+
import { t as TickledController } from "./tickled-controller-C66DgJHl.js";
|
|
2
2
|
import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
|
|
3
3
|
import { t as themeFallbacks } from "./fallbacks-DNI9xt0F.js";
|
|
4
4
|
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
5
|
-
import "./
|
|
5
|
+
import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES } from "./incr-search-DpbSJtgj.js";
|
|
6
|
+
import { i as listItemFadeKeyframes } from "./list-item-animation-DuiwgN3l.js";
|
|
7
|
+
import "./interaction-Cr13azbM.js";
|
|
6
8
|
import { t as createDragGhost } from "./drag-ghost-DtSDvjri.js";
|
|
7
|
-
import "./menu-
|
|
9
|
+
import "./menu-Bg90Qr0B.js";
|
|
8
10
|
import { LitElement, css, html, nothing } from "lit";
|
|
9
11
|
import { property, query, state } from "lit/decorators.js";
|
|
12
|
+
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
10
13
|
import { repeat } from "lit/directives/repeat.js";
|
|
11
14
|
//#region src/data-grid/data-grid.ts
|
|
12
15
|
let DataGridElement = class DataGridElement extends LitElement {
|
|
@@ -24,6 +27,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
24
27
|
this.groupBy = null;
|
|
25
28
|
this.allowGrouping = false;
|
|
26
29
|
this.crossGroupSelection = false;
|
|
30
|
+
this.columnMenu = `auto`;
|
|
27
31
|
this._columnFormatters = /* @__PURE__ */ new Map();
|
|
28
32
|
this._selectedKeys = /* @__PURE__ */ new Set();
|
|
29
33
|
this._scrollTop = 0;
|
|
@@ -46,10 +50,18 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
46
50
|
this._sortedRows = [];
|
|
47
51
|
this._flat = [];
|
|
48
52
|
this._flatKeys = [];
|
|
53
|
+
this.#searchKeyByRow = /* @__PURE__ */ new Map();
|
|
54
|
+
this.search = new ListSearchController(this, { adapter: this.#createSearchAdapter() });
|
|
55
|
+
this.#prevFlatKeys = [];
|
|
56
|
+
this.#enteringRowKeys = /* @__PURE__ */ new Set();
|
|
57
|
+
this.#rowReflowTimer = 0;
|
|
58
|
+
this.#dataGridRenderedOnce = false;
|
|
49
59
|
this._visibleColumns = [];
|
|
50
60
|
this._colOffsets = [];
|
|
51
61
|
this._colWidthSum = 0;
|
|
52
62
|
this._raf = 0;
|
|
63
|
+
this.#appendInProgress = false;
|
|
64
|
+
this.#resortRaf = 0;
|
|
53
65
|
this._drag = null;
|
|
54
66
|
this._onFocusOut = (e) => {
|
|
55
67
|
if (this._suppressBlurCommit) return;
|
|
@@ -244,6 +256,8 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
244
256
|
themeFallbacks,
|
|
245
257
|
tickledStyles,
|
|
246
258
|
tickledItemStyles,
|
|
259
|
+
listItemFadeKeyframes,
|
|
260
|
+
listSearchStyles,
|
|
247
261
|
css`
|
|
248
262
|
:host {
|
|
249
263
|
--data-grid-row-height: 28px;
|
|
@@ -252,6 +266,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
252
266
|
--data-grid-header-bg: var(--surface-2);
|
|
253
267
|
--data-grid-border: var(--border);
|
|
254
268
|
--data-grid-header-text: var(--surface-3-text);
|
|
269
|
+
position: relative;
|
|
255
270
|
display: block;
|
|
256
271
|
overflow: hidden;
|
|
257
272
|
border: var(--data-grid-border);
|
|
@@ -300,6 +315,22 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
300
315
|
.row.item.tickled { background: var(--item-bg-tickled); border: var(--item-border-tickled); color: var(--item-text-tickled); }
|
|
301
316
|
.row.item.selected { background: var(--item-bg-selected); border: var(--item-border-selected); color: var(--item-text-selected); }
|
|
302
317
|
.row.item.selected.tickled { background: var(--item-bg-selected-tickled); }
|
|
318
|
+
|
|
319
|
+
/* Insertion / removal animation. Only while [reflowing] — the ~0.3s after
|
|
320
|
+
the row set changes — do rows slide (their top transitions) to make or
|
|
321
|
+
close a gap; a freshly inserted row also fades in. Kept scoped so it
|
|
322
|
+
never fires while scrolling the virtualised list. */
|
|
323
|
+
:host([reflowing]) .row.item,
|
|
324
|
+
:host([reflowing]) .group-row {
|
|
325
|
+
transition: top var(--data-grid-row-move-duration, 200ms) cubic-bezier(0.2, 0, 0, 1);
|
|
326
|
+
}
|
|
327
|
+
.row.item.entering {
|
|
328
|
+
animation: ixfx-list-item-in var(--data-grid-row-move-duration, 200ms) ease both;
|
|
329
|
+
}
|
|
330
|
+
@media (prefers-reduced-motion: reduce) {
|
|
331
|
+
:host([reflowing]) .row.item, :host([reflowing]) .group-row { transition: none; }
|
|
332
|
+
.row.item.entering { animation: none; }
|
|
333
|
+
}
|
|
303
334
|
.cell {
|
|
304
335
|
flex-shrink: 0; display: flex; align-items: center; padding: 0 var(--space-s);
|
|
305
336
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-right: var(--border-subtle);
|
|
@@ -329,17 +360,89 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
329
360
|
`
|
|
330
361
|
];
|
|
331
362
|
}
|
|
363
|
+
#searchRegistry;
|
|
364
|
+
#unregisterSearchCommands;
|
|
365
|
+
#searchKeyByRow;
|
|
366
|
+
/** Command registry carrying this grid's `list.search.*` commands. */
|
|
367
|
+
get registry() {
|
|
368
|
+
return this.#searchRegistry;
|
|
369
|
+
}
|
|
370
|
+
#rowSearchText(row) {
|
|
371
|
+
if (this.rowSearchText) return this.rowSearchText(row);
|
|
372
|
+
const rec = row;
|
|
373
|
+
return this._visibleColumns.map((c) => String(rec[c.key] ?? ``)).join(` `);
|
|
374
|
+
}
|
|
375
|
+
#createSearchAdapter() {
|
|
376
|
+
return {
|
|
377
|
+
getItems: () => {
|
|
378
|
+
this.#searchKeyByRow.clear();
|
|
379
|
+
this._sortedRows.forEach((r, i) => this.#searchKeyByRow.set(r, this.getRowKey(r, i)));
|
|
380
|
+
return this._sortedRows;
|
|
381
|
+
},
|
|
382
|
+
getLabel: (row) => this.#rowSearchText(row),
|
|
383
|
+
getKey: (row) => this.#searchKeyByRow.get(row) ?? String(this._sortedRows.indexOf(row)),
|
|
384
|
+
focusItem: (row) => {
|
|
385
|
+
if (row === void 0) return;
|
|
386
|
+
const key = this.#searchKeyByRow.get(row);
|
|
387
|
+
if (key !== void 0) this.tickleRow(key);
|
|
388
|
+
},
|
|
389
|
+
selectItems: (rows) => {
|
|
390
|
+
this.selectKeys(rows.map((r) => this.#searchKeyByRow.get(r)).filter((k) => k !== void 0));
|
|
391
|
+
},
|
|
392
|
+
applyFilter: (matched) => {
|
|
393
|
+
this.filterPredicate = matched === void 0 ? void 0 : (row) => {
|
|
394
|
+
const k = this.#searchKeyByRow.get(row);
|
|
395
|
+
return k === void 0 || matched.has(k);
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
#effectiveSearchModes() {
|
|
401
|
+
const raw = this.searchModes?.trim();
|
|
402
|
+
if (raw === void 0) return [...LIST_SEARCH_MODES];
|
|
403
|
+
const requested = new Set(raw.split(/\s+/));
|
|
404
|
+
return LIST_SEARCH_MODES.filter((m) => requested.has(m));
|
|
405
|
+
}
|
|
406
|
+
#syncSearchCommands() {
|
|
407
|
+
if (!this.#searchRegistry) return;
|
|
408
|
+
this.search.setModes(this.#effectiveSearchModes());
|
|
409
|
+
this.#unregisterSearchCommands?.();
|
|
410
|
+
this.#unregisterSearchCommands = registerListSearchCommands(this.#searchRegistry, this.search);
|
|
411
|
+
}
|
|
412
|
+
/** Row-key snapshot from the previous update, for the insertion / removal animation. */
|
|
413
|
+
#prevFlatKeys;
|
|
414
|
+
#enteringRowKeys;
|
|
415
|
+
#rowReflowTimer;
|
|
416
|
+
#dataGridRenderedOnce;
|
|
417
|
+
#appendInProgress;
|
|
418
|
+
#resortRaf;
|
|
332
419
|
connectedCallback() {
|
|
333
420
|
super.connectedCallback();
|
|
334
421
|
if (!this.hasAttribute(`tabindex`)) this.tabIndex = 0;
|
|
335
422
|
this.addEventListener(`keydown`, this._onKeyDown);
|
|
336
423
|
this.addEventListener(`focusout`, this._onFocusOut);
|
|
424
|
+
this.#searchRegistry ??= createCommandRegistry();
|
|
425
|
+
this.#syncSearchCommands();
|
|
337
426
|
}
|
|
338
427
|
disconnectedCallback() {
|
|
339
428
|
super.disconnectedCallback();
|
|
340
429
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
341
430
|
this.removeEventListener(`focusout`, this._onFocusOut);
|
|
342
431
|
cancelAnimationFrame(this._raf);
|
|
432
|
+
this.#unregisterSearchCommands?.();
|
|
433
|
+
this.#unregisterSearchCommands = void 0;
|
|
434
|
+
this.#searchRegistry = void 0;
|
|
435
|
+
if (this.#rowReflowTimer) {
|
|
436
|
+
clearTimeout(this.#rowReflowTimer);
|
|
437
|
+
this.#rowReflowTimer = 0;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Dispatch a command to this grid — routes through the command registry so
|
|
442
|
+
* `list.search.*` (and any other registered commands) work.
|
|
443
|
+
*/
|
|
444
|
+
dispatch(commandId, args) {
|
|
445
|
+
this.#searchRegistry?.invoke(commandId, args);
|
|
343
446
|
}
|
|
344
447
|
firstUpdated() {
|
|
345
448
|
new ResizeObserver(() => {
|
|
@@ -366,8 +469,11 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
366
469
|
willUpdate(changed) {
|
|
367
470
|
super.willUpdate(changed);
|
|
368
471
|
this.setAttribute(`data-input-mode`, this._tickled.inputMode);
|
|
369
|
-
if (changed.has(`
|
|
370
|
-
this
|
|
472
|
+
if (changed.has(`searchModes`)) this.#syncSearchCommands();
|
|
473
|
+
if (!this.#appendInProgress) {
|
|
474
|
+
if (changed.has(`rows`) || changed.has(`sortState`) || changed.has(`columns`) || changed.has(`groupBy`) || changed.has(`groupLabel`)) this._sortedRows = this._applySort([...this.rows]);
|
|
475
|
+
this._rebuildFlat();
|
|
476
|
+
}
|
|
371
477
|
this._visibleColumns = this.columns.filter((c) => c.visible !== false);
|
|
372
478
|
let off = 0;
|
|
373
479
|
this._colOffsets = this._visibleColumns.map((c) => {
|
|
@@ -377,6 +483,40 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
377
483
|
});
|
|
378
484
|
this._colWidthSum = off;
|
|
379
485
|
if (this.interactionMode === `checked`) this._colWidthSum += 28;
|
|
486
|
+
this.#noteFlatMutation();
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Diff the row-key list against the previous update. Rows that appeared get an
|
|
490
|
+
* enter fade; any add/remove opens a short `[reflowing]` window so the rows
|
|
491
|
+
* that shift slide (their `top` transitions) instead of snapping. Bounded in
|
|
492
|
+
* time so it never bleeds into scroll virtualisation.
|
|
493
|
+
*/
|
|
494
|
+
#noteFlatMutation() {
|
|
495
|
+
const now = this._flatKeys;
|
|
496
|
+
const prev = this.#prevFlatKeys;
|
|
497
|
+
this.#prevFlatKeys = now.slice();
|
|
498
|
+
if (!this.#dataGridRenderedOnce) {
|
|
499
|
+
this.#dataGridRenderedOnce = true;
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (prev.length === 0 || now.length === 0) {
|
|
503
|
+
this.#enteringRowKeys.clear();
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const before = new Set(prev);
|
|
507
|
+
const after = new Set(now);
|
|
508
|
+
const added = now.filter((k) => !before.has(k));
|
|
509
|
+
const removed = prev.filter((k) => !after.has(k));
|
|
510
|
+
if (added.length === now.length || added.length === 0 && removed.length === 0) return;
|
|
511
|
+
this.#enteringRowKeys = new Set(added);
|
|
512
|
+
this.toggleAttribute(`reflowing`, true);
|
|
513
|
+
if (this.#rowReflowTimer) clearTimeout(this.#rowReflowTimer);
|
|
514
|
+
this.#rowReflowTimer = window.setTimeout(() => {
|
|
515
|
+
this.#rowReflowTimer = 0;
|
|
516
|
+
this.#enteringRowKeys.clear();
|
|
517
|
+
this.toggleAttribute(`reflowing`, false);
|
|
518
|
+
this.requestUpdate();
|
|
519
|
+
}, 320);
|
|
380
520
|
}
|
|
381
521
|
_getGroupKey(row) {
|
|
382
522
|
if (!this.groupBy) return null;
|
|
@@ -384,18 +524,23 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
384
524
|
return String(this.groupBy(row));
|
|
385
525
|
}
|
|
386
526
|
_rebuildFlat() {
|
|
527
|
+
const filtered = this.filterPredicate !== void 0;
|
|
528
|
+
const source = filtered ? this._sortedRows.filter((r) => this.filterPredicate(r)) : this._sortedRows;
|
|
387
529
|
if (!this.groupBy) {
|
|
388
|
-
this._flat =
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
530
|
+
this._flat = source.map((r, i) => {
|
|
531
|
+
const idx = filtered ? this._sortedRows.indexOf(r) : i;
|
|
532
|
+
return {
|
|
533
|
+
type: `row`,
|
|
534
|
+
key: this.getRowKey(r, idx),
|
|
535
|
+
row: r,
|
|
536
|
+
idx
|
|
537
|
+
};
|
|
538
|
+
});
|
|
394
539
|
this._flatKeys = this._flat.map((f) => f.key);
|
|
395
540
|
return;
|
|
396
541
|
}
|
|
397
542
|
const groups = /* @__PURE__ */ new Map();
|
|
398
|
-
for (const r of
|
|
543
|
+
for (const r of source) {
|
|
399
544
|
const k = this._getGroupKey(r) ?? ``;
|
|
400
545
|
const arr = groups.get(k);
|
|
401
546
|
if (arr) arr.push(r);
|
|
@@ -624,6 +769,102 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
624
769
|
_getRowForKey(key) {
|
|
625
770
|
return this._flat.find((f) => f.key === key)?.row;
|
|
626
771
|
}
|
|
772
|
+
/** The selected row keys (read-only). */
|
|
773
|
+
get selectedKeys() {
|
|
774
|
+
return this._selectedKeys;
|
|
775
|
+
}
|
|
776
|
+
/** Replace the selection with these row keys (clamped to known rows). */
|
|
777
|
+
set selectedKeys(keys) {
|
|
778
|
+
this.selectKeys(keys);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Replace the selection with the given row keys. Unknown keys are dropped;
|
|
782
|
+
* in a single-select mode only the last surviving key is kept;
|
|
783
|
+
* `selectionMode="none"` clears. Fires `datagrid-select` with the previous
|
|
784
|
+
* set when the selection actually changes.
|
|
785
|
+
*/
|
|
786
|
+
selectKeys(keys) {
|
|
787
|
+
const known = new Set(this._flat.filter((f) => f.type === `row`).map((f) => f.key));
|
|
788
|
+
let next = new Set([...keys].filter((k) => known.has(k)));
|
|
789
|
+
const multi = this.selectionMode === `multiple` || this.interactionMode === `checked` || this.interactionMode === `sticky` || this.interactionMode === `vscode`;
|
|
790
|
+
if (this.selectionMode === `none`) next = /* @__PURE__ */ new Set();
|
|
791
|
+
else if (!multi && next.size > 1) {
|
|
792
|
+
const last = [...next].at(-1);
|
|
793
|
+
next = last === void 0 ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([last]);
|
|
794
|
+
}
|
|
795
|
+
const prev = new Set(this._selectedKeys);
|
|
796
|
+
if (prev.size === next.size && [...next].every((k) => prev.has(k))) return;
|
|
797
|
+
this._selectedKeys = next;
|
|
798
|
+
this._anchorKey = [...next].at(-1);
|
|
799
|
+
this.dispatchEvent(new CustomEvent(`datagrid-select`, {
|
|
800
|
+
detail: {
|
|
801
|
+
selectedKeys: new Set(next),
|
|
802
|
+
previous: prev
|
|
803
|
+
},
|
|
804
|
+
bubbles: true,
|
|
805
|
+
composed: true
|
|
806
|
+
}));
|
|
807
|
+
}
|
|
808
|
+
/** The row key under the cursor, or `undefined`. */
|
|
809
|
+
get tickledKey() {
|
|
810
|
+
return this._tickled.tickledId;
|
|
811
|
+
}
|
|
812
|
+
/** Move the cursor to this row key and scroll it into view. */
|
|
813
|
+
tickleRow(key) {
|
|
814
|
+
if (!this._flatKeys.includes(key)) return;
|
|
815
|
+
this._tickled.focus(key);
|
|
816
|
+
this._scrollRowIntoView(key);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Append rows without the full O(n log n) rebuild that reassigning `rows`
|
|
820
|
+
* incurs. `rows` still gets a new array reference (reactivity is preserved),
|
|
821
|
+
* but the derived arrays are extended over the appended slice only. When a
|
|
822
|
+
* sort is active the new rows show unsorted for one frame, then a single
|
|
823
|
+
* coalesced re-sort runs. Scroll position, selection and cursor are kept.
|
|
824
|
+
*/
|
|
825
|
+
appendRows(rows) {
|
|
826
|
+
if (rows.length === 0) return;
|
|
827
|
+
const startIdx = this.rows.length;
|
|
828
|
+
this.#appendInProgress = true;
|
|
829
|
+
this.rows = [...this.rows, ...rows];
|
|
830
|
+
const appended = this.rows.slice(startIdx);
|
|
831
|
+
if (this._sortedRows.length === startIdx) this._sortedRows = [...this._sortedRows, ...appended];
|
|
832
|
+
else {
|
|
833
|
+
this._sortedRows = this._applySort([...this.rows]);
|
|
834
|
+
this._rebuildFlat();
|
|
835
|
+
this.#appendInProgress = false;
|
|
836
|
+
this.requestUpdate();
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
this.#appendToFlat(appended, startIdx);
|
|
840
|
+
this.#appendInProgress = false;
|
|
841
|
+
this.requestUpdate();
|
|
842
|
+
if (this.sortState != null) {
|
|
843
|
+
cancelAnimationFrame(this.#resortRaf);
|
|
844
|
+
this.#resortRaf = requestAnimationFrame(() => {
|
|
845
|
+
this._sortedRows = this._applySort([...this.rows]);
|
|
846
|
+
this._rebuildFlat();
|
|
847
|
+
this.requestUpdate();
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
#appendToFlat(appended, startIdx) {
|
|
852
|
+
if (this.groupBy) {
|
|
853
|
+
this._rebuildFlat();
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
for (let j = 0; j < appended.length; j++) {
|
|
857
|
+
const idx = startIdx + j;
|
|
858
|
+
const key = this.getRowKey(appended[j], idx);
|
|
859
|
+
this._flat.push({
|
|
860
|
+
type: `row`,
|
|
861
|
+
key,
|
|
862
|
+
row: appended[j],
|
|
863
|
+
idx
|
|
864
|
+
});
|
|
865
|
+
this._flatKeys.push(key);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
627
868
|
_replaceSelection(key) {
|
|
628
869
|
if (this.selectionMode === `none`) return;
|
|
629
870
|
const prev = new Set(this._selectedKeys);
|
|
@@ -979,6 +1220,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
979
1220
|
return last >= 0 ? this._colOffsets[last] + (this._visibleColumns[last].width ?? 150) : 0;
|
|
980
1221
|
})()}px"></div>` : nothing}
|
|
981
1222
|
</div>
|
|
1223
|
+
${this.columnMenu === `none` ? nothing : html`
|
|
982
1224
|
<ixfx-menu-trigger label="⚙" placement="bottom-end" @menu-command=${(e) => {
|
|
983
1225
|
const cmd = e.detail.command;
|
|
984
1226
|
const checked = e.detail.checked;
|
|
@@ -1018,7 +1260,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
1018
1260
|
</ixfx-menu-radio-group>
|
|
1019
1261
|
` : nothing}
|
|
1020
1262
|
</ixfx-menu-container>
|
|
1021
|
-
</ixfx-menu-trigger
|
|
1263
|
+
</ixfx-menu-trigger>`}
|
|
1022
1264
|
</div>
|
|
1023
1265
|
<div class="viewport" @scroll=${this._onScroll}>
|
|
1024
1266
|
<div class="spacer" style="height:${this._flat.length * rh}px; width:${this._colWidthSum}px">
|
|
@@ -1035,7 +1277,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
1035
1277
|
const selected = this._selectedKeys.has(rowKey);
|
|
1036
1278
|
const tickled = this._tickled.isTickled(rowKey);
|
|
1037
1279
|
return html`
|
|
1038
|
-
<div class="row item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``}" style="top:${absIdx * rh}px; height:${rh}px"
|
|
1280
|
+
<div class="row item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${this.#enteringRowKeys.has(rowKey) ? `entering` : ``}" style="top:${absIdx * rh}px; height:${rh}px"
|
|
1039
1281
|
data-key=${rowKey}
|
|
1040
1282
|
@click=${(e) => {
|
|
1041
1283
|
this._onRowClick(rowKey, null, e);
|
|
@@ -1168,6 +1410,7 @@ let DataGridElement = class DataGridElement extends LitElement {
|
|
|
1168
1410
|
})}
|
|
1169
1411
|
</div>
|
|
1170
1412
|
</div>
|
|
1413
|
+
${this.search.renderField()}
|
|
1171
1414
|
</div>
|
|
1172
1415
|
`;
|
|
1173
1416
|
}
|
|
@@ -1206,7 +1449,18 @@ __decorate([property({
|
|
|
1206
1449
|
attribute: `cross-group-selection`,
|
|
1207
1450
|
reflect: true
|
|
1208
1451
|
})], DataGridElement.prototype, "crossGroupSelection", void 0);
|
|
1452
|
+
__decorate([property({
|
|
1453
|
+
type: String,
|
|
1454
|
+
attribute: `column-menu`
|
|
1455
|
+
})], DataGridElement.prototype, "columnMenu", void 0);
|
|
1209
1456
|
__decorate([property({ attribute: false })], DataGridElement.prototype, "globalFormatter", void 0);
|
|
1457
|
+
__decorate([property({ attribute: false })], DataGridElement.prototype, "filterPredicate", void 0);
|
|
1458
|
+
__decorate([property({ attribute: false })], DataGridElement.prototype, "rowSearchText", void 0);
|
|
1459
|
+
__decorate([property({
|
|
1460
|
+
type: String,
|
|
1461
|
+
attribute: `search-modes`,
|
|
1462
|
+
reflect: true
|
|
1463
|
+
})], DataGridElement.prototype, "searchModes", void 0);
|
|
1210
1464
|
__decorate([state()], DataGridElement.prototype, "_selectedKeys", void 0);
|
|
1211
1465
|
__decorate([state()], DataGridElement.prototype, "_scrollTop", void 0);
|
|
1212
1466
|
__decorate([state()], DataGridElement.prototype, "_scrollLeft", void 0);
|