@toolbox-web/grid 1.6.2 → 1.8.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 (114) hide show
  1. package/README.md +51 -15
  2. package/all.js +267 -158
  3. package/all.js.map +1 -1
  4. package/index.js +866 -722
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +68 -1
  7. package/lib/core/grid.d.ts.map +1 -1
  8. package/lib/core/internal/header.d.ts.map +1 -1
  9. package/lib/core/plugin/base-plugin.d.ts +182 -1
  10. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  11. package/lib/core/plugin/index.d.ts +1 -1
  12. package/lib/core/plugin/index.d.ts.map +1 -1
  13. package/lib/core/plugin/plugin-manager.d.ts +56 -1
  14. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  15. package/lib/core/plugin/types.d.ts +36 -0
  16. package/lib/core/plugin/types.d.ts.map +1 -1
  17. package/lib/core/types.d.ts +1349 -31
  18. package/lib/core/types.d.ts.map +1 -1
  19. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  20. package/lib/plugins/clipboard/index.js +140 -87
  21. package/lib/plugins/clipboard/index.js.map +1 -1
  22. package/lib/plugins/column-virtualization/index.js +64 -7
  23. package/lib/plugins/column-virtualization/index.js.map +1 -1
  24. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  25. package/lib/plugins/context-menu/index.js +123 -65
  26. package/lib/plugins/context-menu/index.js.map +1 -1
  27. package/lib/plugins/editing/EditingPlugin.d.ts +6 -1
  28. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  29. package/lib/plugins/editing/index.js +95 -13
  30. package/lib/plugins/editing/index.js.map +1 -1
  31. package/lib/plugins/export/index.js +91 -34
  32. package/lib/plugins/export/index.js.map +1 -1
  33. package/lib/plugins/filtering/FilteringPlugin.d.ts +6 -1
  34. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  35. package/lib/plugins/filtering/index.js +192 -123
  36. package/lib/plugins/filtering/index.js.map +1 -1
  37. package/lib/plugins/grouping-columns/index.js +57 -0
  38. package/lib/plugins/grouping-columns/index.js.map +1 -1
  39. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +7 -2
  40. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  41. package/lib/plugins/grouping-rows/index.js +142 -60
  42. package/lib/plugins/grouping-rows/index.js.map +1 -1
  43. package/lib/plugins/master-detail/index.js +69 -12
  44. package/lib/plugins/master-detail/index.js.map +1 -1
  45. package/lib/plugins/multi-sort/index.js +70 -13
  46. package/lib/plugins/multi-sort/index.js.map +1 -1
  47. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +3 -3
  48. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  49. package/lib/plugins/pinned-columns/index.js +106 -36
  50. package/lib/plugins/pinned-columns/index.js.map +1 -1
  51. package/lib/plugins/pinned-rows/index.js +57 -0
  52. package/lib/plugins/pinned-rows/index.js.map +1 -1
  53. package/lib/plugins/pivot/index.js +57 -0
  54. package/lib/plugins/pivot/index.js.map +1 -1
  55. package/lib/plugins/print/PrintPlugin.d.ts.map +1 -1
  56. package/lib/plugins/print/index.js +58 -1
  57. package/lib/plugins/print/index.js.map +1 -1
  58. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  59. package/lib/plugins/reorder/column-drag.d.ts +2 -2
  60. package/lib/plugins/reorder/index.js +68 -17
  61. package/lib/plugins/reorder/index.js.map +1 -1
  62. package/lib/plugins/responsive/ResponsivePlugin.d.ts +6 -1
  63. package/lib/plugins/responsive/ResponsivePlugin.d.ts.map +1 -1
  64. package/lib/plugins/responsive/index.js +125 -54
  65. package/lib/plugins/responsive/index.js.map +1 -1
  66. package/lib/plugins/row-reorder/index.js +169 -112
  67. package/lib/plugins/row-reorder/index.js.map +1 -1
  68. package/lib/plugins/selection/SelectionPlugin.d.ts +14 -2
  69. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  70. package/lib/plugins/selection/index.js +84 -7
  71. package/lib/plugins/selection/index.js.map +1 -1
  72. package/lib/plugins/server-side/index.js +79 -22
  73. package/lib/plugins/server-side/index.js.map +1 -1
  74. package/lib/plugins/tree/TreePlugin.d.ts +7 -1
  75. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  76. package/lib/plugins/tree/index.js +140 -58
  77. package/lib/plugins/tree/index.js.map +1 -1
  78. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +6 -1
  79. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  80. package/lib/plugins/undo-redo/index.js +79 -10
  81. package/lib/plugins/undo-redo/index.js.map +1 -1
  82. package/lib/plugins/visibility/index.js +57 -0
  83. package/lib/plugins/visibility/index.js.map +1 -1
  84. package/package.json +1 -1
  85. package/public.d.ts +80 -2
  86. package/public.d.ts.map +1 -1
  87. package/umd/grid.all.umd.js +25 -25
  88. package/umd/grid.all.umd.js.map +1 -1
  89. package/umd/grid.umd.js +15 -15
  90. package/umd/grid.umd.js.map +1 -1
  91. package/umd/plugins/clipboard.umd.js +5 -5
  92. package/umd/plugins/clipboard.umd.js.map +1 -1
  93. package/umd/plugins/context-menu.umd.js +1 -1
  94. package/umd/plugins/context-menu.umd.js.map +1 -1
  95. package/umd/plugins/editing.umd.js +1 -1
  96. package/umd/plugins/editing.umd.js.map +1 -1
  97. package/umd/plugins/filtering.umd.js +1 -1
  98. package/umd/plugins/filtering.umd.js.map +1 -1
  99. package/umd/plugins/grouping-rows.umd.js +2 -2
  100. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  101. package/umd/plugins/pinned-columns.umd.js +1 -1
  102. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  103. package/umd/plugins/print.umd.js +1 -1
  104. package/umd/plugins/print.umd.js.map +1 -1
  105. package/umd/plugins/reorder.umd.js +1 -1
  106. package/umd/plugins/reorder.umd.js.map +1 -1
  107. package/umd/plugins/responsive.umd.js +1 -1
  108. package/umd/plugins/responsive.umd.js.map +1 -1
  109. package/umd/plugins/selection.umd.js +2 -2
  110. package/umd/plugins/selection.umd.js.map +1 -1
  111. package/umd/plugins/tree.umd.js +1 -1
  112. package/umd/plugins/tree.umd.js.map +1 -1
  113. package/umd/plugins/undo-redo.umd.js +1 -1
  114. package/umd/plugins/undo-redo.umd.js.map +1 -1
@@ -1,7 +1,29 @@
1
1
  import { PluginQuery } from './plugin/base-plugin';
2
2
  import { AfterCellRenderContext, AfterRowRenderContext, CellMouseEvent } from './plugin/types';
3
3
  /**
4
- * The compiled webcomponent interface for DataGrid
4
+ * The compiled web component interface for DataGrid.
5
+ *
6
+ * This interface represents the `<tbw-grid>` custom element, combining
7
+ * the public grid API with standard HTMLElement functionality.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // Query existing grid
12
+ * const grid = document.querySelector('tbw-grid') as DataGridElement<Employee>;
13
+ * grid.rows = employees;
14
+ * grid.addEventListener('cell-click', (e) => console.log(e.detail));
15
+ *
16
+ * // Create grid programmatically
17
+ * import { createGrid } from '@toolbox-web/grid';
18
+ * const grid = createGrid<Employee>({
19
+ * columns: [{ field: 'name' }, { field: 'email' }],
20
+ * });
21
+ * document.body.appendChild(grid);
22
+ * ```
23
+ *
24
+ * @see {@link PublicGrid} for the public API methods and properties
25
+ * @see {@link createGrid} for typed grid creation
26
+ * @see {@link queryGrid} for typed grid querying
5
27
  */
6
28
  export interface DataGridElement extends PublicGrid, HTMLElement {
7
29
  }
@@ -100,6 +122,74 @@ export interface PublicGrid<T = any> {
100
122
  * Unregister a previously registered tool panel.
101
123
  */
102
124
  unregisterToolPanel?(panelId: string): void;
125
+ /**
126
+ * Whether the grid is currently in a loading state.
127
+ * When true, displays a loading overlay with spinner.
128
+ *
129
+ * Can also be set via the `loading` HTML attribute.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Show loading overlay
134
+ * grid.loading = true;
135
+ * const data = await fetchData();
136
+ * grid.rows = data;
137
+ * grid.loading = false;
138
+ * ```
139
+ */
140
+ loading?: boolean;
141
+ /**
142
+ * Set loading state for a specific row.
143
+ * Displays a small spinner indicator on the row.
144
+ *
145
+ * Use when persisting row data or performing row-level async operations.
146
+ *
147
+ * @param rowId - The row's unique identifier (from getRowId)
148
+ * @param loading - Whether the row is loading
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * // Show loading while saving row
153
+ * grid.setRowLoading('emp-123', true);
154
+ * await saveRow(row);
155
+ * grid.setRowLoading('emp-123', false);
156
+ * ```
157
+ */
158
+ setRowLoading?(rowId: string, loading: boolean): void;
159
+ /**
160
+ * Set loading state for a specific cell.
161
+ * Displays a small spinner indicator on the cell.
162
+ *
163
+ * Use when performing cell-level async operations (e.g., validation, lookup).
164
+ *
165
+ * @param rowId - The row's unique identifier (from getRowId)
166
+ * @param field - The column field
167
+ * @param loading - Whether the cell is loading
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * // Show loading while validating cell
172
+ * grid.setCellLoading('emp-123', 'email', true);
173
+ * const isValid = await validateEmail(email);
174
+ * grid.setCellLoading('emp-123', 'email', false);
175
+ * ```
176
+ */
177
+ setCellLoading?(rowId: string, field: string, loading: boolean): void;
178
+ /**
179
+ * Check if a row is currently in loading state.
180
+ * @param rowId - The row's unique identifier
181
+ */
182
+ isRowLoading?(rowId: string): boolean;
183
+ /**
184
+ * Check if a cell is currently in loading state.
185
+ * @param rowId - The row's unique identifier
186
+ * @param field - The column field
187
+ */
188
+ isCellLoading?(rowId: string, field: string): boolean;
189
+ /**
190
+ * Clear all row and cell loading states.
191
+ */
192
+ clearAllLoading?(): void;
103
193
  }
104
194
  /**
105
195
  * Internal-only augmented interface for DataGrid component.
@@ -212,10 +302,64 @@ export interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {
212
302
  /** Request emission of column-state-change event (debounced) */
213
303
  requestStateChange?: () => void;
214
304
  }
305
+ /**
306
+ * Built-in primitive column types with automatic formatting and editing support.
307
+ *
308
+ * - `'string'` - Text content, default text input editor
309
+ * - `'number'` - Numeric content, right-aligned, number input editor
310
+ * - `'date'` - Date content, formatted display, date picker editor
311
+ * - `'boolean'` - True/false, rendered as checkbox
312
+ * - `'select'` - Dropdown selection from `options` array
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * columns: [
317
+ * { field: 'name', type: 'string' },
318
+ * { field: 'age', type: 'number' },
319
+ * { field: 'hireDate', type: 'date' },
320
+ * { field: 'active', type: 'boolean' },
321
+ * { field: 'department', type: 'select', options: [
322
+ * { label: 'Engineering', value: 'eng' },
323
+ * { label: 'Sales', value: 'sales' },
324
+ * ]},
325
+ * ]
326
+ * ```
327
+ *
328
+ * @see {@link ColumnType} for custom type support
329
+ * @see {@link TypeDefault} for type-level defaults
330
+ */
215
331
  export type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select';
216
332
  /**
217
333
  * Column type - built-in primitives or custom type strings.
218
- * Custom types (e.g., 'currency', 'country') can have type-level defaults via `typeDefaults`.
334
+ *
335
+ * Use built-in types for automatic formatting, or define custom types
336
+ * (e.g., 'currency', 'country') with type-level defaults via `typeDefaults`.
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * // Built-in types
341
+ * { field: 'name', type: 'string' }
342
+ * { field: 'salary', type: 'number' }
343
+ *
344
+ * // Custom types with defaults
345
+ * grid.gridConfig = {
346
+ * columns: [
347
+ * { field: 'salary', type: 'currency' },
348
+ * { field: 'birthCountry', type: 'country' },
349
+ * ],
350
+ * typeDefaults: {
351
+ * currency: {
352
+ * format: (v) => `$${Number(v).toFixed(2)}`,
353
+ * },
354
+ * country: {
355
+ * renderer: (ctx) => `🌍 ${ctx.value}`,
356
+ * },
357
+ * },
358
+ * };
359
+ * ```
360
+ *
361
+ * @see {@link PrimitiveColumnType} for built-in types
362
+ * @see {@link TypeDefault} for defining custom type defaults
219
363
  */
220
364
  export type ColumnType = PrimitiveColumnType | (string & {});
221
365
  /**
@@ -243,6 +387,10 @@ export type ColumnType = PrimitiveColumnType | (string & {});
243
387
  * }
244
388
  * }
245
389
  * ```
390
+ *
391
+ * @see {@link ColumnViewRenderer} for custom renderer function signature
392
+ * @see {@link ColumnType} for type strings that can have defaults
393
+ * @see {@link GridConfig.typeDefaults} for registering type defaults
246
394
  */
247
395
  export interface TypeDefault<TRow = unknown> {
248
396
  /**
@@ -302,8 +450,41 @@ export interface TypeDefault<TRow = unknown> {
302
450
  renderer?: ColumnViewRenderer<TRow, unknown>;
303
451
  }
304
452
  /**
305
- * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.
306
- * Prefer adding optional properties here only when broadly useful to most grids.
453
+ * Base contract for a column configuration.
454
+ *
455
+ * Defines the fundamental properties all columns share. Extended by {@link ColumnConfig}
456
+ * with additional features like custom renderers and grouping.
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * // Basic column with common properties
461
+ * const columns: BaseColumnConfig<Employee>[] = [
462
+ * {
463
+ * field: 'name',
464
+ * header: 'Full Name',
465
+ * sortable: true,
466
+ * resizable: true,
467
+ * },
468
+ * {
469
+ * field: 'salary',
470
+ * type: 'number',
471
+ * width: 120,
472
+ * format: (value) => `$${value.toLocaleString()}`,
473
+ * sortComparator: (a, b) => a - b,
474
+ * },
475
+ * {
476
+ * field: 'department',
477
+ * type: 'select',
478
+ * options: [
479
+ * { label: 'Engineering', value: 'eng' },
480
+ * { label: 'Sales', value: 'sales' },
481
+ * ],
482
+ * },
483
+ * ];
484
+ * ```
485
+ *
486
+ * @see {@link ColumnConfig} for full column configuration with renderers
487
+ * @see {@link ColumnType} for type options
307
488
  */
308
489
  export interface BaseColumnConfig<TRow = any, TValue = any> {
309
490
  /** Unique field key referencing property in row objects */
@@ -347,7 +528,54 @@ export interface BaseColumnConfig<TRow = any, TValue = any> {
347
528
  meta?: Record<string, unknown>;
348
529
  }
349
530
  /**
350
- * Full column configuration including optional custom view/renderer & grouping metadata.
531
+ * Full column configuration including custom renderers, editors, and grouping metadata.
532
+ *
533
+ * Extends {@link BaseColumnConfig} with additional features for customizing
534
+ * how cells are displayed and edited.
535
+ *
536
+ * @example
537
+ * ```typescript
538
+ * const columns: ColumnConfig<Employee>[] = [
539
+ * // Basic sortable column
540
+ * { field: 'id', header: 'ID', width: 60, sortable: true },
541
+ *
542
+ * // Column with custom renderer
543
+ * {
544
+ * field: 'name',
545
+ * header: 'Employee',
546
+ * renderer: (ctx) => {
547
+ * const div = document.createElement('div');
548
+ * div.innerHTML = `<img src="${ctx.row.avatar}" /><span>${ctx.value}</span>`;
549
+ * return div;
550
+ * },
551
+ * },
552
+ *
553
+ * // Column with custom header
554
+ * {
555
+ * field: 'email',
556
+ * headerLabelRenderer: (ctx) => `${ctx.value} 📧`,
557
+ * },
558
+ *
559
+ * // Editable column (requires EditingPlugin)
560
+ * {
561
+ * field: 'status',
562
+ * editable: true,
563
+ * editor: (ctx) => {
564
+ * const select = document.createElement('select');
565
+ * // ... editor implementation
566
+ * return select;
567
+ * },
568
+ * },
569
+ *
570
+ * // Hidden column (can be shown via VisibilityPlugin)
571
+ * { field: 'internalNotes', hidden: true },
572
+ * ];
573
+ * ```
574
+ *
575
+ * @see {@link BaseColumnConfig} for basic column properties
576
+ * @see {@link ColumnViewRenderer} for custom cell renderers
577
+ * @see {@link ColumnEditorSpec} for custom cell editors
578
+ * @see {@link HeaderRenderer} for custom header renderers
351
579
  */
352
580
  export interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {
353
581
  /**
@@ -422,12 +650,11 @@ export interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {
422
650
  headerLabelRenderer?: HeaderLabelRenderer<TRow>;
423
651
  /**
424
652
  * Custom header cell renderer. Complete control over the entire header cell.
425
- * When using this, you are responsible for all content and interactions.
653
+ * Resize handles are added automatically for resizable columns.
426
654
  *
427
- * The context provides helper functions to include standard elements if desired:
655
+ * The context provides helper functions to include standard elements:
428
656
  * - `renderSortIcon()` - Returns sort indicator element (null if not sortable)
429
657
  * - `renderFilterButton()` - Returns filter button (null if not filterable)
430
- * - `renderResizeHandle()` - Returns resize handle element
431
658
  *
432
659
  * **Precedence**: `headerRenderer` > `headerLabelRenderer` > `header` > `field`
433
660
  *
@@ -445,8 +672,75 @@ export interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {
445
672
  */
446
673
  headerRenderer?: HeaderRenderer<TRow>;
447
674
  }
675
+ /**
676
+ * Array of column configurations.
677
+ * Convenience type alias for `ColumnConfig<TRow>[]`.
678
+ *
679
+ * @example
680
+ * ```typescript
681
+ * const columns: ColumnConfigMap<Employee> = [
682
+ * { field: 'name', header: 'Full Name', sortable: true },
683
+ * { field: 'email', header: 'Email Address' },
684
+ * { field: 'department', type: 'select', options: deptOptions },
685
+ * ];
686
+ *
687
+ * grid.columns = columns;
688
+ * ```
689
+ *
690
+ * @see {@link ColumnConfig} for individual column options
691
+ * @see {@link GridConfig.columns} for setting columns on the grid
692
+ */
448
693
  export type ColumnConfigMap<TRow = any> = ColumnConfig<TRow>[];
449
- /** External editor spec: tag name, factory function, or external mount spec */
694
+ /**
695
+ * Editor specification for inline cell editing.
696
+ * Supports multiple formats for maximum flexibility.
697
+ *
698
+ * **Format Options:**
699
+ * - `string` - Custom element tag name (e.g., 'my-date-picker')
700
+ * - `function` - Factory function returning an editor element
701
+ * - `object` - External component spec for framework integration
702
+ *
703
+ * @example
704
+ * ```typescript
705
+ * // 1. Custom element tag name
706
+ * columns: [
707
+ * { field: 'date', editor: 'my-date-picker' }
708
+ * ]
709
+ *
710
+ * // 2. Factory function (full control)
711
+ * columns: [
712
+ * {
713
+ * field: 'status',
714
+ * editor: (ctx) => {
715
+ * const select = document.createElement('select');
716
+ * select.innerHTML = `
717
+ * <option value="active">Active</option>
718
+ * <option value="inactive">Inactive</option>
719
+ * `;
720
+ * select.value = ctx.value;
721
+ * select.onchange = () => ctx.commit(select.value);
722
+ * select.onkeydown = (e) => {
723
+ * if (e.key === 'Escape') ctx.cancel();
724
+ * };
725
+ * return select;
726
+ * }
727
+ * }
728
+ * ]
729
+ *
730
+ * // 3. External component (React, Angular, Vue)
731
+ * columns: [
732
+ * {
733
+ * field: 'country',
734
+ * editor: {
735
+ * component: CountrySelect,
736
+ * props: { showFlags: true }
737
+ * }
738
+ * }
739
+ * ]
740
+ * ```
741
+ *
742
+ * @see {@link ColumnEditorContext} for the context passed to factory functions
743
+ */
450
744
  export type ColumnEditorSpec<TRow = unknown, TValue = unknown> = string | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string) | {
451
745
  /** Arbitrary component reference (class, function, token) */
452
746
  component: unknown;
@@ -463,6 +757,37 @@ export type ColumnEditorSpec<TRow = unknown, TValue = unknown> = string | ((cont
463
757
  };
464
758
  /**
465
759
  * Context object provided to editor factories allowing mutation (commit/cancel) of a cell value.
760
+ *
761
+ * The `commit` and `cancel` functions control the editing lifecycle:
762
+ * - Call `commit(newValue)` to save changes and exit edit mode
763
+ * - Call `cancel()` to discard changes and exit edit mode
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * const myEditor: ColumnEditorSpec = (ctx: ColumnEditorContext) => {
768
+ * const input = document.createElement('input');
769
+ * input.value = ctx.value;
770
+ * input.className = 'my-editor';
771
+ *
772
+ * // Save on Enter, cancel on Escape
773
+ * input.onkeydown = (e) => {
774
+ * if (e.key === 'Enter') {
775
+ * ctx.commit(input.value);
776
+ * } else if (e.key === 'Escape') {
777
+ * ctx.cancel();
778
+ * }
779
+ * };
780
+ *
781
+ * // Access row data for validation
782
+ * if (ctx.row.locked) {
783
+ * input.disabled = true;
784
+ * }
785
+ *
786
+ * return input;
787
+ * };
788
+ * ```
789
+ *
790
+ * @see {@link ColumnEditorSpec} for editor specification options
466
791
  */
467
792
  export interface ColumnEditorContext<TRow = any, TValue = any> {
468
793
  /** Underlying full row object for the active edit. */
@@ -480,6 +805,36 @@ export interface ColumnEditorContext<TRow = any, TValue = any> {
480
805
  }
481
806
  /**
482
807
  * Context passed to custom view renderers (pure display – no commit helpers).
808
+ *
809
+ * Used by `viewRenderer` and `renderer` column properties to create
810
+ * custom cell content. Return a DOM node or HTML string.
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * // Status badge renderer
815
+ * const statusRenderer: ColumnViewRenderer = (ctx: CellRenderContext) => {
816
+ * const badge = document.createElement('span');
817
+ * badge.className = `badge badge-${ctx.value}`;
818
+ * badge.textContent = ctx.value;
819
+ * return badge;
820
+ * };
821
+ *
822
+ * // Progress bar using row data
823
+ * const progressRenderer: ColumnViewRenderer = (ctx) => {
824
+ * const bar = document.createElement('div');
825
+ * bar.className = 'progress-bar';
826
+ * bar.style.width = `${ctx.value}%`;
827
+ * bar.title = `${ctx.row.taskName}: ${ctx.value}%`;
828
+ * return bar;
829
+ * };
830
+ *
831
+ * // Return HTML string (simpler, less performant)
832
+ * const htmlRenderer: ColumnViewRenderer = (ctx) => {
833
+ * return `<strong>${ctx.value}</strong>`;
834
+ * };
835
+ * ```
836
+ *
837
+ * @see {@link ColumnViewRenderer} for the renderer function signature
483
838
  */
484
839
  export interface CellRenderContext<TRow = any, TValue = any> {
485
840
  /** Row object for the cell being rendered. */
@@ -497,6 +852,39 @@ export interface CellRenderContext<TRow = any, TValue = any> {
497
852
  */
498
853
  cellEl?: HTMLElement;
499
854
  }
855
+ /**
856
+ * Custom view renderer function for cell content.
857
+ *
858
+ * Returns one of:
859
+ * - `Node` - DOM element to display in the cell
860
+ * - `string` - HTML string (parsed and inserted)
861
+ * - `void | null` - Use default text rendering
862
+ *
863
+ * @example
864
+ * ```typescript
865
+ * // DOM element (recommended for interactivity)
866
+ * const avatarRenderer: ColumnViewRenderer<Employee> = (ctx) => {
867
+ * const img = document.createElement('img');
868
+ * img.src = ctx.row.avatarUrl;
869
+ * img.alt = ctx.row.name;
870
+ * img.className = 'avatar';
871
+ * return img;
872
+ * };
873
+ *
874
+ * // HTML string (simpler, good for static content)
875
+ * const emailRenderer: ColumnViewRenderer = (ctx) => {
876
+ * return `<a href="mailto:${ctx.value}">${ctx.value}</a>`;
877
+ * };
878
+ *
879
+ * // Conditional rendering
880
+ * const conditionalRenderer: ColumnViewRenderer = (ctx) => {
881
+ * if (!ctx.value) return null; // Use default
882
+ * return `<em>${ctx.value}</em>`;
883
+ * };
884
+ * ```
885
+ *
886
+ * @see {@link CellRenderContext} for available context properties
887
+ */
500
888
  export type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (ctx: CellRenderContext<TRow, TValue>) => Node | string | void | null;
501
889
  /**
502
890
  * Context passed to `headerLabelRenderer` for customizing header label content.
@@ -519,7 +907,8 @@ export interface HeaderLabelContext<TRow = unknown> {
519
907
  }
520
908
  /**
521
909
  * Context passed to `headerRenderer` for complete control over header cell content.
522
- * When using this, the user is responsible for all content and interactions.
910
+ * When using this, you control the header content. Resize handles are added automatically
911
+ * for resizable columns.
523
912
  *
524
913
  * @example
525
914
  * ```typescript
@@ -527,10 +916,9 @@ export interface HeaderLabelContext<TRow = unknown> {
527
916
  * const div = document.createElement('div');
528
917
  * div.className = 'custom-header';
529
918
  * div.innerHTML = `<span>${ctx.value}</span>`;
530
- * // Optionally include standard elements
919
+ * // Optionally include sort icon
531
920
  * const sortIcon = ctx.renderSortIcon();
532
921
  * if (sortIcon) div.appendChild(sortIcon);
533
- * div.appendChild(ctx.renderResizeHandle());
534
922
  * return div;
535
923
  * }
536
924
  * ```
@@ -557,20 +945,79 @@ export interface HeaderCellContext<TRow = unknown> {
557
945
  * Note: The actual button is added by FilteringPlugin's afterRender hook.
558
946
  */
559
947
  renderFilterButton: () => HTMLElement | null;
560
- /**
561
- * Render the standard resize handle.
562
- * Returns a handle element that will be managed by the grid's resize controller.
563
- */
564
- renderResizeHandle: () => HTMLElement;
565
948
  }
566
949
  /**
567
950
  * Header label renderer function type.
568
951
  * Customize the label while framework handles sort icons, filter buttons, resize handles.
952
+ *
953
+ * Use this for simple label customizations without taking over the entire header.
954
+ * The grid automatically appends sort icons, filter buttons, and resize handles.
955
+ *
956
+ * @example
957
+ * ```typescript
958
+ * // Add required indicator
959
+ * const requiredHeader: HeaderLabelRenderer = (ctx) => {
960
+ * return `${ctx.value} <span style="color: red;">*</span>`;
961
+ * };
962
+ *
963
+ * // Add unit suffix
964
+ * const priceHeader: HeaderLabelRenderer = (ctx) => {
965
+ * const span = document.createElement('span');
966
+ * span.innerHTML = `${ctx.value} <small>(USD)</small>`;
967
+ * return span;
968
+ * };
969
+ *
970
+ * // Column config usage
971
+ * columns: [
972
+ * { field: 'name', headerLabelRenderer: requiredHeader },
973
+ * { field: 'price', headerLabelRenderer: priceHeader },
974
+ * ]
975
+ * ```
976
+ *
977
+ * @see {@link HeaderLabelContext} for context properties
978
+ * @see {@link HeaderRenderer} for full header control
569
979
  */
570
980
  export type HeaderLabelRenderer<TRow = unknown> = (ctx: HeaderLabelContext<TRow>) => Node | string | void | null;
571
981
  /**
572
982
  * Header cell renderer function type.
573
983
  * Full control over header cell content. User is responsible for all content and interactions.
984
+ *
985
+ * When using this, you have complete control but must manually include
986
+ * sort icons, filter buttons, and resize handles using the helper functions.
987
+ *
988
+ * @example
989
+ * ```typescript
990
+ * // Custom header with all standard elements
991
+ * const customHeader: HeaderRenderer = (ctx) => {
992
+ * const div = document.createElement('div');
993
+ * div.className = 'custom-header';
994
+ * div.innerHTML = `<span class="label">${ctx.value}</span>`;
995
+ *
996
+ * // Add sort icon (returns null if not sortable)
997
+ * const sortIcon = ctx.renderSortIcon();
998
+ * if (sortIcon) div.appendChild(sortIcon);
999
+ *
1000
+ * // Add filter button (returns null if not filterable)
1001
+ * const filterBtn = ctx.renderFilterButton();
1002
+ * if (filterBtn) div.appendChild(filterBtn);
1003
+ *
1004
+ * // Resize handles are added automatically for resizable columns
1005
+ * return div;
1006
+ * };
1007
+ *
1008
+ * // Minimal header (no sort/resize)
1009
+ * const minimalHeader: HeaderRenderer = (ctx) => {
1010
+ * return `<div class="minimal">${ctx.value}</div>`;
1011
+ * };
1012
+ *
1013
+ * // Column config usage
1014
+ * columns: [
1015
+ * { field: 'name', headerRenderer: customHeader },
1016
+ * ]
1017
+ * ```
1018
+ *
1019
+ * @see {@link HeaderCellContext} for context properties and helper functions
1020
+ * @see {@link HeaderLabelRenderer} for simpler label-only customization
574
1021
  */
575
1022
  export type HeaderRenderer<TRow = unknown> = (ctx: HeaderCellContext<TRow>) => Node | string | void | null;
576
1023
  /**
@@ -654,6 +1101,28 @@ export interface ColumnParsedAttributes {
654
1101
  * Extended column config used internally.
655
1102
  * Includes all internal properties needed during grid lifecycle.
656
1103
  *
1104
+ * Plugin developers may need to access these when working with
1105
+ * column caching and compiled templates.
1106
+ *
1107
+ * @example
1108
+ * ```typescript
1109
+ * import type { ColumnInternal } from '@toolbox-web/grid';
1110
+ *
1111
+ * class MyPlugin extends BaseGridPlugin {
1112
+ * afterRender(): void {
1113
+ * // Access internal column properties
1114
+ * const columns = this.columns as ColumnInternal[];
1115
+ * for (const col of columns) {
1116
+ * // Check if column was auto-sized
1117
+ * if (col.__autoSized) {
1118
+ * console.log(`${col.field} was auto-sized`);
1119
+ * }
1120
+ * }
1121
+ * }
1122
+ * }
1123
+ * ```
1124
+ *
1125
+ * @see {@link ColumnConfig} for public column properties
657
1126
  * @category Plugin Development
658
1127
  * @internal
659
1128
  */
@@ -709,6 +1178,21 @@ export interface CompiledViewFunction<T = any> {
709
1178
  /**
710
1179
  * Runtime cell context used internally for compiled template execution.
711
1180
  *
1181
+ * Contains the minimal context needed to render a cell: the row data,
1182
+ * cell value, field name, and column configuration.
1183
+ *
1184
+ * @example
1185
+ * ```typescript
1186
+ * import type { CellContext, ColumnInternal } from '@toolbox-web/grid';
1187
+ *
1188
+ * // Used internally by compiled templates
1189
+ * const renderCell = (ctx: CellContext) => {
1190
+ * return `<span title="${ctx.field}">${ctx.value}</span>`;
1191
+ * };
1192
+ * ```
1193
+ *
1194
+ * @see {@link CellRenderContext} for public cell render context
1195
+ * @see {@link EditorExecContext} for editor context with commit/cancel
712
1196
  * @category Plugin Development
713
1197
  */
714
1198
  export interface CellContext<T = any> {
@@ -720,6 +1204,27 @@ export interface CellContext<T = any> {
720
1204
  /**
721
1205
  * Internal editor execution context extending the generic cell context with commit helpers.
722
1206
  *
1207
+ * Used internally by the editing system. For public editor APIs,
1208
+ * prefer using {@link ColumnEditorContext}.
1209
+ *
1210
+ * @example
1211
+ * ```typescript
1212
+ * import type { EditorExecContext } from '@toolbox-web/grid';
1213
+ *
1214
+ * // Internal editor template execution
1215
+ * const execEditor = (ctx: EditorExecContext) => {
1216
+ * const input = document.createElement('input');
1217
+ * input.value = String(ctx.value);
1218
+ * input.onkeydown = (e) => {
1219
+ * if (e.key === 'Enter') ctx.commit(input.value);
1220
+ * if (e.key === 'Escape') ctx.cancel();
1221
+ * };
1222
+ * return input;
1223
+ * };
1224
+ * ```
1225
+ *
1226
+ * @see {@link ColumnEditorContext} for public editor context
1227
+ * @see {@link CellContext} for base cell context
723
1228
  * @category Plugin Development
724
1229
  */
725
1230
  export interface EditorExecContext<T = any> extends CellContext<T> {
@@ -729,6 +1234,29 @@ export interface EditorExecContext<T = any> extends CellContext<T> {
729
1234
  /**
730
1235
  * Controller managing drag-based column resize lifecycle.
731
1236
  *
1237
+ * Exposed internally for plugins that need to interact with resize behavior.
1238
+ *
1239
+ * @example
1240
+ * ```typescript
1241
+ * import type { ResizeController, InternalGrid } from '@toolbox-web/grid';
1242
+ *
1243
+ * class MyPlugin extends BaseGridPlugin {
1244
+ * handleColumnAction(colIndex: number): void {
1245
+ * const grid = this.grid as InternalGrid;
1246
+ * const resizeCtrl = grid._resizeController;
1247
+ *
1248
+ * // Check if resize is in progress
1249
+ * if (resizeCtrl?.isResizing) {
1250
+ * return; // Don't interfere
1251
+ * }
1252
+ *
1253
+ * // Reset column to configured width
1254
+ * resizeCtrl?.resetColumn(colIndex);
1255
+ * }
1256
+ * }
1257
+ * ```
1258
+ *
1259
+ * @see {@link ColumnResizeDetail} for resize event details
732
1260
  * @category Plugin Development
733
1261
  */
734
1262
  export interface ResizeController {
@@ -742,6 +1270,26 @@ export interface ResizeController {
742
1270
  /**
743
1271
  * Virtual window bookkeeping; modified in-place as scroll position changes.
744
1272
  *
1273
+ * Tracks virtualization state for row rendering. The grid only renders
1274
+ * rows within the visible viewport window (start to end) plus overscan.
1275
+ *
1276
+ * @example
1277
+ * ```typescript
1278
+ * import type { VirtualState, InternalGrid } from '@toolbox-web/grid';
1279
+ *
1280
+ * class MyPlugin extends BaseGridPlugin {
1281
+ * logVirtualWindow(): void {
1282
+ * const grid = this.grid as InternalGrid;
1283
+ * const vs = grid.virtualization;
1284
+ *
1285
+ * console.log(`Row height: ${vs.rowHeight}px`);
1286
+ * console.log(`Visible rows: ${vs.start} to ${vs.end}`);
1287
+ * console.log(`Virtualization: ${vs.enabled ? 'on' : 'off'}`);
1288
+ * }
1289
+ * }
1290
+ * ```
1291
+ *
1292
+ * @see {@link GridConfig.rowHeight} for configuring row height
745
1293
  * @category Plugin Development
746
1294
  */
747
1295
  export interface VirtualState {
@@ -770,7 +1318,37 @@ export type InputLikeElement = HTMLInputElement | HTMLTextAreaElement | HTMLSele
770
1318
  };
771
1319
  /**
772
1320
  * Group row rendering customization options.
773
- * Used within grouping-rows plugin config for presentation of group rows.
1321
+ * Controls how group header rows are displayed in the GroupingRowsPlugin.
1322
+ *
1323
+ * @example
1324
+ * ```typescript
1325
+ * import { GroupingRowsPlugin } from '@toolbox-web/grid/all';
1326
+ *
1327
+ * new GroupingRowsPlugin({
1328
+ * groupBy: ['department', 'team'],
1329
+ * render: {
1330
+ * // Group row spans all columns
1331
+ * fullWidth: true,
1332
+ *
1333
+ * // Custom label format
1334
+ * formatLabel: (value, depth, key) => {
1335
+ * if (depth === 0) return `Department: ${value}`;
1336
+ * return `Team: ${value}`;
1337
+ * },
1338
+ *
1339
+ * // Show aggregates in group rows (when not fullWidth)
1340
+ * aggregators: {
1341
+ * salary: 'sum',
1342
+ * age: 'avg',
1343
+ * },
1344
+ *
1345
+ * // Custom CSS class
1346
+ * class: 'my-group-row',
1347
+ * },
1348
+ * });
1349
+ * ```
1350
+ *
1351
+ * @see {@link AggregatorRef} for aggregation options
774
1352
  */
775
1353
  export interface RowGroupRenderConfig {
776
1354
  /** If true, group rows span all columns (single full-width cell). Default false. */
@@ -782,12 +1360,78 @@ export interface RowGroupRenderConfig {
782
1360
  /** Additional CSS class applied to each group row root element. */
783
1361
  class?: string;
784
1362
  }
1363
+ /**
1364
+ * Reference to an aggregation function for footer/group summaries.
1365
+ *
1366
+ * Can be either:
1367
+ * - A built-in aggregator name: `'sum'`, `'avg'`, `'min'`, `'max'`, `'count'`
1368
+ * - A custom function that calculates the aggregate value
1369
+ *
1370
+ * @example
1371
+ * ```typescript
1372
+ * // Built-in aggregator
1373
+ * { field: 'amount', aggregator: 'sum' }
1374
+ *
1375
+ * // Custom aggregator function
1376
+ * { field: 'price', aggregator: (rows, field) => {
1377
+ * const values = rows.map(r => r[field]).filter(v => v != null);
1378
+ * return values.length ? Math.max(...values) : null;
1379
+ * }}
1380
+ * ```
1381
+ *
1382
+ * @see {@link RowGroupRenderConfig} for using aggregators in group rows
1383
+ */
785
1384
  export type AggregatorRef = string | ((rows: unknown[], field: string, column?: unknown) => unknown);
786
- /** Result of automatic column inference from sample rows. */
1385
+ /**
1386
+ * Result of automatic column inference from sample rows.
1387
+ *
1388
+ * When no columns are configured, the grid analyzes the first row of data
1389
+ * to automatically generate column definitions with inferred types.
1390
+ *
1391
+ * @example
1392
+ * ```typescript
1393
+ * // Automatic inference (no columns configured)
1394
+ * grid.rows = [
1395
+ * { name: 'Alice', age: 30, active: true, hireDate: new Date() },
1396
+ * ];
1397
+ * // Grid infers:
1398
+ * // - name: type 'string'
1399
+ * // - age: type 'number'
1400
+ * // - active: type 'boolean'
1401
+ * // - hireDate: type 'date'
1402
+ *
1403
+ * // Access inferred result programmatically
1404
+ * const config = await grid.getConfig();
1405
+ * console.log(config.columns); // Inferred columns
1406
+ * ```
1407
+ *
1408
+ * @see {@link ColumnConfig} for column configuration options
1409
+ * @see {@link ColumnType} for type inference rules
1410
+ */
787
1411
  export interface InferredColumnResult<TRow = unknown> {
1412
+ /** Generated column configurations based on data analysis */
788
1413
  columns: ColumnConfigMap<TRow>;
1414
+ /** Map of field names to their inferred types */
789
1415
  typeMap: Record<string, ColumnType>;
790
1416
  }
1417
+ /**
1418
+ * Column sizing mode.
1419
+ *
1420
+ * - `'fixed'` - Columns use their configured widths. Horizontal scrolling if content overflows.
1421
+ * - `'stretch'` - Columns stretch proportionally to fill available width. No horizontal scrolling.
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * // Fixed widths - good for many columns
1426
+ * grid.fitMode = 'fixed';
1427
+ *
1428
+ * // Stretch to fill - good for few columns
1429
+ * grid.fitMode = 'stretch';
1430
+ *
1431
+ * // Via gridConfig
1432
+ * grid.gridConfig = { fitMode: 'stretch' };
1433
+ * ```
1434
+ */
791
1435
  export declare const FitModeEnum: {
792
1436
  readonly STRETCH: "stretch";
793
1437
  readonly FIXED: "fixed";
@@ -798,11 +1442,30 @@ export type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum];
798
1442
  * This interface is defined here to avoid circular imports with BaseGridPlugin.
799
1443
  * All plugins must satisfy this shape (BaseGridPlugin implements it).
800
1444
  *
801
- * @category Plugin Development
802
- */
803
- export interface GridPlugin {
804
- /** Unique plugin identifier */
805
- readonly name: string;
1445
+ * @example
1446
+ * ```typescript
1447
+ * // Using plugins in grid config
1448
+ * import { SelectionPlugin, FilteringPlugin } from '@toolbox-web/grid/all';
1449
+ *
1450
+ * grid.gridConfig = {
1451
+ * plugins: [
1452
+ * new SelectionPlugin({ mode: 'row' }),
1453
+ * new FilteringPlugin({ debounceMs: 200 }),
1454
+ * ],
1455
+ * };
1456
+ *
1457
+ * // Accessing plugin instance at runtime
1458
+ * const selection = grid.getPlugin(SelectionPlugin);
1459
+ * if (selection) {
1460
+ * selection.selectAll();
1461
+ * }
1462
+ * ```
1463
+ *
1464
+ * @category Plugin Development
1465
+ */
1466
+ export interface GridPlugin {
1467
+ /** Unique plugin identifier */
1468
+ readonly name: string;
806
1469
  /** Plugin version */
807
1470
  readonly version: string;
808
1471
  /** CSS styles to inject into the grid */
@@ -840,7 +1503,11 @@ export interface GridPlugin {
840
1503
  * ```
841
1504
  */
842
1505
  export interface GridConfig<TRow = any> {
843
- /** Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM. */
1506
+ /**
1507
+ * Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM.
1508
+ * @see {@link ColumnConfig} for column options
1509
+ * @see {@link ColumnConfigMap}
1510
+ */
844
1511
  columns?: ColumnConfigMap<TRow>;
845
1512
  /**
846
1513
  * Dynamic CSS class(es) for data rows.
@@ -880,6 +1547,27 @@ export interface GridConfig<TRow = any> {
880
1547
  * ```
881
1548
  */
882
1549
  sortable?: boolean;
1550
+ /**
1551
+ * Grid-wide resizing toggle.
1552
+ * When false, disables column resizing for all columns regardless of their individual `resizable` setting.
1553
+ * When true (default), columns with `resizable: true` (or resizable not set, since it defaults to true) can be resized.
1554
+ *
1555
+ * This affects:
1556
+ * - Resize handle visibility in header cells
1557
+ * - Double-click to auto-size behavior
1558
+ *
1559
+ * @default true
1560
+ *
1561
+ * @example
1562
+ * ```typescript
1563
+ * // Disable all column resizing
1564
+ * gridConfig = { resizable: false };
1565
+ *
1566
+ * // Enable resizing (default) - individual columns can opt out with resizable: false
1567
+ * gridConfig = { resizable: true };
1568
+ * ```
1569
+ */
1570
+ resizable?: boolean;
883
1571
  /**
884
1572
  * Row height in pixels for virtualization calculations.
885
1573
  * The virtualization system assumes uniform row heights for performance.
@@ -1043,9 +1731,52 @@ export interface GridConfig<TRow = any> {
1043
1731
  * ```
1044
1732
  */
1045
1733
  gridAriaDescribedBy?: string;
1734
+ /**
1735
+ * Custom renderer for the loading overlay.
1736
+ *
1737
+ * When provided, replaces the default spinner with custom content.
1738
+ * Receives a context object with the current loading size.
1739
+ *
1740
+ * @example
1741
+ * ```typescript
1742
+ * // Simple text loading indicator
1743
+ * loadingRenderer: () => {
1744
+ * const el = document.createElement('div');
1745
+ * el.textContent = 'Loading...';
1746
+ * return el;
1747
+ * }
1748
+ *
1749
+ * // Custom spinner component
1750
+ * loadingRenderer: (ctx) => {
1751
+ * const spinner = document.createElement('my-spinner');
1752
+ * spinner.size = ctx.size === 'large' ? 48 : 24;
1753
+ * return spinner;
1754
+ * }
1755
+ * ```
1756
+ */
1757
+ loadingRenderer?: LoadingRenderer;
1046
1758
  }
1047
1759
  /**
1048
1760
  * Sort state passed to custom sort handlers.
1761
+ * Represents the current sorting configuration for a column.
1762
+ *
1763
+ * @example
1764
+ * ```typescript
1765
+ * // In a custom sort handler
1766
+ * const sortHandler: SortHandler = (rows, sortState, columns) => {
1767
+ * const { field, direction } = sortState;
1768
+ * console.log(`Sorting by ${field} ${direction === 1 ? 'ASC' : 'DESC'}`);
1769
+ *
1770
+ * return [...rows].sort((a, b) => {
1771
+ * const aVal = a[field];
1772
+ * const bVal = b[field];
1773
+ * return (aVal < bVal ? -1 : aVal > bVal ? 1 : 0) * direction;
1774
+ * });
1775
+ * };
1776
+ * ```
1777
+ *
1778
+ * @see {@link SortHandler} for custom sort handler signature
1779
+ * @see {@link SortChangeDetail} for sort change events
1049
1780
  */
1050
1781
  export interface SortState {
1051
1782
  /** Field to sort by */
@@ -1056,12 +1787,136 @@ export interface SortState {
1056
1787
  /**
1057
1788
  * Custom sort handler function signature.
1058
1789
  *
1790
+ * Enables full control over sorting behavior including server-side sorting,
1791
+ * custom algorithms, or multi-column sorting.
1792
+ *
1059
1793
  * @param rows - Current row array to sort
1060
1794
  * @param sortState - Sort field and direction
1061
1795
  * @param columns - Column configurations (for accessing sortComparator)
1062
1796
  * @returns Sorted array (sync) or Promise resolving to sorted array (async)
1797
+ *
1798
+ * @example
1799
+ * ```typescript
1800
+ * // Custom client-side sort with locale awareness
1801
+ * const localeSortHandler: SortHandler<Employee> = (rows, state, cols) => {
1802
+ * const col = cols.find(c => c.field === state.field);
1803
+ * return [...rows].sort((a, b) => {
1804
+ * const aVal = String(a[state.field] ?? '');
1805
+ * const bVal = String(b[state.field] ?? '');
1806
+ * return aVal.localeCompare(bVal) * state.direction;
1807
+ * });
1808
+ * };
1809
+ *
1810
+ * // Server-side sorting
1811
+ * const serverSortHandler: SortHandler<Employee> = async (rows, state) => {
1812
+ * const response = await fetch(
1813
+ * `/api/employees?sortBy=${state.field}&dir=${state.direction}`
1814
+ * );
1815
+ * return response.json();
1816
+ * };
1817
+ *
1818
+ * grid.gridConfig = {
1819
+ * sortHandler: localeSortHandler,
1820
+ * };
1821
+ * ```
1822
+ *
1823
+ * @see {@link SortState} for the sort state object
1824
+ * @see {@link GridConfig.sortHandler} for configuring the handler
1825
+ * @see {@link BaseColumnConfig.sortComparator} for column-level comparators
1063
1826
  */
1064
1827
  export type SortHandler<TRow = any> = (rows: TRow[], sortState: SortState, columns: ColumnConfig<TRow>[]) => TRow[] | Promise<TRow[]>;
1828
+ /**
1829
+ * Loading indicator size variant.
1830
+ *
1831
+ * - `'large'`: 48x48px max - used for grid-level loading overlay (`grid.loading = true`)
1832
+ * - `'small'`: Follows row height - used for row/cell loading states
1833
+ *
1834
+ * @example
1835
+ * ```typescript
1836
+ * // Custom loading renderer adapting to size
1837
+ * const myLoader: LoadingRenderer = (ctx) => {
1838
+ * if (ctx.size === 'large') {
1839
+ * // Full overlay spinner
1840
+ * return '<div class="spinner-lg"></div>';
1841
+ * }
1842
+ * // Inline row/cell spinner
1843
+ * return '<span class="spinner-sm"></span>';
1844
+ * };
1845
+ * ```
1846
+ *
1847
+ * @see {@link LoadingRenderer} for custom loading renderer
1848
+ * @see {@link LoadingContext} for context passed to renderers
1849
+ */
1850
+ export type LoadingSize = 'large' | 'small';
1851
+ /**
1852
+ * Context passed to custom loading renderers.
1853
+ *
1854
+ * Provides information about the loading indicator being rendered,
1855
+ * allowing the renderer to adapt its appearance based on the size variant.
1856
+ *
1857
+ * @example
1858
+ * ```typescript
1859
+ * const myLoadingRenderer: LoadingRenderer = (ctx: LoadingContext) => {
1860
+ * if (ctx.size === 'large') {
1861
+ * // Full-size spinner for grid-level loading
1862
+ * return '<div class="large-spinner"></div>';
1863
+ * } else {
1864
+ * // Compact spinner for row/cell loading
1865
+ * return '<div class="small-spinner"></div>';
1866
+ * }
1867
+ * };
1868
+ * ```
1869
+ *
1870
+ * @see {@link LoadingRenderer} for the renderer function signature
1871
+ * @see {@link LoadingSize} for available size variants
1872
+ */
1873
+ export interface LoadingContext {
1874
+ /** The size variant being rendered: 'large' for grid-level, 'small' for row/cell */
1875
+ size: LoadingSize;
1876
+ }
1877
+ /**
1878
+ * Custom loading renderer function.
1879
+ * Returns an element or HTML string to display as the loading indicator.
1880
+ *
1881
+ * Used with the `loadingRenderer` property in {@link GridConfig} to replace
1882
+ * the default spinner with custom content.
1883
+ *
1884
+ * @param context - Context containing size information
1885
+ * @returns HTMLElement or HTML string
1886
+ *
1887
+ * @example
1888
+ * ```typescript
1889
+ * // Simple text loading indicator
1890
+ * const textLoader: LoadingRenderer = () => {
1891
+ * const el = document.createElement('div');
1892
+ * el.textContent = 'Loading...';
1893
+ * return el;
1894
+ * };
1895
+ *
1896
+ * // Custom spinner with size awareness
1897
+ * const customSpinner: LoadingRenderer = (ctx) => {
1898
+ * const spinner = document.createElement('my-spinner');
1899
+ * spinner.size = ctx.size === 'large' ? 48 : 24;
1900
+ * return spinner;
1901
+ * };
1902
+ *
1903
+ * // Material Design-style progress bar
1904
+ * const progressBar: LoadingRenderer = () => {
1905
+ * const container = document.createElement('div');
1906
+ * container.className = 'progress-bar-container';
1907
+ * container.innerHTML = '<div class="progress-bar"></div>';
1908
+ * return container;
1909
+ * };
1910
+ *
1911
+ * grid.gridConfig = {
1912
+ * loadingRenderer: customSpinner,
1913
+ * };
1914
+ * ```
1915
+ *
1916
+ * @see {@link LoadingContext} for the context object passed to the renderer
1917
+ * @see {@link LoadingSize} for size variants ('large' | 'small')
1918
+ */
1919
+ export type LoadingRenderer = (context: LoadingContext) => HTMLElement | string;
1065
1920
  /**
1066
1921
  * Indicates the origin of a data change.
1067
1922
  * Used to prevent infinite loops in cascade update handlers.
@@ -1070,6 +1925,25 @@ export type SortHandler<TRow = any> = (rows: TRow[], sortState: SortState, colum
1070
1925
  * - `'cascade'`: Triggered by `updateRow()` in an event handler
1071
1926
  * - `'api'`: External programmatic update via `grid.updateRow()`
1072
1927
  *
1928
+ * @example
1929
+ * ```typescript
1930
+ * grid.addEventListener('cell-change', (e) => {
1931
+ * const { source, field, newValue } = e.detail;
1932
+ *
1933
+ * // Only cascade updates for user edits
1934
+ * if (source === 'user' && field === 'price') {
1935
+ * // Update calculated field (marked as 'cascade')
1936
+ * grid.updateRow(e.detail.rowId, {
1937
+ * total: newValue * e.detail.row.quantity,
1938
+ * });
1939
+ * }
1940
+ *
1941
+ * // Ignore cascade updates to prevent infinite loops
1942
+ * if (source === 'cascade') return;
1943
+ * });
1944
+ * ```
1945
+ *
1946
+ * @see {@link CellChangeDetail} for the event detail containing source
1073
1947
  * @category Data Management
1074
1948
  */
1075
1949
  export type UpdateSource = 'user' | 'cascade' | 'api';
@@ -1077,6 +1951,28 @@ export type UpdateSource = 'user' | 'cascade' | 'api';
1077
1951
  * Detail for cell-change event (emitted by core after mutation).
1078
1952
  * This is an informational event that fires for ALL data mutations.
1079
1953
  *
1954
+ * Use this event for:
1955
+ * - Logging/auditing changes
1956
+ * - Cascading updates (updating other fields based on a change)
1957
+ * - Syncing changes to external state
1958
+ *
1959
+ * @example
1960
+ * ```typescript
1961
+ * grid.addEventListener('cell-change', (e: CustomEvent<CellChangeDetail>) => {
1962
+ * const { row, rowId, field, oldValue, newValue, source } = e.detail;
1963
+ *
1964
+ * console.log(`${field} changed from ${oldValue} to ${newValue}`);
1965
+ * console.log(`Change source: ${source}`);
1966
+ *
1967
+ * // Cascade: update total when price changes
1968
+ * if (source === 'user' && field === 'price') {
1969
+ * grid.updateRow(rowId, { total: newValue * row.quantity });
1970
+ * }
1971
+ * });
1972
+ * ```
1973
+ *
1974
+ * @see {@link UpdateSource} for understanding change origins
1975
+ * @see {@link CellCommitDetail} for the commit event (editing lifecycle)
1080
1976
  * @category Events
1081
1977
  */
1082
1978
  export interface CellChangeDetail<TRow = unknown> {
@@ -1100,6 +1996,23 @@ export interface CellChangeDetail<TRow = unknown> {
1100
1996
  /**
1101
1997
  * Batch update specification for updateRows().
1102
1998
  *
1999
+ * Used when you need to update multiple rows at once efficiently.
2000
+ * The grid will batch all updates and trigger a single re-render.
2001
+ *
2002
+ * @example
2003
+ * ```typescript
2004
+ * // Update multiple rows in a single batch
2005
+ * const updates: RowUpdate<Employee>[] = [
2006
+ * { id: 'emp-1', changes: { status: 'active', updatedAt: new Date() } },
2007
+ * { id: 'emp-2', changes: { status: 'inactive' } },
2008
+ * { id: 'emp-3', changes: { salary: 75000 } },
2009
+ * ];
2010
+ *
2011
+ * grid.updateRows(updates);
2012
+ * ```
2013
+ *
2014
+ * @see {@link CellChangeDetail} for individual change events
2015
+ * @see {@link GridConfig.getRowId} for row identification
1103
2016
  * @category Data Management
1104
2017
  */
1105
2018
  export interface RowUpdate<TRow = unknown> {
@@ -1113,6 +2026,20 @@ export interface RowUpdate<TRow = unknown> {
1113
2026
  * - `true` or `'on'`: Animations always enabled
1114
2027
  * - `false` or `'off'`: Animations always disabled
1115
2028
  * - `'reduced-motion'`: Respects `prefers-reduced-motion` media query (default)
2029
+ *
2030
+ * @example
2031
+ * ```typescript
2032
+ * // Force animations on (ignore system preference)
2033
+ * grid.gridConfig = { animation: { mode: 'on' } };
2034
+ *
2035
+ * // Disable all animations
2036
+ * grid.gridConfig = { animation: { mode: false } };
2037
+ *
2038
+ * // Respect user's accessibility settings (default)
2039
+ * grid.gridConfig = { animation: { mode: 'reduced-motion' } };
2040
+ * ```
2041
+ *
2042
+ * @see {@link AnimationConfig} for full animation configuration
1116
2043
  */
1117
2044
  export type AnimationMode = boolean | 'on' | 'off' | 'reduced-motion';
1118
2045
  /**
@@ -1121,6 +2048,21 @@ export type AnimationMode = boolean | 'on' | 'off' | 'reduced-motion';
1121
2048
  * - `'fade'`: Opacity fade animation
1122
2049
  * - `'flip'`: FLIP technique for position changes (First, Last, Invert, Play)
1123
2050
  * - `false`: No animation for this specific feature
2051
+ *
2052
+ * @example
2053
+ * ```typescript
2054
+ * // Plugin-specific animation styles
2055
+ * new TreePlugin({
2056
+ * expandAnimation: 'slide', // Slide children down when expanding
2057
+ * });
2058
+ *
2059
+ * new ReorderPlugin({
2060
+ * animation: 'flip', // FLIP animation for column reordering
2061
+ * });
2062
+ * ```
2063
+ *
2064
+ * @see {@link AnimationConfig} for grid-wide animation settings
2065
+ * @see {@link ExpandCollapseAnimation} for expand/collapse-specific styles
1124
2066
  */
1125
2067
  export type AnimationStyle = 'slide' | 'fade' | 'flip' | false;
1126
2068
  /**
@@ -1129,6 +2071,21 @@ export type AnimationStyle = 'slide' | 'fade' | 'flip' | false;
1129
2071
  * - `'slide'`: Slide down/up animation for expanding/collapsing content
1130
2072
  * - `'fade'`: Fade in/out animation
1131
2073
  * - `false`: No animation
2074
+ *
2075
+ * @example
2076
+ * ```typescript
2077
+ * // Tree rows slide down when expanding
2078
+ * new TreePlugin({ expandAnimation: 'slide' });
2079
+ *
2080
+ * // Row groups fade in/out
2081
+ * new GroupingRowsPlugin({ expandAnimation: 'fade' });
2082
+ *
2083
+ * // Master-detail panels with no animation
2084
+ * new MasterDetailPlugin({ expandAnimation: false });
2085
+ * ```
2086
+ *
2087
+ * @see {@link AnimationStyle} for all animation styles
2088
+ * @see {@link AnimationConfig} for grid-wide settings
1132
2089
  */
1133
2090
  export type ExpandCollapseAnimation = 'slide' | 'fade' | false;
1134
2091
  /**
@@ -1136,12 +2093,51 @@ export type ExpandCollapseAnimation = 'slide' | 'fade' | false;
1136
2093
  * - `'change'`: Flash highlight when row data changes (e.g., after cell edit)
1137
2094
  * - `'insert'`: Slide-in animation for newly added rows
1138
2095
  * - `'remove'`: Fade-out animation for rows being removed
2096
+ *
2097
+ * @example
2098
+ * ```typescript
2099
+ * // Internal usage - row animation is triggered automatically:
2100
+ * // - 'change' after cell-commit event
2101
+ * // - 'insert' when rows are added to the grid
2102
+ * // - 'remove' when rows are deleted
2103
+ *
2104
+ * // The animation respects AnimationConfig.mode
2105
+ * grid.gridConfig = {
2106
+ * animation: { mode: 'on', duration: 300 },
2107
+ * };
2108
+ * ```
2109
+ *
2110
+ * @see {@link AnimationConfig} for animation configuration
1139
2111
  */
1140
2112
  export type RowAnimationType = 'change' | 'insert' | 'remove';
1141
2113
  /**
1142
2114
  * Grid-wide animation configuration.
1143
2115
  * Controls global animation behavior - individual plugins define their own animation styles.
1144
2116
  * Duration and easing values set corresponding CSS variables on the grid element.
2117
+ *
2118
+ * @example
2119
+ * ```typescript
2120
+ * // Enable animations regardless of system preferences
2121
+ * grid.gridConfig = {
2122
+ * animation: {
2123
+ * mode: 'on',
2124
+ * duration: 300,
2125
+ * easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
2126
+ * },
2127
+ * };
2128
+ *
2129
+ * // Disable all animations
2130
+ * grid.gridConfig = {
2131
+ * animation: { mode: 'off' },
2132
+ * };
2133
+ *
2134
+ * // Respect user's reduced-motion preference (default)
2135
+ * grid.gridConfig = {
2136
+ * animation: { mode: 'reduced-motion' },
2137
+ * };
2138
+ * ```
2139
+ *
2140
+ * @see {@link AnimationMode} for mode options
1145
2141
  */
1146
2142
  export interface AnimationConfig {
1147
2143
  /**
@@ -1169,6 +2165,27 @@ export type IconValue = string | HTMLElement;
1169
2165
  /**
1170
2166
  * Grid-wide icon configuration.
1171
2167
  * All icons are optional - sensible defaults are used when not specified.
2168
+ *
2169
+ * Icons can be text (including emoji), HTML strings (for SVG), or HTMLElement instances.
2170
+ *
2171
+ * @example
2172
+ * ```typescript
2173
+ * grid.gridConfig = {
2174
+ * icons: {
2175
+ * // Emoji icons
2176
+ * expand: '➕',
2177
+ * collapse: '➖',
2178
+ *
2179
+ * // Custom SVG icon
2180
+ * sortAsc: '<svg viewBox="0 0 16 16"><path d="M8 4l4 8H4z"/></svg>',
2181
+ *
2182
+ * // Font icon class (wrap in span)
2183
+ * filter: '<span class="icon icon-filter"></span>',
2184
+ * },
2185
+ * };
2186
+ * ```
2187
+ *
2188
+ * @see {@link IconValue} for allowed icon formats
1172
2189
  */
1173
2190
  export interface GridIcons {
1174
2191
  /** Expand icon for collapsed items (trees, groups, details). Default: '▶' */
@@ -1198,6 +2215,39 @@ export interface GridIcons {
1198
2215
  export declare const DEFAULT_GRID_ICONS: Required<GridIcons>;
1199
2216
  /**
1200
2217
  * Shell configuration for the grid's optional header bar and tool panels.
2218
+ *
2219
+ * The shell provides a wrapper around the grid with:
2220
+ * - Header bar with title, toolbar buttons, and custom content
2221
+ * - Collapsible side panel for filters, column visibility, settings, etc.
2222
+ *
2223
+ * @example
2224
+ * ```typescript
2225
+ * grid.gridConfig = {
2226
+ * shell: {
2227
+ * header: {
2228
+ * title: 'Employee Directory',
2229
+ * },
2230
+ * toolPanel: {
2231
+ * position: 'right',
2232
+ * defaultOpen: 'columns', // Open by default
2233
+ * },
2234
+ * },
2235
+ * plugins: [new VisibilityPlugin()], // Adds "Columns" panel
2236
+ * };
2237
+ *
2238
+ * // Register custom tool panels
2239
+ * grid.registerToolPanel({
2240
+ * id: 'filters',
2241
+ * title: 'Filters',
2242
+ * icon: '🔍',
2243
+ * render: (container) => {
2244
+ * container.innerHTML = '<div>Filter controls...</div>';
2245
+ * },
2246
+ * });
2247
+ * ```
2248
+ *
2249
+ * @see {@link ShellHeaderConfig} for header options
2250
+ * @see {@link ToolPanelConfig} for tool panel options
1201
2251
  */
1202
2252
  export interface ShellConfig {
1203
2253
  /** Shell header bar configuration */
@@ -1280,6 +2330,34 @@ export interface ToolbarContentDefinition {
1280
2330
  }
1281
2331
  /**
1282
2332
  * Tool panel definition registered by plugins or consumers.
2333
+ *
2334
+ * Register via `grid.registerToolPanel()` to add panels to the sidebar.
2335
+ * Panels appear as collapsible sections with icons and titles.
2336
+ *
2337
+ * @example
2338
+ * ```typescript
2339
+ * grid.registerToolPanel({
2340
+ * id: 'filters',
2341
+ * title: 'Filters',
2342
+ * icon: '🔍',
2343
+ * tooltip: 'Filter grid data',
2344
+ * order: 10, // Lower = appears first
2345
+ * render: (container) => {
2346
+ * container.innerHTML = `
2347
+ * <div class="filter-panel">
2348
+ * <input type="text" placeholder="Search..." />
2349
+ * </div>
2350
+ * `;
2351
+ * // Return cleanup function
2352
+ * return () => container.innerHTML = '';
2353
+ * },
2354
+ * onClose: () => {
2355
+ * console.log('Filter panel closed');
2356
+ * },
2357
+ * });
2358
+ * ```
2359
+ *
2360
+ * @see {@link ShellConfig} for shell configuration
1283
2361
  */
1284
2362
  export interface ToolPanelDefinition {
1285
2363
  /** Unique panel ID */
@@ -1299,6 +2377,33 @@ export interface ToolPanelDefinition {
1299
2377
  }
1300
2378
  /**
1301
2379
  * Header content definition for plugins contributing to shell header center section.
2380
+ *
2381
+ * Register via `grid.registerHeaderContent()` to add content between
2382
+ * the title and toolbar buttons.
2383
+ *
2384
+ * @example
2385
+ * ```typescript
2386
+ * grid.registerHeaderContent({
2387
+ * id: 'row-count',
2388
+ * order: 10,
2389
+ * render: (container) => {
2390
+ * const span = document.createElement('span');
2391
+ * span.className = 'row-count';
2392
+ * span.textContent = `${grid.rows.length} rows`;
2393
+ * container.appendChild(span);
2394
+ *
2395
+ * // Update on data changes
2396
+ * const update = () => span.textContent = `${grid.rows.length} rows`;
2397
+ * grid.addEventListener('data-change', update);
2398
+ *
2399
+ * return () => {
2400
+ * grid.removeEventListener('data-change', update);
2401
+ * };
2402
+ * },
2403
+ * });
2404
+ * ```
2405
+ *
2406
+ * @see {@link ShellConfig} for shell configuration
1302
2407
  */
1303
2408
  export interface HeaderContentDefinition {
1304
2409
  /** Unique content ID */
@@ -1314,15 +2419,43 @@ export interface HeaderContentDefinition {
1314
2419
  * State for a single column. Captures user-driven changes at runtime.
1315
2420
  * Plugins can extend this interface via module augmentation to add their own state.
1316
2421
  *
2422
+ * Used with `grid.getColumnState()` and `grid.columnState` for persisting
2423
+ * user customizations (column widths, order, visibility, sort).
2424
+ *
1317
2425
  * @example
1318
- * ```ts
1319
- * // In filtering plugin
2426
+ * ```typescript
2427
+ * // Save column state to localStorage
2428
+ * const state = grid.getColumnState();
2429
+ * localStorage.setItem('gridState', JSON.stringify(state));
2430
+ *
2431
+ * // Restore on page load
2432
+ * const saved = localStorage.getItem('gridState');
2433
+ * if (saved) {
2434
+ * grid.columnState = JSON.parse(saved);
2435
+ * }
2436
+ *
2437
+ * // Example column state structure
2438
+ * const state: GridColumnState = {
2439
+ * columns: [
2440
+ * { field: 'name', order: 0, width: 200, hidden: false },
2441
+ * { field: 'email', order: 1, width: 300, hidden: false },
2442
+ * { field: 'phone', order: 2, hidden: true }, // Hidden column
2443
+ * ],
2444
+ * sort: { field: 'name', direction: 1 },
2445
+ * };
2446
+ * ```
2447
+ *
2448
+ * @example
2449
+ * ```typescript
2450
+ * // Plugin augmentation example (in filtering plugin)
1320
2451
  * declare module '@toolbox-web/grid' {
1321
2452
  * interface ColumnState {
1322
2453
  * filter?: FilterValue;
1323
2454
  * }
1324
2455
  * }
1325
2456
  * ```
2457
+ *
2458
+ * @see {@link GridColumnState} for the full state object
1326
2459
  */
1327
2460
  export interface ColumnState {
1328
2461
  /** Column field identifier */
@@ -1333,11 +2466,15 @@ export interface ColumnState {
1333
2466
  width?: number;
1334
2467
  /** Visibility state */
1335
2468
  visible: boolean;
1336
- /** Sort state (undefined = not sorted) */
2469
+ /** Sort state (undefined = not sorted). */
1337
2470
  sort?: ColumnSortState;
1338
2471
  }
1339
2472
  /**
1340
- * Sort state for a column
2473
+ * Sort state for a column.
2474
+ * Used within {@link ColumnState} to track sort direction and priority.
2475
+ *
2476
+ * @see {@link ColumnState} for column state persistence
2477
+ * @see {@link SortChangeDetail} for sort change events
1341
2478
  */
1342
2479
  export interface ColumnSortState {
1343
2480
  /** Sort direction */
@@ -1348,8 +2485,22 @@ export interface ColumnSortState {
1348
2485
  /**
1349
2486
  * Complete grid column state for persistence.
1350
2487
  * Contains state for all columns, including plugin-contributed properties.
2488
+ *
2489
+ * @example
2490
+ * ```typescript
2491
+ * // Save state
2492
+ * const state = grid.getColumnState();
2493
+ * localStorage.setItem('grid-state', JSON.stringify(state));
2494
+ *
2495
+ * // Restore state
2496
+ * grid.columnState = JSON.parse(localStorage.getItem('grid-state'));
2497
+ * ```
2498
+ *
2499
+ * @see {@link ColumnState} for individual column state
2500
+ * @see {@link PublicGrid.getColumnState} for retrieving state
1351
2501
  */
1352
2502
  export interface GridColumnState {
2503
+ /** Array of column states. */
1353
2504
  columns: ColumnState[];
1354
2505
  }
1355
2506
  /**
@@ -1417,6 +2568,18 @@ export interface ChangedRowsResetDetail<TRow = unknown> {
1417
2568
  * Detail for a cell click event.
1418
2569
  * Provides full context about the clicked cell including row data.
1419
2570
  *
2571
+ * @example
2572
+ * ```typescript
2573
+ * grid.addEventListener('cell-click', (e: CustomEvent<CellClickDetail>) => {
2574
+ * const { row, field, value, rowIndex, colIndex } = e.detail;
2575
+ * console.log(`Clicked ${field} = ${value} in row ${rowIndex}`);\n *
2576
+ * // Access the full row data
2577
+ * if (row.status === 'pending') {
2578
+ * showApprovalDialog(row);
2579
+ * }
2580
+ * });
2581
+ * ```
2582
+ *
1420
2583
  * @category Events
1421
2584
  */
1422
2585
  export interface CellClickDetail<TRow = unknown> {
@@ -1439,6 +2602,20 @@ export interface CellClickDetail<TRow = unknown> {
1439
2602
  * Detail for a row click event.
1440
2603
  * Provides context about the clicked row.
1441
2604
  *
2605
+ * @example
2606
+ * ```typescript
2607
+ * grid.addEventListener('row-click', (e: CustomEvent<RowClickDetail>) => {
2608
+ * const { row, rowIndex, rowEl } = e.detail;
2609
+ * console.log(`Clicked row ${rowIndex}: ${row.name}`);
2610
+ *
2611
+ * // Highlight the row
2612
+ * rowEl.classList.add('selected');
2613
+ *
2614
+ * // Open detail panel
2615
+ * showDetailPanel(row);
2616
+ * });
2617
+ * ```
2618
+ *
1442
2619
  * @category Events
1443
2620
  */
1444
2621
  export interface RowClickDetail<TRow = unknown> {
@@ -1454,6 +2631,25 @@ export interface RowClickDetail<TRow = unknown> {
1454
2631
  /**
1455
2632
  * Detail for a sort change (direction 0 indicates cleared sort).
1456
2633
  *
2634
+ * @example
2635
+ * ```typescript
2636
+ * grid.addEventListener('sort-change', (e: CustomEvent<SortChangeDetail>) => {
2637
+ * const { field, direction } = e.detail;
2638
+ *
2639
+ * if (direction === 0) {
2640
+ * console.log(`Sort cleared on ${field}`);
2641
+ * } else {
2642
+ * const dir = direction === 1 ? 'ascending' : 'descending';
2643
+ * console.log(`Sorted by ${field} ${dir}`);
2644
+ * }
2645
+ *
2646
+ * // Fetch sorted data from server
2647
+ * fetchData({ sortBy: field, sortDir: direction });
2648
+ * });
2649
+ * ```
2650
+ *
2651
+ * @see {@link SortState} for the sort state object
2652
+ * @see {@link SortHandler} for custom sort handlers
1457
2653
  * @category Events
1458
2654
  */
1459
2655
  export interface SortChangeDetail {
@@ -1465,6 +2661,19 @@ export interface SortChangeDetail {
1465
2661
  /**
1466
2662
  * Column resize event detail containing final pixel width.
1467
2663
  *
2664
+ * @example
2665
+ * ```typescript
2666
+ * grid.addEventListener('column-resize', (e: CustomEvent<ColumnResizeDetail>) => {
2667
+ * const { field, width } = e.detail;
2668
+ * console.log(`Column ${field} resized to ${width}px`);
2669
+ *
2670
+ * // Persist to user preferences
2671
+ * saveColumnWidth(field, width);
2672
+ * });
2673
+ * ```
2674
+ *
2675
+ * @see {@link ColumnState} for persisting column state
2676
+ * @see {@link ResizeController} for resize implementation
1468
2677
  * @category Events
1469
2678
  */
1470
2679
  export interface ColumnResizeDetail {
@@ -1478,6 +2687,7 @@ export interface ColumnResizeDetail {
1478
2687
  * - `'keyboard'`: Enter key pressed on focused cell
1479
2688
  * - `'pointer'`: Mouse/touch/pen click on cell
1480
2689
  *
2690
+ * @see {@link CellActivateDetail} for the activation event detail
1481
2691
  * @category Events
1482
2692
  */
1483
2693
  export type CellActivateTrigger = 'keyboard' | 'pointer';
@@ -1485,6 +2695,27 @@ export type CellActivateTrigger = 'keyboard' | 'pointer';
1485
2695
  * Fired when a cell is activated by user interaction (Enter key or click).
1486
2696
  * Unified event for both keyboard and pointer activation.
1487
2697
  *
2698
+ * @example
2699
+ * ```typescript
2700
+ * grid.addEventListener('cell-activate', (e: CustomEvent<CellActivateDetail>) => {
2701
+ * const { row, field, value, trigger, cellEl } = e.detail;
2702
+ *
2703
+ * if (trigger === 'keyboard') {
2704
+ * console.log('Activated via Enter key');
2705
+ * } else {
2706
+ * console.log('Activated via click/tap');
2707
+ * }
2708
+ *
2709
+ * // Start custom editing for specific columns
2710
+ * if (field === 'notes') {
2711
+ * openNotesEditor(row, cellEl);
2712
+ * e.preventDefault(); // Prevent default editing
2713
+ * }
2714
+ * });
2715
+ * ```
2716
+ *
2717
+ * @see {@link CellClickDetail} for click-only events
2718
+ * @see {@link CellActivateTrigger} for trigger types
1488
2719
  * @category Events
1489
2720
  */
1490
2721
  export interface CellActivateDetail<TRow = unknown> {
@@ -1520,7 +2751,22 @@ export interface ActivateCellDetail {
1520
2751
  /**
1521
2752
  * Event detail for mounting external view renderers.
1522
2753
  *
1523
- * @category Events
2754
+ * Emitted when a cell uses an external component spec (React, Angular, Vue)
2755
+ * and needs the framework adapter to mount the component.
2756
+ *
2757
+ * @example
2758
+ * ```typescript
2759
+ * // Framework adapter listens for this event
2760
+ * grid.addEventListener('mount-external-view', (e: CustomEvent<ExternalMountViewDetail>) => {
2761
+ * const { placeholder, spec, context } = e.detail;
2762
+ * // Mount framework component into placeholder
2763
+ * mountComponent(spec.component, placeholder, context);
2764
+ * });
2765
+ * ```
2766
+ *
2767
+ * @see {@link ColumnConfig.externalView} for external view spec
2768
+ * @see {@link FrameworkAdapter} for adapter interface
2769
+ * @category Framework Adapters
1524
2770
  */
1525
2771
  export interface ExternalMountViewDetail<TRow = unknown> {
1526
2772
  placeholder: HTMLElement;
@@ -1535,7 +2781,26 @@ export interface ExternalMountViewDetail<TRow = unknown> {
1535
2781
  /**
1536
2782
  * Event detail for mounting external editor renderers.
1537
2783
  *
1538
- * @category Events
2784
+ * Emitted when a cell uses an external editor component spec and needs
2785
+ * the framework adapter to mount the editor with commit/cancel bindings.
2786
+ *
2787
+ * @example
2788
+ * ```typescript
2789
+ * // Framework adapter listens for this event
2790
+ * grid.addEventListener('mount-external-editor', (e: CustomEvent<ExternalMountEditorDetail>) => {
2791
+ * const { placeholder, spec, context } = e.detail;
2792
+ * // Mount framework editor with commit/cancel wired
2793
+ * mountEditor(spec.component, placeholder, {
2794
+ * value: context.value,
2795
+ * onCommit: context.commit,
2796
+ * onCancel: context.cancel,
2797
+ * });
2798
+ * });
2799
+ * ```
2800
+ *
2801
+ * @see {@link ColumnEditorSpec} for external editor spec
2802
+ * @see {@link FrameworkAdapter} for adapter interface
2803
+ * @category Framework Adapters
1539
2804
  */
1540
2805
  export interface ExternalMountEditorDetail<TRow = unknown> {
1541
2806
  placeholder: HTMLElement;
@@ -1552,6 +2817,26 @@ export interface ExternalMountEditorDetail<TRow = unknown> {
1552
2817
  /**
1553
2818
  * Maps event names to their detail payload types.
1554
2819
  *
2820
+ * Use this interface for strongly typed event handling.
2821
+ *
2822
+ * @example
2823
+ * ```typescript
2824
+ * // Type-safe event listener
2825
+ * function handleEvent<K extends keyof DataGridEventMap>(
2826
+ * grid: DataGridElement,
2827
+ * event: K,
2828
+ * handler: (detail: DataGridEventMap[K]) => void,
2829
+ * ): void {
2830
+ * grid.addEventListener(event, (e: CustomEvent) => handler(e.detail));
2831
+ * }
2832
+ *
2833
+ * handleEvent(grid, 'cell-click', (detail) => {
2834
+ * console.log(detail.field); // Type-safe access
2835
+ * });
2836
+ * ```
2837
+ *
2838
+ * @see {@link DataGridCustomEvent} for typed CustomEvent wrapper
2839
+ * @see {@link DGEvents} for event name constants
1555
2840
  * @category Events
1556
2841
  */
1557
2842
  export interface DataGridEventMap<TRow = unknown> {
@@ -1573,12 +2858,45 @@ export interface DataGridEventMap<TRow = unknown> {
1573
2858
  /**
1574
2859
  * Extracts the event detail type for a given event name.
1575
2860
  *
2861
+ * Utility type for getting the detail payload type of a specific event.
2862
+ *
2863
+ * @example
2864
+ * ```typescript
2865
+ * // Extract detail type for specific event
2866
+ * type ClickDetail = DataGridEventDetail<'cell-click', Employee>;
2867
+ * // Equivalent to: CellClickDetail<Employee>
2868
+ *
2869
+ * // Use in generic handler
2870
+ * function logDetail<K extends keyof DataGridEventMap>(
2871
+ * eventName: K,
2872
+ * detail: DataGridEventDetail<K>,
2873
+ * ): void {
2874
+ * console.log(`${eventName}:`, detail);
2875
+ * }
2876
+ * ```
2877
+ *
2878
+ * @see {@link DataGridEventMap} for all event types
1576
2879
  * @category Events
1577
2880
  */
1578
2881
  export type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];
1579
2882
  /**
1580
2883
  * Custom event type for DataGrid events with typed detail payload.
1581
2884
  *
2885
+ * Use this type when you need to cast or declare event handler parameters.
2886
+ *
2887
+ * @example
2888
+ * ```typescript
2889
+ * // Strongly typed event handler
2890
+ * function onCellClick(e: DataGridCustomEvent<'cell-click', Employee>): void {
2891
+ * const { row, field, value } = e.detail;
2892
+ * console.log(`Clicked ${field} = ${value} on ${row.name}`);
2893
+ * }
2894
+ *
2895
+ * grid.addEventListener('cell-click', onCellClick);
2896
+ * ```
2897
+ *
2898
+ * @see {@link DataGridEventMap} for all event types
2899
+ * @see {@link DataGridEventDetail} for extracting detail type only
1582
2900
  * @category Events
1583
2901
  */
1584
2902
  export type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<DataGridEventMap<TRow>[K]>;