@toolbox-web/grid 0.6.0 → 1.1.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 (197) hide show
  1. package/README.md +79 -26
  2. package/all.d.ts +1 -0
  3. package/all.d.ts.map +1 -1
  4. package/all.js +1899 -2696
  5. package/all.js.map +1 -1
  6. package/index.js +1498 -2489
  7. package/index.js.map +1 -1
  8. package/lib/core/constants.d.ts +8 -0
  9. package/lib/core/constants.d.ts.map +1 -1
  10. package/lib/core/grid.d.ts +704 -55
  11. package/lib/core/grid.d.ts.map +1 -1
  12. package/lib/core/internal/config-manager.d.ts +3 -7
  13. package/lib/core/internal/config-manager.d.ts.map +1 -1
  14. package/lib/core/internal/dom-builder.d.ts +2 -10
  15. package/lib/core/internal/dom-builder.d.ts.map +1 -1
  16. package/lib/core/internal/inference.d.ts.map +1 -1
  17. package/lib/core/internal/keyboard.d.ts.map +1 -1
  18. package/lib/core/internal/render-scheduler.d.ts +2 -0
  19. package/lib/core/internal/render-scheduler.d.ts.map +1 -1
  20. package/lib/core/internal/rows.d.ts +9 -1
  21. package/lib/core/internal/rows.d.ts.map +1 -1
  22. package/lib/core/internal/shell.d.ts +41 -41
  23. package/lib/core/internal/shell.d.ts.map +1 -1
  24. package/lib/core/internal/validate-config.d.ts +10 -0
  25. package/lib/core/internal/validate-config.d.ts.map +1 -1
  26. package/lib/core/plugin/base-plugin.d.ts +103 -15
  27. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  28. package/lib/core/plugin/index.d.ts +1 -1
  29. package/lib/core/plugin/index.d.ts.map +1 -1
  30. package/lib/core/plugin/types.d.ts +33 -6
  31. package/lib/core/plugin/types.d.ts.map +1 -1
  32. package/lib/core/types.d.ts +376 -68
  33. package/lib/core/types.d.ts.map +1 -1
  34. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +89 -2
  35. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  36. package/lib/plugins/clipboard/index.d.ts +2 -0
  37. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  38. package/lib/plugins/clipboard/index.js +46 -35
  39. package/lib/plugins/clipboard/index.js.map +1 -1
  40. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +57 -2
  41. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  42. package/lib/plugins/column-virtualization/index.d.ts +2 -0
  43. package/lib/plugins/column-virtualization/index.d.ts.map +1 -1
  44. package/lib/plugins/column-virtualization/index.js +55 -43
  45. package/lib/plugins/column-virtualization/index.js.map +1 -1
  46. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +75 -5
  47. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  48. package/lib/plugins/context-menu/index.d.ts +3 -1
  49. package/lib/plugins/context-menu/index.d.ts.map +1 -1
  50. package/lib/plugins/context-menu/index.js +76 -66
  51. package/lib/plugins/context-menu/index.js.map +1 -1
  52. package/lib/plugins/editing/EditingPlugin.d.ts +107 -10
  53. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  54. package/lib/plugins/editing/editors.d.ts +9 -1
  55. package/lib/plugins/editing/editors.d.ts.map +1 -1
  56. package/lib/plugins/editing/index.d.ts +4 -2
  57. package/lib/plugins/editing/index.d.ts.map +1 -1
  58. package/lib/plugins/editing/index.js +458 -279
  59. package/lib/plugins/editing/index.js.map +1 -1
  60. package/lib/plugins/editing/types.d.ts +88 -0
  61. package/lib/plugins/editing/types.d.ts.map +1 -1
  62. package/lib/plugins/export/ExportPlugin.d.ts +73 -7
  63. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  64. package/lib/plugins/export/index.d.ts +2 -0
  65. package/lib/plugins/export/index.d.ts.map +1 -1
  66. package/lib/plugins/export/index.js +40 -33
  67. package/lib/plugins/export/index.js.map +1 -1
  68. package/lib/plugins/filtering/FilteringPlugin.d.ts +98 -2
  69. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  70. package/lib/plugins/filtering/index.d.ts +2 -0
  71. package/lib/plugins/filtering/index.d.ts.map +1 -1
  72. package/lib/plugins/filtering/index.js +31 -17
  73. package/lib/plugins/filtering/index.js.map +1 -1
  74. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +86 -7
  75. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  76. package/lib/plugins/grouping-columns/index.d.ts +2 -0
  77. package/lib/plugins/grouping-columns/index.d.ts.map +1 -1
  78. package/lib/plugins/grouping-columns/index.js +57 -27
  79. package/lib/plugins/grouping-columns/index.js.map +1 -1
  80. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +81 -5
  81. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  82. package/lib/plugins/grouping-rows/index.d.ts +3 -1
  83. package/lib/plugins/grouping-rows/index.d.ts.map +1 -1
  84. package/lib/plugins/grouping-rows/index.js +35 -21
  85. package/lib/plugins/grouping-rows/index.js.map +1 -1
  86. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +90 -5
  87. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  88. package/lib/plugins/master-detail/index.d.ts +2 -0
  89. package/lib/plugins/master-detail/index.d.ts.map +1 -1
  90. package/lib/plugins/master-detail/index.js +33 -17
  91. package/lib/plugins/master-detail/index.js.map +1 -1
  92. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +83 -2
  93. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  94. package/lib/plugins/multi-sort/index.d.ts +2 -0
  95. package/lib/plugins/multi-sort/index.d.ts.map +1 -1
  96. package/lib/plugins/multi-sort/index.js +33 -19
  97. package/lib/plugins/multi-sort/index.js.map +1 -1
  98. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +67 -3
  99. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  100. package/lib/plugins/pinned-columns/index.d.ts +3 -1
  101. package/lib/plugins/pinned-columns/index.d.ts.map +1 -1
  102. package/lib/plugins/pinned-columns/index.js +43 -17
  103. package/lib/plugins/pinned-columns/index.js.map +1 -1
  104. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +71 -10
  105. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  106. package/lib/plugins/pinned-rows/index.d.ts +3 -1
  107. package/lib/plugins/pinned-rows/index.d.ts.map +1 -1
  108. package/lib/plugins/pinned-rows/index.js +27 -17
  109. package/lib/plugins/pinned-rows/index.js.map +1 -1
  110. package/lib/plugins/pivot/PivotPlugin.d.ts +81 -4
  111. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  112. package/lib/plugins/pivot/index.d.ts +2 -0
  113. package/lib/plugins/pivot/index.d.ts.map +1 -1
  114. package/lib/plugins/pivot/index.js +32 -17
  115. package/lib/plugins/pivot/index.js.map +1 -1
  116. package/lib/plugins/reorder/ReorderPlugin.d.ts +71 -3
  117. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  118. package/lib/plugins/reorder/index.d.ts +2 -0
  119. package/lib/plugins/reorder/index.d.ts.map +1 -1
  120. package/lib/plugins/reorder/index.js +30 -18
  121. package/lib/plugins/reorder/index.js.map +1 -1
  122. package/lib/plugins/reorder/types.d.ts +0 -5
  123. package/lib/plugins/reorder/types.d.ts.map +1 -1
  124. package/lib/plugins/responsive/ResponsivePlugin.d.ts +123 -0
  125. package/lib/plugins/responsive/ResponsivePlugin.d.ts.map +1 -0
  126. package/lib/plugins/responsive/index.d.ts +11 -0
  127. package/lib/plugins/responsive/index.d.ts.map +1 -0
  128. package/lib/plugins/responsive/index.js +589 -0
  129. package/lib/plugins/responsive/index.js.map +1 -0
  130. package/lib/plugins/responsive/types.d.ts +133 -0
  131. package/lib/plugins/responsive/types.d.ts.map +1 -0
  132. package/lib/plugins/selection/SelectionPlugin.d.ts +90 -21
  133. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  134. package/lib/plugins/selection/index.d.ts +3 -2
  135. package/lib/plugins/selection/index.d.ts.map +1 -1
  136. package/lib/plugins/selection/index.js +125 -144
  137. package/lib/plugins/selection/index.js.map +1 -1
  138. package/lib/plugins/selection/types.d.ts +51 -4
  139. package/lib/plugins/selection/types.d.ts.map +1 -1
  140. package/lib/plugins/server-side/ServerSidePlugin.d.ts +65 -4
  141. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  142. package/lib/plugins/server-side/index.d.ts +3 -1
  143. package/lib/plugins/server-side/index.d.ts.map +1 -1
  144. package/lib/plugins/server-side/index.js +27 -17
  145. package/lib/plugins/server-side/index.js.map +1 -1
  146. package/lib/plugins/tree/TreePlugin.d.ts +89 -2
  147. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  148. package/lib/plugins/tree/index.d.ts +3 -2
  149. package/lib/plugins/tree/index.d.ts.map +1 -1
  150. package/lib/plugins/tree/index.js +81 -94
  151. package/lib/plugins/tree/index.js.map +1 -1
  152. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +66 -3
  153. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  154. package/lib/plugins/undo-redo/index.d.ts +3 -1
  155. package/lib/plugins/undo-redo/index.d.ts.map +1 -1
  156. package/lib/plugins/undo-redo/index.js +32 -22
  157. package/lib/plugins/undo-redo/index.js.map +1 -1
  158. package/lib/plugins/visibility/VisibilityPlugin.d.ts +86 -2
  159. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  160. package/lib/plugins/visibility/index.d.ts +2 -0
  161. package/lib/plugins/visibility/index.d.ts.map +1 -1
  162. package/lib/plugins/visibility/index.js +28 -17
  163. package/lib/plugins/visibility/index.js.map +1 -1
  164. package/package.json +1 -1
  165. package/public.d.ts +30 -2
  166. package/public.d.ts.map +1 -1
  167. package/umd/grid.all.umd.js +31 -25
  168. package/umd/grid.all.umd.js.map +1 -1
  169. package/umd/grid.umd.js +21 -17
  170. package/umd/grid.umd.js.map +1 -1
  171. package/umd/plugins/clipboard.umd.js.map +1 -1
  172. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  173. package/umd/plugins/context-menu.umd.js.map +1 -1
  174. package/umd/plugins/editing.umd.js +1 -1
  175. package/umd/plugins/editing.umd.js.map +1 -1
  176. package/umd/plugins/export.umd.js.map +1 -1
  177. package/umd/plugins/filtering.umd.js.map +1 -1
  178. package/umd/plugins/grouping-columns.umd.js +1 -1
  179. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  180. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  181. package/umd/plugins/master-detail.umd.js.map +1 -1
  182. package/umd/plugins/multi-sort.umd.js.map +1 -1
  183. package/umd/plugins/pinned-columns.umd.js +1 -1
  184. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  185. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  186. package/umd/plugins/pivot.umd.js.map +1 -1
  187. package/umd/plugins/reorder.umd.js +1 -1
  188. package/umd/plugins/reorder.umd.js.map +1 -1
  189. package/umd/plugins/responsive.umd.js +2 -0
  190. package/umd/plugins/responsive.umd.js.map +1 -0
  191. package/umd/plugins/selection.umd.js +3 -1
  192. package/umd/plugins/selection.umd.js.map +1 -1
  193. package/umd/plugins/server-side.umd.js.map +1 -1
  194. package/umd/plugins/tree.umd.js +1 -1
  195. package/umd/plugins/tree.umd.js.map +1 -1
  196. package/umd/plugins/undo-redo.umd.js.map +1 -1
  197. package/umd/plugins/visibility.umd.js.map +1 -1
@@ -65,6 +65,8 @@ export interface PublicGrid<T = any> {
65
65
  * Member prefixes indicate accessibility:
66
66
  * - `_underscore` = protected members - private outside core, accessible to plugins. Marked with @internal.
67
67
  * - `__doubleUnderscore` = deeply internal members - private outside core, only for internal functions.
68
+ *
69
+ * @category Plugin Development
68
70
  */
69
71
  export interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {
70
72
  querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
@@ -110,17 +112,21 @@ export interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {
110
112
  _activeEditRows?: number;
111
113
  /** Snapshots of row data before editing. Injected by EditingPlugin. @internal */
112
114
  _rowEditSnapshots?: Map<number, T>;
113
- /** Set of row indices that have been modified. Injected by EditingPlugin. @internal */
114
- _changedRowIndices?: Set<number>;
115
115
  /** Get all changed rows. Injected by EditingPlugin. */
116
116
  changedRows?: T[];
117
- /** Get indices of all changed rows. Injected by EditingPlugin. */
118
- changedRowIndices?: number[];
117
+ /** Get IDs of all changed rows. Injected by EditingPlugin. */
118
+ changedRowIds?: string[];
119
119
  effectiveConfig?: GridConfig<T>;
120
120
  findHeaderRow?: () => HTMLElement;
121
121
  refreshVirtualWindow: (full: boolean) => void;
122
122
  updateTemplate?: () => void;
123
123
  findRenderedRowElement?: (rowIndex: number) => HTMLElement | null;
124
+ /** Get a row by its ID. Implemented in grid.ts */
125
+ getRow?: (id: string) => T | undefined;
126
+ /** Get the unique ID for a row. Implemented in grid.ts */
127
+ getRowId?: (row: T) => string;
128
+ /** Update a row by ID. Implemented in grid.ts */
129
+ updateRow?: (id: string, changes: Partial<T>, source?: UpdateSource) => void;
124
130
  /** Begin bulk edit on a row. Injected by EditingPlugin. */
125
131
  beginBulkEdit?: (rowIndex: number) => void;
126
132
  /** Commit active row edit. Injected by EditingPlugin. */
@@ -150,7 +156,40 @@ export interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {
150
156
  /** Request emission of column-state-change event (debounced) */
151
157
  requestStateChange?: () => void;
152
158
  }
153
- export type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select' | 'typeahead';
159
+ export type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select';
160
+ /**
161
+ * Column type - built-in primitives or custom type strings.
162
+ * Custom types (e.g., 'currency', 'country') can have type-level defaults via `typeDefaults`.
163
+ */
164
+ export type ColumnType = PrimitiveColumnType | (string & {});
165
+ /**
166
+ * Type-level defaults for renderers and editors.
167
+ * Applied to all columns of a given type unless overridden at column level.
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * typeDefaults: {
172
+ * country: {
173
+ * renderer: (ctx) => {
174
+ * const span = document.createElement('span');
175
+ * span.innerHTML = `<img src="/flags/${ctx.value}.svg" /> ${ctx.value}`;
176
+ * return span;
177
+ * }
178
+ * },
179
+ * date: {
180
+ * editor: (ctx) => createDatePickerEditor(ctx)
181
+ * }
182
+ * }
183
+ * ```
184
+ */
185
+ export interface TypeDefault<TRow = unknown> {
186
+ /** Renderer template for this type */
187
+ renderer?: ColumnViewRenderer<TRow, unknown>;
188
+ /** Editor template for this type (requires EditingPlugin) */
189
+ editor?: ColumnEditorSpec<TRow, unknown>;
190
+ /** Default editorParams for this type */
191
+ editorParams?: Record<string, unknown>;
192
+ }
154
193
  /**
155
194
  * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.
156
195
  * Prefer adding optional properties here only when broadly useful to most grids.
@@ -160,8 +199,17 @@ export interface BaseColumnConfig<TRow = any, TValue = any> {
160
199
  field: keyof TRow & string;
161
200
  /** Visible header label; defaults to capitalized field */
162
201
  header?: string;
163
- /** Column data type; inferred if omitted */
164
- type?: PrimitiveColumnType;
202
+ /**
203
+ * Column data type.
204
+ *
205
+ * Built-in types: `'string'`, `'number'`, `'date'`, `'boolean'`, `'select'`
206
+ *
207
+ * Custom types (e.g., `'currency'`, `'country'`) can have type-level defaults
208
+ * via `gridConfig.typeDefaults` or framework adapter registries.
209
+ *
210
+ * @default Inferred from first row data
211
+ */
212
+ type?: ColumnType;
165
213
  /** Column width in pixels; fixed size (no flexibility) */
166
214
  width?: string | number;
167
215
  /** Minimum column width in pixels (stretch mode only); when set, column uses minmax(minWidth, 1fr) */
@@ -172,7 +220,7 @@ export interface BaseColumnConfig<TRow = any, TValue = any> {
172
220
  resizable?: boolean;
173
221
  /** Optional custom comparator for sorting (a,b) -> number */
174
222
  sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;
175
- /** For select/typeahead types - available options */
223
+ /** For select type - available options */
176
224
  options?: Array<{
177
225
  label: string;
178
226
  value: unknown;
@@ -180,7 +228,7 @@ export interface BaseColumnConfig<TRow = any, TValue = any> {
180
228
  label: string;
181
229
  value: unknown;
182
230
  }>);
183
- /** For select/typeahead - allow multi select */
231
+ /** For select - allow multi select */
184
232
  multi?: boolean;
185
233
  /** Optional formatter */
186
234
  format?: (value: TValue, row: TRow) => string;
@@ -329,6 +377,7 @@ export type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (ctx: CellRen
329
377
  * // User registers adapter once in their app
330
378
  * GridElement.registerAdapter(new AngularGridAdapter(injector, appRef));
331
379
  * ```
380
+ * @category Framework Adapters
332
381
  */
333
382
  export interface FrameworkAdapter {
334
383
  /**
@@ -351,6 +400,14 @@ export interface FrameworkAdapter {
351
400
  * The renderer receives a container element and optionally returns a cleanup function.
352
401
  */
353
402
  createToolPanelRenderer?(element: HTMLElement): ((container: HTMLElement) => void | (() => void)) | undefined;
403
+ /**
404
+ * Gets type-level defaults from an application-level registry.
405
+ * Used by Angular's `GridTypeRegistry` and React's `GridTypeProvider`.
406
+ *
407
+ * @param type - The column type (e.g., 'date', 'currency', 'country')
408
+ * @returns Type defaults for renderer/editor, or undefined if not registered
409
+ */
410
+ getTypeDefault?<TRow = unknown>(type: string): TypeDefault<TRow> | undefined;
354
411
  }
355
412
  /**
356
413
  * Column internal properties used during light DOM parsing.
@@ -366,6 +423,8 @@ export interface ColumnParsedAttributes {
366
423
  /**
367
424
  * Extended column config used internally.
368
425
  * Includes all internal properties needed during grid lifecycle.
426
+ *
427
+ * @category Plugin Development
369
428
  * @internal
370
429
  */
371
430
  export interface ColumnInternal<T = any> extends ColumnConfig<T>, ColumnParsedAttributes {
@@ -383,6 +442,8 @@ export interface ColumnInternal<T = any> extends ColumnConfig<T>, ColumnParsedAt
383
442
  /**
384
443
  * Row element with internal tracking properties.
385
444
  * Used during virtualization and row pooling.
445
+ *
446
+ * @category Plugin Development
386
447
  * @internal
387
448
  */
388
449
  export interface RowElementInternal extends HTMLElement {
@@ -406,6 +467,8 @@ export interface ElementWithPart {
406
467
  /**
407
468
  * Compiled view function type with optional blocked flag.
408
469
  * The __blocked flag is set when a template contains unsafe expressions.
470
+ *
471
+ * @category Plugin Development
409
472
  * @internal
410
473
  */
411
474
  export interface CompiledViewFunction<T = any> {
@@ -415,6 +478,8 @@ export interface CompiledViewFunction<T = any> {
415
478
  }
416
479
  /**
417
480
  * Runtime cell context used internally for compiled template execution.
481
+ *
482
+ * @category Plugin Development
418
483
  */
419
484
  export interface CellContext<T = any> {
420
485
  row: T;
@@ -424,12 +489,18 @@ export interface CellContext<T = any> {
424
489
  }
425
490
  /**
426
491
  * Internal editor execution context extending the generic cell context with commit helpers.
492
+ *
493
+ * @category Plugin Development
427
494
  */
428
495
  export interface EditorExecContext<T = any> extends CellContext<T> {
429
496
  commit: (newValue: unknown) => void;
430
497
  cancel: () => void;
431
498
  }
432
- /** Controller managing drag-based column resize lifecycle. */
499
+ /**
500
+ * Controller managing drag-based column resize lifecycle.
501
+ *
502
+ * @category Plugin Development
503
+ */
433
504
  export interface ResizeController {
434
505
  start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;
435
506
  /** Reset a column to its configured width (or auto-size if none configured). */
@@ -438,7 +509,11 @@ export interface ResizeController {
438
509
  /** True while a resize drag is in progress (used to suppress header click/sort). */
439
510
  isResizing: boolean;
440
511
  }
441
- /** Virtual window bookkeeping; modified in-place as scroll position changes. */
512
+ /**
513
+ * Virtual window bookkeeping; modified in-place as scroll position changes.
514
+ *
515
+ * @category Plugin Development
516
+ */
442
517
  export interface VirtualState {
443
518
  enabled: boolean;
444
519
  rowHeight: number;
@@ -456,6 +531,8 @@ export interface VirtualState {
456
531
  /**
457
532
  * Union type for input-like elements that have a `value` property.
458
533
  * Covers standard form elements and custom elements with value semantics.
534
+ *
535
+ * @category Plugin Development
459
536
  * @internal
460
537
  */
461
538
  export type InputLikeElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | {
@@ -479,7 +556,7 @@ export type AggregatorRef = string | ((rows: unknown[], field: string, column?:
479
556
  /** Result of automatic column inference from sample rows. */
480
557
  export interface InferredColumnResult<TRow = unknown> {
481
558
  columns: ColumnConfigMap<TRow>;
482
- typeMap: Record<string, PrimitiveColumnType>;
559
+ typeMap: Record<string, ColumnType>;
483
560
  }
484
561
  export declare const FitModeEnum: {
485
562
  readonly STRETCH: "stretch";
@@ -490,6 +567,8 @@ export type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum];
490
567
  * Minimal plugin interface for type-checking.
491
568
  * This interface is defined here to avoid circular imports with BaseGridPlugin.
492
569
  * All plugins must satisfy this shape (BaseGridPlugin implements it).
570
+ *
571
+ * @category Plugin Development
493
572
  */
494
573
  export interface GridPlugin {
495
574
  /** Unique plugin identifier */
@@ -509,12 +588,11 @@ export interface GridPlugin {
509
588
  * - `gridConfig` property - direct assignment of this object
510
589
  * - `columns` property - shorthand for `gridConfig.columns`
511
590
  * - `fitMode` property - shorthand for `gridConfig.fitMode`
512
- * - `editOn` property - shorthand for `gridConfig.editOn`
513
591
  * - Light DOM `<tbw-grid-column>` - declarative columns (merged into `columns`)
514
592
  * - Light DOM `<tbw-grid-header>` - declarative shell header (merged into `shell.header`)
515
593
  *
516
594
  * **Precedence (when same property set multiple ways):**
517
- * Individual props (`fitMode`, `editOn`) > `columns` prop > Light DOM > `gridConfig`
595
+ * Individual props (`fitMode`) > `columns` prop > Light DOM > `gridConfig`
518
596
  *
519
597
  * @example
520
598
  * ```ts
@@ -550,8 +628,18 @@ export interface GridConfig<TRow = any> {
550
628
  rowClass?: (row: TRow) => string[];
551
629
  /** Sizing mode for columns. Can also be set via `fitMode` prop. */
552
630
  fitMode?: FitMode;
553
- /** Edit activation mode ('click' | 'dblClick' | false). Set to false to disable editing. Can also be set via `editOn` prop. */
554
- editOn?: string | boolean;
631
+ /**
632
+ * Edit trigger mode. Requires `EditingPlugin` to be loaded.
633
+ *
634
+ * Configure via `new EditingPlugin({ editOn: 'click' })` or set on gridConfig.
635
+ * Plugin config takes precedence over gridConfig.
636
+ *
637
+ * - `'click'`: Single click to edit
638
+ * - `'dblclick'`: Double-click to edit (default)
639
+ * - `'manual'`: Only via programmatic API (beginEdit)
640
+ * - `false`: Disable editing entirely
641
+ */
642
+ editOn?: 'click' | 'dblclick' | 'manual' | false;
555
643
  /**
556
644
  * Row height in pixels for virtualization calculations.
557
645
  * The virtualization system assumes uniform row heights for performance.
@@ -638,6 +726,57 @@ export interface GridConfig<TRow = any> {
638
726
  * ```
639
727
  */
640
728
  sortHandler?: SortHandler<TRow>;
729
+ /**
730
+ * Function to extract a unique identifier from a row.
731
+ * Used by `updateRow()`, `getRow()`, and ID-based tracking.
732
+ *
733
+ * If not provided, falls back to `row.id` or `row._id` if present.
734
+ * Rows without IDs are silently skipped during map building.
735
+ * Only throws when explicitly calling `getRowId()` or `updateRow()` on a row without an ID.
736
+ *
737
+ * @example
738
+ * ```ts
739
+ * // Simple field
740
+ * getRowId: (row) => row.id
741
+ *
742
+ * // Composite key
743
+ * getRowId: (row) => `${row.voyageId}-${row.legNumber}`
744
+ *
745
+ * // UUID field
746
+ * getRowId: (row) => row.uuid
747
+ * ```
748
+ */
749
+ getRowId?: (row: TRow) => string;
750
+ /**
751
+ * Type-level renderer and editor defaults.
752
+ *
753
+ * Keys can be:
754
+ * - Built-in types: `'string'`, `'number'`, `'date'`, `'boolean'`, `'select'`
755
+ * - Custom types: `'currency'`, `'country'`, `'status'`, etc.
756
+ *
757
+ * Resolution order (highest priority first):
758
+ * 1. Column-level (`column.renderer` / `column.editor`)
759
+ * 2. Grid-level (`gridConfig.typeDefaults[column.type]`)
760
+ * 3. App-level (Angular `GridTypeRegistry`, React `GridTypeProvider`)
761
+ * 4. Built-in (checkbox for boolean, select for select, etc.)
762
+ * 5. Fallback (plain text / text input)
763
+ *
764
+ * @example
765
+ * ```typescript
766
+ * typeDefaults: {
767
+ * date: { editor: myDatePickerEditor },
768
+ * country: {
769
+ * renderer: (ctx) => {
770
+ * const span = document.createElement('span');
771
+ * span.innerHTML = `<img src="/flags/${ctx.value}.svg" /> ${ctx.value}`;
772
+ * return span;
773
+ * },
774
+ * editor: (ctx) => createCountrySelect(ctx)
775
+ * }
776
+ * }
777
+ * ```
778
+ */
779
+ typeDefaults?: Record<string, TypeDefault<TRow>>;
641
780
  }
642
781
  /**
643
782
  * Sort state passed to custom sort handlers.
@@ -657,6 +796,52 @@ export interface SortState {
657
796
  * @returns Sorted array (sync) or Promise resolving to sorted array (async)
658
797
  */
659
798
  export type SortHandler<TRow = any> = (rows: TRow[], sortState: SortState, columns: ColumnConfig<TRow>[]) => TRow[] | Promise<TRow[]>;
799
+ /**
800
+ * Indicates the origin of a data change.
801
+ * Used to prevent infinite loops in cascade update handlers.
802
+ *
803
+ * - `'user'`: Direct user interaction via EditingPlugin (typing, selecting)
804
+ * - `'cascade'`: Triggered by `updateRow()` in an event handler
805
+ * - `'api'`: External programmatic update via `grid.updateRow()`
806
+ *
807
+ * @category Data Management
808
+ */
809
+ export type UpdateSource = 'user' | 'cascade' | 'api';
810
+ /**
811
+ * Detail for cell-change event (emitted by core after mutation).
812
+ * This is an informational event that fires for ALL data mutations.
813
+ *
814
+ * @category Events
815
+ */
816
+ export interface CellChangeDetail<TRow = unknown> {
817
+ /** The row object (after mutation) */
818
+ row: TRow;
819
+ /** Stable row identifier */
820
+ rowId: string;
821
+ /** Current index in rows array */
822
+ rowIndex: number;
823
+ /** Field that changed */
824
+ field: string;
825
+ /** Value before change */
826
+ oldValue: unknown;
827
+ /** Value after change */
828
+ newValue: unknown;
829
+ /** All changes passed to updateRow/updateRows (for context) */
830
+ changes: Partial<TRow>;
831
+ /** Origin of this change */
832
+ source: UpdateSource;
833
+ }
834
+ /**
835
+ * Batch update specification for updateRows().
836
+ *
837
+ * @category Data Management
838
+ */
839
+ export interface RowUpdate<TRow = unknown> {
840
+ /** Row identifier (from getRowId) */
841
+ id: string;
842
+ /** Fields to update */
843
+ changes: Partial<TRow>;
844
+ }
660
845
  /**
661
846
  * Animation behavior mode.
662
847
  * - `true` or `'on'`: Animations always enabled
@@ -759,8 +944,8 @@ export interface ShellConfig {
759
944
  export interface ShellHeaderConfig {
760
945
  /** Grid title displayed on the left (optional) */
761
946
  title?: string;
762
- /** Custom toolbar buttons (rendered before tool panel toggles) */
763
- toolbarButtons?: ToolbarButtonConfig[];
947
+ /** Custom toolbar content (rendered before tool panel toggle) */
948
+ toolbarContents?: ToolbarContentDefinition[];
764
949
  /**
765
950
  * Light DOM header content elements (parsed from <tbw-grid-header> children).
766
951
  * @internal Set by ConfigManager during merge
@@ -786,51 +971,33 @@ export interface ToolPanelConfig {
786
971
  persistState?: boolean;
787
972
  }
788
973
  /**
789
- * Toolbar button defined via config (programmatic approach).
974
+ * Toolbar content definition for the shell header toolbar area.
975
+ * Register via `registerToolbarContent()` or use light DOM `<tbw-grid-tool-buttons>`.
790
976
  *
791
- * The grid does NOT create buttons - developers have full control over their own buttons.
792
- * Provide either:
793
- * - `element`: A ready-made DOM element (grid appends it to toolbar)
794
- * - `render`: A factory function that receives a container and appends content
795
- *
796
- * For declarative HTML buttons, use light-dom instead:
797
- * ```html
798
- * <tbw-grid>
799
- * <tbw-grid-header>
800
- * <button slot="toolbar">My Button</button>
801
- * </tbw-grid-header>
802
- * </tbw-grid>
977
+ * @example
978
+ * ```typescript
979
+ * grid.registerToolbarContent({
980
+ * id: 'my-toolbar',
981
+ * order: 10,
982
+ * render: (container) => {
983
+ * const btn = document.createElement('button');
984
+ * btn.textContent = 'Refresh';
985
+ * btn.onclick = () => console.log('clicked');
986
+ * container.appendChild(btn);
987
+ * return () => btn.remove();
988
+ * },
989
+ * });
803
990
  * ```
804
991
  */
805
- export interface ToolbarButtonConfig {
806
- /** Unique button ID */
992
+ export interface ToolbarContentDefinition {
993
+ /** Unique content ID */
807
994
  id: string;
808
- /** Tooltip / aria-label (for accessibility, used when grid generates panel toggle) */
809
- label?: string;
995
+ /** Content factory - called once when shell header renders */
996
+ render: (container: HTMLElement) => void | (() => void);
997
+ /** Called when content is removed (for cleanup) */
998
+ onDestroy?: () => void;
810
999
  /** Order priority (lower = first, default: 100) */
811
1000
  order?: number;
812
- /**
813
- * User-provided element. Grid appends it to the toolbar.
814
- * User is responsible for styling, event handlers, accessibility, etc.
815
- */
816
- element?: HTMLElement;
817
- /**
818
- * Render function called once. Receives container, user appends their DOM.
819
- * User is responsible for event handlers.
820
- * Return a cleanup function (optional).
821
- */
822
- render?: (container: HTMLElement) => void | (() => void);
823
- }
824
- /**
825
- * Toolbar button info returned by getToolbarButtons().
826
- */
827
- export interface ToolbarButtonInfo {
828
- id: string;
829
- label: string;
830
- /** Source of this button: 'config' | 'light-dom' | 'panel-toggle' */
831
- source: 'config' | 'light-dom' | 'panel-toggle';
832
- /** For panel toggles, the associated panel ID */
833
- panelId?: string;
834
1001
  }
835
1002
  /**
836
1003
  * Tool panel definition registered by plugins or consumers.
@@ -906,9 +1073,16 @@ export interface ColumnSortState {
906
1073
  export interface GridColumnState {
907
1074
  columns: ColumnState[];
908
1075
  }
1076
+ /**
1077
+ * Event detail for cell value commit.
1078
+ *
1079
+ * @category Events
1080
+ */
909
1081
  export interface CellCommitDetail<TRow = unknown> {
910
1082
  /** The row object (not yet mutated if event is cancelable). */
911
1083
  row: TRow;
1084
+ /** Stable row identifier (from getRowId). */
1085
+ rowId: string;
912
1086
  /** Field name whose value changed. */
913
1087
  field: string;
914
1088
  /** Previous value before change. */
@@ -919,52 +1093,156 @@ export interface CellCommitDetail<TRow = unknown> {
919
1093
  rowIndex: number;
920
1094
  /** All rows that have at least one committed change (snapshot list). */
921
1095
  changedRows: TRow[];
922
- /** Indices parallel to changedRows. */
923
- changedRowIndices: number[];
1096
+ /** IDs of changed rows. */
1097
+ changedRowIds: string[];
924
1098
  /** True if this row just entered the changed set. */
925
1099
  firstTimeForRow: boolean;
1100
+ /**
1101
+ * Update other fields in this row.
1102
+ * Convenience wrapper for grid.updateRow(rowId, changes, 'cascade').
1103
+ * Useful for cascade updates (e.g., calculating totals).
1104
+ */
1105
+ updateRow: (changes: Partial<TRow>) => void;
926
1106
  }
927
- /** Detail payload for a committed row edit (may or may not include changes). */
1107
+ /**
1108
+ * Detail payload for a committed row edit (may or may not include changes).
1109
+ *
1110
+ * @category Events
1111
+ */
928
1112
  export interface RowCommitDetail<TRow = unknown> {
929
1113
  /** Row index that lost edit focus. */
930
1114
  rowIndex: number;
1115
+ /** Stable row identifier (from getRowId). */
1116
+ rowId: string;
931
1117
  /** Row object reference. */
932
1118
  row: TRow;
933
1119
  /** Whether any cell changes were actually committed in this row during the session. */
934
1120
  changed: boolean;
935
1121
  /** Current changed row collection. */
936
1122
  changedRows: TRow[];
937
- /** Indices of changed rows. */
938
- changedRowIndices: number[];
1123
+ /** IDs of changed rows. */
1124
+ changedRowIds: string[];
939
1125
  }
940
- /** Emitted when the changed rows tracking set is cleared programmatically. */
1126
+ /**
1127
+ * Emitted when the changed rows tracking set is cleared programmatically.
1128
+ *
1129
+ * @category Events
1130
+ */
941
1131
  export interface ChangedRowsResetDetail<TRow = unknown> {
942
1132
  /** New (empty) changed rows array after reset. */
943
1133
  rows: TRow[];
944
- /** Parallel indices (likely empty). */
945
- indices: number[];
1134
+ /** IDs of changed rows (likely empty). */
1135
+ ids: string[];
946
1136
  }
947
- /** Detail for a sort change (direction 0 indicates cleared sort). */
1137
+ /**
1138
+ * Detail for a cell click event.
1139
+ * Provides full context about the clicked cell including row data.
1140
+ *
1141
+ * @category Events
1142
+ */
1143
+ export interface CellClickDetail<TRow = unknown> {
1144
+ /** Zero-based row index of the clicked cell. */
1145
+ rowIndex: number;
1146
+ /** Zero-based column index of the clicked cell. */
1147
+ colIndex: number;
1148
+ /** Field name of the clicked column. */
1149
+ field: string;
1150
+ /** Cell value at the clicked position. */
1151
+ value: unknown;
1152
+ /** Full row data object. */
1153
+ row: TRow;
1154
+ /** The clicked cell element. */
1155
+ cellEl: HTMLElement;
1156
+ /** The original mouse event. */
1157
+ originalEvent: MouseEvent;
1158
+ }
1159
+ /**
1160
+ * Detail for a row click event.
1161
+ * Provides context about the clicked row.
1162
+ *
1163
+ * @category Events
1164
+ */
1165
+ export interface RowClickDetail<TRow = unknown> {
1166
+ /** Zero-based row index of the clicked row. */
1167
+ rowIndex: number;
1168
+ /** Full row data object. */
1169
+ row: TRow;
1170
+ /** The clicked row element. */
1171
+ rowEl: HTMLElement;
1172
+ /** The original mouse event. */
1173
+ originalEvent: MouseEvent;
1174
+ }
1175
+ /**
1176
+ * Detail for a sort change (direction 0 indicates cleared sort).
1177
+ *
1178
+ * @category Events
1179
+ */
948
1180
  export interface SortChangeDetail {
949
1181
  /** Sorted field key. */
950
1182
  field: string;
951
1183
  /** Direction: 1 ascending, -1 descending, 0 cleared. */
952
1184
  direction: 1 | -1 | 0;
953
1185
  }
954
- /** Column resize event detail containing final pixel width. */
1186
+ /**
1187
+ * Column resize event detail containing final pixel width.
1188
+ *
1189
+ * @category Events
1190
+ */
955
1191
  export interface ColumnResizeDetail {
956
1192
  /** Resized column field key. */
957
1193
  field: string;
958
1194
  /** New width in pixels. */
959
1195
  width: number;
960
1196
  }
961
- /** Fired when keyboard navigation or programmatic focus changes active cell. */
1197
+ /**
1198
+ * Trigger type for cell activation.
1199
+ * - `'keyboard'`: Enter key pressed on focused cell
1200
+ * - `'pointer'`: Mouse/touch/pen click on cell
1201
+ *
1202
+ * @category Events
1203
+ */
1204
+ export type CellActivateTrigger = 'keyboard' | 'pointer';
1205
+ /**
1206
+ * Fired when a cell is activated by user interaction (Enter key or click).
1207
+ * Unified event for both keyboard and pointer activation.
1208
+ *
1209
+ * @category Events
1210
+ */
1211
+ export interface CellActivateDetail<TRow = unknown> {
1212
+ /** Zero-based row index of the activated cell. */
1213
+ rowIndex: number;
1214
+ /** Zero-based column index of the activated cell. */
1215
+ colIndex: number;
1216
+ /** Field name of the activated column. */
1217
+ field: string;
1218
+ /** Cell value at the activated position. */
1219
+ value: unknown;
1220
+ /** Full row data object. */
1221
+ row: TRow;
1222
+ /** The activated cell element. */
1223
+ cellEl: HTMLElement;
1224
+ /** What triggered the activation. */
1225
+ trigger: CellActivateTrigger;
1226
+ /** The original event (KeyboardEvent for keyboard, MouseEvent/PointerEvent for pointer). */
1227
+ originalEvent: KeyboardEvent | MouseEvent | PointerEvent;
1228
+ }
1229
+ /**
1230
+ * @deprecated Use `CellActivateDetail` instead. Will be removed in next major version.
1231
+ * Kept for backwards compatibility.
1232
+ *
1233
+ * @category Events
1234
+ */
962
1235
  export interface ActivateCellDetail {
963
1236
  /** Zero-based row index now focused. */
964
1237
  row: number;
965
1238
  /** Zero-based column index now focused. */
966
1239
  col: number;
967
1240
  }
1241
+ /**
1242
+ * Event detail for mounting external view renderers.
1243
+ *
1244
+ * @category Events
1245
+ */
968
1246
  export interface ExternalMountViewDetail<TRow = unknown> {
969
1247
  placeholder: HTMLElement;
970
1248
  spec: unknown;
@@ -975,6 +1253,11 @@ export interface ExternalMountViewDetail<TRow = unknown> {
975
1253
  column: unknown;
976
1254
  };
977
1255
  }
1256
+ /**
1257
+ * Event detail for mounting external editor renderers.
1258
+ *
1259
+ * @category Events
1260
+ */
978
1261
  export interface ExternalMountEditorDetail<TRow = unknown> {
979
1262
  placeholder: HTMLElement;
980
1263
  spec: unknown;
@@ -987,7 +1270,16 @@ export interface ExternalMountEditorDetail<TRow = unknown> {
987
1270
  cancel: () => void;
988
1271
  };
989
1272
  }
1273
+ /**
1274
+ * Maps event names to their detail payload types.
1275
+ *
1276
+ * @category Events
1277
+ */
990
1278
  export interface DataGridEventMap<TRow = unknown> {
1279
+ 'cell-click': CellClickDetail<TRow>;
1280
+ 'row-click': RowClickDetail<TRow>;
1281
+ 'cell-activate': CellActivateDetail<TRow>;
1282
+ 'cell-change': CellChangeDetail<TRow>;
991
1283
  'cell-commit': CellCommitDetail<TRow>;
992
1284
  'row-commit': RowCommitDetail<TRow>;
993
1285
  'changed-rows-reset': ChangedRowsResetDetail<TRow>;
@@ -995,12 +1287,28 @@ export interface DataGridEventMap<TRow = unknown> {
995
1287
  'mount-external-editor': ExternalMountEditorDetail<TRow>;
996
1288
  'sort-change': SortChangeDetail;
997
1289
  'column-resize': ColumnResizeDetail;
1290
+ /** @deprecated Use 'cell-activate' instead */
998
1291
  'activate-cell': ActivateCellDetail;
999
1292
  'column-state-change': GridColumnState;
1000
1293
  }
1294
+ /**
1295
+ * Extracts the event detail type for a given event name.
1296
+ *
1297
+ * @category Events
1298
+ */
1001
1299
  export type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];
1300
+ /**
1301
+ * Custom event type for DataGrid events with typed detail payload.
1302
+ *
1303
+ * @category Events
1304
+ */
1002
1305
  export type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<DataGridEventMap<TRow>[K]>;
1003
1306
  export type EditorContext<T = unknown> = ColumnEditorContext<T, unknown>;
1307
+ /**
1308
+ * Template evaluation context for dynamic templates.
1309
+ *
1310
+ * @category Plugin Development
1311
+ */
1004
1312
  export interface EvalContext {
1005
1313
  value: unknown;
1006
1314
  row: Record<string, unknown> | null;