@toolbox-web/grid 3.9.1 → 3.9.2

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 (77) hide show
  1. package/all.js +1 -1
  2. package/all.js.map +1 -1
  3. package/custom-elements.json +2 -2
  4. package/index.js +1 -1
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +8 -4
  7. package/lib/core/plugin/base-plugin.d.ts +7 -0
  8. package/lib/core/types.d.ts +2 -0
  9. package/lib/features/registry.js +1 -1
  10. package/lib/plugins/context-menu/context-menu-plugin.d.ts +9 -4
  11. package/lib/plugins/context-menu/index.js +1 -1
  12. package/lib/plugins/context-menu/index.js.map +1 -1
  13. package/lib/plugins/context-menu/types.d.ts +8 -4
  14. package/lib/plugins/editing/index.js +1 -1
  15. package/lib/plugins/editing/index.js.map +1 -1
  16. package/lib/plugins/editing/internal/dirty-tracking-manager.d.ts +2 -1
  17. package/lib/plugins/filtering/filter-model.d.ts +2 -1
  18. package/lib/plugins/filtering/filtering-plugin.d.ts +5 -2
  19. package/lib/plugins/filtering/index.js +1 -1
  20. package/lib/plugins/filtering/index.js.map +1 -1
  21. package/lib/plugins/grouping-rows/grouping-rows-plugin.d.ts +7 -14
  22. package/lib/plugins/grouping-rows/grouping-rows.d.ts +48 -0
  23. package/lib/plugins/grouping-rows/index.d.ts +1 -1
  24. package/lib/plugins/grouping-rows/index.js +1 -1
  25. package/lib/plugins/grouping-rows/index.js.map +1 -1
  26. package/lib/plugins/grouping-rows/types.d.ts +21 -0
  27. package/lib/plugins/master-detail/index.d.ts +1 -1
  28. package/lib/plugins/master-detail/index.js +1 -1
  29. package/lib/plugins/master-detail/index.js.map +1 -1
  30. package/lib/plugins/master-detail/master-detail-plugin.d.ts +28 -6
  31. package/lib/plugins/master-detail/master-detail.d.ts +0 -8
  32. package/lib/plugins/master-detail/types.d.ts +25 -1
  33. package/lib/plugins/multi-sort/index.js +1 -1
  34. package/lib/plugins/multi-sort/index.js.map +1 -1
  35. package/lib/plugins/selection/index.js +1 -1
  36. package/lib/plugins/selection/index.js.map +1 -1
  37. package/lib/plugins/selection/selection-plugin.d.ts +8 -1
  38. package/lib/plugins/server-side/datasource-types.d.ts +28 -0
  39. package/lib/plugins/server-side/datasource.d.ts +7 -0
  40. package/lib/plugins/server-side/index.js +1 -1
  41. package/lib/plugins/server-side/index.js.map +1 -1
  42. package/lib/plugins/server-side/server-side-plugin.d.ts +61 -8
  43. package/lib/plugins/server-side/types.d.ts +9 -1
  44. package/lib/plugins/tree/index.js +1 -1
  45. package/lib/plugins/tree/index.js.map +1 -1
  46. package/lib/plugins/tree/tree-plugin.d.ts +5 -11
  47. package/lib/plugins/tree/types.d.ts +22 -6
  48. package/lib/plugins/undo-redo/history.d.ts +2 -1
  49. package/lib/plugins/undo-redo/index.js +1 -1
  50. package/lib/plugins/undo-redo/index.js.map +1 -1
  51. package/lib/plugins/undo-redo/types.d.ts +13 -1
  52. package/lib/plugins/undo-redo/undo-redo-plugin.d.ts +15 -2
  53. package/package.json +1 -1
  54. package/umd/grid.all.umd.js +1 -1
  55. package/umd/grid.all.umd.js.map +1 -1
  56. package/umd/grid.umd.js +1 -1
  57. package/umd/grid.umd.js.map +1 -1
  58. package/umd/plugins/context-menu.umd.js +1 -1
  59. package/umd/plugins/context-menu.umd.js.map +1 -1
  60. package/umd/plugins/editing.umd.js +1 -1
  61. package/umd/plugins/editing.umd.js.map +1 -1
  62. package/umd/plugins/filtering.umd.js +1 -1
  63. package/umd/plugins/filtering.umd.js.map +1 -1
  64. package/umd/plugins/grouping-rows.umd.js +1 -1
  65. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  66. package/umd/plugins/master-detail.umd.js +1 -1
  67. package/umd/plugins/master-detail.umd.js.map +1 -1
  68. package/umd/plugins/multi-sort.umd.js +1 -1
  69. package/umd/plugins/multi-sort.umd.js.map +1 -1
  70. package/umd/plugins/selection.umd.js +1 -1
  71. package/umd/plugins/selection.umd.js.map +1 -1
  72. package/umd/plugins/server-side.umd.js +1 -1
  73. package/umd/plugins/server-side.umd.js.map +1 -1
  74. package/umd/plugins/tree.umd.js +1 -1
  75. package/umd/plugins/tree.umd.js.map +1 -1
  76. package/umd/plugins/undo-redo.umd.js +1 -1
  77. package/umd/plugins/undo-redo.umd.js.map +1 -1
@@ -78,7 +78,8 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
78
78
  * @internal
79
79
  */
80
80
  get _pluginManager(): PluginManager | undefined;
81
- _rows: T[];
81
+ get _rows(): T[];
82
+ set _rows(value: T[]);
82
83
  get _columns(): ColumnInternal<T>[];
83
84
  set _columns(value: ColumnInternal<T>[]);
84
85
  get _visibleColumns(): ColumnInternal<T>[];
@@ -899,7 +900,9 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
899
900
  *
900
901
  * Resolves the row from the full dataset, so a row that is filtered or paged
901
902
  * out of the visible view can still be updated. If the ID matches no row at
902
- * all, a `TBW041` warning is logged and the call is a no-op (never throws).
903
+ * all, a `TBW041` warning is logged and the call is a no-op (never throws);
904
+ * with `source: 'history'` (an undo/redo replay of a since-deleted row) the
905
+ * no-op is silent.
903
906
  *
904
907
  * **Filtered/paged-out rows:** the emitted `cell-change.rowIndex` is `-1`
905
908
  * (the row is not in the processed view). The update only schedules a
@@ -928,8 +931,9 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
928
931
  * More efficient than multiple `updateRow()` calls - single render cycle.
929
932
  *
930
933
  * Each row is resolved from the full dataset, so filtered/paged-out rows are
931
- * updated too. An unresolvable ID logs a `TBW041` warning and is skipped
932
- * without aborting the rest of the batch (never throws).
934
+ * updated too. An unresolvable ID logs a `TBW041` warning (silent for
935
+ * `source: 'history'`) and is skipped without aborting the rest of the batch
936
+ * (never throws).
933
937
  *
934
938
  * **Filtered/paged-out rows:** for a row resolved from the source dataset but
935
939
  * not currently in the processed view, the emitted `cell-change.rowIndex` is
@@ -497,6 +497,13 @@ export declare abstract class BaseGridPlugin<TConfig = unknown> implements GridP
497
497
  * ```
498
498
  */
499
499
  detach(): void;
500
+ /**
501
+ * Abort {@link disconnectSignal} (idempotent). The plugin manager calls this after
502
+ * every `detach()` so listeners bound to the signal are released even when an
503
+ * override does not call `super.detach()`.
504
+ * @internal
505
+ */
506
+ __releaseDisconnectSignal(): void;
500
507
  /**
501
508
  * Called when another plugin is attached to the same grid.
502
509
  * Use for inter-plugin coordination, e.g., to integrate with new plugins.
@@ -3353,6 +3353,8 @@ export interface TbwScrollDetail {
3353
3353
  * - `'history'`: Re-application of a value by the undo/redo plugin. Data
3354
3354
  * plugins (e.g. editing) apply the value but MUST NOT record a fresh
3355
3355
  * history entry or mark the row changed — the undo stack owns this change.
3356
+ * An ID that no longer resolves (row deleted since the edit) is skipped
3357
+ * without the `TBW041` warning.
3356
3358
  *
3357
3359
  * @example
3358
3360
  * ```typescript
@@ -1,2 +1,2 @@
1
- import{setFeatureResolver as o}from"@toolbox-web/grid";function e(o,e,t,n){console.warn(function(o,e,t,n){return`${function(o,e){return`[tbw-grid${o?`#${o}`:""}${e?`:${e}`:""}]`}(t,n)} ${o}: ${e}\n\n → More info: ${function(o){return`https://toolboxjs.com/grid/errors#${o.toLowerCase()}`}(o)}`}(o,e,t,n))}var t="3.9.1",n=Symbol.for(`@toolbox-web/grid:feature-registry@${t}/v1`),r=Symbol.for(`@toolbox-web/grid:feature-registry-warned@${t}/v1`);function i(o,e){let t=Reflect.get(globalThis,o);return void 0===t&&(t=e(),Reflect.set(globalThis,o,t)),t}var s=i(n,()=>/* @__PURE__ */new Map),c=i(r,()=>/* @__PURE__ */new Set),f=()=>"undefined"!=typeof window&&("localhost"===window.location?.hostname||"127.0.0.1"===window.location?.hostname);function a(o,t,n){f()&&s.has(o)&&!n?.override&&e("TBW030",`Feature "${o}" was re-registered. Previous registration overwritten.`),s.set(o,{factory:t,name:o})}function u(o){return s.has(o)}function d(o){return s.get(o)?.factory}function l(){return Array.from(s.keys())}var w={undoRedo:["editing"],clipboard:["selection"]};function g(o,t){const n=s.get(o);if(n)return n.factory(t);if(f()&&!c.has(o)){c.add(o);const t=o.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();e("TBW031",`Feature "${o}" is configured but not registered.\nAdd this import to enable it:\n\n import '@toolbox-web/grid/features/${t}';\n`)}}function b(o){const t=[];for(const[e,r]of Object.entries(o))void 0!==r&&!1!==r&&t.push(e);!function(o){const t=new Set(o);for(const n of o){const o=w[n];if(o)for(const r of o)t.has(r)||f()&&e("TBW032",`Feature "${n}" requires "${r}" to be enabled. Add "${r}" to your features configuration.`)}}(t);const n=[];for(const e of t){const t=g(e,o[e]);t&&n.push(t)}return function(o){if(o.length<2)return o;const e=/* @__PURE__ */new Map;for(const s of o)e.set(s.name,s);const t=[],n=/* @__PURE__ */new Set,r=/* @__PURE__ */new Set,i=o=>{if(n.has(o)||r.has(o))return;r.add(o);const s=o.constructor.dependencies??[];for(const t of s){const o=e.get(t.name);o&&i(o)}r.delete(o),n.add(o),t.push(o)};for(const s of o)i(s);return t}(n)}function $(){s.clear(),c.clear()}o(b);export{$ as clearFeatureRegistry,g as createPluginFromFeature,b as createPluginsFromFeatures,d as getFeatureFactory,l as getRegisteredFeatures,u as isFeatureRegistered,a as registerFeature};
1
+ import{setFeatureResolver as o}from"@toolbox-web/grid";function e(o,e,t,n){console.warn(function(o,e,t,n){return`${function(o,e){return`[tbw-grid${o?`#${o}`:""}${e?`:${e}`:""}]`}(t,n)} ${o}: ${e}\n\n → More info: ${function(o){return`https://toolboxjs.com/grid/errors#${o.toLowerCase()}`}(o)}`}(o,e,t,n))}var t="3.9.2",n=Symbol.for(`@toolbox-web/grid:feature-registry@${t}/v1`),r=Symbol.for(`@toolbox-web/grid:feature-registry-warned@${t}/v1`);function i(o,e){let t=Reflect.get(globalThis,o);return void 0===t&&(t=e(),Reflect.set(globalThis,o,t)),t}var s=i(n,()=>/* @__PURE__ */new Map),c=i(r,()=>/* @__PURE__ */new Set),f=()=>"undefined"!=typeof window&&("localhost"===window.location?.hostname||"127.0.0.1"===window.location?.hostname);function a(o,t,n){f()&&s.has(o)&&!n?.override&&e("TBW030",`Feature "${o}" was re-registered. Previous registration overwritten.`),s.set(o,{factory:t,name:o})}function u(o){return s.has(o)}function d(o){return s.get(o)?.factory}function l(){return Array.from(s.keys())}var w={undoRedo:["editing"],clipboard:["selection"]};function g(o,t){const n=s.get(o);if(n)return n.factory(t);if(f()&&!c.has(o)){c.add(o);const t=o.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();e("TBW031",`Feature "${o}" is configured but not registered.\nAdd this import to enable it:\n\n import '@toolbox-web/grid/features/${t}';\n`)}}function b(o){const t=[];for(const[e,r]of Object.entries(o))void 0!==r&&!1!==r&&t.push(e);!function(o){const t=new Set(o);for(const n of o){const o=w[n];if(o)for(const r of o)t.has(r)||f()&&e("TBW032",`Feature "${n}" requires "${r}" to be enabled. Add "${r}" to your features configuration.`)}}(t);const n=[];for(const e of t){const t=g(e,o[e]);t&&n.push(t)}return function(o){if(o.length<2)return o;const e=/* @__PURE__ */new Map;for(const s of o)e.set(s.name,s);const t=[],n=/* @__PURE__ */new Set,r=/* @__PURE__ */new Set,i=o=>{if(n.has(o)||r.has(o))return;r.add(o);const s=o.constructor.dependencies??[];for(const t of s){const o=e.get(t.name);o&&i(o)}r.delete(o),n.add(o),t.push(o)};for(const s of o)i(s);return t}(n)}function $(){s.clear(),c.clear()}o(b);export{$ as clearFeatureRegistry,g as createPluginFromFeature,b as createPluginsFromFeatures,d as getFeatureFactory,l as getRegisteredFeatures,u as isFeatureRegistered,a as registerFeature};
2
2
  //# sourceMappingURL=registry.js.map
@@ -127,11 +127,16 @@ export declare class ContextMenuPlugin extends BaseGridPlugin<ContextMenuConfig>
127
127
  /** @internal */
128
128
  detach(): void;
129
129
  /**
130
- * Sync selection with the right-clicked row.
131
- * If the right-clicked row is already selected, keeps the multi-selection.
132
- * If not, selects only the right-clicked row (standard behavior in file managers / spreadsheets).
130
+ * Sync the selection with the cell the menu was invoked on — identically for
131
+ * every invocation (mouse right-click, touch long-press, Shift+F10, the
132
+ * ContextMenu key, a synthesised `contextmenu`), since all of them land here.
133
133
  *
134
- * @returns Sorted array of selected row indices after sync
134
+ * `SelectionPlugin` keeps a selection the cell is already part of (so the menu
135
+ * acts on all of it) and otherwise moves the selection to that row/cell, in
136
+ * every selection mode. Queried rather than imported for loose coupling.
137
+ *
138
+ * @returns Sorted row indices the menu acts on — `[rowIndex]` when no selection
139
+ * plugin is loaded or the target could not be selected (e.g. `isSelectable`).
135
140
  */
136
141
  private syncSelectionOnContextMenu;
137
142
  /**
@@ -1,2 +1,2 @@
1
- import{BaseGridPlugin as e}from"@toolbox-web/grid";var t="__otorp__|__retteGenifed__|__retteSenifed__|rotcurtsnoc|wodniw|sihTlabolg|labolg|ssecorp|noitcnuF|tropmi|lave|tcelfeR|yxorP|rorrE|stnemugra|tnemucod|noitacol|eikooc|egarotSlacol|egarotSnoisses|BDdexedni|hctef|tseuqeRpttHLMX|tekcoSbeW|rekroW|rekroWderahS|rekroWecivreS|renepo|tnerap|pot|semarf|fles".split("|").map(e=>e.split("").reverse().join("")),n=(new RegExp(`__(proto|defineGetter|defineSetter)|${t.slice(3).join("|")}|this\\b`),new Set("script|iframe|object|embed|form|input|button|textarea|select|link|meta|base|style|template|slot|portal|frame|frameset|applet|noscript|noembed|plaintext|xmp|listing|math".split("|"))),o=/^on\w+$/i,s=new Set("href|src|action|formaction|data|srcdoc|xlink:href|poster|srcset".split("|")),r=/^\s*(javascript|vbscript|data|blob):/i;function i(e){const t=document.createElement("template");return e&&"string"==typeof e&&(t.innerHTML=e,function(e){const t=[],i=e.querySelectorAll("*");for(const a of i){const e=a.tagName.toLowerCase();if(n.has(e)){t.push(a);continue}if(("svg"===e||"http://www.w3.org/2000/svg"===a.namespaceURI)&&Array.from(a.attributes).some(e=>o.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(a);continue}const i=[];for(const t of a.attributes){const e=t.name.toLowerCase();o.test(e)?i.push(t.name):"is"!==e?(s.has(e)&&r.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&i.push(t.name):i.push(t.name)}i.forEach(e=>a.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content)),t.content}function a(e,t){t&&"string"==typeof t?-1!==t.indexOf("<")||-1!==t.indexOf("&")?e.replaceChildren(i(t)):e.textContent=t:e.replaceChildren()}function l(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}function c(e,t){return("function"==typeof e?e(t):e).filter(e=>!0!==e.hidden&&("function"!=typeof e.hidden||!e.hidden(t)))}function u(e,t){return!0===e.disabled||"function"==typeof e.disabled&&e.disabled(t)}function d(e,t,n,o){const s=document.createElement("div");s.className="tbw-context-menu",s.setAttribute("role","menu");const r=e.some(e=>!e.separator&&e.icon);for(const i of e){if(i.separator){const e=document.createElement("div");e.className="tbw-context-menu-separator",e.setAttribute("role","separator"),s.appendChild(e);continue}const e=document.createElement("div");e.className="tbw-context-menu-item",i.cssClass&&e.classList.add(i.cssClass),e.setAttribute("role","menuitem"),e.setAttribute("data-id",i.id),e.setAttribute("tabindex","-1");const m=u(i,t);if(m&&(e.classList.add("disabled"),e.setAttribute("aria-disabled","true")),i.icon){const t=document.createElement("span");t.className="tbw-context-menu-icon",a(t,i.icon),e.appendChild(t)}else if(r){const t=document.createElement("span");t.className="tbw-context-menu-icon",t.innerHTML="&nbsp;",e.appendChild(t)}const p=document.createElement("span");if(p.className="tbw-context-menu-label",p.textContent=i.name,e.appendChild(p),i.shortcut){const t=document.createElement("span");if(t.className="tbw-context-menu-shortcut",Array.isArray(i.shortcut))i.shortcut.forEach((e,n)=>{n>0&&t.appendChild(document.createTextNode("+"));const o=document.createElement("kbd");o.textContent=e,t.appendChild(o)});else{const e=document.createElement("kbd");e.textContent=i.shortcut,t.appendChild(e)}e.appendChild(t)}if(i.subMenu?.length){const s=document.createElement("span");s.className="tbw-context-menu-arrow",s.dataset.icon=l("submenuArrow"),void 0!==o&&("string"==typeof o?a(s,o):o instanceof HTMLElement&&s.appendChild(o.cloneNode(!0))),e.appendChild(s),e.addEventListener("mouseenter",()=>{if(e.querySelector(".tbw-context-menu"))return;if(!i.subMenu)return;const s=d(c(i.subMenu,t),t,n,o);s.classList.add("tbw-context-submenu"),s.style.position="absolute",s.style.left="100%",s.style.top="0",e.style.position="relative",e.appendChild(s)}),e.addEventListener("mouseleave",()=>{const t=e.querySelector(".tbw-context-menu");t&&t.remove()})}m||!i.action||i.subMenu||e.addEventListener("click",e=>{e.stopPropagation(),n(i)}),s.appendChild(e)}return s}var m="getContextMenuItems",p=null,b=null,h=0,w=/* @__PURE__ */new Set,f=[{id:"copy",name:"Copy",shortcut:"Ctrl+C",action:e=>{e.grid?.query?.("clipboard:copy")}},{separator:!0,id:"sep1",name:""},{id:"export-csv",name:"Export CSV",action:e=>{e.grid?.query?.("export:csv")}}],x=class t extends e{static manifest={queries:[{type:m,description:"Collects context menu items from other plugins for header right-click menus"}]};name="contextMenu";get defaultConfig(){return{items:f}}isOpen=!1;position={x:0,y:0};params=null;menuElement=null;boundHost=null;attach(e){super.attach(e),this.installGlobalHandlers(),h++,w.add(this)}detach(){this.menuElement&&(this.menuElement.remove(),this.menuElement=null),this.isOpen=!1,this.params=null,this.boundHost=null,w.delete(this),this.uninstallGlobalHandlers()}syncSelectionOnContextMenu(e){if(e<0)return[];const t=(this.grid?.query("getSelectedRowIndices"))?.[0];return t?t.includes(e)?t:(this.grid?.query("selectRows",[e]),[e]):[e]}static CSS_VARS_TO_COPY=["--tbw-color-panel-bg","--tbw-color-fg","--tbw-color-fg-muted","--tbw-color-border","--tbw-color-row-hover","--tbw-color-shadow","--tbw-color-danger","--tbw-border-radius","--tbw-font-family","--tbw-font-size-sm","--tbw-font-size-xs","--tbw-font-size-2xs","--tbw-spacing-xs","--tbw-icon-size","--tbw-menu-min-width","--tbw-menu-item-padding","--tbw-menu-item-gap","--tbw-context-menu-bg","--tbw-context-menu-fg","--tbw-context-menu-border","--tbw-context-menu-radius","--tbw-context-menu-shadow","--tbw-context-menu-hover","--tbw-context-menu-danger","--tbw-context-menu-muted","--tbw-context-menu-min-width","--tbw-context-menu-font-size","--tbw-context-menu-font-family","--tbw-context-menu-item-padding","--tbw-context-menu-item-gap","--tbw-context-menu-icon-size","--tbw-context-menu-shortcut-size","--tbw-context-menu-arrow-size","--tbw-icon-submenu-arrow"];copyGridStyles(e){const n=this.gridElement;if(!n)return;const o=getComputedStyle(n),s=[],r=o.getPropertyValue("color-scheme").trim();r&&s.push(`color-scheme: ${r}`);for(const i of t.CSS_VARS_TO_COPY){const e=o.getPropertyValue(i).trim();e&&s.push(`${i}: ${e}`)}if(s.length>0){const t=e.getAttribute("style")||"";e.setAttribute("style",t+s.join("; ")+";")}}installGlobalHandlers(){if(b||"undefined"==typeof document||((b=document.createElement("style")).id="tbw-context-menu-styles",b.textContent="@layer tbw-plugins{.tbw-context-menu{background:var(--tbw-context-menu-bg,var(--tbw-color-panel-bg));color:var(--tbw-context-menu-fg,var(--tbw-color-fg));border:1px solid var(--tbw-context-menu-border,var(--tbw-color-border));border-radius:var(--tbw-context-menu-radius,var(--tbw-border-radius));box-shadow:var(--tbw-context-menu-shadow,0 2px 10px var(--tbw-color-shadow));min-width:var(--tbw-context-menu-min-width,var(--tbw-menu-min-width));padding:var(--tbw-spacing-xs) 0;z-index:10000;font-size:var(--tbw-context-menu-font-size,var(--tbw-font-size-sm));font-family:var(--tbw-context-menu-font-family,var(--tbw-font-family));position:fixed}.tbw-context-menu-item{padding:var(--tbw-context-menu-item-padding,var(--tbw-menu-item-padding));cursor:pointer;align-items:center;gap:var(--tbw-context-menu-item-gap,var(--tbw-menu-item-gap));display:flex}.tbw-context-menu-item:hover:not(.disabled){background:var(--tbw-context-menu-hover,var(--tbw-color-row-hover))}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:var(--tbw-context-menu-danger,var(--tbw-color-danger))}.tbw-context-menu-icon{width:var(--tbw-context-menu-icon-size,var(--tbw-icon-size));text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut kbd{color:var(--tbw-context-menu-muted,var(--tbw-color-fg-muted));font-size:var(--tbw-context-menu-shortcut-size,var(--tbw-font-size-xs))}.tbw-context-menu-arrow{font-size:var(--tbw-context-menu-arrow-size,var(--tbw-font-size-2xs));color:var(--tbw-context-menu-muted,var(--tbw-color-fg-muted))}.tbw-context-menu-separator{background:var(--tbw-context-menu-border,var(--tbw-color-border));height:1px;margin:var(--tbw-spacing-xs) 0}}",document.head.appendChild(b)),!p){const e=(p=new AbortController).signal,t=()=>{for(const e of w)e.isMenuOpen()&&e.hideMenu();document.querySelectorAll(".tbw-context-menu").forEach(e=>e.remove())};document.addEventListener("click",t,{signal:e}),document.addEventListener("keydown",e=>{"Escape"===e.key&&t()},{signal:e}),document.addEventListener("scroll",t,{capture:!0,signal:e})}}uninstallGlobalHandlers(){--h>0||(p&&(p.abort(),p=null),b&&(b.remove(),b=null))}collectPluginItems(e){if(!this.grid)return[];const t=this.grid.query(m,e),n=[];for(const o of t)Array.isArray(o)&&n.push(...o);return n.sort((e,t)=>(e.order??100)-(t.order??100)),this.insertGroupSeparators(n)}insertGroupSeparators(e){if(e.length<=1)return e;const t=[];let n=-1;for(const o of e){if(o.separator){t.push(o);continue}const e=Math.floor((o.order??100)/10);n>=0&&e!==n&&t.push({id:`__sep-${n}-${e}`,label:"",separator:!0,action:()=>{}}),n=e,t.push(o)}return t}convertPluginItems(e){return e.map(e=>({id:e.id,name:e.label,icon:e.icon,shortcut:e.shortcut,disabled:e.disabled??!1,action:()=>e.action(),separator:e.separator,cssClass:e.cssClass}))}openMenuAt(e,t,n,o=!1){this.params=e,this.position={x:t,y:n};const s=this.collectPluginItems(e);let r=c(this.config.items??f,e);if(s.length>0){const e=this.convertPluginItems(s);r=r.length>0&&e.length>0?[...r,{id:"__plugin-sep",name:"",separator:!0},...e]:[...r,...e]}var i,a;(r=function(e){const t=[];for(const n of e)n.separator&&(0===t.length||t[t.length-1].separator)||t.push(n);return t.length>0&&t[t.length-1].separator&&t.pop(),t}(r),r.length)&&(document.querySelectorAll(".tbw-context-menu").forEach(e=>e.remove()),this.menuElement=null,this.menuElement=d(r,e,t=>{t.action&&t.action(e),this.hideMenu()},this.grid?.gridConfig?.icons?.submenuArrow),i=this.menuElement,a=()=>this.hideMenu(),i.addEventListener("keydown",e=>{const t=Array.from(i.querySelectorAll('[role="menuitem"]:not(.disabled)'));if(!t.length)return;const n=document.activeElement,o=t.indexOf(n);switch(e.key){case"ArrowDown":e.preventDefault(),t[o<t.length-1?o+1:0].focus();break;case"ArrowUp":e.preventDefault(),t[o>0?o-1:t.length-1].focus();break;case"Enter":case" ":e.preventDefault(),n&&t.includes(n)&&n.click();break;case"Escape":e.preventDefault(),a()}}),document.body.appendChild(this.menuElement),this.copyGridStyles(this.menuElement),function(e,t,n){e.style.position="fixed",e.style.left=`${t}px`,e.style.top=`${n}px`,e.style.visibility="hidden",e.style.zIndex="10000";const o=e.getBoundingClientRect(),s=window.innerWidth,r=window.innerHeight;let i=t,a=n;t+o.width>s&&(i=t-o.width),n+o.height>r&&(a=n-o.height),i=Math.max(0,i),a=Math.max(0,a),e.style.left=`${i}px`,e.style.top=`${a}px`,e.style.visibility="visible"}(this.menuElement,t,n),this.isOpen=!0,o&&function(e){e.querySelector('[role="menuitem"]:not(.disabled)')?.focus()}(this.menuElement),this.emit("context-menu-open",{params:e,items:r}))}openMenuAtFocusedCell(e){const t=this.grid;if(!t)return!1;const n=t._focusRow,o=t._focusCol;if(n<0||o<0)return!1;const s=this.visibleColumns[o],r=this.rows[n],i=this.gridElement?.querySelector(`[data-row="${n}"][data-col="${o}"]`);if(!i&&!0===r?.__loading)return!1;let a=0,l=0;if(i){const e=i.getBoundingClientRect();a=e.left+e.width/2,l=e.bottom}const c=this.syncSelectionOnContextMenu(n);return this.openMenuAt({row:r,rowIndex:n,column:s,columnIndex:o,field:s?.field??"",value:r?.[s?.field]??null,isHeader:!1,event:e,selectedRows:c},a,l,!0),!0}handleContextMenu=e=>{const t=e;t.preventDefault();const n=t.target,o=n?.closest("[data-row][data-col]"),s=n?.closest('[part~="header-cell"]');let r;if(o){const e=parseInt(o.getAttribute("data-row")??"-1",10),n=parseInt(o.getAttribute("data-col")??"-1",10),s=this.visibleColumns[n],i=this.rows[e],a=this.syncSelectionOnContextMenu(e);r={row:i,rowIndex:e,column:s,columnIndex:n,field:s?.field??"",value:i?.[s?.field]??null,isHeader:!1,event:t,selectedRows:a}}else{if(!s)return void(-1===t.button&&t.target===this.boundHost&&this.openMenuAtFocusedCell(t));{const e=parseInt(s.getAttribute("data-col")??"-1",10),n=this.visibleColumns[e];r={row:null,rowIndex:-1,column:n,columnIndex:e,field:n?.field??"",value:null,isHeader:!0,event:t,selectedRows:[]}}}this.openMenuAt(r,t.clientX,t.clientY)};afterRender(){const e=this.gridElement;e&&this.boundHost!==e&&(this.boundHost=e,e.addEventListener("contextmenu",this.handleContextMenu,{signal:this.disconnectSignal}))}onKeyDown(e){const t="F10"===e.key&&e.shiftKey,n="ContextMenu"===e.key;if((t||n)&&(e.preventDefault(),this.openMenuAtFocusedCell(e)))return!0}showMenu(e,t,n){const o={row:n.row??null,rowIndex:n.rowIndex??-1,column:n.column??null,columnIndex:n.columnIndex??-1,field:n.field??"",value:n.value??null,isHeader:n.isHeader??!1,event:n.event??new MouseEvent("contextmenu"),selectedRows:n.selectedRows??[]};this.openMenuAt(o,e,t)}hideMenu(){this.menuElement&&(this.menuElement.remove(),this.menuElement=null),this.isOpen&&(this.isOpen=!1)}isMenuOpen(){return this.isOpen}};export{x as ContextMenuPlugin};
1
+ import{BaseGridPlugin as e}from"@toolbox-web/grid";var t="__otorp__|__retteGenifed__|__retteSenifed__|rotcurtsnoc|wodniw|sihTlabolg|labolg|ssecorp|noitcnuF|tropmi|lave|tcelfeR|yxorP|rorrE|stnemugra|tnemucod|noitacol|eikooc|egarotSlacol|egarotSnoisses|BDdexedni|hctef|tseuqeRpttHLMX|tekcoSbeW|rekroW|rekroWderahS|rekroWecivreS|renepo|tnerap|pot|semarf|fles".split("|").map(e=>e.split("").reverse().join("")),n=(new RegExp(`__(proto|defineGetter|defineSetter)|${t.slice(3).join("|")}|this\\b`),new Set("script|iframe|object|embed|form|input|button|textarea|select|link|meta|base|style|template|slot|portal|frame|frameset|applet|noscript|noembed|plaintext|xmp|listing|math".split("|"))),o=/^on\w+$/i,s=new Set("href|src|action|formaction|data|srcdoc|xlink:href|poster|srcset".split("|")),r=/^\s*(javascript|vbscript|data|blob):/i;function i(e){const t=document.createElement("template");return e&&"string"==typeof e&&(t.innerHTML=e,function(e){const t=[],i=e.querySelectorAll("*");for(const a of i){const e=a.tagName.toLowerCase();if(n.has(e)){t.push(a);continue}if(("svg"===e||"http://www.w3.org/2000/svg"===a.namespaceURI)&&Array.from(a.attributes).some(e=>o.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(a);continue}const i=[];for(const t of a.attributes){const e=t.name.toLowerCase();o.test(e)?i.push(t.name):"is"!==e?(s.has(e)&&r.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&i.push(t.name):i.push(t.name)}i.forEach(e=>a.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content)),t.content}function a(e,t){t&&"string"==typeof t?-1!==t.indexOf("<")||-1!==t.indexOf("&")?e.replaceChildren(i(t)):e.textContent=t:e.replaceChildren()}function l(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}function c(e,t){return("function"==typeof e?e(t):e).filter(e=>!0!==e.hidden&&("function"!=typeof e.hidden||!e.hidden(t)))}function u(e,t){return!0===e.disabled||"function"==typeof e.disabled&&e.disabled(t)}function d(e,t,n,o){const s=document.createElement("div");s.className="tbw-context-menu",s.setAttribute("role","menu");const r=e.some(e=>!e.separator&&e.icon);for(const i of e){if(i.separator){const e=document.createElement("div");e.className="tbw-context-menu-separator",e.setAttribute("role","separator"),s.appendChild(e);continue}const e=document.createElement("div");e.className="tbw-context-menu-item",i.cssClass&&e.classList.add(i.cssClass),e.setAttribute("role","menuitem"),e.setAttribute("data-id",i.id),e.setAttribute("tabindex","-1");const m=u(i,t);if(m&&(e.classList.add("disabled"),e.setAttribute("aria-disabled","true")),i.icon){const t=document.createElement("span");t.className="tbw-context-menu-icon",a(t,i.icon),e.appendChild(t)}else if(r){const t=document.createElement("span");t.className="tbw-context-menu-icon",t.innerHTML="&nbsp;",e.appendChild(t)}const p=document.createElement("span");if(p.className="tbw-context-menu-label",p.textContent=i.name,e.appendChild(p),i.shortcut){const t=document.createElement("span");if(t.className="tbw-context-menu-shortcut",Array.isArray(i.shortcut))i.shortcut.forEach((e,n)=>{n>0&&t.appendChild(document.createTextNode("+"));const o=document.createElement("kbd");o.textContent=e,t.appendChild(o)});else{const e=document.createElement("kbd");e.textContent=i.shortcut,t.appendChild(e)}e.appendChild(t)}if(i.subMenu?.length){const s=document.createElement("span");s.className="tbw-context-menu-arrow",s.dataset.icon=l("submenuArrow"),void 0!==o&&("string"==typeof o?a(s,o):o instanceof HTMLElement&&s.appendChild(o.cloneNode(!0))),e.appendChild(s),e.addEventListener("mouseenter",()=>{if(e.querySelector(".tbw-context-menu"))return;if(!i.subMenu)return;const s=d(c(i.subMenu,t),t,n,o);s.classList.add("tbw-context-submenu"),s.style.position="absolute",s.style.left="100%",s.style.top="0",e.style.position="relative",e.appendChild(s)}),e.addEventListener("mouseleave",()=>{const t=e.querySelector(".tbw-context-menu");t&&t.remove()})}m||!i.action||i.subMenu||e.addEventListener("click",e=>{e.stopPropagation(),n(i)}),s.appendChild(e)}return s}var m="getContextMenuItems",p=null,b=null,h=0,w=/* @__PURE__ */new Set,f=[{id:"copy",name:"Copy",shortcut:"Ctrl+C",action:e=>{e.grid?.query?.("clipboard:copy")}},{separator:!0,id:"sep1",name:""},{id:"export-csv",name:"Export CSV",action:e=>{e.grid?.query?.("export:csv")}}],x=class t extends e{static manifest={queries:[{type:m,description:"Collects context menu items from other plugins for header right-click menus"}]};name="contextMenu";get defaultConfig(){return{items:f}}isOpen=!1;position={x:0,y:0};params=null;menuElement=null;boundHost=null;attach(e){super.attach(e),this.installGlobalHandlers(),h++,w.add(this)}detach(){this.menuElement&&(this.menuElement.remove(),this.menuElement=null),this.isOpen=!1,this.params=null,this.boundHost=null,w.delete(this),this.uninstallGlobalHandlers()}syncSelectionOnContextMenu(e,t){if(e<0)return[];const n=this.grid?.query("selectContextMenuTarget",{rowIndex:e,colIndex:t})?.[0];return n?.includes(e)?n:[e]}static CSS_VARS_TO_COPY=["--tbw-color-panel-bg","--tbw-color-fg","--tbw-color-fg-muted","--tbw-color-border","--tbw-color-row-hover","--tbw-color-shadow","--tbw-color-danger","--tbw-border-radius","--tbw-font-family","--tbw-font-size-sm","--tbw-font-size-xs","--tbw-font-size-2xs","--tbw-spacing-xs","--tbw-icon-size","--tbw-menu-min-width","--tbw-menu-item-padding","--tbw-menu-item-gap","--tbw-context-menu-bg","--tbw-context-menu-fg","--tbw-context-menu-border","--tbw-context-menu-radius","--tbw-context-menu-shadow","--tbw-context-menu-hover","--tbw-context-menu-danger","--tbw-context-menu-muted","--tbw-context-menu-min-width","--tbw-context-menu-font-size","--tbw-context-menu-font-family","--tbw-context-menu-item-padding","--tbw-context-menu-item-gap","--tbw-context-menu-icon-size","--tbw-context-menu-shortcut-size","--tbw-context-menu-arrow-size","--tbw-icon-submenu-arrow"];copyGridStyles(e){const n=this.gridElement;if(!n)return;const o=getComputedStyle(n),s=[],r=o.getPropertyValue("color-scheme").trim();r&&s.push(`color-scheme: ${r}`);for(const i of t.CSS_VARS_TO_COPY){const e=o.getPropertyValue(i).trim();e&&s.push(`${i}: ${e}`)}if(s.length>0){const t=e.getAttribute("style")||"";e.setAttribute("style",t+s.join("; ")+";")}}installGlobalHandlers(){if(b||"undefined"==typeof document||((b=document.createElement("style")).id="tbw-context-menu-styles",b.textContent="@layer tbw-plugins{.tbw-context-menu{background:var(--tbw-context-menu-bg,var(--tbw-color-panel-bg));color:var(--tbw-context-menu-fg,var(--tbw-color-fg));border:1px solid var(--tbw-context-menu-border,var(--tbw-color-border));border-radius:var(--tbw-context-menu-radius,var(--tbw-border-radius));box-shadow:var(--tbw-context-menu-shadow,0 2px 10px var(--tbw-color-shadow));min-width:var(--tbw-context-menu-min-width,var(--tbw-menu-min-width));padding:var(--tbw-spacing-xs) 0;z-index:10000;font-size:var(--tbw-context-menu-font-size,var(--tbw-font-size-sm));font-family:var(--tbw-context-menu-font-family,var(--tbw-font-family));position:fixed}.tbw-context-menu-item{padding:var(--tbw-context-menu-item-padding,var(--tbw-menu-item-padding));cursor:pointer;align-items:center;gap:var(--tbw-context-menu-item-gap,var(--tbw-menu-item-gap));display:flex}.tbw-context-menu-item:hover:not(.disabled){background:var(--tbw-context-menu-hover,var(--tbw-color-row-hover))}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:var(--tbw-context-menu-danger,var(--tbw-color-danger))}.tbw-context-menu-icon{width:var(--tbw-context-menu-icon-size,var(--tbw-icon-size));text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut kbd{color:var(--tbw-context-menu-muted,var(--tbw-color-fg-muted));font-size:var(--tbw-context-menu-shortcut-size,var(--tbw-font-size-xs))}.tbw-context-menu-arrow{font-size:var(--tbw-context-menu-arrow-size,var(--tbw-font-size-2xs));color:var(--tbw-context-menu-muted,var(--tbw-color-fg-muted))}.tbw-context-menu-separator{background:var(--tbw-context-menu-border,var(--tbw-color-border));height:1px;margin:var(--tbw-spacing-xs) 0}}",document.head.appendChild(b)),!p){const e=(p=new AbortController).signal,t=()=>{for(const e of w)e.isMenuOpen()&&e.hideMenu();document.querySelectorAll(".tbw-context-menu").forEach(e=>e.remove())};document.addEventListener("click",t,{signal:e}),document.addEventListener("keydown",e=>{"Escape"===e.key&&t()},{signal:e}),document.addEventListener("scroll",t,{capture:!0,signal:e})}}uninstallGlobalHandlers(){--h>0||(p&&(p.abort(),p=null),b&&(b.remove(),b=null))}collectPluginItems(e){if(!this.grid)return[];const t=this.grid.query(m,e),n=[];for(const o of t)Array.isArray(o)&&n.push(...o);return n.sort((e,t)=>(e.order??100)-(t.order??100)),this.insertGroupSeparators(n)}insertGroupSeparators(e){if(e.length<=1)return e;const t=[];let n=-1;for(const o of e){if(o.separator){t.push(o);continue}const e=Math.floor((o.order??100)/10);n>=0&&e!==n&&t.push({id:`__sep-${n}-${e}`,label:"",separator:!0,action:()=>{}}),n=e,t.push(o)}return t}convertPluginItems(e){return e.map(e=>({id:e.id,name:e.label,icon:e.icon,shortcut:e.shortcut,disabled:e.disabled??!1,action:()=>e.action(),separator:e.separator,cssClass:e.cssClass}))}openMenuAt(e,t,n,o=!1){this.params=e,this.position={x:t,y:n};const s=this.collectPluginItems(e);let r=c(this.config.items??f,e);if(s.length>0){const e=this.convertPluginItems(s);r=r.length>0&&e.length>0?[...r,{id:"__plugin-sep",name:"",separator:!0},...e]:[...r,...e]}var i,a;(r=function(e){const t=[];for(const n of e)n.separator&&(0===t.length||t[t.length-1].separator)||t.push(n);return t.length>0&&t[t.length-1].separator&&t.pop(),t}(r),r.length)&&(document.querySelectorAll(".tbw-context-menu").forEach(e=>e.remove()),this.menuElement=null,this.menuElement=d(r,e,t=>{t.action&&t.action(e),this.hideMenu()},this.grid?.gridConfig?.icons?.submenuArrow),i=this.menuElement,a=()=>this.hideMenu(),i.addEventListener("keydown",e=>{const t=Array.from(i.querySelectorAll('[role="menuitem"]:not(.disabled)'));if(!t.length)return;const n=document.activeElement,o=t.indexOf(n);switch(e.key){case"ArrowDown":e.preventDefault(),t[o<t.length-1?o+1:0].focus();break;case"ArrowUp":e.preventDefault(),t[o>0?o-1:t.length-1].focus();break;case"Enter":case" ":e.preventDefault(),n&&t.includes(n)&&n.click();break;case"Escape":e.preventDefault(),a()}}),document.body.appendChild(this.menuElement),this.copyGridStyles(this.menuElement),function(e,t,n){e.style.position="fixed",e.style.left=`${t}px`,e.style.top=`${n}px`,e.style.visibility="hidden",e.style.zIndex="10000";const o=e.getBoundingClientRect(),s=window.innerWidth,r=window.innerHeight;let i=t,a=n;t+o.width>s&&(i=t-o.width),n+o.height>r&&(a=n-o.height),i=Math.max(0,i),a=Math.max(0,a),e.style.left=`${i}px`,e.style.top=`${a}px`,e.style.visibility="visible"}(this.menuElement,t,n),this.isOpen=!0,o&&function(e){e.querySelector('[role="menuitem"]:not(.disabled)')?.focus()}(this.menuElement),this.emit("context-menu-open",{params:e,items:r}))}openMenuAtFocusedCell(e){const t=this.grid;if(!t)return!1;const n=t._focusRow,o=t._focusCol;if(n<0||o<0)return!1;const s=this.visibleColumns[o],r=this.rows[n],i=this.gridElement?.querySelector(`[data-row="${n}"][data-col="${o}"]`);if(!i&&!0===r?.__loading)return!1;let a=0,l=0;if(i){const e=i.getBoundingClientRect();a=e.left+e.width/2,l=e.bottom}const c=this.syncSelectionOnContextMenu(n,o);return this.openMenuAt({row:r,rowIndex:n,column:s,columnIndex:o,field:s?.field??"",value:r?.[s?.field]??null,isHeader:!1,event:e,selectedRows:c},a,l,!0),!0}handleContextMenu=e=>{const t=e;t.preventDefault();const n=t.target,o=n?.closest("[data-row][data-col]"),s=n?.closest('[part~="header-cell"]');let r;if(o){const e=parseInt(o.getAttribute("data-row")??"-1",10),n=parseInt(o.getAttribute("data-col")??"-1",10),s=this.visibleColumns[n],i=this.rows[e],a=this.syncSelectionOnContextMenu(e,n);r={row:i,rowIndex:e,column:s,columnIndex:n,field:s?.field??"",value:i?.[s?.field]??null,isHeader:!1,event:t,selectedRows:a}}else{if(!s)return void(-1===t.button&&t.target===this.boundHost&&this.openMenuAtFocusedCell(t));{const e=parseInt(s.getAttribute("data-col")??"-1",10),n=this.visibleColumns[e];r={row:null,rowIndex:-1,column:n,columnIndex:e,field:n?.field??"",value:null,isHeader:!0,event:t,selectedRows:[]}}}this.openMenuAt(r,t.clientX,t.clientY)};afterRender(){const e=this.gridElement;e&&this.boundHost!==e&&(this.boundHost=e,e.addEventListener("contextmenu",this.handleContextMenu,{signal:this.disconnectSignal}))}onKeyDown(e){const t="F10"===e.key&&e.shiftKey,n="ContextMenu"===e.key;if((t||n)&&(e.preventDefault(),this.openMenuAtFocusedCell(e)))return!0}showMenu(e,t,n){const o={row:n.row??null,rowIndex:n.rowIndex??-1,column:n.column??null,columnIndex:n.columnIndex??-1,field:n.field??"",value:n.value??null,isHeader:n.isHeader??!1,event:n.event??new MouseEvent("contextmenu"),selectedRows:n.selectedRows??[]};this.openMenuAt(o,e,t)}hideMenu(){this.menuElement&&(this.menuElement.remove(),this.menuElement=null),this.isOpen&&(this.isOpen=!1)}isMenuOpen(){return this.isOpen}};export{x as ContextMenuPlugin};
2
2
  //# sourceMappingURL=index.js.map