apex-grid 3.2.0 → 3.4.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 (205) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/README.md +229 -52
  3. package/components/cell.d.ts +16 -3
  4. package/components/cell.js +78 -8
  5. package/components/cell.js.map +1 -1
  6. package/components/filter-row.d.ts +3 -6
  7. package/components/filter-row.js +144 -115
  8. package/components/filter-row.js.map +1 -1
  9. package/components/grid.d.ts +421 -77
  10. package/components/grid.js +432 -13
  11. package/components/grid.js.map +1 -1
  12. package/components/group-header-row.d.ts +34 -0
  13. package/components/group-header-row.js +125 -0
  14. package/components/group-header-row.js.map +1 -0
  15. package/components/header-row.d.ts +13 -2
  16. package/components/header-row.js +33 -18
  17. package/components/header-row.js.map +1 -1
  18. package/components/header.d.ts +11 -0
  19. package/components/header.js +209 -8
  20. package/components/header.js.map +1 -1
  21. package/components/paginator.d.ts +6 -1
  22. package/components/paginator.js +17 -11
  23. package/components/paginator.js.map +1 -1
  24. package/components/row.d.ts +28 -0
  25. package/components/row.js +100 -3
  26. package/components/row.js.map +1 -1
  27. package/components/toolbar.d.ts +8 -1
  28. package/components/toolbar.js +25 -7
  29. package/components/toolbar.js.map +1 -1
  30. package/controllers/data-operation.js +1 -0
  31. package/controllers/data-operation.js.map +1 -1
  32. package/controllers/dom.d.ts +24 -6
  33. package/controllers/dom.js +62 -5
  34. package/controllers/dom.js.map +1 -1
  35. package/controllers/editing.d.ts +68 -1
  36. package/controllers/editing.js +129 -44
  37. package/controllers/editing.js.map +1 -1
  38. package/controllers/expansion.js +4 -4
  39. package/controllers/expansion.js.map +1 -1
  40. package/controllers/filter.d.ts +1 -1
  41. package/controllers/filter.js +27 -5
  42. package/controllers/filter.js.map +1 -1
  43. package/controllers/history.d.ts +86 -0
  44. package/controllers/history.js +125 -0
  45. package/controllers/history.js.map +1 -0
  46. package/controllers/navigation.d.ts +49 -2
  47. package/controllers/navigation.js +145 -3
  48. package/controllers/navigation.js.map +1 -1
  49. package/controllers/pagination.js +1 -1
  50. package/controllers/pagination.js.map +1 -1
  51. package/controllers/reorder.js +3 -1
  52. package/controllers/reorder.js.map +1 -1
  53. package/controllers/row-pin.d.ts +59 -0
  54. package/controllers/row-pin.js +75 -0
  55. package/controllers/row-pin.js.map +1 -0
  56. package/controllers/row-reorder.d.ts +161 -0
  57. package/controllers/row-reorder.js +332 -0
  58. package/controllers/row-reorder.js.map +1 -0
  59. package/controllers/selection.js +3 -3
  60. package/controllers/selection.js.map +1 -1
  61. package/controllers/sort.js +13 -3
  62. package/controllers/sort.js.map +1 -1
  63. package/controllers/state.d.ts +33 -0
  64. package/controllers/state.js +37 -2
  65. package/controllers/state.js.map +1 -1
  66. package/controllers/tree.d.ts +8 -0
  67. package/controllers/tree.js +0 -0
  68. package/controllers/tree.js.map +1 -1
  69. package/custom-elements.json +4667 -926
  70. package/docs/assets/hierarchy.js +1 -1
  71. package/docs/assets/highlight.css +28 -0
  72. package/docs/assets/navigation.js +1 -1
  73. package/docs/assets/search.js +1 -1
  74. package/docs/functions/custom.html +3 -0
  75. package/docs/functions/interpolate.html +4 -0
  76. package/docs/functions/localize.html +8 -0
  77. package/docs/functions/max.html +3 -0
  78. package/docs/functions/min.html +3 -0
  79. package/docs/functions/pattern.html +3 -0
  80. package/docs/functions/required.html +3 -0
  81. package/docs/hierarchy.html +1 -1
  82. package/docs/index.html +245 -54
  83. package/docs/interfaces/ApexCellValidationFailedEvent.html +13 -0
  84. package/docs/interfaces/ApexCellValueChangedEvent.html +1 -1
  85. package/docs/interfaces/ApexCellValueChangingEvent.html +2 -2
  86. package/docs/interfaces/ApexColumnGroupContext.html +6 -0
  87. package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
  88. package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
  89. package/docs/interfaces/ApexDetailContext.html +2 -2
  90. package/docs/interfaces/ApexGridEventMap.html +37 -9
  91. package/docs/interfaces/ApexHistoryChangedEvent.html +6 -0
  92. package/docs/interfaces/ApexPageChangedEvent.html +1 -1
  93. package/docs/interfaces/ApexRowMovingEvent.html +9 -0
  94. package/docs/interfaces/ApexRowPinningEvent.html +8 -0
  95. package/docs/interfaces/ApexStateChangedEvent.html +4 -0
  96. package/docs/interfaces/BaseApexCellContext.html +1 -1
  97. package/docs/interfaces/BaseApexEditorContext.html +1 -1
  98. package/docs/interfaces/BaseColumnConfiguration.html +42 -17
  99. package/docs/interfaces/CSVExportOptions.html +2 -2
  100. package/docs/interfaces/ColumnGroupConfiguration.html +12 -0
  101. package/docs/interfaces/ColumnLayoutState.html +2 -0
  102. package/docs/interfaces/ColumnSchema.html +22 -0
  103. package/docs/interfaces/DataPipelineConfiguration.html +2 -2
  104. package/docs/interfaces/EditingHistoryConfiguration.html +10 -0
  105. package/docs/interfaces/ExportFormat.html +2 -2
  106. package/docs/interfaces/ExportOptions.html +1 -1
  107. package/docs/interfaces/FilterStateSnapshot.html +4 -0
  108. package/docs/interfaces/GetStateOptions.html +4 -0
  109. package/docs/interfaces/GridCapabilities.html +8 -0
  110. package/docs/interfaces/GridEditingConfiguration.html +4 -2
  111. package/docs/interfaces/GridRowPinningConfiguration.html +5 -0
  112. package/docs/interfaces/GridRowReorderingConfiguration.html +22 -0
  113. package/docs/interfaces/GridSchema.html +19 -0
  114. package/docs/interfaces/GridState.html +41 -0
  115. package/docs/interfaces/GridTreeConfiguration.html +2 -2
  116. package/docs/interfaces/PaginationConfiguration.html +1 -1
  117. package/docs/interfaces/PaginationState.html +1 -1
  118. package/docs/interfaces/SetStateOptions.html +9 -0
  119. package/docs/interfaces/SetStateResult.html +11 -0
  120. package/docs/interfaces/SortStateSnapshot.html +2 -0
  121. package/docs/interfaces/ValidatorContext.html +8 -0
  122. package/docs/media/_tokens.scss +70 -81
  123. package/docs/media/package.json +2 -2
  124. package/docs/media/state-persistence.html +189 -0
  125. package/docs/modules.html +1 -1
  126. package/docs/types/DataPipelineParams.html +2 -2
  127. package/docs/types/EditMode.html +2 -2
  128. package/docs/types/GridLocaleKey.html +3 -0
  129. package/docs/types/GridLocaleText.html +5 -0
  130. package/docs/types/LocaleParams.html +2 -0
  131. package/docs/types/PaginationMode.html +1 -1
  132. package/docs/types/RowDropPosition.html +2 -0
  133. package/docs/types/RowPinPosition.html +2 -0
  134. package/docs/types/RowRef.html +3 -0
  135. package/docs/types/Validator.html +4 -0
  136. package/docs/variables/EN_LOCALE.html +9 -0
  137. package/docs/variables/esLocale.html +8 -0
  138. package/i18n/en.d.ts +245 -0
  139. package/i18n/en.js +219 -0
  140. package/i18n/en.js.map +1 -0
  141. package/i18n/es.d.ts +18 -0
  142. package/i18n/es.js +219 -0
  143. package/i18n/es.js.map +1 -0
  144. package/i18n/index.d.ts +3 -0
  145. package/i18n/index.js +4 -0
  146. package/i18n/index.js.map +1 -0
  147. package/i18n/localize.d.ts +23 -0
  148. package/i18n/localize.js +15 -0
  149. package/i18n/localize.js.map +1 -0
  150. package/index.d.ts +8 -2
  151. package/index.js +2 -0
  152. package/index.js.map +1 -1
  153. package/internal/column-types.js +1 -1
  154. package/internal/column-types.js.map +1 -1
  155. package/internal/feature-module.d.ts +46 -0
  156. package/internal/feature-module.js +11 -0
  157. package/internal/feature-module.js.map +1 -1
  158. package/internal/flip.js +1 -1
  159. package/internal/flip.js.map +1 -1
  160. package/internal/icons.d.ts +9 -7
  161. package/internal/icons.js +75 -35
  162. package/internal/icons.js.map +1 -1
  163. package/internal/index.d.ts +5 -3
  164. package/internal/index.js +2 -1
  165. package/internal/index.js.map +1 -1
  166. package/internal/state-schema.d.ts +85 -0
  167. package/internal/state-schema.js +27 -0
  168. package/internal/state-schema.js.map +1 -0
  169. package/internal/state-snapshot.d.ts +152 -0
  170. package/internal/state-snapshot.js +115 -0
  171. package/internal/state-snapshot.js.map +1 -0
  172. package/internal/tags.d.ts +1 -0
  173. package/internal/tags.js +1 -0
  174. package/internal/tags.js.map +1 -1
  175. package/internal/types.d.ts +162 -2
  176. package/internal/types.js.map +1 -1
  177. package/internal/utils.d.ts +12 -0
  178. package/internal/utils.js +17 -0
  179. package/internal/utils.js.map +1 -1
  180. package/internal/validators.d.ts +31 -0
  181. package/internal/validators.js +44 -0
  182. package/internal/validators.js.map +1 -0
  183. package/package.json +1 -1
  184. package/styles/_tokens.css.js +1 -1
  185. package/styles/_tokens.css.js.map +1 -1
  186. package/styles/body-cell/body-cell.css.js +1 -1
  187. package/styles/body-cell/body-cell.css.js.map +1 -1
  188. package/styles/body-row/body-row.css.js +1 -1
  189. package/styles/body-row/body-row.css.js.map +1 -1
  190. package/styles/filter-row/filter-row.css.js +1 -1
  191. package/styles/filter-row/filter-row.css.js.map +1 -1
  192. package/styles/grid/_grid.base.css.js +1 -1
  193. package/styles/grid/_grid.base.css.js.map +1 -1
  194. package/styles/grid/grid.css.js +1 -1
  195. package/styles/grid/grid.css.js.map +1 -1
  196. package/styles/group-header-row/group-header-row.css.d.ts +1 -0
  197. package/styles/group-header-row/group-header-row.css.js +3 -0
  198. package/styles/group-header-row/group-header-row.css.js.map +1 -0
  199. package/styles/header-cell/header-cell.css.js +1 -1
  200. package/styles/header-cell/header-cell.css.js.map +1 -1
  201. package/styles/header-row/header-row.base.css.js +1 -1
  202. package/styles/header-row/header-row.base.css.js.map +1 -1
  203. package/styles/toolbar/toolbar.css.js +1 -1
  204. package/styles/toolbar/toolbar.css.js.map +1 -1
  205. package/docs/classes/ApexGrid.html +0 -399
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-schema.js","sourceRoot":"","sources":["../../src/internal/state-schema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAwElD,MAAM,UAAU,YAAY,CAAmB,MAA8B;IAC3E,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAiB;QAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,GAAG,CAAC;QAC9C,QAAQ,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAa;QAC/C,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAC9B,UAAU;QACV,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;QAC3E,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;KAC/B,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACxF,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD,MAAM,UAAU,cAAc,CAC5B,OAA8C;IAE9C,MAAM,GAAG,GAAwC,EAAE,CAAC;IACpD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAa,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["import type { SortingDirection } from '../operations/sort/types.js';\nimport type { GridState } from './state-snapshot.js';\nimport type { ColumnConfiguration, DataType, SelectionMode } from './types.js';\nimport { getFilterOperandsFor } from './utils.js';\n\n/**\n * A machine-readable description of what the grid is and what can be done to it:\n * the columns and their data types, the operations available per column, the\n * grid-level capabilities, and the current {@link GridState}. Produced by\n * `ApexGrid.getSchema`.\n *\n * @remarks\n * This is the contract an AI layer feeds to an LLM (as the basis of a\n * structured-output schema) and validates a returned state patch against, but it\n * is AI-agnostic: it is equally useful for building a view-editor UI or for docs.\n * It is a descriptor, not a JSON-Schema document — everything needed to *build* a\n * strict JSON Schema (or validate a `setState` patch) is here. Enterprise grids\n * populate the optional grouping / pivot / aggregation fields.\n */\nexport interface GridSchema {\n /** Schema version, matching {@link GridState.version}. */\n version: 1;\n /** Per-column description, in display order. */\n columns: ColumnSchema[];\n /** Grid-level operation availability. */\n capabilities: GridCapabilities;\n /** The current restorable state, so capabilities and live values travel together. */\n state: GridState;\n}\n\n/** Description of a single column for {@link GridSchema}. */\nexport interface ColumnSchema {\n key: string;\n /** Human label (`headerText`, falling back to `key`). */\n label: string;\n dataType: DataType;\n /** Whether the column opts into sorting (its header sort affordance). */\n sortable: boolean;\n /** Whether the column opts into filtering. */\n filterable: boolean;\n /** Operand names valid for this column when `filterable` (e.g. `'contains'`); else empty. */\n filterOperands: string[];\n editable: boolean;\n hidden: boolean;\n /** Pin band, omitted when the column scrolls with the body. */\n pinned?: 'start' | 'end';\n /** Enterprise: whether the column can be row-grouped. Set by the enterprise grid. */\n groupable?: boolean;\n /** Enterprise: whether the column can be a pivot dimension. Set by the enterprise grid. */\n pivotable?: boolean;\n /** Enterprise: whether the column can be aggregated. Set by the enterprise grid. */\n aggregatable?: boolean;\n /** Enterprise: aggregation functions valid for this column, when `aggregatable`. */\n aggFuncs?: string[];\n /** Enterprise: whether the column accepts spreadsheet formulas. Set by the enterprise grid. */\n allowFormula?: boolean;\n}\n\n/** Grid-level operation availability for {@link GridSchema}. */\nexport interface GridCapabilities {\n sort: { directions: SortingDirection[]; multi: boolean };\n filter: { operandsByType: Partial<Record<DataType, string[]>> };\n pagination: boolean;\n selection: SelectionMode | false;\n rowPinning: boolean;\n rowReordering: boolean;\n /** Enterprise: whether row grouping is available. Set by the enterprise grid. */\n grouping?: boolean;\n /** Enterprise: whether pivoting is available. Set by the enterprise grid. */\n pivot?: boolean;\n /** Enterprise: aggregation availability + the supported functions. Set by the enterprise grid. */\n aggregation?: { funcs: string[] };\n}\n\n/** Describe a single column: data type + the operations it opts into. */\nexport function columnSchema<T extends object>(column: ColumnConfiguration<T>): ColumnSchema {\n const filterable = Boolean(column.filter);\n const schema: ColumnSchema = {\n key: String(column.key),\n label: String(column.headerText ?? column.key),\n dataType: (column.type ?? 'string') as DataType,\n sortable: Boolean(column.sort),\n filterable,\n filterOperands: filterable ? Object.keys(getFilterOperandsFor(column)) : [],\n editable: Boolean(column.editable),\n hidden: Boolean(column.hidden),\n };\n if (column.pinned === 'start' || column.pinned === 'end') schema.pinned = column.pinned;\n return schema;\n}\n\n/**\n * The filter-operand vocabulary keyed by the data types present among `columns`\n * (the global reference for `capabilities.filter`), resolved from the same\n * source the apply path trusts ({@link getFilterOperandsFor}), so the schema and\n * `setState` can never disagree about valid operands.\n */\nexport function operandsByType<T extends object>(\n columns: ReadonlyArray<ColumnConfiguration<T>>\n): Partial<Record<DataType, string[]>> {\n const out: Partial<Record<DataType, string[]>> = {};\n for (const column of columns) {\n const type = (column.type ?? 'string') as DataType;\n if (!out[type]) out[type] = Object.keys(getFilterOperandsFor(column));\n }\n return out;\n}\n"]}
@@ -0,0 +1,152 @@
1
+ import type { FilterCriteria, FilterExpression } from '../operations/filter/types.js';
2
+ import type { SortExpression, SortingDirection } from '../operations/sort/types.js';
3
+ import type { ColumnConfiguration, PinPosition } from './types.js';
4
+ /**
5
+ * A serializable, JSON-safe snapshot of the grid's restorable state, produced by
6
+ * `ApexGrid.getState` and consumed by `ApexGrid.setState`.
7
+ *
8
+ * @remarks
9
+ * Functions and templates are never serialized — sort comparers, filter
10
+ * condition functions, and cell/header/editor templates are re-bound from the
11
+ * live column configuration on restore. Filter conditions are captured as
12
+ * operand name strings (e.g. `'contains'`). Selection / expansion / tree rows
13
+ * are captured as {@link RowRef}s (a stable `id` when an `ApexGrid.rowId`
14
+ * resolver is configured, otherwise a positional `index` into `ApexGrid.data`,
15
+ * which round-trips within a session but not across a data reload).
16
+ */
17
+ export interface GridState {
18
+ /** Snapshot schema version. */
19
+ version: 1;
20
+ /** Per-column layout (order, width, pinning, visibility). */
21
+ columns: ColumnLayoutState[];
22
+ /** Active sort expressions (comparer functions omitted). */
23
+ sort: SortStateSnapshot[];
24
+ /** Active per-column filter expressions (condition captured by operand name). */
25
+ filter: FilterStateSnapshot[];
26
+ /** Global quick-filter term. */
27
+ quickFilter: string;
28
+ /** Pagination position. */
29
+ pagination: {
30
+ page: number;
31
+ pageSize: number;
32
+ };
33
+ /** Selected rows. */
34
+ selection: RowRef[];
35
+ /** Expanded (master-detail) rows. */
36
+ expansion: RowRef[];
37
+ /** Expanded tree rows that have backing data. */
38
+ treeExpanded: RowRef[];
39
+ /** Expanded synthesized tree parents (path-keyed; already string-stable). */
40
+ treeExpandedKeys: string[];
41
+ /**
42
+ * Pinned rows (F4) by {@link RowRef}, per band. Optional: absent on snapshots
43
+ * produced before row pinning existed; `getState` always emits it (empty bands
44
+ * when nothing is pinned).
45
+ */
46
+ rowPinning?: {
47
+ top: RowRef[];
48
+ bottom: RowRef[];
49
+ };
50
+ /**
51
+ * Manual drag-reorder order (F5) as a full {@link RowRef} list, or `null` for
52
+ * the derived (filter → sort) order. Optional for back-compat; `getState`
53
+ * always emits it (`null` when no manual order is active). Mutually exclusive
54
+ * with `sort`: a snapshot carrying both drops `rowOrder` on restore.
55
+ */
56
+ rowOrder?: RowRef[] | null;
57
+ /** Per-module serialized state, keyed by module id. */
58
+ modules: Record<string, unknown>;
59
+ }
60
+ /** Layout state for a single column. Order is implied by array position. */
61
+ export interface ColumnLayoutState {
62
+ key: string;
63
+ width?: string;
64
+ pinned?: PinPosition;
65
+ hidden?: boolean;
66
+ }
67
+ /** A single sort expression, stripped of its (non-serializable) comparer. */
68
+ export interface SortStateSnapshot {
69
+ key: string;
70
+ direction: SortingDirection;
71
+ caseSensitive?: boolean;
72
+ }
73
+ /** A single filter expression with its condition captured by operand name. */
74
+ export interface FilterStateSnapshot {
75
+ key: string;
76
+ /** Operand name, e.g. `'contains'` / `'greaterThan'` (see the `*Operands`). */
77
+ operand: string;
78
+ searchTerm?: unknown;
79
+ criteria?: FilterCriteria;
80
+ caseSensitive?: boolean;
81
+ }
82
+ /**
83
+ * A reference to a row in `ApexGrid.data`: a stable `id` (when an
84
+ * `ApexGrid.rowId` resolver is configured) or a positional `index`.
85
+ */
86
+ export type RowRef = {
87
+ readonly id: string | number;
88
+ } | {
89
+ readonly index: number;
90
+ };
91
+ /** Options for `ApexGrid.getState`. */
92
+ export interface GetStateOptions<T extends object> {
93
+ /** Row-identity resolver; overrides `ApexGrid.rowId` for this call. */
94
+ rowId?: (row: T) => string | number;
95
+ }
96
+ /** Options for `ApexGrid.setState`. */
97
+ export interface SetStateOptions<T extends object> {
98
+ /** Row-identity resolver; overrides `ApexGrid.rowId` for this call. */
99
+ rowId?: (row: T) => string | number;
100
+ /**
101
+ * Throw on the first problem instead of degrading. Off by default: `setState`
102
+ * applies what it can and reports the rest via {@link SetStateResult.warnings}
103
+ * (the right behavior for LLM-produced or persisted-and-possibly-stale input).
104
+ * Turn on for tests / development to fail loudly.
105
+ */
106
+ strict?: boolean;
107
+ }
108
+ /**
109
+ * The outcome of an {@link SetStateOptions} apply. `setState` never throws on
110
+ * malformed input (unless `strict`): it applies recognized slices, skips the
111
+ * rest, and records human-readable {@link warnings} for anything dropped,
112
+ * clamped, or unresolved.
113
+ */
114
+ export interface SetStateResult {
115
+ /** Slice names that were present and applied (e.g. `'sort'`, `'columns'`). */
116
+ applied: string[];
117
+ /** Known slice names that were absent (left untouched). */
118
+ skipped: string[];
119
+ /** What was dropped / clamped / unresolved, one message each. */
120
+ warnings: string[];
121
+ }
122
+ /** Capture the layout-managed properties of each column, in array order. */
123
+ export declare function serializeColumnLayout<T extends object>(columns: ReadonlyArray<ColumnConfiguration<T>>): ColumnLayoutState[];
124
+ /**
125
+ * Return a new columns array reordered to match `layout`, with width / pinning /
126
+ * visibility applied. Column objects are shallow-cloned so non-layout
127
+ * properties (templates, comparers, type config) are preserved. Columns absent
128
+ * from `layout` are appended unchanged; layout entries with no matching column
129
+ * are ignored.
130
+ */
131
+ export declare function applyColumnLayout<T extends object>(columns: ReadonlyArray<ColumnConfiguration<T>>, layout: ReadonlyArray<ColumnLayoutState>): ColumnConfiguration<T>[];
132
+ export declare function serializeSort<T extends object>(expressions: ReadonlyArray<SortExpression<T>>): SortStateSnapshot[];
133
+ export declare function serializeFilter<T extends object>(expressions: ReadonlyArray<FilterExpression<T>>): FilterStateSnapshot[];
134
+ /**
135
+ * Rebuild filter expressions from a snapshot, resolving each operand name back
136
+ * to a live {@link FilterOperation} via the target column's operand set.
137
+ * Entries whose column or operand can't be resolved are dropped; `onDrop` (when
138
+ * given) is called with the dropped entry and a reason.
139
+ */
140
+ export declare function deserializeFilter<T extends object>(snapshots: ReadonlyArray<FilterStateSnapshot>, getColumn: (key: string) => ColumnConfiguration<T> | undefined, onDrop?: (snapshot: FilterStateSnapshot, reason: string) => void): FilterExpression<T>[];
141
+ /**
142
+ * Serialize a set of rows to {@link RowRef}s. With a `rowId` resolver each row
143
+ * is captured by id; otherwise by its positional index in `universe`
144
+ * (`ApexGrid.data`). Rows not found in `universe` (index mode) are skipped.
145
+ */
146
+ export declare function serializeRowRefs<T extends object>(rows: ReadonlyArray<T>, universe: ReadonlyArray<T>, rowId?: (row: T) => string | number): RowRef[];
147
+ /**
148
+ * Resolve {@link RowRef}s back to rows in `universe`. `id` refs require a
149
+ * `rowId` resolver (otherwise they're skipped); `index` refs resolve
150
+ * positionally. Unresolvable refs are dropped.
151
+ */
152
+ export declare function resolveRowRefs<T extends object>(refs: ReadonlyArray<RowRef>, universe: ReadonlyArray<T>, rowId?: (row: T) => string | number): T[];
@@ -0,0 +1,115 @@
1
+ import { getFilterOperandsFor } from './utils.js';
2
+ export function serializeColumnLayout(columns) {
3
+ return columns.map((column) => ({
4
+ key: String(column.key),
5
+ width: column.width,
6
+ pinned: column.pinned ?? undefined,
7
+ hidden: column.hidden ?? undefined,
8
+ }));
9
+ }
10
+ export function applyColumnLayout(columns, layout) {
11
+ const byKey = new Map();
12
+ for (const column of columns)
13
+ byKey.set(String(column.key), column);
14
+ const used = new Set();
15
+ const ordered = [];
16
+ for (const entry of layout) {
17
+ const column = byKey.get(entry.key);
18
+ if (!column)
19
+ continue;
20
+ used.add(entry.key);
21
+ ordered.push({
22
+ ...column,
23
+ width: entry.width,
24
+ pinned: entry.pinned ?? undefined,
25
+ hidden: entry.hidden ?? false,
26
+ });
27
+ }
28
+ for (const column of columns) {
29
+ if (!used.has(String(column.key)))
30
+ ordered.push(column);
31
+ }
32
+ return ordered;
33
+ }
34
+ export function serializeSort(expressions) {
35
+ return expressions.map((expression) => ({
36
+ key: String(expression.key),
37
+ direction: expression.direction,
38
+ caseSensitive: expression.caseSensitive,
39
+ }));
40
+ }
41
+ export function serializeFilter(expressions) {
42
+ return expressions.map((expression) => {
43
+ const condition = expression.condition;
44
+ return {
45
+ key: String(expression.key),
46
+ operand: typeof condition === 'string' ? condition : condition.name,
47
+ searchTerm: expression.searchTerm,
48
+ criteria: expression.criteria,
49
+ caseSensitive: expression.caseSensitive,
50
+ };
51
+ });
52
+ }
53
+ export function deserializeFilter(snapshots, getColumn, onDrop) {
54
+ const expressions = [];
55
+ for (const snapshot of snapshots) {
56
+ const column = getColumn(snapshot.key);
57
+ if (!column) {
58
+ onDrop?.(snapshot, 'unknown column');
59
+ continue;
60
+ }
61
+ const operands = getFilterOperandsFor(column);
62
+ const condition = operands[snapshot.operand];
63
+ if (!condition) {
64
+ onDrop?.(snapshot, `unknown operand "${snapshot.operand}"`);
65
+ continue;
66
+ }
67
+ expressions.push({
68
+ key: snapshot.key,
69
+ condition,
70
+ searchTerm: snapshot.searchTerm,
71
+ criteria: snapshot.criteria,
72
+ caseSensitive: snapshot.caseSensitive,
73
+ });
74
+ }
75
+ return expressions;
76
+ }
77
+ export function serializeRowRefs(rows, universe, rowId) {
78
+ const refs = [];
79
+ for (const row of rows) {
80
+ if (rowId) {
81
+ refs.push({ id: rowId(row) });
82
+ }
83
+ else {
84
+ const index = universe.indexOf(row);
85
+ if (index !== -1)
86
+ refs.push({ index });
87
+ }
88
+ }
89
+ return refs;
90
+ }
91
+ export function resolveRowRefs(refs, universe, rowId) {
92
+ const out = [];
93
+ let byId = null;
94
+ for (const ref of refs) {
95
+ if ('id' in ref) {
96
+ if (!rowId)
97
+ continue;
98
+ if (!byId) {
99
+ byId = new Map();
100
+ for (const row of universe)
101
+ byId.set(rowId(row), row);
102
+ }
103
+ const row = byId.get(ref.id);
104
+ if (row)
105
+ out.push(row);
106
+ }
107
+ else {
108
+ const row = universe[ref.index];
109
+ if (row)
110
+ out.push(row);
111
+ }
112
+ }
113
+ return out;
114
+ }
115
+ //# sourceMappingURL=state-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-snapshot.js","sourceRoot":"","sources":["../../src/internal/state-snapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n FilterCriteria,\n FilterExpression,\n FilterOperation,\n} from '../operations/filter/types.js';\nimport type { SortExpression, SortingDirection } from '../operations/sort/types.js';\nimport type { ColumnConfiguration, Keys, PinPosition } from './types.js';\nimport { getFilterOperandsFor } from './utils.js';\n\n/**\n * A serializable, JSON-safe snapshot of the grid's restorable state, produced by\n * `ApexGrid.getState` and consumed by `ApexGrid.setState`.\n *\n * @remarks\n * Functions and templates are never serialized — sort comparers, filter\n * condition functions, and cell/header/editor templates are re-bound from the\n * live column configuration on restore. Filter conditions are captured as\n * operand name strings (e.g. `'contains'`). Selection / expansion / tree rows\n * are captured as {@link RowRef}s (a stable `id` when an `ApexGrid.rowId`\n * resolver is configured, otherwise a positional `index` into `ApexGrid.data`,\n * which round-trips within a session but not across a data reload).\n */\nexport interface GridState {\n /** Snapshot schema version. */\n version: 1;\n /** Per-column layout (order, width, pinning, visibility). */\n columns: ColumnLayoutState[];\n /** Active sort expressions (comparer functions omitted). */\n sort: SortStateSnapshot[];\n /** Active per-column filter expressions (condition captured by operand name). */\n filter: FilterStateSnapshot[];\n /** Global quick-filter term. */\n quickFilter: string;\n /** Pagination position. */\n pagination: { page: number; pageSize: number };\n /** Selected rows. */\n selection: RowRef[];\n /** Expanded (master-detail) rows. */\n expansion: RowRef[];\n /** Expanded tree rows that have backing data. */\n treeExpanded: RowRef[];\n /** Expanded synthesized tree parents (path-keyed; already string-stable). */\n treeExpandedKeys: string[];\n /**\n * Pinned rows (F4) by {@link RowRef}, per band. Optional: absent on snapshots\n * produced before row pinning existed; `getState` always emits it (empty bands\n * when nothing is pinned).\n */\n rowPinning?: { top: RowRef[]; bottom: RowRef[] };\n /**\n * Manual drag-reorder order (F5) as a full {@link RowRef} list, or `null` for\n * the derived (filter → sort) order. Optional for back-compat; `getState`\n * always emits it (`null` when no manual order is active). Mutually exclusive\n * with `sort`: a snapshot carrying both drops `rowOrder` on restore.\n */\n rowOrder?: RowRef[] | null;\n /** Per-module serialized state, keyed by module id. */\n modules: Record<string, unknown>;\n}\n\n/** Layout state for a single column. Order is implied by array position. */\nexport interface ColumnLayoutState {\n key: string;\n width?: string;\n pinned?: PinPosition;\n hidden?: boolean;\n}\n\n/** A single sort expression, stripped of its (non-serializable) comparer. */\nexport interface SortStateSnapshot {\n key: string;\n direction: SortingDirection;\n caseSensitive?: boolean;\n}\n\n/** A single filter expression with its condition captured by operand name. */\nexport interface FilterStateSnapshot {\n key: string;\n /** Operand name, e.g. `'contains'` / `'greaterThan'` (see the `*Operands`). */\n operand: string;\n searchTerm?: unknown;\n criteria?: FilterCriteria;\n caseSensitive?: boolean;\n}\n\n/**\n * A reference to a row in `ApexGrid.data`: a stable `id` (when an\n * `ApexGrid.rowId` resolver is configured) or a positional `index`.\n */\nexport type RowRef = { readonly id: string | number } | { readonly index: number };\n\n/** Options for `ApexGrid.getState`. */\nexport interface GetStateOptions<T extends object> {\n /** Row-identity resolver; overrides `ApexGrid.rowId` for this call. */\n rowId?: (row: T) => string | number;\n}\n\n/** Options for `ApexGrid.setState`. */\nexport interface SetStateOptions<T extends object> {\n /** Row-identity resolver; overrides `ApexGrid.rowId` for this call. */\n rowId?: (row: T) => string | number;\n /**\n * Throw on the first problem instead of degrading. Off by default: `setState`\n * applies what it can and reports the rest via {@link SetStateResult.warnings}\n * (the right behavior for LLM-produced or persisted-and-possibly-stale input).\n * Turn on for tests / development to fail loudly.\n */\n strict?: boolean;\n}\n\n/**\n * The outcome of an {@link SetStateOptions} apply. `setState` never throws on\n * malformed input (unless `strict`): it applies recognized slices, skips the\n * rest, and records human-readable {@link warnings} for anything dropped,\n * clamped, or unresolved.\n */\nexport interface SetStateResult {\n /** Slice names that were present and applied (e.g. `'sort'`, `'columns'`). */\n applied: string[];\n /** Known slice names that were absent (left untouched). */\n skipped: string[];\n /** What was dropped / clamped / unresolved, one message each. */\n warnings: string[];\n}\n\n// --- columns ---------------------------------------------------------------\n\n/** Capture the layout-managed properties of each column, in array order. */\nexport function serializeColumnLayout<T extends object>(\n columns: ReadonlyArray<ColumnConfiguration<T>>\n): ColumnLayoutState[] {\n return columns.map((column) => ({\n key: String(column.key),\n width: column.width,\n pinned: column.pinned ?? undefined,\n hidden: column.hidden ?? undefined,\n }));\n}\n\n/**\n * Return a new columns array reordered to match `layout`, with width / pinning /\n * visibility applied. Column objects are shallow-cloned so non-layout\n * properties (templates, comparers, type config) are preserved. Columns absent\n * from `layout` are appended unchanged; layout entries with no matching column\n * are ignored.\n */\nexport function applyColumnLayout<T extends object>(\n columns: ReadonlyArray<ColumnConfiguration<T>>,\n layout: ReadonlyArray<ColumnLayoutState>\n): ColumnConfiguration<T>[] {\n const byKey = new Map<string, ColumnConfiguration<T>>();\n for (const column of columns) byKey.set(String(column.key), column);\n\n const used = new Set<string>();\n const ordered: ColumnConfiguration<T>[] = [];\n for (const entry of layout) {\n const column = byKey.get(entry.key);\n if (!column) continue;\n used.add(entry.key);\n ordered.push({\n ...column,\n width: entry.width,\n pinned: entry.pinned ?? undefined,\n hidden: entry.hidden ?? false,\n } as ColumnConfiguration<T>);\n }\n for (const column of columns) {\n if (!used.has(String(column.key))) ordered.push(column);\n }\n return ordered;\n}\n\n// --- sort ------------------------------------------------------------------\n\nexport function serializeSort<T extends object>(\n expressions: ReadonlyArray<SortExpression<T>>\n): SortStateSnapshot[] {\n return expressions.map((expression) => ({\n key: String(expression.key),\n direction: expression.direction,\n caseSensitive: expression.caseSensitive,\n }));\n}\n\n// --- filter ----------------------------------------------------------------\n\nexport function serializeFilter<T extends object>(\n expressions: ReadonlyArray<FilterExpression<T>>\n): FilterStateSnapshot[] {\n return expressions.map((expression) => {\n const condition = expression.condition as FilterOperation<unknown> | string;\n return {\n key: String(expression.key),\n operand: typeof condition === 'string' ? condition : condition.name,\n searchTerm: expression.searchTerm,\n criteria: expression.criteria,\n caseSensitive: expression.caseSensitive,\n };\n });\n}\n\n/**\n * Rebuild filter expressions from a snapshot, resolving each operand name back\n * to a live {@link FilterOperation} via the target column's operand set.\n * Entries whose column or operand can't be resolved are dropped; `onDrop` (when\n * given) is called with the dropped entry and a reason.\n */\nexport function deserializeFilter<T extends object>(\n snapshots: ReadonlyArray<FilterStateSnapshot>,\n getColumn: (key: string) => ColumnConfiguration<T> | undefined,\n onDrop?: (snapshot: FilterStateSnapshot, reason: string) => void\n): FilterExpression<T>[] {\n const expressions: FilterExpression<T>[] = [];\n for (const snapshot of snapshots) {\n const column = getColumn(snapshot.key);\n if (!column) {\n onDrop?.(snapshot, 'unknown column');\n continue;\n }\n const operands = getFilterOperandsFor(column) as unknown as Record<\n string,\n FilterOperation<unknown>\n >;\n const condition = operands[snapshot.operand];\n if (!condition) {\n onDrop?.(snapshot, `unknown operand \"${snapshot.operand}\"`);\n continue;\n }\n expressions.push({\n key: snapshot.key as Keys<T>,\n condition,\n searchTerm: snapshot.searchTerm,\n criteria: snapshot.criteria,\n caseSensitive: snapshot.caseSensitive,\n } as unknown as FilterExpression<T>);\n }\n return expressions;\n}\n\n// --- row references --------------------------------------------------------\n\n/**\n * Serialize a set of rows to {@link RowRef}s. With a `rowId` resolver each row\n * is captured by id; otherwise by its positional index in `universe`\n * (`ApexGrid.data`). Rows not found in `universe` (index mode) are skipped.\n */\nexport function serializeRowRefs<T extends object>(\n rows: ReadonlyArray<T>,\n universe: ReadonlyArray<T>,\n rowId?: (row: T) => string | number\n): RowRef[] {\n const refs: RowRef[] = [];\n for (const row of rows) {\n if (rowId) {\n refs.push({ id: rowId(row) });\n } else {\n const index = universe.indexOf(row);\n if (index !== -1) refs.push({ index });\n }\n }\n return refs;\n}\n\n/**\n * Resolve {@link RowRef}s back to rows in `universe`. `id` refs require a\n * `rowId` resolver (otherwise they're skipped); `index` refs resolve\n * positionally. Unresolvable refs are dropped.\n */\nexport function resolveRowRefs<T extends object>(\n refs: ReadonlyArray<RowRef>,\n universe: ReadonlyArray<T>,\n rowId?: (row: T) => string | number\n): T[] {\n const out: T[] = [];\n let byId: Map<string | number, T> | null = null;\n for (const ref of refs) {\n if ('id' in ref) {\n if (!rowId) continue;\n if (!byId) {\n byId = new Map();\n for (const row of universe) byId.set(rowId(row), row);\n }\n const row = byId.get(ref.id);\n if (row) out.push(row);\n } else {\n const row = universe[ref.index];\n if (row) out.push(row);\n }\n }\n return out;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  export declare const GRID_TAG: "apex-grid";
2
2
  export declare const GRID_BODY: "apex-virtualizer";
3
+ export declare const GRID_GROUP_HEADER_ROW_TAG: "apex-grid-group-header-row";
3
4
  export declare const GRID_HEADER_ROW_TAG: "apex-grid-header-row";
4
5
  export declare const GRID_HEADER_TAG: "apex-grid-header";
5
6
  export declare const GRID_ROW_TAG: "apex-grid-row";
package/internal/tags.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export const GRID_TAG = 'apex-grid';
2
2
  export const GRID_BODY = 'apex-virtualizer';
3
+ export const GRID_GROUP_HEADER_ROW_TAG = 'apex-grid-group-header-row';
3
4
  export const GRID_HEADER_ROW_TAG = 'apex-grid-header-row';
4
5
  export const GRID_HEADER_TAG = 'apex-grid-header';
5
6
  export const GRID_ROW_TAG = 'apex-grid-row';
@@ -1 +1 @@
1
- {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/internal/tags.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,WAAoB,CAAC;AAC7C,MAAM,CAAC,MAAM,SAAS,GAAG,kBAA2B,CAAC;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAA+B,CAAC;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,kBAA2B,CAAC;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG,eAAwB,CAAC;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAyB,CAAC;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAA0B,CAAC;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAA8B,CAAC;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC","sourcesContent":["export const GRID_TAG = 'apex-grid' as const;\nexport const GRID_BODY = 'apex-virtualizer' as const;\nexport const GRID_HEADER_ROW_TAG = 'apex-grid-header-row' as const;\nexport const GRID_HEADER_TAG = 'apex-grid-header' as const;\nexport const GRID_ROW_TAG = 'apex-grid-row' as const;\nexport const GRID_CELL_TAG = 'apex-grid-cell' as const;\nexport const GRID_FILTER_ROW_TAG = 'apex-filter-row' as const;\nexport const GRID_PAGINATOR_TAG = 'apex-grid-paginator' as const;\nexport const GRID_TOOLBAR_TAG = 'apex-grid-toolbar' as const;\n"]}
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/internal/tags.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,WAAoB,CAAC;AAC7C,MAAM,CAAC,MAAM,SAAS,GAAG,kBAA2B,CAAC;AACrD,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAAqC,CAAC;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAA+B,CAAC;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,kBAA2B,CAAC;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG,eAAwB,CAAC;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAyB,CAAC;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAA0B,CAAC;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAA8B,CAAC;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC","sourcesContent":["export const GRID_TAG = 'apex-grid' as const;\nexport const GRID_BODY = 'apex-virtualizer' as const;\nexport const GRID_GROUP_HEADER_ROW_TAG = 'apex-grid-group-header-row' as const;\nexport const GRID_HEADER_ROW_TAG = 'apex-grid-header-row' as const;\nexport const GRID_HEADER_TAG = 'apex-grid-header' as const;\nexport const GRID_ROW_TAG = 'apex-grid-row' as const;\nexport const GRID_CELL_TAG = 'apex-grid-cell' as const;\nexport const GRID_FILTER_ROW_TAG = 'apex-filter-row' as const;\nexport const GRID_PAGINATOR_TAG = 'apex-grid-paginator' as const;\nexport const GRID_TOOLBAR_TAG = 'apex-grid-toolbar' as const;\n"]}
@@ -6,6 +6,23 @@ import type ApexGridRow from '../components/row.js';
6
6
  import type { SortComparer } from '../operations/sort/types.js';
7
7
  export type NavigationState = 'previous' | 'current';
8
8
  export type GridHost<T extends object> = ReactiveControllerHost & ApexGrid<T>;
9
+ /**
10
+ * A custom action button contributed to the toolbar's trailing actions area.
11
+ *
12
+ * @remarks
13
+ * The seam derived grids use to add toolbar buttons, mirroring the export-format
14
+ * seam: the community grid contributes none (its {@link ApexGrid.toolbarActions}
15
+ * returns `[]`), and the toolbar renders one button per entry, invoking
16
+ * {@link ToolbarAction.run} on click.
17
+ */
18
+ export interface ToolbarAction {
19
+ /** Stable identifier, e.g. `'create-chart'`. */
20
+ id: string;
21
+ /** Button label. */
22
+ label: string;
23
+ /** Invoked when the button is clicked. */
24
+ run(): void;
25
+ }
9
26
  /**
10
27
  * Helper type for resolving keys of type T.
11
28
  */
@@ -218,6 +235,16 @@ export interface BaseColumnConfiguration<T extends object, K extends Keys<T> = K
218
235
  * Header template callback.
219
236
  */
220
237
  headerTemplate?: (params: ApexHeaderContext<T>) => TemplateResult | unknown;
238
+ /**
239
+ * The id of the {@link ColumnGroupConfiguration} this column belongs to.
240
+ *
241
+ * @remarks
242
+ * Columns sharing a `group` id render under a single spanning header cell in
243
+ * the group header row. Members must be **contiguous within one pin region**
244
+ * (the grid warns and skips the spanning cell otherwise). Has no effect unless
245
+ * {@link ApexGrid.columnGroups} defines a matching group.
246
+ */
247
+ group?: string;
221
248
  /**
222
249
  * Cell template callback.
223
250
  */
@@ -241,6 +268,33 @@ export interface BaseColumnConfiguration<T extends object, K extends Keys<T> = K
241
268
  * recommended so keyboard handoff works.
242
269
  */
243
270
  editorTemplate?: (params: ApexEditorContext<T, K>) => TemplateResult | unknown;
271
+ /**
272
+ * Allows cells in this column to hold spreadsheet-style formulas.
273
+ *
274
+ * @remarks
275
+ * An enterprise feature: the free core only carries this flag. With the
276
+ * enterprise formula module active and the column also
277
+ * {@link BaseColumnConfiguration.editable}, a cell whose edited text starts
278
+ * with `=` is parsed, stored as a formula, and its computed result becomes the
279
+ * cell value (so sorting, filtering, and aggregation keep working on the
280
+ * value). Has no effect without that module. Default `false`.
281
+ */
282
+ allowFormula?: boolean;
283
+ /**
284
+ * Declarative validators run before a candidate value is written to this
285
+ * column's cells.
286
+ *
287
+ * @remarks
288
+ * Each validator receives the candidate value and a {@link ValidatorContext}
289
+ * and returns an error message string (the cell is rejected) or `null` (it
290
+ * passes). All validators run and every message is collected, so a single
291
+ * failed commit can surface multiple errors. A failing commit keeps the
292
+ * inline editor open, marks the cell `aria-invalid`, and emits
293
+ * `cellValidationFailed`. Validation also covers bulk edits (paste / fill).
294
+ * Use the built-in factories ({@link required}, {@link min}, {@link max},
295
+ * {@link pattern}, {@link custom}) or supply your own function.
296
+ */
297
+ validators?: Validator<T, K>[];
244
298
  /**
245
299
  * Option list for columns with `type: 'select'`.
246
300
  *
@@ -318,6 +372,50 @@ export interface BaseColumnConfiguration<T extends object, K extends Keys<T> = K
318
372
  * See {@link BaseColumnConfiguration} for the full documentation.
319
373
  */
320
374
  export type ColumnConfiguration<T extends object, K extends Keys<T> = Keys<T>> = K extends Keys<T> ? BaseColumnConfiguration<T, K> : never;
375
+ /**
376
+ * Context passed to a {@link ColumnGroupConfiguration.headerTemplate}.
377
+ */
378
+ export interface ApexColumnGroupContext {
379
+ /** The group configuration being rendered. */
380
+ group: ColumnGroupConfiguration;
381
+ /** Number of (visible) member columns the group spans. */
382
+ span: number;
383
+ }
384
+ /**
385
+ * Configuration for a spanning group header over a contiguous run of columns
386
+ * (see {@link BaseColumnConfiguration.group}).
387
+ */
388
+ export interface ColumnGroupConfiguration {
389
+ /** Unique group id, referenced by a column's {@link BaseColumnConfiguration.group}. */
390
+ id: string;
391
+ /** Text rendered in the spanning group header cell. */
392
+ headerText: string;
393
+ /**
394
+ * Reserved for a future collapse affordance. Inert in v1 (static spanning
395
+ * headers only).
396
+ */
397
+ collapsible?: boolean;
398
+ /** Custom template for the group header cell, overriding `headerText`. */
399
+ headerTemplate?: (context: ApexColumnGroupContext) => TemplateResult | unknown;
400
+ }
401
+ /**
402
+ * Context passed to a {@link Validator} alongside the candidate value.
403
+ */
404
+ export interface ValidatorContext<T extends object, K extends Keys<T> = Keys<T>> {
405
+ /** The column configuration the value is being validated against. */
406
+ column: ColumnConfiguration<T, K>;
407
+ /** The full data record being edited (a live reference). */
408
+ data: T;
409
+ /** The view-relative row index of the edited cell. */
410
+ rowIndex: number;
411
+ }
412
+ /**
413
+ * A single declarative validation rule for a column.
414
+ *
415
+ * @returns An error message string when the value is invalid, or `null` when
416
+ * it passes.
417
+ */
418
+ export type Validator<T extends object, K extends Keys<T> = Keys<T>> = (value: unknown, context: ValidatorContext<T, K>) => string | null;
321
419
  export interface ActiveNode<T> {
322
420
  column: Keys<T>;
323
421
  row: number;
@@ -459,8 +557,8 @@ export interface ApexDetailContext<T extends object> {
459
557
  *
460
558
  * @remarks
461
559
  * Tree mode renders hierarchical data as nested rows that share the same
462
- * column layout — collapsible parents with indented children, AG Grid's
463
- * "tree data" pattern. The data array stays flat; the grid derives the
560
+ * column layout — collapsible parents with indented children, the
561
+ * flat-array "tree data" pattern. The data array stays flat; the grid derives the
464
562
  * hierarchy from {@link getDataPath} at runtime.
465
563
  *
466
564
  * This is distinct from {@link GridExpansionConfiguration} (master-detail),
@@ -530,6 +628,64 @@ export interface GridExpansionConfiguration<T extends object> {
530
628
  */
531
629
  showToggleColumn?: boolean;
532
630
  }
631
+ /**
632
+ * Undo / redo history configuration for cell-data edits.
633
+ */
634
+ export interface EditingHistoryConfiguration {
635
+ /**
636
+ * Whether undo / redo tracking is enabled. When `true`, every committed cell
637
+ * edit (single, row-mode, and bulk paste / fill) is recorded and can be
638
+ * reversed via {@link ApexGrid.undo} / {@link ApexGrid.redo} or the keyboard
639
+ * (Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y).
640
+ */
641
+ enabled: boolean;
642
+ /**
643
+ * Maximum number of commands retained on the undo stack. Older commands are
644
+ * evicted once the cap is exceeded. Defaults to `100`.
645
+ */
646
+ stackSize?: number;
647
+ }
648
+ /**
649
+ * Grid-level row-pinning configuration.
650
+ */
651
+ export interface GridRowPinningConfiguration {
652
+ /**
653
+ * Whether rows can be pinned to a sticky top / bottom band via
654
+ * {@link ApexGrid.pinRow}. Disabled when omitted.
655
+ */
656
+ enabled: boolean;
657
+ }
658
+ /**
659
+ * Grid-level row-reordering configuration.
660
+ */
661
+ export interface GridRowReorderingConfiguration {
662
+ /**
663
+ * Whether rows can be reordered by drag, keyboard, or {@link ApexGrid.moveRow}.
664
+ * A manual order, once set, is mutually exclusive with column sorting
665
+ * (applying a sort clears it). Disabled when omitted.
666
+ */
667
+ enabled: boolean;
668
+ /**
669
+ * When `true`, a reorder also splices {@link ApexGrid.data} in place so the
670
+ * source array reflects the new order. Defaults to `false`: the order lives in
671
+ * the grid and the app persists it via the `rowMoved` event.
672
+ */
673
+ applyToData?: boolean;
674
+ /**
675
+ * Controls how a pointer drag is initiated.
676
+ *
677
+ * - `true` (default): a dedicated drag-handle (grip) cell is rendered at the
678
+ * start of every reorderable row, and a drag only begins from that handle.
679
+ * The rest of the row stays free for selection / editing.
680
+ * - `false`: no handle is rendered and a drag begins by pressing anywhere on
681
+ * the row (excluding interactive sub-parts like inputs and buttons).
682
+ *
683
+ * Either way the dragged row is shown as a floating ghost that follows the
684
+ * cursor, and the keyboard reorder flow (grab with Space, move with arrows) is
685
+ * unchanged.
686
+ */
687
+ handle?: boolean;
688
+ }
533
689
  /**
534
690
  * Grid-level editing configuration.
535
691
  */
@@ -548,6 +704,10 @@ export interface GridEditingConfiguration {
548
704
  * The interaction that opens an editor. Defaults to `'doubleClick'`.
549
705
  */
550
706
  trigger?: EditTrigger;
707
+ /**
708
+ * Undo / redo history for cell-data edits. Disabled when omitted.
709
+ */
710
+ history?: EditingHistoryConfiguration;
551
711
  }
552
712
  /**
553
713
  * The parameters passed to a {@link DataPipelineHook} callback.