@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.
- package/all.js +1 -1
- package/all.js.map +1 -1
- package/custom-elements.json +2 -2
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/lib/core/grid.d.ts +8 -4
- package/lib/core/plugin/base-plugin.d.ts +7 -0
- package/lib/core/types.d.ts +2 -0
- package/lib/features/registry.js +1 -1
- package/lib/plugins/context-menu/context-menu-plugin.d.ts +9 -4
- package/lib/plugins/context-menu/index.js +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/context-menu/types.d.ts +8 -4
- package/lib/plugins/editing/index.js +1 -1
- package/lib/plugins/editing/index.js.map +1 -1
- package/lib/plugins/editing/internal/dirty-tracking-manager.d.ts +2 -1
- package/lib/plugins/filtering/filter-model.d.ts +2 -1
- package/lib/plugins/filtering/filtering-plugin.d.ts +5 -2
- package/lib/plugins/filtering/index.js +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-rows/grouping-rows-plugin.d.ts +7 -14
- package/lib/plugins/grouping-rows/grouping-rows.d.ts +48 -0
- package/lib/plugins/grouping-rows/index.d.ts +1 -1
- package/lib/plugins/grouping-rows/index.js +1 -1
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/grouping-rows/types.d.ts +21 -0
- package/lib/plugins/master-detail/index.d.ts +1 -1
- package/lib/plugins/master-detail/index.js +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/master-detail/master-detail-plugin.d.ts +28 -6
- package/lib/plugins/master-detail/master-detail.d.ts +0 -8
- package/lib/plugins/master-detail/types.d.ts +25 -1
- package/lib/plugins/multi-sort/index.js +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/selection/index.js +1 -1
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/selection/selection-plugin.d.ts +8 -1
- package/lib/plugins/server-side/datasource-types.d.ts +28 -0
- package/lib/plugins/server-side/datasource.d.ts +7 -0
- package/lib/plugins/server-side/index.js +1 -1
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/server-side/server-side-plugin.d.ts +61 -8
- package/lib/plugins/server-side/types.d.ts +9 -1
- package/lib/plugins/tree/index.js +1 -1
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/tree/tree-plugin.d.ts +5 -11
- package/lib/plugins/tree/types.d.ts +22 -6
- package/lib/plugins/undo-redo/history.d.ts +2 -1
- package/lib/plugins/undo-redo/index.js +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/undo-redo/types.d.ts +13 -1
- package/lib/plugins/undo-redo/undo-redo-plugin.d.ts +15 -2
- package/package.json +1 -1
- package/umd/grid.all.umd.js +1 -1
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +1 -1
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/context-menu.umd.js +1 -1
- package/umd/plugins/context-menu.umd.js.map +1 -1
- package/umd/plugins/editing.umd.js +1 -1
- package/umd/plugins/editing.umd.js.map +1 -1
- package/umd/plugins/filtering.umd.js +1 -1
- package/umd/plugins/filtering.umd.js.map +1 -1
- package/umd/plugins/grouping-rows.umd.js +1 -1
- package/umd/plugins/grouping-rows.umd.js.map +1 -1
- package/umd/plugins/master-detail.umd.js +1 -1
- package/umd/plugins/master-detail.umd.js.map +1 -1
- package/umd/plugins/multi-sort.umd.js +1 -1
- package/umd/plugins/multi-sort.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js +1 -1
- package/umd/plugins/selection.umd.js.map +1 -1
- package/umd/plugins/server-side.umd.js +1 -1
- package/umd/plugins/server-side.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js +1 -1
- package/umd/plugins/tree.umd.js.map +1 -1
- package/umd/plugins/undo-redo.umd.js +1 -1
- package/umd/plugins/undo-redo.umd.js.map +1 -1
package/lib/core/grid.d.ts
CHANGED
|
@@ -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
|
|
932
|
-
* without aborting the rest of the batch
|
|
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.
|
package/lib/core/types.d.ts
CHANGED
|
@@ -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
|
package/lib/features/registry.js
CHANGED
|
@@ -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
|
+
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
|
|
131
|
-
*
|
|
132
|
-
*
|
|
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
|
-
*
|
|
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=" ",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=" ",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
|