@toolbox-web/grid 2.3.0 → 2.4.1

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 (106) hide show
  1. package/all.d.ts +1 -0
  2. package/all.js +2 -2
  3. package/all.js.map +1 -1
  4. package/index.js +1 -1
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +2 -1
  7. package/lib/core/internal/aria.d.ts +13 -0
  8. package/lib/core/internal/diagnostics.d.ts +5 -1
  9. package/lib/core/internal/dom-builder.d.ts +0 -25
  10. package/lib/core/internal/drag-drop-registry.d.ts +66 -0
  11. package/lib/core/internal/render-scheduler.d.ts +9 -8
  12. package/lib/core/plugin/base-plugin.d.ts +23 -0
  13. package/lib/core/plugin/plugin-manager.d.ts +9 -0
  14. package/lib/core/types.d.ts +67 -46
  15. package/lib/features/registry.js.map +1 -1
  16. package/lib/features/reorder-rows.d.ts +3 -3
  17. package/lib/features/reorder-rows.js +1 -1
  18. package/lib/features/reorder-rows.js.map +1 -1
  19. package/lib/features/row-drag-drop.d.ts +9 -0
  20. package/lib/features/row-drag-drop.js +2 -0
  21. package/lib/features/row-drag-drop.js.map +1 -0
  22. package/lib/features/server-side.js.map +1 -1
  23. package/lib/plugins/clipboard/index.js +1 -1
  24. package/lib/plugins/clipboard/index.js.map +1 -1
  25. package/lib/plugins/column-virtualization/index.js +1 -1
  26. package/lib/plugins/column-virtualization/index.js.map +1 -1
  27. package/lib/plugins/context-menu/index.js +1 -1
  28. package/lib/plugins/context-menu/index.js.map +1 -1
  29. package/lib/plugins/editing/index.js +1 -1
  30. package/lib/plugins/editing/index.js.map +1 -1
  31. package/lib/plugins/export/ExportPlugin.d.ts +89 -0
  32. package/lib/plugins/export/index.d.ts +3 -2
  33. package/lib/plugins/export/index.js +1 -1
  34. package/lib/plugins/export/index.js.map +1 -1
  35. package/lib/plugins/export/types.d.ts +30 -0
  36. package/lib/plugins/filtering/FilteringPlugin.d.ts +15 -0
  37. package/lib/plugins/filtering/index.js +1 -1
  38. package/lib/plugins/filtering/index.js.map +1 -1
  39. package/lib/plugins/grouping-columns/index.js +1 -1
  40. package/lib/plugins/grouping-columns/index.js.map +1 -1
  41. package/lib/plugins/grouping-rows/index.js +2 -2
  42. package/lib/plugins/grouping-rows/index.js.map +1 -1
  43. package/lib/plugins/master-detail/index.js +1 -1
  44. package/lib/plugins/master-detail/index.js.map +1 -1
  45. package/lib/plugins/multi-sort/index.js +1 -1
  46. package/lib/plugins/multi-sort/index.js.map +1 -1
  47. package/lib/plugins/pinned-columns/index.js +1 -1
  48. package/lib/plugins/pinned-columns/index.js.map +1 -1
  49. package/lib/plugins/pinned-rows/index.js +1 -1
  50. package/lib/plugins/pinned-rows/index.js.map +1 -1
  51. package/lib/plugins/pivot/index.js +1 -1
  52. package/lib/plugins/pivot/index.js.map +1 -1
  53. package/lib/plugins/print/index.js +1 -1
  54. package/lib/plugins/print/index.js.map +1 -1
  55. package/lib/plugins/reorder-columns/index.js +1 -1
  56. package/lib/plugins/reorder-columns/index.js.map +1 -1
  57. package/lib/plugins/reorder-rows/RowReorderPlugin.d.ts +14 -156
  58. package/lib/plugins/reorder-rows/index.d.ts +10 -4
  59. package/lib/plugins/reorder-rows/index.js +1 -1
  60. package/lib/plugins/reorder-rows/index.js.map +1 -1
  61. package/lib/plugins/reorder-rows/types.d.ts +9 -86
  62. package/lib/plugins/responsive/index.js +1 -1
  63. package/lib/plugins/responsive/index.js.map +1 -1
  64. package/lib/plugins/row-drag-drop/RowDragDropPlugin.d.ts +146 -0
  65. package/lib/plugins/row-drag-drop/index.d.ts +9 -0
  66. package/lib/plugins/row-drag-drop/index.js +2 -0
  67. package/lib/plugins/row-drag-drop/index.js.map +1 -0
  68. package/lib/plugins/row-drag-drop/types.d.ts +276 -0
  69. package/lib/plugins/selection/index.js +1 -1
  70. package/lib/plugins/selection/index.js.map +1 -1
  71. package/lib/plugins/server-side/ServerSidePlugin.d.ts +13 -0
  72. package/lib/plugins/server-side/datasource-types.d.ts +54 -7
  73. package/lib/plugins/server-side/datasource.d.ts +10 -2
  74. package/lib/plugins/server-side/index.d.ts +1 -1
  75. package/lib/plugins/server-side/index.js +1 -1
  76. package/lib/plugins/server-side/index.js.map +1 -1
  77. package/lib/plugins/server-side/types.d.ts +1 -1
  78. package/lib/plugins/shared/drag-drop-protocol.d.ts +98 -0
  79. package/lib/plugins/tooltip/index.js +1 -1
  80. package/lib/plugins/tooltip/index.js.map +1 -1
  81. package/lib/plugins/tree/TreePlugin.d.ts +19 -6
  82. package/lib/plugins/tree/index.js +1 -1
  83. package/lib/plugins/tree/index.js.map +1 -1
  84. package/lib/plugins/undo-redo/index.js +1 -1
  85. package/lib/plugins/undo-redo/index.js.map +1 -1
  86. package/lib/plugins/visibility/index.js +1 -1
  87. package/lib/plugins/visibility/index.js.map +1 -1
  88. package/package.json +1 -1
  89. package/umd/grid.all.umd.js +1 -1
  90. package/umd/grid.all.umd.js.map +1 -1
  91. package/umd/grid.umd.js +1 -1
  92. package/umd/grid.umd.js.map +1 -1
  93. package/umd/plugins/export.umd.js +1 -1
  94. package/umd/plugins/export.umd.js.map +1 -1
  95. package/umd/plugins/filtering.umd.js +1 -1
  96. package/umd/plugins/filtering.umd.js.map +1 -1
  97. package/umd/plugins/reorder-rows.umd.js +1 -1
  98. package/umd/plugins/reorder-rows.umd.js.map +1 -1
  99. package/umd/plugins/row-drag-drop.umd.js +2 -0
  100. package/umd/plugins/row-drag-drop.umd.js.map +1 -0
  101. package/umd/plugins/selection.umd.js +1 -1
  102. package/umd/plugins/selection.umd.js.map +1 -1
  103. package/umd/plugins/server-side.umd.js +1 -1
  104. package/umd/plugins/server-side.umd.js.map +1 -1
  105. package/umd/plugins/tree.umd.js +1 -1
  106. package/umd/plugins/tree.umd.js.map +1 -1
@@ -0,0 +1,146 @@
1
+ import { BaseGridPlugin, GridElement, PluginManifest } from '../../core/plugin/base-plugin';
2
+ import { ColumnConfig } from '../../core/types';
3
+ import { RowDragDropConfig, RowTransferDetail } from './types';
4
+ /** Field name for the drag handle column. */
5
+ export declare const ROW_DRAG_HANDLE_FIELD = "__tbw_row_drag";
6
+ /**
7
+ * Row Drag-Drop Plugin for `<tbw-grid>`.
8
+ *
9
+ * @example Intra-grid (parity with deprecated `RowReorderPlugin`)
10
+ * ```ts
11
+ * import { RowDragDropPlugin } from '@toolbox-web/grid/plugins/row-drag-drop';
12
+ *
13
+ * grid.gridConfig = {
14
+ * plugins: [new RowDragDropPlugin()],
15
+ * };
16
+ * ```
17
+ *
18
+ * @example Cross-grid transfer list
19
+ * ```ts
20
+ * gridA.gridConfig = { plugins: [new RowDragDropPlugin({ dropZone: 'tasks' })] };
21
+ * gridB.gridConfig = { plugins: [new RowDragDropPlugin({ dropZone: 'tasks' })] };
22
+ *
23
+ * gridA.addEventListener('row-transfer', (e) => persist(e.detail));
24
+ * gridB.addEventListener('row-transfer', (e) => persist(e.detail));
25
+ * ```
26
+ *
27
+ * @category Plugin
28
+ */
29
+ export declare class RowDragDropPlugin<T = unknown> extends BaseGridPlugin<RowDragDropConfig<T>> {
30
+ /** @internal */
31
+ readonly name = "rowDragDrop";
32
+ /**
33
+ * Backwards-compatible aliases. `RowReorderPlugin`'s legacy plugin name
34
+ * (`reorderRows`) and short alias (`rowReorder`) both resolve here so that
35
+ * `getPluginByName('reorderRows')` keeps working.
36
+ * @internal
37
+ */
38
+ readonly aliases: readonly ["reorderRows", "rowReorder"];
39
+ /** @internal */
40
+ readonly styles: string;
41
+ /** @internal */
42
+ static readonly manifest: PluginManifest<RowDragDropConfig>;
43
+ /** @internal */
44
+ protected get defaultConfig(): Partial<RowDragDropConfig<T>>;
45
+ /**
46
+ * Resolve whether the grip column should be rendered. The handle is shown
47
+ * unless the user explicitly set `showDragHandle: false`, OR `dragFrom`
48
+ * is `'row'` and `showDragHandle` was not explicitly set to `true`.
49
+ */
50
+ private shouldRenderDragHandle;
51
+ /** Whether the row element itself should accept native HTML5 drag. */
52
+ private get rowIsDraggable();
53
+ /** Resolve animation type from plugin config (respects grid-level reduced-motion). */
54
+ private get animationType();
55
+ private isDragging;
56
+ private draggedRowIndex;
57
+ private draggedRows;
58
+ private draggedIndices;
59
+ private dragSessionId;
60
+ private dragAccepted;
61
+ private dropRowIndex;
62
+ private pendingMove;
63
+ private debounceTimer;
64
+ private lastFocusCol;
65
+ private autoScroller;
66
+ /** Stable id for this grid instance (used as `sourceGridId` in payloads). */
67
+ private gridId;
68
+ /** Bound listener so we can register/unregister the same reference. */
69
+ private readonly remoteTransferListener;
70
+ /** Typed internal grid accessor. */
71
+ private get internalGrid();
72
+ /** @internal */
73
+ attach(grid: GridElement): void;
74
+ /** @internal */
75
+ detach(): void;
76
+ /** @internal */
77
+ processColumns(columns: readonly ColumnConfig[]): ColumnConfig[];
78
+ /** @internal */
79
+ afterRender(): void;
80
+ /** @internal */
81
+ onScrollRender(): void;
82
+ /**
83
+ * Set or clear the `draggable` attribute on every visible row, depending on
84
+ * `config.dragFrom`. Idempotent and cheap (one attribute write per row).
85
+ */
86
+ private applyRowDraggable;
87
+ /** @internal */
88
+ onKeyDown(event: KeyboardEvent): boolean | void;
89
+ /** @internal */
90
+ onCellClick(): void;
91
+ /** Move a row to a new position programmatically (intra-grid). */
92
+ moveRow(fromIndex: number, toIndex: number): void;
93
+ /**
94
+ * Check if a row can be moved within this grid.
95
+ * Consults the user-provided `canMove` callback (or `canDrag` veto for the
96
+ * source row), the plugin query system (`canMoveRow`), and `canDrop` for
97
+ * the target.
98
+ */
99
+ canMoveRow(fromIndex: number, toIndex: number): boolean;
100
+ private setupDelegatedDragListeners;
101
+ private onDragStart;
102
+ /**
103
+ * Selectors whose dragstart should NOT initiate a row drag in `dragFrom: 'row'`
104
+ * mode. Keeps native interactions (text input, button clicks, link drag,
105
+ * cell editing, selection checkboxes) working unchanged.
106
+ */
107
+ private static readonly INTERACTIVE_DRAG_SELECTORS;
108
+ /** @internal */
109
+ private isInteractiveDragOrigin;
110
+ /**
111
+ * Build a full-row drag image by cloning `rowEl` so the user sees the
112
+ * actual row — not just the grip icon — while dragging.
113
+ *
114
+ * The clone is appended off-screen, snapshotted by the browser via
115
+ * `setDragImage`, then removed on the next tick (after the snapshot).
116
+ * The cursor offset is preserved relative to where the user pressed.
117
+ */
118
+ private attachRowCloneDragImage;
119
+ private onDragOver;
120
+ private onDragLeave;
121
+ private onDrop;
122
+ /**
123
+ * Source-window handler for a remote `row-transfer` broadcast from a target
124
+ * window. Only runs on the plugin instance whose grid id matches the message.
125
+ * @internal
126
+ */
127
+ private onRemoteTransfer;
128
+ private onDragEnd;
129
+ /** Public wrapper so a peer plugin can dispatch `row-transfer` on this grid. @internal */
130
+ emitTransfer(detail: RowTransferDetail<T>): void;
131
+ /** Find the peer `RowDragDropPlugin` instance on another grid by id. */
132
+ private findPeerOnGrid;
133
+ private resolveDraggedRows;
134
+ private ensureAutoScroller;
135
+ private applyDropPositionClasses;
136
+ private clearDropTargetClasses;
137
+ private clearDragClasses;
138
+ private resetDragState;
139
+ private getRowIndex;
140
+ private clearDebounceTimer;
141
+ private handleKeyboardMove;
142
+ private flushPendingMove;
143
+ private executeIntraGridMove;
144
+ private captureRowPositions;
145
+ private animateFLIP;
146
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Row Drag-Drop Plugin Entry Point
3
+ *
4
+ * Re-exports plugin class and types for tree-shakeable imports.
5
+ *
6
+ * @module Plugins/Row Drag-Drop
7
+ */
8
+ export { ROW_DRAG_HANDLE_FIELD, RowDragDropPlugin } from './RowDragDropPlugin';
9
+ export type { RowDragDropConfig, RowDragEndDetail, RowDragPayload, RowDragStartDetail, RowDropDetail, RowMoveDetail, RowTransferDetail, } from './types';
@@ -0,0 +1,2 @@
1
+ const e="editing",t="dragging",r=/* @__PURE__ */new Map;function o(e){const t=r.get(e);if(!t)return;if(t.hasPrimitives)return;const o=[];for(const r of t.refs){const e=r.deref();if(void 0===e)return;o.push(e)}return o}function i(e){r.delete(e)}function n(){if("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();if("undefined"!=typeof crypto&&"function"==typeof crypto.getRandomValues){const e=new Uint32Array(2);return crypto.getRandomValues(e),`drag-${Date.now().toString(36)}-${e[0].toString(36)}${e[1].toString(36)}`}return`drag-${Date.now().toString(36)}-${(++s).toString(36)}`}let s=0;function a(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function d(e,t,r,o){return`${a(r,o)} ${e}: ${t}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(e)}`}const c="__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)|${c.slice(3).join("|")}|this\\b`);const l=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("|")),g=/^on\w+$/i,u=new Set("href|src|action|formaction|data|srcdoc|xlink:href|poster|srcset".split("|")),f=/^\s*(javascript|vbscript|data|blob):/i;function h(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=[],r=e.querySelectorAll("*");for(const o of r){const e=o.tagName.toLowerCase();if(l.has(e)){t.push(o);continue}if("svg"===e||"http://www.w3.org/2000/svg"===o.namespaceURI){if(Array.from(o.attributes).some(e=>g.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(o);continue}}const r=[];for(const t of o.attributes){const e=t.name.toLowerCase();g.test(e)?r.push(t.name):(u.has(e)&&f.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&r.push(t.name)}r.forEach(e=>o.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}document.createElement("template").innerHTML='<div class="cell" role="gridcell" part="cell"></div>';function p(t,r){if(t._virtualization?.enabled){const{rowHeight:e,container:r,viewportEl:o}=t._virtualization,i=r,n=o?.clientHeight??i?.clientHeight??0;if(i&&n>0){const r=t._focusRow*e;r<i.scrollTop?i.scrollTop=r:r+e>i.scrollTop+n&&(i.scrollTop=r-n+e)}}const o=void 0!==t._activeEditRows&&-1!==t._activeEditRows||!!t._isGridEditMode;var i;o||t.refreshVirtualWindow(!1),(i=t._bodyEl)&&i.querySelectorAll(".cell-focus").forEach(e=>e.classList.remove("cell-focus")),Array.from(t._bodyEl.querySelectorAll('[aria-selected="true"]')).forEach(e=>{e.setAttribute("aria-selected","false")});const n=t._focusRow,s=t._virtualization.start??0,a=t._virtualization.end??t._rows.length;if(n>=s&&n<a){const i=t._bodyEl.querySelectorAll(".data-grid-row")[n-s];let a=i?.children[t._focusCol];if(a&&a.classList?.contains("cell")||(a=i?.querySelector(`.cell[data-col="${t._focusCol}"]`)??i?.querySelector(".cell[data-col]")),a){a.classList.add("cell-focus"),a.setAttribute("aria-selected","true");const n=t.querySelector(".tbw-scroll-area");if(n&&a&&(!o||r?.forceHorizontalScroll)){const e=t._getHorizontalScrollOffsets?.(i??void 0,a)??{left:0,right:0};if(!e.skipScroll){const t=a.getBoundingClientRect(),r=n.getBoundingClientRect(),o=t.left-r.left+n.scrollLeft,i=o+t.width,s=n.scrollLeft+e.left,d=n.scrollLeft+n.clientWidth-e.right;o<s?n.scrollLeft=o-e.left:i>d&&(n.scrollLeft=i-n.clientWidth+e.right)}}if(o&&a.classList.contains(e)){const e=a.querySelector('input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])');if(e&&document.activeElement!==e)try{e.focus({preventScroll:!0})}catch{}}else if(o&&!a.contains(document.activeElement)){a.hasAttribute("tabindex")||a.setAttribute("tabindex","-1");try{a.focus({preventScroll:!0})}catch{}}else o||document.activeElement!==t&&t.focus({preventScroll:!0})}}}document.createElement("template").innerHTML='<div class="data-grid-row" role="row" part="row"></div>';const w={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:"",filterActive:"",print:"🖨️"};class m{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}mergeConfigsFrom(e){if(0===e.length)return;const t={...this.userConfig},r={};for(const o of Object.keys(t))r[o]=this;for(const o of e){const e=o.userConfig;for(const[i,n]of Object.entries(e)){if(void 0===n)continue;if(!(i in t)){t[i]=n,r[i]=o;continue}if(t[i]===n)continue;const e=r[i]?.constructor.name??this.constructor.name,s=o.constructor.name,a=d("TBW025",`Cannot merge plugin configs for "${this.name}": conflicting value for "${i}" supplied by both ${e} and ${s}. Pass the option on a single instance, or remove the duplicate.`,void 0,this.name);throw new Error(a)}}Object.assign(this.userConfig,t)}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 r=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(r),r.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{...w,...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(),r=parseInt(t,10);if(!isNaN(r))return r}return 200}setIcon(e,t,r){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const o=this.#t(t,r);void 0!==o?"string"==typeof o?e.innerHTML=h(o):o instanceof HTMLElement&&(e.innerHTML="",e.appendChild(o.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 r=document.createElement("span");r.setAttribute("part","sort-indicator"),r.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(r,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(r,"sortNone"));const o=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return o?e.insertBefore(r,o):e.appendChild(r),r}warn(e,t){void 0!==t?console.warn(d(e,t,this.gridElement.id,this.name)):console.warn(`${a(this.gridElement.id,this.name)} ${e}`)}throwDiagnostic(e,t){throw new Error(d(e,t,this.gridElement.id,this.name))}}let b=null;function v(){return b}function I(){b=null}const y="application/x-tbw-grid-rows+json";function R(e){const t=e.match(/^application\/x-tbw-grid-rows\+json;zone=(.*)$/);if(!t)return null;try{return decodeURIComponent(t[1])}catch{return t[1]}}function x(e){return JSON.stringify(e)}function D(e,t,r,o){if(!e)return{overIndex:null,insertIndex:o,isBefore:!1};const i=r(e);if(i<0)return{overIndex:null,insertIndex:o,isBefore:!1};const n=e.getBoundingClientRect(),s=t<n.top+n.height/2;return{overIndex:i,insertIndex:s?i:i+1,isBefore:s}}const E="__tbw_row_drag";let S=null;const C=/* @__PURE__ */new Set;function _(){if("undefined"==typeof BroadcastChannel)return null;if(S)return S;try{S=new BroadcastChannel("tbw-row-drag-drop"),S.addEventListener("message",e=>{const t=e.data;if(t&&"tbw-row-drag-drop:transfer"===t.type)for(const r of Array.from(C))try{r(t)}catch{}})}catch{S=null}return S}class A extends m{name="rowDragDrop";aliases=["reorderRows","rowReorder"];styles='@layer tbw-plugins{[data-field=__tbw_row_drag]{display:flex;align-items:center;justify-content:center}.dg-row-drag-handle{display:flex;align-items:center;justify-content:center;min-width:1em;min-height:1em;cursor:grab;-webkit-user-select:none;user-select:none;color:var(--tbw-row-reorder-handle-color, var(--tbw-color-fg-muted));transition:color var(--tbw-transition-duration, .12s) var(--tbw-transition-ease, ease);font-size:var(--tbw-font-size, 1em);letter-spacing:-2px}.dg-row-drag-handle:hover{color:var(--tbw-row-reorder-handle-hover, var(--tbw-color-fg))}.dg-row-drag-handle:active{cursor:grabbing}.data-grid-row.dragging{opacity:.6}.data-grid-row[draggable=true]{cursor:grab}.data-grid-row[draggable=true].dragging{cursor:grabbing}.tbw-row-drag-clone{position:fixed;top:-10000px;left:-10000px;pointer-events:none}.tbw-row-drag-count{position:fixed;top:-1000px;left:-1000px;pointer-events:none;background:var(--tbw-row-reorder-indicator, var(--tbw-color-accent));color:var(--tbw-color-accent-fg);font:600 12px/1.4 system-ui,sans-serif;border-radius:999px;padding:2px 8px;box-shadow:0 2px 6px var(--tbw-color-shadow);z-index:9999}.data-grid-row.drop-target{position:relative}.data-grid-row.drop-target.drop-before:before,.data-grid-row.drop-target.drop-after:after{content:"";position:absolute;left:0;right:0;height:var(--tbw-drop-indicator-width, 2px);background-color:var(--tbw-drop-indicator-color, var(--tbw-row-reorder-indicator, var(--tbw-color-accent)));z-index:10;pointer-events:none}.data-grid-row.drop-target.drop-before:before{top:0}.data-grid-row.drop-target.drop-after:after{bottom:0}.tbw-grid--drop-target-active{outline:2px dashed var(--tbw-drop-indicator-color, var(--tbw-color-accent));outline-offset:-2px}.tbw-grid--drop-target-rejected{outline:2px dashed var(--tbw-color-danger);outline-offset:-2px}.tbw-grid--auto-scrolling{cursor:ns-resize}.data-grid-row.flip-animating{transition:transform var(--tbw-animation-duration, .2s) ease-out;will-change:transform;z-index:1}}';static manifest={events:[{type:"row-move",description:"Intra-grid row reorder.",cancelable:!0},{type:"row-drag-start",description:"Cross-grid drag started on this grid.",cancelable:!0},{type:"row-drag-end",description:"Drag finished on this grid (regardless of outcome)."},{type:"row-drop",description:"Cross-grid drop landing on this grid.",cancelable:!0},{type:"row-transfer",description:"Cross-grid transfer completed (fires on both grids)."}]};get defaultConfig(){return{enableKeyboard:!0,dragHandlePosition:"left",dragHandleWidth:40,debounceMs:150,animation:"flip",operation:"move",autoScroll:!0,dragFrom:"handle"}}shouldRenderDragHandle(){const e=this.config.showDragHandle;return!1!==e&&(!0===e||"row"!==this.config.dragFrom)}get rowIsDraggable(){return"row"===this.config.dragFrom||"both"===this.config.dragFrom}get animationType(){return!!this.isAnimationEnabled&&(void 0!==this.config.animation?this.config.animation:"flip")}isDragging=!1;draggedRowIndex=null;draggedRows=[];draggedIndices=[];dragSessionId=null;dragAccepted=!1;dropRowIndex=null;pendingMove=null;debounceTimer=null;lastFocusCol=0;autoScroller=null;gridId="";remoteTransferListener=e=>this.onRemoteTransfer(e);get internalGrid(){return this.grid}attach(e){super.attach(e);const t=this.gridElement;var r;t&&(this.gridId=t.id||`tbw-grid-${n().slice(0,8)}`,t.id||(t.id=this.gridId),this.setupDelegatedDragListeners(),r=this.remoteTransferListener,C.add(r),_())}detach(){this.clearDebounceTimer(),this.autoScroller?.stop(),this.autoScroller=null,function(e){if(C.delete(e),0===C.size&&S){try{S.close()}catch{}S=null}}(this.remoteTransferListener),this.dragSessionId&&i(this.dragSessionId),I(),this.resetDragState(),super.detach()}processColumns(e){if(!this.shouldRenderDragHandle())return[...e];const t={field:E,header:"",width:this.config.dragHandleWidth??40,resizable:!1,sortable:!1,filterable:!1,lockPosition:!0,utility:!0,viewRenderer:()=>{const e=document.createElement("div");return e.className="dg-row-drag-handle",e.setAttribute("aria-label","Drag to reorder"),e.setAttribute("role","button"),e.setAttribute("tabindex","-1"),e.draggable=!0,this.setIcon(e,"dragHandle"),e}};return"right"===this.config.dragHandlePosition?[...e,t]:[t,...e]}afterRender(){this.applyRowDraggable()}onScrollRender(){this.applyRowDraggable()}applyRowDraggable(){const e=this.internalGrid._bodyEl;if(!e)return;const t=this.rowIsDraggable,r=e.querySelectorAll(".data-grid-row");for(const o of r)t?"true"!==o.getAttribute("draggable")&&o.setAttribute("draggable","true"):o.hasAttribute("draggable")&&o.removeAttribute("draggable")}onKeyDown(e){if(!this.config.enableKeyboard)return;if(!e.ctrlKey||"ArrowUp"!==e.key&&"ArrowDown"!==e.key)return;const t=this.internalGrid,r=t._focusRow,o=t._rows??this.sourceRows;if(r<0||r>=o.length)return;const i="up"===("ArrowUp"===e.key?"up":"down")?r-1:r+1;if(i<0||i>=o.length)return;const n=o[r];return this.canMoveRow(r,i)?(this.handleKeyboardMove(n,r,i,t._focusCol),e.preventDefault(),e.stopPropagation(),!0):void 0}onCellClick(){this.flushPendingMove()}moveRow(e,t){const r=[...this.sourceRows];e<0||e>=r.length||t<0||t>=r.length||e!==t&&this.canMoveRow(e,t)&&this.executeIntraGridMove(r[e],e,t,"keyboard")}canMoveRow(e,t){const r=this.internalGrid._rows??this.sourceRows;if(e<0||e>=r.length)return!1;if(t<0||t>=r.length)return!1;if(e===t)return!1;const o=r[e],i=this.grid?.query?.("canMoveRow",o);if(Array.isArray(i)&&i.includes(!1))return!1;if(this.config.canDrag&&!this.config.canDrag(o,e))return!1;if(this.config.canMove){const r=t<e?"up":"down";if(!this.config.canMove(o,e,t,r))return!1}if(this.config.canDrop){const r={sessionId:"intra",sourceGridId:this.gridId,dropZone:this.config.dropZone??"",rows:[o],rowIndices:[e],operation:"move"};if(!this.config.canDrop(r,t))return!1}return!0}setupDelegatedDragListeners(){const e=this.gridElement;if(!e)return;const t=this.disconnectSignal;e.addEventListener("dragstart",e=>this.onDragStart(e),{signal:t}),e.addEventListener("dragend",()=>this.onDragEnd(),{signal:t}),e.addEventListener("dragover",e=>this.onDragOver(e),{signal:t}),e.addEventListener("dragleave",e=>this.onDragLeave(e),{signal:t}),e.addEventListener("drop",e=>this.onDrop(e),{signal:t})}onDragStart(e){const o=e.target;if(!o)return;const i=o.closest(".dg-row-drag-handle");let s=null,a=!1;if(i)s=i.closest(".data-grid-row"),a=!0;else if(this.rowIsDraggable){if(this.isInteractiveDragOrigin(o))return;s=o.closest(".data-grid-row")}if(!s)return;const d=this.getRowIndex(s);if(d<0)return;const{rows:c,indices:l}=this.resolveDraggedRows(d);if(0===c.length)return;if(this.config.canDrag&&!this.config.canDrag(c[0],d))return void e.preventDefault();const g=this.config.operation??"move",u=this.config.dropZone??"",f=n(),h={rows:c,indices:l,operation:g,dropZone:u};if(this.emitCancelable("row-drag-start",h))return void e.preventDefault();this.isDragging=!0,this.draggedRowIndex=d,this.draggedRows=c,this.draggedIndices=l,this.dragSessionId=f,this.dragAccepted=!1;const p=this.config.serializeRow??(e=>e),w={sessionId:f,sourceGridId:this.gridId,dropZone:u,rows:c.map(p),rowIndices:l,operation:g};if(e.dataTransfer){e.dataTransfer.effectAllowed="copy"===g?"copyMove":"move";try{e.dataTransfer.setData(y,x(w)),u&&e.dataTransfer.setData(`${y};zone=${encodeURIComponent(u)}`,x(w)),e.dataTransfer.setData("text/plain",function(e,t){const r=t.filter(e=>!e.utility&&"string"==typeof e.field&&""!==e.field),o=[];for(const i of e){const e=r.map(e=>{const t=i[e.field];return null==t?"":String(t).replace(/[\t\r\n]+/g," ")});o.push(e.join("\t"))}return o.join("\n")}(c,this.columns))}catch{}if(c.length>1){const t=document.createElement("div");t.className="tbw-row-drag-count",t.textContent=`${c.length} rows`,document.body.appendChild(t);try{e.dataTransfer.setDragImage(t,10,10)}catch{}setTimeout(()=>t.remove(),0)}else this.attachRowCloneDragImage(e,s,a?i:null)}!function(e,t,o){const i=[];let n=!1;for(const r of t)null!==r&&"object"==typeof r?i.push(new WeakRef(r)):n=!0;r.set(e,{refs:i,hasPrimitives:n,meta:o})}(f,c),function(e,t){b={sessionId:e,payload:t}}(f,w),s.classList.add(t),this.gridElement.classList.add("tbw-grid--drag-source")}static INTERACTIVE_DRAG_SELECTORS='input,textarea,select,button,a,[contenteditable=""],[contenteditable="true"],.dg-cell-editor,.tbw-checkbox-cell';isInteractiveDragOrigin(e){return null!==e.closest(A.INTERACTIVE_DRAG_SELECTORS)}attachRowCloneDragImage(e,t,r){if(!e.dataTransfer)return;const o=t.getBoundingClientRect(),i=t.cloneNode(!0);i.classList.add("tbw-row-drag-clone"),i.classList.remove("dragging","drop-target","drop-before","drop-after","flip-animating","row-focus"),i.removeAttribute("aria-selected"),i.style.width=`${o.width}px`,i.style.height=`${o.height}px`,this.gridElement.appendChild(i);let n=e.clientX-o.left,s=e.clientY-o.top;if(r){const e=r.getBoundingClientRect();n=e.left-o.left+e.width/2,s=e.top-o.top+e.height/2}n=Math.max(0,Math.min(o.width,n)),s=Math.max(0,Math.min(o.height,s));try{e.dataTransfer.setDragImage(i,n,s)}catch{}setTimeout(()=>i.remove(),0)}onDragOver(e){const t=e.dataTransfer;if(!t)return;const r=t.types?Array.from(t.types):[];if(!function(e){for(const t of e)if(t===y||t.startsWith(`${y};`))return!0;return!1}(r)&&!this.isDragging)return;const o=this.config.dropZone??"",i=v(),n=this.isDragging&&i?.payload.sourceGridId===this.gridId;if(!n){if(!o)return;const e=function(e,t){for(const r of e)if(R(r)===t)return r;return null}(r,o);if(!(e||i&&i.payload.dropZone===o))return}e.preventDefault(),t&&(t.dropEffect=i?.payload.operation??this.config.operation??"move");const s=e.target.closest(".data-grid-row"),a=this.internalGrid._rows??[],d=D(s,e.clientY,e=>this.getRowIndex(e),a.length);if(n&&null!==d.overIndex&&d.overIndex===this.draggedRowIndex)this.clearDropTargetClasses();else{if(i&&this.config.canDrop){const e=this.config.canDrop(i.payload,d.insertIndex);if(this.gridElement.classList.toggle("tbw-grid--drop-target-active",e),this.gridElement.classList.toggle("tbw-grid--drop-target-rejected",!e),!e)return void this.clearDropTargetClasses()}else this.gridElement.classList.add("tbw-grid--drop-target-active");this.dropRowIndex=d.insertIndex,this.applyDropPositionClasses(s,d.isBefore),!1!==this.config.autoScroll&&(this.ensureAutoScroller(),this.autoScroller?.onPointerMove(e.clientY))}}onDragLeave(e){const t=e.target.closest(".data-grid-row");t&&t.classList.remove("drop-target","drop-before","drop-after"),e.currentTarget&&!this.gridElement.contains(e.relatedTarget)&&(this.gridElement.classList.remove("tbw-grid--drop-target-active","tbw-grid--drop-target-rejected"),this.autoScroller?.stop())}onDrop(e){e.preventDefault(),this.autoScroller?.stop(),this.gridElement.classList.remove("tbw-grid--drop-target-active","tbw-grid--drop-target-rejected"),this.clearDropTargetClasses();const t=e.dataTransfer;if(!t)return;const r=v();let i=r?.payload??null,n=null;if(i){const e=o(i.sessionId);e&&(n=e)}else{if(i=function(e){if(!e)return null;try{const t=JSON.parse(e);if("string"!=typeof t?.sessionId||"string"!=typeof t?.sourceGridId||"string"!=typeof t?.dropZone||!Array.isArray(t?.rows)||!Array.isArray(t?.rowIndices)||"move"!==t.operation&&"copy"!==t.operation)return null;for(const e of t.rowIndices)if("number"!=typeof e||!Number.isInteger(e)||e<0)return null;return t}catch{return null}}(t.getData(y)),i){const e=o(i.sessionId);e&&(n=e)}}if(!i)return;const s=e.target.closest(".data-grid-row"),a=this.internalGrid._rows??[],d=D(s,e.clientY,e=>this.getRowIndex(e),a.length);let c=this.dropRowIndex??d.insertIndex;const l=i.sourceGridId===this.gridId,g=this.config.dropZone??"";if(l){const e=i.rowIndices[0];if(1===i.rowIndices.length&&c>e&&c--,e===c)return;const t=(n??i.rows)[0];if(!this.canMoveRow(e,c))return;return void this.executeIntraGridMove(t,e,c,"drag")}if(!g||g!==i.dropZone)return;if(this.config.canDrop&&!this.config.canDrop(i,c))return this.gridElement.classList.add("tbw-grid--drop-target-rejected"),void setTimeout(()=>this.gridElement.classList.remove("tbw-grid--drop-target-rejected"),200);const u=this.config.deserializeRow??(e=>e),f=n??i.rows.map(e=>u(e)),h={payload:i,sourceGridId:i.sourceGridId,targetIndex:c,operation:i.operation};if(this.emitCancelable("row-drop",h))return;const p=[...a];p.splice(c,0,...f),this.grid.rows=p;const w=this.findPeerOnGrid(i.sourceGridId);if("move"===i.operation&&w){const e=document.getElementById(i.sourceGridId);if(e){const t=(e._rows??e.rows??[]).slice(),r=[...i.rowIndices].sort((e,t)=>t-e);for(const e of r)e>=0&&e<t.length&&t.splice(e,1);e.rows=t}}w&&(w.dragAccepted=!0);const m={rows:f,fromGridId:i.sourceGridId,toGridId:this.gridId,fromIndices:i.rowIndices,toIndex:c,operation:i.operation};this.emit("row-transfer",m),w?w.emitTransfer(m):function(e){const t=_();if(t)try{t.postMessage(e)}catch{}}({type:"tbw-row-drag-drop:transfer",sessionId:i.sessionId,sourceGridId:i.sourceGridId,toGridId:this.gridId,dropZone:g,rowIndices:i.rowIndices,toIndex:c,operation:i.operation,serializedRows:i.rows})}onRemoteTransfer(e){if(e.sourceGridId!==this.gridId)return;const t=this.config.dropZone??"";if(!t||e.dropZone!==t)return;const r=this.config.deserializeRow??(e=>e),o=e.serializedRows.map(e=>r(e));if("move"===e.operation){const t=(this.internalGrid._rows??this.sourceRows).slice(),r=[...e.rowIndices].sort((e,t)=>t-e);for(const e of r)e>=0&&e<t.length&&t.splice(e,1);this.grid.rows=t}this.dragAccepted=!0,this.emit("row-transfer",{rows:o,fromGridId:e.sourceGridId,toGridId:e.toGridId,fromIndices:e.rowIndices,toIndex:e.toIndex,operation:e.operation})}onDragEnd(){if(this.dragSessionId&&i(this.dragSessionId),I(),this.autoScroller?.stop(),this.gridElement.classList.remove("tbw-grid--drag-source"),this.isDragging){const e={rows:this.draggedRows,indices:this.draggedIndices,accepted:this.dragAccepted};this.emit("row-drag-end",e)}this.clearDragClasses(),this.resetDragState()}emitTransfer(e){this.emit("row-transfer",e)}findPeerOnGrid(e){const t=document.getElementById(e);return t?.getPluginByName?t.getPluginByName("rowDragDrop")??null:null}resolveDraggedRows(e){const t=this.internalGrid._rows??this.sourceRows,r=t[e],o=this.grid?.getPluginByName?.("selection");if(o?.getSelectedRowIndices){const r=o.getSelectedRowIndices();if(r.includes(e)&&r.length>1){const e=[...r].sort((e,t)=>e-t);return{rows:e.map(e=>t[e]),indices:e}}}return{rows:[r],indices:[e]}}ensureAutoScroller(){if(this.autoScroller)return;const e=this.gridElement.querySelector(".rows-viewport");if(!e)return;const t="object"==typeof this.config.autoScroll?this.config.autoScroll:void 0;this.autoScroller=function(e,t={},r){const o=t.edgeSize??60,i=t.speed??8,n=t.maxSpeed??24;let s=null,a=null,d=!1;const c=e=>{e!==d&&(d=e,r?.(e))},l=()=>{if(s=null,null===a)return void c(!1);const t=e.getBoundingClientRect();let r=0;if(a<t.top+o){const e=1-Math.max(0,a-t.top)/o;r=-Math.round(i+(n-i)*e)}else if(a>t.bottom-o){const e=1-Math.max(0,t.bottom-a)/o;r=Math.round(i+(n-i)*e)}if(0===r)return void c(!1);const d=e.scrollTop;e.scrollTop=d+r,e.scrollTop!==d?(c(!0),s=requestAnimationFrame(l)):c(!1)};return{onPointerMove(e){a=e,null===s&&(s=requestAnimationFrame(l))},stop(){null!==s&&(cancelAnimationFrame(s),s=null),a=null,c(!1)},get isScrolling(){return d}}}(e,t,e=>{this.gridElement.classList.toggle("tbw-grid--auto-scrolling",e)})}applyDropPositionClasses(e,t){this.clearDropTargetClasses(),e&&(e.classList.add("drop-target"),e.classList.toggle("drop-before",t),e.classList.toggle("drop-after",!t))}clearDropTargetClasses(){this.gridElement?.querySelectorAll(".data-grid-row.drop-target").forEach(e=>{e.classList.remove("drop-target","drop-before","drop-after")})}clearDragClasses(){this.gridElement?.querySelectorAll(".data-grid-row").forEach(e=>{e.classList.remove(t,"drop-target","drop-before","drop-after")})}resetDragState(){this.isDragging=!1,this.draggedRowIndex=null,this.draggedRows=[],this.draggedIndices=[],this.dragSessionId=null,this.dragAccepted=!1,this.dropRowIndex=null,this.pendingMove=null}getRowIndex(e){const t=e.querySelector(".cell[data-row]");return t?parseInt(t.getAttribute("data-row")??"-1",10):-1}clearDebounceTimer(){this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=null)}handleKeyboardMove(e,t,r,o){this.pendingMove?this.pendingMove.currentIndex=r:this.pendingMove={originalIndex:t,currentIndex:r,row:e},this.lastFocusCol=o;const i=this.internalGrid,n=[...i._rows??this.sourceRows],[s]=n.splice(t,1);n.splice(r,0,s),i._rows=n,i._focusRow=r,i._focusCol=o,i.refreshVirtualWindow(!0),p(i),this.clearDebounceTimer(),this.debounceTimer=setTimeout(()=>this.flushPendingMove(),this.config.debounceMs??300)}flushPendingMove(){if(this.clearDebounceTimer(),!this.pendingMove)return;const{originalIndex:e,currentIndex:t,row:r}=this.pendingMove;if(this.pendingMove=null,e===t)return;const o=this.internalGrid,i={row:r,fromIndex:e,toIndex:t,rows:[...o._rows??this.sourceRows],source:"keyboard"};this.emitCancelable("row-move",i)&&(o._rows=[...this.sourceRows],o._focusRow=e,o._focusCol=this.lastFocusCol,o.refreshVirtualWindow(!0),p(o))}executeIntraGridMove(e,t,r,o){const i=[...this.sourceRows],[n]=i.splice(t,1);i.splice(r,0,n);const s={row:e,fromIndex:t,toIndex:r,rows:i,source:o};if(!this.emitCancelable("row-move",s))if("flip"===this.animationType&&this.gridElement){const e=this.captureRowPositions();this.grid.rows=i,requestAnimationFrame(()=>{this.gridElement.offsetHeight,this.animateFLIP(e,t,r)})}else this.grid.rows=i}captureRowPositions(){const e=/* @__PURE__ */new Map;return this.gridElement?.querySelectorAll(".data-grid-row").forEach(t=>{const r=this.getRowIndex(t);r>=0&&e.set(r,t.getBoundingClientRect().top)}),e}animateFLIP(e,t,r){const o=this.gridElement;if(!o||0===e.size)return;const i=Math.min(t,r),n=Math.max(t,r),s=[];if(o.querySelectorAll(".data-grid-row").forEach(o=>{const a=o,d=this.getRowIndex(a);if(d<0||d<i||d>n)return;let c;c=d===r?t:t<r?d+1:d-1;const l=e.get(c);if(void 0===l)return;const g=l-a.getBoundingClientRect().top;Math.abs(g)>1&&s.push({el:a,deltaY:g})}),0===s.length)return;s.forEach(({el:e,deltaY:t})=>{e.style.transform=`translateY(${t}px)`}),o.offsetHeight;const a=this.animationDuration;requestAnimationFrame(()=>{s.forEach(({el:e})=>{e.classList.add("flip-animating"),e.style.transform=""}),setTimeout(()=>{s.forEach(({el:e})=>{e.style.transform="",e.classList.remove("flip-animating")})},a+50)})}}export{E as ROW_DRAG_HANDLE_FIELD,A as RowDragDropPlugin};
2
+ //# sourceMappingURL=index.js.map