@toolbox-web/grid 0.4.1 → 0.5.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 (176) hide show
  1. package/README.md +9 -13
  2. package/all.js +1678 -1588
  3. package/all.js.map +1 -1
  4. package/index.js +762 -568
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +21 -0
  7. package/lib/core/grid.d.ts.map +1 -1
  8. package/lib/core/internal/config-manager.d.ts +1 -0
  9. package/lib/core/internal/config-manager.d.ts.map +1 -1
  10. package/lib/core/internal/dom-builder.d.ts +2 -0
  11. package/lib/core/internal/dom-builder.d.ts.map +1 -1
  12. package/lib/core/internal/header.d.ts.map +1 -1
  13. package/lib/core/internal/keyboard.d.ts.map +1 -1
  14. package/lib/core/internal/resize.d.ts.map +1 -1
  15. package/lib/core/internal/rows.d.ts.map +1 -1
  16. package/lib/core/internal/shell.d.ts +19 -13
  17. package/lib/core/internal/shell.d.ts.map +1 -1
  18. package/lib/core/internal/utils.d.ts +1 -0
  19. package/lib/core/internal/utils.d.ts.map +1 -1
  20. package/lib/core/plugin/base-plugin.d.ts +70 -3
  21. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  22. package/lib/core/plugin/expander-column.d.ts +51 -0
  23. package/lib/core/plugin/expander-column.d.ts.map +1 -0
  24. package/lib/core/plugin/plugin-manager.d.ts +6 -2
  25. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  26. package/lib/core/plugin/types.d.ts +117 -1
  27. package/lib/core/plugin/types.d.ts.map +1 -1
  28. package/lib/core/types.d.ts +10 -5
  29. package/lib/core/types.d.ts.map +1 -1
  30. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +5 -4
  31. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  32. package/lib/plugins/clipboard/index.d.ts +1 -1
  33. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  34. package/lib/plugins/clipboard/index.js +295 -190
  35. package/lib/plugins/clipboard/index.js.map +1 -1
  36. package/lib/plugins/clipboard/types.d.ts +72 -2
  37. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  38. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
  39. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  40. package/lib/plugins/column-virtualization/index.js +143 -56
  41. package/lib/plugins/column-virtualization/index.js.map +1 -1
  42. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
  43. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  44. package/lib/plugins/context-menu/index.js +189 -102
  45. package/lib/plugins/context-menu/index.js.map +1 -1
  46. package/lib/plugins/editing/EditingPlugin.d.ts +2 -7
  47. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  48. package/lib/plugins/editing/index.js +227 -150
  49. package/lib/plugins/editing/index.js.map +1 -1
  50. package/lib/plugins/export/ExportPlugin.d.ts +0 -1
  51. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  52. package/lib/plugins/export/index.js +184 -97
  53. package/lib/plugins/export/index.js.map +1 -1
  54. package/lib/plugins/filtering/FilteringPlugin.d.ts +14 -3
  55. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  56. package/lib/plugins/filtering/index.js +296 -176
  57. package/lib/plugins/filtering/index.js.map +1 -1
  58. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +2 -2
  59. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  60. package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
  61. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  62. package/lib/plugins/grouping-columns/index.js +169 -61
  63. package/lib/plugins/grouping-columns/index.js.map +1 -1
  64. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
  65. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  66. package/lib/plugins/grouping-rows/index.js +243 -140
  67. package/lib/plugins/grouping-rows/index.js.map +1 -1
  68. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
  69. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  70. package/lib/plugins/master-detail/index.js +278 -196
  71. package/lib/plugins/master-detail/index.js.map +1 -1
  72. package/lib/plugins/master-detail/types.d.ts +0 -10
  73. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  74. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
  75. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  76. package/lib/plugins/multi-sort/index.js +125 -40
  77. package/lib/plugins/multi-sort/index.js.map +1 -1
  78. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
  79. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  80. package/lib/plugins/pinned-columns/index.js +156 -75
  81. package/lib/plugins/pinned-columns/index.js.map +1 -1
  82. package/lib/plugins/pinned-columns/pinned-columns.d.ts +2 -2
  83. package/lib/plugins/pinned-columns/pinned-columns.d.ts.map +1 -1
  84. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
  85. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  86. package/lib/plugins/pinned-rows/index.js +202 -117
  87. package/lib/plugins/pinned-rows/index.js.map +1 -1
  88. package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
  89. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  90. package/lib/plugins/pivot/index.js +413 -314
  91. package/lib/plugins/pivot/index.js.map +1 -1
  92. package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
  93. package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
  94. package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
  95. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  96. package/lib/plugins/reorder/index.d.ts +1 -1
  97. package/lib/plugins/reorder/index.d.ts.map +1 -1
  98. package/lib/plugins/reorder/index.js +296 -223
  99. package/lib/plugins/reorder/index.js.map +1 -1
  100. package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
  101. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  102. package/lib/plugins/selection/index.d.ts +2 -2
  103. package/lib/plugins/selection/index.d.ts.map +1 -1
  104. package/lib/plugins/selection/index.js +282 -141
  105. package/lib/plugins/selection/index.js.map +1 -1
  106. package/lib/plugins/selection/types.d.ts +24 -0
  107. package/lib/plugins/selection/types.d.ts.map +1 -1
  108. package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
  109. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  110. package/lib/plugins/server-side/index.js +96 -9
  111. package/lib/plugins/server-side/index.js.map +1 -1
  112. package/lib/plugins/tree/TreePlugin.d.ts +5 -1
  113. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  114. package/lib/plugins/tree/index.js +209 -113
  115. package/lib/plugins/tree/index.js.map +1 -1
  116. package/lib/plugins/tree/types.d.ts +0 -10
  117. package/lib/plugins/tree/types.d.ts.map +1 -1
  118. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +0 -1
  119. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  120. package/lib/plugins/undo-redo/index.js +98 -11
  121. package/lib/plugins/undo-redo/index.js.map +1 -1
  122. package/lib/plugins/visibility/VisibilityPlugin.d.ts +7 -4
  123. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  124. package/lib/plugins/visibility/index.js +155 -64
  125. package/lib/plugins/visibility/index.js.map +1 -1
  126. package/package.json +1 -1
  127. package/themes/dg-theme-bootstrap.css +55 -53
  128. package/themes/dg-theme-contrast.css +42 -40
  129. package/themes/dg-theme-large.css +38 -37
  130. package/themes/dg-theme-material.css +54 -52
  131. package/themes/dg-theme-standard.css +19 -17
  132. package/themes/dg-theme-vibrant.css +16 -14
  133. package/umd/grid.all.umd.js +23 -24
  134. package/umd/grid.all.umd.js.map +1 -1
  135. package/umd/grid.umd.js +12 -11
  136. package/umd/grid.umd.js.map +1 -1
  137. package/umd/plugins/clipboard.umd.js +5 -7
  138. package/umd/plugins/clipboard.umd.js.map +1 -1
  139. package/umd/plugins/column-virtualization.umd.js +1 -1
  140. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  141. package/umd/plugins/context-menu.umd.js +1 -1
  142. package/umd/plugins/context-menu.umd.js.map +1 -1
  143. package/umd/plugins/editing.umd.js +1 -1
  144. package/umd/plugins/editing.umd.js.map +1 -1
  145. package/umd/plugins/export.umd.js +1 -1
  146. package/umd/plugins/export.umd.js.map +1 -1
  147. package/umd/plugins/filtering.umd.js +1 -1
  148. package/umd/plugins/filtering.umd.js.map +1 -1
  149. package/umd/plugins/grouping-columns.umd.js +1 -1
  150. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  151. package/umd/plugins/grouping-rows.umd.js +1 -1
  152. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  153. package/umd/plugins/master-detail.umd.js +1 -1
  154. package/umd/plugins/master-detail.umd.js.map +1 -1
  155. package/umd/plugins/multi-sort.umd.js +1 -1
  156. package/umd/plugins/multi-sort.umd.js.map +1 -1
  157. package/umd/plugins/pinned-columns.umd.js +1 -1
  158. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  159. package/umd/plugins/pinned-rows.umd.js +1 -1
  160. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  161. package/umd/plugins/pivot.umd.js +1 -1
  162. package/umd/plugins/pivot.umd.js.map +1 -1
  163. package/umd/plugins/reorder.umd.js +1 -1
  164. package/umd/plugins/reorder.umd.js.map +1 -1
  165. package/umd/plugins/selection.umd.js +1 -1
  166. package/umd/plugins/selection.umd.js.map +1 -1
  167. package/umd/plugins/server-side.umd.js +1 -1
  168. package/umd/plugins/server-side.umd.js.map +1 -1
  169. package/umd/plugins/tree.umd.js +1 -1
  170. package/umd/plugins/tree.umd.js.map +1 -1
  171. package/umd/plugins/undo-redo.umd.js +1 -1
  172. package/umd/plugins/undo-redo.umd.js.map +1 -1
  173. package/umd/plugins/visibility.umd.js +1 -1
  174. package/umd/plugins/visibility.umd.js.map +1 -1
  175. package/lib/core/internal/editing.d.ts +0 -76
  176. package/lib/core/internal/editing.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- const R = {
1
+ const _ = {
2
2
  expand: "▶",
3
3
  collapse: "▼",
4
4
  sortAsc: "▲",
@@ -8,7 +8,7 @@ const R = {
8
8
  dragHandle: "⋮⋮",
9
9
  toolPanel: "☰"
10
10
  };
11
- class _ {
11
+ class S {
12
12
  /**
13
13
  * Plugin dependencies - declare other plugins this one requires.
14
14
  *
@@ -25,8 +25,11 @@ class _ {
25
25
  * ```
26
26
  */
27
27
  static dependencies;
28
- /** Plugin version - override in subclass if needed */
29
- version = "1.0.0";
28
+ /**
29
+ * Plugin version - defaults to grid version for built-in plugins.
30
+ * Third-party plugins can override with their own semver.
31
+ */
32
+ version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
30
33
  /** CSS styles to inject into the grid's shadow DOM */
31
34
  styles;
32
35
  /** Custom cell renderers keyed by type name */
@@ -113,12 +116,28 @@ class _ {
113
116
  emit(e, t) {
114
117
  this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
115
118
  }
119
+ /**
120
+ * Emit a cancelable custom event from the grid.
121
+ * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
122
+ */
123
+ emitCancelable(e, t) {
124
+ const i = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
125
+ return this.grid?.dispatchEvent?.(i), i.defaultPrevented;
126
+ }
116
127
  /**
117
128
  * Request a re-render of the grid.
118
129
  */
119
130
  requestRender() {
120
131
  this.grid?.requestRender?.();
121
132
  }
133
+ /**
134
+ * Request a re-render and restore focus styling afterward.
135
+ * Use this when a plugin action (like expand/collapse) triggers a render
136
+ * but needs to maintain keyboard navigation focus.
137
+ */
138
+ requestRenderWithFocus() {
139
+ this.grid?.requestRenderWithFocus?.();
140
+ }
122
141
  /**
123
142
  * Request a lightweight style update without rebuilding DOM.
124
143
  * Use this instead of requestRender() when only CSS classes need updating.
@@ -153,10 +172,34 @@ class _ {
153
172
  return this.grid?._visibleColumns ?? [];
154
173
  }
155
174
  /**
156
- * Get the shadow root of the grid.
175
+ * Get the grid as an HTMLElement for direct DOM operations.
176
+ * Use sparingly - prefer the typed GridElementRef API when possible.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const width = this.gridElement.clientWidth;
181
+ * this.gridElement.classList.add('my-plugin-active');
182
+ * ```
183
+ */
184
+ get gridElement() {
185
+ return this.grid;
186
+ }
187
+ /**
188
+ * Get the render root of the grid for DOM queries.
189
+ * @deprecated Use `gridElement` instead. This getter exists only for backward compatibility.
190
+ *
191
+ * With Shadow DOM removed, the grid element itself is the render root.
192
+ * All new code should use `this.gridElement` for DOM queries.
193
+ *
194
+ * @example
195
+ * // OLD (deprecated)
196
+ * const rows = this.shadowRoot?.querySelector('.rows');
197
+ *
198
+ * // NEW (preferred)
199
+ * const rows = this.gridElement.querySelector('.rows');
157
200
  */
158
201
  get shadowRoot() {
159
- return this.grid?.shadowRoot ?? null;
202
+ return this.gridElement;
160
203
  }
161
204
  /**
162
205
  * Get the disconnect signal for event listener cleanup.
@@ -184,8 +227,53 @@ class _ {
184
227
  */
185
228
  get gridIcons() {
186
229
  const e = this.grid?.gridConfig?.icons ?? {};
187
- return { ...R, ...e };
230
+ return { ..._, ...e };
188
231
  }
232
+ // #region Animation Helpers
233
+ /**
234
+ * Check if animations are enabled at the grid level.
235
+ * Respects gridConfig.animation.mode and the CSS variable set by the grid.
236
+ *
237
+ * Plugins should use this to skip animations when:
238
+ * - Animation mode is 'off' or `false`
239
+ * - User prefers reduced motion and mode is 'reduced-motion' (default)
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * private get animationStyle(): 'slide' | 'fade' | false {
244
+ * if (!this.isAnimationEnabled) return false;
245
+ * return this.config.animation ?? 'slide';
246
+ * }
247
+ * ```
248
+ */
249
+ get isAnimationEnabled() {
250
+ const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
251
+ if (e === !1 || e === "off") return !1;
252
+ if (e === !0 || e === "on") return !0;
253
+ const t = this.gridElement;
254
+ return t ? getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
255
+ }
256
+ /**
257
+ * Get the animation duration in milliseconds from CSS variable.
258
+ * Falls back to 200ms if not set.
259
+ *
260
+ * Plugins can use this for their animation timing to stay consistent
261
+ * with the grid-level animation.duration setting.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * element.animate(keyframes, { duration: this.animationDuration });
266
+ * ```
267
+ */
268
+ get animationDuration() {
269
+ const e = this.gridElement;
270
+ if (e) {
271
+ const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), i = parseInt(t, 10);
272
+ if (!isNaN(i)) return i;
273
+ }
274
+ return 200;
275
+ }
276
+ // #endregion
189
277
  /**
190
278
  * Resolve an icon value to string or HTMLElement.
191
279
  * Checks plugin config first, then grid-level icons, then defaults.
@@ -215,8 +303,9 @@ class _ {
215
303
  }
216
304
  // #endregion
217
305
  }
218
- function k(f) {
219
- switch (f.type) {
306
+ const L = "@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-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}}";
307
+ function k(l) {
308
+ switch (l.type) {
220
309
  case "number":
221
310
  return (e) => {
222
311
  const t = document.createElement("input");
@@ -243,19 +332,19 @@ function k(f) {
243
332
  i.multi && (t.multiple = !0);
244
333
  const s = i.options;
245
334
  (typeof s == "function" ? s() : s || []).forEach((r) => {
246
- const c = document.createElement("option");
247
- c.value = String(r.value), c.textContent = r.label, (i.multi && Array.isArray(e.value) && e.value.includes(r.value) || !i.multi && e.value === r.value) && (c.selected = !0), t.appendChild(c);
335
+ const a = document.createElement("option");
336
+ a.value = String(r.value), a.textContent = r.label, (i.multi && Array.isArray(e.value) && e.value.includes(r.value) || !i.multi && e.value === r.value) && (a.selected = !0), t.appendChild(a);
248
337
  });
249
- const l = () => {
338
+ const o = () => {
250
339
  if (i.multi) {
251
340
  const r = [];
252
- Array.from(t.selectedOptions).forEach((c) => {
253
- r.push(c.value);
341
+ Array.from(t.selectedOptions).forEach((a) => {
342
+ r.push(a.value);
254
343
  }), e.commit(r);
255
344
  } else
256
345
  e.commit(t.value);
257
346
  };
258
- return t.addEventListener("change", l), t.addEventListener("blur", l), t.addEventListener("keydown", (r) => {
347
+ return t.addEventListener("change", o), t.addEventListener("blur", o), t.addEventListener("keydown", (r) => {
259
348
  r.key === "Escape" && e.cancel();
260
349
  }), t;
261
350
  };
@@ -268,31 +357,32 @@ function k(f) {
268
357
  };
269
358
  }
270
359
  }
271
- const w = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
272
- function b(f) {
273
- return !(typeof f != "string" || f === "__proto__" || f === "constructor" || f === "prototype");
360
+ const C = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
361
+ function w(l) {
362
+ return !(typeof l != "string" || l === "__proto__" || l === "constructor" || l === "prototype");
363
+ }
364
+ function O(l) {
365
+ return (l.__editingCellCount ?? 0) > 0;
274
366
  }
275
- function T(f) {
276
- return (f.__editingCellCount ?? 0) > 0;
367
+ function A(l) {
368
+ const e = (l.__editingCellCount ?? 0) + 1;
369
+ l.__editingCellCount = e, l.setAttribute("data-has-editing", "");
277
370
  }
278
- function L(f) {
279
- const e = (f.__editingCellCount ?? 0) + 1;
280
- f.__editingCellCount = e, f.setAttribute("data-has-editing", "");
371
+ function q(l) {
372
+ l.__editingCellCount = 0, l.removeAttribute("data-has-editing");
281
373
  }
282
- function S(f) {
283
- f.__editingCellCount = 0, f.removeAttribute("data-has-editing");
374
+ function v(l, e) {
375
+ return l instanceof HTMLInputElement ? l.type === "checkbox" ? l.checked : l.type === "number" ? l.value === "" ? null : Number(l.value) : l.type === "date" ? l.valueAsDate : l.value : e?.type === "number" && l.value !== "" ? Number(l.value) : l.value;
284
376
  }
285
- function A(f, e, t) {
286
- const i = f.querySelector("input,textarea,select");
287
- if (!i) return;
288
- const s = () => i instanceof HTMLInputElement ? i.type === "checkbox" ? i.checked : i.type === "number" ? i.value === "" ? null : Number(i.value) : i.type === "date" ? i.valueAsDate : i.value : e.type === "number" && i.value !== "" ? Number(i.value) : i.value;
289
- i.addEventListener("blur", () => {
290
- t(s());
291
- }), i instanceof HTMLInputElement && i.type === "checkbox" ? i.addEventListener("change", () => t(i.checked)) : i instanceof HTMLSelectElement && i.addEventListener("change", () => t(s()));
377
+ function T(l, e, t) {
378
+ const i = l.querySelector("input,textarea,select");
379
+ i && (i.addEventListener("blur", () => {
380
+ t(v(i, e));
381
+ }), i instanceof HTMLInputElement && i.type === "checkbox" ? i.addEventListener("change", () => t(i.checked)) : i instanceof HTMLSelectElement && i.addEventListener("change", () => t(v(i, e))));
292
382
  }
293
- class q extends _ {
383
+ class N extends S {
294
384
  name = "editing";
295
- version = "1.0.0";
385
+ styles = L;
296
386
  get defaultConfig() {
297
387
  return {
298
388
  editOn: "click"
@@ -344,15 +434,6 @@ class q extends _ {
344
434
  this.#e = -1, this.#r = -1, this.#s.clear(), this.#t.clear(), this.#n.clear(), super.detach();
345
435
  }
346
436
  // #endregion
347
- // #region Config Augmentation (processColumns hook)
348
- /**
349
- * Augment columns with editing metadata.
350
- * This enables the grid to recognize editable columns without core knowledge.
351
- */
352
- processColumns(e) {
353
- return e;
354
- }
355
- // #endregion
356
437
  // #region Event Handlers (event distribution)
357
438
  /**
358
439
  * Handle cell clicks - start editing if configured for click mode.
@@ -377,12 +458,12 @@ class q extends _ {
377
458
  if (e.key === " " || e.key === "Spacebar") {
378
459
  const i = t._focusRow, s = t._focusCol;
379
460
  if (i >= 0 && s >= 0) {
380
- const n = t._visibleColumns[s], l = t._rows[i];
381
- if (n?.editable && n.type === "boolean" && l) {
461
+ const n = t._visibleColumns[s], o = t._rows[i];
462
+ if (n?.editable && n.type === "boolean" && o) {
382
463
  const r = n.field;
383
- if (b(r)) {
384
- const u = !l[r];
385
- return this.#c(i, n, u, l), e.preventDefault(), this.requestRender(), !0;
464
+ if (w(r)) {
465
+ const f = !o[r];
466
+ return this.#a(i, n, f, o), e.preventDefault(), this.requestRender(), !0;
386
467
  }
387
468
  }
388
469
  }
@@ -394,7 +475,7 @@ class q extends _ {
394
475
  const i = this.config.editOn ?? t.effectiveConfig?.editOn;
395
476
  if (i === !1 || i === "manual") return !1;
396
477
  const s = t._focusRow;
397
- return s >= 0 && t._columns?.some((l) => l.editable) ? (this.beginBulkEdit(s), !0) : !1;
478
+ return s >= 0 && t._columns?.some((o) => o.editable) ? (this.beginBulkEdit(s), !0) : !1;
398
479
  }
399
480
  return !1;
400
481
  }
@@ -409,12 +490,12 @@ class q extends _ {
409
490
  const e = this.grid;
410
491
  if (this.#o && (this.#o = !1, this.#u(e)), this.#n.size !== 0)
411
492
  for (const t of this.#n) {
412
- const [i, s] = t.split(":"), n = parseInt(i, 10), l = parseInt(s, 10), r = e.findRenderedRowElement?.(n);
493
+ const [i, s] = t.split(":"), n = parseInt(i, 10), o = parseInt(s, 10), r = e.findRenderedRowElement?.(n);
413
494
  if (!r) continue;
414
- const c = r.querySelector(`.cell[data-col="${l}"]`);
415
- if (!c || c.classList.contains("editing")) continue;
416
- const u = e._rows[n], a = e._visibleColumns[l];
417
- u && a && this.#a(u, n, a, l, c, !0);
495
+ const a = r.querySelector(`.cell[data-col="${o}"]`);
496
+ if (!a || a.classList.contains("editing")) continue;
497
+ const f = e._rows[n], d = e._visibleColumns[o];
498
+ f && d && this.#c(f, n, d, o, a, !0);
418
499
  }
419
500
  }
420
501
  /**
@@ -479,7 +560,7 @@ class q extends _ {
479
560
  * Programmatically begin editing a cell.
480
561
  */
481
562
  beginCellEdit(e, t) {
482
- const i = this.grid, s = i._visibleColumns.findIndex((c) => c.field === t);
563
+ const i = this.grid, s = i._visibleColumns.findIndex((a) => a.field === t);
483
564
  if (s === -1 || !i._visibleColumns[s]?.editable) return;
484
565
  const r = i.findRenderedRowElement?.(e)?.querySelector(`.cell[data-col="${s}"]`);
485
566
  r && this.#f(e, s, r);
@@ -492,19 +573,19 @@ class q extends _ {
492
573
  if ((this.config.editOn ?? t.effectiveConfig?.editOn) === !1 || !t._columns?.some((r) => r.editable)) return;
493
574
  const n = t.findRenderedRowElement?.(e);
494
575
  if (!n) return;
495
- const l = t._rows[e];
496
- this.#d(e, l), Array.from(n.children).forEach((r, c) => {
497
- const u = t._visibleColumns[c];
498
- if (u?.editable) {
499
- const a = r;
500
- a.classList.contains("editing") || this.#a(l, e, u, c, a, !0);
576
+ const o = t._rows[e];
577
+ this.#d(e, o), Array.from(n.children).forEach((r, a) => {
578
+ const f = t._visibleColumns[a];
579
+ if (f?.editable) {
580
+ const d = r;
581
+ d.classList.contains("editing") || this.#c(o, e, f, a, d, !0);
501
582
  }
502
583
  }), setTimeout(() => {
503
584
  let r = n.querySelector(`.cell[data-col="${t._focusCol}"]`);
504
585
  if (r?.classList.contains("editing") || (r = n.querySelector(".cell.editing")), r?.classList.contains("editing")) {
505
- const c = r.querySelector(w);
586
+ const a = r.querySelector(C);
506
587
  try {
507
- c?.focus({ preventScroll: !0 });
588
+ a?.focus({ preventScroll: !0 });
508
589
  } catch {
509
590
  }
510
591
  }
@@ -528,8 +609,8 @@ class q extends _ {
528
609
  * Begin editing a single cell.
529
610
  */
530
611
  #f(e, t, i) {
531
- const s = this.grid, n = s._rows[e], l = s._visibleColumns[t];
532
- !n || !l?.editable || i.classList.contains("editing") || (this.#e !== e && this.#d(e, n), this.#r = t, this.#a(n, e, l, t, i, !1));
612
+ const s = this.grid, n = s._rows[e], o = s._visibleColumns[t];
613
+ !n || !o?.editable || i.classList.contains("editing") || (this.#e !== e && this.#d(e, n), this.#r = t, this.#c(n, e, o, t, i, !1));
533
614
  }
534
615
  /**
535
616
  * Sync the internal grid state with the plugin's editing state.
@@ -549,16 +630,16 @@ class q extends _ {
549
630
  */
550
631
  #i(e, t) {
551
632
  if (this.#e !== e) return;
552
- const i = this.grid, s = this.#s.get(e), n = i._rows[e], l = i.findRenderedRowElement?.(e);
553
- if (!t && l && n && l.querySelectorAll(".cell.editing").forEach((c) => {
554
- const u = Number(c.getAttribute("data-col"));
555
- if (isNaN(u)) return;
556
- const a = i._visibleColumns[u];
557
- if (!a) return;
558
- const g = c.querySelector("input,textarea,select");
559
- if (g) {
560
- let o;
561
- g instanceof HTMLInputElement && g.type === "checkbox" ? o = g.checked : (o = g.value, a.type === "number" && o !== "" && (o = Number(o))), n[a.field] !== o && this.#c(e, a, o, n);
633
+ const i = this.grid, s = this.#s.get(e), n = i._rows[e], o = i.findRenderedRowElement?.(e);
634
+ if (!t && o && n && o.querySelectorAll(".cell.editing").forEach((a) => {
635
+ const f = Number(a.getAttribute("data-col"));
636
+ if (isNaN(f)) return;
637
+ const d = i._visibleColumns[f];
638
+ if (!d) return;
639
+ const b = a.querySelector("input,textarea,select");
640
+ if (b) {
641
+ const c = v(b, d);
642
+ n[d.field] !== c && this.#a(e, d, c, n);
562
643
  }
563
644
  }), t && s && n)
564
645
  Object.keys(s).forEach((r) => {
@@ -577,119 +658,115 @@ class q extends _ {
577
658
  this.#s.delete(e), this.#e = -1, this.#r = -1, this.#l();
578
659
  for (const r of this.#n)
579
660
  r.startsWith(`${e}:`) && this.#n.delete(r);
580
- l && (l.querySelectorAll(".cell.editing").forEach((r) => {
581
- r.classList.remove("editing"), S(r.parentElement);
582
- }), this.requestRender()), this.#o = !0, l || (this.#u(i), this.#o = !1);
661
+ o && (o.querySelectorAll(".cell.editing").forEach((r) => {
662
+ r.classList.remove("editing"), q(r.parentElement);
663
+ }), this.requestRender()), this.#o = !0, o || (this.#u(i), this.#o = !1);
583
664
  }
584
665
  /**
585
666
  * Commit a single cell value change.
586
667
  */
587
- #c(e, t, i, s) {
668
+ #a(e, t, i, s) {
588
669
  const n = t.field;
589
- if (!b(n) || s[n] === i) return;
590
- s[n] = i;
670
+ if (!w(n)) return;
671
+ const o = s[n];
672
+ if (o === i) return;
591
673
  const r = !this.#t.has(e);
592
- this.#t.add(e), this.#l();
593
- const u = this.grid.findRenderedRowElement?.(e);
594
- u && u.classList.add("changed"), this.emit("cell-commit", {
674
+ if (this.emitCancelable("cell-commit", {
595
675
  row: s,
596
676
  field: n,
677
+ oldValue: o,
597
678
  value: i,
598
679
  rowIndex: e,
599
680
  changedRows: this.changedRows,
600
681
  changedRowIndices: this.changedRowIndices,
601
682
  firstTimeForRow: r
602
- });
683
+ })) return;
684
+ s[n] = i, this.#t.add(e), this.#l();
685
+ const d = this.grid.findRenderedRowElement?.(e);
686
+ d && d.classList.add("changed");
603
687
  }
604
688
  /**
605
689
  * Inject an editor into a cell.
606
690
  */
607
- #a(e, t, i, s, n, l) {
691
+ #c(e, t, i, s, n, o) {
608
692
  if (!i.editable || n.classList.contains("editing")) return;
609
- const r = b(i.field) ? e[i.field] : void 0;
693
+ const r = w(i.field) ? e[i.field] : void 0;
610
694
  n.classList.add("editing"), this.#n.add(`${t}:${s}`);
611
- const c = n.parentElement;
612
- c && L(c);
613
- let u = !1;
614
- const a = (h) => {
615
- u || this.#e === -1 || this.#c(t, i, h, e);
616
- }, g = () => {
617
- u = !0, b(i.field) && (e[i.field] = r);
618
- }, o = document.createElement("div");
619
- o.className = "tbw-editor-host", n.innerHTML = "", n.appendChild(o), o.addEventListener("keydown", (h) => {
620
- h.key === "Enter" && (h.stopPropagation(), h.preventDefault(), u = !0, this.#i(t, !1)), h.key === "Escape" && (h.stopPropagation(), h.preventDefault(), g(), this.#i(t, !0));
695
+ const a = n.parentElement;
696
+ a && A(a);
697
+ let f = !1;
698
+ const d = (h) => {
699
+ f || this.#e === -1 || this.#a(t, i, h, e);
700
+ }, b = () => {
701
+ f = !0, w(i.field) && (e[i.field] = r);
702
+ }, c = document.createElement("div");
703
+ c.className = "tbw-editor-host", n.innerHTML = "", n.appendChild(c), c.addEventListener("keydown", (h) => {
704
+ h.key === "Enter" && (h.stopPropagation(), h.preventDefault(), f = !0, this.#i(t, !1)), h.key === "Escape" && (h.stopPropagation(), h.preventDefault(), b(), this.#i(t, !0));
621
705
  });
622
- const p = i, v = p.__editorTemplate, d = p.editor || (v ? "template" : k(i)), m = r;
623
- if (d === "template" && v)
624
- this.#h(o, p, e, r, a, g, l, t);
625
- else if (typeof d == "string") {
626
- const h = document.createElement(d);
627
- h.value = m, h.addEventListener("change", () => a(h.value)), o.appendChild(h), l || queueMicrotask(() => {
628
- o.querySelector(w)?.focus({ preventScroll: !0 });
706
+ const g = i, E = g.__editorTemplate, u = g.editor || (E ? "template" : k(i)), m = r;
707
+ if (u === "template" && E)
708
+ this.#h(c, g, e, r, d, b, o, t);
709
+ else if (typeof u == "string") {
710
+ const h = document.createElement(u);
711
+ h.value = m, h.addEventListener("change", () => d(h.value)), c.appendChild(h), o || queueMicrotask(() => {
712
+ c.querySelector(C)?.focus({ preventScroll: !0 });
629
713
  });
630
- } else if (typeof d == "function") {
631
- const h = { row: e, value: m, field: i.field, column: i, commit: a, cancel: g }, E = d(h);
632
- typeof E == "string" ? (o.innerHTML = E, A(o, i, a)) : E instanceof Node && o.appendChild(E), l || queueMicrotask(() => {
633
- o.querySelector(w)?.focus({ preventScroll: !0 });
714
+ } else if (typeof u == "function") {
715
+ const h = { row: e, value: m, field: i.field, column: i, commit: d, cancel: b }, p = u(h);
716
+ typeof p == "string" ? (c.innerHTML = p, T(c, i, d)) : p instanceof Node && c.appendChild(p), o || queueMicrotask(() => {
717
+ c.querySelector(C)?.focus({ preventScroll: !0 });
634
718
  });
635
- } else if (d && typeof d == "object") {
636
- const h = this.grid, E = document.createElement("div");
637
- E.setAttribute("data-external-editor", ""), E.setAttribute("data-field", i.field), o.appendChild(E);
638
- const y = { row: e, value: m, field: i.field, column: i, commit: a, cancel: g };
639
- if (d.mount)
719
+ } else if (u && typeof u == "object") {
720
+ const h = this.grid, p = document.createElement("div");
721
+ p.setAttribute("data-external-editor", ""), p.setAttribute("data-field", i.field), c.appendChild(p);
722
+ const y = { row: e, value: m, field: i.field, column: i, commit: d, cancel: b };
723
+ if (u.mount)
640
724
  try {
641
- d.mount({ placeholder: E, context: y, spec: d });
642
- } catch (C) {
643
- console.warn(`[tbw-grid] External editor mount error for column '${i.field}':`, C);
725
+ u.mount({ placeholder: p, context: y, spec: u });
726
+ } catch (R) {
727
+ console.warn(`[tbw-grid] External editor mount error for column '${i.field}':`, R);
644
728
  }
645
729
  else
646
730
  h.dispatchEvent(
647
- new CustomEvent("mount-external-editor", { detail: { placeholder: E, spec: d, context: y } })
731
+ new CustomEvent("mount-external-editor", { detail: { placeholder: p, spec: u, context: y } })
648
732
  );
649
733
  }
650
734
  }
651
735
  /**
652
736
  * Render a template-based editor.
653
737
  */
654
- #h(e, t, i, s, n, l, r, c) {
655
- const u = t.__editorTemplate;
656
- if (!u) return;
657
- const a = u.cloneNode(!0), g = t.__compiledEditor;
658
- g ? a.innerHTML = g({
738
+ #h(e, t, i, s, n, o, r, a) {
739
+ const f = t.__editorTemplate;
740
+ if (!f) return;
741
+ const d = f.cloneNode(!0), b = t.__compiledEditor;
742
+ b ? d.innerHTML = b({
659
743
  row: i,
660
744
  value: s,
661
745
  field: t.field,
662
746
  column: t,
663
747
  commit: n,
664
- cancel: l
665
- }) : a.querySelectorAll("*").forEach((p) => {
666
- p.childNodes.length === 1 && p.firstChild?.nodeType === Node.TEXT_NODE && (p.textContent = p.textContent?.replace(/{{\s*value\s*}}/g, s == null ? "" : String(s)).replace(/{{\s*row\.([a-zA-Z0-9_]+)\s*}}/g, (v, d) => {
667
- if (!b(d)) return "";
668
- const m = i[d];
748
+ cancel: o
749
+ }) : d.querySelectorAll("*").forEach((g) => {
750
+ g.childNodes.length === 1 && g.firstChild?.nodeType === Node.TEXT_NODE && (g.textContent = g.textContent?.replace(/{{\s*value\s*}}/g, s == null ? "" : String(s)).replace(/{{\s*row\.([a-zA-Z0-9_]+)\s*}}/g, (E, u) => {
751
+ if (!w(u)) return "";
752
+ const m = i[u];
669
753
  return m == null ? "" : String(m);
670
754
  }) || "");
671
755
  });
672
- const o = a.querySelector(
756
+ const c = d.querySelector(
673
757
  "input,textarea,select"
674
758
  );
675
- if (o) {
676
- o instanceof HTMLInputElement && o.type === "checkbox" ? o.checked = !!s : o.value = String(s ?? "");
677
- let p = !1;
678
- o.addEventListener("blur", () => {
679
- if (p) return;
680
- const v = o instanceof HTMLInputElement && o.type === "checkbox" ? o.checked : o.value;
681
- n(v);
682
- }), o.addEventListener("keydown", (v) => {
683
- const d = v;
684
- if (d.key === "Enter") {
685
- d.stopPropagation(), d.preventDefault(), p = !0;
686
- const m = o instanceof HTMLInputElement && o.type === "checkbox" ? o.checked : o.value;
687
- n(m), this.#i(c, !1);
688
- }
689
- d.key === "Escape" && (d.stopPropagation(), d.preventDefault(), l(), this.#i(c, !0));
690
- }), o instanceof HTMLInputElement && o.type === "checkbox" && o.addEventListener("change", () => n(o.checked)), r || setTimeout(() => o.focus({ preventScroll: !0 }), 0);
759
+ if (c) {
760
+ c instanceof HTMLInputElement && c.type === "checkbox" ? c.checked = !!s : c.value = String(s ?? "");
761
+ let g = !1;
762
+ c.addEventListener("blur", () => {
763
+ g || n(v(c, t));
764
+ }), c.addEventListener("keydown", (E) => {
765
+ const u = E;
766
+ u.key === "Enter" && (u.stopPropagation(), u.preventDefault(), g = !0, n(v(c, t)), this.#i(a, !1)), u.key === "Escape" && (u.stopPropagation(), u.preventDefault(), o(), this.#i(a, !0));
767
+ }), c instanceof HTMLInputElement && c.type === "checkbox" && c.addEventListener("change", () => n(c.checked)), r || setTimeout(() => c.focus({ preventScroll: !0 }), 0);
691
768
  }
692
- e.appendChild(a);
769
+ e.appendChild(d);
693
770
  }
694
771
  /**
695
772
  * Restore focus to cell after exiting edit mode.
@@ -700,7 +777,7 @@ class q extends _ {
700
777
  const t = e._focusRow, i = e._focusCol, s = e.findRenderedRowElement?.(t);
701
778
  if (s) {
702
779
  Array.from(e._bodyEl.querySelectorAll(".cell-focus")).forEach(
703
- (l) => l.classList.remove("cell-focus")
780
+ (o) => o.classList.remove("cell-focus")
704
781
  );
705
782
  const n = s.querySelector(`.cell[data-row="${t}"][data-col="${i}"]`);
706
783
  n && (n.classList.add("cell-focus"), n.setAttribute("aria-selected", "true"), n.hasAttribute("tabindex") || n.setAttribute("tabindex", "-1"), n.focus({ preventScroll: !0 }));
@@ -712,10 +789,10 @@ class q extends _ {
712
789
  // #endregion
713
790
  }
714
791
  export {
715
- q as EditingPlugin,
716
- w as FOCUSABLE_EDITOR_SELECTOR,
717
- S as clearEditingState,
792
+ N as EditingPlugin,
793
+ C as FOCUSABLE_EDITOR_SELECTOR,
794
+ q as clearEditingState,
718
795
  k as defaultEditorFor,
719
- T as hasEditingCells
796
+ O as hasEditingCells
720
797
  };
721
798
  //# sourceMappingURL=index.js.map