@toolbox-web/grid 2.11.1 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/all.js +2 -2
  2. package/all.js.map +1 -1
  3. package/custom-elements.json +20 -1
  4. package/index.js +1 -1
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +24 -2
  7. package/lib/core/internal/empty.d.ts +73 -0
  8. package/lib/core/internal/focus-manager.d.ts +17 -0
  9. package/lib/core/internal/shell.d.ts +1 -1
  10. package/lib/core/internal/virtualization.d.ts +103 -1
  11. package/lib/core/styles/index.d.ts +3 -2
  12. package/lib/core/types.d.ts +103 -7
  13. package/lib/features/pinned-columns.js.map +1 -1
  14. package/lib/plugins/clipboard/index.js.map +1 -1
  15. package/lib/plugins/column-virtualization/index.js.map +1 -1
  16. package/lib/plugins/context-menu/index.js.map +1 -1
  17. package/lib/plugins/editing/EditingPlugin.d.ts +1 -1
  18. package/lib/plugins/editing/index.js +1 -1
  19. package/lib/plugins/editing/index.js.map +1 -1
  20. package/lib/plugins/editing/types.d.ts +9 -1
  21. package/lib/plugins/export/index.js.map +1 -1
  22. package/lib/plugins/filtering/index.js +1 -1
  23. package/lib/plugins/filtering/index.js.map +1 -1
  24. package/lib/plugins/grouping-columns/index.js.map +1 -1
  25. package/lib/plugins/grouping-rows/index.js.map +1 -1
  26. package/lib/plugins/master-detail/index.js.map +1 -1
  27. package/lib/plugins/multi-sort/index.js.map +1 -1
  28. package/lib/plugins/pinned-columns/index.js +1 -1
  29. package/lib/plugins/pinned-columns/index.js.map +1 -1
  30. package/lib/plugins/pinned-rows/index.js.map +1 -1
  31. package/lib/plugins/pivot/index.js.map +1 -1
  32. package/lib/plugins/print/index.js.map +1 -1
  33. package/lib/plugins/reorder-columns/index.js +1 -1
  34. package/lib/plugins/reorder-columns/index.js.map +1 -1
  35. package/lib/plugins/reorder-rows/index.js +1 -1
  36. package/lib/plugins/reorder-rows/index.js.map +1 -1
  37. package/lib/plugins/responsive/index.js +1 -1
  38. package/lib/plugins/responsive/index.js.map +1 -1
  39. package/lib/plugins/row-drag-drop/RowDragDropPlugin.d.ts +1 -1
  40. package/lib/plugins/row-drag-drop/index.js +1 -1
  41. package/lib/plugins/row-drag-drop/index.js.map +1 -1
  42. package/lib/plugins/selection/SelectionPlugin.d.ts +1 -1
  43. package/lib/plugins/selection/index.d.ts +1 -1
  44. package/lib/plugins/selection/index.js.map +1 -1
  45. package/lib/plugins/server-side/ServerSidePlugin.d.ts +1 -1
  46. package/lib/plugins/server-side/index.js.map +1 -1
  47. package/lib/plugins/sticky-rows/index.js.map +1 -1
  48. package/lib/plugins/tooltip/index.js.map +1 -1
  49. package/lib/plugins/tree/index.js.map +1 -1
  50. package/lib/plugins/undo-redo/index.js.map +1 -1
  51. package/lib/plugins/visibility/index.js.map +1 -1
  52. package/package.json +1 -1
  53. package/public.d.ts +10 -1
  54. package/umd/grid.all.umd.js +1 -1
  55. package/umd/grid.all.umd.js.map +1 -1
  56. package/umd/grid.umd.js +1 -1
  57. package/umd/grid.umd.js.map +1 -1
  58. package/umd/plugins/editing.umd.js.map +1 -1
  59. package/umd/plugins/pinned-columns.umd.js +1 -1
  60. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  61. package/umd/plugins/reorder-rows.umd.js.map +1 -1
  62. package/umd/plugins/row-drag-drop.umd.js.map +1 -1
  63. package/umd/plugins/selection.umd.js.map +1 -1
  64. package/umd/plugins/server-side.umd.js.map +1 -1
@@ -333,7 +333,7 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
333
333
  * const editing = grid.getPluginByName('editing');
334
334
  * ```
335
335
  *
336
- * @param name - The plugin name (matches {@link BaseGridPlugin.name}).
336
+ * @param name - The plugin name (matches `BaseGridPlugin.name`).
337
337
  * @returns The plugin instance, or `undefined` if not registered.
338
338
  * @group Plugin Communication
339
339
  */
@@ -566,7 +566,7 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
566
566
  /** @internal Run grid setup (DOM rebuild). */
567
567
  _setup(): void;
568
568
  /** @internal Apply animation configuration to host element. */
569
- _applyAnimationConfig(config: GridConfig<T>): void;
569
+ _applyAnimationConfig(gridConfig: GridConfig<T>): void;
570
570
  /**
571
571
  * Find the header row element.
572
572
  * Used by plugins that need to access header cells for styling or measurement.
@@ -1728,6 +1728,28 @@ export declare class DataGridElement<T = any> extends HTMLElement implements Int
1728
1728
  * ```
1729
1729
  */
1730
1730
  containsFocus(node?: Node | null): boolean;
1731
+ /**
1732
+ * The last meaningful element inside the grid host's light-DOM subtree
1733
+ * that received user focus. Excludes the grid host itself (synthetic
1734
+ * `tabindex=0` focus during keyboard navigation), bare `.cell` elements
1735
+ * (whose focus is virtual), and descendants of registered external focus
1736
+ * containers (overlays/datepickers/dropdowns). Returns `null` when the
1737
+ * user has not yet interacted with any tracked descendant.
1738
+ *
1739
+ * @group Focus Management
1740
+ */
1741
+ get lastFocusedElement(): HTMLElement | null;
1742
+ /**
1743
+ * Restore focus to the last meaningful user-focused element inside the
1744
+ * grid (see {@link lastFocusedElement} for what counts as "meaningful").
1745
+ * The grid invokes this automatically whenever focus is bounced to
1746
+ * `<body>` (e.g. when a body-level overlay is removed). Exposed publicly
1747
+ * so application code can re-anchor focus on demand.
1748
+ *
1749
+ * @group Focus Management
1750
+ * @returns `true` if a tracked element existed and was refocused; `false` otherwise.
1751
+ */
1752
+ restoreLastFocus(): boolean;
1731
1753
  /**
1732
1754
  * Re-parse light DOM column elements and refresh the grid.
1733
1755
  * Call this after framework adapters have registered their templates.
@@ -0,0 +1,73 @@
1
+ import { EmptyContext, EmptyOverlay, EmptyRenderer, GridConfig } from '../types';
2
+ /** Default messages used when no `emptyRenderer` is configured. */
3
+ export declare const DEFAULT_EMPTY_MESSAGE = "No data to display";
4
+ export declare const DEFAULT_FILTERED_OUT_MESSAGE = "No matching rows";
5
+ /**
6
+ * Default empty-state renderer.
7
+ * Produces a non-interactive `<div>` carrying a translatable message.
8
+ */
9
+ export declare function defaultEmptyRenderer(ctx: EmptyContext): HTMLElement;
10
+ /**
11
+ * Create the rendered content for the empty overlay.
12
+ * If a custom renderer is provided, use it; otherwise fall back to the default
13
+ * message. Strings returned by user renderers are sanitized through
14
+ * `sanitizeHTML()` before being assigned to `innerHTML` — mirroring the cell
15
+ * render path — so consumers can safely embed values from API responses
16
+ * (e.g. `Failed to load deals: ${error.message}`) without opening an XSS sink.
17
+ */
18
+ export declare function createEmptyContent(ctx: EmptyContext, renderer?: EmptyRenderer): HTMLElement;
19
+ /**
20
+ * Create the empty-state overlay element.
21
+ * Always carries `role="status"` + `aria-live="polite"` so screen readers
22
+ * announce the state on transition; the `data-overlay-target` attribute is
23
+ * informational only. CSS positions absolutely against the closest positioned
24
+ * ancestor — `.tbw-grid-root` is positioned by `base.css`, and `.rows-container`
25
+ * is given `position: relative` for `target='rows'` for the same reason.
26
+ */
27
+ export declare function createEmptyOverlay(ctx: EmptyContext, renderer?: EmptyRenderer, target?: EmptyOverlay): HTMLElement;
28
+ /**
29
+ * Mount the overlay into the chosen target element.
30
+ * Caller resolves the actual element (`.rows-container` for `'rows'`, the
31
+ * `.tbw-grid-root` for `'grid'`).
32
+ */
33
+ export declare function showEmptyOverlay(target: Element, overlayEl: HTMLElement): void;
34
+ /** Detach the overlay from the DOM. */
35
+ export declare function hideEmptyOverlay(overlayEl: HTMLElement | undefined): void;
36
+ /**
37
+ * Decide whether the empty overlay should be visible.
38
+ * The overlay is shown only when:
39
+ * - the grid is not currently in a loading state (loading takes precedence);
40
+ * - the rendered row count is zero (after all plugin processing);
41
+ * - the renderer has not been explicitly disabled by setting it to `null`.
42
+ */
43
+ export declare function shouldShowEmpty(loading: boolean, renderedRowCount: number, renderer: GridConfig['emptyRenderer'] | undefined): boolean;
44
+ /**
45
+ * Per-grid mutable state cached between overlay updates so the hot path
46
+ * (`_schedulerAfterRender` fires on every render phase, including
47
+ * VIRTUALIZATION during scroll) can skip the recreate when nothing observable
48
+ * has changed. Without this guard we'd churn DOM and could leak
49
+ * framework-adapter portals returned from user renderers.
50
+ *
51
+ * `sourceRows` is the array reference (not just its length): reassigning
52
+ * `grid.rows` produces a new reference and busts the cache, even when the
53
+ * length is unchanged (e.g. `grid.rows = []` after a previous `grid.rows = []`).
54
+ * That is the user's explicit "something changed" signal, and it lets custom
55
+ * renderers that close over external state (e.g. an `errorMessage` variable)
56
+ * re-render without forcing them to mint a new renderer function.
57
+ */
58
+ export interface EmptyOverlayState {
59
+ el?: HTMLElement;
60
+ renderer?: GridConfig['emptyRenderer'];
61
+ target?: EmptyOverlay;
62
+ sourceRows?: readonly unknown[];
63
+ filteredOut?: boolean;
64
+ }
65
+ /**
66
+ * Compute, mount, or tear down the empty-state overlay in a single call.
67
+ * Encapsulates show/hide decision, change detection, mount-point resolution,
68
+ * and the `filteredOut` derivation so the grid host can stay a one-liner.
69
+ *
70
+ * The `state` object is mutated in place — callers store a single reference
71
+ * and pass it back on every tick.
72
+ */
73
+ export declare function updateEmptyOverlay(gridRoot: Element | null, loading: boolean, renderedRowCount: number, sourceRows: readonly unknown[], renderer: GridConfig['emptyRenderer'] | undefined, target: EmptyOverlay, state: EmptyOverlayState): void;
@@ -41,6 +41,23 @@ export declare class FocusManager<T = any> {
41
41
  * Check whether a node is inside any registered external focus container.
42
42
  */
43
43
  isInExternalFocusContainer(node: Node): boolean;
44
+ /**
45
+ * Restore focus to the last tracked user-focused element if it is still
46
+ * connected and focusable. Returns `true` on success.
47
+ *
48
+ * Stale references (element removed from DOM during a re-render) are
49
+ * silently dropped so callers can fall back to their own restoration logic.
50
+ */
51
+ restoreLastFocus(): boolean;
52
+ /**
53
+ * Currently tracked last-user-focused element inside the grid host's
54
+ * light-DOM subtree, if any. Excludes the grid host itself, bare `.cell`
55
+ * elements, and descendants of registered external focus containers.
56
+ * Exposed so plugins (notably EditingPlugin) can defer to the unified
57
+ * trap before falling back to plugin-specific restoration logic.
58
+ * @internal
59
+ */
60
+ get lastFocusedElement(): HTMLElement | null;
44
61
  /**
45
62
  * Clean up all external focus container listeners.
46
63
  * Called when the grid disconnects.
@@ -204,7 +204,7 @@ export declare function renderHeaderContent(renderRoot: Element, state: ShellSta
204
204
  * Render content for expanded accordion sections.
205
205
  * @param icons - Optional icons for expand/collapse chevrons (from grid config)
206
206
  */
207
- export declare function renderPanelContent(renderRoot: Element, state: ShellState, icons?: {
207
+ export declare function renderPanelContent(renderRoot: Element, state: ShellState, _icons?: {
208
208
  expand?: IconValue;
209
209
  collapse?: IconValue;
210
210
  }): void;
@@ -173,6 +173,84 @@ export declare function computeAverageExcludingPluginRows<T>(cache: RowPosition[
173
173
  measuredCount: number;
174
174
  averageHeight: number;
175
175
  };
176
+ /**
177
+ * Maximum spacer element height (px) before browsers cap the rendered height.
178
+ *
179
+ * Chromium's hard cap is `2^25 = 33,554,432` px; Firefox/Safari are similar or larger.
180
+ * We pick `33,500,000` — ~54 KB of headroom under Chromium's cap so that floating-point
181
+ * drift in the fractional mapping math (`scrollTop * rMax / sMax`) cannot push a computed
182
+ * spacer position past the engine cap and silently truncate.
183
+ *
184
+ * For datasets where `totalRows * rowHeight` exceeds this value, the faux-vscroll
185
+ * spacer would silently truncate, making the tail of the dataset unreachable via
186
+ * the native scrollbar / `Ctrl+End`. The grid switches to fractional scroll mapping
187
+ * above this threshold — see {@link computeScrollMapping}.
188
+ *
189
+ * @category Plugin Development
190
+ * @since 2.13.0
191
+ */
192
+ export declare const MAX_ELEMENT_HEIGHT_PX = 33500000;
193
+ /**
194
+ * Mapping between native `scrollTop` (clamped spacer space) and "virtual" scroll
195
+ * position (raw row-content space). See {@link computeScrollMapping}.
196
+ *
197
+ * @category Plugin Development
198
+ * @since 2.13.0
199
+ */
200
+ export interface ScrollMapping {
201
+ /** Raw row-content height in pixels (totalRows * rowHeight or sum of variable heights). */
202
+ rawContentHeight: number;
203
+ /** Effective spacer DOM height — `min(rawContentHeight, maxSpacerHeight)`. */
204
+ spacerHeight: number;
205
+ /** Viewport height used for computing scrollable extents. */
206
+ viewportHeight: number;
207
+ /** True when `rawContentHeight > maxSpacerHeight` — fractional mapping is active. */
208
+ capped: boolean;
209
+ }
210
+ /**
211
+ * Compute a mapping between the spacer's native scrollTop and the virtual
212
+ * row-content scroll offset.
213
+ *
214
+ * For datasets within `maxSpacerHeight`, mapping is identity (no transform).
215
+ * Above the cap, the spacer is clamped and `scrollTop` units no longer equal
216
+ * row-content units — call {@link toVirtualScrollTop} / {@link fromVirtualScrollTop}
217
+ * to translate between the two coordinate spaces.
218
+ *
219
+ * @category Plugin Development
220
+ * @since 2.13.0
221
+ */
222
+ export declare function computeScrollMapping(rawContentHeight: number, viewportHeight: number, maxSpacerHeight?: number): ScrollMapping;
223
+ /**
224
+ * Translate a native `scrollTop` (spacer space) into a virtual scroll offset
225
+ * in raw row-content space. Identity when the mapping is not capped.
226
+ *
227
+ * The result is clamped to `[0, rawContentHeight - viewportHeight]` so callers
228
+ * never index past the dataset, even when the spacer's actual scrollable extent
229
+ * slightly exceeds `spacerHeight - viewportHeight` (e.g. when a horizontal scrollbar
230
+ * adds bottom padding to the faux spacer).
231
+ *
232
+ * @category Plugin Development
233
+ * @since 2.13.0
234
+ */
235
+ export declare function toVirtualScrollTop(scrollTop: number, mapping: ScrollMapping): number;
236
+ /**
237
+ * Translate a virtual scroll offset (raw row-content space) into a native
238
+ * `scrollTop` value (spacer space). Identity when the mapping is not capped.
239
+ *
240
+ * @category Plugin Development
241
+ * @since 2.13.0
242
+ */
243
+ export declare function fromVirtualScrollTop(virtualTop: number, mapping: ScrollMapping): number;
244
+ /**
245
+ * Identity scroll mapping (no cap applied). Useful as a default in places that
246
+ * don't yet know the dataset extents. `viewportHeight` is `0` until the first
247
+ * `calculateTotalSpacerHeight` call populates the real extents — safe because
248
+ * `capped: false` short-circuits both translation helpers before they read it.
249
+ *
250
+ * @category Plugin Development
251
+ * @since 2.13.0
252
+ */
253
+ export declare function createIdentityScrollMapping(): ScrollMapping;
176
254
  /**
177
255
  * Result of computing a virtual window for fixed-height rows.
178
256
  * Used by plugins like FilteringPlugin for virtualized dropdowns.
@@ -184,8 +262,19 @@ export interface VirtualWindow {
184
262
  end: number;
185
263
  /** Pixel offset to apply to the rows container (translateY) */
186
264
  offsetY: number;
187
- /** Total height of the scrollable content */
265
+ /**
266
+ * Effective spacer DOM height — use this for the scrollable spacer element.
267
+ * Equal to `min(totalRows * rowHeight, maxSpacerHeight)`. Above the cap this
268
+ * is clamped; use {@link VirtualWindow.rawContentHeight} for the un-clamped value.
269
+ */
188
270
  totalHeight: number;
271
+ /**
272
+ * Raw, un-clamped row-content height (`totalRows * rowHeight`). Equal to
273
+ * `totalHeight` when the dataset is below `maxSpacerHeight`.
274
+ *
275
+ * @since 2.13.0
276
+ */
277
+ rawContentHeight: number;
189
278
  }
190
279
  /** Parameters for computing the virtual window */
191
280
  export interface VirtualWindowParams {
@@ -199,11 +288,24 @@ export interface VirtualWindowParams {
199
288
  rowHeight: number;
200
289
  /** Number of extra rows to render above/below viewport */
201
290
  overscan: number;
291
+ /**
292
+ * Optional cap on the spacer's DOM height. When `totalRows * rowHeight` exceeds
293
+ * this value, `scrollTop` is treated as a spacer-space position and translated
294
+ * to virtual row-content space via fractional mapping. Defaults to {@link MAX_ELEMENT_HEIGHT_PX}.
295
+ * Pass `Infinity` to disable.
296
+ *
297
+ * @since 2.13.0
298
+ */
299
+ maxSpacerHeight?: number;
202
300
  }
203
301
  /**
204
302
  * Compute the virtual row window based on scroll position and viewport.
205
303
  * Simple fixed-height implementation for plugins needing basic virtualization.
206
304
  *
305
+ * For datasets where `totalRows * rowHeight > maxSpacerHeight`, scroll position
306
+ * is mapped fractionally so the entire dataset stays reachable past the browser's
307
+ * single-element height cap (Chromium ~33.5M px). See {@link computeScrollMapping}.
308
+ *
207
309
  * @param params - Parameters for computing the window
208
310
  * @returns VirtualWindow with start/end indices and transforms
209
311
  */
@@ -24,7 +24,8 @@
24
24
  * 6. Shell (toolbar, layout)
25
25
  * 7. Tool Panel (side panels, accordion)
26
26
  * 8. Loading (spinners, overlays)
27
- * 9. Animations (keyframes, transitions)
28
- * 10. Media Queries (accessibility, responsive)
27
+ * 9. Empty state (no-rows overlay)
28
+ * 10. Animations (keyframes, transitions)
29
+ * 11. Media Queries (accessibility, responsive)
29
30
  */
30
31
  export declare const gridStyles: string;
@@ -1,6 +1,6 @@
1
1
  import { RenderPhase } from './internal/render-scheduler';
2
2
  import { ShellState } from './internal/shell';
3
- import { RowPosition } from './internal/virtualization';
3
+ import { RowPosition, ScrollMapping } from './internal/virtualization';
4
4
  import { AfterCellRenderContext, AfterRowRenderContext, CellMouseEvent } from './plugin/types';
5
5
  /**
6
6
  * Position entry for a single row in the position cache.
@@ -1887,6 +1887,17 @@ export interface VirtualState {
1887
1887
  cachedScrollAreaHeight: number;
1888
1888
  /** Cached reference to .tbw-scroll-area element. Set during scroll listener setup. */
1889
1889
  scrollAreaEl: HTMLElement | null;
1890
+ /**
1891
+ * Active scroll mapping between native `scrollTop` (clamped spacer space) and
1892
+ * "virtual" row-content space. Identity (`capped: false`) for datasets within
1893
+ * the browser's max-element-height cap (Chromium ~33.5M px). For larger datasets,
1894
+ * the spacer height is clamped and `scrollTop` must be translated via this
1895
+ * mapping before computing the visible window. Updated by `calculateTotalSpacerHeight`.
1896
+ *
1897
+ * @see {@link computeScrollMapping}
1898
+ * @since 2.13.0
1899
+ */
1900
+ scrollMapping: ScrollMapping;
1890
1901
  }
1891
1902
  /**
1892
1903
  * Union type for input-like elements that have a `value` property.
@@ -2438,7 +2449,7 @@ export interface GridConfig<TRow = any> {
2438
2449
  * instead. It is honored by every sort code path in the grid (core, multi-sort,
2439
2450
  * tree, server-side) and is composable across columns.
2440
2451
  *
2441
- * For server-side sort, prefer {@link ServerSideConfig.dataSource} — the
2452
+ * For server-side sort, prefer `ServerSideConfig.dataSource` — the
2442
2453
  * `sortModel` is shipped to your `getRows` handler so the backend can return
2443
2454
  * pre-sorted blocks.
2444
2455
  * :::
@@ -2461,7 +2472,7 @@ export interface GridConfig<TRow = any> {
2461
2472
  * ```
2462
2473
  *
2463
2474
  * @see {@link BaseColumnConfig.sortComparator} — recommended per-column override
2464
- * @see {@link ServerSideConfig.dataSource} — recommended server-side sort path
2475
+ * @see `ServerSideConfig.dataSource` — recommended server-side sort path
2465
2476
  */
2466
2477
  sortHandler?: SortHandler<TRow>;
2467
2478
  /**
@@ -2477,8 +2488,8 @@ export interface GridConfig<TRow = any> {
2477
2488
  * };
2478
2489
  * ```
2479
2490
  *
2480
- * @see {@link DataGrid.sort} for runtime sorting
2481
- * @see {@link DataGrid.sortModel} for reading current sort state
2491
+ * @see {@link DataGridElement.sort} for runtime sorting
2492
+ * @see {@link DataGridElement.sortModel} for reading current sort state
2482
2493
  */
2483
2494
  initialSort?: {
2484
2495
  field: string;
@@ -2652,7 +2663,92 @@ export interface GridConfig<TRow = any> {
2652
2663
  * ```
2653
2664
  */
2654
2665
  loadingRenderer?: LoadingRenderer;
2666
+ /**
2667
+ * Custom renderer shown when the grid has no rows to display
2668
+ * (`loading === false` AND the rendered row count is `0`, after all plugin
2669
+ * processing such as filtering / grouping / server-side).
2670
+ *
2671
+ * - When **omitted**, a built-in message is rendered ("No data to display"
2672
+ * or "No matching rows" when source rows existed but were filtered out).
2673
+ * - When set to a function, the function receives an {@link EmptyContext}
2674
+ * and returns an `HTMLElement` or HTML string.
2675
+ * - When **explicitly `null`**, the empty overlay is suppressed entirely.
2676
+ *
2677
+ * The empty overlay is mutually exclusive with the loading overlay; if
2678
+ * `loading === true`, the loading overlay always wins.
2679
+ *
2680
+ * @example
2681
+ * ```typescript
2682
+ * // Show a backend error message via a closure over the consumer's state.
2683
+ * gridConfig.emptyRenderer = () =>
2684
+ * error
2685
+ * ? `Failed to load deals: ${error.message}`
2686
+ * : 'No deals to display';
2687
+ * ```
2688
+ *
2689
+ * @see {@link EmptyOverlay} to control where the overlay is mounted.
2690
+ * @since 2.12.0
2691
+ */
2692
+ emptyRenderer?: EmptyRenderer | null;
2693
+ /**
2694
+ * Where the empty-state overlay is mounted.
2695
+ *
2696
+ * - `'rows'` (default) — overlays the `.rows-container`. Headers stay
2697
+ * visible so users can clear filters or see the column schema.
2698
+ * - `'grid'` — overlays the `.tbw-grid-root`. Hides headers and any
2699
+ * shell/toolbar content too.
2700
+ *
2701
+ * @defaultValue `'rows'`
2702
+ * @since 2.12.0
2703
+ */
2704
+ emptyOverlay?: EmptyOverlay;
2705
+ }
2706
+ /**
2707
+ * Where the empty-state overlay is mounted.
2708
+ *
2709
+ * @see {@link GridConfig.emptyOverlay}
2710
+ * @since 2.12.0
2711
+ */
2712
+ export type EmptyOverlay = 'rows' | 'grid';
2713
+ /**
2714
+ * Context passed to a custom {@link EmptyRenderer}.
2715
+ *
2716
+ * @since 2.12.0
2717
+ */
2718
+ export interface EmptyContext {
2719
+ /**
2720
+ * Number of rows in the source data before any plugin processing
2721
+ * (sort / filter / group / server-side). Equivalent to
2722
+ * `grid.sourceRows.length`.
2723
+ */
2724
+ sourceRowCount: number;
2725
+ /**
2726
+ * `true` when the source had rows but all of them were filtered out
2727
+ * (i.e. `sourceRowCount > 0` while the rendered row count is `0`).
2728
+ * The default renderer uses this flag to switch between
2729
+ * "No data to display" and "No matching rows".
2730
+ */
2731
+ filteredOut: boolean;
2655
2732
  }
2733
+ /**
2734
+ * Custom renderer for the empty state overlay.
2735
+ *
2736
+ * @param context - {@link EmptyContext} describing why the grid is empty.
2737
+ * @returns An `HTMLElement` or an HTML string.
2738
+ *
2739
+ * @example
2740
+ * ```typescript
2741
+ * const renderer: EmptyRenderer = (ctx) => {
2742
+ * const div = document.createElement('div');
2743
+ * div.textContent = ctx.filteredOut ? 'No matches' : 'No data';
2744
+ * return div;
2745
+ * };
2746
+ * ```
2747
+ *
2748
+ * @see {@link GridConfig.emptyRenderer}
2749
+ * @since 2.12.0
2750
+ */
2751
+ export type EmptyRenderer = (context: EmptyContext) => HTMLElement | string;
2656
2752
  /**
2657
2753
  * Sort state passed to custom sort handlers.
2658
2754
  * Represents the current sorting configuration for a column.
@@ -2691,7 +2787,7 @@ export interface SortState {
2691
2787
  * active sort field. For per-column custom sort logic that survives every
2692
2788
  * sort code path (core, multi-sort, tree, server-side), set `sortComparator`
2693
2789
  * on the relevant columns instead. For server-side sort, use
2694
- * {@link ServerSideConfig.dataSource}.
2790
+ * `ServerSideConfig.dataSource`.
2695
2791
  * :::
2696
2792
  *
2697
2793
  * Use `SortHandler` only when you need to replace the grid's sort engine
@@ -3320,7 +3416,7 @@ export interface ShellHeaderConfig {
3320
3416
  *
3321
3417
  * Set to `false` when you want to provide your own toggle button (e.g. a
3322
3418
  * design-system button styled to match your application). Wire your button
3323
- * to call {@link Grid.toggleToolPanel} (or `toggleToolPanelSection(id)` for
3419
+ * to call {@link DataGridElement.toggleToolPanel} (or `toggleToolPanelSection(id)` for
3324
3420
  * a specific section). All tool panels remain functional; only the
3325
3421
  * built-in toggle button and adjacent separator are suppressed.
3326
3422
  *
@@ -1 +1 @@
1
- {"version":3,"file":"pinned-columns.js","sources":["../../../../../libs/grid/src/lib/features/pinned-columns.ts"],"sourcesContent":["/**\n * Pinned Columns feature for @toolbox-web/grid\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid/features/pinned-columns';\n *\n * grid.gridConfig = { features: { pinnedColumns: true } };\n * ```\n */\n\nimport { PinnedColumnsPlugin } from '../plugins/pinned-columns';\nimport { registerFeature } from './registry';\n\ndeclare module '../core/types' {\n interface FeatureConfig {\n /** Enable column pinning (left/right). */\n pinnedColumns?: boolean;\n }\n}\n\nregisterFeature('pinnedColumns', (config) => {\n return new PinnedColumnsPlugin();\n});\n\n/** @internal Type anchor — forces bundlers to preserve this module's FeatureConfig augmentation when re-exported. */\nexport type _Augmentation = true;\n"],"names":["registerFeature","config","PinnedColumnsPlugin"],"mappings":"qJAqBAA,EAAgB,gBAAkBC,GACzB,IAAIC"}
1
+ {"version":3,"file":"pinned-columns.js","sources":["../../../../../libs/grid/src/lib/features/pinned-columns.ts"],"sourcesContent":["/**\n * Pinned Columns feature for @toolbox-web/grid\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid/features/pinned-columns';\n *\n * grid.gridConfig = { features: { pinnedColumns: true } };\n * ```\n */\n\nimport { PinnedColumnsPlugin } from '../plugins/pinned-columns';\nimport { registerFeature } from './registry';\n\ndeclare module '../core/types' {\n interface FeatureConfig {\n /** Enable column pinning (left/right). */\n pinnedColumns?: boolean;\n }\n}\n\nregisterFeature('pinnedColumns', (_config) => {\n return new PinnedColumnsPlugin();\n});\n\n/** @internal Type anchor — forces bundlers to preserve this module's FeatureConfig augmentation when re-exported. */\nexport type _Augmentation = true;\n"],"names":["registerFeature","_config","PinnedColumnsPlugin"],"mappings":"qJAqBAA,EAAgB,gBAAkBC,GACzB,IAAIC"}