@toolbox-web/grid 0.4.0 → 0.4.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/README.md +10 -13
- package/all.js +1124 -1047
- package/all.js.map +1 -1
- package/index.js +688 -515
- package/index.js.map +1 -1
- package/lib/core/grid.d.ts +10 -0
- package/lib/core/grid.d.ts.map +1 -1
- package/lib/core/internal/config-manager.d.ts +1 -0
- package/lib/core/internal/config-manager.d.ts.map +1 -1
- package/lib/core/internal/keyboard.d.ts.map +1 -1
- package/lib/core/internal/utils.d.ts +1 -0
- package/lib/core/internal/utils.d.ts.map +1 -1
- package/lib/core/internal/validate-config.d.ts +14 -0
- package/lib/core/internal/validate-config.d.ts.map +1 -1
- package/lib/core/plugin/base-plugin.d.ts +105 -1
- package/lib/core/plugin/base-plugin.d.ts.map +1 -1
- package/lib/core/plugin/expander-column.d.ts +51 -0
- package/lib/core/plugin/expander-column.d.ts.map +1 -0
- package/lib/core/plugin/index.d.ts +1 -0
- package/lib/core/plugin/index.d.ts.map +1 -1
- package/lib/core/plugin/plugin-manager.d.ts +1 -1
- package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
- package/lib/core/plugin/types.d.ts +117 -1
- package/lib/core/plugin/types.d.ts.map +1 -1
- package/lib/core/types.d.ts +4 -2
- package/lib/core/types.d.ts.map +1 -1
- package/lib/plugins/clipboard/ClipboardPlugin.d.ts +9 -2
- package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
- package/lib/plugins/clipboard/index.d.ts +1 -1
- package/lib/plugins/clipboard/index.d.ts.map +1 -1
- package/lib/plugins/clipboard/index.js +303 -185
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/clipboard/types.d.ts +72 -2
- package/lib/plugins/clipboard/types.d.ts.map +1 -1
- package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
- package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
- package/lib/plugins/column-virtualization/index.js +116 -24
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
- package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
- package/lib/plugins/context-menu/index.js +164 -72
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/editing/EditingPlugin.d.ts +1 -7
- package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
- package/lib/plugins/editing/index.js +213 -133
- package/lib/plugins/editing/index.js.map +1 -1
- package/lib/plugins/export/ExportPlugin.d.ts +0 -1
- package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
- package/lib/plugins/export/index.js +195 -103
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/FilteringPlugin.d.ts +5 -2
- package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
- package/lib/plugins/filtering/index.js +145 -43
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +1 -2
- package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
- package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
- package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
- package/lib/plugins/grouping-columns/index.js +162 -68
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
- package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
- package/lib/plugins/grouping-rows/index.js +246 -138
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
- package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
- package/lib/plugins/master-detail/index.js +281 -196
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/master-detail/types.d.ts +0 -10
- package/lib/plugins/master-detail/types.d.ts.map +1 -1
- package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
- package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
- package/lib/plugins/multi-sort/index.js +121 -31
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
- package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
- package/lib/plugins/pinned-columns/index.js +144 -52
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
- package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
- package/lib/plugins/pinned-rows/index.js +178 -88
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
- package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
- package/lib/plugins/pivot/index.js +414 -310
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
- package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
- package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
- package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
- package/lib/plugins/reorder/index.js +304 -226
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
- package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
- package/lib/plugins/selection/index.d.ts +2 -2
- package/lib/plugins/selection/index.d.ts.map +1 -1
- package/lib/plugins/selection/index.js +292 -145
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/selection/types.d.ts +24 -0
- package/lib/plugins/selection/types.d.ts.map +1 -1
- package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
- package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
- package/lib/plugins/server-side/index.js +95 -3
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/TreePlugin.d.ts +5 -1
- package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
- package/lib/plugins/tree/index.js +213 -112
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/tree/types.d.ts +0 -10
- package/lib/plugins/tree/types.d.ts.map +1 -1
- package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +7 -2
- package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
- package/lib/plugins/undo-redo/index.js +112 -12
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/VisibilityPlugin.d.ts +14 -5
- package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
- package/lib/plugins/visibility/index.js +168 -65
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/umd/grid.all.umd.js +21 -17
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +14 -8
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/clipboard.umd.js +5 -7
- package/umd/plugins/clipboard.umd.js.map +1 -1
- package/umd/plugins/column-virtualization.umd.js +1 -1
- package/umd/plugins/column-virtualization.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/export.umd.js +1 -1
- package/umd/plugins/export.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-columns.umd.js +1 -1
- package/umd/plugins/grouping-columns.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/pinned-columns.umd.js +1 -1
- package/umd/plugins/pinned-columns.umd.js.map +1 -1
- package/umd/plugins/pinned-rows.umd.js +1 -1
- package/umd/plugins/pinned-rows.umd.js.map +1 -1
- package/umd/plugins/pivot.umd.js +1 -1
- package/umd/plugins/pivot.umd.js.map +1 -1
- package/umd/plugins/reorder.umd.js +1 -1
- package/umd/plugins/reorder.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/umd/plugins/visibility.umd.js +1 -1
- package/umd/plugins/visibility.umd.js.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const b = {
|
|
2
2
|
expand: "▶",
|
|
3
3
|
collapse: "▼",
|
|
4
4
|
sortAsc: "▲",
|
|
@@ -8,9 +8,28 @@ const R = {
|
|
|
8
8
|
dragHandle: "⋮⋮",
|
|
9
9
|
toolPanel: "☰"
|
|
10
10
|
};
|
|
11
|
-
class
|
|
12
|
-
/**
|
|
13
|
-
|
|
11
|
+
class x {
|
|
12
|
+
/**
|
|
13
|
+
* Plugin dependencies - declare other plugins this one requires.
|
|
14
|
+
*
|
|
15
|
+
* Dependencies are validated when the plugin is attached.
|
|
16
|
+
* Required dependencies throw an error if missing.
|
|
17
|
+
* Optional dependencies log an info message if missing.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* static readonly dependencies: PluginDependency[] = [
|
|
22
|
+
* { name: 'editing', required: true, reason: 'Tracks cell edits for undo/redo' },
|
|
23
|
+
* { name: 'selection', required: false, reason: 'Enables selection-based undo' },
|
|
24
|
+
* ];
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
static dependencies;
|
|
28
|
+
/**
|
|
29
|
+
* Plugin version - defaults to grid version for built-in plugins.
|
|
30
|
+
* Third-party plugins can override with their own semver.
|
|
31
|
+
*/
|
|
32
|
+
version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
|
|
14
33
|
/** CSS styles to inject into the grid's shadow DOM */
|
|
15
34
|
styles;
|
|
16
35
|
/** Custom cell renderers keyed by type name */
|
|
@@ -30,7 +49,7 @@ class I {
|
|
|
30
49
|
* Created fresh in attach(), aborted in detach().
|
|
31
50
|
* This ensures event listeners are properly cleaned up when plugins are re-attached.
|
|
32
51
|
*/
|
|
33
|
-
#
|
|
52
|
+
#t;
|
|
34
53
|
/**
|
|
35
54
|
* Default configuration - subclasses should override this getter.
|
|
36
55
|
* Note: This must be a getter (not property initializer) for proper inheritance
|
|
@@ -39,8 +58,8 @@ class I {
|
|
|
39
58
|
get defaultConfig() {
|
|
40
59
|
return {};
|
|
41
60
|
}
|
|
42
|
-
constructor(
|
|
43
|
-
this.userConfig =
|
|
61
|
+
constructor(t = {}) {
|
|
62
|
+
this.userConfig = t;
|
|
44
63
|
}
|
|
45
64
|
/**
|
|
46
65
|
* Called when the plugin is attached to a grid.
|
|
@@ -57,8 +76,8 @@ class I {
|
|
|
57
76
|
* }
|
|
58
77
|
* ```
|
|
59
78
|
*/
|
|
60
|
-
attach(
|
|
61
|
-
this.#
|
|
79
|
+
attach(t) {
|
|
80
|
+
this.#t?.abort(), this.#t = new AbortController(), this.grid = t, this.config = { ...this.defaultConfig, ...this.userConfig };
|
|
62
81
|
}
|
|
63
82
|
/**
|
|
64
83
|
* Called when the plugin is detached from a grid.
|
|
@@ -74,7 +93,7 @@ class I {
|
|
|
74
93
|
* ```
|
|
75
94
|
*/
|
|
76
95
|
detach() {
|
|
77
|
-
this.#
|
|
96
|
+
this.#t?.abort(), this.#t = void 0;
|
|
78
97
|
}
|
|
79
98
|
/**
|
|
80
99
|
* Get another plugin instance from the same grid.
|
|
@@ -88,14 +107,22 @@ class I {
|
|
|
88
107
|
* }
|
|
89
108
|
* ```
|
|
90
109
|
*/
|
|
91
|
-
getPlugin(
|
|
92
|
-
return this.grid?.getPlugin(
|
|
110
|
+
getPlugin(t) {
|
|
111
|
+
return this.grid?.getPlugin(t);
|
|
93
112
|
}
|
|
94
113
|
/**
|
|
95
114
|
* Emit a custom event from the grid.
|
|
96
115
|
*/
|
|
97
|
-
emit(
|
|
98
|
-
this.grid?.dispatchEvent?.(new CustomEvent(
|
|
116
|
+
emit(t, e) {
|
|
117
|
+
this.grid?.dispatchEvent?.(new CustomEvent(t, { detail: e, bubbles: !0 }));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Emit a cancelable custom event from the grid.
|
|
121
|
+
* @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
|
|
122
|
+
*/
|
|
123
|
+
emitCancelable(t, e) {
|
|
124
|
+
const o = new CustomEvent(t, { detail: e, bubbles: !0, cancelable: !0 });
|
|
125
|
+
return this.grid?.dispatchEvent?.(o), o.defaultPrevented;
|
|
99
126
|
}
|
|
100
127
|
/**
|
|
101
128
|
* Request a re-render of the grid.
|
|
@@ -103,6 +130,14 @@ class I {
|
|
|
103
130
|
requestRender() {
|
|
104
131
|
this.grid?.requestRender?.();
|
|
105
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Request a re-render and restore focus styling afterward.
|
|
135
|
+
* Use this when a plugin action (like expand/collapse) triggers a render
|
|
136
|
+
* but needs to maintain keyboard navigation focus.
|
|
137
|
+
*/
|
|
138
|
+
requestRenderWithFocus() {
|
|
139
|
+
this.grid?.requestRenderWithFocus?.();
|
|
140
|
+
}
|
|
106
141
|
/**
|
|
107
142
|
* Request a lightweight style update without rebuilding DOM.
|
|
108
143
|
* Use this instead of requestRender() when only CSS classes need updating.
|
|
@@ -136,6 +171,19 @@ class I {
|
|
|
136
171
|
get visibleColumns() {
|
|
137
172
|
return this.grid?._visibleColumns ?? [];
|
|
138
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the grid as an HTMLElement for direct DOM operations.
|
|
176
|
+
* Use sparingly - prefer the typed GridElementRef API when possible.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* const width = this.gridElement.clientWidth;
|
|
181
|
+
* this.gridElement.classList.add('my-plugin-active');
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
get gridElement() {
|
|
185
|
+
return this.grid;
|
|
186
|
+
}
|
|
139
187
|
/**
|
|
140
188
|
* Get the shadow root of the grid.
|
|
141
189
|
*/
|
|
@@ -160,16 +208,61 @@ class I {
|
|
|
160
208
|
* document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
|
|
161
209
|
*/
|
|
162
210
|
get disconnectSignal() {
|
|
163
|
-
return this.#
|
|
211
|
+
return this.#t?.signal ?? this.grid?.disconnectSignal;
|
|
164
212
|
}
|
|
165
213
|
/**
|
|
166
214
|
* Get the grid-level icons configuration.
|
|
167
215
|
* Returns merged icons (user config + defaults).
|
|
168
216
|
*/
|
|
169
217
|
get gridIcons() {
|
|
170
|
-
const
|
|
171
|
-
return { ...
|
|
218
|
+
const t = this.grid?.gridConfig?.icons ?? {};
|
|
219
|
+
return { ...b, ...t };
|
|
220
|
+
}
|
|
221
|
+
// #region Animation Helpers
|
|
222
|
+
/**
|
|
223
|
+
* Check if animations are enabled at the grid level.
|
|
224
|
+
* Respects gridConfig.animation.mode and the CSS variable set by the grid.
|
|
225
|
+
*
|
|
226
|
+
* Plugins should use this to skip animations when:
|
|
227
|
+
* - Animation mode is 'off' or `false`
|
|
228
|
+
* - User prefers reduced motion and mode is 'reduced-motion' (default)
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* private get animationStyle(): 'slide' | 'fade' | false {
|
|
233
|
+
* if (!this.isAnimationEnabled) return false;
|
|
234
|
+
* return this.config.animation ?? 'slide';
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
get isAnimationEnabled() {
|
|
239
|
+
const t = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
|
|
240
|
+
if (t === !1 || t === "off") return !1;
|
|
241
|
+
if (t === !0 || t === "on") return !0;
|
|
242
|
+
const e = this.shadowRoot?.host;
|
|
243
|
+
return e ? getComputedStyle(e).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
|
|
172
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Get the animation duration in milliseconds from CSS variable.
|
|
247
|
+
* Falls back to 200ms if not set.
|
|
248
|
+
*
|
|
249
|
+
* Plugins can use this for their animation timing to stay consistent
|
|
250
|
+
* with the grid-level animation.duration setting.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* element.animate(keyframes, { duration: this.animationDuration });
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
get animationDuration() {
|
|
258
|
+
const t = this.shadowRoot?.host;
|
|
259
|
+
if (t) {
|
|
260
|
+
const e = getComputedStyle(t).getPropertyValue("--tbw-animation-duration").trim(), o = parseInt(e, 10);
|
|
261
|
+
if (!isNaN(o)) return o;
|
|
262
|
+
}
|
|
263
|
+
return 200;
|
|
264
|
+
}
|
|
265
|
+
// #endregion
|
|
173
266
|
/**
|
|
174
267
|
* Resolve an icon value to string or HTMLElement.
|
|
175
268
|
* Checks plugin config first, then grid-level icons, then defaults.
|
|
@@ -178,8 +271,8 @@ class I {
|
|
|
178
271
|
* @param pluginOverride - Optional plugin-level override
|
|
179
272
|
* @returns The resolved icon value
|
|
180
273
|
*/
|
|
181
|
-
resolveIcon(
|
|
182
|
-
return
|
|
274
|
+
resolveIcon(t, e) {
|
|
275
|
+
return e !== void 0 ? e : this.gridIcons[t];
|
|
183
276
|
}
|
|
184
277
|
/**
|
|
185
278
|
* Set an icon value on an element.
|
|
@@ -188,80 +281,81 @@ class I {
|
|
|
188
281
|
* @param element - The element to set the icon on
|
|
189
282
|
* @param icon - The icon value (string or HTMLElement)
|
|
190
283
|
*/
|
|
191
|
-
setIcon(
|
|
192
|
-
typeof
|
|
284
|
+
setIcon(t, e) {
|
|
285
|
+
typeof e == "string" ? t.innerHTML = e : e instanceof HTMLElement && (t.innerHTML = "", t.appendChild(e.cloneNode(!0)));
|
|
193
286
|
}
|
|
194
287
|
/**
|
|
195
288
|
* Log a warning message.
|
|
196
289
|
*/
|
|
197
|
-
warn(
|
|
198
|
-
console.warn(`[tbw-grid:${this.name}] ${
|
|
290
|
+
warn(t) {
|
|
291
|
+
console.warn(`[tbw-grid:${this.name}] ${t}`);
|
|
199
292
|
}
|
|
200
293
|
// #endregion
|
|
201
294
|
}
|
|
202
|
-
function
|
|
203
|
-
|
|
204
|
-
return n.processCell(h, e, t);
|
|
205
|
-
if (h == null) return "";
|
|
206
|
-
if (h instanceof Date) return h.toISOString();
|
|
207
|
-
if (typeof h == "object") return JSON.stringify(h);
|
|
208
|
-
const i = String(h), l = n.delimiter ?? " ", o = n.newline ?? `
|
|
209
|
-
`;
|
|
210
|
-
return n.quoteStrings || i.includes(l) || i.includes(o) || i.includes('"') ? `"${i.replace(/"/g, '""')}"` : i;
|
|
295
|
+
function v(h) {
|
|
296
|
+
return h.meta?.utility === !0;
|
|
211
297
|
}
|
|
212
|
-
function
|
|
213
|
-
const { rows: e, columns: t, selectedIndices: n, config: i } = h, l = i.delimiter ?? " ", o = i.newline ?? `
|
|
214
|
-
`, r = t.filter((s) => !s.hidden && !s.field.startsWith("__")), c = [];
|
|
215
|
-
if (i.includeHeaders) {
|
|
216
|
-
const s = r.map((d) => {
|
|
217
|
-
const f = d.header || d.field;
|
|
218
|
-
return f.includes(l) || f.includes(o) || f.includes('"') ? `"${f.replace(/"/g, '""')}"` : f;
|
|
219
|
-
});
|
|
220
|
-
c.push(s.join(l));
|
|
221
|
-
}
|
|
222
|
-
const u = [...n instanceof Set ? [...n] : n].sort((s, d) => s - d);
|
|
223
|
-
for (const s of u) {
|
|
224
|
-
const d = e[s];
|
|
225
|
-
if (!d) continue;
|
|
226
|
-
const f = r.map(
|
|
227
|
-
(g) => T(d[g.field], g.field, d, i)
|
|
228
|
-
);
|
|
229
|
-
c.push(f.join(l));
|
|
230
|
-
}
|
|
231
|
-
return c.join(o);
|
|
232
|
-
}
|
|
233
|
-
async function C(h) {
|
|
298
|
+
async function R(h) {
|
|
234
299
|
try {
|
|
235
300
|
return await navigator.clipboard.writeText(h), !0;
|
|
236
301
|
} catch {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
return document.body.removeChild(
|
|
302
|
+
const t = document.createElement("textarea");
|
|
303
|
+
t.value = h, t.style.position = "fixed", t.style.opacity = "0", t.style.pointerEvents = "none", document.body.appendChild(t), t.select();
|
|
304
|
+
const e = document.execCommand("copy");
|
|
305
|
+
return document.body.removeChild(t), e;
|
|
241
306
|
}
|
|
242
307
|
}
|
|
243
|
-
function y(h,
|
|
244
|
-
const
|
|
245
|
-
`,
|
|
308
|
+
function y(h, t) {
|
|
309
|
+
const e = t.delimiter ?? " ", o = t.newline ?? `
|
|
310
|
+
`, a = h.replace(/\r\n/g, `
|
|
246
311
|
`).replace(/\r/g, `
|
|
247
|
-
`),
|
|
248
|
-
let
|
|
249
|
-
for (let
|
|
250
|
-
const
|
|
251
|
-
|
|
312
|
+
`), r = [];
|
|
313
|
+
let n = [], i = "", s = !1;
|
|
314
|
+
for (let c = 0; c < a.length; c++) {
|
|
315
|
+
const l = a[c];
|
|
316
|
+
l === '"' && !s ? s = !0 : l === '"' && s ? a[c + 1] === '"' ? (i += '"', c++) : s = !1 : l === e && !s ? (n.push(i), i = "") : l === o && !s ? (n.push(i), i = "", (n.length > 1 || n.some((w) => w.trim() !== "")) && r.push(n), n = []) : i += l;
|
|
252
317
|
}
|
|
253
|
-
return
|
|
318
|
+
return n.push(i), (n.length > 1 || n.some((c) => c.trim() !== "")) && r.push(n), r;
|
|
254
319
|
}
|
|
255
|
-
async function
|
|
320
|
+
async function I() {
|
|
256
321
|
try {
|
|
257
322
|
return await navigator.clipboard.readText();
|
|
258
323
|
} catch {
|
|
259
324
|
return "";
|
|
260
325
|
}
|
|
261
326
|
}
|
|
262
|
-
|
|
327
|
+
function P(h, t) {
|
|
328
|
+
const { rows: e, target: o, fields: a } = h;
|
|
329
|
+
if (!o) return;
|
|
330
|
+
const r = t.rows, i = (t.effectiveConfig.columns ?? []).map((l) => l.field), s = [...r], c = o.bounds ? o.bounds.endRow : 1 / 0;
|
|
331
|
+
e.forEach((l, w) => {
|
|
332
|
+
const u = o.row + w;
|
|
333
|
+
if (!(u > c)) {
|
|
334
|
+
if (o.bounds) {
|
|
335
|
+
if (u >= s.length)
|
|
336
|
+
return;
|
|
337
|
+
} else for (; u >= s.length; ) {
|
|
338
|
+
const f = {};
|
|
339
|
+
i.forEach((d) => f[d] = ""), s.push(f);
|
|
340
|
+
}
|
|
341
|
+
s[u] = { ...s[u] }, l.forEach((f, d) => {
|
|
342
|
+
const g = a[d];
|
|
343
|
+
g && (s[u][g] = f);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}), t.rows = s;
|
|
347
|
+
}
|
|
348
|
+
class E extends x {
|
|
349
|
+
/**
|
|
350
|
+
* Plugin dependencies - ClipboardPlugin works best with SelectionPlugin.
|
|
351
|
+
*
|
|
352
|
+
* Without SelectionPlugin: copies entire grid, pastes at row 0 col 0.
|
|
353
|
+
* With SelectionPlugin: copies/pastes based on selection.
|
|
354
|
+
*/
|
|
355
|
+
static dependencies = [
|
|
356
|
+
{ name: "selection", required: !1, reason: "Enables copy/paste of selected cells instead of entire grid" }
|
|
357
|
+
];
|
|
263
358
|
name = "clipboard";
|
|
264
|
-
version = "1.0.0";
|
|
265
359
|
get defaultConfig() {
|
|
266
360
|
return {
|
|
267
361
|
includeHeaders: !1,
|
|
@@ -276,137 +370,153 @@ class D extends I {
|
|
|
276
370
|
lastCopied = null;
|
|
277
371
|
// #endregion
|
|
278
372
|
// #region Lifecycle
|
|
373
|
+
attach(t) {
|
|
374
|
+
super.attach(t), t.addEventListener(
|
|
375
|
+
"paste",
|
|
376
|
+
(e) => this.#o(e),
|
|
377
|
+
{ signal: this.disconnectSignal }
|
|
378
|
+
);
|
|
379
|
+
}
|
|
279
380
|
detach() {
|
|
280
381
|
this.lastCopied = null;
|
|
281
382
|
}
|
|
282
383
|
// #endregion
|
|
283
384
|
// #region Event Handlers
|
|
284
|
-
onKeyDown(
|
|
285
|
-
|
|
286
|
-
return t ? (this.#e(e.target), !0) : n ? (this.#n(), !0) : !1;
|
|
385
|
+
onKeyDown(t) {
|
|
386
|
+
return (t.ctrlKey || t.metaKey) && t.key === "c" ? (this.#t(t.target), !0) : !1;
|
|
287
387
|
}
|
|
288
388
|
// #endregion
|
|
289
389
|
// #region Private Methods
|
|
290
390
|
/**
|
|
291
|
-
* Handle copy operation
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
startRow:
|
|
306
|
-
startCol:
|
|
307
|
-
endRow:
|
|
308
|
-
endCol:
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
} else
|
|
316
|
-
|
|
391
|
+
* Handle copy operation.
|
|
392
|
+
*
|
|
393
|
+
* Everything is treated as a range:
|
|
394
|
+
* - With selection: copies the selected range
|
|
395
|
+
* - Row mode: range spanning all columns for selected rows
|
|
396
|
+
* - No selection plugin: entire grid as a range
|
|
397
|
+
* - No selection: try to get focused cell from DOM as 1x1 range
|
|
398
|
+
*/
|
|
399
|
+
#t(t) {
|
|
400
|
+
const e = this.#e(), o = e?.getSelection(), a = this.columns.length - 1, r = this.rows.length - 1;
|
|
401
|
+
let n;
|
|
402
|
+
if (o && o.ranges.length > 0) {
|
|
403
|
+
const { mode: s, ranges: c } = o, l = c[c.length - 1];
|
|
404
|
+
s === "row" ? n = {
|
|
405
|
+
startRow: l.from.row,
|
|
406
|
+
startCol: 0,
|
|
407
|
+
endRow: l.to.row,
|
|
408
|
+
endCol: a
|
|
409
|
+
} : n = {
|
|
410
|
+
startRow: l.from.row,
|
|
411
|
+
startCol: l.from.col,
|
|
412
|
+
endRow: l.to.row,
|
|
413
|
+
endCol: l.to.col
|
|
414
|
+
};
|
|
415
|
+
} else if (!e)
|
|
416
|
+
n = { startRow: 0, startCol: 0, endRow: r, endCol: a };
|
|
417
|
+
else {
|
|
418
|
+
const s = this.#r(t);
|
|
317
419
|
if (!s) return;
|
|
318
|
-
|
|
420
|
+
n = { startRow: s.row, startCol: s.col, endRow: s.row, endCol: s.col };
|
|
319
421
|
}
|
|
320
|
-
|
|
321
|
-
|
|
422
|
+
const i = this.#n(n);
|
|
423
|
+
R(i.text).then(() => {
|
|
424
|
+
this.lastCopied = { text: i.text, timestamp: Date.now() }, this.emit("copy", {
|
|
425
|
+
text: i.text,
|
|
426
|
+
rowCount: i.rowCount,
|
|
427
|
+
columnCount: i.columnCount
|
|
428
|
+
});
|
|
322
429
|
});
|
|
323
430
|
}
|
|
324
431
|
/**
|
|
325
|
-
* Handle paste
|
|
432
|
+
* Handle native paste event (preferred method - works in iframes).
|
|
433
|
+
* Uses synchronous clipboardData from the native paste event.
|
|
434
|
+
*
|
|
435
|
+
* Flow:
|
|
436
|
+
* 1. Parse clipboard text
|
|
437
|
+
* 2. Build target/fields info from selection
|
|
438
|
+
* 3. Emit 'paste' event (for listeners)
|
|
439
|
+
* 4. Call paste handler (if configured) to apply data to grid
|
|
440
|
+
*
|
|
441
|
+
* Selection behavior:
|
|
442
|
+
* - Single cell: paste starts at cell, expands freely
|
|
443
|
+
* - Range/row: paste is clipped to fit within selection bounds
|
|
444
|
+
* - No selection: paste starts at row 0, col 0
|
|
326
445
|
*/
|
|
327
|
-
#
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
446
|
+
#o(t) {
|
|
447
|
+
const e = t.clipboardData?.getData("text/plain");
|
|
448
|
+
if (!e) return;
|
|
449
|
+
t.preventDefault();
|
|
450
|
+
const o = y(e, this.config), r = this.#e()?.getSelection(), n = r?.ranges?.[0], i = n?.from.row ?? 0, s = n?.from.col ?? 0, l = n && (r?.mode === "range" || r?.mode === "row") && (n.from.row !== n.to.row || n.from.col !== n.to.col) ? { endRow: n.to.row, endCol: n.to.col } : null, w = l?.endCol ?? this.columns.length - 1, u = this.columns[s], f = u ? { row: i, col: s, field: u.field, bounds: l } : null, d = [], g = o[0]?.length ?? 0;
|
|
451
|
+
for (let p = 0; p < g && s + p <= w; p++) {
|
|
452
|
+
const m = this.columns[s + p];
|
|
453
|
+
m && !m.hidden && d.push(m.field);
|
|
454
|
+
}
|
|
455
|
+
const C = { rows: o, text: e, target: f, fields: d };
|
|
456
|
+
this.emit("paste", C), this.#s(C);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Apply the paste handler to update grid data.
|
|
460
|
+
*
|
|
461
|
+
* Uses the configured `pasteHandler`, or the default handler if not specified.
|
|
462
|
+
* Set `pasteHandler: null` in config to disable auto-paste.
|
|
463
|
+
*/
|
|
464
|
+
#s(t) {
|
|
465
|
+
if (!this.grid) return;
|
|
466
|
+
const { pasteHandler: e } = this.config;
|
|
467
|
+
if (e === null) return;
|
|
468
|
+
(e ?? P)(t, this.grid);
|
|
333
469
|
}
|
|
334
470
|
/**
|
|
335
471
|
* Get the selection plugin instance if available.
|
|
336
472
|
*/
|
|
337
|
-
#
|
|
473
|
+
#e() {
|
|
338
474
|
try {
|
|
339
|
-
const
|
|
340
|
-
if (
|
|
341
|
-
return
|
|
475
|
+
const t = this.grid?.getPluginByName("selection");
|
|
476
|
+
if (t)
|
|
477
|
+
return t;
|
|
342
478
|
} catch {
|
|
343
479
|
}
|
|
344
480
|
}
|
|
345
|
-
/**
|
|
346
|
-
* Build text for a single cell by row/col index.
|
|
347
|
-
*/
|
|
348
|
-
#s(e, t) {
|
|
349
|
-
const n = this.rows[e];
|
|
350
|
-
if (!n) return null;
|
|
351
|
-
const i = this.columns[t];
|
|
352
|
-
if (!i) return null;
|
|
353
|
-
const l = n[i.field], o = i.header || i.field;
|
|
354
|
-
let r;
|
|
355
|
-
if (this.config.includeHeaders) {
|
|
356
|
-
const c = l == null ? "" : String(l);
|
|
357
|
-
r = `${o}: ${c}`;
|
|
358
|
-
} else
|
|
359
|
-
r = l == null ? "" : String(l);
|
|
360
|
-
return { text: r };
|
|
361
|
-
}
|
|
362
481
|
/**
|
|
363
482
|
* Build text for a rectangular range of cells.
|
|
483
|
+
* Utility columns (like expander columns) are automatically excluded.
|
|
364
484
|
*/
|
|
365
|
-
#
|
|
366
|
-
const { startRow:
|
|
367
|
-
`,
|
|
485
|
+
#n(t) {
|
|
486
|
+
const { startRow: e, startCol: o, endRow: a, endCol: r } = t, n = Math.min(e, a), i = Math.max(e, a), s = Math.min(o, r), c = Math.max(o, r), l = this.config.delimiter ?? " ", w = this.config.newline ?? `
|
|
487
|
+
`, u = [], f = this.columns.slice(s, c + 1).filter((d) => !v(d));
|
|
368
488
|
if (this.config.includeHeaders) {
|
|
369
|
-
const
|
|
370
|
-
|
|
489
|
+
const d = f.map((g) => g.header || g.field);
|
|
490
|
+
u.push(d.join(l));
|
|
371
491
|
}
|
|
372
|
-
for (let
|
|
373
|
-
const
|
|
374
|
-
if (!
|
|
375
|
-
const
|
|
376
|
-
const
|
|
377
|
-
return
|
|
492
|
+
for (let d = n; d <= i; d++) {
|
|
493
|
+
const g = this.rows[d];
|
|
494
|
+
if (!g) continue;
|
|
495
|
+
const C = f.map((p) => {
|
|
496
|
+
const m = g[p.field];
|
|
497
|
+
return m == null ? "" : m instanceof Date ? m.toISOString() : String(m);
|
|
378
498
|
});
|
|
379
|
-
|
|
499
|
+
u.push(C.join(l));
|
|
380
500
|
}
|
|
381
501
|
return {
|
|
382
|
-
text:
|
|
383
|
-
rowCount:
|
|
384
|
-
columnCount:
|
|
502
|
+
text: u.join(w),
|
|
503
|
+
rowCount: i - n + 1,
|
|
504
|
+
columnCount: c - s + 1
|
|
385
505
|
};
|
|
386
506
|
}
|
|
387
507
|
/**
|
|
388
|
-
*
|
|
389
|
-
* Used
|
|
390
|
-
*/
|
|
391
|
-
#
|
|
392
|
-
const
|
|
393
|
-
if (!
|
|
394
|
-
const
|
|
395
|
-
if (!
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
const o = this.rows[l];
|
|
401
|
-
if (!o) return null;
|
|
402
|
-
const r = o[n], a = this.columns.find((s) => s.field === n)?.header || n;
|
|
403
|
-
let u;
|
|
404
|
-
if (this.config.includeHeaders) {
|
|
405
|
-
const s = r == null ? "" : String(r);
|
|
406
|
-
u = `${a}: ${s}`;
|
|
407
|
-
} else
|
|
408
|
-
u = r == null ? "" : String(r);
|
|
409
|
-
return { text: u, field: n, value: r };
|
|
508
|
+
* Get focused cell coordinates from DOM.
|
|
509
|
+
* Used as fallback when SelectionPlugin has no selection.
|
|
510
|
+
*/
|
|
511
|
+
#r(t) {
|
|
512
|
+
const e = t.closest("[data-field-cache]");
|
|
513
|
+
if (!e) return null;
|
|
514
|
+
const o = e.dataset.fieldCache, a = e.dataset.row;
|
|
515
|
+
if (!o || !a) return null;
|
|
516
|
+
const r = parseInt(a, 10);
|
|
517
|
+
if (isNaN(r)) return null;
|
|
518
|
+
const n = this.columns.findIndex((i) => i.field === o);
|
|
519
|
+
return n === -1 ? null : { row: r, col: n };
|
|
410
520
|
}
|
|
411
521
|
// #endregion
|
|
412
522
|
// #region Public API
|
|
@@ -415,35 +525,42 @@ class D extends I {
|
|
|
415
525
|
* @returns The copied text
|
|
416
526
|
*/
|
|
417
527
|
async copy() {
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
528
|
+
const e = this.#e()?.getSelection(), o = this.columns.length - 1;
|
|
529
|
+
let a = { startRow: 0, startCol: 0, endRow: this.rows.length - 1, endCol: o };
|
|
530
|
+
if (e && e.ranges.length > 0) {
|
|
531
|
+
const n = e.ranges[e.ranges.length - 1];
|
|
532
|
+
e.mode === "row" ? a = { startRow: n.from.row, startCol: 0, endRow: n.to.row, endCol: o } : a = {
|
|
533
|
+
startRow: n.from.row,
|
|
534
|
+
startCol: n.from.col,
|
|
535
|
+
endRow: n.to.row,
|
|
536
|
+
endCol: n.to.col
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const r = this.#n(a);
|
|
540
|
+
return await R(r.text), this.lastCopied = { text: r.text, timestamp: Date.now() }, r.text;
|
|
425
541
|
}
|
|
426
542
|
/**
|
|
427
543
|
* Copy specific rows by index to clipboard.
|
|
428
544
|
* @param indices - Array of row indices to copy
|
|
429
545
|
* @returns The copied text
|
|
430
546
|
*/
|
|
431
|
-
async copyRows(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
547
|
+
async copyRows(t) {
|
|
548
|
+
if (t.length === 0) return "";
|
|
549
|
+
const e = [...t].sort((n, i) => n - i), o = this.columns.length - 1, a = {
|
|
550
|
+
startRow: e[0],
|
|
551
|
+
startCol: 0,
|
|
552
|
+
endRow: e[e.length - 1],
|
|
553
|
+
endCol: o
|
|
554
|
+
}, r = this.#n(a);
|
|
555
|
+
return await R(r.text), this.lastCopied = { text: r.text, timestamp: Date.now() }, r.text;
|
|
439
556
|
}
|
|
440
557
|
/**
|
|
441
558
|
* Read and parse clipboard content.
|
|
442
559
|
* @returns Parsed 2D array of cell values, or null if clipboard is empty
|
|
443
560
|
*/
|
|
444
561
|
async paste() {
|
|
445
|
-
const
|
|
446
|
-
return
|
|
562
|
+
const t = await I();
|
|
563
|
+
return t ? y(t, this.config) : null;
|
|
447
564
|
}
|
|
448
565
|
/**
|
|
449
566
|
* Get the last copied text and timestamp.
|
|
@@ -455,6 +572,7 @@ class D extends I {
|
|
|
455
572
|
// #endregion
|
|
456
573
|
}
|
|
457
574
|
export {
|
|
458
|
-
|
|
575
|
+
E as ClipboardPlugin,
|
|
576
|
+
P as defaultPasteHandler
|
|
459
577
|
};
|
|
460
578
|
//# sourceMappingURL=index.js.map
|