@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.
- package/all.d.ts +50 -6
- package/all.js +101 -98
- package/all.js.map +1 -1
- package/index.d.ts +54 -0
- package/index.js +793 -692
- package/index.js.map +1 -1
- package/lib/plugins/clipboard/index.js +55 -35
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +49 -29
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +35 -15
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/export/index.js +52 -32
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js +116 -99
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +42 -22
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js +20 -0
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +50 -27
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +25 -5
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js +20 -0
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +20 -0
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +20 -0
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/reorder/index.js +56 -33
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js +138 -100
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +20 -0
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js +76 -53
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +20 -0
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js +20 -0
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +4 -1
- package/themes/dg-theme-contrast.css +43 -43
- package/themes/dg-theme-large.css +54 -54
- package/themes/dg-theme-standard.css +19 -19
- package/themes/dg-theme-vibrant.css +16 -16
- package/umd/grid.all.umd.js +24 -24
- 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/filtering.umd.js +3 -3
- package/umd/plugins/filtering.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.map +1 -1
- package/umd/plugins/reorder.umd.js +1 -1
- package/umd/plugins/reorder.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js +2 -2
- package/umd/plugins/selection.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.map +1 -1
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
function M(f) {
|
|
2
|
+
const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: l, overscan: s } = f, i = Math.ceil(t / l);
|
|
3
|
+
let n = Math.floor(r / l) - s;
|
|
4
|
+
n < 0 && (n = 0);
|
|
5
|
+
let u = n + i + s * 2;
|
|
6
|
+
return u > e && (u = e), u === e && n > 0 && (n = Math.max(0, u - i - s * 2)), {
|
|
7
|
+
start: n,
|
|
8
|
+
end: u,
|
|
9
|
+
offsetY: n * l,
|
|
10
|
+
totalHeight: e * l
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function P(f, e) {
|
|
14
|
+
return f <= e;
|
|
15
|
+
}
|
|
16
|
+
class V {
|
|
2
17
|
/** Plugin version - override in subclass if needed */
|
|
3
18
|
version = "1.0.0";
|
|
4
19
|
/** CSS styles to inject into the grid's shadow DOM */
|
|
@@ -97,6 +112,26 @@ class P {
|
|
|
97
112
|
get shadowRoot() {
|
|
98
113
|
return this.grid?.shadowRoot ?? null;
|
|
99
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the disconnect signal for event listener cleanup.
|
|
117
|
+
* This signal is aborted when the grid disconnects from the DOM.
|
|
118
|
+
* Use this when adding event listeners that should be cleaned up automatically.
|
|
119
|
+
*
|
|
120
|
+
* Best for:
|
|
121
|
+
* - Document/window-level listeners added in attach()
|
|
122
|
+
* - Listeners on the grid element itself
|
|
123
|
+
* - Any listener that should persist across renders
|
|
124
|
+
*
|
|
125
|
+
* Not needed for:
|
|
126
|
+
* - Listeners on elements created in afterRender() (removed with element)
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* element.addEventListener('click', handler, { signal: this.disconnectSignal });
|
|
130
|
+
* document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
|
|
131
|
+
*/
|
|
132
|
+
get disconnectSignal() {
|
|
133
|
+
return this.grid?.disconnectSignal;
|
|
134
|
+
}
|
|
100
135
|
/**
|
|
101
136
|
* Log a warning message.
|
|
102
137
|
*/
|
|
@@ -104,21 +139,6 @@ class P {
|
|
|
104
139
|
console.warn(`[tbw-grid:${this.name}] ${e}`);
|
|
105
140
|
}
|
|
106
141
|
}
|
|
107
|
-
function A(f) {
|
|
108
|
-
const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: l, overscan: s } = f, i = Math.ceil(t / l);
|
|
109
|
-
let n = Math.floor(r / l) - s;
|
|
110
|
-
n < 0 && (n = 0);
|
|
111
|
-
let u = n + i + s * 2;
|
|
112
|
-
return u > e && (u = e), u === e && n > 0 && (n = Math.max(0, u - i - s * 2)), {
|
|
113
|
-
start: n,
|
|
114
|
-
end: u,
|
|
115
|
-
offsetY: n * l,
|
|
116
|
-
totalHeight: e * l
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function V(f, e) {
|
|
120
|
-
return f <= e;
|
|
121
|
-
}
|
|
122
142
|
function _(f, e, t = !1) {
|
|
123
143
|
const r = f[e.field];
|
|
124
144
|
if (e.operator === "blank")
|
|
@@ -174,7 +194,7 @@ function B(f) {
|
|
|
174
194
|
}))
|
|
175
195
|
);
|
|
176
196
|
}
|
|
177
|
-
function
|
|
197
|
+
function H(f, e) {
|
|
178
198
|
const t = /* @__PURE__ */ new Set();
|
|
179
199
|
for (const r of f) {
|
|
180
200
|
const l = r[e];
|
|
@@ -324,7 +344,7 @@ const z = `
|
|
|
324
344
|
background: var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)));
|
|
325
345
|
}
|
|
326
346
|
`;
|
|
327
|
-
class
|
|
347
|
+
class x extends V {
|
|
328
348
|
name = "filtering";
|
|
329
349
|
version = "1.0.0";
|
|
330
350
|
get defaultConfig() {
|
|
@@ -344,7 +364,8 @@ class y extends P {
|
|
|
344
364
|
panelElement = null;
|
|
345
365
|
searchText = /* @__PURE__ */ new Map();
|
|
346
366
|
excludedValues = /* @__PURE__ */ new Map();
|
|
347
|
-
|
|
367
|
+
panelAbortController = null;
|
|
368
|
+
// For panel-scoped listeners
|
|
348
369
|
globalStylesInjected = !1;
|
|
349
370
|
// Virtualization constants for filter value list
|
|
350
371
|
static LIST_ITEM_HEIGHT = 28;
|
|
@@ -356,7 +377,7 @@ class y extends P {
|
|
|
356
377
|
super.attach(e), this.injectGlobalStyles();
|
|
357
378
|
}
|
|
358
379
|
detach() {
|
|
359
|
-
this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.
|
|
380
|
+
this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.panelAbortController?.abort(), this.panelAbortController = null;
|
|
360
381
|
}
|
|
361
382
|
// ===== Hooks =====
|
|
362
383
|
processRows(e) {
|
|
@@ -468,7 +489,7 @@ class y extends P {
|
|
|
468
489
|
* Uses sourceRows to include all values regardless of current filter.
|
|
469
490
|
*/
|
|
470
491
|
getUniqueValues(e) {
|
|
471
|
-
return
|
|
492
|
+
return H(this.sourceRows, e);
|
|
472
493
|
}
|
|
473
494
|
// ===== Private Methods =====
|
|
474
495
|
/**
|
|
@@ -494,7 +515,7 @@ class y extends P {
|
|
|
494
515
|
this.closeFilterPanel();
|
|
495
516
|
const l = document.createElement("div");
|
|
496
517
|
l.className = "tbw-filter-panel", this.panelElement = l, this.openPanelField = e;
|
|
497
|
-
const s =
|
|
518
|
+
const s = H(this.sourceRows, e);
|
|
498
519
|
let i = this.excludedValues.get(e);
|
|
499
520
|
i || (i = /* @__PURE__ */ new Set(), this.excludedValues.set(e, i));
|
|
500
521
|
const n = this.searchText.get(e) ?? "", u = {
|
|
@@ -503,11 +524,11 @@ class y extends P {
|
|
|
503
524
|
uniqueValues: s,
|
|
504
525
|
excludedValues: i,
|
|
505
526
|
searchText: n,
|
|
506
|
-
applySetFilter: (
|
|
507
|
-
this.applySetFilter(e,
|
|
527
|
+
applySetFilter: (h) => {
|
|
528
|
+
this.applySetFilter(e, h), this.closeFilterPanel();
|
|
508
529
|
},
|
|
509
|
-
applyTextFilter: (
|
|
510
|
-
this.applyTextFilter(e,
|
|
530
|
+
applyTextFilter: (h, E, C) => {
|
|
531
|
+
this.applyTextFilter(e, h, E, C), this.closeFilterPanel();
|
|
511
532
|
},
|
|
512
533
|
clearFilter: () => {
|
|
513
534
|
this.clearFieldFilter(e), this.closeFilterPanel();
|
|
@@ -515,25 +536,21 @@ class y extends P {
|
|
|
515
536
|
closePanel: () => this.closeFilterPanel()
|
|
516
537
|
};
|
|
517
538
|
let g = !1;
|
|
518
|
-
this.config.filterPanelRenderer && (this.config.filterPanelRenderer(l, u), g = l.children.length > 0), g || this.renderDefaultFilterPanel(l, u, s, i), document.body.appendChild(l), this.positionPanel(l, r)
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
539
|
+
this.config.filterPanelRenderer && (this.config.filterPanelRenderer(l, u), g = l.children.length > 0), g || this.renderDefaultFilterPanel(l, u, s, i), document.body.appendChild(l), this.positionPanel(l, r), this.panelAbortController = new AbortController(), setTimeout(() => {
|
|
540
|
+
document.addEventListener(
|
|
541
|
+
"click",
|
|
542
|
+
(h) => {
|
|
543
|
+
!l.contains(h.target) && h.target !== r && this.closeFilterPanel();
|
|
544
|
+
},
|
|
545
|
+
{ signal: this.panelAbortController?.signal }
|
|
546
|
+
);
|
|
524
547
|
}, 0);
|
|
525
548
|
}
|
|
526
549
|
/**
|
|
527
550
|
* Close the filter panel
|
|
528
551
|
*/
|
|
529
552
|
closeFilterPanel() {
|
|
530
|
-
this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.openPanelField = null, this.
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Remove the document click handler
|
|
534
|
-
*/
|
|
535
|
-
removeDocumentClickHandler() {
|
|
536
|
-
this.documentClickHandler && (document.removeEventListener("click", this.documentClickHandler), this.documentClickHandler = null);
|
|
553
|
+
this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.openPanelField = null, this.panelAbortController?.abort(), this.panelAbortController = null;
|
|
537
554
|
}
|
|
538
555
|
/**
|
|
539
556
|
* Position the panel below the button
|
|
@@ -557,92 +574,92 @@ class y extends P {
|
|
|
557
574
|
u.className = "tbw-filter-actions";
|
|
558
575
|
const g = document.createElement("label");
|
|
559
576
|
g.className = "tbw-filter-value-item", g.style.padding = "0", g.style.margin = "0";
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
const
|
|
565
|
-
const a = [...
|
|
566
|
-
|
|
577
|
+
const h = document.createElement("input");
|
|
578
|
+
h.type = "checkbox", h.className = "tbw-filter-checkbox";
|
|
579
|
+
const E = document.createElement("span");
|
|
580
|
+
E.textContent = "Select All", g.appendChild(h), g.appendChild(E), u.appendChild(g);
|
|
581
|
+
const C = () => {
|
|
582
|
+
const a = [...v.values()], d = a.every((c) => c), p = a.every((c) => !c);
|
|
583
|
+
h.checked = d, h.indeterminate = !d && !p;
|
|
567
584
|
};
|
|
568
|
-
|
|
569
|
-
const a =
|
|
570
|
-
for (const d of
|
|
571
|
-
|
|
572
|
-
|
|
585
|
+
h.addEventListener("change", () => {
|
|
586
|
+
const a = h.checked;
|
|
587
|
+
for (const d of v.keys())
|
|
588
|
+
v.set(d, a);
|
|
589
|
+
C(), F();
|
|
573
590
|
}), e.appendChild(u);
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
591
|
+
const m = document.createElement("div");
|
|
592
|
+
m.className = "tbw-filter-values";
|
|
593
|
+
const R = document.createElement("div");
|
|
594
|
+
R.className = "tbw-filter-values-spacer", m.appendChild(R);
|
|
578
595
|
const b = document.createElement("div");
|
|
579
|
-
b.className = "tbw-filter-values-content",
|
|
580
|
-
const
|
|
596
|
+
b.className = "tbw-filter-values-content", m.appendChild(b);
|
|
597
|
+
const v = /* @__PURE__ */ new Map();
|
|
581
598
|
r.forEach((a) => {
|
|
582
599
|
const d = a == null ? "__null__" : String(a);
|
|
583
|
-
|
|
584
|
-
}),
|
|
585
|
-
let
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
o.className = "tbw-filter-value-item", o.style.position = "absolute", o.style.top = `${d *
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
600
|
+
v.set(d, !l.has(a));
|
|
601
|
+
}), C();
|
|
602
|
+
let y = [];
|
|
603
|
+
const I = (a, d) => {
|
|
604
|
+
const p = a == null ? "(Blank)" : String(a), c = a == null ? "__null__" : String(a), o = document.createElement("label");
|
|
605
|
+
o.className = "tbw-filter-value-item", o.style.position = "absolute", o.style.top = `${d * x.LIST_ITEM_HEIGHT}px`, o.style.left = "0", o.style.right = "0", o.style.height = `${x.LIST_ITEM_HEIGHT}px`, o.style.boxSizing = "border-box";
|
|
606
|
+
const w = document.createElement("input");
|
|
607
|
+
w.type = "checkbox", w.className = "tbw-filter-checkbox", w.checked = v.get(c) ?? !0, w.dataset.value = c, w.addEventListener("change", () => {
|
|
608
|
+
v.set(c, w.checked), C();
|
|
592
609
|
});
|
|
593
|
-
const
|
|
594
|
-
return
|
|
610
|
+
const A = document.createElement("span");
|
|
611
|
+
return A.textContent = p, o.appendChild(w), o.appendChild(A), o;
|
|
595
612
|
}, F = () => {
|
|
596
|
-
const a =
|
|
597
|
-
if (
|
|
598
|
-
b.innerHTML = "", b.style.transform = "translateY(0px)",
|
|
599
|
-
b.appendChild(
|
|
613
|
+
const a = y.length, d = m.clientHeight, p = m.scrollTop;
|
|
614
|
+
if (R.style.height = `${a * x.LIST_ITEM_HEIGHT}px`, P(a, x.LIST_BYPASS_THRESHOLD / 3)) {
|
|
615
|
+
b.innerHTML = "", b.style.transform = "translateY(0px)", y.forEach((o, w) => {
|
|
616
|
+
b.appendChild(I(o, w));
|
|
600
617
|
});
|
|
601
618
|
return;
|
|
602
619
|
}
|
|
603
|
-
const c =
|
|
620
|
+
const c = M({
|
|
604
621
|
totalRows: a,
|
|
605
622
|
viewportHeight: d,
|
|
606
|
-
scrollTop:
|
|
607
|
-
rowHeight:
|
|
608
|
-
overscan:
|
|
623
|
+
scrollTop: p,
|
|
624
|
+
rowHeight: x.LIST_ITEM_HEIGHT,
|
|
625
|
+
overscan: x.LIST_OVERSCAN
|
|
609
626
|
});
|
|
610
627
|
b.style.transform = `translateY(${c.offsetY}px)`, b.innerHTML = "";
|
|
611
628
|
for (let o = c.start; o < c.end; o++)
|
|
612
|
-
b.appendChild(
|
|
613
|
-
},
|
|
629
|
+
b.appendChild(I(y[o], o - c.start));
|
|
630
|
+
}, N = (a) => {
|
|
614
631
|
const d = a.toLowerCase();
|
|
615
|
-
if (
|
|
616
|
-
const c =
|
|
632
|
+
if (y = r.filter((p) => {
|
|
633
|
+
const c = p == null ? "(Blank)" : String(p);
|
|
617
634
|
return !a || c.toLowerCase().includes(d);
|
|
618
|
-
}),
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
635
|
+
}), y.length === 0) {
|
|
636
|
+
R.style.height = "0px", b.innerHTML = "";
|
|
637
|
+
const p = document.createElement("div");
|
|
638
|
+
p.className = "tbw-filter-no-match", p.textContent = "No matching values", b.appendChild(p);
|
|
622
639
|
return;
|
|
623
640
|
}
|
|
624
641
|
F();
|
|
625
642
|
};
|
|
626
|
-
|
|
643
|
+
m.addEventListener(
|
|
627
644
|
"scroll",
|
|
628
645
|
() => {
|
|
629
|
-
|
|
646
|
+
y.length > 0 && F();
|
|
630
647
|
},
|
|
631
648
|
{ passive: !0 }
|
|
632
|
-
),
|
|
649
|
+
), N(n.value), e.appendChild(m);
|
|
633
650
|
let L;
|
|
634
651
|
n.addEventListener("input", () => {
|
|
635
652
|
clearTimeout(L), L = setTimeout(() => {
|
|
636
|
-
this.searchText.set(s, n.value),
|
|
653
|
+
this.searchText.set(s, n.value), N(n.value);
|
|
637
654
|
}, this.config.debounceMs ?? 150);
|
|
638
655
|
});
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
|
|
656
|
+
const S = document.createElement("div");
|
|
657
|
+
S.className = "tbw-filter-buttons";
|
|
658
|
+
const T = document.createElement("button");
|
|
659
|
+
T.className = "tbw-filter-apply-btn", T.textContent = "Apply", T.addEventListener("click", () => {
|
|
643
660
|
const a = [];
|
|
644
|
-
for (const [d,
|
|
645
|
-
if (!
|
|
661
|
+
for (const [d, p] of v)
|
|
662
|
+
if (!p)
|
|
646
663
|
if (d === "__null__")
|
|
647
664
|
a.push(null);
|
|
648
665
|
else {
|
|
@@ -650,11 +667,11 @@ class y extends P {
|
|
|
650
667
|
a.push(c !== void 0 ? c : d);
|
|
651
668
|
}
|
|
652
669
|
t.applySetFilter(a);
|
|
653
|
-
}),
|
|
654
|
-
const
|
|
655
|
-
|
|
670
|
+
}), S.appendChild(T);
|
|
671
|
+
const k = document.createElement("button");
|
|
672
|
+
k.className = "tbw-filter-clear-btn", k.textContent = "Clear Filter", k.addEventListener("click", () => {
|
|
656
673
|
t.clearFilter();
|
|
657
|
-
}),
|
|
674
|
+
}), S.appendChild(k), e.appendChild(S);
|
|
658
675
|
}
|
|
659
676
|
/**
|
|
660
677
|
* Apply a set filter (exclude values)
|
|
@@ -754,6 +771,6 @@ class y extends P {
|
|
|
754
771
|
`;
|
|
755
772
|
}
|
|
756
773
|
export {
|
|
757
|
-
|
|
774
|
+
x as FilteringPlugin
|
|
758
775
|
};
|
|
759
776
|
//# sourceMappingURL=index.js.map
|