@toolbox-web/grid 1.9.2 → 1.10.0
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.js +489 -402
- package/all.js.map +1 -1
- package/index.js +11 -6
- package/index.js.map +1 -1
- package/lib/core/grid.d.ts +31 -1
- package/lib/core/grid.d.ts.map +1 -1
- package/lib/core/types.d.ts +0 -64
- package/lib/core/types.d.ts.map +1 -1
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/editing/EditingPlugin.d.ts +69 -0
- package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
- package/lib/plugins/editing/editors.d.ts.map +1 -1
- package/lib/plugins/editing/index.d.ts +1 -1
- package/lib/plugins/editing/index.d.ts.map +1 -1
- package/lib/plugins/editing/index.js +426 -293
- package/lib/plugins/editing/index.js.map +1 -1
- package/lib/plugins/editing/types.d.ts +117 -1
- package/lib/plugins/editing/types.d.ts.map +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +7 -7
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/print/index.js.map +1 -1
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/responsive/index.js.map +1 -1
- package/lib/plugins/row-reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/public.d.ts +1 -1
- package/public.d.ts.map +1 -1
- package/umd/grid.all.umd.js +21 -21
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +2 -2
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/editing.umd.js +1 -1
- package/umd/plugins/editing.umd.js.map +1 -1
- package/umd/plugins/pinned-rows.umd.js +1 -1
- package/umd/plugins/pinned-rows.umd.js.map +1 -1
|
@@ -1,33 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
change: "--tbw-row-change-duration",
|
|
3
|
-
insert: "--tbw-row-insert-duration",
|
|
4
|
-
remove: "--tbw-row-remove-duration"
|
|
5
|
-
}, P = {
|
|
6
|
-
change: 500,
|
|
7
|
-
insert: 300,
|
|
8
|
-
remove: 200
|
|
9
|
-
};
|
|
10
|
-
function T(s) {
|
|
11
|
-
const e = s.trim().toLowerCase();
|
|
12
|
-
return e.endsWith("ms") ? parseFloat(e) : e.endsWith("s") ? parseFloat(e) * 1e3 : parseFloat(e);
|
|
13
|
-
}
|
|
14
|
-
function I(s, e) {
|
|
15
|
-
const i = A[e], t = getComputedStyle(s).getPropertyValue(i);
|
|
16
|
-
if (t) {
|
|
17
|
-
const r = T(t);
|
|
18
|
-
if (!isNaN(r) && r > 0)
|
|
19
|
-
return r;
|
|
20
|
-
}
|
|
21
|
-
return P[e];
|
|
22
|
-
}
|
|
23
|
-
function D(s, e, i) {
|
|
24
|
-
s.removeAttribute(R), s.offsetWidth, s.setAttribute(R, e);
|
|
25
|
-
const t = I(s, e);
|
|
26
|
-
setTimeout(() => {
|
|
27
|
-
s.removeAttribute(R);
|
|
28
|
-
}, t);
|
|
29
|
-
}
|
|
30
|
-
const L = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>', q = {
|
|
1
|
+
const S = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>', L = {
|
|
31
2
|
expand: "▶",
|
|
32
3
|
collapse: "▼",
|
|
33
4
|
sortAsc: "▲",
|
|
@@ -36,11 +7,11 @@ const L = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentCo
|
|
|
36
7
|
submenuArrow: "▶",
|
|
37
8
|
dragHandle: "⋮⋮",
|
|
38
9
|
toolPanel: "☰",
|
|
39
|
-
filter:
|
|
40
|
-
filterActive:
|
|
10
|
+
filter: S,
|
|
11
|
+
filterActive: S,
|
|
41
12
|
print: "🖨️"
|
|
42
13
|
};
|
|
43
|
-
class
|
|
14
|
+
class I {
|
|
44
15
|
/**
|
|
45
16
|
* Plugin dependencies - declare other plugins this one requires.
|
|
46
17
|
*
|
|
@@ -167,16 +138,16 @@ class O {
|
|
|
167
138
|
/**
|
|
168
139
|
* Emit a custom event from the grid.
|
|
169
140
|
*/
|
|
170
|
-
emit(e,
|
|
171
|
-
this.grid?.dispatchEvent?.(new CustomEvent(e, { detail:
|
|
141
|
+
emit(e, t) {
|
|
142
|
+
this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
|
|
172
143
|
}
|
|
173
144
|
/**
|
|
174
145
|
* Emit a cancelable custom event from the grid.
|
|
175
146
|
* @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
|
|
176
147
|
*/
|
|
177
|
-
emitCancelable(e,
|
|
178
|
-
const
|
|
179
|
-
return this.grid?.dispatchEvent?.(
|
|
148
|
+
emitCancelable(e, t) {
|
|
149
|
+
const i = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
|
|
150
|
+
return this.grid?.dispatchEvent?.(i), i.defaultPrevented;
|
|
180
151
|
}
|
|
181
152
|
// =========================================================================
|
|
182
153
|
// Event Bus - Plugin-to-Plugin Communication
|
|
@@ -197,8 +168,8 @@ class O {
|
|
|
197
168
|
* });
|
|
198
169
|
* ```
|
|
199
170
|
*/
|
|
200
|
-
on(e,
|
|
201
|
-
this.grid?._pluginManager?.subscribe(this, e,
|
|
171
|
+
on(e, t) {
|
|
172
|
+
this.grid?._pluginManager?.subscribe(this, e, t);
|
|
202
173
|
}
|
|
203
174
|
/**
|
|
204
175
|
* Unsubscribe from a plugin event.
|
|
@@ -232,8 +203,8 @@ class O {
|
|
|
232
203
|
* this.emit('filter-change', { field: 'name', value: 'Alice' });
|
|
233
204
|
* ```
|
|
234
205
|
*/
|
|
235
|
-
emitPluginEvent(e,
|
|
236
|
-
this.grid?._pluginManager?.emitPluginEvent(e,
|
|
206
|
+
emitPluginEvent(e, t) {
|
|
207
|
+
this.grid?._pluginManager?.emitPluginEvent(e, t);
|
|
237
208
|
}
|
|
238
209
|
/**
|
|
239
210
|
* Request a re-render of the grid.
|
|
@@ -330,7 +301,7 @@ class O {
|
|
|
330
301
|
*/
|
|
331
302
|
get gridIcons() {
|
|
332
303
|
const e = this.grid?.gridConfig?.icons ?? {};
|
|
333
|
-
return { ...
|
|
304
|
+
return { ...L, ...e };
|
|
334
305
|
}
|
|
335
306
|
// #region Animation Helpers
|
|
336
307
|
/**
|
|
@@ -353,8 +324,8 @@ class O {
|
|
|
353
324
|
const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
|
|
354
325
|
if (e === !1 || e === "off") return !1;
|
|
355
326
|
if (e === !0 || e === "on") return !0;
|
|
356
|
-
const
|
|
357
|
-
return
|
|
327
|
+
const t = this.gridElement;
|
|
328
|
+
return t ? getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
|
|
358
329
|
}
|
|
359
330
|
/**
|
|
360
331
|
* Get the animation duration in milliseconds from CSS variable.
|
|
@@ -371,8 +342,8 @@ class O {
|
|
|
371
342
|
get animationDuration() {
|
|
372
343
|
const e = this.gridElement;
|
|
373
344
|
if (e) {
|
|
374
|
-
const
|
|
375
|
-
if (!isNaN(
|
|
345
|
+
const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), i = parseInt(t, 10);
|
|
346
|
+
if (!isNaN(i)) return i;
|
|
376
347
|
}
|
|
377
348
|
return 200;
|
|
378
349
|
}
|
|
@@ -385,8 +356,8 @@ class O {
|
|
|
385
356
|
* @param pluginOverride - Optional plugin-level override
|
|
386
357
|
* @returns The resolved icon value
|
|
387
358
|
*/
|
|
388
|
-
resolveIcon(e,
|
|
389
|
-
return
|
|
359
|
+
resolveIcon(e, t) {
|
|
360
|
+
return t !== void 0 ? t : this.gridIcons[e];
|
|
390
361
|
}
|
|
391
362
|
/**
|
|
392
363
|
* Set an icon value on an element.
|
|
@@ -395,8 +366,8 @@ class O {
|
|
|
395
366
|
* @param element - The element to set the icon on
|
|
396
367
|
* @param icon - The icon value (string or HTMLElement)
|
|
397
368
|
*/
|
|
398
|
-
setIcon(e,
|
|
399
|
-
typeof
|
|
369
|
+
setIcon(e, t) {
|
|
370
|
+
typeof t == "string" ? e.innerHTML = t : t instanceof HTMLElement && (e.innerHTML = "", e.appendChild(t.cloneNode(!0)));
|
|
400
371
|
}
|
|
401
372
|
/**
|
|
402
373
|
* Log a warning message.
|
|
@@ -406,88 +377,97 @@ class O {
|
|
|
406
377
|
}
|
|
407
378
|
// #endregion
|
|
408
379
|
}
|
|
409
|
-
const
|
|
410
|
-
function
|
|
380
|
+
const A = "@layer tbw-plugins{tbw-grid{--tbw-editing-bg: var(--tbw-color-selection);--tbw-editing-row-bg: var(--tbw-editing-bg);--tbw-editing-border: var(--tbw-border-input, 1px solid var(--tbw-color-border-strong));--tbw-padding-editing-input: var(--tbw-cell-padding-input, 2px 6px);--tbw-font-size-editor: inherit;--tbw-editing-row-outline-color: var(--tbw-color-accent);--tbw-editing-row-outline-width: 1px;--tbw-invalid-bg: light-dark(#fef2f2, #450a0a);--tbw-invalid-border-color: light-dark(#ef4444, #f87171)}tbw-grid .data-grid-row:has(.editing){background:var(--tbw-editing-row-bg);outline:var(--tbw-editing-row-outline-width) solid var(--tbw-editing-row-outline-color);outline-offset:calc(-1 * var(--tbw-editing-row-outline-width))}tbw-grid .data-grid-row>.cell.editing{overflow:hidden;padding:0;display:flex;min-height:calc(var(--tbw-row-height) + 2px);align-items:center;justify-content:center}tbw-grid .data-grid-row>.cell.editing input:not([type=checkbox]),tbw-grid .data-grid-row>.cell.editing select,tbw-grid .data-grid-row>.cell.editing textarea{width:100%;height:100%;flex:1 1 auto;min-width:0;border:var(--tbw-editing-border);padding:var(--tbw-padding-editing-input);font-size:var(--tbw-font-size-editor)}tbw-grid .tbw-editor-host{display:contents}tbw-grid .data-grid-row>.cell[data-invalid=true]{background:var(--tbw-invalid-bg);outline:1px solid var(--tbw-invalid-border-color);outline-offset:-1px}}";
|
|
381
|
+
function P(s) {
|
|
411
382
|
const e = s.options;
|
|
412
383
|
return e ? typeof e == "function" ? e() : e : [];
|
|
413
384
|
}
|
|
414
|
-
function
|
|
385
|
+
function T(s) {
|
|
415
386
|
return (e) => {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
const r = () => e.commit(
|
|
419
|
-
return
|
|
387
|
+
const t = s.editorParams, i = document.createElement("input");
|
|
388
|
+
i.type = "number", i.value = e.value != null ? String(e.value) : "", t?.min !== void 0 && (i.min = String(t.min)), t?.max !== void 0 && (i.max = String(t.max)), t?.step !== void 0 && (i.step = String(t.step)), t?.placeholder && (i.placeholder = t.placeholder);
|
|
389
|
+
const r = () => e.commit(i.value === "" ? null : Number(i.value));
|
|
390
|
+
return i.addEventListener("blur", r), i.addEventListener("keydown", (n) => {
|
|
420
391
|
n.key === "Enter" && r(), n.key === "Escape" && e.cancel();
|
|
421
|
-
}),
|
|
392
|
+
}), i;
|
|
422
393
|
};
|
|
423
394
|
}
|
|
424
|
-
function
|
|
395
|
+
function q() {
|
|
425
396
|
return (s) => {
|
|
426
397
|
const e = document.createElement("input");
|
|
427
398
|
return e.type = "checkbox", e.checked = !!s.value, e.addEventListener("change", () => s.commit(e.checked)), e;
|
|
428
399
|
};
|
|
429
400
|
}
|
|
430
|
-
function
|
|
401
|
+
function O(s) {
|
|
431
402
|
return (e) => {
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
403
|
+
const t = s.editorParams, i = document.createElement("input");
|
|
404
|
+
i.type = "date", e.value instanceof Date ? i.valueAsDate = e.value : typeof e.value == "string" && e.value && (i.value = e.value.split("T")[0]), t?.min && (i.min = t.min), t?.max && (i.max = t.max), t?.placeholder && (i.placeholder = t.placeholder);
|
|
405
|
+
const r = () => {
|
|
406
|
+
typeof e.value == "string" ? e.commit(i.value) : e.commit(i.valueAsDate);
|
|
407
|
+
};
|
|
408
|
+
return i.addEventListener("change", r), i.addEventListener("keydown", (n) => {
|
|
409
|
+
n.key === "Escape" && e.cancel();
|
|
410
|
+
}), i;
|
|
436
411
|
};
|
|
437
412
|
}
|
|
438
|
-
function
|
|
413
|
+
function D(s) {
|
|
439
414
|
return (e) => {
|
|
440
|
-
const
|
|
441
|
-
if (s.multi && (
|
|
415
|
+
const t = s.editorParams, i = document.createElement("select");
|
|
416
|
+
if (s.multi && (i.multiple = !0), t?.includeEmpty) {
|
|
442
417
|
const o = document.createElement("option");
|
|
443
|
-
o.value = "", o.textContent =
|
|
418
|
+
o.value = "", o.textContent = t.emptyLabel ?? "", i.appendChild(o);
|
|
444
419
|
}
|
|
445
|
-
|
|
420
|
+
P(s).forEach((o) => {
|
|
446
421
|
const a = document.createElement("option");
|
|
447
|
-
a.value = String(o.value), a.textContent = o.label, (s.multi && Array.isArray(e.value) && e.value.includes(o.value) || !s.multi && e.value === o.value) && (a.selected = !0),
|
|
422
|
+
a.value = String(o.value), a.textContent = o.label, (s.multi && Array.isArray(e.value) && e.value.includes(o.value) || !s.multi && e.value === o.value) && (a.selected = !0), i.appendChild(a);
|
|
448
423
|
});
|
|
449
424
|
const n = () => {
|
|
450
425
|
if (s.multi) {
|
|
451
|
-
const o = Array.from(
|
|
426
|
+
const o = Array.from(i.selectedOptions).map((a) => a.value);
|
|
452
427
|
e.commit(o);
|
|
453
428
|
} else
|
|
454
|
-
e.commit(
|
|
429
|
+
e.commit(i.value);
|
|
455
430
|
};
|
|
456
|
-
return
|
|
431
|
+
return i.addEventListener("change", n), i.addEventListener("blur", n), i.addEventListener("keydown", (o) => {
|
|
457
432
|
o.key === "Escape" && e.cancel();
|
|
458
|
-
}),
|
|
433
|
+
}), i;
|
|
459
434
|
};
|
|
460
435
|
}
|
|
461
|
-
function
|
|
436
|
+
function M(s) {
|
|
462
437
|
return (e) => {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
438
|
+
const t = s.editorParams, i = document.createElement("input");
|
|
439
|
+
i.type = "text", i.value = e.value != null ? String(e.value) : "", t?.maxLength !== void 0 && (i.maxLength = t.maxLength), t?.pattern && (i.pattern = t.pattern), t?.placeholder && (i.placeholder = t.placeholder);
|
|
440
|
+
const r = () => {
|
|
441
|
+
const n = i.value;
|
|
442
|
+
typeof e.value == "number" && n !== "" ? e.commit(Number(n)) : e.commit(n);
|
|
443
|
+
};
|
|
444
|
+
return i.addEventListener("blur", r), i.addEventListener("keydown", (n) => {
|
|
445
|
+
n.key === "Enter" && r(), n.key === "Escape" && e.cancel();
|
|
446
|
+
}), i;
|
|
467
447
|
};
|
|
468
448
|
}
|
|
469
|
-
function
|
|
449
|
+
function N(s) {
|
|
470
450
|
switch (s.type) {
|
|
471
451
|
case "number":
|
|
472
|
-
return
|
|
452
|
+
return T(s);
|
|
473
453
|
case "boolean":
|
|
474
|
-
return
|
|
454
|
+
return q();
|
|
475
455
|
case "date":
|
|
476
|
-
return
|
|
456
|
+
return O(s);
|
|
477
457
|
case "select":
|
|
478
|
-
return
|
|
458
|
+
return D(s);
|
|
479
459
|
default:
|
|
480
|
-
return
|
|
460
|
+
return M(s);
|
|
481
461
|
}
|
|
482
462
|
}
|
|
483
|
-
const
|
|
484
|
-
function
|
|
463
|
+
const R = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
|
|
464
|
+
function G(s, e) {
|
|
485
465
|
if (e.editor) return e.editor;
|
|
486
466
|
if (e.__editorTemplate) return "template";
|
|
487
467
|
if (!e.type) return;
|
|
488
|
-
const
|
|
489
|
-
if (
|
|
490
|
-
return
|
|
468
|
+
const i = s.effectiveConfig?.typeDefaults;
|
|
469
|
+
if (i?.[e.type]?.editor)
|
|
470
|
+
return i[e.type].editor;
|
|
491
471
|
const r = s.__frameworkAdapter;
|
|
492
472
|
if (r?.getTypeDefault) {
|
|
493
473
|
const n = r.getTypeDefault(e.type);
|
|
@@ -495,28 +475,28 @@ function B(s, e) {
|
|
|
495
475
|
return n.editor;
|
|
496
476
|
}
|
|
497
477
|
}
|
|
498
|
-
function
|
|
478
|
+
function w(s) {
|
|
499
479
|
return !(typeof s != "string" || s === "__proto__" || s === "constructor" || s === "prototype");
|
|
500
480
|
}
|
|
501
|
-
function
|
|
481
|
+
function H(s) {
|
|
502
482
|
const e = (s.__editingCellCount ?? 0) + 1;
|
|
503
483
|
s.__editingCellCount = e, s.setAttribute("data-has-editing", "");
|
|
504
484
|
}
|
|
505
|
-
function
|
|
485
|
+
function x(s) {
|
|
506
486
|
s.__editingCellCount = 0, s.removeAttribute("data-has-editing");
|
|
507
487
|
}
|
|
508
|
-
function E(s, e) {
|
|
509
|
-
return s instanceof HTMLInputElement ? s.type === "checkbox" ? s.checked : s.type === "number" ? s.value === "" ? null : Number(s.value) : s.type === "date" ? s.valueAsDate : s.value : e?.type === "number" && s.value !== "" ? Number(s.value) : s.value;
|
|
488
|
+
function E(s, e, t) {
|
|
489
|
+
return s instanceof HTMLInputElement ? s.type === "checkbox" ? s.checked : s.type === "number" ? s.value === "" ? null : Number(s.value) : s.type === "date" ? typeof t == "string" ? s.value : s.valueAsDate : typeof t == "number" ? s.value === "" ? null : Number(s.value) : s.value : e?.type === "number" && s.value !== "" || typeof t == "number" && s.value !== "" ? Number(s.value) : s.value;
|
|
510
490
|
}
|
|
511
491
|
function k(s) {
|
|
512
492
|
}
|
|
513
|
-
function
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}),
|
|
493
|
+
function $(s, e, t, i) {
|
|
494
|
+
const r = s.querySelector("input,textarea,select");
|
|
495
|
+
r && (r.addEventListener("blur", () => {
|
|
496
|
+
t(E(r, e, i));
|
|
497
|
+
}), r instanceof HTMLInputElement && r.type === "checkbox" ? r.addEventListener("change", () => t(r.checked)) : r instanceof HTMLSelectElement && r.addEventListener("change", () => t(E(r, e, i))));
|
|
518
498
|
}
|
|
519
|
-
class
|
|
499
|
+
class z extends I {
|
|
520
500
|
/**
|
|
521
501
|
* Plugin manifest - declares owned properties for configuration validation.
|
|
522
502
|
* @internal
|
|
@@ -556,7 +536,7 @@ class K extends O {
|
|
|
556
536
|
/** @internal */
|
|
557
537
|
name = "editing";
|
|
558
538
|
/** @internal */
|
|
559
|
-
styles =
|
|
539
|
+
styles = A;
|
|
560
540
|
/** @internal */
|
|
561
541
|
get defaultConfig() {
|
|
562
542
|
return {
|
|
@@ -567,22 +547,29 @@ class K extends O {
|
|
|
567
547
|
/** Currently active edit row index, or -1 if not editing */
|
|
568
548
|
#e = -1;
|
|
569
549
|
/** Currently active edit column index, or -1 if not editing */
|
|
570
|
-
#
|
|
550
|
+
#o = -1;
|
|
571
551
|
/** Snapshots of row data before editing started */
|
|
572
|
-
#
|
|
552
|
+
#s = /* @__PURE__ */ new Map();
|
|
573
553
|
/** Set of row IDs that have been modified (ID-based for stability) */
|
|
574
|
-
#
|
|
554
|
+
#i = /* @__PURE__ */ new Set();
|
|
575
555
|
/** Set of cells currently in edit mode: "rowIndex:colIndex" */
|
|
576
|
-
#
|
|
556
|
+
#r = /* @__PURE__ */ new Set();
|
|
577
557
|
/** Flag to restore focus after next render (used when exiting edit mode) */
|
|
578
|
-
#
|
|
558
|
+
#a = !1;
|
|
559
|
+
/** Row index pending animation after render, or -1 if none */
|
|
560
|
+
#l = -1;
|
|
561
|
+
/**
|
|
562
|
+
* Invalid cell tracking: Map<rowId, Map<field, message>>
|
|
563
|
+
* Used for validation feedback without canceling edits.
|
|
564
|
+
*/
|
|
565
|
+
#t = /* @__PURE__ */ new Map();
|
|
579
566
|
// #endregion
|
|
580
567
|
// #region Lifecycle
|
|
581
568
|
/** @internal */
|
|
582
569
|
attach(e) {
|
|
583
570
|
super.attach(e);
|
|
584
|
-
const
|
|
585
|
-
|
|
571
|
+
const t = this.disconnectSignal, i = e;
|
|
572
|
+
i._activeEditRows = -1, i._rowEditSnapshots = /* @__PURE__ */ new Map(), Object.defineProperty(e, "changedRows", {
|
|
586
573
|
get: () => this.changedRows,
|
|
587
574
|
configurable: !0
|
|
588
575
|
}), Object.defineProperty(e, "changedRowIds", {
|
|
@@ -593,24 +580,24 @@ class K extends O {
|
|
|
593
580
|
}, document.addEventListener(
|
|
594
581
|
"keydown",
|
|
595
582
|
(r) => {
|
|
596
|
-
r.key === "Escape" && this.#e !== -1 && this.#
|
|
583
|
+
r.key === "Escape" && this.#e !== -1 && this.#n(this.#e, !0);
|
|
597
584
|
},
|
|
598
|
-
{ capture: !0, signal:
|
|
585
|
+
{ capture: !0, signal: t }
|
|
599
586
|
), document.addEventListener(
|
|
600
587
|
"mousedown",
|
|
601
588
|
(r) => {
|
|
602
589
|
if (this.#e === -1) return;
|
|
603
|
-
const n =
|
|
590
|
+
const n = i.findRenderedRowElement?.(this.#e);
|
|
604
591
|
!n || (r.composedPath && r.composedPath() || []).includes(n) || queueMicrotask(() => {
|
|
605
|
-
this.#e !== -1 && this.#
|
|
592
|
+
this.#e !== -1 && this.#n(this.#e, !1);
|
|
606
593
|
});
|
|
607
594
|
},
|
|
608
|
-
{ signal:
|
|
595
|
+
{ signal: t }
|
|
609
596
|
);
|
|
610
597
|
}
|
|
611
598
|
/** @internal */
|
|
612
599
|
detach() {
|
|
613
|
-
this.#e = -1, this.#
|
|
600
|
+
this.#e = -1, this.#o = -1, this.#s.clear(), this.#i.clear(), this.#r.clear(), super.detach();
|
|
614
601
|
}
|
|
615
602
|
/**
|
|
616
603
|
* Handle plugin queries.
|
|
@@ -629,30 +616,30 @@ class K extends O {
|
|
|
629
616
|
* @internal
|
|
630
617
|
*/
|
|
631
618
|
onCellClick(e) {
|
|
632
|
-
const
|
|
633
|
-
if (
|
|
619
|
+
const t = this.grid, i = this.config.editOn ?? t.effectiveConfig?.editOn;
|
|
620
|
+
if (i === !1 || i === "manual" || i !== "click" && i !== "dblclick") return !1;
|
|
634
621
|
const r = e.originalEvent.type === "dblclick";
|
|
635
|
-
if (
|
|
622
|
+
if (i === "click" && r || i === "dblclick" && !r) return !1;
|
|
636
623
|
const { rowIndex: n } = e;
|
|
637
|
-
return
|
|
624
|
+
return t._columns?.some((a) => a.editable) ? (e.originalEvent.stopPropagation(), this.beginBulkEdit(n), !0) : !1;
|
|
638
625
|
}
|
|
639
626
|
/**
|
|
640
627
|
* Handle keyboard events for edit lifecycle.
|
|
641
628
|
* @internal
|
|
642
629
|
*/
|
|
643
630
|
onKeyDown(e) {
|
|
644
|
-
const
|
|
631
|
+
const t = this.grid;
|
|
645
632
|
if (e.key === "Escape" && this.#e !== -1)
|
|
646
|
-
return this.#
|
|
633
|
+
return this.#n(this.#e, !0), !0;
|
|
647
634
|
if (e.key === " " || e.key === "Spacebar") {
|
|
648
|
-
const
|
|
649
|
-
if (
|
|
650
|
-
const n =
|
|
635
|
+
const i = t._focusRow, r = t._focusCol;
|
|
636
|
+
if (i >= 0 && r >= 0) {
|
|
637
|
+
const n = t._visibleColumns[r], o = t._rows[i];
|
|
651
638
|
if (n?.editable && n.type === "boolean" && o) {
|
|
652
639
|
const a = n.field;
|
|
653
|
-
if (
|
|
654
|
-
const
|
|
655
|
-
return this.#
|
|
640
|
+
if (w(a)) {
|
|
641
|
+
const d = !o[a];
|
|
642
|
+
return this.#u(i, n, d, o), e.preventDefault(), this.requestRender(), !0;
|
|
656
643
|
}
|
|
657
644
|
}
|
|
658
645
|
}
|
|
@@ -661,31 +648,31 @@ class K extends O {
|
|
|
661
648
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
662
649
|
if (this.#e !== -1)
|
|
663
650
|
return !1;
|
|
664
|
-
const
|
|
665
|
-
if (
|
|
666
|
-
const r =
|
|
667
|
-
if (r >= 0 &&
|
|
668
|
-
const a =
|
|
651
|
+
const i = this.config.editOn ?? t.effectiveConfig?.editOn;
|
|
652
|
+
if (i === !1 || i === "manual") return !1;
|
|
653
|
+
const r = t._focusRow, n = t._focusCol;
|
|
654
|
+
if (r >= 0 && t._columns?.some((a) => a.editable)) {
|
|
655
|
+
const a = t._visibleColumns[n], l = t._rows[r], d = a?.field ?? "", c = d && l ? l[d] : void 0, p = this.gridElement.querySelector(`[data-row="${r}"][data-col="${n}"]`), u = new CustomEvent("cell-activate", {
|
|
669
656
|
cancelable: !0,
|
|
670
657
|
bubbles: !0,
|
|
671
658
|
detail: {
|
|
672
659
|
rowIndex: r,
|
|
673
660
|
colIndex: n,
|
|
674
|
-
field:
|
|
675
|
-
value:
|
|
661
|
+
field: d,
|
|
662
|
+
value: c,
|
|
676
663
|
row: l,
|
|
677
|
-
cellEl:
|
|
664
|
+
cellEl: p,
|
|
678
665
|
trigger: "keyboard",
|
|
679
666
|
originalEvent: e
|
|
680
667
|
}
|
|
681
668
|
});
|
|
682
|
-
this.gridElement.dispatchEvent(
|
|
683
|
-
const
|
|
669
|
+
this.gridElement.dispatchEvent(u);
|
|
670
|
+
const m = new CustomEvent("activate-cell", {
|
|
684
671
|
cancelable: !0,
|
|
685
672
|
bubbles: !0,
|
|
686
673
|
detail: { row: r, col: n }
|
|
687
674
|
});
|
|
688
|
-
return this.gridElement.dispatchEvent(
|
|
675
|
+
return this.gridElement.dispatchEvent(m), u.defaultPrevented || m.defaultPrevented ? (e.preventDefault(), !0) : (this.beginBulkEdit(r), !0);
|
|
689
676
|
}
|
|
690
677
|
return !1;
|
|
691
678
|
}
|
|
@@ -699,11 +686,11 @@ class K extends O {
|
|
|
699
686
|
* @internal
|
|
700
687
|
*/
|
|
701
688
|
processColumns(e) {
|
|
702
|
-
const
|
|
703
|
-
return !
|
|
689
|
+
const t = this.grid, i = t.effectiveConfig?.typeDefaults, r = t.__frameworkAdapter;
|
|
690
|
+
return !i && !r?.getTypeDefault ? e : e.map((n) => {
|
|
704
691
|
if (!n.type) return n;
|
|
705
692
|
let o;
|
|
706
|
-
if (
|
|
693
|
+
if (i?.[n.type]?.editorParams && (o = i[n.type].editorParams), !o && r?.getTypeDefault) {
|
|
707
694
|
const a = r.getTypeDefault(n.type);
|
|
708
695
|
a?.editorParams && (o = a.editorParams);
|
|
709
696
|
}
|
|
@@ -721,14 +708,18 @@ class K extends O {
|
|
|
721
708
|
*/
|
|
722
709
|
afterRender() {
|
|
723
710
|
const e = this.grid;
|
|
724
|
-
if (this.#
|
|
725
|
-
|
|
726
|
-
|
|
711
|
+
if (this.#a && (this.#a = !1, this.#g(e)), this.#l !== -1) {
|
|
712
|
+
const t = this.#l;
|
|
713
|
+
this.#l = -1, e.animateRow?.(t, "change");
|
|
714
|
+
}
|
|
715
|
+
if (this.#r.size !== 0)
|
|
716
|
+
for (const t of this.#r) {
|
|
717
|
+
const [i, r] = t.split(":"), n = parseInt(i, 10), o = parseInt(r, 10), a = e.findRenderedRowElement?.(n);
|
|
727
718
|
if (!a) continue;
|
|
728
719
|
const l = a.querySelector(`.cell[data-col="${o}"]`);
|
|
729
720
|
if (!l || l.classList.contains("editing")) continue;
|
|
730
|
-
const
|
|
731
|
-
|
|
721
|
+
const d = e._rows[n], c = e._visibleColumns[o];
|
|
722
|
+
d && c && this.#f(d, n, c, o, l, !0);
|
|
732
723
|
}
|
|
733
724
|
}
|
|
734
725
|
/**
|
|
@@ -746,9 +737,9 @@ class K extends O {
|
|
|
746
737
|
*/
|
|
747
738
|
get changedRows() {
|
|
748
739
|
const e = [];
|
|
749
|
-
for (const
|
|
750
|
-
const
|
|
751
|
-
|
|
740
|
+
for (const t of this.#i) {
|
|
741
|
+
const i = this.grid.getRow(t);
|
|
742
|
+
i && e.push(i);
|
|
752
743
|
}
|
|
753
744
|
return e;
|
|
754
745
|
}
|
|
@@ -756,7 +747,7 @@ class K extends O {
|
|
|
756
747
|
* Get IDs of all modified rows.
|
|
757
748
|
*/
|
|
758
749
|
get changedRowIds() {
|
|
759
|
-
return Array.from(this.#
|
|
750
|
+
return Array.from(this.#i);
|
|
760
751
|
}
|
|
761
752
|
/**
|
|
762
753
|
* Get the currently active edit row index, or -1 if not editing.
|
|
@@ -768,7 +759,7 @@ class K extends O {
|
|
|
768
759
|
* Get the currently active edit column index, or -1 if not editing.
|
|
769
760
|
*/
|
|
770
761
|
get activeEditCol() {
|
|
771
|
-
return this.#
|
|
762
|
+
return this.#o;
|
|
772
763
|
}
|
|
773
764
|
/**
|
|
774
765
|
* Check if a specific row is currently being edited.
|
|
@@ -779,19 +770,19 @@ class K extends O {
|
|
|
779
770
|
/**
|
|
780
771
|
* Check if a specific cell is currently being edited.
|
|
781
772
|
*/
|
|
782
|
-
isCellEditing(e,
|
|
783
|
-
return this.#
|
|
773
|
+
isCellEditing(e, t) {
|
|
774
|
+
return this.#r.has(`${e}:${t}`);
|
|
784
775
|
}
|
|
785
776
|
/**
|
|
786
777
|
* Check if a specific row has been modified.
|
|
787
778
|
* @param rowIndex - Row index to check (will be converted to ID internally)
|
|
788
779
|
*/
|
|
789
780
|
isRowChanged(e) {
|
|
790
|
-
const
|
|
791
|
-
if (!
|
|
781
|
+
const t = this.grid, i = t._rows[e];
|
|
782
|
+
if (!i) return !1;
|
|
792
783
|
try {
|
|
793
|
-
const r =
|
|
794
|
-
return r ? this.#
|
|
784
|
+
const r = t.getRowId?.(i);
|
|
785
|
+
return r ? this.#i.has(r) : !1;
|
|
795
786
|
} catch {
|
|
796
787
|
return !1;
|
|
797
788
|
}
|
|
@@ -801,16 +792,136 @@ class K extends O {
|
|
|
801
792
|
* @param rowId - Row ID to check
|
|
802
793
|
*/
|
|
803
794
|
isRowChangedById(e) {
|
|
804
|
-
return this.#
|
|
795
|
+
return this.#i.has(e);
|
|
796
|
+
}
|
|
797
|
+
// #region Cell Validation
|
|
798
|
+
/**
|
|
799
|
+
* Mark a cell as invalid with an optional validation message.
|
|
800
|
+
* Invalid cells are marked with a `data-invalid` attribute for styling.
|
|
801
|
+
*
|
|
802
|
+
* @param rowId - The row ID (from getRowId)
|
|
803
|
+
* @param field - The field name
|
|
804
|
+
* @param message - Optional validation message (for tooltips or display)
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```typescript
|
|
808
|
+
* // In cell-commit handler:
|
|
809
|
+
* grid.addEventListener('cell-commit', (e) => {
|
|
810
|
+
* if (e.detail.field === 'email' && !isValidEmail(e.detail.value)) {
|
|
811
|
+
* e.detail.setInvalid('Invalid email format');
|
|
812
|
+
* }
|
|
813
|
+
* });
|
|
814
|
+
*
|
|
815
|
+
* // Or programmatically:
|
|
816
|
+
* editingPlugin.setInvalid('row-123', 'email', 'Invalid email format');
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
819
|
+
setInvalid(e, t, i = "") {
|
|
820
|
+
let r = this.#t.get(e);
|
|
821
|
+
r || (r = /* @__PURE__ */ new Map(), this.#t.set(e, r)), r.set(t, i), this.#d(e, t, !0);
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Clear the invalid state for a specific cell.
|
|
825
|
+
*
|
|
826
|
+
* @param rowId - The row ID (from getRowId)
|
|
827
|
+
* @param field - The field name
|
|
828
|
+
*/
|
|
829
|
+
clearInvalid(e, t) {
|
|
830
|
+
const i = this.#t.get(e);
|
|
831
|
+
i && (i.delete(t), i.size === 0 && this.#t.delete(e)), this.#d(e, t, !1);
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Clear all invalid cells for a specific row.
|
|
835
|
+
*
|
|
836
|
+
* @param rowId - The row ID (from getRowId)
|
|
837
|
+
*/
|
|
838
|
+
clearRowInvalid(e) {
|
|
839
|
+
const t = this.#t.get(e);
|
|
840
|
+
if (t) {
|
|
841
|
+
const i = Array.from(t.keys());
|
|
842
|
+
this.#t.delete(e), i.forEach((r) => this.#d(e, r, !1));
|
|
843
|
+
}
|
|
805
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* Clear all invalid cell states across all rows.
|
|
847
|
+
*/
|
|
848
|
+
clearAllInvalid() {
|
|
849
|
+
const e = Array.from(this.#t.entries());
|
|
850
|
+
this.#t.clear(), e.forEach(([t, i]) => {
|
|
851
|
+
i.forEach((r, n) => this.#d(t, n, !1));
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Check if a specific cell is marked as invalid.
|
|
856
|
+
*
|
|
857
|
+
* @param rowId - The row ID (from getRowId)
|
|
858
|
+
* @param field - The field name
|
|
859
|
+
* @returns True if the cell is marked as invalid
|
|
860
|
+
*/
|
|
861
|
+
isCellInvalid(e, t) {
|
|
862
|
+
return this.#t.get(e)?.has(t) ?? !1;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Get the validation message for an invalid cell.
|
|
866
|
+
*
|
|
867
|
+
* @param rowId - The row ID (from getRowId)
|
|
868
|
+
* @param field - The field name
|
|
869
|
+
* @returns The validation message, or undefined if cell is valid
|
|
870
|
+
*/
|
|
871
|
+
getInvalidMessage(e, t) {
|
|
872
|
+
return this.#t.get(e)?.get(t);
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Check if a row has any invalid cells.
|
|
876
|
+
*
|
|
877
|
+
* @param rowId - The row ID (from getRowId)
|
|
878
|
+
* @returns True if the row has at least one invalid cell
|
|
879
|
+
*/
|
|
880
|
+
hasInvalidCells(e) {
|
|
881
|
+
const t = this.#t.get(e);
|
|
882
|
+
return t ? t.size > 0 : !1;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Get all invalid fields for a row.
|
|
886
|
+
*
|
|
887
|
+
* @param rowId - The row ID (from getRowId)
|
|
888
|
+
* @returns Map of field names to validation messages
|
|
889
|
+
*/
|
|
890
|
+
getInvalidFields(e) {
|
|
891
|
+
return new Map(this.#t.get(e) ?? []);
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Sync the data-invalid attribute on a cell element.
|
|
895
|
+
*/
|
|
896
|
+
#d(e, t, i) {
|
|
897
|
+
const r = this.grid, n = r._visibleColumns?.findIndex((c) => c.field === t);
|
|
898
|
+
if (n === -1 || n === void 0) return;
|
|
899
|
+
const a = r._rows?.findIndex((c) => {
|
|
900
|
+
try {
|
|
901
|
+
return r.getRowId?.(c) === e;
|
|
902
|
+
} catch {
|
|
903
|
+
return !1;
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
if (a === -1 || a === void 0) return;
|
|
907
|
+
const d = r.findRenderedRowElement?.(a)?.querySelector(`.cell[data-col="${n}"]`);
|
|
908
|
+
if (d)
|
|
909
|
+
if (i) {
|
|
910
|
+
d.setAttribute("data-invalid", "true");
|
|
911
|
+
const c = this.#t.get(e)?.get(t);
|
|
912
|
+
c && d.setAttribute("title", c);
|
|
913
|
+
} else
|
|
914
|
+
d.removeAttribute("data-invalid"), d.removeAttribute("title");
|
|
915
|
+
}
|
|
916
|
+
// #endregion
|
|
806
917
|
/**
|
|
807
918
|
* Reset all change tracking.
|
|
808
919
|
* @param silent - If true, suppresses the `changed-rows-reset` event
|
|
809
920
|
* @fires changed-rows-reset - Emitted when tracking is reset (unless silent)
|
|
810
921
|
*/
|
|
811
922
|
resetChangedRows(e) {
|
|
812
|
-
const
|
|
813
|
-
this.#
|
|
923
|
+
const t = this.changedRows, i = this.changedRowIds;
|
|
924
|
+
this.#i.clear(), this.#c(), e || this.emit("changed-rows-reset", { rows: t, ids: i }), this.grid._rowPool?.forEach((n) => n.classList.remove("changed"));
|
|
814
925
|
}
|
|
815
926
|
/**
|
|
816
927
|
* Programmatically begin editing a cell.
|
|
@@ -818,11 +929,11 @@ class K extends O {
|
|
|
818
929
|
* @param field - Field name of the column to edit
|
|
819
930
|
* @fires cell-commit - Emitted when the cell value is committed (on blur or Enter)
|
|
820
931
|
*/
|
|
821
|
-
beginCellEdit(e,
|
|
822
|
-
const
|
|
823
|
-
if (r === -1 || !
|
|
824
|
-
const a =
|
|
825
|
-
a && this.#
|
|
932
|
+
beginCellEdit(e, t) {
|
|
933
|
+
const i = this.grid, r = i._visibleColumns.findIndex((l) => l.field === t);
|
|
934
|
+
if (r === -1 || !i._visibleColumns[r]?.editable) return;
|
|
935
|
+
const a = i.findRenderedRowElement?.(e)?.querySelector(`.cell[data-col="${r}"]`);
|
|
936
|
+
a && this.#p(e, r, a);
|
|
826
937
|
}
|
|
827
938
|
/**
|
|
828
939
|
* Programmatically begin editing all editable cells in a row.
|
|
@@ -831,21 +942,21 @@ class K extends O {
|
|
|
831
942
|
* @fires row-commit - Emitted when focus leaves the row
|
|
832
943
|
*/
|
|
833
944
|
beginBulkEdit(e) {
|
|
834
|
-
const
|
|
835
|
-
if ((this.config.editOn ??
|
|
836
|
-
const n =
|
|
945
|
+
const t = this.grid;
|
|
946
|
+
if ((this.config.editOn ?? t.effectiveConfig?.editOn) === !1 || !t._columns?.some((a) => a.editable)) return;
|
|
947
|
+
const n = t.findRenderedRowElement?.(e);
|
|
837
948
|
if (!n) return;
|
|
838
|
-
const o =
|
|
839
|
-
this.#
|
|
840
|
-
const
|
|
841
|
-
if (
|
|
842
|
-
const
|
|
843
|
-
|
|
949
|
+
const o = t._rows[e];
|
|
950
|
+
this.#h(e, o), Array.from(n.children).forEach((a, l) => {
|
|
951
|
+
const d = t._visibleColumns[l];
|
|
952
|
+
if (d?.editable) {
|
|
953
|
+
const c = a;
|
|
954
|
+
c.classList.contains("editing") || this.#f(o, e, d, l, c, !0);
|
|
844
955
|
}
|
|
845
956
|
}), setTimeout(() => {
|
|
846
|
-
let a = n.querySelector(`.cell[data-col="${
|
|
957
|
+
let a = n.querySelector(`.cell[data-col="${t._focusCol}"]`);
|
|
847
958
|
if (a?.classList.contains("editing") || (a = n.querySelector(".cell.editing")), a?.classList.contains("editing")) {
|
|
848
|
-
const l = a.querySelector(
|
|
959
|
+
const l = a.querySelector(R);
|
|
849
960
|
try {
|
|
850
961
|
l?.focus({ preventScroll: !0 });
|
|
851
962
|
} catch {
|
|
@@ -858,235 +969,257 @@ class K extends O {
|
|
|
858
969
|
* @fires row-commit - Emitted after the row edit is committed
|
|
859
970
|
*/
|
|
860
971
|
commitActiveRowEdit() {
|
|
861
|
-
this.#e !== -1 && this.#
|
|
972
|
+
this.#e !== -1 && this.#n(this.#e, !1);
|
|
862
973
|
}
|
|
863
974
|
/**
|
|
864
975
|
* Cancel the currently active row edit.
|
|
865
976
|
*/
|
|
866
977
|
cancelActiveRowEdit() {
|
|
867
|
-
this.#e !== -1 && this.#
|
|
978
|
+
this.#e !== -1 && this.#n(this.#e, !0);
|
|
868
979
|
}
|
|
869
980
|
// #endregion
|
|
870
981
|
// #region Internal Methods
|
|
871
982
|
/**
|
|
872
983
|
* Begin editing a single cell.
|
|
873
984
|
*/
|
|
874
|
-
#
|
|
875
|
-
const r = this.grid, n = r._rows[e], o = r._visibleColumns[
|
|
876
|
-
!n || !o?.editable ||
|
|
985
|
+
#p(e, t, i) {
|
|
986
|
+
const r = this.grid, n = r._rows[e], o = r._visibleColumns[t];
|
|
987
|
+
!n || !o?.editable || i.classList.contains("editing") || (this.#e !== e && this.#h(e, n), this.#o = t, this.#f(n, e, o, t, i, !1));
|
|
877
988
|
}
|
|
878
989
|
/**
|
|
879
990
|
* Sync the internal grid state with the plugin's editing state.
|
|
880
991
|
*/
|
|
881
|
-
#
|
|
992
|
+
#c() {
|
|
882
993
|
const e = this.grid;
|
|
883
|
-
e._activeEditRows = this.#e, e._rowEditSnapshots = this.#
|
|
994
|
+
e._activeEditRows = this.#e, e._rowEditSnapshots = this.#s;
|
|
884
995
|
}
|
|
885
996
|
/**
|
|
886
997
|
* Snapshot original row data and mark as editing.
|
|
887
998
|
*/
|
|
888
|
-
#
|
|
889
|
-
this.#e !== e && (this.#
|
|
999
|
+
#h(e, t) {
|
|
1000
|
+
this.#e !== e && (this.#s.set(e, { ...t }), this.#e = e, this.#c());
|
|
890
1001
|
}
|
|
891
1002
|
/**
|
|
892
1003
|
* Exit editing for a row.
|
|
893
1004
|
*/
|
|
894
|
-
#
|
|
1005
|
+
#n(e, t) {
|
|
895
1006
|
if (this.#e !== e) return;
|
|
896
|
-
const
|
|
1007
|
+
const i = this.grid, r = this.#s.get(e), n = i._rows[e], o = i.findRenderedRowElement?.(e);
|
|
897
1008
|
let a;
|
|
898
1009
|
if (n)
|
|
899
1010
|
try {
|
|
900
|
-
a =
|
|
1011
|
+
a = i.getRowId?.(n);
|
|
901
1012
|
} catch {
|
|
902
1013
|
}
|
|
903
|
-
if (!
|
|
904
|
-
const
|
|
905
|
-
if (isNaN(
|
|
906
|
-
const
|
|
907
|
-
if (!
|
|
908
|
-
const
|
|
909
|
-
if (
|
|
910
|
-
const h = E(
|
|
911
|
-
|
|
1014
|
+
if (!t && o && n && o.querySelectorAll(".cell.editing").forEach((d) => {
|
|
1015
|
+
const c = Number(d.getAttribute("data-col"));
|
|
1016
|
+
if (isNaN(c)) return;
|
|
1017
|
+
const p = i._visibleColumns[c];
|
|
1018
|
+
if (!p) return;
|
|
1019
|
+
const u = d.querySelector("input,textarea,select");
|
|
1020
|
+
if (u) {
|
|
1021
|
+
const m = p.field, h = n[m], g = E(u, p, h);
|
|
1022
|
+
h !== g && this.#u(e, p, g, n);
|
|
912
1023
|
}
|
|
913
|
-
}),
|
|
1024
|
+
}), t && r && n)
|
|
914
1025
|
Object.keys(r).forEach((l) => {
|
|
915
1026
|
n[l] = r[l];
|
|
916
|
-
}), a && this.#
|
|
917
|
-
else if (!
|
|
918
|
-
const l = a ? this.#
|
|
919
|
-
this.emit("row-commit", {
|
|
1027
|
+
}), a && (this.#i.delete(a), this.clearRowInvalid(a));
|
|
1028
|
+
else if (!t && n) {
|
|
1029
|
+
const l = this.#v(r, n), d = a ? this.#i.has(a) : l, c = this.emitCancelable("row-commit", {
|
|
920
1030
|
rowIndex: e,
|
|
921
1031
|
rowId: a ?? "",
|
|
922
1032
|
row: n,
|
|
923
|
-
|
|
1033
|
+
oldValue: r,
|
|
1034
|
+
newValue: n,
|
|
1035
|
+
changed: d,
|
|
924
1036
|
changedRows: this.changedRows,
|
|
925
1037
|
changedRowIds: this.changedRowIds
|
|
926
|
-
})
|
|
1038
|
+
});
|
|
1039
|
+
c && r ? (Object.keys(r).forEach((p) => {
|
|
1040
|
+
n[p] = r[p];
|
|
1041
|
+
}), a && (this.#i.delete(a), this.clearRowInvalid(a))) : !c && l && this.isAnimationEnabled && (this.#l = e);
|
|
927
1042
|
}
|
|
928
|
-
this.#
|
|
929
|
-
for (const l of this.#
|
|
930
|
-
l.startsWith(`${e}:`) && this.#
|
|
1043
|
+
this.#s.delete(e), this.#e = -1, this.#o = -1, this.#c();
|
|
1044
|
+
for (const l of this.#r)
|
|
1045
|
+
l.startsWith(`${e}:`) && this.#r.delete(l);
|
|
931
1046
|
o && (o.querySelectorAll(".cell.editing").forEach((l) => {
|
|
932
|
-
l.classList.remove("editing"),
|
|
933
|
-
}), this.requestRender()), this.#
|
|
1047
|
+
l.classList.remove("editing"), x(l.parentElement);
|
|
1048
|
+
}), this.requestRender()), this.#a = !0, o || (this.#g(i), this.#a = !1);
|
|
934
1049
|
}
|
|
935
1050
|
/**
|
|
936
1051
|
* Commit a single cell value change.
|
|
937
1052
|
* Uses ID-based change tracking for stability when rows are reordered.
|
|
938
1053
|
*/
|
|
939
|
-
#
|
|
940
|
-
const n =
|
|
941
|
-
if (!
|
|
1054
|
+
#u(e, t, i, r) {
|
|
1055
|
+
const n = t.field;
|
|
1056
|
+
if (!w(n)) return;
|
|
942
1057
|
const o = r[n];
|
|
943
|
-
if (o ===
|
|
1058
|
+
if (o === i) return;
|
|
944
1059
|
const a = this.grid;
|
|
945
1060
|
let l;
|
|
946
1061
|
try {
|
|
947
1062
|
l = this.grid.getRowId(r);
|
|
948
1063
|
} catch {
|
|
949
1064
|
}
|
|
950
|
-
const
|
|
1065
|
+
const d = l ? !this.#i.has(l) : !0, c = l ? (g) => this.grid.updateRow(l, g, "cascade") : k;
|
|
1066
|
+
let p = !1;
|
|
1067
|
+
const u = l ? (g) => {
|
|
1068
|
+
p = !0, this.setInvalid(l, n, g ?? "");
|
|
1069
|
+
} : () => {
|
|
1070
|
+
};
|
|
951
1071
|
if (this.emitCancelable("cell-commit", {
|
|
952
1072
|
row: r,
|
|
953
1073
|
rowId: l ?? "",
|
|
954
1074
|
field: n,
|
|
955
1075
|
oldValue: o,
|
|
956
|
-
value:
|
|
1076
|
+
value: i,
|
|
957
1077
|
rowIndex: e,
|
|
958
1078
|
changedRows: this.changedRows,
|
|
959
1079
|
changedRowIds: this.changedRowIds,
|
|
960
|
-
firstTimeForRow:
|
|
961
|
-
updateRow:
|
|
1080
|
+
firstTimeForRow: d,
|
|
1081
|
+
updateRow: c,
|
|
1082
|
+
setInvalid: u
|
|
962
1083
|
})) return;
|
|
963
|
-
r[n] =
|
|
1084
|
+
l && !p && this.isCellInvalid(l, n) && this.clearInvalid(l, n), r[n] = i, l && this.#i.add(l), this.#c(), this.emitPluginEvent("cell-edit-committed", {
|
|
964
1085
|
rowIndex: e,
|
|
965
1086
|
field: n,
|
|
966
1087
|
oldValue: o,
|
|
967
|
-
newValue:
|
|
1088
|
+
newValue: i
|
|
968
1089
|
});
|
|
969
|
-
const
|
|
970
|
-
|
|
1090
|
+
const h = a.findRenderedRowElement?.(e);
|
|
1091
|
+
h && h.classList.add("changed");
|
|
971
1092
|
}
|
|
972
1093
|
/**
|
|
973
1094
|
* Inject an editor into a cell.
|
|
974
1095
|
*/
|
|
975
|
-
#
|
|
976
|
-
if (!
|
|
1096
|
+
#f(e, t, i, r, n, o) {
|
|
1097
|
+
if (!i.editable || n.classList.contains("editing")) return;
|
|
977
1098
|
let a;
|
|
978
1099
|
try {
|
|
979
1100
|
a = this.grid.getRowId(e);
|
|
980
1101
|
} catch {
|
|
981
1102
|
}
|
|
982
|
-
const l = a ? (
|
|
983
|
-
n.classList.add("editing"), this.#
|
|
984
|
-
const
|
|
985
|
-
|
|
986
|
-
let
|
|
987
|
-
const
|
|
988
|
-
|
|
989
|
-
},
|
|
990
|
-
|
|
991
|
-
},
|
|
992
|
-
|
|
993
|
-
|
|
1103
|
+
const l = a ? (f) => this.grid.updateRow(a, f, "cascade") : k, d = w(i.field) ? e[i.field] : void 0;
|
|
1104
|
+
n.classList.add("editing"), this.#r.add(`${t}:${r}`);
|
|
1105
|
+
const c = n.parentElement;
|
|
1106
|
+
c && H(c);
|
|
1107
|
+
let p = !1;
|
|
1108
|
+
const u = (f) => {
|
|
1109
|
+
p || this.#e === -1 || this.#u(t, i, f, e);
|
|
1110
|
+
}, m = () => {
|
|
1111
|
+
p = !0, w(i.field) && (e[i.field] = d);
|
|
1112
|
+
}, h = document.createElement("div");
|
|
1113
|
+
h.className = "tbw-editor-host", n.innerHTML = "", n.appendChild(h), h.addEventListener("keydown", (f) => {
|
|
1114
|
+
f.key === "Enter" && (f.stopPropagation(), f.preventDefault(), p = !0, this.#n(t, !1)), f.key === "Escape" && (f.stopPropagation(), f.preventDefault(), m(), this.#n(t, !0));
|
|
994
1115
|
});
|
|
995
|
-
const
|
|
996
|
-
if (
|
|
997
|
-
this.#h
|
|
998
|
-
else if (typeof
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1116
|
+
const g = i, y = g.__editorTemplate, v = G(this.grid, g) ?? N(i), C = d;
|
|
1117
|
+
if (v === "template" && y)
|
|
1118
|
+
this.#m(h, g, e, d, u, m, o, t);
|
|
1119
|
+
else if (typeof v == "string") {
|
|
1120
|
+
const f = document.createElement(v);
|
|
1121
|
+
f.value = C, f.addEventListener("change", () => u(f.value)), h.appendChild(f), o || queueMicrotask(() => {
|
|
1122
|
+
h.querySelector(R)?.focus({ preventScroll: !0 });
|
|
1002
1123
|
});
|
|
1003
|
-
} else if (typeof
|
|
1004
|
-
const
|
|
1124
|
+
} else if (typeof v == "function") {
|
|
1125
|
+
const f = {
|
|
1005
1126
|
row: e,
|
|
1006
1127
|
rowId: a ?? "",
|
|
1007
1128
|
value: C,
|
|
1008
|
-
field:
|
|
1009
|
-
column:
|
|
1010
|
-
commit:
|
|
1011
|
-
cancel:
|
|
1129
|
+
field: i.field,
|
|
1130
|
+
column: i,
|
|
1131
|
+
commit: u,
|
|
1132
|
+
cancel: m,
|
|
1012
1133
|
updateRow: l
|
|
1013
|
-
},
|
|
1014
|
-
typeof
|
|
1015
|
-
|
|
1134
|
+
}, b = v(f);
|
|
1135
|
+
typeof b == "string" ? (h.innerHTML = b, $(h, i, u, d)) : b instanceof Node && h.appendChild(b), o || queueMicrotask(() => {
|
|
1136
|
+
h.querySelector(R)?.focus({ preventScroll: !0 });
|
|
1016
1137
|
});
|
|
1017
|
-
} else if (
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
const
|
|
1138
|
+
} else if (v && typeof v == "object") {
|
|
1139
|
+
const f = document.createElement("div");
|
|
1140
|
+
f.setAttribute("data-external-editor", ""), f.setAttribute("data-field", i.field), h.appendChild(f);
|
|
1141
|
+
const b = {
|
|
1021
1142
|
row: e,
|
|
1022
1143
|
rowId: a ?? "",
|
|
1023
1144
|
value: C,
|
|
1024
|
-
field:
|
|
1025
|
-
column:
|
|
1026
|
-
commit:
|
|
1027
|
-
cancel:
|
|
1145
|
+
field: i.field,
|
|
1146
|
+
column: i,
|
|
1147
|
+
commit: u,
|
|
1148
|
+
cancel: m,
|
|
1028
1149
|
updateRow: l
|
|
1029
1150
|
};
|
|
1030
|
-
if (
|
|
1151
|
+
if (v.mount)
|
|
1031
1152
|
try {
|
|
1032
|
-
|
|
1033
|
-
} catch (
|
|
1034
|
-
console.warn(`[tbw-grid] External editor mount error for column '${
|
|
1153
|
+
v.mount({ placeholder: f, context: b, spec: v });
|
|
1154
|
+
} catch (_) {
|
|
1155
|
+
console.warn(`[tbw-grid] External editor mount error for column '${i.field}':`, _);
|
|
1035
1156
|
}
|
|
1036
1157
|
else
|
|
1037
1158
|
this.grid.dispatchEvent(
|
|
1038
|
-
new CustomEvent("mount-external-editor", { detail: { placeholder:
|
|
1159
|
+
new CustomEvent("mount-external-editor", { detail: { placeholder: f, spec: v, context: b } })
|
|
1039
1160
|
);
|
|
1040
1161
|
}
|
|
1041
1162
|
}
|
|
1042
1163
|
/**
|
|
1043
1164
|
* Render a template-based editor.
|
|
1044
1165
|
*/
|
|
1045
|
-
#
|
|
1046
|
-
const
|
|
1047
|
-
if (!
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
row:
|
|
1166
|
+
#m(e, t, i, r, n, o, a, l) {
|
|
1167
|
+
const d = t.__editorTemplate;
|
|
1168
|
+
if (!d) return;
|
|
1169
|
+
const c = d.cloneNode(!0), p = t.__compiledEditor;
|
|
1170
|
+
p ? c.innerHTML = p({
|
|
1171
|
+
row: i,
|
|
1051
1172
|
value: r,
|
|
1052
|
-
field:
|
|
1053
|
-
column:
|
|
1173
|
+
field: t.field,
|
|
1174
|
+
column: t,
|
|
1054
1175
|
commit: n,
|
|
1055
1176
|
cancel: o
|
|
1056
|
-
}) :
|
|
1057
|
-
|
|
1058
|
-
if (!
|
|
1059
|
-
const y =
|
|
1177
|
+
}) : c.querySelectorAll("*").forEach((m) => {
|
|
1178
|
+
m.childNodes.length === 1 && m.firstChild?.nodeType === Node.TEXT_NODE && (m.textContent = m.textContent?.replace(/{{\s*value\s*}}/g, r == null ? "" : String(r)).replace(/{{\s*row\.([a-zA-Z0-9_]+)\s*}}/g, (h, g) => {
|
|
1179
|
+
if (!w(g)) return "";
|
|
1180
|
+
const y = i[g];
|
|
1060
1181
|
return y == null ? "" : String(y);
|
|
1061
1182
|
}) || "");
|
|
1062
1183
|
});
|
|
1063
|
-
const
|
|
1184
|
+
const u = c.querySelector(
|
|
1064
1185
|
"input,textarea,select"
|
|
1065
1186
|
);
|
|
1066
|
-
if (
|
|
1067
|
-
|
|
1068
|
-
let
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
}),
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
}),
|
|
1187
|
+
if (u) {
|
|
1188
|
+
u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked = !!r : u.value = String(r ?? "");
|
|
1189
|
+
let m = !1;
|
|
1190
|
+
u.addEventListener("blur", () => {
|
|
1191
|
+
m || n(E(u, t, r));
|
|
1192
|
+
}), u.addEventListener("keydown", (h) => {
|
|
1193
|
+
const g = h;
|
|
1194
|
+
g.key === "Enter" && (g.stopPropagation(), g.preventDefault(), m = !0, n(E(u, t, r)), this.#n(l, !1)), g.key === "Escape" && (g.stopPropagation(), g.preventDefault(), o(), this.#n(l, !0));
|
|
1195
|
+
}), u instanceof HTMLInputElement && u.type === "checkbox" && u.addEventListener("change", () => n(u.checked)), a || setTimeout(() => u.focus({ preventScroll: !0 }), 0);
|
|
1075
1196
|
}
|
|
1076
|
-
e.appendChild(
|
|
1197
|
+
e.appendChild(c);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Compare snapshot vs current row to detect if any values changed during this edit session.
|
|
1201
|
+
* Uses shallow comparison of all properties.
|
|
1202
|
+
*/
|
|
1203
|
+
#v(e, t) {
|
|
1204
|
+
if (!e) return !1;
|
|
1205
|
+
const i = e, r = t, n = /* @__PURE__ */ new Set([...Object.keys(i), ...Object.keys(r)]);
|
|
1206
|
+
for (const o of n)
|
|
1207
|
+
if (i[o] !== r[o])
|
|
1208
|
+
return !0;
|
|
1209
|
+
return !1;
|
|
1077
1210
|
}
|
|
1078
1211
|
/**
|
|
1079
1212
|
* Restore focus to cell after exiting edit mode.
|
|
1080
1213
|
*/
|
|
1081
|
-
#
|
|
1214
|
+
#g(e) {
|
|
1082
1215
|
queueMicrotask(() => {
|
|
1083
1216
|
try {
|
|
1084
|
-
const
|
|
1217
|
+
const t = e._focusRow, i = e._focusCol, r = e.findRenderedRowElement?.(t);
|
|
1085
1218
|
if (r) {
|
|
1086
1219
|
Array.from(e._bodyEl.querySelectorAll(".cell-focus")).forEach(
|
|
1087
1220
|
(o) => o.classList.remove("cell-focus")
|
|
1088
1221
|
);
|
|
1089
|
-
const n = r.querySelector(`.cell[data-row="${
|
|
1222
|
+
const n = r.querySelector(`.cell[data-row="${t}"][data-col="${i}"]`);
|
|
1090
1223
|
n && (n.classList.add("cell-focus"), n.setAttribute("aria-selected", "true"), n.hasAttribute("tabindex") || n.setAttribute("tabindex", "-1"), n.focus({ preventScroll: !0 }));
|
|
1091
1224
|
}
|
|
1092
1225
|
} catch {
|
|
@@ -1096,7 +1229,7 @@ class K extends O {
|
|
|
1096
1229
|
// #endregion
|
|
1097
1230
|
}
|
|
1098
1231
|
export {
|
|
1099
|
-
|
|
1100
|
-
|
|
1232
|
+
z as EditingPlugin,
|
|
1233
|
+
N as defaultEditorFor
|
|
1101
1234
|
};
|
|
1102
1235
|
//# sourceMappingURL=index.js.map
|