@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.
- package/README.md +43 -0
- package/all.d.ts +1680 -129
- package/all.js +440 -340
- package/all.js.map +1 -1
- package/custom-elements.json +1852 -0
- package/index.d.ts +133 -1
- package/index.js +726 -637
- package/index.js.map +1 -1
- package/lib/plugins/clipboard/index.js +62 -24
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +82 -44
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +141 -93
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/export/index.js +47 -9
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js +89 -51
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +71 -33
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js +91 -55
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +176 -54
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +83 -45
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js +54 -16
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +45 -7
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +97 -59
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/reorder/index.js +71 -33
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js +132 -94
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +76 -38
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js +76 -38
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +50 -12
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js +62 -24
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/umd/grid.all.umd.js +31 -31
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +14 -14
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/context-menu.umd.js +2 -2
- package/umd/plugins/context-menu.umd.js.map +1 -1
- package/umd/plugins/grouping-rows.umd.js +2 -2
- package/umd/plugins/grouping-rows.umd.js.map +1 -1
- package/umd/plugins/master-detail.umd.js +2 -2
- package/umd/plugins/master-detail.umd.js.map +1 -1
- package/umd/plugins/multi-sort.umd.js +1 -1
- package/umd/plugins/multi-sort.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js +2 -2
- package/umd/plugins/tree.umd.js.map +1 -1
- package/umd/plugins/visibility.umd.js +1 -1
- package/umd/plugins/visibility.umd.js.map +1 -1
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
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,
|
|
53
|
-
this.grid?.dispatchEvent?.(new CustomEvent(e, { detail:
|
|
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(
|
|
128
|
-
return (typeof
|
|
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
|
|
131
|
-
return
|
|
168
|
+
function C(s, e) {
|
|
169
|
+
return s.disabled === !0 ? !0 : typeof s.disabled == "function" ? s.disabled(e) : !1;
|
|
132
170
|
}
|
|
133
|
-
function x(
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
for (const
|
|
137
|
-
if (
|
|
138
|
-
const
|
|
139
|
-
|
|
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
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
const
|
|
147
|
-
|
|
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
|
|
150
|
-
if (
|
|
151
|
-
const
|
|
152
|
-
|
|
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 (
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
}),
|
|
161
|
-
const
|
|
162
|
-
|
|
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
|
-
!
|
|
166
|
-
|
|
167
|
-
}),
|
|
203
|
+
!c && o.action && !o.subMenu && t.addEventListener("click", (r) => {
|
|
204
|
+
r.stopPropagation(), n(o);
|
|
205
|
+
}), l.appendChild(t);
|
|
168
206
|
}
|
|
169
|
-
return
|
|
207
|
+
return l;
|
|
170
208
|
}
|
|
171
|
-
function E(
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
let
|
|
175
|
-
e +
|
|
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,
|
|
178
|
-
const
|
|
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: (
|
|
235
|
-
|
|
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: (
|
|
243
|
-
|
|
280
|
+
action: (s) => {
|
|
281
|
+
s.grid?.plugins?.export?.exportCsv?.();
|
|
244
282
|
}
|
|
245
283
|
}
|
|
246
284
|
];
|
|
247
|
-
class M extends
|
|
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
|
-
!
|
|
271
|
-
document.querySelectorAll(".tbw-context-menu").forEach((
|
|
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((
|
|
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
|
|
282
|
-
|
|
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
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
let
|
|
288
|
-
if (
|
|
289
|
-
const
|
|
290
|
-
|
|
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:
|
|
293
|
-
column:
|
|
294
|
-
columnIndex:
|
|
295
|
-
field:
|
|
296
|
-
value: w?.[
|
|
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:
|
|
336
|
+
event: l
|
|
299
337
|
};
|
|
300
|
-
} else if (
|
|
301
|
-
const
|
|
302
|
-
|
|
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:
|
|
306
|
-
columnIndex:
|
|
307
|
-
field:
|
|
343
|
+
column: m,
|
|
344
|
+
columnIndex: u,
|
|
345
|
+
field: m?.field ?? "",
|
|
308
346
|
value: null,
|
|
309
347
|
isHeader: !0,
|
|
310
|
-
event:
|
|
348
|
+
event: l
|
|
311
349
|
};
|
|
312
350
|
} else
|
|
313
351
|
return;
|
|
314
|
-
this.params =
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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,
|
|
329
|
-
const
|
|
330
|
-
row:
|
|
331
|
-
rowIndex:
|
|
332
|
-
column:
|
|
333
|
-
columnIndex:
|
|
334
|
-
field:
|
|
335
|
-
value:
|
|
336
|
-
isHeader:
|
|
337
|
-
event:
|
|
338
|
-
},
|
|
339
|
-
this.menuElement && this.menuElement.remove(), this.menuElement = x(
|
|
340
|
-
|
|
341
|
-
|
|
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.
|