@toolbox-web/grid 2.1.1 → 2.2.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 (61) hide show
  1. package/all.js +2 -2
  2. package/all.js.map +1 -1
  3. package/index.js +1 -1
  4. package/index.js.map +1 -1
  5. package/lib/core/constants.d.ts +18 -0
  6. package/lib/core/internal/value-accessor.d.ts +33 -0
  7. package/lib/core/types.d.ts +114 -0
  8. package/lib/plugins/clipboard/index.js +1 -1
  9. package/lib/plugins/clipboard/index.js.map +1 -1
  10. package/lib/plugins/column-virtualization/index.js.map +1 -1
  11. package/lib/plugins/context-menu/index.js.map +1 -1
  12. package/lib/plugins/editing/index.js +1 -1
  13. package/lib/plugins/editing/index.js.map +1 -1
  14. package/lib/plugins/export/index.js +1 -1
  15. package/lib/plugins/export/index.js.map +1 -1
  16. package/lib/plugins/filtering/FilteringPlugin.d.ts +19 -1
  17. package/lib/plugins/filtering/index.js +1 -1
  18. package/lib/plugins/filtering/index.js.map +1 -1
  19. package/lib/plugins/grouping-columns/index.js.map +1 -1
  20. package/lib/plugins/grouping-rows/index.js +2 -2
  21. package/lib/plugins/grouping-rows/index.js.map +1 -1
  22. package/lib/plugins/master-detail/index.js.map +1 -1
  23. package/lib/plugins/multi-sort/index.js +1 -1
  24. package/lib/plugins/multi-sort/index.js.map +1 -1
  25. package/lib/plugins/pinned-columns/index.js.map +1 -1
  26. package/lib/plugins/pinned-rows/index.js +1 -1
  27. package/lib/plugins/pinned-rows/index.js.map +1 -1
  28. package/lib/plugins/pivot/index.js.map +1 -1
  29. package/lib/plugins/print/index.js.map +1 -1
  30. package/lib/plugins/reorder-columns/index.js.map +1 -1
  31. package/lib/plugins/reorder-rows/index.js.map +1 -1
  32. package/lib/plugins/responsive/index.js.map +1 -1
  33. package/lib/plugins/selection/index.js.map +1 -1
  34. package/lib/plugins/server-side/ServerSidePlugin.d.ts +4 -0
  35. package/lib/plugins/server-side/index.js +1 -1
  36. package/lib/plugins/server-side/index.js.map +1 -1
  37. package/lib/plugins/server-side/types.d.ts +48 -0
  38. package/lib/plugins/tooltip/index.js.map +1 -1
  39. package/lib/plugins/tree/index.js.map +1 -1
  40. package/lib/plugins/undo-redo/index.js.map +1 -1
  41. package/lib/plugins/visibility/index.js.map +1 -1
  42. package/package.json +1 -1
  43. package/public.d.ts +4 -1
  44. package/umd/grid.all.umd.js +1 -1
  45. package/umd/grid.all.umd.js.map +1 -1
  46. package/umd/grid.umd.js +1 -1
  47. package/umd/grid.umd.js.map +1 -1
  48. package/umd/plugins/clipboard.umd.js +1 -1
  49. package/umd/plugins/clipboard.umd.js.map +1 -1
  50. package/umd/plugins/editing.umd.js +1 -1
  51. package/umd/plugins/editing.umd.js.map +1 -1
  52. package/umd/plugins/export.umd.js +1 -1
  53. package/umd/plugins/export.umd.js.map +1 -1
  54. package/umd/plugins/filtering.umd.js +1 -1
  55. package/umd/plugins/filtering.umd.js.map +1 -1
  56. package/umd/plugins/multi-sort.umd.js +1 -1
  57. package/umd/plugins/multi-sort.umd.js.map +1 -1
  58. package/umd/plugins/pinned-rows.umd.js +1 -1
  59. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  60. package/umd/plugins/server-side.umd.js +1 -1
  61. package/umd/plugins/server-side.umd.js.map +1 -1
@@ -110,6 +110,24 @@ export declare const GridCSSVars: {
110
110
  readonly BORDER_RADIUS: "--tbw-border-radius";
111
111
  readonly FOCUS_OUTLINE: "--tbw-focus-outline";
112
112
  };
113
+ /**
114
+ * Union of all CSS class names used in the grid's DOM.
115
+ * Use `GridClasses` to access individual values by key.
116
+ *
117
+ * @category Plugin Development
118
+ */
113
119
  export type GridClassName = (typeof GridClasses)[keyof typeof GridClasses];
120
+ /**
121
+ * Union of all `data-*` attribute names used on grid elements.
122
+ * Use `GridDataAttrs` to access individual values by key.
123
+ *
124
+ * @category Plugin Development
125
+ */
114
126
  export type GridDataAttr = (typeof GridDataAttrs)[keyof typeof GridDataAttrs];
127
+ /**
128
+ * Union of all CSS custom property names (`--tbw-*`) available for theming.
129
+ * Use `GridCSSVars` to access individual values by key.
130
+ *
131
+ * @category Plugin Development
132
+ */
115
133
  export type GridCSSVar = (typeof GridCSSVars)[keyof typeof GridCSSVars];
@@ -0,0 +1,33 @@
1
+ import { ColumnConfig } from '../types';
2
+ /**
3
+ * Resolve the cell value for a column, honoring `valueAccessor` if defined,
4
+ * otherwise reading `row[column.field]`.
5
+ *
6
+ * @param row - The row object
7
+ * @param column - The column definition
8
+ * @param rowIndex - The visible row index (passed to accessor; defaults to -1)
9
+ * @returns The resolved cell value
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const value = resolveCellValue(row, column);
14
+ * ```
15
+ */
16
+ export declare function resolveCellValue<TRow>(row: TRow, column: ColumnConfig<TRow>, rowIndex?: number): unknown;
17
+ /**
18
+ * Invalidate cached accessor values for a row (after in-place mutation),
19
+ * a single (row, field) pair, or — when called with no argument — clear
20
+ * the entire cache. Immutable updates auto-invalidate via row identity.
21
+ *
22
+ * Edit/transaction paths that mutate row objects in-place must call this.
23
+ */
24
+ export declare function invalidateAccessorCache(row?: object, field?: string): void;
25
+ /**
26
+ * Build a `(value, row) => unknown` extractor compatible with
27
+ * `filterValue`-style APIs from a column's `valueAccessor`. Returns `undefined`
28
+ * when the column has no accessor.
29
+ *
30
+ * Used by FilteringPlugin to bridge the two API shapes without duplicating
31
+ * cache lookups.
32
+ */
33
+ export declare function accessorAsFilterValue<TRow>(column: ColumnConfig<TRow>): ((value: unknown, row: TRow) => unknown) | undefined;
@@ -465,6 +465,8 @@ export interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {
465
465
  /** @internal Access the plugin manager's cached state. */
466
466
  _pluginManager?: {
467
467
  _hasRowStructurePlugins: boolean;
468
+ /** Emit an event on the plugin event bus (does not dispatch a DOM event). */
469
+ emitPluginEvent?: <D>(eventType: string, detail: D) => void;
468
470
  };
469
471
  _gridTemplate: string;
470
472
  _virtualization: VirtualState;
@@ -792,6 +794,50 @@ export interface BaseColumnConfig<TRow = any, TValue = any> {
792
794
  resizable?: boolean;
793
795
  /** Optional custom comparator for sorting (a,b) -> number */
794
796
  sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;
797
+ /**
798
+ * Compute the cell's value from the row. When defined, this is the single
799
+ * source of truth used by sorting, filtering, formatting, cell rendering,
800
+ * export, and clipboard — eliminating the need to duplicate value-extraction
801
+ * logic across `sortComparator`, `filterValue`, and per-renderer code.
802
+ *
803
+ * **Resolution precedence**:
804
+ * - **Sort**: `sortComparator` → `valueAccessor` → `row[field]`
805
+ * - **Filter**: `filterValue` → `valueAccessor` → `row[field]`
806
+ * - **Render / format / export / copy**: `valueAccessor` → `row[field]`
807
+ *
808
+ * The accessor is the *default* value source — per-column escape hatches
809
+ * (`sortComparator`, `filterValue`) still take precedence when set.
810
+ *
811
+ * Results are memoized per `(row identity, column field)` so accessors are
812
+ * free to be "slow but correct" (e.g. `array.find(...)`). Immutable row
813
+ * updates auto-invalidate; in-place mutations are invalidated by the grid's
814
+ * edit / transaction paths.
815
+ *
816
+ * Note: a `valueAccessor` without a paired `valueSetter` (planned API)
817
+ * implies the column is read-only — editors will not commit through it.
818
+ *
819
+ * @example
820
+ * ```typescript
821
+ * // Computed value from nested data
822
+ * {
823
+ * field: 'bolDate',
824
+ * header: 'BL date',
825
+ * valueAccessor: ({ row }) => {
826
+ * if (isCargo(row)) {
827
+ * return row.movements.find(m => m.operationType === 'LOAD')?.movementDate ?? null;
828
+ * }
829
+ * return row.movementDate ?? null;
830
+ * },
831
+ * filterType: 'date',
832
+ * // No need for sortComparator or filterValue — they fall back to the accessor.
833
+ * }
834
+ * ```
835
+ */
836
+ valueAccessor?: (ctx: {
837
+ row: TRow;
838
+ column: ColumnConfig<TRow>;
839
+ rowIndex: number;
840
+ }) => TValue;
795
841
  /** For select type - available options */
796
842
  options?: Array<{
797
843
  label: string;
@@ -1883,6 +1929,10 @@ export declare const FitModeEnum: {
1883
1929
  readonly STRETCH: "stretch";
1884
1930
  readonly FIXED: "fixed";
1885
1931
  };
1932
+ /**
1933
+ * Column sizing mode — determines how columns fill the available grid width.
1934
+ * Use `FitModeEnum` to access individual values by key.
1935
+ */
1886
1936
  export type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum];
1887
1937
  /**
1888
1938
  * Minimal plugin interface for type-checking.
@@ -2615,6 +2665,42 @@ export interface DataChangeDetail {
2615
2665
  /** Total number of source rows (before filtering/grouping) */
2616
2666
  sourceRowCount: number;
2617
2667
  }
2668
+ /**
2669
+ * Detail payload for the `tbw-scroll` event.
2670
+ *
2671
+ * Dispatched on the grid host whenever the vertical viewport scrolls
2672
+ * (rAF-batched — at most one per frame). Use to trigger pagination,
2673
+ * defer heavy cell content rendering, dismiss overlays, or sync a
2674
+ * scroll-tracking UI outside the grid.
2675
+ *
2676
+ * For server-side pagination of large datasets, prefer
2677
+ * `ServerSidePlugin` which handles block fetching out of the box.
2678
+ *
2679
+ * @example
2680
+ * ```typescript
2681
+ * grid.addEventListener('tbw-scroll', (e) => {
2682
+ * const { scrollTop, scrollHeight, clientHeight } = e.detail;
2683
+ * if (scrollTop + clientHeight >= scrollHeight - 200) loadMore();
2684
+ * });
2685
+ * ```
2686
+ *
2687
+ * @see {@link DataGridEventMap} for all event types
2688
+ * @category Events
2689
+ */
2690
+ export interface TbwScrollDetail {
2691
+ /** Current vertical scroll offset in pixels (faux scrollbar). */
2692
+ scrollTop: number;
2693
+ /** Total scrollable height in pixels (faux scrollbar). */
2694
+ scrollHeight: number;
2695
+ /** Visible viewport height in pixels (faux scrollbar). */
2696
+ clientHeight: number;
2697
+ /**
2698
+ * Axis that triggered this dispatch. Currently always `'vertical'`;
2699
+ * `'horizontal'` is reserved for a future opt-in dispatch and is
2700
+ * declared up-front so consumer narrowing remains source-compatible.
2701
+ */
2702
+ direction: 'vertical' | 'horizontal';
2703
+ }
2618
2704
  /**
2619
2705
  * Indicates the origin of a data change.
2620
2706
  * Used to prevent infinite loops in cascade update handlers.
@@ -3625,6 +3711,34 @@ export interface DataGridEventMap<TRow = unknown> {
3625
3711
  * @group Core Events
3626
3712
  */
3627
3713
  'data-change': DataChangeDetail;
3714
+ /**
3715
+ * Fired when the grid's viewport is scrolled vertically (rAF-batched).
3716
+ * Use to trigger pagination, defer heavy cell content, dismiss overlays,
3717
+ * or sync external UI to the grid's scroll position.
3718
+ *
3719
+ * For server-side pagination of large datasets, prefer the
3720
+ * `ServerSidePlugin` — it handles block fetching out of the box.
3721
+ *
3722
+ * @example
3723
+ * ```typescript
3724
+ * // Infinite scroll
3725
+ * grid.on('tbw-scroll', ({ scrollTop, scrollHeight, clientHeight }) => {
3726
+ * if (scrollTop + clientHeight >= scrollHeight - 200) loadMore();
3727
+ * });
3728
+ *
3729
+ * // Defer heavy cell content (Angular @defer style)
3730
+ * grid.on('tbw-scroll', ({ scrollTop }) => {
3731
+ * updateVisibleHeavyCells(scrollTop);
3732
+ * });
3733
+ *
3734
+ * // Dismiss tooltip/popover on scroll
3735
+ * grid.on('tbw-scroll', () => closeOpenOverlays());
3736
+ * ```
3737
+ *
3738
+ * @see {@link TbwScrollDetail}
3739
+ * @group Core Events
3740
+ */
3741
+ 'tbw-scroll': TbwScrollDetail;
3628
3742
  /**
3629
3743
  * Emitted when a cell with an external view renderer (React, Angular, Vue component)
3630
3744
  * needs to be mounted. Framework adapters listen for this event internally.
@@ -1,2 +1,2 @@
1
- function e(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function t(t,n,r,o){return`${e(r,o)} ${t}: ${n}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(t)}`}const n="__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(""));new RegExp(`__(proto|defineGetter|defineSetter)|${n.slice(3).join("|")}|this\\b`);const r=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".split("|")),o=/^on\w+$/i,i=new Set("href|src|action|formaction|data|srcdoc|xlink:href|poster|srcset".split("|")),s=/^\s*(javascript|vbscript|data|blob):/i;function l(e){if(!e||"string"!=typeof e)return"";if(-1===e.indexOf("<"))return e;const t=document.createElement("template");return t.innerHTML=e,function(e){const t=[],n=e.querySelectorAll("*");for(const l of n){const e=l.tagName.toLowerCase();if(r.has(e)){t.push(l);continue}if("svg"===e||"http://www.w3.org/2000/svg"===l.namespaceURI){if(Array.from(l.attributes).some(e=>o.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(l);continue}}const n=[];for(const t of l.attributes){const e=t.name.toLowerCase();o.test(e)?n.push(t.name):(i.has(e)&&s.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&n.push(t.name)}n.forEach(e=>l.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}const a='<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>',c={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:a,filterActive:a,print:"🖨️"};class d{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#e;get defaultConfig(){return{}}constructor(e={}){this.userConfig=e}attach(e){this.#e?.abort(),this.#e=new AbortController,this.grid=e,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#e?.abort(),this.#e=void 0}getPlugin(e){return this.grid?.getPlugin(e)}emit(e,t){this.grid?.dispatchEvent?.(new CustomEvent(e,{detail:t,bubbles:!0}))}emitCancelable(e,t){const n=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(n),n.defaultPrevented}on(e,t){this.grid?._pluginManager?.subscribe(this,e,t)}off(e){this.grid?._pluginManager?.unsubscribe(this,e)}emitPluginEvent(e,t){this.grid?._pluginManager?.emitPluginEvent(e,t)}broadcast(e,t){this.emitPluginEvent(e,t),this.emit(e,t)}requestRender(){this.grid?.requestRender?.()}requestColumnsRender(){this.grid?.requestColumnsRender?.()}requestRenderWithFocus(){this.grid?.requestRenderWithFocus?.()}requestAfterRender(){this.grid?.requestAfterRender?.()}requestVirtualRefresh(){this.grid?.requestVirtualRefresh?.()}get rows(){return this.grid?.rows??[]}get sourceRows(){return this.grid?.sourceRows??[]}get columns(){return this.grid?.columns??[]}get visibleColumns(){return this.grid?._visibleColumns??[]}get gridElement(){return this.grid?._hostElement}get disconnectSignal(){return this.#e?.signal??this.grid?.disconnectSignal}get gridIcons(){const e=this.grid?.gridConfig?.icons??{};return{...c,...e}}get isAnimationEnabled(){const e=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===e||"off"===e)return!1;if(!0===e||"on"===e)return!0;const t=this.gridElement;if(t){return"0"!==getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const e=this.gridElement;if(e){const t=getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(),n=parseInt(t,10);if(!isNaN(n))return n}return 200}setIcon(e,t,n){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const r=this.#t(t,n);void 0!==r?"string"==typeof r?e.innerHTML=l(r):r instanceof HTMLElement&&(e.innerHTML="",e.appendChild(r.cloneNode(!0))):e.innerHTML=""}#t(e,t){return void 0!==t?t:this.grid?.gridConfig?.icons?.[e]}updateSortIndicator(e,t){e.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove();const n=document.createElement("span");n.setAttribute("part","sort-indicator"),n.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(n,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(n,"sortNone"));const r=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return r?e.insertBefore(n,r):e.appendChild(n),n}warn(n,r){void 0!==r?console.warn(t(n,r,this.gridElement.id,this.name)):console.warn(`${e(this.gridElement.id,this.name)} ${n}`)}throwDiagnostic(e,n){throw new Error(t(e,n,this.gridElement.id,this.name))}}function u(e,t,n=!0){let r=e;if(n&&(r=r.filter(e=>!e.hidden&&!e.field.startsWith("__")&&!0!==e.meta?.utility)),t?.length){const e=new Set(t);r=r.filter(t=>e.has(t.field))}return r}async function h(e){try{return await navigator.clipboard.writeText(e),!0}catch(s){n="TBW100",r=`Clipboard API failed: ${s}`,console.warn(t(n,r,o,i));const l=document.createElement("textarea");l.value=e,l.style.position="fixed",l.style.opacity="0",l.style.pointerEvents="none",document.body.appendChild(l),l.select();const a=document.execCommand("copy");return document.body.removeChild(l),a}var n,r,o,i}function f(e,t){const n=t.delimiter??"\t",r=t.newline??"\n",o=e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),i=[];let s=[],l="",a=!1;for(let c=0;c<o.length;c++){const e=o[c];'"'!==e||a?'"'===e&&a?'"'===o[c+1]?(l+='"',c++):a=!1:e!==n||a?e!==r||a?l+=e:(s.push(l),l="",(s.length>1||s.some(e=>""!==e.trim()))&&i.push(s),s=[]):(s.push(l),l=""):a=!0}return s.push(l),(s.length>1||s.some(e=>""!==e.trim()))&&i.push(s),i}function g(e,t){const{rows:n,target:r,fields:o}=e;if(!r)return;const i=t.rows,s=t.effectiveConfig.columns??[],l=s.map(e=>e.field),a=/* @__PURE__ */new Map;s.forEach(e=>{a.set(e.field,!0===e.editable)});const c=[...i],d=r.bounds?r.bounds.endRow:1/0;n.forEach((e,t)=>{const n=r.row+t;if(!(n>d)){if(r.bounds){if(n>=c.length)return}else for(;n>=c.length;){const e={};l.forEach(t=>e[t]=""),c.push(e)}c[n]={...c[n]},e.forEach((e,t)=>{const r=o[t];r&&a.get(r)&&(c[n][r]=e)})}}),t.rows=c}class m extends d{static manifest={queries:[{type:"clipboard:copy",description:"Triggers a copy operation and returns the copied text"}]};static dependencies=[{name:"selection",required:!1,reason:"Enables copy/paste of selected cells instead of entire grid"}];name="clipboard";get defaultConfig(){return{includeHeaders:!1,delimiter:"\t",newline:"\n",quoteStrings:!1}}lastCopied=null;attach(e){super.attach(e),e.addEventListener("paste",e=>this.#n(e),{signal:this.disconnectSignal})}detach(){this.lastCopied=null}handleQuery(e){if("clipboard:copy"===e.type)return this.copy(),!0}onKeyDown(e){return!(!e.ctrlKey&&!e.metaKey||"c"!==e.key)&&(e.preventDefault(),this.#r(e.target),!0)}#r(e){const t=this.#o();if(t&&0===t.ranges.length){const t=this.#i(e);if(!t)return;const n=this.columns[t.col];if(!n)return;return void this.copy({rowIndices:[t.row],columns:[n.field]})}this.copy()}#n(e){const t=e.clipboardData?.getData("text/plain");if(!t)return;e.preventDefault();const n=f(t,this.config),r=this.#o(),o=r?.ranges?.[0],i=o?.from.row??0,s=o?.from.col??0,l=o&&("range"===r?.mode||"row"===r?.mode)&&(o.from.row!==o.to.row||o.from.col!==o.to.col)?{endRow:o.to.row,endCol:o.to.col}:null,a=l?.endCol??this.visibleColumns.length-1,c=this.visibleColumns[s],d=c?{row:i,col:s,field:c.field,bounds:l}:null,u=[],h=n[0]?.length??0;for(let f=0;f<h&&s+f<=a;f++){const e=this.visibleColumns[s+f];e&&u.push(e.field)}const g={rows:n,text:t,target:d,fields:u};this.emit("paste",g),this.#s(g)}#s(e){if(!this.grid)return;const{pasteHandler:t}=this.config;if(null===t)return;(t??g)(e,this.grid)}#o(){const e=this.grid?.query("getSelection");return e?.[0]}#l(e){const t=this.#o();let n,r;if(e?.columns)n=u(this.columns,e.columns);else if(t?.ranges.length&&"row"!==t.mode){const e=t.ranges[t.ranges.length-1],r=Math.min(e.from.col,e.to.col),o=Math.max(e.from.col,e.to.col);n=u(this.visibleColumns.slice(r,o+1))}else n=u(this.columns);if(e?.rowIndices)r=function(e,t){return t?.length?[...t].sort((e,t)=>e-t).map(t=>e[t]).filter(e=>null!=e):e}(this.rows,e.rowIndices);else if(t?.ranges.length){const e=t.ranges[t.ranges.length-1],n=Math.min(e.from.row,e.to.row),o=Math.max(e.from.row,e.to.row);r=[];for(let t=n;t<=o;t++){const e=this.rows[t];e&&r.push(e)}}else r=this.rows;return{columns:n,rows:r}}#a(e,t,n){const r=n?.delimiter??this.config.delimiter??"\t",o=n?.newline??this.config.newline??"\n",i=n?.includeHeaders??this.config.includeHeaders??!1,s=n?.processCell??this.config.processCell,l=[];i&&l.push(e.map(e=>e.header||e.field).join(r));for(const a of t){const t=e.map(e=>{const t=a[e.field];return s?s(t,e.field,a):this.#c(e,t,a)});l.push(t.join(r))}return l.join(o)}#c(e,t,n){if(e.format)try{const r=e.format(t,n);return null==r?"":String(r)}catch{}if(e.renderer||e.viewRenderer){const t=this.#d(e.field,n);if(null!=t)return t}return function(e){return null==e?"":e instanceof Date?e.toISOString():"object"==typeof e?JSON.stringify(e):String(e)}(t)}#d(e,t){const n=this.gridElement;if(!n)return null;const r=this.rows.indexOf(t);if(-1===r)return null;const o=n.querySelector(`.cell[data-row="${r}"][data-field="${e}"]`);return o?o.textContent?.trim()??null:null}#i(e){const t=e.closest("[data-field-cache]");if(!t)return null;const n=t.dataset.fieldCache,r=t.dataset.row;if(!n||!r)return null;const o=parseInt(r,10);if(isNaN(o))return null;const i=this.columns.findIndex(e=>e.field===n);return-1===i?null:{row:o,col:i}}getSelectionAsText(e){const{columns:t,rows:n}=this.#l(e);return 0===t.length||0===n.length?"":this.#a(t,n,e)}async copy(e){const{columns:t,rows:n}=this.#l(e);if(0===t.length||0===n.length)return"";const r=this.#a(t,n,e);return await h(r),this.lastCopied={text:r,timestamp:Date.now()},this.emit("copy",{text:r,rowCount:n.length,columnCount:t.length}),r}async copyRows(e,t){return 0===e.length?"":this.copy({...t,rowIndices:e})}async paste(){const e=await async function(){try{return await navigator.clipboard.readText()}catch{return""}}();return e?f(e,this.config):null}getLastCopied(){return this.lastCopied}}export{m as ClipboardPlugin,g as defaultPasteHandler};
1
+ const e=/* @__PURE__ */new WeakMap;function t(t,n,r=-1){if(!n.valueAccessor)return t?.[n.field];if("object"!=typeof t||null===t)return n.valueAccessor({row:t,column:n,rowIndex:r});const o=n.field;let i=e.get(t);if(i){if(i.has(o))return i.get(o)}else i=/* @__PURE__ */new Map,e.set(t,i);const s=n.valueAccessor({row:t,column:n,rowIndex:r});return i.set(o,s),s}function n(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function r(e,t,r,o){return`${n(r,o)} ${e}: ${t}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(e)}`}const o="__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(""));new RegExp(`__(proto|defineGetter|defineSetter)|${o.slice(3).join("|")}|this\\b`);const i=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".split("|")),s=/^on\w+$/i,l=new Set("href|src|action|formaction|data|srcdoc|xlink:href|poster|srcset".split("|")),a=/^\s*(javascript|vbscript|data|blob):/i;function c(e){if(!e||"string"!=typeof e)return"";if(-1===e.indexOf("<"))return e;const t=document.createElement("template");return t.innerHTML=e,function(e){const t=[],n=e.querySelectorAll("*");for(const r of n){const e=r.tagName.toLowerCase();if(i.has(e)){t.push(r);continue}if("svg"===e||"http://www.w3.org/2000/svg"===r.namespaceURI){if(Array.from(r.attributes).some(e=>s.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(r);continue}}const n=[];for(const t of r.attributes){const e=t.name.toLowerCase();s.test(e)?n.push(t.name):(l.has(e)&&a.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&n.push(t.name)}n.forEach(e=>r.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}const d='<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>',u={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:d,filterActive:d,print:"🖨️"};class h{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#e;get defaultConfig(){return{}}constructor(e={}){this.userConfig=e}attach(e){this.#e?.abort(),this.#e=new AbortController,this.grid=e,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#e?.abort(),this.#e=void 0}getPlugin(e){return this.grid?.getPlugin(e)}emit(e,t){this.grid?.dispatchEvent?.(new CustomEvent(e,{detail:t,bubbles:!0}))}emitCancelable(e,t){const n=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(n),n.defaultPrevented}on(e,t){this.grid?._pluginManager?.subscribe(this,e,t)}off(e){this.grid?._pluginManager?.unsubscribe(this,e)}emitPluginEvent(e,t){this.grid?._pluginManager?.emitPluginEvent(e,t)}broadcast(e,t){this.emitPluginEvent(e,t),this.emit(e,t)}requestRender(){this.grid?.requestRender?.()}requestColumnsRender(){this.grid?.requestColumnsRender?.()}requestRenderWithFocus(){this.grid?.requestRenderWithFocus?.()}requestAfterRender(){this.grid?.requestAfterRender?.()}requestVirtualRefresh(){this.grid?.requestVirtualRefresh?.()}get rows(){return this.grid?.rows??[]}get sourceRows(){return this.grid?.sourceRows??[]}get columns(){return this.grid?.columns??[]}get visibleColumns(){return this.grid?._visibleColumns??[]}get gridElement(){return this.grid?._hostElement}get disconnectSignal(){return this.#e?.signal??this.grid?.disconnectSignal}get gridIcons(){const e=this.grid?.gridConfig?.icons??{};return{...u,...e}}get isAnimationEnabled(){const e=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===e||"off"===e)return!1;if(!0===e||"on"===e)return!0;const t=this.gridElement;if(t){return"0"!==getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const e=this.gridElement;if(e){const t=getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(),n=parseInt(t,10);if(!isNaN(n))return n}return 200}setIcon(e,t,n){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const r=this.#t(t,n);void 0!==r?"string"==typeof r?e.innerHTML=c(r):r instanceof HTMLElement&&(e.innerHTML="",e.appendChild(r.cloneNode(!0))):e.innerHTML=""}#t(e,t){return void 0!==t?t:this.grid?.gridConfig?.icons?.[e]}updateSortIndicator(e,t){e.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove();const n=document.createElement("span");n.setAttribute("part","sort-indicator"),n.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(n,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(n,"sortNone"));const r=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return r?e.insertBefore(n,r):e.appendChild(n),n}warn(e,t){void 0!==t?console.warn(r(e,t,this.gridElement.id,this.name)):console.warn(`${n(this.gridElement.id,this.name)} ${e}`)}throwDiagnostic(e,t){throw new Error(r(e,t,this.gridElement.id,this.name))}}function f(e,t,n=!0){let r=e;if(n&&(r=r.filter(e=>!e.hidden&&!e.field.startsWith("__")&&!0!==e.meta?.utility)),t?.length){const e=new Set(t);r=r.filter(t=>e.has(t.field))}return r}async function g(e){try{return await navigator.clipboard.writeText(e),!0}catch(s){t="TBW100",n=`Clipboard API failed: ${s}`,console.warn(r(t,n,o,i));const l=document.createElement("textarea");l.value=e,l.style.position="fixed",l.style.opacity="0",l.style.pointerEvents="none",document.body.appendChild(l),l.select();const a=document.execCommand("copy");return document.body.removeChild(l),a}var t,n,o,i}function m(e,t){const n=t.delimiter??"\t",r=t.newline??"\n",o=e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),i=[];let s=[],l="",a=!1;for(let c=0;c<o.length;c++){const e=o[c];'"'!==e||a?'"'===e&&a?'"'===o[c+1]?(l+='"',c++):a=!1:e!==n||a?e!==r||a?l+=e:(s.push(l),l="",(s.length>1||s.some(e=>""!==e.trim()))&&i.push(s),s=[]):(s.push(l),l=""):a=!0}return s.push(l),(s.length>1||s.some(e=>""!==e.trim()))&&i.push(s),i}function p(e,t){const{rows:n,target:r,fields:o}=e;if(!r)return;const i=t.rows,s=t.effectiveConfig.columns??[],l=s.map(e=>e.field),a=/* @__PURE__ */new Map;s.forEach(e=>{a.set(e.field,!0===e.editable)});const c=[...i],d=r.bounds?r.bounds.endRow:1/0;n.forEach((e,t)=>{const n=r.row+t;if(!(n>d)){if(r.bounds){if(n>=c.length)return}else for(;n>=c.length;){const e={};l.forEach(t=>e[t]=""),c.push(e)}c[n]={...c[n]},e.forEach((e,t)=>{const r=o[t];r&&a.get(r)&&(c[n][r]=e)})}}),t.rows=c}class w extends h{static manifest={queries:[{type:"clipboard:copy",description:"Triggers a copy operation and returns the copied text"}]};static dependencies=[{name:"selection",required:!1,reason:"Enables copy/paste of selected cells instead of entire grid"}];name="clipboard";get defaultConfig(){return{includeHeaders:!1,delimiter:"\t",newline:"\n",quoteStrings:!1}}lastCopied=null;attach(e){super.attach(e),e.addEventListener("paste",e=>this.#n(e),{signal:this.disconnectSignal})}detach(){this.lastCopied=null}handleQuery(e){if("clipboard:copy"===e.type)return this.copy(),!0}onKeyDown(e){return!(!e.ctrlKey&&!e.metaKey||"c"!==e.key)&&(e.preventDefault(),this.#r(e.target),!0)}#r(e){const t=this.#o();if(t&&0===t.ranges.length){const t=this.#i(e);if(!t)return;const n=this.columns[t.col];if(!n)return;return void this.copy({rowIndices:[t.row],columns:[n.field]})}this.copy()}#n(e){const t=e.clipboardData?.getData("text/plain");if(!t)return;e.preventDefault();const n=m(t,this.config),r=this.#o(),o=r?.ranges?.[0],i=o?.from.row??0,s=o?.from.col??0,l=o&&("range"===r?.mode||"row"===r?.mode)&&(o.from.row!==o.to.row||o.from.col!==o.to.col)?{endRow:o.to.row,endCol:o.to.col}:null,a=l?.endCol??this.visibleColumns.length-1,c=this.visibleColumns[s],d=c?{row:i,col:s,field:c.field,bounds:l}:null,u=[],h=n[0]?.length??0;for(let g=0;g<h&&s+g<=a;g++){const e=this.visibleColumns[s+g];e&&u.push(e.field)}const f={rows:n,text:t,target:d,fields:u};this.emit("paste",f),this.#s(f)}#s(e){if(!this.grid)return;const{pasteHandler:t}=this.config;if(null===t)return;(t??p)(e,this.grid)}#o(){const e=this.grid?.query("getSelection");return e?.[0]}#l(e){const t=this.#o();let n,r;if(e?.columns)n=f(this.columns,e.columns);else if(t?.ranges.length&&"row"!==t.mode){const e=t.ranges[t.ranges.length-1],r=Math.min(e.from.col,e.to.col),o=Math.max(e.from.col,e.to.col);n=f(this.visibleColumns.slice(r,o+1))}else n=f(this.columns);if(e?.rowIndices)r=function(e,t){return t?.length?[...t].sort((e,t)=>e-t).map(t=>e[t]).filter(e=>null!=e):e}(this.rows,e.rowIndices);else if(t?.ranges.length){const e=t.ranges[t.ranges.length-1],n=Math.min(e.from.row,e.to.row),o=Math.max(e.from.row,e.to.row);r=[];for(let t=n;t<=o;t++){const e=this.rows[t];e&&r.push(e)}}else r=this.rows;return{columns:n,rows:r}}#a(e,n,r){const o=r?.delimiter??this.config.delimiter??"\t",i=r?.newline??this.config.newline??"\n",s=r?.includeHeaders??this.config.includeHeaders??!1,l=r?.processCell??this.config.processCell,a=[];s&&a.push(e.map(e=>e.header||e.field).join(o));for(const c of n){const n=e.map(e=>{const n=t(c,e);return l?l(n,e.field,c):this.#c(e,n,c)});a.push(n.join(o))}return a.join(i)}#c(e,t,n){if(e.format)try{const r=e.format(t,n);return null==r?"":String(r)}catch{}if(e.renderer||e.viewRenderer){const t=this.#d(e.field,n);if(null!=t)return t}return function(e){return null==e?"":e instanceof Date?e.toISOString():"object"==typeof e?JSON.stringify(e):String(e)}(t)}#d(e,t){const n=this.gridElement;if(!n)return null;const r=this.rows.indexOf(t);if(-1===r)return null;const o=n.querySelector(`.cell[data-row="${r}"][data-field="${e}"]`);return o?o.textContent?.trim()??null:null}#i(e){const t=e.closest("[data-field-cache]");if(!t)return null;const n=t.dataset.fieldCache,r=t.dataset.row;if(!n||!r)return null;const o=parseInt(r,10);if(isNaN(o))return null;const i=this.columns.findIndex(e=>e.field===n);return-1===i?null:{row:o,col:i}}getSelectionAsText(e){const{columns:t,rows:n}=this.#l(e);return 0===t.length||0===n.length?"":this.#a(t,n,e)}async copy(e){const{columns:t,rows:n}=this.#l(e);if(0===t.length||0===n.length)return"";const r=this.#a(t,n,e);return await g(r),this.lastCopied={text:r,timestamp:Date.now()},this.emit("copy",{text:r,rowCount:n.length,columnCount:t.length}),r}async copyRows(e,t){return 0===e.length?"":this.copy({...t,rowIndices:e})}async paste(){const e=await async function(){try{return await navigator.clipboard.readText()}catch{return""}}();return e?m(e,this.config):null}getLastCopied(){return this.lastCopied}}export{w as ClipboardPlugin,p as defaultPasteHandler};
2
2
  //# sourceMappingURL=index.js.map