@toolbox-web/grid-react 2.0.0-rc.0 → 2.0.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.
@@ -1,518 +0,0 @@
1
- import { useRef as k, useCallback as B, useEffect as D } from "react";
2
- import { p as M, n as A, c as S } from "./react-column-config-BOe_PgL1.js";
3
- import { jsx as F } from "react/jsx-runtime";
4
- import { a as f, r as p, b as N, e as U } from "./portal-bridge-CvxNt40O.js";
5
- const v = /* @__PURE__ */ new Set();
6
- let b = null;
7
- function x(n) {
8
- v.has(n) || (v.add(n), b = null);
9
- }
10
- function J() {
11
- return b === null && (b = Object.freeze(Array.from(v))), b;
12
- }
13
- const G = [
14
- "selection",
15
- "editing",
16
- "filtering",
17
- "multiSort",
18
- "clipboard",
19
- "contextMenu",
20
- "reorderColumns",
21
- "rowDragDrop",
22
- "visibility",
23
- "undoRedo",
24
- "tree",
25
- "groupingRows",
26
- "groupingColumns",
27
- "pinnedColumns",
28
- "pinnedRows",
29
- "masterDetail",
30
- "responsive",
31
- "columnVirtualization",
32
- "export",
33
- "print",
34
- "pivot",
35
- "serverSide",
36
- "tooltip"
37
- ];
38
- for (const n of G)
39
- x(n);
40
- const R = /* @__PURE__ */ new WeakMap(), P = /* @__PURE__ */ new Map();
41
- function I(n) {
42
- const e = R.get(n);
43
- if (e) return e;
44
- const t = n.id;
45
- if (t)
46
- return P.get(t);
47
- }
48
- function Q(n) {
49
- const { id: e, title: t, icon: r, tooltip: i, order: s = 100, children: o } = n, d = k(null), c = B(
50
- (a) => {
51
- d.current = a, a && (R.set(a, o), e && P.set(e, o));
52
- },
53
- [o, e]
54
- );
55
- return D(() => () => {
56
- const a = d.current;
57
- a && (R.delete(a), e && P.delete(e));
58
- }, [e]), /* @__PURE__ */ F(
59
- "tbw-grid-tool-panel",
60
- {
61
- ref: c,
62
- id: e,
63
- title: t,
64
- icon: r,
65
- tooltip: i,
66
- order: s?.toString()
67
- }
68
- );
69
- }
70
- let m = null, K = null, w = null;
71
- function X(n) {
72
- m = n;
73
- }
74
- function Z(n) {
75
- K = n;
76
- }
77
- function $(n) {
78
- w = n;
79
- }
80
- const l = /* @__PURE__ */ new WeakMap(), u = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new WeakMap(), W = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Set();
81
- function O(n) {
82
- return n.closest("tbw-grid, [data-tbw-grid]") ?? void 0;
83
- }
84
- function y(n, e) {
85
- const t = O(n);
86
- if (!t)
87
- return W;
88
- const r = T.get(t);
89
- if (r || !e)
90
- return r;
91
- const i = /* @__PURE__ */ new Map();
92
- return T.set(t, i), i;
93
- }
94
- function h(n) {
95
- return n.tagName.toLowerCase() === "tbw-grid-type" ? n.getAttribute("name") : n.closest("tbw-grid-type")?.getAttribute("name") ?? null;
96
- }
97
- function ee(n, e) {
98
- const t = n.getAttribute("field"), r = l.get(n) ?? {};
99
- if (r.renderer = e, l.set(n, r), t) {
100
- const i = u.get(t) ?? {};
101
- i.renderer = e, u.set(t, i);
102
- }
103
- }
104
- function te(n, e) {
105
- const t = n.getAttribute("field"), r = l.get(n) ?? {};
106
- if (r.editor = e, l.set(n, r), t) {
107
- const i = u.get(t) ?? {};
108
- i.editor = e, u.set(t, i);
109
- }
110
- }
111
- function _(n) {
112
- let e = l.get(n)?.renderer;
113
- if (!e) {
114
- const t = n.getAttribute("field");
115
- t && (e = u.get(t)?.renderer);
116
- }
117
- return e;
118
- }
119
- function j(n) {
120
- let e = l.get(n)?.editor;
121
- if (!e) {
122
- const t = n.getAttribute("field");
123
- t && (e = u.get(t)?.editor);
124
- }
125
- return e;
126
- }
127
- function re(n, e) {
128
- const t = h(n);
129
- if (!t) return;
130
- const r = y(n, !0);
131
- if (!r) return;
132
- const i = r.get(t) ?? {};
133
- i.renderer = e, r.set(t, i), E.add(t);
134
- }
135
- function z(n) {
136
- const e = h(n);
137
- return e ? y(n, !1)?.get(e)?.renderer : void 0;
138
- }
139
- function ne(n, e) {
140
- const t = h(n);
141
- if (!t) return;
142
- const r = y(n, !0);
143
- if (!r) return;
144
- const i = r.get(t) ?? {};
145
- i.editor = e, r.set(t, i), E.add(t);
146
- }
147
- function L(n) {
148
- const e = h(n);
149
- return e ? y(n, !1)?.get(e)?.editor : void 0;
150
- }
151
- class ie {
152
- /** Portal keys for all managed portals (for cleanup on destroy). */
153
- allPortalKeys = /* @__PURE__ */ new Set();
154
- /** Portal keys for editor-specific portals (for per-cell cleanup via releaseCell). */
155
- editorPortalKeys = /* @__PURE__ */ new Set();
156
- /** Maps portal keys to their containers (for container-based lookups in releaseCell/unmount). */
157
- keyToContainer = /* @__PURE__ */ new Map();
158
- /**
159
- * Reverse index: container element → portal key. Maintained alongside
160
- * `keyToContainer` so `releaseCell` can resolve only the containers
161
- * actually inside the released cell (via `cellEl.querySelectorAll`)
162
- * instead of scanning every tracked portal — important for grids with
163
- * many cells, where `releaseCell` runs on every cell teardown.
164
- */
165
- containerToKey = /* @__PURE__ */ new WeakMap();
166
- /**
167
- * Per-editor `before-edit-close` listener teardown functions, keyed by portal key.
168
- *
169
- * The grid's editing plugin emits `before-edit-close` on the host `<tbw-grid>`
170
- * before tearing down a row's managed editors. React editors commonly write
171
- * `onBlur={commit}` to flush local state on click-away, but Tab / programmatic
172
- * row exit rebuilds the cell DOM synchronously without giving the focused
173
- * input a chance to fire `blur` first.
174
- *
175
- * To bridge that gap we call `.blur()` on the focused input inside the editor
176
- * container as soon as `before-edit-close` fires. The native `.blur()` method
177
- * is what React's event system actually observes — React 17+ delegates focus
178
- * events at the root by listening to `focusout` (bubbling) and mapping it to
179
- * `onBlur`. A bare `dispatchEvent(new FocusEvent('blur'))` would be ignored
180
- * by React because `blur` does not bubble. Calling the native `.blur()`
181
- * dispatches the full focus-loss chain (`blur` + `focusout`) and also moves
182
- * focus off the input — both desirable here since the editor DOM is about to
183
- * be torn down anyway.
184
- *
185
- * Mirrors the Angular adapter's `BaseGridEditor.onBeforeEditClose()` hook.
186
- * Requires zero per-editor code: any editor with `onBlur={commit}` is
187
- * automatically covered for Tab commits and programmatic row exit.
188
- */
189
- editorBeforeCloseUnsubs = /* @__PURE__ */ new Map();
190
- typeDefaults = null;
191
- /**
192
- * Sets the type defaults map for this adapter.
193
- * Called by DataGrid when it receives type defaults from context.
194
- *
195
- * @internal
196
- */
197
- setTypeDefaults(e) {
198
- this.typeDefaults = e;
199
- }
200
- /**
201
- * FrameworkAdapter.processConfig implementation.
202
- * Called automatically by the grid's `set gridConfig` setter.
203
- * Converts React renderer/editor functions to DOM-returning functions.
204
- */
205
- processConfig(e) {
206
- return M(e) ?? e;
207
- }
208
- /**
209
- * Determines if this adapter can handle the given element.
210
- * Checks if a renderer or editor is registered for this element.
211
- */
212
- canHandle(e) {
213
- const t = e.getAttribute("field");
214
- let r = l.get(e);
215
- if (!r && t) {
216
- const c = u.get(t);
217
- c && (c.renderer || c.editor) && (r = c, l.set(e, r));
218
- }
219
- const i = r?.renderer !== void 0, s = r?.editor !== void 0;
220
- if (r !== void 0 && (i || s))
221
- return !0;
222
- const o = h(e), d = o ? y(e, !1)?.get(o) : void 0;
223
- return !!d && (d.renderer !== void 0 || d.editor !== void 0);
224
- }
225
- /**
226
- * Creates a view renderer function that renders a React component
227
- * and returns its container DOM element.
228
- *
229
- * Uses a cell cache to reuse portals for performance - instead of
230
- * creating new portals on each render, we reuse existing ones and
231
- * update their content.
232
- *
233
- * Returns undefined if no renderer is registered for this element,
234
- * allowing the grid to use its default rendering.
235
- */
236
- createRenderer(e) {
237
- const t = _(e) ?? z(e);
238
- if (!t)
239
- return;
240
- const r = e.closest("tbw-grid, [data-tbw-grid]"), i = /* @__PURE__ */ new WeakMap();
241
- return (s) => {
242
- const o = s.cellEl;
243
- if (o) {
244
- const a = i.get(o);
245
- if (a) {
246
- if (o.contains(a.container))
247
- return f(a.container, t(s), a.portalKey), a.container;
248
- p(a.portalKey, { sync: !0 }), this.untrackPortal(a.portalKey), i.delete(o);
249
- }
250
- const g = document.createElement("div");
251
- g.className = "react-cell-renderer", g.style.display = "contents";
252
- const C = f(
253
- g,
254
- t(s),
255
- void 0,
256
- r ?? void 0
257
- );
258
- return i.set(o, { portalKey: C, container: g }), this.trackPortal(C, g, !1), g;
259
- }
260
- const d = document.createElement("div");
261
- d.className = "react-cell-renderer", d.style.display = "contents";
262
- const c = f(
263
- d,
264
- t(s),
265
- void 0,
266
- r ?? void 0
267
- );
268
- return this.trackPortal(c, d, !1), d;
269
- };
270
- }
271
- /**
272
- * Creates an editor spec that renders a React component
273
- * with commit/cancel callbacks passed as props.
274
- */
275
- createEditor(e) {
276
- const t = j(e) ?? L(e);
277
- if (!t)
278
- return () => document.createElement("div");
279
- const r = e.closest("tbw-grid, [data-tbw-grid]") ?? void 0;
280
- return (i) => {
281
- const s = document.createElement("div");
282
- s.className = "react-cell-editor", s.style.display = "contents";
283
- const o = f(
284
- s,
285
- t(i),
286
- void 0,
287
- r
288
- );
289
- return this.trackPortal(o, s, !0), r && this.editorBeforeCloseUnsubs.set(o, A(s, r)), s;
290
- };
291
- }
292
- /**
293
- * Creates a detail renderer function for MasterDetailPlugin.
294
- * Implementation is installed by `@toolbox-web/grid-react/features/master-detail`
295
- * via `registerDetailRendererBridge`. Returns undefined if the
296
- * master-detail feature has not been imported, or if no GridDetailPanel
297
- * was registered for this grid.
298
- */
299
- createDetailRenderer(e) {
300
- return m?.(e, this.bridgeContext);
301
- }
302
- /**
303
- * Framework adapter hook called by MasterDetailPlugin during attach().
304
- * Parses the <tbw-grid-detail> element and returns a React-based renderer.
305
- */
306
- parseDetailElement(e) {
307
- const t = e.closest("tbw-grid, [data-tbw-grid]");
308
- if (t)
309
- return this.createDetailRenderer(t);
310
- }
311
- /**
312
- * Creates a responsive card renderer function for ResponsivePlugin.
313
- * Implementation is installed by `@toolbox-web/grid-react/features/responsive`
314
- * via `registerResponsiveCardRendererBridge`. Returns undefined if
315
- * the responsive feature has not been imported, or if no GridResponsiveCard
316
- * was registered for this grid.
317
- */
318
- createResponsiveCardRenderer(e) {
319
- return K?.(e, this.bridgeContext);
320
- }
321
- /**
322
- * FrameworkAdapter hook called by ResponsivePlugin during attach().
323
- * Parses the `<tbw-grid-responsive-card>` element and delegates to
324
- * {@link createResponsiveCardRenderer}. Needed for parity with the Vue
325
- * and Angular adapters so ResponsivePlugin's standard lookup path works
326
- * for React users as well, not just via the imperative
327
- * `refreshResponsiveCardRenderer` hook in DataGrid.
328
- */
329
- parseResponsiveCardElement(e) {
330
- const t = e.closest("tbw-grid, [data-tbw-grid]");
331
- if (t)
332
- return this.createResponsiveCardRenderer(t);
333
- }
334
- /**
335
- * Creates a tool panel renderer from a light DOM element.
336
- * Renders React components into tool panel containers.
337
- */
338
- createToolPanelRenderer(e) {
339
- const t = I(e);
340
- if (!t)
341
- return;
342
- const r = e.closest("tbw-grid, [data-tbw-grid]");
343
- return (i) => {
344
- const o = f(i, t({
345
- grid: r ?? i
346
- }), void 0, r ?? void 0);
347
- return this.trackPortal(o, i, !1), () => {
348
- p(o, { sync: !0 }), this.untrackPortal(o);
349
- };
350
- };
351
- }
352
- /**
353
- * Gets type-level defaults from the type defaults map.
354
- *
355
- * This enables application-wide type defaults configured via GridTypeProvider.
356
- * The returned TypeDefault contains renderer/editor functions that render
357
- * React components into the grid's cells.
358
- *
359
- * @example
360
- * ```tsx
361
- * // App.tsx
362
- * const typeDefaults = {
363
- * country: {
364
- * renderer: (ctx) => <CountryBadge code={ctx.value} />,
365
- * editor: (ctx) => <CountrySelect value={ctx.value} onCommit={ctx.commit} />
366
- * }
367
- * };
368
- *
369
- * <GridTypeProvider defaults={typeDefaults}>
370
- * <App />
371
- * </GridTypeProvider>
372
- *
373
- * // Any grid with type: 'country' columns will use these components
374
- * ```
375
- */
376
- getTypeDefault(e, t) {
377
- if (!this.typeDefaults)
378
- return;
379
- const r = this.typeDefaults[e];
380
- if (!r)
381
- return;
382
- const i = {
383
- editorParams: r.editorParams
384
- };
385
- return r.renderer && (i.renderer = this.createTypeRenderer(r.renderer, t)), r.editor && (i.editor = this.createTypeEditor(r.editor, t)), r.filterPanelRenderer && w && (i.filterPanelRenderer = w(
386
- r.filterPanelRenderer,
387
- t,
388
- this.bridgeContext
389
- )), i;
390
- }
391
- /**
392
- * Creates a renderer function from a React render function for type defaults.
393
- * @internal
394
- */
395
- createTypeRenderer(e, t) {
396
- return (r) => {
397
- const i = document.createElement("span");
398
- i.style.display = "contents";
399
- const s = r.cellEl?.closest("tbw-grid, [data-tbw-grid]") ?? t, o = f(i, e(r), void 0, s);
400
- return this.trackPortal(o, i, !1), i;
401
- };
402
- }
403
- /**
404
- * Creates an editor function from a React render function for type defaults.
405
- * @internal
406
- */
407
- createTypeEditor(e, t) {
408
- return (r) => {
409
- const i = document.createElement("span");
410
- i.style.display = "contents";
411
- const s = f(i, e(r), void 0, t);
412
- return this.trackPortal(s, i, !0), i;
413
- };
414
- }
415
- // #region Portal tracking helpers
416
- /**
417
- * Stable bridge context handed to feature installers. Bound once per adapter
418
- * so feature bridges can call `trackPortal` without each invocation creating
419
- * a fresh closure.
420
- */
421
- bridgeContext = {
422
- trackPortal: (e, t, r) => this.trackPortal(e, t, r)
423
- };
424
- /** Register a portal key for lifecycle tracking. */
425
- trackPortal(e, t, r) {
426
- this.allPortalKeys.add(e), this.keyToContainer.set(e, t), this.containerToKey.set(t, e), r && this.editorPortalKeys.add(e);
427
- }
428
- /** Unregister a portal key from all tracking sets. */
429
- untrackPortal(e) {
430
- this.allPortalKeys.delete(e), this.editorPortalKeys.delete(e);
431
- const t = this.keyToContainer.get(e);
432
- this.keyToContainer.delete(e), t && this.containerToKey.delete(t);
433
- const r = this.editorBeforeCloseUnsubs.get(e);
434
- r && (r(), this.editorBeforeCloseUnsubs.delete(e));
435
- }
436
- // #endregion
437
- /**
438
- * Clean up all mounted portals.
439
- * Call this when the grid is unmounted.
440
- */
441
- destroy() {
442
- for (const e of this.allPortalKeys)
443
- p(e);
444
- this.allPortalKeys.clear(), this.editorPortalKeys.clear(), this.keyToContainer.clear();
445
- for (const e of this.editorBeforeCloseUnsubs.values()) e();
446
- this.editorBeforeCloseUnsubs.clear(), u.clear();
447
- }
448
- /**
449
- * Called when a cell's content is about to be wiped.
450
- *
451
- * Destroys editor portals AND renderer portals whose container is inside
452
- * the cell. Releasing renderers here is critical: the editing pipeline
453
- * runs `cell.innerHTML = ''` immediately after this returns, which
454
- * silently detaches React-managed renderer containers from the DOM.
455
- * If we leave the React root mounted, its fiber tree still believes
456
- * the now-orphaned children are present — a subsequent React commit
457
- * (e.g. the user's `onCellCommit` → `setRows`) tries to `removeChild`
458
- * those gone nodes and throws `NotFoundError` (issue #250).
459
- *
460
- * Calling this BEFORE the wipe lets React unmount cleanly while DOM
461
- * still matches its fiber tree. The `wrapReactRenderer` cache will
462
- * detect the missing entry on the next render and create a fresh
463
- * container — see the cache-validation defense in `createRenderer`
464
- * and `wrapReactRenderer` (`react-column-config.ts`).
465
- *
466
- * Also cleans up config-based editor and renderer roots
467
- * (from processGridConfig/wrapReactEditor/wrapReactRenderer) that
468
- * bypass the adapter's own portal tracking.
469
- */
470
- releaseCell(e) {
471
- const t = e.querySelectorAll(".react-cell-renderer, .react-cell-editor");
472
- for (const r of t) {
473
- const i = this.containerToKey.get(r);
474
- i && (p(i, { sync: !0 }), this.untrackPortal(i));
475
- }
476
- S(e);
477
- }
478
- /**
479
- * Unmount a specific container (called when cell is recycled).
480
- */
481
- unmount(e) {
482
- const t = this.containerToKey.get(e);
483
- t && (p(t), this.untrackPortal(t));
484
- }
485
- /**
486
- * Open a teardown batch on the PortalManager. Grid core wraps multi-cell
487
- * release loops (`_clearRowPool`, row-pool shrink, full row rebuild) with
488
- * `beginBatch` / `endBatch` so the N per-cell sync removals collapse to a
489
- * single deferred render instead of N `flushSync` calls. Eliminates the
490
- * "flushSync was called from inside a lifecycle method" warning storm on
491
- * grouping changes (#330).
492
- */
493
- beginBatch(e) {
494
- N(e);
495
- }
496
- /**
497
- * Close a teardown batch opened by {@link beginBatch}. Caller is
498
- * responsible for ensuring affected containers are detached from the
499
- * DOM before this returns; the manager's render-time `isConnected`
500
- * filter then prunes them silently.
501
- */
502
- endBatch(e) {
503
- U(e);
504
- }
505
- }
506
- export {
507
- ie as G,
508
- X as a,
509
- Z as b,
510
- ee as c,
511
- te as d,
512
- re as e,
513
- ne as f,
514
- J as g,
515
- Q as h,
516
- x as i,
517
- $ as r
518
- };