@toolbox-web/grid 1.10.1 → 1.11.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.
Files changed (64) hide show
  1. package/all.js +426 -377
  2. package/all.js.map +1 -1
  3. package/index.js +575 -532
  4. package/index.js.map +1 -1
  5. package/lib/core/grid.d.ts.map +1 -1
  6. package/lib/core/internal/columns.d.ts.map +1 -1
  7. package/lib/core/internal/config-manager.d.ts.map +1 -1
  8. package/lib/core/internal/dom-builder.d.ts.map +1 -1
  9. package/lib/core/internal/event-delegation.d.ts.map +1 -1
  10. package/lib/core/internal/header.d.ts.map +1 -1
  11. package/lib/core/internal/keyboard.d.ts +2 -0
  12. package/lib/core/internal/keyboard.d.ts.map +1 -1
  13. package/lib/core/internal/loading.d.ts +79 -0
  14. package/lib/core/internal/loading.d.ts.map +1 -0
  15. package/lib/core/internal/render-scheduler.d.ts.map +1 -1
  16. package/lib/core/internal/rows.d.ts.map +1 -1
  17. package/lib/core/internal/sanitize.d.ts.map +1 -1
  18. package/lib/core/internal/shell.d.ts.map +1 -1
  19. package/lib/core/internal/style-injector.d.ts +43 -0
  20. package/lib/core/internal/style-injector.d.ts.map +1 -0
  21. package/lib/core/internal/touch-scroll.d.ts.map +1 -1
  22. package/lib/core/internal/validate-config.d.ts.map +1 -1
  23. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  24. package/lib/core/plugin/types.d.ts.map +1 -1
  25. package/lib/core/styles/index.d.ts +32 -0
  26. package/lib/core/styles/index.d.ts.map +1 -0
  27. package/lib/core/types.d.ts +44 -1
  28. package/lib/core/types.d.ts.map +1 -1
  29. package/lib/plugins/clipboard/index.js.map +1 -1
  30. package/lib/plugins/column-virtualization/index.js.map +1 -1
  31. package/lib/plugins/context-menu/index.js.map +1 -1
  32. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  33. package/lib/plugins/editing/index.js +322 -213
  34. package/lib/plugins/editing/index.js.map +1 -1
  35. package/lib/plugins/editing/types.d.ts +44 -2
  36. package/lib/plugins/editing/types.d.ts.map +1 -1
  37. package/lib/plugins/export/index.js.map +1 -1
  38. package/lib/plugins/filtering/index.js.map +1 -1
  39. package/lib/plugins/grouping-columns/index.js.map +1 -1
  40. package/lib/plugins/grouping-rows/index.js.map +1 -1
  41. package/lib/plugins/master-detail/index.js.map +1 -1
  42. package/lib/plugins/multi-sort/index.js.map +1 -1
  43. package/lib/plugins/pinned-columns/index.js.map +1 -1
  44. package/lib/plugins/pinned-rows/index.js.map +1 -1
  45. package/lib/plugins/pivot/index.js.map +1 -1
  46. package/lib/plugins/print/index.js.map +1 -1
  47. package/lib/plugins/reorder/index.js +1 -1
  48. package/lib/plugins/reorder/index.js.map +1 -1
  49. package/lib/plugins/responsive/index.js +35 -35
  50. package/lib/plugins/responsive/index.js.map +1 -1
  51. package/lib/plugins/row-reorder/index.js +1 -1
  52. package/lib/plugins/row-reorder/index.js.map +1 -1
  53. package/lib/plugins/selection/index.js.map +1 -1
  54. package/lib/plugins/server-side/index.js.map +1 -1
  55. package/lib/plugins/tree/index.js.map +1 -1
  56. package/lib/plugins/undo-redo/index.js.map +1 -1
  57. package/lib/plugins/visibility/index.js.map +1 -1
  58. package/package.json +1 -1
  59. package/umd/grid.all.umd.js +61 -33
  60. package/umd/grid.all.umd.js.map +1 -1
  61. package/umd/grid.umd.js +40 -12
  62. package/umd/grid.umd.js.map +1 -1
  63. package/umd/plugins/editing.umd.js +1 -1
  64. package/umd/plugins/editing.umd.js.map +1 -1
@@ -1,4 +1,59 @@
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 = {
1
+ function k(s) {
2
+ s && s.querySelectorAll(".cell-focus").forEach((e) => e.classList.remove("cell-focus"));
3
+ }
4
+ const I = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])', T = document.createElement("template");
5
+ T.innerHTML = '<div class="cell" role="gridcell" part="cell"></div>';
6
+ const q = document.createElement("template");
7
+ q.innerHTML = '<div class="data-grid-row" role="row" part="row"></div>';
8
+ function S(s, e) {
9
+ if (s._virtualization?.enabled) {
10
+ const { rowHeight: l, container: o, viewportEl: a } = s._virtualization, c = o, d = a?.clientHeight ?? c?.clientHeight ?? 0;
11
+ if (c && d > 0) {
12
+ const f = s._focusRow * l;
13
+ f < c.scrollTop ? c.scrollTop = f : f + l > c.scrollTop + d && (c.scrollTop = f - d + l);
14
+ }
15
+ }
16
+ const t = s._activeEditRows !== void 0 && s._activeEditRows !== -1;
17
+ t || s.refreshVirtualWindow(!1), k(s._bodyEl), Array.from(s._bodyEl.querySelectorAll('[aria-selected="true"]')).forEach((l) => {
18
+ l.setAttribute("aria-selected", "false");
19
+ });
20
+ const i = s._focusRow, r = s._virtualization.start ?? 0, n = s._virtualization.end ?? s._rows.length;
21
+ if (i >= r && i < n) {
22
+ const l = s._bodyEl.querySelectorAll(".data-grid-row")[i - r];
23
+ let o = l?.children[s._focusCol];
24
+ if ((!o || !o.classList?.contains("cell")) && (o = l?.querySelector(`.cell[data-col="${s._focusCol}"]`) ?? l?.querySelector(".cell[data-col]")), o) {
25
+ o.classList.add("cell-focus"), o.setAttribute("aria-selected", "true");
26
+ const a = s.querySelector(".tbw-scroll-area");
27
+ if (a && o && (!t || e?.forceHorizontalScroll))
28
+ if (e?.forceScrollLeft)
29
+ a.scrollLeft = 0;
30
+ else if (e?.forceScrollRight)
31
+ a.scrollLeft = a.scrollWidth - a.clientWidth;
32
+ else {
33
+ const c = s._getHorizontalScrollOffsets?.(l ?? void 0, o) ?? { left: 0, right: 0 };
34
+ if (!c.skipScroll) {
35
+ const d = o.getBoundingClientRect(), f = a.getBoundingClientRect(), u = d.left - f.left + a.scrollLeft, m = u + d.width, p = a.scrollLeft + c.left, g = a.scrollLeft + a.clientWidth - c.right;
36
+ u < p ? a.scrollLeft = u - c.left : m > g && (a.scrollLeft = m - a.clientWidth + c.right);
37
+ }
38
+ }
39
+ if (s._activeEditRows !== void 0 && s._activeEditRows !== -1 && o.classList.contains("editing")) {
40
+ const c = o.querySelector(I);
41
+ if (c && document.activeElement !== c)
42
+ try {
43
+ c.focus({ preventScroll: !0 });
44
+ } catch {
45
+ }
46
+ } else if (!o.contains(document.activeElement)) {
47
+ o.hasAttribute("tabindex") || o.setAttribute("tabindex", "-1");
48
+ try {
49
+ o.focus({ preventScroll: !0 });
50
+ } catch {
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ 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>', P = {
2
57
  expand: "▶",
3
58
  collapse: "▼",
4
59
  sortAsc: "▲",
@@ -7,11 +62,11 @@ const S = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentCo
7
62
  submenuArrow: "▶",
8
63
  dragHandle: "⋮⋮",
9
64
  toolPanel: "☰",
10
- filter: S,
11
- filterActive: S,
65
+ filter: L,
66
+ filterActive: L,
12
67
  print: "🖨️"
13
68
  };
14
- class I {
69
+ class O {
15
70
  /**
16
71
  * Plugin dependencies - declare other plugins this one requires.
17
72
  *
@@ -301,7 +356,7 @@ class I {
301
356
  */
302
357
  get gridIcons() {
303
358
  const e = this.grid?.gridConfig?.icons ?? {};
304
- return { ...L, ...e };
359
+ return { ...P, ...e };
305
360
  }
306
361
  // #region Animation Helpers
307
362
  /**
@@ -377,12 +432,12 @@ class I {
377
432
  }
378
433
  // #endregion
379
434
  }
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) {
435
+ const D = "@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}}";
436
+ function M(s) {
382
437
  const e = s.options;
383
438
  return e ? typeof e == "function" ? e() : e : [];
384
439
  }
385
- function T(s) {
440
+ function x(s) {
386
441
  return (e) => {
387
442
  const t = s.editorParams, i = document.createElement("input");
388
443
  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);
@@ -392,13 +447,13 @@ function T(s) {
392
447
  }), i;
393
448
  };
394
449
  }
395
- function q() {
450
+ function B() {
396
451
  return (s) => {
397
452
  const e = document.createElement("input");
398
453
  return e.type = "checkbox", e.checked = !!s.value, e.addEventListener("change", () => s.commit(e.checked)), e;
399
454
  };
400
455
  }
401
- function O(s) {
456
+ function H(s) {
402
457
  return (e) => {
403
458
  const t = s.editorParams, i = document.createElement("input");
404
459
  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);
@@ -410,30 +465,30 @@ function O(s) {
410
465
  }), i;
411
466
  };
412
467
  }
413
- function D(s) {
468
+ function N(s) {
414
469
  return (e) => {
415
470
  const t = s.editorParams, i = document.createElement("select");
416
471
  if (s.multi && (i.multiple = !0), t?.includeEmpty) {
417
- const o = document.createElement("option");
418
- o.value = "", o.textContent = t.emptyLabel ?? "", i.appendChild(o);
472
+ const l = document.createElement("option");
473
+ l.value = "", l.textContent = t.emptyLabel ?? "", i.appendChild(l);
419
474
  }
420
- P(s).forEach((o) => {
421
- const a = document.createElement("option");
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);
475
+ M(s).forEach((l) => {
476
+ const o = document.createElement("option");
477
+ o.value = String(l.value), o.textContent = l.label, (s.multi && Array.isArray(e.value) && e.value.includes(l.value) || !s.multi && e.value === l.value) && (o.selected = !0), i.appendChild(o);
423
478
  });
424
479
  const n = () => {
425
480
  if (s.multi) {
426
- const o = Array.from(i.selectedOptions).map((a) => a.value);
427
- e.commit(o);
481
+ const l = Array.from(i.selectedOptions).map((o) => o.value);
482
+ e.commit(l);
428
483
  } else
429
484
  e.commit(i.value);
430
485
  };
431
- return i.addEventListener("change", n), i.addEventListener("blur", n), i.addEventListener("keydown", (o) => {
432
- o.key === "Escape" && e.cancel();
486
+ return i.addEventListener("change", n), i.addEventListener("blur", n), i.addEventListener("keydown", (l) => {
487
+ l.key === "Escape" && e.cancel();
433
488
  }), i;
434
489
  };
435
490
  }
436
- function M(s) {
491
+ function z(s) {
437
492
  return (e) => {
438
493
  const t = s.editorParams, i = document.createElement("input");
439
494
  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);
@@ -446,21 +501,21 @@ function M(s) {
446
501
  }), i;
447
502
  };
448
503
  }
449
- function N(s) {
504
+ function $(s) {
450
505
  switch (s.type) {
451
506
  case "number":
452
- return T(s);
507
+ return x(s);
453
508
  case "boolean":
454
- return q();
509
+ return B();
455
510
  case "date":
456
- return O(s);
511
+ return H(s);
457
512
  case "select":
458
- return D(s);
513
+ return N(s);
459
514
  default:
460
- return M(s);
515
+ return z(s);
461
516
  }
462
517
  }
463
- const R = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
518
+ const C = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
464
519
  function G(s, e) {
465
520
  if (e.editor) return e.editor;
466
521
  if (e.__editorTemplate) return "template";
@@ -475,28 +530,28 @@ function G(s, e) {
475
530
  return n.editor;
476
531
  }
477
532
  }
478
- function w(s) {
533
+ function E(s) {
479
534
  return !(typeof s != "string" || s === "__proto__" || s === "constructor" || s === "prototype");
480
535
  }
481
- function H(s) {
536
+ function F(s) {
482
537
  const e = (s.__editingCellCount ?? 0) + 1;
483
538
  s.__editingCellCount = e, s.setAttribute("data-has-editing", "");
484
539
  }
485
- function x(s) {
540
+ function j(s) {
486
541
  s.__editingCellCount = 0, s.removeAttribute("data-has-editing");
487
542
  }
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;
543
+ function y(s, e, t) {
544
+ 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) : t == null && s.value === "" ? t : s.value : e?.type === "number" && s.value !== "" || typeof t == "number" && s.value !== "" ? Number(s.value) : t == null && s.value === "" ? t : s.value;
490
545
  }
491
- function k(s) {
546
+ function A(s) {
492
547
  }
493
- function $(s, e, t, i) {
548
+ function W(s, e, t, i) {
494
549
  const r = s.querySelector("input,textarea,select");
495
550
  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))));
551
+ t(y(r, e, i));
552
+ }), r instanceof HTMLInputElement && r.type === "checkbox" ? r.addEventListener("change", () => t(r.checked)) : r instanceof HTMLSelectElement && r.addEventListener("change", () => t(y(r, e, i))));
498
553
  }
499
- class z extends I {
554
+ class K extends O {
500
555
  /**
501
556
  * Plugin manifest - declares owned properties for configuration validation.
502
557
  * @internal
@@ -536,7 +591,7 @@ class z extends I {
536
591
  /** @internal */
537
592
  name = "editing";
538
593
  /** @internal */
539
- styles = A;
594
+ styles = D;
540
595
  /** @internal */
541
596
  get defaultConfig() {
542
597
  return {
@@ -555,9 +610,9 @@ class z extends I {
555
610
  /** Set of cells currently in edit mode: "rowIndex:colIndex" */
556
611
  #r = /* @__PURE__ */ new Set();
557
612
  /** Flag to restore focus after next render (used when exiting edit mode) */
558
- #a = !1;
613
+ #l = !1;
559
614
  /** Row index pending animation after render, or -1 if none */
560
- #l = -1;
615
+ #a = -1;
561
616
  /**
562
617
  * Invalid cell tracking: Map<rowId, Map<field, message>>
563
618
  * Used for validation feedback without canceling edits.
@@ -580,7 +635,11 @@ class z extends I {
580
635
  }, document.addEventListener(
581
636
  "keydown",
582
637
  (r) => {
583
- r.key === "Escape" && this.#e !== -1 && this.#n(this.#e, !0);
638
+ if (r.key === "Escape" && this.#e !== -1) {
639
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(r) === !1)
640
+ return;
641
+ this.#n(this.#e, !0);
642
+ }
584
643
  },
585
644
  { capture: !0, signal: t }
586
645
  ), document.addEventListener(
@@ -588,7 +647,7 @@ class z extends I {
588
647
  (r) => {
589
648
  if (this.#e === -1) return;
590
649
  const n = i.findRenderedRowElement?.(this.#e);
591
- !n || (r.composedPath && r.composedPath() || []).includes(n) || queueMicrotask(() => {
650
+ !n || (r.composedPath && r.composedPath() || []).includes(n) || this.config.onBeforeEditClose && this.config.onBeforeEditClose(r) === !1 || queueMicrotask(() => {
592
651
  this.#e !== -1 && this.#n(this.#e, !1);
593
652
  });
594
653
  },
@@ -621,7 +680,7 @@ class z extends I {
621
680
  const r = e.originalEvent.type === "dblclick";
622
681
  if (i === "click" && r || i === "dblclick" && !r) return !1;
623
682
  const { rowIndex: n } = e;
624
- return t._columns?.some((a) => a.editable) ? (e.originalEvent.stopPropagation(), this.beginBulkEdit(n), !0) : !1;
683
+ return t._columns?.some((o) => o.editable) ? (e.originalEvent.stopPropagation(), this.beginBulkEdit(n), !0) : !1;
625
684
  }
626
685
  /**
627
686
  * Handle keyboard events for edit lifecycle.
@@ -630,16 +689,29 @@ class z extends I {
630
689
  onKeyDown(e) {
631
690
  const t = this.grid;
632
691
  if (e.key === "Escape" && this.#e !== -1)
633
- return this.#n(this.#e, !0), !0;
692
+ return this.config.onBeforeEditClose && this.config.onBeforeEditClose(e) === !1 || this.#n(this.#e, !0), !0;
693
+ if ((e.key === "ArrowUp" || e.key === "ArrowDown") && this.#e !== -1) {
694
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(e) === !1)
695
+ return !0;
696
+ const i = t._rows.length - 1, r = this.#e;
697
+ return this.#n(r, !1), e.key === "ArrowDown" ? t._focusRow = Math.min(i, t._focusRow + 1) : t._focusRow = Math.max(0, t._focusRow - 1), e.preventDefault(), S(t), this.requestAfterRender(), !0;
698
+ }
699
+ if (e.key === "Tab" && this.#e !== -1) {
700
+ e.preventDefault();
701
+ const i = !e.shiftKey;
702
+ return this.#m(i), !0;
703
+ }
634
704
  if (e.key === " " || e.key === "Spacebar") {
705
+ if (this.#e !== -1)
706
+ return !1;
635
707
  const i = t._focusRow, r = t._focusCol;
636
708
  if (i >= 0 && r >= 0) {
637
- const n = t._visibleColumns[r], o = t._rows[i];
638
- if (n?.editable && n.type === "boolean" && o) {
639
- const a = n.field;
640
- if (w(a)) {
641
- const d = !o[a];
642
- return this.#u(i, n, d, o), e.preventDefault(), this.requestRender(), !0;
709
+ const n = t._visibleColumns[r], l = t._rows[i];
710
+ if (n?.editable && n.type === "boolean" && l) {
711
+ const o = n.field;
712
+ if (E(o)) {
713
+ const c = !l[o];
714
+ return this.#u(i, n, c, l), e.preventDefault(), this.requestRender(), !0;
643
715
  }
644
716
  }
645
717
  }
@@ -647,21 +719,21 @@ class z extends I {
647
719
  }
648
720
  if (e.key === "Enter" && !e.shiftKey) {
649
721
  if (this.#e !== -1)
650
- return !1;
722
+ return !!(this.config.onBeforeEditClose && this.config.onBeforeEditClose(e) === !1);
651
723
  const i = this.config.editOn ?? t.effectiveConfig?.editOn;
652
724
  if (i === !1 || i === "manual") return !1;
653
725
  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", {
726
+ if (r >= 0 && t._columns?.some((o) => o.editable)) {
727
+ const o = t._visibleColumns[n], a = t._rows[r], c = o?.field ?? "", d = c && a ? a[c] : void 0, f = this.gridElement.querySelector(`[data-row="${r}"][data-col="${n}"]`), u = new CustomEvent("cell-activate", {
656
728
  cancelable: !0,
657
729
  bubbles: !0,
658
730
  detail: {
659
731
  rowIndex: r,
660
732
  colIndex: n,
661
- field: d,
662
- value: c,
663
- row: l,
664
- cellEl: p,
733
+ field: c,
734
+ value: d,
735
+ row: a,
736
+ cellEl: f,
665
737
  trigger: "keyboard",
666
738
  originalEvent: e
667
739
  }
@@ -689,14 +761,14 @@ class z extends I {
689
761
  const t = this.grid, i = t.effectiveConfig?.typeDefaults, r = t.__frameworkAdapter;
690
762
  return !i && !r?.getTypeDefault ? e : e.map((n) => {
691
763
  if (!n.type) return n;
692
- let o;
693
- if (i?.[n.type]?.editorParams && (o = i[n.type].editorParams), !o && r?.getTypeDefault) {
694
- const a = r.getTypeDefault(n.type);
695
- a?.editorParams && (o = a.editorParams);
764
+ let l;
765
+ if (i?.[n.type]?.editorParams && (l = i[n.type].editorParams), !l && r?.getTypeDefault) {
766
+ const o = r.getTypeDefault(n.type);
767
+ o?.editorParams && (l = o.editorParams);
696
768
  }
697
- return o ? {
769
+ return l ? {
698
770
  ...n,
699
- editorParams: { ...o, ...n.editorParams }
771
+ editorParams: { ...l, ...n.editorParams }
700
772
  } : n;
701
773
  });
702
774
  }
@@ -708,18 +780,18 @@ class z extends I {
708
780
  */
709
781
  afterRender() {
710
782
  const e = this.grid;
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");
783
+ if (this.#l && (this.#l = !1, this.#g(e)), this.#a !== -1) {
784
+ const t = this.#a;
785
+ this.#a = -1, e.animateRow?.(t, "change");
714
786
  }
715
787
  if (this.#r.size !== 0)
716
788
  for (const t of this.#r) {
717
- const [i, r] = t.split(":"), n = parseInt(i, 10), o = parseInt(r, 10), a = e.findRenderedRowElement?.(n);
718
- if (!a) continue;
719
- const l = a.querySelector(`.cell[data-col="${o}"]`);
720
- if (!l || l.classList.contains("editing")) continue;
721
- const d = e._rows[n], c = e._visibleColumns[o];
722
- d && c && this.#f(d, n, c, o, l, !0);
789
+ const [i, r] = t.split(":"), n = parseInt(i, 10), l = parseInt(r, 10), o = e.findRenderedRowElement?.(n);
790
+ if (!o) continue;
791
+ const a = o.querySelector(`.cell[data-col="${l}"]`);
792
+ if (!a || a.classList.contains("editing")) continue;
793
+ const c = e._rows[n], d = e._visibleColumns[l];
794
+ c && d && this.#f(c, n, d, l, a, !0);
723
795
  }
724
796
  }
725
797
  /**
@@ -818,7 +890,7 @@ class z extends I {
818
890
  */
819
891
  setInvalid(e, t, i = "") {
820
892
  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);
893
+ r || (r = /* @__PURE__ */ new Map(), this.#t.set(e, r)), r.set(t, i), this.#c(e, t, !0);
822
894
  }
823
895
  /**
824
896
  * Clear the invalid state for a specific cell.
@@ -828,7 +900,7 @@ class z extends I {
828
900
  */
829
901
  clearInvalid(e, t) {
830
902
  const i = this.#t.get(e);
831
- i && (i.delete(t), i.size === 0 && this.#t.delete(e)), this.#d(e, t, !1);
903
+ i && (i.delete(t), i.size === 0 && this.#t.delete(e)), this.#c(e, t, !1);
832
904
  }
833
905
  /**
834
906
  * Clear all invalid cells for a specific row.
@@ -839,7 +911,7 @@ class z extends I {
839
911
  const t = this.#t.get(e);
840
912
  if (t) {
841
913
  const i = Array.from(t.keys());
842
- this.#t.delete(e), i.forEach((r) => this.#d(e, r, !1));
914
+ this.#t.delete(e), i.forEach((r) => this.#c(e, r, !1));
843
915
  }
844
916
  }
845
917
  /**
@@ -848,7 +920,7 @@ class z extends I {
848
920
  clearAllInvalid() {
849
921
  const e = Array.from(this.#t.entries());
850
922
  this.#t.clear(), e.forEach(([t, i]) => {
851
- i.forEach((r, n) => this.#d(t, n, !1));
923
+ i.forEach((r, n) => this.#c(t, n, !1));
852
924
  });
853
925
  }
854
926
  /**
@@ -893,25 +965,25 @@ class z extends I {
893
965
  /**
894
966
  * Sync the data-invalid attribute on a cell element.
895
967
  */
896
- #d(e, t, i) {
897
- const r = this.grid, n = r._visibleColumns?.findIndex((c) => c.field === t);
968
+ #c(e, t, i) {
969
+ const r = this.grid, n = r._visibleColumns?.findIndex((d) => d.field === t);
898
970
  if (n === -1 || n === void 0) return;
899
- const a = r._rows?.findIndex((c) => {
971
+ const o = r._rows?.findIndex((d) => {
900
972
  try {
901
- return r.getRowId?.(c) === e;
973
+ return r.getRowId?.(d) === e;
902
974
  } catch {
903
975
  return !1;
904
976
  }
905
977
  });
906
- if (a === -1 || a === void 0) return;
907
- const d = r.findRenderedRowElement?.(a)?.querySelector(`.cell[data-col="${n}"]`);
908
- if (d)
978
+ if (o === -1 || o === void 0) return;
979
+ const c = r.findRenderedRowElement?.(o)?.querySelector(`.cell[data-col="${n}"]`);
980
+ if (c)
909
981
  if (i) {
910
- d.setAttribute("data-invalid", "true");
911
- const c = this.#t.get(e)?.get(t);
912
- c && d.setAttribute("title", c);
982
+ c.setAttribute("data-invalid", "true");
983
+ const d = this.#t.get(e)?.get(t);
984
+ d && c.setAttribute("title", d);
913
985
  } else
914
- d.removeAttribute("data-invalid"), d.removeAttribute("title");
986
+ c.removeAttribute("data-invalid"), c.removeAttribute("title");
915
987
  }
916
988
  // #endregion
917
989
  /**
@@ -921,7 +993,7 @@ class z extends I {
921
993
  */
922
994
  resetChangedRows(e) {
923
995
  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"));
996
+ this.#i.clear(), this.#d(), e || this.emit("changed-rows-reset", { rows: t, ids: i }), this.grid._rowPool?.forEach((n) => n.classList.remove("changed"));
925
997
  }
926
998
  /**
927
999
  * Programmatically begin editing a cell.
@@ -930,10 +1002,10 @@ class z extends I {
930
1002
  * @fires cell-commit - Emitted when the cell value is committed (on blur or Enter)
931
1003
  */
932
1004
  beginCellEdit(e, t) {
933
- const i = this.grid, r = i._visibleColumns.findIndex((l) => l.field === t);
1005
+ const i = this.grid, r = i._visibleColumns.findIndex((a) => a.field === t);
934
1006
  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);
1007
+ const o = i.findRenderedRowElement?.(e)?.querySelector(`.cell[data-col="${r}"]`);
1008
+ o && this.#p(e, r, o);
937
1009
  }
938
1010
  /**
939
1011
  * Programmatically begin editing all editable cells in a row.
@@ -943,22 +1015,22 @@ class z extends I {
943
1015
  */
944
1016
  beginBulkEdit(e) {
945
1017
  const t = this.grid;
946
- if ((this.config.editOn ?? t.effectiveConfig?.editOn) === !1 || !t._columns?.some((a) => a.editable)) return;
1018
+ if ((this.config.editOn ?? t.effectiveConfig?.editOn) === !1 || !t._columns?.some((o) => o.editable)) return;
947
1019
  const n = t.findRenderedRowElement?.(e);
948
1020
  if (!n) return;
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);
1021
+ const l = t._rows[e];
1022
+ this.#h(e, l), Array.from(n.children).forEach((o, a) => {
1023
+ const c = t._visibleColumns[a];
1024
+ if (c?.editable) {
1025
+ const d = o;
1026
+ d.classList.contains("editing") || this.#f(l, e, c, a, d, !0);
955
1027
  }
956
1028
  }), setTimeout(() => {
957
- let a = n.querySelector(`.cell[data-col="${t._focusCol}"]`);
958
- if (a?.classList.contains("editing") || (a = n.querySelector(".cell.editing")), a?.classList.contains("editing")) {
959
- const l = a.querySelector(R);
1029
+ let o = n.querySelector(`.cell[data-col="${t._focusCol}"]`);
1030
+ if (o?.classList.contains("editing") || (o = n.querySelector(".cell.editing")), o?.classList.contains("editing")) {
1031
+ const a = o.querySelector(C);
960
1032
  try {
961
- l?.focus({ preventScroll: !0 });
1033
+ a?.focus({ preventScroll: !0 });
962
1034
  } catch {
963
1035
  }
964
1036
  }
@@ -983,13 +1055,31 @@ class z extends I {
983
1055
  * Begin editing a single cell.
984
1056
  */
985
1057
  #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));
1058
+ const r = this.grid, n = r._rows[e], l = r._visibleColumns[t];
1059
+ !n || !l?.editable || i.classList.contains("editing") || (this.#e !== e && this.#h(e, n), this.#o = t, this.#f(n, e, l, t, i, !1));
1060
+ }
1061
+ /**
1062
+ * Handle Tab/Shift+Tab navigation while editing.
1063
+ * Moves to next/previous editable cell, staying in edit mode.
1064
+ * Wraps to next/previous row when reaching row boundaries.
1065
+ */
1066
+ #m(e) {
1067
+ const t = this.grid, i = t._rows, r = this.#e, n = t._visibleColumns.map((c, d) => c.editable ? d : -1).filter((c) => c >= 0);
1068
+ if (n.length === 0) return;
1069
+ const o = n.indexOf(t._focusCol) + (e ? 1 : -1);
1070
+ if (o >= 0 && o < n.length) {
1071
+ t._focusCol = n[o];
1072
+ const d = t.findRenderedRowElement?.(r)?.querySelector(`.cell[data-col="${n[o]}"]`);
1073
+ d?.classList.contains("editing") && d.querySelector(C)?.focus({ preventScroll: !0 }), S(t, { forceHorizontalScroll: !0 });
1074
+ return;
1075
+ }
1076
+ const a = r + (e ? 1 : -1);
1077
+ a >= 0 && a < i.length && (this.#n(r, !1), t._focusRow = a, t._focusCol = e ? n[0] : n[n.length - 1], this.beginBulkEdit(a), S(t, { forceHorizontalScroll: !0 }));
988
1078
  }
989
1079
  /**
990
1080
  * Sync the internal grid state with the plugin's editing state.
991
1081
  */
992
- #c() {
1082
+ #d() {
993
1083
  const e = this.grid;
994
1084
  e._activeEditRows = this.#e, e._rowEditSnapshots = this.#s;
995
1085
  }
@@ -997,55 +1087,56 @@ class z extends I {
997
1087
  * Snapshot original row data and mark as editing.
998
1088
  */
999
1089
  #h(e, t) {
1000
- this.#e !== e && (this.#s.set(e, { ...t }), this.#e = e, this.#c());
1090
+ this.#e !== e && (this.#s.set(e, { ...t }), this.#e = e, this.#d());
1001
1091
  }
1002
1092
  /**
1003
1093
  * Exit editing for a row.
1004
1094
  */
1005
1095
  #n(e, t) {
1006
1096
  if (this.#e !== e) return;
1007
- const i = this.grid, r = this.#s.get(e), n = i._rows[e], o = i.findRenderedRowElement?.(e);
1008
- let a;
1097
+ const i = this.grid, r = this.#s.get(e), n = i._rows[e], l = i.findRenderedRowElement?.(e);
1098
+ let o;
1009
1099
  if (n)
1010
1100
  try {
1011
- a = i.getRowId?.(n);
1101
+ o = i.getRowId?.(n);
1012
1102
  } catch {
1013
1103
  }
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");
1104
+ if (!t && l && n && l.querySelectorAll(".cell.editing").forEach((c) => {
1105
+ const d = Number(c.getAttribute("data-col"));
1106
+ if (isNaN(d)) return;
1107
+ const f = i._visibleColumns[d];
1108
+ if (!f || c.hasAttribute("data-editor-managed"))
1109
+ return;
1110
+ const u = c.querySelector("input,textarea,select");
1020
1111
  if (u) {
1021
- const m = p.field, h = n[m], g = E(u, p, h);
1022
- h !== g && this.#u(e, p, g, n);
1112
+ const m = f.field, p = n[m], g = y(u, f, p);
1113
+ p !== g && this.#u(e, f, g, n);
1023
1114
  }
1024
1115
  }), t && r && n)
1025
- Object.keys(r).forEach((l) => {
1026
- n[l] = r[l];
1027
- }), a && (this.#i.delete(a), this.clearRowInvalid(a));
1116
+ Object.keys(r).forEach((a) => {
1117
+ n[a] = r[a];
1118
+ }), o && (this.#i.delete(o), this.clearRowInvalid(o));
1028
1119
  else if (!t && n) {
1029
- const l = this.#v(r, n), d = a ? this.#i.has(a) : l, c = this.emitCancelable("row-commit", {
1120
+ const a = this.#b(r, n), c = o ? this.#i.has(o) : a, d = this.emitCancelable("row-commit", {
1030
1121
  rowIndex: e,
1031
- rowId: a ?? "",
1122
+ rowId: o ?? "",
1032
1123
  row: n,
1033
1124
  oldValue: r,
1034
1125
  newValue: n,
1035
- changed: d,
1126
+ changed: c,
1036
1127
  changedRows: this.changedRows,
1037
1128
  changedRowIds: this.changedRowIds
1038
1129
  });
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);
1130
+ d && r ? (Object.keys(r).forEach((f) => {
1131
+ n[f] = r[f];
1132
+ }), o && (this.#i.delete(o), this.clearRowInvalid(o))) : !d && a && this.isAnimationEnabled && (this.#a = e);
1042
1133
  }
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);
1046
- o && (o.querySelectorAll(".cell.editing").forEach((l) => {
1047
- l.classList.remove("editing"), x(l.parentElement);
1048
- }), this.requestRender()), this.#a = !0, o || (this.#g(i), this.#a = !1);
1134
+ this.#s.delete(e), this.#e = -1, this.#o = -1, this.#d();
1135
+ for (const a of this.#r)
1136
+ a.startsWith(`${e}:`) && this.#r.delete(a);
1137
+ l && (l.querySelectorAll(".cell.editing").forEach((a) => {
1138
+ a.classList.remove("editing"), j(a.parentElement);
1139
+ }), this.requestRender()), this.#l = !0, l || (this.#g(i), this.#l = !1);
1049
1140
  }
1050
1141
  /**
1051
1142
  * Commit a single cell value change.
@@ -1053,158 +1144,176 @@ class z extends I {
1053
1144
  */
1054
1145
  #u(e, t, i, r) {
1055
1146
  const n = t.field;
1056
- if (!w(n)) return;
1057
- const o = r[n];
1058
- if (o === i) return;
1059
- const a = this.grid;
1060
- let l;
1147
+ if (!E(n)) return;
1148
+ const l = r[n];
1149
+ if (l === i) return;
1150
+ const o = this.grid;
1151
+ let a;
1061
1152
  try {
1062
- l = this.grid.getRowId(r);
1153
+ a = this.grid.getRowId(r);
1063
1154
  } catch {
1064
1155
  }
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 ?? "");
1156
+ const c = a ? !this.#i.has(a) : !0, d = a ? (g) => this.grid.updateRow(a, g, "cascade") : A;
1157
+ let f = !1;
1158
+ const u = a ? (g) => {
1159
+ f = !0, this.setInvalid(a, n, g ?? "");
1069
1160
  } : () => {
1070
1161
  };
1071
1162
  if (this.emitCancelable("cell-commit", {
1072
1163
  row: r,
1073
- rowId: l ?? "",
1164
+ rowId: a ?? "",
1074
1165
  field: n,
1075
- oldValue: o,
1166
+ oldValue: l,
1076
1167
  value: i,
1077
1168
  rowIndex: e,
1078
1169
  changedRows: this.changedRows,
1079
1170
  changedRowIds: this.changedRowIds,
1080
- firstTimeForRow: d,
1081
- updateRow: c,
1171
+ firstTimeForRow: c,
1172
+ updateRow: d,
1082
1173
  setInvalid: u
1083
1174
  })) return;
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", {
1175
+ a && !f && this.isCellInvalid(a, n) && this.clearInvalid(a, n), r[n] = i, a && this.#i.add(a), this.#d(), this.emitPluginEvent("cell-edit-committed", {
1085
1176
  rowIndex: e,
1086
1177
  field: n,
1087
- oldValue: o,
1178
+ oldValue: l,
1088
1179
  newValue: i
1089
1180
  });
1090
- const h = a.findRenderedRowElement?.(e);
1091
- h && h.classList.add("changed");
1181
+ const p = o.findRenderedRowElement?.(e);
1182
+ p && p.classList.add("changed");
1092
1183
  }
1093
1184
  /**
1094
1185
  * Inject an editor into a cell.
1095
1186
  */
1096
- #f(e, t, i, r, n, o) {
1187
+ #f(e, t, i, r, n, l) {
1097
1188
  if (!i.editable || n.classList.contains("editing")) return;
1098
- let a;
1189
+ let o;
1099
1190
  try {
1100
- a = this.grid.getRowId(e);
1191
+ o = this.grid.getRowId(e);
1101
1192
  } catch {
1102
1193
  }
1103
- const l = a ? (f) => this.grid.updateRow(a, f, "cascade") : k, d = w(i.field) ? e[i.field] : void 0;
1194
+ const a = o ? (h) => this.grid.updateRow(o, h, "cascade") : A, c = E(i.field) ? e[i.field] : void 0;
1104
1195
  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);
1196
+ const d = n.parentElement;
1197
+ d && F(d);
1198
+ let f = !1;
1199
+ const u = (h) => {
1200
+ f || this.#e === -1 || this.#u(t, i, h, e);
1110
1201
  }, 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));
1202
+ f = !0, E(i.field) && (e[i.field] = c);
1203
+ }, p = document.createElement("div");
1204
+ p.className = "tbw-editor-host", n.innerHTML = "", n.appendChild(p), p.addEventListener("keydown", (h) => {
1205
+ if (h.key === "Enter") {
1206
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(h) === !1)
1207
+ return;
1208
+ h.stopPropagation(), h.preventDefault(), f = !0, this.#n(t, !1);
1209
+ }
1210
+ if (h.key === "Escape") {
1211
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(h) === !1)
1212
+ return;
1213
+ h.stopPropagation(), h.preventDefault(), m(), this.#n(t, !0);
1214
+ }
1115
1215
  });
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 });
1216
+ const g = i, w = g.__editorTemplate, b = G(this.grid, g) ?? $(i), R = c;
1217
+ if (b === "template" && w)
1218
+ this.#v(p, g, e, c, u, m, l, t);
1219
+ else if (typeof b == "string") {
1220
+ const h = document.createElement(b);
1221
+ h.value = R, h.addEventListener("change", () => u(h.value)), p.appendChild(h), l || queueMicrotask(() => {
1222
+ p.querySelector(C)?.focus({ preventScroll: !0 });
1123
1223
  });
1124
- } else if (typeof v == "function") {
1125
- const f = {
1224
+ } else if (typeof b == "function") {
1225
+ const h = {
1126
1226
  row: e,
1127
- rowId: a ?? "",
1128
- value: C,
1227
+ rowId: o ?? "",
1228
+ value: R,
1129
1229
  field: i.field,
1130
1230
  column: i,
1131
1231
  commit: u,
1132
1232
  cancel: m,
1133
- updateRow: l
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 });
1233
+ updateRow: a
1234
+ }, v = b(h);
1235
+ typeof v == "string" ? (p.innerHTML = v, W(p, i, u, c)) : v instanceof Node && (p.appendChild(v), v instanceof HTMLInputElement || v instanceof HTMLSelectElement || v instanceof HTMLTextAreaElement || n.setAttribute("data-editor-managed", "")), l || queueMicrotask(() => {
1236
+ p.querySelector(C)?.focus({ preventScroll: !0 });
1137
1237
  });
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 = {
1238
+ } else if (b && typeof b == "object") {
1239
+ const h = document.createElement("div");
1240
+ h.setAttribute("data-external-editor", ""), h.setAttribute("data-field", i.field), p.appendChild(h), n.setAttribute("data-editor-managed", "");
1241
+ const v = {
1142
1242
  row: e,
1143
- rowId: a ?? "",
1144
- value: C,
1243
+ rowId: o ?? "",
1244
+ value: R,
1145
1245
  field: i.field,
1146
1246
  column: i,
1147
1247
  commit: u,
1148
1248
  cancel: m,
1149
- updateRow: l
1249
+ updateRow: a
1150
1250
  };
1151
- if (v.mount)
1251
+ if (b.mount)
1152
1252
  try {
1153
- v.mount({ placeholder: f, context: b, spec: v });
1253
+ b.mount({ placeholder: h, context: v, spec: b });
1154
1254
  } catch (_) {
1155
1255
  console.warn(`[tbw-grid] External editor mount error for column '${i.field}':`, _);
1156
1256
  }
1157
1257
  else
1158
1258
  this.grid.dispatchEvent(
1159
- new CustomEvent("mount-external-editor", { detail: { placeholder: f, spec: v, context: b } })
1259
+ new CustomEvent("mount-external-editor", { detail: { placeholder: h, spec: b, context: v } })
1160
1260
  );
1161
1261
  }
1162
1262
  }
1163
1263
  /**
1164
1264
  * Render a template-based editor.
1165
1265
  */
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({
1266
+ #v(e, t, i, r, n, l, o, a) {
1267
+ const c = t.__editorTemplate;
1268
+ if (!c) return;
1269
+ const d = c.cloneNode(!0), f = t.__compiledEditor;
1270
+ f ? d.innerHTML = f({
1171
1271
  row: i,
1172
1272
  value: r,
1173
1273
  field: t.field,
1174
1274
  column: t,
1175
1275
  commit: n,
1176
- cancel: o
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];
1181
- return y == null ? "" : String(y);
1276
+ cancel: l
1277
+ }) : d.querySelectorAll("*").forEach((m) => {
1278
+ 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, (p, g) => {
1279
+ if (!E(g)) return "";
1280
+ const w = i[g];
1281
+ return w == null ? "" : String(w);
1182
1282
  }) || "");
1183
1283
  });
1184
- const u = c.querySelector(
1284
+ const u = d.querySelector(
1185
1285
  "input,textarea,select"
1186
1286
  );
1187
1287
  if (u) {
1188
1288
  u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked = !!r : u.value = String(r ?? "");
1189
1289
  let m = !1;
1190
1290
  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);
1291
+ m || n(y(u, t, r));
1292
+ }), u.addEventListener("keydown", (p) => {
1293
+ const g = p;
1294
+ if (g.key === "Enter") {
1295
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(g) === !1)
1296
+ return;
1297
+ g.stopPropagation(), g.preventDefault(), m = !0, n(y(u, t, r)), this.#n(a, !1);
1298
+ }
1299
+ if (g.key === "Escape") {
1300
+ if (this.config.onBeforeEditClose && this.config.onBeforeEditClose(g) === !1)
1301
+ return;
1302
+ g.stopPropagation(), g.preventDefault(), l(), this.#n(a, !0);
1303
+ }
1304
+ }), u instanceof HTMLInputElement && u.type === "checkbox" && u.addEventListener("change", () => n(u.checked)), o || setTimeout(() => u.focus({ preventScroll: !0 }), 0);
1196
1305
  }
1197
- e.appendChild(c);
1306
+ e.appendChild(d);
1198
1307
  }
1199
1308
  /**
1200
1309
  * Compare snapshot vs current row to detect if any values changed during this edit session.
1201
1310
  * Uses shallow comparison of all properties.
1202
1311
  */
1203
- #v(e, t) {
1312
+ #b(e, t) {
1204
1313
  if (!e) return !1;
1205
1314
  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])
1315
+ for (const l of n)
1316
+ if (i[l] !== r[l])
1208
1317
  return !0;
1209
1318
  return !1;
1210
1319
  }
@@ -1217,7 +1326,7 @@ class z extends I {
1217
1326
  const t = e._focusRow, i = e._focusCol, r = e.findRenderedRowElement?.(t);
1218
1327
  if (r) {
1219
1328
  Array.from(e._bodyEl.querySelectorAll(".cell-focus")).forEach(
1220
- (o) => o.classList.remove("cell-focus")
1329
+ (l) => l.classList.remove("cell-focus")
1221
1330
  );
1222
1331
  const n = r.querySelector(`.cell[data-row="${t}"][data-col="${i}"]`);
1223
1332
  n && (n.classList.add("cell-focus"), n.setAttribute("aria-selected", "true"), n.hasAttribute("tabindex") || n.setAttribute("tabindex", "-1"), n.focus({ preventScroll: !0 }));
@@ -1229,7 +1338,7 @@ class z extends I {
1229
1338
  // #endregion
1230
1339
  }
1231
1340
  export {
1232
- z as EditingPlugin,
1233
- N as defaultEditorFor
1341
+ K as EditingPlugin,
1342
+ $ as defaultEditorFor
1234
1343
  };
1235
1344
  //# sourceMappingURL=index.js.map