@toolbox-web/grid 0.0.5 → 0.0.7

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 (61) hide show
  1. package/README.md +43 -0
  2. package/all.d.ts +1680 -129
  3. package/all.js +440 -340
  4. package/all.js.map +1 -1
  5. package/custom-elements.json +1852 -0
  6. package/index.d.ts +133 -1
  7. package/index.js +726 -637
  8. package/index.js.map +1 -1
  9. package/lib/plugins/clipboard/index.js +62 -24
  10. package/lib/plugins/clipboard/index.js.map +1 -1
  11. package/lib/plugins/column-virtualization/index.js +82 -44
  12. package/lib/plugins/column-virtualization/index.js.map +1 -1
  13. package/lib/plugins/context-menu/index.js +141 -93
  14. package/lib/plugins/context-menu/index.js.map +1 -1
  15. package/lib/plugins/export/index.js +47 -9
  16. package/lib/plugins/export/index.js.map +1 -1
  17. package/lib/plugins/filtering/index.js +89 -51
  18. package/lib/plugins/filtering/index.js.map +1 -1
  19. package/lib/plugins/grouping-columns/index.js +71 -33
  20. package/lib/plugins/grouping-columns/index.js.map +1 -1
  21. package/lib/plugins/grouping-rows/index.js +91 -55
  22. package/lib/plugins/grouping-rows/index.js.map +1 -1
  23. package/lib/plugins/master-detail/index.js +176 -54
  24. package/lib/plugins/master-detail/index.js.map +1 -1
  25. package/lib/plugins/multi-sort/index.js +83 -45
  26. package/lib/plugins/multi-sort/index.js.map +1 -1
  27. package/lib/plugins/pinned-columns/index.js +54 -16
  28. package/lib/plugins/pinned-columns/index.js.map +1 -1
  29. package/lib/plugins/pinned-rows/index.js +45 -7
  30. package/lib/plugins/pinned-rows/index.js.map +1 -1
  31. package/lib/plugins/pivot/index.js +97 -59
  32. package/lib/plugins/pivot/index.js.map +1 -1
  33. package/lib/plugins/reorder/index.js +71 -33
  34. package/lib/plugins/reorder/index.js.map +1 -1
  35. package/lib/plugins/selection/index.js +132 -94
  36. package/lib/plugins/selection/index.js.map +1 -1
  37. package/lib/plugins/server-side/index.js +76 -38
  38. package/lib/plugins/server-side/index.js.map +1 -1
  39. package/lib/plugins/tree/index.js +76 -38
  40. package/lib/plugins/tree/index.js.map +1 -1
  41. package/lib/plugins/undo-redo/index.js +50 -12
  42. package/lib/plugins/undo-redo/index.js.map +1 -1
  43. package/lib/plugins/visibility/index.js +62 -24
  44. package/lib/plugins/visibility/index.js.map +1 -1
  45. package/package.json +1 -1
  46. package/umd/grid.all.umd.js +31 -31
  47. package/umd/grid.all.umd.js.map +1 -1
  48. package/umd/grid.umd.js +14 -14
  49. package/umd/grid.umd.js.map +1 -1
  50. package/umd/plugins/context-menu.umd.js +2 -2
  51. package/umd/plugins/context-menu.umd.js.map +1 -1
  52. package/umd/plugins/grouping-rows.umd.js +2 -2
  53. package/umd/plugins/grouping-rows.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 +1 -1
  57. package/umd/plugins/multi-sort.umd.js.map +1 -1
  58. package/umd/plugins/tree.umd.js +2 -2
  59. package/umd/plugins/tree.umd.js.map +1 -1
  60. package/umd/plugins/visibility.umd.js +1 -1
  61. package/umd/plugins/visibility.umd.js.map +1 -1
@@ -1,4 +1,13 @@
1
- class v {
1
+ const v = {
2
+ expand: "▶",
3
+ collapse: "▼",
4
+ sortAsc: "▲",
5
+ sortDesc: "▼",
6
+ sortNone: "⇅",
7
+ submenuArrow: "▶",
8
+ dragHandle: "⋮⋮"
9
+ };
10
+ class y {
2
11
  /** Plugin version - override in subclass if needed */
3
12
  version = "1.0.0";
4
13
  /** CSS styles to inject into the grid's shadow DOM */
@@ -49,8 +58,8 @@ class v {
49
58
  /**
50
59
  * Emit a custom event from the grid.
51
60
  */
52
- emit(e, l) {
53
- this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: l, bubbles: !0 }));
61
+ emit(e, n) {
62
+ this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: n, bubbles: !0 }));
54
63
  }
55
64
  /**
56
65
  * Request a re-render of the grid.
@@ -117,6 +126,35 @@ class v {
117
126
  get disconnectSignal() {
118
127
  return this.grid?.disconnectSignal;
119
128
  }
129
+ /**
130
+ * Get the grid-level icons configuration.
131
+ * Returns merged icons (user config + defaults).
132
+ */
133
+ get gridIcons() {
134
+ const e = this.grid?.gridConfig?.icons ?? {};
135
+ return { ...v, ...e };
136
+ }
137
+ /**
138
+ * Resolve an icon value to string or HTMLElement.
139
+ * Checks plugin config first, then grid-level icons, then defaults.
140
+ *
141
+ * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')
142
+ * @param pluginOverride - Optional plugin-level override
143
+ * @returns The resolved icon value
144
+ */
145
+ resolveIcon(e, n) {
146
+ return n !== void 0 ? n : this.gridIcons[e];
147
+ }
148
+ /**
149
+ * Set an icon value on an element.
150
+ * Handles both string (text/HTML) and HTMLElement values.
151
+ *
152
+ * @param element - The element to set the icon on
153
+ * @param icon - The icon value (string or HTMLElement)
154
+ */
155
+ setIcon(e, n) {
156
+ typeof n == "string" ? e.innerHTML = n : n instanceof HTMLElement && (e.innerHTML = "", e.appendChild(n.cloneNode(!0)));
157
+ }
120
158
  /**
121
159
  * Log a warning message.
122
160
  */
@@ -124,58 +162,58 @@ class v {
124
162
  console.warn(`[tbw-grid:${this.name}] ${e}`);
125
163
  }
126
164
  }
127
- function b(i, e) {
128
- return (typeof i == "function" ? i(e) : i).filter((n) => !(n.hidden === !0 || typeof n.hidden == "function" && n.hidden(e)));
165
+ function b(s, e) {
166
+ return (typeof s == "function" ? s(e) : s).filter((i) => !(i.hidden === !0 || typeof i.hidden == "function" && i.hidden(e)));
129
167
  }
130
- function y(i, e) {
131
- return i.disabled === !0 ? !0 : typeof i.disabled == "function" ? i.disabled(e) : !1;
168
+ function C(s, e) {
169
+ return s.disabled === !0 ? !0 : typeof s.disabled == "function" ? s.disabled(e) : !1;
132
170
  }
133
- function x(i, e, l) {
134
- const n = document.createElement("div");
135
- n.className = "tbw-context-menu", n.setAttribute("role", "menu");
136
- for (const t of i) {
137
- if (t.separator) {
138
- const o = document.createElement("div");
139
- o.className = "tbw-context-menu-separator", o.setAttribute("role", "separator"), n.appendChild(o);
171
+ function x(s, e, n, i = v.submenuArrow) {
172
+ const l = document.createElement("div");
173
+ l.className = "tbw-context-menu", l.setAttribute("role", "menu");
174
+ for (const o of s) {
175
+ if (o.separator) {
176
+ const r = document.createElement("div");
177
+ r.className = "tbw-context-menu-separator", r.setAttribute("role", "separator"), l.appendChild(r);
140
178
  continue;
141
179
  }
142
- const s = document.createElement("div");
143
- s.className = "tbw-context-menu-item", t.cssClass && s.classList.add(t.cssClass), s.setAttribute("role", "menuitem"), s.setAttribute("data-id", t.id);
144
- const r = y(t, e);
145
- if (r && (s.classList.add("disabled"), s.setAttribute("aria-disabled", "true")), t.icon) {
146
- const o = document.createElement("span");
147
- o.className = "tbw-context-menu-icon", o.innerHTML = t.icon, s.appendChild(o);
180
+ const t = document.createElement("div");
181
+ t.className = "tbw-context-menu-item", o.cssClass && t.classList.add(o.cssClass), t.setAttribute("role", "menuitem"), t.setAttribute("data-id", o.id);
182
+ const c = C(o, e);
183
+ if (c && (t.classList.add("disabled"), t.setAttribute("aria-disabled", "true")), o.icon) {
184
+ const r = document.createElement("span");
185
+ r.className = "tbw-context-menu-icon", r.innerHTML = o.icon, t.appendChild(r);
148
186
  }
149
- const u = document.createElement("span");
150
- if (u.className = "tbw-context-menu-label", u.textContent = t.name, s.appendChild(u), t.shortcut) {
151
- const o = document.createElement("span");
152
- o.className = "tbw-context-menu-shortcut", o.textContent = t.shortcut, s.appendChild(o);
187
+ const d = document.createElement("span");
188
+ if (d.className = "tbw-context-menu-label", d.textContent = o.name, t.appendChild(d), o.shortcut) {
189
+ const r = document.createElement("span");
190
+ r.className = "tbw-context-menu-shortcut", r.textContent = o.shortcut, t.appendChild(r);
153
191
  }
154
- if (t.subMenu?.length) {
155
- const o = document.createElement("span");
156
- o.className = "tbw-context-menu-arrow", o.textContent = "▶", s.appendChild(o), s.addEventListener("mouseenter", () => {
157
- if (s.querySelector(".tbw-context-menu") || !t.subMenu) return;
158
- const c = b(t.subMenu, e), d = x(c, e, l);
159
- d.classList.add("tbw-context-submenu"), d.style.position = "absolute", d.style.left = "100%", d.style.top = "0", s.style.position = "relative", s.appendChild(d);
160
- }), s.addEventListener("mouseleave", () => {
161
- const a = s.querySelector(".tbw-context-menu");
162
- a && a.remove();
192
+ if (o.subMenu?.length) {
193
+ const r = document.createElement("span");
194
+ r.className = "tbw-context-menu-arrow", typeof i == "string" ? r.innerHTML = i : i instanceof HTMLElement && r.appendChild(i.cloneNode(!0)), t.appendChild(r), t.addEventListener("mouseenter", () => {
195
+ if (t.querySelector(".tbw-context-menu") || !o.subMenu) return;
196
+ const m = b(o.subMenu, e), a = x(m, e, n, i);
197
+ a.classList.add("tbw-context-submenu"), a.style.position = "absolute", a.style.left = "100%", a.style.top = "0", t.style.position = "relative", t.appendChild(a);
198
+ }), t.addEventListener("mouseleave", () => {
199
+ const u = t.querySelector(".tbw-context-menu");
200
+ u && u.remove();
163
201
  });
164
202
  }
165
- !r && t.action && !t.subMenu && s.addEventListener("click", (o) => {
166
- o.stopPropagation(), l(t);
167
- }), n.appendChild(s);
203
+ !c && o.action && !o.subMenu && t.addEventListener("click", (r) => {
204
+ r.stopPropagation(), n(o);
205
+ }), l.appendChild(t);
168
206
  }
169
- return n;
207
+ return l;
170
208
  }
171
- function E(i, e, l) {
172
- i.style.position = "fixed", i.style.left = `${e}px`, i.style.top = `${l}px`, i.style.visibility = "hidden", i.style.zIndex = "10000";
173
- const n = i.getBoundingClientRect(), t = window.innerWidth, s = window.innerHeight;
174
- let r = e, u = l;
175
- e + n.width > t && (r = e - n.width), l + n.height > s && (u = l - n.height), r = Math.max(0, r), u = Math.max(0, u), i.style.left = `${r}px`, i.style.top = `${u}px`, i.style.visibility = "visible";
209
+ function E(s, e, n) {
210
+ s.style.position = "fixed", s.style.left = `${e}px`, s.style.top = `${n}px`, s.style.visibility = "hidden", s.style.zIndex = "10000";
211
+ const i = s.getBoundingClientRect(), l = window.innerWidth, o = window.innerHeight;
212
+ let t = e, c = n;
213
+ e + i.width > l && (t = e - i.width), n + i.height > o && (c = n - i.height), t = Math.max(0, t), c = Math.max(0, c), s.style.left = `${t}px`, s.style.top = `${c}px`, s.style.visibility = "visible";
176
214
  }
177
- let f = null, p = null, m = null;
178
- const C = `
215
+ let f = null, p = null, h = null;
216
+ const I = `
179
217
  .tbw-context-menu {
180
218
  position: fixed;
181
219
  background: light-dark(#f5f5f5, #2a2a2a);
@@ -231,20 +269,20 @@ const C = `
231
269
  id: "copy",
232
270
  name: "Copy",
233
271
  shortcut: "Ctrl+C",
234
- action: (i) => {
235
- i.grid?.plugins?.clipboard?.copy?.();
272
+ action: (s) => {
273
+ s.grid?.plugins?.clipboard?.copy?.();
236
274
  }
237
275
  },
238
276
  { separator: !0, id: "sep1", name: "" },
239
277
  {
240
278
  id: "export-csv",
241
279
  name: "Export CSV",
242
- action: (i) => {
243
- i.grid?.plugins?.export?.exportCsv?.();
280
+ action: (s) => {
281
+ s.grid?.plugins?.export?.exportCsv?.();
244
282
  }
245
283
  }
246
284
  ];
247
- class M extends v {
285
+ class M extends y {
248
286
  name = "contextMenu";
249
287
  version = "1.0.0";
250
288
  get defaultConfig() {
@@ -267,10 +305,10 @@ class M extends v {
267
305
  }
268
306
  // ===== Private Methods =====
269
307
  installGlobalHandlers() {
270
- !m && typeof document < "u" && (m = document.createElement("style"), m.id = "tbw-context-menu-styles", m.textContent = C, document.head.appendChild(m)), f || (f = () => {
271
- document.querySelectorAll(".tbw-context-menu").forEach((l) => l.remove());
308
+ !h && typeof document < "u" && (h = document.createElement("style"), h.id = "tbw-context-menu-styles", h.textContent = I, document.head.appendChild(h)), f || (f = () => {
309
+ document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
272
310
  }, document.addEventListener("click", f)), p || (p = (e) => {
273
- e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
311
+ e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((i) => i.remove());
274
312
  }, document.addEventListener("keydown", p));
275
313
  }
276
314
  // ===== Hooks =====
@@ -278,44 +316,49 @@ class M extends v {
278
316
  if (!this.config.enabled) return;
279
317
  const e = this.shadowRoot;
280
318
  if (!e) return;
281
- const l = e.children[0];
282
- l && l.getAttribute("data-context-menu-bound") !== "true" && (l.setAttribute("data-context-menu-bound", "true"), l.addEventListener("contextmenu", (n) => {
319
+ const n = e.children[0];
320
+ n && n.getAttribute("data-context-menu-bound") !== "true" && (n.setAttribute("data-context-menu-bound", "true"), n.addEventListener("contextmenu", (i) => {
283
321
  if (!this.config.enabled) return;
284
- const t = n;
285
- t.preventDefault();
286
- const s = t.target, r = s.closest("[data-row][data-col]"), u = s.closest(".header-cell");
287
- let o;
288
- if (r) {
289
- const c = parseInt(r.getAttribute("data-row") ?? "-1", 10), d = parseInt(r.getAttribute("data-col") ?? "-1", 10), h = this.columns[d], w = this.rows[c];
290
- o = {
322
+ const l = i;
323
+ l.preventDefault();
324
+ const o = l.target, t = o.closest("[data-row][data-col]"), c = o.closest(".header-cell");
325
+ let d;
326
+ if (t) {
327
+ const u = parseInt(t.getAttribute("data-row") ?? "-1", 10), m = parseInt(t.getAttribute("data-col") ?? "-1", 10), a = this.columns[m], w = this.rows[u];
328
+ d = {
291
329
  row: w,
292
- rowIndex: c,
293
- column: h,
294
- columnIndex: d,
295
- field: h?.field ?? "",
296
- value: w?.[h?.field] ?? null,
330
+ rowIndex: u,
331
+ column: a,
332
+ columnIndex: m,
333
+ field: a?.field ?? "",
334
+ value: w?.[a?.field] ?? null,
297
335
  isHeader: !1,
298
- event: t
336
+ event: l
299
337
  };
300
- } else if (u) {
301
- const c = parseInt(u.getAttribute("data-col") ?? "-1", 10), d = this.columns[c];
302
- o = {
338
+ } else if (c) {
339
+ const u = parseInt(c.getAttribute("data-col") ?? "-1", 10), m = this.columns[u];
340
+ d = {
303
341
  row: null,
304
342
  rowIndex: -1,
305
- column: d,
306
- columnIndex: c,
307
- field: d?.field ?? "",
343
+ column: m,
344
+ columnIndex: u,
345
+ field: m?.field ?? "",
308
346
  value: null,
309
347
  isHeader: !0,
310
- event: t
348
+ event: l
311
349
  };
312
350
  } else
313
351
  return;
314
- this.params = o, this.position = { x: t.clientX, y: t.clientY };
315
- const a = b(this.config.items ?? g, o);
316
- a.length && (this.menuElement && this.menuElement.remove(), this.menuElement = x(a, o, (c) => {
317
- c.action && c.action(o), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
318
- }), document.body.appendChild(this.menuElement), E(this.menuElement, t.clientX, t.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: o, items: a }));
352
+ this.params = d, this.position = { x: l.clientX, y: l.clientY };
353
+ const r = b(this.config.items ?? g, d);
354
+ r.length && (this.menuElement && this.menuElement.remove(), this.menuElement = x(
355
+ r,
356
+ d,
357
+ (u) => {
358
+ u.action && u.action(d), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
359
+ },
360
+ this.gridIcons.submenuArrow
361
+ ), document.body.appendChild(this.menuElement), E(this.menuElement, l.clientX, l.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: d, items: r }));
319
362
  }));
320
363
  }
321
364
  // ===== Public API =====
@@ -325,20 +368,25 @@ class M extends v {
325
368
  * @param y - Y coordinate
326
369
  * @param params - Partial context menu parameters
327
370
  */
328
- showMenu(e, l, n) {
329
- const t = {
330
- row: n.row ?? null,
331
- rowIndex: n.rowIndex ?? -1,
332
- column: n.column ?? null,
333
- columnIndex: n.columnIndex ?? -1,
334
- field: n.field ?? "",
335
- value: n.value ?? null,
336
- isHeader: n.isHeader ?? !1,
337
- event: n.event ?? new MouseEvent("contextmenu")
338
- }, s = b(this.config.items ?? g, t);
339
- this.menuElement && this.menuElement.remove(), this.menuElement = x(s, t, (r) => {
340
- r.action && r.action(t), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
341
- }), document.body.appendChild(this.menuElement), E(this.menuElement, e, l), this.isOpen = !0;
371
+ showMenu(e, n, i) {
372
+ const l = {
373
+ row: i.row ?? null,
374
+ rowIndex: i.rowIndex ?? -1,
375
+ column: i.column ?? null,
376
+ columnIndex: i.columnIndex ?? -1,
377
+ field: i.field ?? "",
378
+ value: i.value ?? null,
379
+ isHeader: i.isHeader ?? !1,
380
+ event: i.event ?? new MouseEvent("contextmenu")
381
+ }, o = b(this.config.items ?? g, l);
382
+ this.menuElement && this.menuElement.remove(), this.menuElement = x(
383
+ o,
384
+ l,
385
+ (t) => {
386
+ t.action && t.action(l), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
387
+ },
388
+ this.gridIcons.submenuArrow
389
+ ), document.body.appendChild(this.menuElement), E(this.menuElement, e, n), this.isOpen = !0;
342
390
  }
343
391
  /**
344
392
  * Hide the context menu.