@toolbox-web/grid-angular 1.3.0 → 1.3.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.
@@ -1554,6 +1554,21 @@ class GridAdapter {
1554
1554
  editorViewRefs = [];
1555
1555
  /** Editor-specific component refs tracked separately for per-cell cleanup via releaseCell. */
1556
1556
  editorComponentRefs = [];
1557
+ /**
1558
+ * Per-editor `before-edit-close` listener teardown functions, keyed by
1559
+ * editor host element.
1560
+ *
1561
+ * The grid's editing plugin emits `before-edit-close` on the host
1562
+ * `<tbw-grid>` before tearing down a row's managed editors. Angular
1563
+ * editors that commit on `(blur)` rely on the focused input firing `blur`
1564
+ * naturally, but Tab / programmatic row exit rebuilds the cell DOM
1565
+ * synchronously without giving the focused input a chance to blur first
1566
+ * — pending input is silently discarded.
1567
+ *
1568
+ * Mirror of Vue's `editorBeforeCloseUnsubs` and React's
1569
+ * `wrapReactEditor` queueMicrotask bridge.
1570
+ */
1571
+ editorBeforeCloseUnsubs = new Map();
1557
1572
  typeRegistry = null;
1558
1573
  constructor(injector, appRef, viewContainerRef) {
1559
1574
  this.injector = injector;
@@ -1828,6 +1843,7 @@ class GridAdapter {
1828
1843
  const container = document.createElement('span');
1829
1844
  container.style.display = 'contents';
1830
1845
  syncRootNodes(viewRef, container);
1846
+ this.attachBeforeEditCloseFlush(container);
1831
1847
  // Auto-wire: Listen for commit/cancel events on the rendered component.
1832
1848
  // This allows components to just emit (commit) and (cancel) without
1833
1849
  // requiring explicit template bindings like (commit)="onCommit($event)".
@@ -2114,6 +2130,7 @@ class GridAdapter {
2114
2130
  column: ctx.column,
2115
2131
  }, true);
2116
2132
  wireEditorCallbacks(hostElement, componentRef.instance, (value) => ctx.commit(value), () => ctx.cancel());
2133
+ this.attachBeforeEditCloseFlush(hostElement);
2117
2134
  // Auto-update editor when value changes externally (e.g., via updateRow cascade
2118
2135
  // or Escape-revert). Update the component input and run detectChanges() —
2119
2136
  // the component's own template handles rendering regardless of editor type.
@@ -2432,6 +2449,13 @@ class GridAdapter {
2432
2449
  this.editorComponentRefs.splice(i, 1);
2433
2450
  }
2434
2451
  }
2452
+ // Detach `before-edit-close` listeners for editor hosts inside this cell
2453
+ for (const [hostEl, unsub] of this.editorBeforeCloseUnsubs) {
2454
+ if (cellEl.contains(hostEl)) {
2455
+ unsub();
2456
+ this.editorBeforeCloseUnsubs.delete(hostEl);
2457
+ }
2458
+ }
2435
2459
  }
2436
2460
  /**
2437
2461
  * Unmount a specific container (e.g., detail panel, tool panel).
@@ -2469,6 +2493,41 @@ class GridAdapter {
2469
2493
  this.componentRefs = [];
2470
2494
  this.editorComponentRefs.forEach((ref) => ref.destroy());
2471
2495
  this.editorComponentRefs = [];
2496
+ this.editorBeforeCloseUnsubs.forEach((unsub) => unsub());
2497
+ this.editorBeforeCloseUnsubs.clear();
2498
+ }
2499
+ /**
2500
+ * Attaches a `before-edit-close` listener on the host grid that flushes
2501
+ * the focused input inside `host` via native `.blur()` so editors that
2502
+ * commit on `(blur)` flush pending input before the cell DOM is torn
2503
+ * down by Tab / programmatic row exit.
2504
+ *
2505
+ * The grid is resolved lazily via `queueMicrotask` because the host is
2506
+ * appended to the cell *after* the editor wrapper returns. Mirror of
2507
+ * Vue's `attachBeforeEditCloseFlush` and React's `wrapReactEditor`
2508
+ * queueMicrotask bridge.
2509
+ * @internal
2510
+ */
2511
+ attachBeforeEditCloseFlush(host) {
2512
+ queueMicrotask(() => {
2513
+ const gridEl = host.closest('tbw-grid');
2514
+ if (!gridEl)
2515
+ return;
2516
+ const flush = () => {
2517
+ const focused = host.ownerDocument.activeElement;
2518
+ if (focused &&
2519
+ host.contains(focused) &&
2520
+ (focused instanceof HTMLInputElement ||
2521
+ focused instanceof HTMLTextAreaElement ||
2522
+ focused instanceof HTMLSelectElement)) {
2523
+ focused.blur();
2524
+ }
2525
+ };
2526
+ gridEl.addEventListener('before-edit-close', flush);
2527
+ this.editorBeforeCloseUnsubs.set(host, () => {
2528
+ gridEl.removeEventListener('before-edit-close', flush);
2529
+ });
2530
+ });
2472
2531
  }
2473
2532
  }
2474
2533