@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
@@ -25,8 +25,11 @@ class I {
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 */
@@ -110,8 +113,16 @@ class I {
110
113
  /**
111
114
  * Emit a custom event from the grid.
112
115
  */
113
- emit(e, n) {
114
- this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: n, bubbles: !0 }));
116
+ emit(e, t) {
117
+ this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
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 n = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
125
+ return this.grid?.dispatchEvent?.(n), n.defaultPrevented;
115
126
  }
116
127
  /**
117
128
  * Request a re-render of the grid.
@@ -119,6 +130,14 @@ class I {
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 I {
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.
@@ -186,6 +229,51 @@ class I {
186
229
  const e = this.grid?.gridConfig?.icons ?? {};
187
230
  return { ...C, ...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(), n = parseInt(t, 10);
272
+ if (!isNaN(n)) return n;
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.
@@ -194,8 +282,8 @@ class I {
194
282
  * @param pluginOverride - Optional plugin-level override
195
283
  * @returns The resolved icon value
196
284
  */
197
- resolveIcon(e, n) {
198
- return n !== void 0 ? n : this.gridIcons[e];
285
+ resolveIcon(e, t) {
286
+ return t !== void 0 ? t : this.gridIcons[e];
199
287
  }
200
288
  /**
201
289
  * Set an icon value on an element.
@@ -204,8 +292,8 @@ class I {
204
292
  * @param element - The element to set the icon on
205
293
  * @param icon - The icon value (string or HTMLElement)
206
294
  */
207
- setIcon(e, n) {
208
- typeof n == "string" ? e.innerHTML = n : n instanceof HTMLElement && (e.innerHTML = "", e.appendChild(n.cloneNode(!0)));
295
+ setIcon(e, t) {
296
+ typeof t == "string" ? e.innerHTML = t : t instanceof HTMLElement && (e.innerHTML = "", e.appendChild(t.cloneNode(!0)));
209
297
  }
210
298
  /**
211
299
  * Log a warning message.
@@ -215,82 +303,81 @@ class I {
215
303
  }
216
304
  // #endregion
217
305
  }
218
- const g = ".tbw-context-menu{position:fixed;background:light-dark(#f5f5f5,#2a2a2a);color:light-dark(#222,#eee);border:1px solid light-dark(#d0d0d4,#454545);border-radius:4px;box-shadow:0 2px 10px #00000026;min-width:160px;padding:4px 0;z-index:10000;font-size:13px;font-family:system-ui,sans-serif}.tbw-context-menu-item{display:flex;align-items:center;padding:6px 12px;cursor:pointer;gap:8px}.tbw-context-menu-item:hover:not(.disabled){background:light-dark(#e8e8e8,#3a3a3a)}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:light-dark(#c00,#f66)}.tbw-context-menu-icon{width:16px;text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut{color:light-dark(#888,#888);font-size:11px}.tbw-context-menu-arrow{font-size:10px;color:light-dark(#888,#888)}.tbw-context-menu-separator{height:1px;background:light-dark(#d0d0d4,#454545);margin:4px 0}";
219
- function w(s, e) {
220
- return (typeof s == "function" ? s(e) : s).filter((i) => !(i.hidden === !0 || typeof i.hidden == "function" && i.hidden(e)));
306
+ const g = "@layer tbw-plugins{.tbw-context-menu{position:fixed;background:var(--tbw-context-menu-bg, var(--tbw-color-panel-bg, light-dark(#f5f5f5, #2a2a2a)));color:var(--tbw-context-menu-fg, var(--tbw-color-fg, light-dark(#222, #eee)));border:1px solid var(--tbw-context-menu-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-border-radius, .25rem);box-shadow:0 2px 10px var(--tbw-color-shadow, rgba(0, 0, 0, .15));min-width:var(--tbw-menu-min-width, 10rem);padding:var(--tbw-spacing-xs, .25rem) 0;z-index:10000;font-size:var(--tbw-font-size-sm, .8125rem);font-family:var(--tbw-font-family, system-ui, sans-serif)}.tbw-context-menu-item{display:flex;align-items:center;padding:var(--tbw-menu-item-padding, .375rem .75rem);cursor:pointer;gap:var(--tbw-menu-item-gap, .5rem)}.tbw-context-menu-item:hover:not(.disabled){background:var(--tbw-context-menu-hover, var(--tbw-color-row-hover, light-dark(#e8e8e8, #3a3a3a)))}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:light-dark(#c00,#f66)}.tbw-context-menu-icon{width:var(--tbw-icon-size, 1rem);text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut{color:var(--tbw-color-fg-muted, light-dark(#888, #888));font-size:var(--tbw-font-size-xs, .6875rem)}.tbw-context-menu-arrow{font-size:var(--tbw-font-size-2xs, .625rem);color:var(--tbw-color-fg-muted, light-dark(#888, #888))}.tbw-context-menu-separator{height:1px;background:var(--tbw-context-menu-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));margin:var(--tbw-spacing-xs, .25rem) 0}}";
307
+ function v(r, e) {
308
+ return (typeof r == "function" ? r(e) : r).filter((n) => !(n.hidden === !0 || typeof n.hidden == "function" && n.hidden(e)));
221
309
  }
222
- function M(s, e) {
223
- return s.disabled === !0 ? !0 : typeof s.disabled == "function" ? s.disabled(e) : !1;
310
+ function M(r, e) {
311
+ return r.disabled === !0 ? !0 : typeof r.disabled == "function" ? r.disabled(e) : !1;
224
312
  }
225
- function v(s, e, n, i = C.submenuArrow) {
226
- const r = document.createElement("div");
227
- r.className = "tbw-context-menu", r.setAttribute("role", "menu");
228
- for (const o of s) {
313
+ function x(r, e, t, n = C.submenuArrow) {
314
+ const l = document.createElement("div");
315
+ l.className = "tbw-context-menu", l.setAttribute("role", "menu");
316
+ for (const o of r) {
229
317
  if (o.separator) {
230
- const l = document.createElement("div");
231
- l.className = "tbw-context-menu-separator", l.setAttribute("role", "separator"), r.appendChild(l);
318
+ const s = document.createElement("div");
319
+ s.className = "tbw-context-menu-separator", s.setAttribute("role", "separator"), l.appendChild(s);
232
320
  continue;
233
321
  }
234
- const t = document.createElement("div");
235
- t.className = "tbw-context-menu-item", o.cssClass && t.classList.add(o.cssClass), t.setAttribute("role", "menuitem"), t.setAttribute("data-id", o.id);
236
- const c = M(o, e);
237
- if (c && (t.classList.add("disabled"), t.setAttribute("aria-disabled", "true")), o.icon) {
238
- const l = document.createElement("span");
239
- l.className = "tbw-context-menu-icon", l.innerHTML = o.icon, t.appendChild(l);
322
+ const i = document.createElement("div");
323
+ i.className = "tbw-context-menu-item", o.cssClass && i.classList.add(o.cssClass), i.setAttribute("role", "menuitem"), i.setAttribute("data-id", o.id);
324
+ const d = M(o, e);
325
+ if (d && (i.classList.add("disabled"), i.setAttribute("aria-disabled", "true")), o.icon) {
326
+ const s = document.createElement("span");
327
+ s.className = "tbw-context-menu-icon", s.innerHTML = o.icon, i.appendChild(s);
240
328
  }
241
- const d = document.createElement("span");
242
- if (d.className = "tbw-context-menu-label", d.textContent = o.name, t.appendChild(d), o.shortcut) {
243
- const l = document.createElement("span");
244
- l.className = "tbw-context-menu-shortcut", l.textContent = o.shortcut, t.appendChild(l);
329
+ const a = document.createElement("span");
330
+ if (a.className = "tbw-context-menu-label", a.textContent = o.name, i.appendChild(a), o.shortcut) {
331
+ const s = document.createElement("span");
332
+ s.className = "tbw-context-menu-shortcut", s.textContent = o.shortcut, i.appendChild(s);
245
333
  }
246
334
  if (o.subMenu?.length) {
247
- const l = document.createElement("span");
248
- l.className = "tbw-context-menu-arrow", typeof i == "string" ? l.innerHTML = i : i instanceof HTMLElement && l.appendChild(i.cloneNode(!0)), t.appendChild(l), t.addEventListener("mouseenter", () => {
249
- if (t.querySelector(".tbw-context-menu") || !o.subMenu) return;
250
- const h = w(o.subMenu, e), a = v(h, e, n, i);
251
- a.classList.add("tbw-context-submenu"), a.style.position = "absolute", a.style.left = "100%", a.style.top = "0", t.style.position = "relative", t.appendChild(a);
252
- }), t.addEventListener("mouseleave", () => {
253
- const u = t.querySelector(".tbw-context-menu");
335
+ const s = document.createElement("span");
336
+ s.className = "tbw-context-menu-arrow", typeof n == "string" ? s.innerHTML = n : n instanceof HTMLElement && s.appendChild(n.cloneNode(!0)), i.appendChild(s), i.addEventListener("mouseenter", () => {
337
+ if (i.querySelector(".tbw-context-menu") || !o.subMenu) return;
338
+ const h = v(o.subMenu, e), c = x(h, e, t, n);
339
+ c.classList.add("tbw-context-submenu"), c.style.position = "absolute", c.style.left = "100%", c.style.top = "0", i.style.position = "relative", i.appendChild(c);
340
+ }), i.addEventListener("mouseleave", () => {
341
+ const u = i.querySelector(".tbw-context-menu");
254
342
  u && u.remove();
255
343
  });
256
344
  }
257
- !c && o.action && !o.subMenu && t.addEventListener("click", (l) => {
258
- l.stopPropagation(), n(o);
259
- }), r.appendChild(t);
345
+ !d && o.action && !o.subMenu && i.addEventListener("click", (s) => {
346
+ s.stopPropagation(), t(o);
347
+ }), l.appendChild(i);
260
348
  }
261
- return r;
349
+ return l;
262
350
  }
263
- function y(s, e, n) {
264
- s.style.position = "fixed", s.style.left = `${e}px`, s.style.top = `${n}px`, s.style.visibility = "hidden", s.style.zIndex = "10000";
265
- const i = s.getBoundingClientRect(), r = window.innerWidth, o = window.innerHeight;
266
- let t = e, c = n;
267
- e + i.width > r && (t = e - i.width), n + i.height > o && (c = n - i.height), t = Math.max(0, t), c = Math.max(0, c), s.style.left = `${t}px`, s.style.top = `${c}px`, s.style.visibility = "visible";
351
+ function y(r, e, t) {
352
+ r.style.position = "fixed", r.style.left = `${e}px`, r.style.top = `${t}px`, r.style.visibility = "hidden", r.style.zIndex = "10000";
353
+ const n = r.getBoundingClientRect(), l = window.innerWidth, o = window.innerHeight;
354
+ let i = e, d = t;
355
+ e + n.width > l && (i = e - n.width), t + n.height > o && (d = t - n.height), i = Math.max(0, i), d = Math.max(0, d), r.style.left = `${i}px`, r.style.top = `${d}px`, r.style.visibility = "visible";
268
356
  }
269
- let f = null, p = null, m = null, b = 0;
270
- const x = [
357
+ let f = null, b = null, m = null, p = 0;
358
+ const w = [
271
359
  {
272
360
  id: "copy",
273
361
  name: "Copy",
274
362
  shortcut: "Ctrl+C",
275
- action: (s) => {
276
- s.grid?.plugins?.clipboard?.copy?.();
363
+ action: (r) => {
364
+ r.grid?.plugins?.clipboard?.copy?.();
277
365
  }
278
366
  },
279
367
  { separator: !0, id: "sep1", name: "" },
280
368
  {
281
369
  id: "export-csv",
282
370
  name: "Export CSV",
283
- action: (s) => {
284
- s.grid?.plugins?.export?.exportCsv?.();
371
+ action: (r) => {
372
+ r.grid?.plugins?.export?.exportCsv?.();
285
373
  }
286
374
  }
287
375
  ];
288
376
  class H extends I {
289
377
  name = "contextMenu";
290
- version = "1.0.0";
291
378
  get defaultConfig() {
292
379
  return {
293
- items: x
380
+ items: w
294
381
  };
295
382
  }
296
383
  // #region Internal State
@@ -301,7 +388,7 @@ class H extends I {
301
388
  // #endregion
302
389
  // #region Lifecycle
303
390
  attach(e) {
304
- super.attach(e), this.installGlobalHandlers(), b++;
391
+ super.attach(e), this.installGlobalHandlers(), p++;
305
392
  }
306
393
  detach() {
307
394
  this.menuElement && (this.menuElement.remove(), this.menuElement = null), this.isOpen = !1, this.params = null, this.uninstallGlobalHandlers();
@@ -310,44 +397,44 @@ class H extends I {
310
397
  // #region Private Methods
311
398
  installGlobalHandlers() {
312
399
  !m && typeof document < "u" && typeof g == "string" && g && (m = document.createElement("style"), m.id = "tbw-context-menu-styles", m.textContent = g, document.head.appendChild(m)), f || (f = () => {
313
- document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
314
- }, document.addEventListener("click", f)), p || (p = (e) => {
315
- e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((i) => i.remove());
316
- }, document.addEventListener("keydown", p));
400
+ document.querySelectorAll(".tbw-context-menu").forEach((t) => t.remove());
401
+ }, document.addEventListener("click", f)), b || (b = (e) => {
402
+ e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
403
+ }, document.addEventListener("keydown", b));
317
404
  }
318
405
  /**
319
406
  * Clean up global handlers when the last instance detaches.
320
407
  * Uses reference counting to ensure handlers persist while any grid uses the plugin.
321
408
  */
322
409
  uninstallGlobalHandlers() {
323
- b--, !(b > 0) && (f && (document.removeEventListener("click", f), f = null), p && (document.removeEventListener("keydown", p), p = null), m && (m.remove(), m = null));
410
+ p--, !(p > 0) && (f && (document.removeEventListener("click", f), f = null), b && (document.removeEventListener("keydown", b), b = null), m && (m.remove(), m = null));
324
411
  }
325
412
  // #endregion
326
413
  // #region Hooks
327
414
  afterRender() {
328
- const e = this.shadowRoot;
415
+ const e = this.gridElement;
329
416
  if (!e) return;
330
- const n = e.children[0];
331
- n && n.getAttribute("data-context-menu-bound") !== "true" && (n.setAttribute("data-context-menu-bound", "true"), n.addEventListener("contextmenu", (i) => {
332
- const r = i;
333
- r.preventDefault();
334
- const o = r.target, t = o.closest("[data-row][data-col]"), c = o.closest(".header-cell");
335
- let d;
336
- if (t) {
337
- const u = parseInt(t.getAttribute("data-row") ?? "-1", 10), h = parseInt(t.getAttribute("data-col") ?? "-1", 10), a = this.columns[h], E = this.rows[u];
338
- d = {
417
+ const t = e.children[0];
418
+ t && t.getAttribute("data-context-menu-bound") !== "true" && (t.setAttribute("data-context-menu-bound", "true"), t.addEventListener("contextmenu", (n) => {
419
+ const l = n;
420
+ l.preventDefault();
421
+ const o = l.target, i = o.closest("[data-row][data-col]"), d = o.closest(".header-cell");
422
+ let a;
423
+ if (i) {
424
+ const u = parseInt(i.getAttribute("data-row") ?? "-1", 10), h = parseInt(i.getAttribute("data-col") ?? "-1", 10), c = this.columns[h], E = this.rows[u];
425
+ a = {
339
426
  row: E,
340
427
  rowIndex: u,
341
- column: a,
428
+ column: c,
342
429
  columnIndex: h,
343
- field: a?.field ?? "",
344
- value: E?.[a?.field] ?? null,
430
+ field: c?.field ?? "",
431
+ value: E?.[c?.field] ?? null,
345
432
  isHeader: !1,
346
- event: r
433
+ event: l
347
434
  };
348
- } else if (c) {
349
- const u = parseInt(c.getAttribute("data-col") ?? "-1", 10), h = this.columns[u];
350
- d = {
435
+ } else if (d) {
436
+ const u = parseInt(d.getAttribute("data-col") ?? "-1", 10), h = this.columns[u];
437
+ a = {
351
438
  row: null,
352
439
  rowIndex: -1,
353
440
  column: h,
@@ -355,20 +442,20 @@ class H extends I {
355
442
  field: h?.field ?? "",
356
443
  value: null,
357
444
  isHeader: !0,
358
- event: r
445
+ event: l
359
446
  };
360
447
  } else
361
448
  return;
362
- this.params = d, this.position = { x: r.clientX, y: r.clientY };
363
- const l = w(this.config.items ?? x, d);
364
- l.length && (this.menuElement && this.menuElement.remove(), this.menuElement = v(
365
- l,
366
- d,
449
+ this.params = a, this.position = { x: l.clientX, y: l.clientY };
450
+ const s = v(this.config.items ?? w, a);
451
+ s.length && (this.menuElement && this.menuElement.remove(), this.menuElement = x(
452
+ s,
453
+ a,
367
454
  (u) => {
368
- u.action && u.action(d), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
455
+ u.action && u.action(a), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
369
456
  },
370
457
  this.gridIcons.submenuArrow
371
- ), document.body.appendChild(this.menuElement), y(this.menuElement, r.clientX, r.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: d, items: l }));
458
+ ), document.body.appendChild(this.menuElement), y(this.menuElement, l.clientX, l.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: a, items: s }));
372
459
  }));
373
460
  }
374
461
  // #endregion
@@ -379,25 +466,25 @@ class H extends I {
379
466
  * @param y - Y coordinate
380
467
  * @param params - Partial context menu parameters
381
468
  */
382
- showMenu(e, n, i) {
383
- const r = {
384
- row: i.row ?? null,
385
- rowIndex: i.rowIndex ?? -1,
386
- column: i.column ?? null,
387
- columnIndex: i.columnIndex ?? -1,
388
- field: i.field ?? "",
389
- value: i.value ?? null,
390
- isHeader: i.isHeader ?? !1,
391
- event: i.event ?? new MouseEvent("contextmenu")
392
- }, o = w(this.config.items ?? x, r);
393
- this.menuElement && this.menuElement.remove(), this.menuElement = v(
469
+ showMenu(e, t, n) {
470
+ const l = {
471
+ row: n.row ?? null,
472
+ rowIndex: n.rowIndex ?? -1,
473
+ column: n.column ?? null,
474
+ columnIndex: n.columnIndex ?? -1,
475
+ field: n.field ?? "",
476
+ value: n.value ?? null,
477
+ isHeader: n.isHeader ?? !1,
478
+ event: n.event ?? new MouseEvent("contextmenu")
479
+ }, o = v(this.config.items ?? w, l);
480
+ this.menuElement && this.menuElement.remove(), this.menuElement = x(
394
481
  o,
395
- r,
396
- (t) => {
397
- t.action && t.action(r), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
482
+ l,
483
+ (i) => {
484
+ i.action && i.action(l), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
398
485
  },
399
486
  this.gridIcons.submenuArrow
400
- ), document.body.appendChild(this.menuElement), y(this.menuElement, e, n), this.isOpen = !0;
487
+ ), document.body.appendChild(this.menuElement), y(this.menuElement, e, t), this.isOpen = !0;
401
488
  }
402
489
  /**
403
490
  * Hide the context menu.