@toolbox-web/grid 0.0.3 → 0.0.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.
Files changed (63) hide show
  1. package/all.d.ts +50 -6
  2. package/all.js +101 -98
  3. package/all.js.map +1 -1
  4. package/index.d.ts +54 -0
  5. package/index.js +793 -692
  6. package/index.js.map +1 -1
  7. package/lib/plugins/clipboard/index.js +55 -35
  8. package/lib/plugins/clipboard/index.js.map +1 -1
  9. package/lib/plugins/column-virtualization/index.js +49 -29
  10. package/lib/plugins/column-virtualization/index.js.map +1 -1
  11. package/lib/plugins/context-menu/index.js +35 -15
  12. package/lib/plugins/context-menu/index.js.map +1 -1
  13. package/lib/plugins/export/index.js +52 -32
  14. package/lib/plugins/export/index.js.map +1 -1
  15. package/lib/plugins/filtering/index.js +116 -99
  16. package/lib/plugins/filtering/index.js.map +1 -1
  17. package/lib/plugins/grouping-columns/index.js +42 -22
  18. package/lib/plugins/grouping-columns/index.js.map +1 -1
  19. package/lib/plugins/grouping-rows/index.js +20 -0
  20. package/lib/plugins/grouping-rows/index.js.map +1 -1
  21. package/lib/plugins/master-detail/index.js +50 -27
  22. package/lib/plugins/master-detail/index.js.map +1 -1
  23. package/lib/plugins/multi-sort/index.js +25 -5
  24. package/lib/plugins/multi-sort/index.js.map +1 -1
  25. package/lib/plugins/pinned-columns/index.js +20 -0
  26. package/lib/plugins/pinned-columns/index.js.map +1 -1
  27. package/lib/plugins/pinned-rows/index.js +20 -0
  28. package/lib/plugins/pinned-rows/index.js.map +1 -1
  29. package/lib/plugins/pivot/index.js +20 -0
  30. package/lib/plugins/pivot/index.js.map +1 -1
  31. package/lib/plugins/reorder/index.js +56 -33
  32. package/lib/plugins/reorder/index.js.map +1 -1
  33. package/lib/plugins/selection/index.js +138 -100
  34. package/lib/plugins/selection/index.js.map +1 -1
  35. package/lib/plugins/server-side/index.js +20 -0
  36. package/lib/plugins/server-side/index.js.map +1 -1
  37. package/lib/plugins/tree/index.js +76 -53
  38. package/lib/plugins/tree/index.js.map +1 -1
  39. package/lib/plugins/undo-redo/index.js +20 -0
  40. package/lib/plugins/undo-redo/index.js.map +1 -1
  41. package/lib/plugins/visibility/index.js +20 -0
  42. package/lib/plugins/visibility/index.js.map +1 -1
  43. package/package.json +4 -1
  44. package/themes/dg-theme-contrast.css +43 -43
  45. package/themes/dg-theme-large.css +54 -54
  46. package/themes/dg-theme-standard.css +19 -19
  47. package/themes/dg-theme-vibrant.css +16 -16
  48. package/umd/grid.all.umd.js +24 -24
  49. package/umd/grid.all.umd.js.map +1 -1
  50. package/umd/grid.umd.js +14 -14
  51. package/umd/grid.umd.js.map +1 -1
  52. package/umd/plugins/filtering.umd.js +3 -3
  53. package/umd/plugins/filtering.umd.js.map +1 -1
  54. package/umd/plugins/master-detail.umd.js +2 -2
  55. package/umd/plugins/master-detail.umd.js.map +1 -1
  56. package/umd/plugins/multi-sort.umd.js.map +1 -1
  57. package/umd/plugins/reorder.umd.js +1 -1
  58. package/umd/plugins/reorder.umd.js.map +1 -1
  59. package/umd/plugins/selection.umd.js +2 -2
  60. package/umd/plugins/selection.umd.js.map +1 -1
  61. package/umd/plugins/tree.umd.js +2 -2
  62. package/umd/plugins/tree.umd.js.map +1 -1
  63. package/umd/plugins/visibility.umd.js.map +1 -1
@@ -1,4 +1,4 @@
1
- class w {
1
+ class f {
2
2
  /** Plugin version - override in subclass if needed */
3
3
  version = "1.0.0";
4
4
  /** CSS styles to inject into the grid's shadow DOM */
@@ -97,6 +97,26 @@ class w {
97
97
  get shadowRoot() {
98
98
  return this.grid?.shadowRoot ?? null;
99
99
  }
100
+ /**
101
+ * Get the disconnect signal for event listener cleanup.
102
+ * This signal is aborted when the grid disconnects from the DOM.
103
+ * Use this when adding event listeners that should be cleaned up automatically.
104
+ *
105
+ * Best for:
106
+ * - Document/window-level listeners added in attach()
107
+ * - Listeners on the grid element itself
108
+ * - Any listener that should persist across renders
109
+ *
110
+ * Not needed for:
111
+ * - Listeners on elements created in afterRender() (removed with element)
112
+ *
113
+ * @example
114
+ * element.addEventListener('click', handler, { signal: this.disconnectSignal });
115
+ * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
116
+ */
117
+ get disconnectSignal() {
118
+ return this.grid?.disconnectSignal;
119
+ }
100
120
  /**
101
121
  * Log a warning message.
102
122
  */
@@ -104,7 +124,7 @@ class w {
104
124
  console.warn(`[tbw-grid:${this.name}] ${e}`);
105
125
  }
106
126
  }
107
- function d(s) {
127
+ function h(s) {
108
128
  return {
109
129
  startRow: Math.min(s.startRow, s.endRow),
110
130
  startCol: Math.min(s.startCol, s.endCol),
@@ -112,38 +132,38 @@ function d(s) {
112
132
  endCol: Math.max(s.startCol, s.endCol)
113
133
  };
114
134
  }
115
- function R(s) {
116
- const e = d(s);
135
+ function w(s) {
136
+ const e = h(s);
117
137
  return {
118
138
  from: { row: e.startRow, col: e.startCol },
119
139
  to: { row: e.endRow, col: e.endCol }
120
140
  };
121
141
  }
122
- function g(s) {
123
- return s.map(R);
142
+ function d(s) {
143
+ return s.map(w);
124
144
  }
125
- function C(s, e, t) {
126
- const r = d(t);
127
- return s >= r.startRow && s <= r.endRow && e >= r.startCol && e <= r.endCol;
145
+ function R(s, e, t) {
146
+ const l = h(t);
147
+ return s >= l.startRow && s <= l.endRow && e >= l.startCol && e <= l.endCol;
128
148
  }
129
- function u(s, e, t) {
130
- return t.some((r) => C(s, e, r));
149
+ function g(s, e, t) {
150
+ return t.some((l) => R(s, e, l));
131
151
  }
132
- function m(s) {
133
- const e = [], t = d(s);
134
- for (let r = t.startRow; r <= t.endRow; r++)
135
- for (let n = t.startCol; n <= t.endCol; n++)
136
- e.push({ row: r, col: n });
152
+ function C(s) {
153
+ const e = [], t = h(s);
154
+ for (let l = t.startRow; l <= t.endRow; l++)
155
+ for (let r = t.startCol; r <= t.endCol; r++)
156
+ e.push({ row: l, col: r });
137
157
  return e;
138
158
  }
139
- function b(s) {
159
+ function m(s) {
140
160
  const e = /* @__PURE__ */ new Map();
141
161
  for (const t of s)
142
- for (const r of m(t))
143
- e.set(`${r.row},${r.col}`, r);
162
+ for (const l of C(t))
163
+ e.set(`${l.row},${l.col}`, l);
144
164
  return [...e.values()];
145
165
  }
146
- function f(s, e) {
166
+ function u(s, e) {
147
167
  return {
148
168
  startRow: s.row,
149
169
  startCol: s.col,
@@ -151,7 +171,7 @@ function f(s, e) {
151
171
  endCol: e.col
152
172
  };
153
173
  }
154
- function A(s, e, t) {
174
+ function b(s, e, t) {
155
175
  if (s === "cell" && e.selectedCell)
156
176
  return {
157
177
  mode: s,
@@ -163,15 +183,15 @@ function A(s, e, t) {
163
183
  ]
164
184
  };
165
185
  if (s === "row" && e.selected.size > 0) {
166
- const r = [...e.selected].map((n) => ({
167
- from: { row: n, col: 0 },
168
- to: { row: n, col: t - 1 }
186
+ const l = [...e.selected].map((r) => ({
187
+ from: { row: r, col: 0 },
188
+ to: { row: r, col: t - 1 }
169
189
  }));
170
- return { mode: s, ranges: r };
190
+ return { mode: s, ranges: l };
171
191
  }
172
- return s === "range" && e.ranges.length > 0 ? { mode: s, ranges: g(e.ranges) } : { mode: s, ranges: [] };
192
+ return s === "range" && e.ranges.length > 0 ? { mode: s, ranges: d(e.ranges) } : { mode: s, ranges: [] };
173
193
  }
174
- class p extends w {
194
+ class v extends f {
175
195
  name = "selection";
176
196
  version = "1.0.0";
177
197
  get defaultConfig() {
@@ -197,32 +217,32 @@ class p extends w {
197
217
  }
198
218
  // ===== Event Handlers =====
199
219
  onCellClick(e) {
200
- const { rowIndex: t, colIndex: r, originalEvent: n } = e, { mode: o } = this.config;
201
- if (o === "cell")
202
- return this.selectedCell = { row: t, col: r }, this.emit("selection-change", this.#e()), this.requestAfterRender(), !1;
203
- if (o === "row")
220
+ const { rowIndex: t, colIndex: l, originalEvent: r } = e, { mode: n } = this.config;
221
+ if (n === "cell")
222
+ return this.selectedCell = { row: t, col: l }, this.emit("selection-change", this.#e()), this.requestAfterRender(), !1;
223
+ if (n === "row")
204
224
  return this.selected.clear(), this.selected.add(t), this.lastSelected = t, this.emit("selection-change", this.#e()), this.requestAfterRender(), !1;
205
- if (o === "range") {
206
- const i = n.shiftKey, a = n.ctrlKey || n.metaKey;
207
- if (i && this.cellAnchor) {
208
- const l = f(this.cellAnchor, { row: t, col: r });
209
- a ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = l : this.ranges.push(l) : this.ranges = [l], this.activeRange = l;
210
- } else if (a) {
211
- const l = {
225
+ if (n === "range") {
226
+ const a = r.shiftKey, i = r.ctrlKey || r.metaKey;
227
+ if (a && this.cellAnchor) {
228
+ const o = u(this.cellAnchor, { row: t, col: l });
229
+ i ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = o : this.ranges.push(o) : this.ranges = [o], this.activeRange = o;
230
+ } else if (i) {
231
+ const o = {
212
232
  startRow: t,
213
- startCol: r,
233
+ startCol: l,
214
234
  endRow: t,
215
- endCol: r
235
+ endCol: l
216
236
  };
217
- this.ranges.push(l), this.activeRange = l, this.cellAnchor = { row: t, col: r };
237
+ this.ranges.push(o), this.activeRange = o, this.cellAnchor = { row: t, col: l };
218
238
  } else {
219
- const l = {
239
+ const o = {
220
240
  startRow: t,
221
- startCol: r,
241
+ startCol: l,
222
242
  endRow: t,
223
- endCol: r
243
+ endCol: l
224
244
  };
225
- this.ranges = [l], this.activeRange = l, this.cellAnchor = { row: t, col: r };
245
+ this.ranges = [o], this.activeRange = o, this.cellAnchor = { row: t, col: l };
226
246
  }
227
247
  return this.emit("selection-change", this.#e()), this.requestAfterRender(), !1;
228
248
  }
@@ -233,15 +253,15 @@ class p extends w {
233
253
  if (e.key === "Escape")
234
254
  return t === "cell" ? this.selectedCell = null : t === "row" ? (this.selected.clear(), this.anchor = null) : t === "range" && (this.ranges = [], this.activeRange = null, this.cellAnchor = null), this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
235
255
  if (t === "range" && e.key === "a" && (e.ctrlKey || e.metaKey)) {
236
- const r = this.rows.length, n = this.columns.length;
237
- if (r > 0 && n > 0) {
238
- const o = {
256
+ const l = this.rows.length, r = this.columns.length;
257
+ if (l > 0 && r > 0) {
258
+ const n = {
239
259
  startRow: 0,
240
260
  startCol: 0,
241
- endRow: r - 1,
242
- endCol: n - 1
261
+ endRow: l - 1,
262
+ endCol: r - 1
243
263
  };
244
- return this.ranges = [o], this.activeRange = o, this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
264
+ return this.ranges = [n], this.activeRange = n, this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
245
265
  }
246
266
  }
247
267
  return !1;
@@ -250,45 +270,63 @@ class p extends w {
250
270
  if (this.config.mode !== "range" || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0 || e.originalEvent.shiftKey && this.cellAnchor)
251
271
  return;
252
272
  this.isDragging = !0;
253
- const t = e.rowIndex, r = e.colIndex;
254
- this.cellAnchor = { row: t, col: r }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
255
- const o = {
273
+ const t = e.rowIndex, l = e.colIndex;
274
+ this.cellAnchor = { row: t, col: l }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
275
+ const n = {
256
276
  startRow: t,
257
- startCol: r,
277
+ startCol: l,
258
278
  endRow: t,
259
- endCol: r
279
+ endCol: l
260
280
  };
261
- return this.ranges.push(o), this.activeRange = o, this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
281
+ return this.ranges.push(n), this.activeRange = n, this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
262
282
  }
263
283
  onCellMouseMove(e) {
264
284
  if (this.config.mode !== "range" || !this.isDragging || !this.cellAnchor || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0) return;
265
- const t = f(this.cellAnchor, { row: e.rowIndex, col: e.colIndex });
285
+ const t = u(this.cellAnchor, { row: e.rowIndex, col: e.colIndex });
266
286
  return this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = t : this.ranges.push(t), this.activeRange = t, this.emit("selection-change", this.#e()), this.requestAfterRender(), !0;
267
287
  }
268
288
  onCellMouseUp(e) {
269
289
  if (this.config.mode === "range" && this.isDragging)
270
290
  return this.isDragging = !1, !0;
271
291
  }
272
- afterRender() {
292
+ /**
293
+ * Apply selection classes to visible cells/rows.
294
+ * Shared by afterRender and onScrollRender.
295
+ */
296
+ #t() {
273
297
  const e = this.shadowRoot;
274
298
  if (!e) return;
275
- const t = e.children[0], { mode: r } = this.config;
276
- this.grid.setAttribute("data-selection-mode", r), t && t.classList.toggle("selecting", this.isDragging), e.querySelectorAll(".cell").forEach((i) => {
277
- i.classList.remove("selected", "top", "bottom", "first", "last");
299
+ const { mode: t } = this.config;
300
+ e.querySelectorAll(".cell").forEach((n) => {
301
+ n.classList.remove("selected", "top", "bottom", "first", "last");
278
302
  });
279
- const o = e.querySelectorAll(".data-grid-row");
280
- if (o.forEach((i) => {
281
- i.classList.remove("selected");
282
- }), r === "row" && (o.forEach((i) => i.classList.remove("row-focus")), o.forEach((i) => {
283
- const a = i.querySelector(".cell[data-row]"), l = parseInt(a?.getAttribute("data-row") ?? "-1", 10);
284
- l >= 0 && this.selected.has(l) && i.classList.add("selected", "row-focus");
285
- })), r === "range" && this.ranges.length > 0) {
286
- const i = this.activeRange ? d(this.activeRange) : null;
287
- e.querySelectorAll(".cell[data-row][data-col]").forEach((l) => {
288
- const c = parseInt(l.getAttribute("data-row") ?? "-1", 10), h = parseInt(l.getAttribute("data-col") ?? "-1", 10);
289
- c >= 0 && h >= 0 && u(c, h, this.ranges) && (l.classList.add("selected"), i && (c === i.startRow && l.classList.add("top"), c === i.endRow && l.classList.add("bottom"), h === i.startCol && l.classList.add("first"), h === i.endCol && l.classList.add("last")));
303
+ const r = e.querySelectorAll(".data-grid-row");
304
+ if (r.forEach((n) => {
305
+ n.classList.remove("selected", "row-focus");
306
+ }), t === "row" && r.forEach((n) => {
307
+ const a = n.querySelector(".cell[data-row]"), i = parseInt(a?.getAttribute("data-row") ?? "-1", 10);
308
+ i >= 0 && this.selected.has(i) && (n.classList.add("selected", "row-focus"), n.querySelectorAll(".cell-focus").forEach((o) => o.classList.remove("cell-focus")));
309
+ }), t === "range" && this.ranges.length > 0) {
310
+ const n = this.activeRange ? h(this.activeRange) : null;
311
+ e.querySelectorAll(".cell[data-row][data-col]").forEach((i) => {
312
+ const o = parseInt(i.getAttribute("data-row") ?? "-1", 10), c = parseInt(i.getAttribute("data-col") ?? "-1", 10);
313
+ o >= 0 && c >= 0 && g(o, c, this.ranges) && (i.classList.add("selected"), i.classList.remove("cell-focus"), n && (o === n.startRow && i.classList.add("top"), o === n.endRow && i.classList.add("bottom"), c === n.startCol && i.classList.add("first"), c === n.endCol && i.classList.add("last")));
290
314
  });
291
315
  }
316
+ t === "cell" && this.selectedCell && e.querySelectorAll(".cell-focus").forEach((n) => n.classList.remove("cell-focus"));
317
+ }
318
+ afterRender() {
319
+ const e = this.shadowRoot;
320
+ if (!e) return;
321
+ const t = e.children[0], { mode: l } = this.config;
322
+ this.grid.setAttribute("data-selection-mode", l), t && t.classList.toggle("selecting", this.isDragging), this.#t();
323
+ }
324
+ /**
325
+ * Called after scroll-triggered row rendering.
326
+ * Reapplies selection classes to recycled DOM elements.
327
+ */
328
+ onScrollRender() {
329
+ this.#t();
292
330
  }
293
331
  // ===== Public API =====
294
332
  /**
@@ -307,19 +345,19 @@ class p extends w {
307
345
  * Get all selected cell ranges in public format.
308
346
  */
309
347
  getRanges() {
310
- return g(this.ranges);
348
+ return d(this.ranges);
311
349
  }
312
350
  /**
313
351
  * Get all selected cells across all ranges.
314
352
  */
315
353
  getSelectedCells() {
316
- return b(this.ranges);
354
+ return m(this.ranges);
317
355
  }
318
356
  /**
319
357
  * Check if a specific cell is in range selection.
320
358
  */
321
359
  isCellSelected(e, t) {
322
- return u(e, t, this.ranges);
360
+ return g(e, t, this.ranges);
323
361
  }
324
362
  /**
325
363
  * Clear all selection.
@@ -338,12 +376,12 @@ class p extends w {
338
376
  endCol: t.to.col
339
377
  })), this.activeRange = this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] : null, this.emit("selection-change", {
340
378
  mode: this.config.mode,
341
- ranges: g(this.ranges)
379
+ ranges: d(this.ranges)
342
380
  }), this.requestAfterRender();
343
381
  }
344
382
  // ===== Private Helpers =====
345
383
  #e() {
346
- return A(
384
+ return b(
347
385
  this.config.mode,
348
386
  {
349
387
  selectedCell: this.selectedCell,
@@ -388,39 +426,39 @@ class p extends w {
388
426
  }
389
427
  `;
390
428
  }
391
- function y(s, e, t, r) {
392
- const n = new Set(s.selected);
393
- let o = s.anchor;
429
+ function p(s, e, t, l) {
430
+ const r = new Set(s.selected);
431
+ let n = s.anchor;
394
432
  if (t === "single")
395
- n.clear(), n.add(e), o = e;
433
+ r.clear(), r.add(e), n = e;
396
434
  else if (t === "multiple") {
397
- const i = r.ctrlKey || r.metaKey;
398
- if (r.shiftKey && s.anchor !== null) {
399
- const a = Math.min(s.anchor, e), l = Math.max(s.anchor, e);
400
- for (let c = a; c <= l; c++)
401
- n.add(c);
402
- } else i ? (n.has(e) ? n.delete(e) : n.add(e), o = e) : (n.clear(), n.add(e), o = e);
403
- }
404
- return { selected: n, lastSelected: e, anchor: o };
435
+ const a = l.ctrlKey || l.metaKey;
436
+ if (l.shiftKey && s.anchor !== null) {
437
+ const i = Math.min(s.anchor, e), o = Math.max(s.anchor, e);
438
+ for (let c = i; c <= o; c++)
439
+ r.add(c);
440
+ } else a ? (r.has(e) ? r.delete(e) : r.add(e), n = e) : (r.clear(), r.add(e), n = e);
441
+ }
442
+ return { selected: r, lastSelected: e, anchor: n };
405
443
  }
406
- function x(s) {
444
+ function y(s) {
407
445
  const e = /* @__PURE__ */ new Set();
408
446
  for (let t = 0; t < s; t++)
409
447
  e.add(t);
410
448
  return e;
411
449
  }
412
450
  function S(s, e) {
413
- const t = [], r = [];
414
- for (const n of e)
415
- s.has(n) || t.push(n);
416
- for (const n of s)
417
- e.has(n) || r.push(n);
418
- return { added: t, removed: r };
451
+ const t = [], l = [];
452
+ for (const r of e)
453
+ s.has(r) || t.push(r);
454
+ for (const r of s)
455
+ e.has(r) || l.push(r);
456
+ return { added: t, removed: l };
419
457
  }
420
458
  export {
421
- p as SelectionPlugin,
459
+ v as SelectionPlugin,
422
460
  S as computeSelectionDiff,
423
- y as handleRowClick,
424
- x as selectAll
461
+ p as handleRowClick,
462
+ y as selectAll
425
463
  };
426
464
  //# sourceMappingURL=index.js.map