apex-grid 3.4.0 → 3.6.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.
- package/CHANGELOG.md +439 -0
- package/LICENSE.md +125 -0
- package/README.md +107 -14
- package/components/cell.d.ts +30 -4
- package/components/cell.js +199 -53
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +2 -0
- package/components/filter-row.js +82 -28
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +257 -20
- package/components/grid.js +463 -99
- package/components/grid.js.map +1 -1
- package/components/group-header-row.js +28 -25
- package/components/group-header-row.js.map +1 -1
- package/components/header-row.d.ts +7 -5
- package/components/header-row.js +19 -9
- package/components/header-row.js.map +1 -1
- package/components/header.js +36 -22
- package/components/header.js.map +1 -1
- package/components/row.d.ts +19 -3
- package/components/row.js +96 -22
- package/components/row.js.map +1 -1
- package/components/toolbar.js +2 -1
- package/components/toolbar.js.map +1 -1
- package/components/virtualizer.d.ts +45 -1
- package/components/virtualizer.js +184 -3
- package/components/virtualizer.js.map +1 -1
- package/controllers/dom.d.ts +4 -4
- package/controllers/dom.js +40 -22
- package/controllers/dom.js.map +1 -1
- package/controllers/editing.d.ts +104 -37
- package/controllers/editing.js +230 -78
- package/controllers/editing.js.map +1 -1
- package/controllers/expansion.d.ts +14 -5
- package/controllers/expansion.js +24 -1
- package/controllers/expansion.js.map +1 -1
- package/controllers/filter.d.ts +10 -2
- package/controllers/filter.js +62 -17
- package/controllers/filter.js.map +1 -1
- package/controllers/history.d.ts +45 -8
- package/controllers/history.js +58 -20
- package/controllers/history.js.map +1 -1
- package/controllers/navigation.d.ts +68 -13
- package/controllers/navigation.js +196 -51
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.d.ts +6 -0
- package/controllers/pagination.js +10 -2
- package/controllers/pagination.js.map +1 -1
- package/controllers/reorder.js +42 -24
- package/controllers/reorder.js.map +1 -1
- package/controllers/resize.d.ts +17 -2
- package/controllers/resize.js +16 -6
- package/controllers/resize.js.map +1 -1
- package/controllers/row-pin.d.ts +20 -2
- package/controllers/row-pin.js +16 -9
- package/controllers/row-pin.js.map +1 -1
- package/controllers/row-reorder.d.ts +31 -11
- package/controllers/row-reorder.js +117 -37
- package/controllers/row-reorder.js.map +1 -1
- package/controllers/selection.d.ts +11 -4
- package/controllers/selection.js +26 -11
- package/controllers/selection.js.map +1 -1
- package/controllers/sort.d.ts +22 -2
- package/controllers/sort.js +29 -23
- package/controllers/sort.js.map +1 -1
- package/controllers/state.d.ts +65 -10
- package/controllers/state.js +86 -6
- package/controllers/state.js.map +1 -1
- package/controllers/tree.d.ts +15 -10
- package/controllers/tree.js +0 -0
- package/controllers/tree.js.map +1 -1
- package/custom-elements.json +3589 -452
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +15 -8
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/ApexGrid.html +660 -0
- package/docs/classes/ApexGridPaginator.html +36 -0
- package/docs/classes/ApexGridToolbar.html +67 -0
- package/docs/functions/localize.html +2 -2
- package/docs/functions/setup.html +1 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +105 -15
- package/docs/interfaces/ApexCellValidationFailedEvent.html +3 -2
- package/docs/interfaces/ApexCellValueChangedEvent.html +4 -2
- package/docs/interfaces/ApexCellValueChangingEvent.html +3 -2
- package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
- package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
- package/docs/interfaces/ApexDetailContext.html +2 -2
- package/docs/interfaces/ApexGridEventMap.html +9 -6
- package/docs/interfaces/ApexRowEditEndedEvent.html +2 -1
- package/docs/interfaces/ApexRowEditStartedEvent.html +2 -1
- package/docs/interfaces/ApexRowMovingEvent.html +9 -3
- package/docs/interfaces/ApexRowPinningEvent.html +1 -1
- package/docs/interfaces/ApexTreeRowExpandedEvent.html +4 -1
- package/docs/interfaces/ApexTreeRowExpandingEvent.html +4 -1
- package/docs/interfaces/BaseApexCellContext.html +1 -1
- package/docs/interfaces/BaseApexEditorContext.html +1 -1
- package/docs/interfaces/BaseColumnConfiguration.html +3 -3
- package/docs/interfaces/BaseFilterExpression.html +2 -2
- package/docs/interfaces/CSVExportOptions.html +13 -5
- package/docs/interfaces/DataPipelineConfiguration.html +2 -2
- package/docs/interfaces/EditingHistoryConfiguration.html +1 -1
- package/docs/interfaces/ExportFormat.html +2 -2
- package/docs/interfaces/ExportOptions.html +5 -3
- package/docs/interfaces/GridExpansionConfiguration.html +6 -2
- package/docs/interfaces/GridRowPinningConfiguration.html +1 -1
- package/docs/interfaces/GridRowReorderingConfiguration.html +2 -2
- package/docs/interfaces/PaginationConfiguration.html +1 -1
- package/docs/interfaces/PaginationState.html +1 -1
- package/docs/interfaces/SetStateResult.html +3 -2
- package/docs/interfaces/ValidatorContext.html +7 -2
- package/docs/media/_token-values.scss +118 -0
- package/docs/media/package.json +5 -5
- package/docs/media/state-persistence.html +0 -10
- package/docs/modules.html +1 -1
- package/docs/types/DataPipelineParams.html +2 -2
- package/docs/types/EditMode.html +2 -2
- package/docs/types/ExportSource.html +6 -4
- package/docs/types/GridLocaleText.html +1 -1
- package/docs/types/OperandKeys.html +9 -0
- package/docs/types/PaginationMode.html +1 -1
- package/docs/variables/EN_LOCALE.html +3 -3
- package/docs/variables/esLocale.html +1 -1
- package/i18n/en.d.ts +19 -0
- package/i18n/en.js +19 -0
- package/i18n/en.js.map +1 -1
- package/i18n/es.js +19 -0
- package/i18n/es.js.map +1 -1
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/internal/column-types.d.ts +27 -1
- package/internal/column-types.js +75 -49
- package/internal/column-types.js.map +1 -1
- package/internal/constants.d.ts +1 -2
- package/internal/constants.js +0 -4
- package/internal/constants.js.map +1 -1
- package/internal/document-styles.d.ts +30 -0
- package/internal/document-styles.js +48 -0
- package/internal/document-styles.js.map +1 -0
- package/internal/export.d.ts +39 -7
- package/internal/export.js +35 -34
- package/internal/export.js.map +1 -1
- package/internal/feature-module.d.ts +82 -3
- package/internal/feature-module.js +11 -0
- package/internal/feature-module.js.map +1 -1
- package/internal/index.d.ts +6 -4
- package/internal/index.js +5 -3
- package/internal/index.js.map +1 -1
- package/internal/normalize-case.d.ts +8 -1
- package/internal/normalize-case.js +3 -2
- package/internal/normalize-case.js.map +1 -1
- package/internal/state-snapshot.d.ts +60 -8
- package/internal/state-snapshot.js +87 -19
- package/internal/state-snapshot.js.map +1 -1
- package/internal/types.d.ts +17 -2
- package/internal/types.js.map +1 -1
- package/internal/utils.d.ts +48 -6
- package/internal/utils.js +35 -21
- package/internal/utils.js.map +1 -1
- package/internal/validators.js +1 -0
- package/internal/validators.js.map +1 -1
- package/operations/filter/operands/number.js +9 -6
- package/operations/filter/operands/number.js.map +1 -1
- package/operations/filter/operands/string.js +2 -3
- package/operations/filter/operands/string.js.map +1 -1
- package/operations/filter/types.d.ts +13 -1
- package/operations/filter/types.js.map +1 -1
- package/operations/filter.d.ts +6 -0
- package/operations/filter.js +23 -7
- package/operations/filter.js.map +1 -1
- package/operations/quick-filter.js +2 -5
- package/operations/quick-filter.js.map +1 -1
- package/operations/sort.d.ts +21 -2
- package/operations/sort.js +41 -14
- package/operations/sort.js.map +1 -1
- package/package.json +8 -4
- package/setup.d.ts +23 -11
- package/setup.js +19 -21
- package/setup.js.map +1 -1
- package/styles/_common.css.js +1 -1
- package/styles/_common.css.js.map +1 -1
- package/styles/_token-values.css.d.ts +1 -0
- package/styles/_token-values.css.js +3 -0
- package/styles/_token-values.css.js.map +1 -0
- package/styles/_tokens.css.js +1 -1
- package/styles/_tokens.css.js.map +1 -1
- package/styles/body-cell/body-cell.css.js +1 -1
- package/styles/body-cell/body-cell.css.js.map +1 -1
- package/styles/body-cell/cell-renderers.css.js +1 -1
- package/styles/body-cell/cell-renderers.css.js.map +1 -1
- package/styles/body-row/body-row.css.js +1 -1
- package/styles/body-row/body-row.css.js.map +1 -1
- package/styles/document-tokens.css.d.ts +1 -0
- package/styles/document-tokens.css.js +3 -0
- package/styles/document-tokens.css.js.map +1 -0
- package/styles/filter-row/filter-row.css.js +1 -1
- package/styles/filter-row/filter-row.css.js.map +1 -1
- package/styles/grid/_grid.base.css.js +1 -1
- package/styles/grid/_grid.base.css.js.map +1 -1
- package/styles/grid/grid.css.js +1 -1
- package/styles/grid/grid.css.js.map +1 -1
- package/styles/group-header-row/group-header-row.css.js +1 -1
- package/styles/group-header-row/group-header-row.css.js.map +1 -1
- package/styles/header-cell/header-cell.css.js +1 -1
- package/styles/header-cell/header-cell.css.js.map +1 -1
- package/styles/header-row/header-row.base.css.js +1 -1
- package/styles/header-row/header-row.base.css.js.map +1 -1
- package/styles/paginator/paginator.css.js +1 -1
- package/styles/paginator/paginator.css.js.map +1 -1
- package/styles/toolbar/toolbar.css.js +1 -1
- package/styles/toolbar/toolbar.css.js.map +1 -1
- package/tokens.css +78 -0
- package/LICENSE +0 -80
- package/docs/media/LICENSE +0 -80
- package/docs/media/_tokens.scss +0 -193
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FilterCriteria, FilterExpression } from '../operations/filter/types.js';
|
|
1
|
+
import type { FilterCriteria, FilterExpression, FilterOperation } from '../operations/filter/types.js';
|
|
2
2
|
import type { SortExpression, SortingDirection } from '../operations/sort/types.js';
|
|
3
3
|
import type { ColumnConfiguration, PinPosition } from './types.js';
|
|
4
4
|
/**
|
|
@@ -105,6 +105,27 @@ export interface SetStateOptions<T extends object> {
|
|
|
105
105
|
*/
|
|
106
106
|
strict?: boolean;
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* The `setState` slices in the order `setState` applies them, each mapped to
|
|
110
|
+
* the {@link GridState} keys it restores (`tree` restores both tree keys).
|
|
111
|
+
*/
|
|
112
|
+
export declare const SET_STATE_SLICE_KEYS: {
|
|
113
|
+
readonly columns: readonly ["columns"];
|
|
114
|
+
readonly sort: readonly ["sort"];
|
|
115
|
+
readonly filter: readonly ["filter"];
|
|
116
|
+
readonly quickFilter: readonly ["quickFilter"];
|
|
117
|
+
readonly modules: readonly ["modules"];
|
|
118
|
+
readonly rowOrder: readonly ["rowOrder"];
|
|
119
|
+
readonly tree: readonly ["treeExpanded", "treeExpandedKeys"];
|
|
120
|
+
readonly expansion: readonly ["expansion"];
|
|
121
|
+
readonly rowPinning: readonly ["rowPinning"];
|
|
122
|
+
readonly selection: readonly ["selection"];
|
|
123
|
+
readonly pagination: readonly ["pagination"];
|
|
124
|
+
};
|
|
125
|
+
/** A `setState` slice name, as reported in {@link SetStateResult}. */
|
|
126
|
+
export type SetStateSlice = keyof typeof SET_STATE_SLICE_KEYS;
|
|
127
|
+
/** Every slice name, in apply order. */
|
|
128
|
+
export declare const SET_STATE_SLICES: SetStateSlice[];
|
|
108
129
|
/**
|
|
109
130
|
* The outcome of an {@link SetStateOptions} apply. `setState` never throws on
|
|
110
131
|
* malformed input (unless `strict`): it applies recognized slices, skips the
|
|
@@ -112,9 +133,12 @@ export interface SetStateOptions<T extends object> {
|
|
|
112
133
|
* clamped, or unresolved.
|
|
113
134
|
*/
|
|
114
135
|
export interface SetStateResult {
|
|
115
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Slice names that were present and applied (e.g. `'sort'`, `'columns'`); see
|
|
138
|
+
* {@link SET_STATE_SLICE_KEYS} for the {@link GridState} keys of each.
|
|
139
|
+
*/
|
|
116
140
|
applied: string[];
|
|
117
|
-
/** Known slice names that were absent
|
|
141
|
+
/** Known slice names ({@link SetStateSlice}) that were absent or not applied. */
|
|
118
142
|
skipped: string[];
|
|
119
143
|
/** What was dropped / clamped / unresolved, one message each. */
|
|
120
144
|
warnings: string[];
|
|
@@ -125,28 +149,56 @@ export declare function serializeColumnLayout<T extends object>(columns: Readonl
|
|
|
125
149
|
* Return a new columns array reordered to match `layout`, with width / pinning /
|
|
126
150
|
* visibility applied. Column objects are shallow-cloned so non-layout
|
|
127
151
|
* properties (templates, comparers, type config) are preserved. Columns absent
|
|
128
|
-
* from `layout` are appended unchanged; layout entries with no matching column
|
|
129
|
-
* are ignored.
|
|
152
|
+
* from `layout` are appended unchanged; layout entries with no matching column,
|
|
153
|
+
* a repeated key, or no string `key` are ignored. This is the full-layout
|
|
154
|
+
* restorer: to change a few fields in place, overlay them with
|
|
155
|
+
* {@link mergeColumnLayout} first.
|
|
130
156
|
*/
|
|
131
157
|
export declare function applyColumnLayout<T extends object>(columns: ReadonlyArray<ColumnConfiguration<T>>, layout: ReadonlyArray<ColumnLayoutState>): ColumnConfiguration<T>[];
|
|
158
|
+
/**
|
|
159
|
+
* Overlay a partial layout onto `current` (a full {@link serializeColumnLayout}
|
|
160
|
+
* result): each `partial` entry changes only the fields it defines on the
|
|
161
|
+
* column with the same key, and the order of `current` is kept. `null` clears
|
|
162
|
+
* a field (e.g. `pinned: null` unpins). Entries for unknown keys are ignored.
|
|
163
|
+
* Returns a new full layout to hand to `setState({ columns })`.
|
|
164
|
+
*/
|
|
165
|
+
export declare function mergeColumnLayout(current: ReadonlyArray<ColumnLayoutState>, partial: ReadonlyArray<Partial<Record<keyof ColumnLayoutState, unknown>>>): ColumnLayoutState[];
|
|
132
166
|
export declare function serializeSort<T extends object>(expressions: ReadonlyArray<SortExpression<T>>): SortStateSnapshot[];
|
|
133
167
|
export declare function serializeFilter<T extends object>(expressions: ReadonlyArray<FilterExpression<T>>): FilterStateSnapshot[];
|
|
168
|
+
/**
|
|
169
|
+
* Make `operation` resolvable by its `name` on every column, after the
|
|
170
|
+
* column type's own operands. For first-party filter UIs (the enterprise set
|
|
171
|
+
* filter) whose expressions must survive `setState(getState())`. The
|
|
172
|
+
* operation must be stateless: everything it needs travels in `searchTerm`.
|
|
173
|
+
*/
|
|
174
|
+
export declare function registerFilterOperand(operation: FilterOperation<unknown>): void;
|
|
175
|
+
/**
|
|
176
|
+
* Resolve a filter operand name (e.g. `'contains'`) to the live
|
|
177
|
+
* {@link FilterOperation} of `column`'s type, else to one registered with
|
|
178
|
+
* {@link registerFilterOperand}. Only the tables' own names resolve, so
|
|
179
|
+
* `'toString'` or `'constructor'` never pass as operands.
|
|
180
|
+
*/
|
|
181
|
+
export declare function resolveFilterOperand<T extends object>(column: ColumnConfiguration<T>, name: unknown): FilterOperation<unknown> | undefined;
|
|
134
182
|
/**
|
|
135
183
|
* Rebuild filter expressions from a snapshot, resolving each operand name back
|
|
136
184
|
* to a live {@link FilterOperation} via the target column's operand set.
|
|
137
|
-
* Entries whose column or operand can't be
|
|
138
|
-
*
|
|
185
|
+
* Entries that are not keyed objects, whose column or operand can't be
|
|
186
|
+
* resolved, or whose binary operand has no `searchTerm` are dropped; `onDrop`
|
|
187
|
+
* (when given) is called with the dropped entry and a reason.
|
|
139
188
|
*/
|
|
140
189
|
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
190
|
/**
|
|
142
191
|
* Serialize a set of rows to {@link RowRef}s. With a `rowId` resolver each row
|
|
143
192
|
* is captured by id; otherwise by its positional index in `universe`
|
|
144
193
|
* (`ApexGrid.data`). Rows not found in `universe` (index mode) are skipped.
|
|
194
|
+
* Index mode builds one position map per call, so it is linear in the sizes
|
|
195
|
+
* of `rows` and `universe` rather than their product.
|
|
145
196
|
*/
|
|
146
197
|
export declare function serializeRowRefs<T extends object>(rows: ReadonlyArray<T>, universe: ReadonlyArray<T>, rowId?: (row: T) => string | number): RowRef[];
|
|
147
198
|
/**
|
|
148
199
|
* Resolve {@link RowRef}s back to rows in `universe`. `id` refs require a
|
|
149
200
|
* `rowId` resolver (otherwise they're skipped); `index` refs resolve
|
|
150
|
-
* positionally.
|
|
201
|
+
* positionally and must be non-negative integers. Refs that are not objects,
|
|
202
|
+
* and unresolvable refs, are dropped.
|
|
151
203
|
*/
|
|
152
204
|
export declare function resolveRowRefs<T extends object>(refs: ReadonlyArray<RowRef>, universe: ReadonlyArray<T>, rowId?: (row: T) => string | number): T[];
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
import { getFilterOperandsFor } from './utils.js';
|
|
2
|
+
export const SET_STATE_SLICE_KEYS = {
|
|
3
|
+
columns: ['columns'],
|
|
4
|
+
sort: ['sort'],
|
|
5
|
+
filter: ['filter'],
|
|
6
|
+
quickFilter: ['quickFilter'],
|
|
7
|
+
modules: ['modules'],
|
|
8
|
+
rowOrder: ['rowOrder'],
|
|
9
|
+
tree: ['treeExpanded', 'treeExpandedKeys'],
|
|
10
|
+
expansion: ['expansion'],
|
|
11
|
+
rowPinning: ['rowPinning'],
|
|
12
|
+
selection: ['selection'],
|
|
13
|
+
pagination: ['pagination'],
|
|
14
|
+
};
|
|
15
|
+
export const SET_STATE_SLICES = Object.keys(SET_STATE_SLICE_KEYS);
|
|
16
|
+
const _everyKeyHasASlice = true;
|
|
17
|
+
void _everyKeyHasASlice;
|
|
18
|
+
function isKeyed(value) {
|
|
19
|
+
return typeof value === 'object' && value !== null && typeof value.key === 'string';
|
|
20
|
+
}
|
|
2
21
|
export function serializeColumnLayout(columns) {
|
|
3
22
|
return columns.map((column) => ({
|
|
4
23
|
key: String(column.key),
|
|
@@ -14,6 +33,8 @@ export function applyColumnLayout(columns, layout) {
|
|
|
14
33
|
const used = new Set();
|
|
15
34
|
const ordered = [];
|
|
16
35
|
for (const entry of layout) {
|
|
36
|
+
if (!isKeyed(entry) || used.has(entry.key))
|
|
37
|
+
continue;
|
|
17
38
|
const column = byKey.get(entry.key);
|
|
18
39
|
if (!column)
|
|
19
40
|
continue;
|
|
@@ -31,6 +52,24 @@ export function applyColumnLayout(columns, layout) {
|
|
|
31
52
|
}
|
|
32
53
|
return ordered;
|
|
33
54
|
}
|
|
55
|
+
export function mergeColumnLayout(current, partial) {
|
|
56
|
+
const patches = new Map();
|
|
57
|
+
for (const entry of partial) {
|
|
58
|
+
if (isKeyed(entry))
|
|
59
|
+
patches.set(entry.key, entry);
|
|
60
|
+
}
|
|
61
|
+
return current.map((column) => {
|
|
62
|
+
const next = { ...column };
|
|
63
|
+
const patch = patches.get(column.key);
|
|
64
|
+
if (patch) {
|
|
65
|
+
for (const field of ['width', 'pinned', 'hidden']) {
|
|
66
|
+
if (patch[field] !== undefined)
|
|
67
|
+
next[field] = patch[field] ?? undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return next;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
34
73
|
export function serializeSort(expressions) {
|
|
35
74
|
return expressions.map((expression) => ({
|
|
36
75
|
key: String(expression.key),
|
|
@@ -38,53 +77,80 @@ export function serializeSort(expressions) {
|
|
|
38
77
|
caseSensitive: expression.caseSensitive,
|
|
39
78
|
}));
|
|
40
79
|
}
|
|
80
|
+
function copyTerm(term) {
|
|
81
|
+
return Array.isArray(term) ? [...term] : term;
|
|
82
|
+
}
|
|
41
83
|
export function serializeFilter(expressions) {
|
|
42
84
|
return expressions.map((expression) => {
|
|
43
85
|
const condition = expression.condition;
|
|
44
86
|
return {
|
|
45
87
|
key: String(expression.key),
|
|
46
88
|
operand: typeof condition === 'string' ? condition : condition.name,
|
|
47
|
-
searchTerm: expression.searchTerm,
|
|
89
|
+
searchTerm: copyTerm(expression.searchTerm),
|
|
48
90
|
criteria: expression.criteria,
|
|
49
91
|
caseSensitive: expression.caseSensitive,
|
|
50
92
|
};
|
|
51
93
|
});
|
|
52
94
|
}
|
|
95
|
+
const registeredOperands = new Map();
|
|
96
|
+
export function registerFilterOperand(operation) {
|
|
97
|
+
registeredOperands.set(operation.name, operation);
|
|
98
|
+
}
|
|
99
|
+
export function resolveFilterOperand(column, name) {
|
|
100
|
+
if (typeof name !== 'string')
|
|
101
|
+
return undefined;
|
|
102
|
+
const operands = getFilterOperandsFor(column);
|
|
103
|
+
return Object.hasOwn(operands, name) ? operands[name] : registeredOperands.get(name);
|
|
104
|
+
}
|
|
53
105
|
export function deserializeFilter(snapshots, getColumn, onDrop) {
|
|
54
106
|
const expressions = [];
|
|
55
107
|
for (const snapshot of snapshots) {
|
|
108
|
+
if (!isKeyed(snapshot)) {
|
|
109
|
+
onDrop?.({ key: String(snapshot) }, 'not a filter entry');
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
56
112
|
const column = getColumn(snapshot.key);
|
|
57
113
|
if (!column) {
|
|
58
114
|
onDrop?.(snapshot, 'unknown column');
|
|
59
115
|
continue;
|
|
60
116
|
}
|
|
61
|
-
const
|
|
62
|
-
const condition = operands[snapshot.operand];
|
|
117
|
+
const condition = resolveFilterOperand(column, snapshot.operand);
|
|
63
118
|
if (!condition) {
|
|
64
119
|
onDrop?.(snapshot, `unknown operand "${snapshot.operand}"`);
|
|
65
120
|
continue;
|
|
66
121
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
122
|
+
if (!condition.unary && (snapshot.searchTerm === undefined || snapshot.searchTerm === null)) {
|
|
123
|
+
onDrop?.(snapshot, `operand "${snapshot.operand}" needs a searchTerm`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const expression = { key: snapshot.key, condition };
|
|
127
|
+
if (snapshot.searchTerm !== undefined)
|
|
128
|
+
expression.searchTerm = copyTerm(snapshot.searchTerm);
|
|
129
|
+
if (snapshot.criteria !== undefined)
|
|
130
|
+
expression.criteria = snapshot.criteria;
|
|
131
|
+
if (snapshot.caseSensitive !== undefined)
|
|
132
|
+
expression.caseSensitive = snapshot.caseSensitive;
|
|
133
|
+
expressions.push(expression);
|
|
74
134
|
}
|
|
75
135
|
return expressions;
|
|
76
136
|
}
|
|
77
137
|
export function serializeRowRefs(rows, universe, rowId) {
|
|
138
|
+
if (rowId)
|
|
139
|
+
return rows.map((row) => ({ id: rowId(row) }));
|
|
140
|
+
if (rows.length < 2) {
|
|
141
|
+
const index = rows.length ? universe.indexOf(rows[0]) : -1;
|
|
142
|
+
return index === -1 ? [] : [{ index }];
|
|
143
|
+
}
|
|
144
|
+
const positions = new Map();
|
|
145
|
+
universe.forEach((row, index) => {
|
|
146
|
+
if (!positions.has(row))
|
|
147
|
+
positions.set(row, index);
|
|
148
|
+
});
|
|
78
149
|
const refs = [];
|
|
79
150
|
for (const row of rows) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
else {
|
|
84
|
-
const index = universe.indexOf(row);
|
|
85
|
-
if (index !== -1)
|
|
86
|
-
refs.push({ index });
|
|
87
|
-
}
|
|
151
|
+
const index = positions.get(row);
|
|
152
|
+
if (index !== undefined)
|
|
153
|
+
refs.push({ index });
|
|
88
154
|
}
|
|
89
155
|
return refs;
|
|
90
156
|
}
|
|
@@ -92,6 +158,8 @@ export function resolveRowRefs(refs, universe, rowId) {
|
|
|
92
158
|
const out = [];
|
|
93
159
|
let byId = null;
|
|
94
160
|
for (const ref of refs) {
|
|
161
|
+
if (typeof ref !== 'object' || ref === null)
|
|
162
|
+
continue;
|
|
95
163
|
if ('id' in ref) {
|
|
96
164
|
if (!rowId)
|
|
97
165
|
continue;
|
|
@@ -104,7 +172,7 @@ export function resolveRowRefs(refs, universe, rowId) {
|
|
|
104
172
|
if (row)
|
|
105
173
|
out.push(row);
|
|
106
174
|
}
|
|
107
|
-
else {
|
|
175
|
+
else if (Number.isInteger(ref.index) && ref.index >= 0) {
|
|
108
176
|
const row = universe[ref.index];
|
|
109
177
|
if (row)
|
|
110
178
|
out.push(row);
|
|
@@ -1 +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
|
+
{"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 `setState` slices in the order `setState` applies them, each mapped to\n * the {@link GridState} keys it restores (`tree` restores both tree keys).\n */\nexport const SET_STATE_SLICE_KEYS = {\n columns: ['columns'],\n sort: ['sort'],\n filter: ['filter'],\n quickFilter: ['quickFilter'],\n modules: ['modules'],\n rowOrder: ['rowOrder'],\n tree: ['treeExpanded', 'treeExpandedKeys'],\n expansion: ['expansion'],\n rowPinning: ['rowPinning'],\n selection: ['selection'],\n pagination: ['pagination'],\n} as const satisfies Record<string, ReadonlyArray<keyof GridState>>;\n\n/** A `setState` slice name, as reported in {@link SetStateResult}. */\nexport type SetStateSlice = keyof typeof SET_STATE_SLICE_KEYS;\n\n/** Every slice name, in apply order. */\nexport const SET_STATE_SLICES = Object.keys(SET_STATE_SLICE_KEYS) as SetStateSlice[];\n\n// Compile-time check: a new GridState key cannot be added without a slice.\nconst _everyKeyHasASlice: Exclude<\n keyof GridState,\n 'version' | (typeof SET_STATE_SLICE_KEYS)[SetStateSlice][number]\n> extends never\n ? true\n : never = true;\nvoid _everyKeyHasASlice;\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 /**\n * Slice names that were present and applied (e.g. `'sort'`, `'columns'`); see\n * {@link SET_STATE_SLICE_KEYS} for the {@link GridState} keys of each.\n */\n applied: string[];\n /** Known slice names ({@link SetStateSlice}) that were absent or not applied. */\n skipped: string[];\n /** What was dropped / clamped / unresolved, one message each. */\n warnings: string[];\n}\n\n/** A non-null object with a string `key`: the shape every keyed entry needs. */\nfunction isKeyed(value: unknown): value is { key: string } {\n return typeof value === 'object' && value !== null && typeof (value as any).key === '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 * a repeated key, or no string `key` are ignored. This is the full-layout\n * restorer: to change a few fields in place, overlay them with\n * {@link mergeColumnLayout} first.\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 if (!isKeyed(entry) || used.has(entry.key)) continue;\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/**\n * Overlay a partial layout onto `current` (a full {@link serializeColumnLayout}\n * result): each `partial` entry changes only the fields it defines on the\n * column with the same key, and the order of `current` is kept. `null` clears\n * a field (e.g. `pinned: null` unpins). Entries for unknown keys are ignored.\n * Returns a new full layout to hand to `setState({ columns })`.\n */\nexport function mergeColumnLayout(\n current: ReadonlyArray<ColumnLayoutState>,\n partial: ReadonlyArray<Partial<Record<keyof ColumnLayoutState, unknown>>>\n): ColumnLayoutState[] {\n const patches = new Map<string, Record<string, unknown>>();\n for (const entry of partial) {\n if (isKeyed(entry)) patches.set(entry.key, entry);\n }\n return current.map((column) => {\n const next: Record<string, unknown> = { ...column };\n const patch = patches.get(column.key);\n if (patch) {\n for (const field of ['width', 'pinned', 'hidden'] as const) {\n if (patch[field] !== undefined) next[field] = patch[field] ?? undefined;\n }\n }\n return next as unknown as ColumnLayoutState;\n });\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\nfunction copyTerm(term: unknown): unknown {\n return Array.isArray(term) ? [...term] : term;\n}\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 // A copied array term, so editing a snapshot never edits the live filter.\n searchTerm: copyTerm(expression.searchTerm),\n criteria: expression.criteria,\n caseSensitive: expression.caseSensitive,\n };\n });\n}\n\n/** Operands a first-party filter UI registered, resolvable on any column. */\nconst registeredOperands = new Map<string, FilterOperation<unknown>>();\n\n/**\n * Make `operation` resolvable by its `name` on every column, after the\n * column type's own operands. For first-party filter UIs (the enterprise set\n * filter) whose expressions must survive `setState(getState())`. The\n * operation must be stateless: everything it needs travels in `searchTerm`.\n */\nexport function registerFilterOperand(operation: FilterOperation<unknown>): void {\n registeredOperands.set(operation.name, operation);\n}\n\n/**\n * Resolve a filter operand name (e.g. `'contains'`) to the live\n * {@link FilterOperation} of `column`'s type, else to one registered with\n * {@link registerFilterOperand}. Only the tables' own names resolve, so\n * `'toString'` or `'constructor'` never pass as operands.\n */\nexport function resolveFilterOperand<T extends object>(\n column: ColumnConfiguration<T>,\n name: unknown\n): FilterOperation<unknown> | undefined {\n if (typeof name !== 'string') return undefined;\n const operands = getFilterOperandsFor(column) as unknown as Record<\n string,\n FilterOperation<unknown>\n >;\n return Object.hasOwn(operands, name) ? operands[name] : registeredOperands.get(name);\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 that are not keyed objects, whose column or operand can't be\n * resolved, or whose binary operand has no `searchTerm` are dropped; `onDrop`\n * (when 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 if (!isKeyed(snapshot)) {\n onDrop?.({ key: String(snapshot) } as FilterStateSnapshot, 'not a filter entry');\n continue;\n }\n const column = getColumn(snapshot.key);\n if (!column) {\n onDrop?.(snapshot, 'unknown column');\n continue;\n }\n const condition = resolveFilterOperand(column, snapshot.operand);\n if (!condition) {\n onDrop?.(snapshot, `unknown operand \"${snapshot.operand}\"`);\n continue;\n }\n if (!condition.unary && (snapshot.searchTerm === undefined || snapshot.searchTerm === null)) {\n onDrop?.(snapshot, `operand \"${snapshot.operand}\" needs a searchTerm`);\n continue;\n }\n // Omitted fields stay absent so the column defaults (case sensitivity,\n // 'and' criteria) apply rather than an explicit undefined.\n const expression: Record<string, unknown> = { key: snapshot.key as Keys<T>, condition };\n if (snapshot.searchTerm !== undefined) expression.searchTerm = copyTerm(snapshot.searchTerm);\n if (snapshot.criteria !== undefined) expression.criteria = snapshot.criteria;\n if (snapshot.caseSensitive !== undefined) expression.caseSensitive = snapshot.caseSensitive;\n expressions.push(expression 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 * Index mode builds one position map per call, so it is linear in the sizes\n * of `rows` and `universe` rather than their product.\n */\nexport function serializeRowRefs<T extends object>(\n rows: ReadonlyArray<T>,\n universe: ReadonlyArray<T>,\n rowId?: (row: T) => string | number\n): RowRef[] {\n if (rowId) return rows.map((row) => ({ id: rowId(row) }));\n if (rows.length < 2) {\n // A single lookup is cheaper than building the map.\n const index = rows.length ? universe.indexOf(rows[0]) : -1;\n return index === -1 ? [] : [{ index }];\n }\n const positions = new Map<T, number>();\n universe.forEach((row, index) => {\n if (!positions.has(row)) positions.set(row, index);\n });\n const refs: RowRef[] = [];\n for (const row of rows) {\n const index = positions.get(row);\n if (index !== undefined) refs.push({ index });\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 and must be non-negative integers. Refs that are not objects,\n * and 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 (typeof ref !== 'object' || ref === null) continue;\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 if (Number.isInteger(ref.index) && ref.index >= 0) {\n const row = universe[ref.index];\n if (row) out.push(row);\n }\n }\n return out;\n}\n"]}
|
package/internal/types.d.ts
CHANGED
|
@@ -404,9 +404,18 @@ export interface ColumnGroupConfiguration {
|
|
|
404
404
|
export interface ValidatorContext<T extends object, K extends Keys<T> = Keys<T>> {
|
|
405
405
|
/** The column configuration the value is being validated against. */
|
|
406
406
|
column: ColumnConfiguration<T, K>;
|
|
407
|
-
/**
|
|
407
|
+
/**
|
|
408
|
+
* The full data record being edited (a live reference). In a row-mode
|
|
409
|
+
* commit it is the staged row instead: a copy of the record (same
|
|
410
|
+
* prototype) with the row's staged values applied, so cross-field rules
|
|
411
|
+
* see the row being saved. A validator that throws on the copy (one that
|
|
412
|
+
* reads private class fields, say) is run again with the live record.
|
|
413
|
+
*/
|
|
408
414
|
data: T;
|
|
409
|
-
/**
|
|
415
|
+
/**
|
|
416
|
+
* The view-relative row index of the edited cell (`-1` for a pinned row or
|
|
417
|
+
* a record on another page).
|
|
418
|
+
*/
|
|
410
419
|
rowIndex: number;
|
|
411
420
|
}
|
|
412
421
|
/**
|
|
@@ -627,6 +636,12 @@ export interface GridExpansionConfiguration<T extends object> {
|
|
|
627
636
|
* custom cell template.
|
|
628
637
|
*/
|
|
629
638
|
showToggleColumn?: boolean;
|
|
639
|
+
/**
|
|
640
|
+
* Parts used inside the `detailTemplate` content to re-export, so
|
|
641
|
+
* `apex-grid::part(name)` can style them from outside the grid. The panel
|
|
642
|
+
* itself is always reachable as `detail-panel`.
|
|
643
|
+
*/
|
|
644
|
+
exportParts?: ReadonlyArray<string>;
|
|
630
645
|
}
|
|
631
646
|
/**
|
|
632
647
|
* Undo / redo history configuration for cell-data edits.
|
package/internal/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/internal/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ReactiveControllerHost, TemplateResult } from 'lit';\nimport type ApexGridCell from '../components/cell.js';\nimport type { ApexGrid } from '../components/grid.js';\nimport type ApexGridHeader from '../components/header.js';\nimport type ApexGridRow from '../components/row.js';\nimport type { SortComparer } from '../operations/sort/types.js';\n\nexport type NavigationState = 'previous' | 'current';\nexport type GridHost<T extends object> = ReactiveControllerHost & ApexGrid<T>;\n\n/**\n * A custom action button contributed to the toolbar's trailing actions area.\n *\n * @remarks\n * The seam derived grids use to add toolbar buttons, mirroring the export-format\n * seam: the community grid contributes none (its {@link ApexGrid.toolbarActions}\n * returns `[]`), and the toolbar renders one button per entry, invoking\n * {@link ToolbarAction.run} on click.\n */\nexport interface ToolbarAction {\n /** Stable identifier, e.g. `'create-chart'`. */\n id: string;\n /** Button label. */\n label: string;\n /** Invoked when the button is clicked. */\n run(): void;\n}\n\n/**\n * Helper type for resolving keys of type T.\n */\nexport type Keys<T> = keyof T;\n\n/**\n * Helper type for resolving types of type T.\n */\nexport type BasePropertyType<T, K extends Keys<T> = Keys<T>> = T[K];\n\n/**\n * Helper type for resolving types of type T.\n */\nexport type PropertyType<T, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BasePropertyType<T, K> : never;\n\n/**\n * The data type — or, for the declarative built-ins (`'select'`, `'rating'`,\n * `'date'`, `'image'`), the presentation type — for the current column.\n *\n * @remarks\n * - `'string'` / `'number'` are the primitive data types. They drive the\n * default filter operands, the default editor, and the default sort\n * comparison.\n * - `'boolean'` stores `true` / `false`. In display mode the grid renders\n * a check-mark icon for `true` and a dimmed mark for `false`. In edit\n * mode the default editor is a native checkbox.\n * - `'select'` is a presentation type for columns that store one of a fixed\n * set of values. Supply the available options via\n * {@link BaseColumnConfiguration.options}. The cell renders the matching\n * option's label in display mode and a native `<select>` in edit mode.\n * For sorting / filtering, select columns behave as their underlying\n * value type (typically string).\n * - `'rating'` renders a numeric value (0..`max`) as filled stars in display\n * mode and as an interactive star picker in edit mode. Configure the star\n * count via {@link BaseColumnConfiguration.max} (defaults to `5`).\n * For sorting / filtering, rating columns behave as numbers.\n * - `'date'` renders values as locale-aware formatted dates in display mode\n * and a native `<input type=\"date\">` in edit mode. Accepts `Date`\n * instances, ISO strings, or millisecond timestamps as input and commits\n * back in the same shape. Configure the display format via\n * {@link BaseColumnConfiguration.format} (`'short' | 'medium' | 'long' |\n * 'full'`, default `'medium'`).\n * - `'image'` renders the value as an `<img>` source. Use\n * {@link BaseColumnConfiguration.shape} to pick between `'square'`\n * (default) and `'circle'`. The cell's default text editor is used for\n * editing the URL string when `editable: true` is set.\n *\n * The remaining types are premium presentation renderers over primitive\n * values; for sorting / filtering they behave as their underlying value type:\n * - `'currency'` formats a number via `Intl.NumberFormat` (tabular, right\n * aligned). Configure with {@link BaseColumnConfiguration.currency} /\n * {@link BaseColumnConfiguration.locale}. Editable via a number input.\n * - `'avatar'` renders the value's first letter in a tinted circle (hue is\n * derived from the value, stable per row).\n * - `'badge'` renders the value as a colored pill. Pick the look with\n * {@link BaseColumnConfiguration.badgeVariant}.\n * - `'progress'` renders a number (0..`max`, default `max` 100) as a health\n * bar; the fill color tiers at ≥80 / ≥65 / below.\n * - `'sparkline'` renders a `number[]` as an inline trend chart with an\n * optional delta label ({@link BaseColumnConfiguration.showDelta}).\n * - `'status'` renders a pill with a leading dot. The state is taken from\n * {@link BaseColumnConfiguration.statusVariant} or inferred from the value.\n */\nexport type DataType =\n | 'number'\n | 'string'\n | 'boolean'\n | 'select'\n | 'rating'\n | 'date'\n | 'image'\n | 'currency'\n | 'avatar'\n | 'badge'\n | 'progress'\n | 'sparkline'\n | 'status';\n\n/** Visual variant for a `type: 'badge'` pill. */\nexport type BadgeVariant = 'gold' | 'brand' | 'neutral' | 'muted';\n\n/** State for a `type: 'status'` badge. */\nexport type StatusVariant = 'active' | 'trial' | 'churn';\n\n/**\n * Display format presets for `'date'` columns. Map to\n * `Intl.DateTimeFormatOptions.dateStyle`.\n */\nexport type ColumnDateFormat = 'short' | 'medium' | 'long' | 'full';\n\n/**\n * An entry in a `'select'` column's `options` list. Bare values use\n * `String(value)` as their display label; the explicit form lets you give\n * a value a separate display label.\n */\nexport type ColumnSelectOption<V = unknown> = V | { value: V; label?: string };\n\n/**\n * Configures the sort behavior for the grid.\n */\nexport interface GridSortConfiguration {\n /**\n * Whether multiple sorting is enabled.\n */\n multiple: boolean;\n /**\n * Whether tri-state sorting is enabled.\n */\n triState: boolean;\n}\n\n/**\n * Extended sort configuration for a column.\n */\nexport interface BaseColumnSortConfiguration<T, K extends Keys<T> = Keys<T>> {\n /**\n * Whether the sort operations will be case sensitive.\n */\n caseSensitive?: boolean;\n /**\n * Custom comparer function for sort operations for this column.\n */\n comparer?: SortComparer<T, K>;\n}\n\n/**\n * See {@link BaseColumnSortConfiguration} for the full documentation.\n */\nexport type ColumnSortConfiguration<T, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseColumnSortConfiguration<T, K> : never;\n\n/**\n * Extended filter configuration for a column.\n */\nexport interface ColumnFilterConfiguration {\n /**\n * Whether the filter operations will be case sensitive.\n */\n caseSensitive?: boolean;\n}\n\n/**\n * Pin position for a column.\n *\n * @remarks\n * `'start'` pins the column to the leading edge of the grid (inline-start);\n * `'end'` pins it to the trailing edge. `null` or `undefined` means the column\n * is part of the scrollable region.\n */\nexport type PinPosition = 'start' | 'end' | null;\n\n/** Configuration object for grid columns. */\nexport interface BaseColumnConfiguration<T extends object, K extends Keys<T> = Keys<T>> {\n /**\n * The field for from the data the this column will reference.\n */\n key: K;\n /**\n * The type of data this column will reference.\n *\n * Affects the default filter operands if the column is with filtering enabled.\n *\n * @remarks\n * If not passed, `string` is assumed to be the default type.\n *\n */\n type?: DataType;\n /**\n * Optional text to display in the column header. By default, the column key is used\n * to render the header text.\n */\n headerText?: string;\n /**\n * Width for the current column.\n *\n * Accepts most CSS units for controlling width.\n *\n * @remarks\n * If not passed, the column will try to size itself based on the number of other\n * columns and the total width of the grid.\n *\n */\n width?: string;\n /**\n * Whether the column is hidden or not.\n */\n hidden?: boolean;\n /**\n * Whether this column is included when exporting via\n * {@link ApexGrid.exportToCSV} (or the enterprise grid's XLSX export).\n *\n * @remarks\n * Defaults to `true`. Set to `false` to omit a column from generated files\n * (useful for action columns, derived UI, or sensitive fields). The\n * grid-rendered selection checkbox column is never exported regardless of\n * this flag.\n */\n exportable?: boolean;\n /**\n * Pin the column to a side of the grid.\n *\n * @remarks\n * Pinned columns stay fixed during horizontal scroll. Use `'start'` (left in LTR,\n * right in RTL) for the leading edge or `'end'` for the trailing edge. The grid\n * renders columns in the order: `'start'`-pinned, unpinned, `'end'`-pinned, while\n * preserving the original array order inside each group. The `columns` array\n * itself is not mutated.\n */\n pinned?: PinPosition;\n /**\n * Whether this column can be reordered via drag-and-drop or the\n * {@link ApexGrid.moveColumn} API.\n *\n * @remarks\n * Has no effect unless the grid's `columnReordering` flag is `true`. When\n * unset, columns inherit the grid-wide flag. Reordering is constrained to the\n * column's own pinning group — start-pinned columns can only swap with other\n * start-pinned columns, and likewise for end-pinned and unpinned.\n */\n reorderable?: boolean;\n /**\n * Whether the the column can be resized or not.\n */\n resizable?: boolean;\n /**\n * Whether the column can be sorted or not.\n */\n sort?: ColumnSortConfiguration<T, K> | boolean;\n /**\n * Whether filter operation can be applied on the column or not.\n */\n filter?: ColumnFilterConfiguration | boolean;\n /**\n * Header template callback.\n */\n headerTemplate?: (params: ApexHeaderContext<T>) => TemplateResult | unknown;\n /**\n * The id of the {@link ColumnGroupConfiguration} this column belongs to.\n *\n * @remarks\n * Columns sharing a `group` id render under a single spanning header cell in\n * the group header row. Members must be **contiguous within one pin region**\n * (the grid warns and skips the spanning cell otherwise). Has no effect unless\n * {@link ApexGrid.columnGroups} defines a matching group.\n */\n group?: string;\n /**\n * Cell template callback.\n */\n cellTemplate?: (params: ApexCellContext<T, K>) => TemplateResult | unknown;\n /**\n * Whether values in this column can be edited inline.\n *\n * @remarks\n * Has no effect unless the grid's `editing.enabled` is `true`. The default\n * editor is chosen from the column's `type` (`'string'` → text input,\n * `'number'` → number input, `'boolean'` → checkbox). Supply\n * {@link BaseColumnConfiguration.editorTemplate} for full control.\n */\n editable?: boolean;\n /**\n * Custom editor template invoked while this column's cell is in edit mode.\n *\n * @remarks\n * The callback receives an {@link ApexEditorContext} that includes the cell\n * value plus `commit` / `cancel` helpers. Returning a focusable element is\n * recommended so keyboard handoff works.\n */\n editorTemplate?: (params: ApexEditorContext<T, K>) => TemplateResult | unknown;\n /**\n * Allows cells in this column to hold spreadsheet-style formulas.\n *\n * @remarks\n * An enterprise feature: the free core only carries this flag. With the\n * enterprise formula module active and the column also\n * {@link BaseColumnConfiguration.editable}, a cell whose edited text starts\n * with `=` is parsed, stored as a formula, and its computed result becomes the\n * cell value (so sorting, filtering, and aggregation keep working on the\n * value). Has no effect without that module. Default `false`.\n */\n allowFormula?: boolean;\n /**\n * Declarative validators run before a candidate value is written to this\n * column's cells.\n *\n * @remarks\n * Each validator receives the candidate value and a {@link ValidatorContext}\n * and returns an error message string (the cell is rejected) or `null` (it\n * passes). All validators run and every message is collected, so a single\n * failed commit can surface multiple errors. A failing commit keeps the\n * inline editor open, marks the cell `aria-invalid`, and emits\n * `cellValidationFailed`. Validation also covers bulk edits (paste / fill).\n * Use the built-in factories ({@link required}, {@link min}, {@link max},\n * {@link pattern}, {@link custom}) or supply your own function.\n */\n validators?: Validator<T, K>[];\n /**\n * Option list for columns with `type: 'select'`.\n *\n * @remarks\n * Each entry is either a bare value or an explicit `{ value, label }` pair.\n * The cell renders the matching option's `label` in display mode and a\n * native `<select>` of all options in edit mode. Has no effect on columns\n * with another `type`.\n */\n options?: ColumnSelectOption<BasePropertyType<T, K>>[];\n /**\n * Upper bound for `type: 'rating'` and `type: 'progress'`.\n *\n * @remarks\n * For `'rating'` this is the star count (default `5`); the displayed value is\n * clamped to `[0, max]`. For `'progress'` this is the value that fills the bar\n * to 100% (default `100`). Has no effect on columns with another `type`.\n */\n max?: number;\n /**\n * Display format for columns with `type: 'date'`.\n *\n * @remarks\n * Selects an `Intl.DateTimeFormatOptions.dateStyle` preset. Defaults to\n * `'medium'`. Has no effect on columns with another `type`.\n */\n format?: ColumnDateFormat;\n /**\n * Cropping shape for columns with `type: 'image'`.\n *\n * @remarks\n * `'square'` (default) renders the image at its native aspect. `'circle'`\n * crops to a circle (useful for avatars). Has no effect on columns with\n * another `type`.\n */\n shape?: 'square' | 'circle';\n /**\n * Alt text for `<img>` elements rendered by `type: 'image'` columns.\n *\n * @remarks\n * Defaults to the column key. Has no effect on columns with another\n * `type`.\n */\n alt?: string;\n /**\n * ISO 4217 currency code for `type: 'currency'` columns (e.g. `'USD'`,\n * `'EUR'`). Defaults to `'USD'`. Has no effect on columns with another\n * `type`.\n */\n currency?: string;\n /**\n * BCP 47 locale for `type: 'currency'` number formatting. Defaults to the\n * runtime locale. Has no effect on columns with another `type`.\n */\n locale?: string;\n /**\n * Visual variant for `type: 'badge'` columns. A literal applies to every\n * cell; a callback picks per value. Defaults to `'neutral'`. Has no effect\n * on columns with another `type`.\n */\n badgeVariant?: BadgeVariant | ((value: BasePropertyType<T, K>) => BadgeVariant);\n /**\n * State for `type: 'status'` columns. A literal applies to every cell; a\n * callback maps a value to a state. When omitted the state is inferred from\n * the value text. Has no effect on columns with another `type`.\n */\n statusVariant?: StatusVariant | ((value: BasePropertyType<T, K>) => StatusVariant);\n /**\n * Whether `type: 'sparkline'` columns render a trailing delta-% label.\n * Defaults to `true`. Has no effect on columns with another `type`.\n */\n showDelta?: boolean;\n}\n\n/**\n * See {@link BaseColumnConfiguration} for the full documentation.\n */\nexport type ColumnConfiguration<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseColumnConfiguration<T, K> : never;\n\n/**\n * Context passed to a {@link ColumnGroupConfiguration.headerTemplate}.\n */\nexport interface ApexColumnGroupContext {\n /** The group configuration being rendered. */\n group: ColumnGroupConfiguration;\n /** Number of (visible) member columns the group spans. */\n span: number;\n}\n\n/**\n * Configuration for a spanning group header over a contiguous run of columns\n * (see {@link BaseColumnConfiguration.group}).\n */\nexport interface ColumnGroupConfiguration {\n /** Unique group id, referenced by a column's {@link BaseColumnConfiguration.group}. */\n id: string;\n /** Text rendered in the spanning group header cell. */\n headerText: string;\n /**\n * Reserved for a future collapse affordance. Inert in v1 (static spanning\n * headers only).\n */\n collapsible?: boolean;\n /** Custom template for the group header cell, overriding `headerText`. */\n headerTemplate?: (context: ApexColumnGroupContext) => TemplateResult | unknown;\n}\n\n/**\n * Context passed to a {@link Validator} alongside the candidate value.\n */\nexport interface ValidatorContext<T extends object, K extends Keys<T> = Keys<T>> {\n /** The column configuration the value is being validated against. */\n column: ColumnConfiguration<T, K>;\n /** The full data record being edited (a live reference). */\n data: T;\n /** The view-relative row index of the edited cell. */\n rowIndex: number;\n}\n\n/**\n * A single declarative validation rule for a column.\n *\n * @returns An error message string when the value is invalid, or `null` when\n * it passes.\n */\nexport type Validator<T extends object, K extends Keys<T> = Keys<T>> = (\n value: unknown,\n context: ValidatorContext<T, K>\n) => string | null;\n\nexport interface ActiveNode<T> {\n column: Keys<T>;\n row: number;\n}\n\n/**\n * Context object for the column header template callback.\n */\nexport interface ApexHeaderContext<T extends object> {\n /**\n * The header element parent of the template.\n */\n parent: ApexGridHeader<T>;\n /**\n * The current configuration for the column.\n */\n column: ColumnConfiguration<T>;\n}\n\n/**\n * Context object for the row cell template callback.\n */\nexport interface BaseApexCellContext<T extends object, K extends Keys<T> = Keys<T>> {\n /**\n * The cell element parent of the template.\n */\n parent: ApexGridCell<T>;\n /**\n * The row element containing the cell.\n */\n row: ApexGridRow<T>;\n /**\n * The current configuration for the column.\n */\n column: ColumnConfiguration<T, K>;\n /**\n * The value from the data source for this cell.\n */\n value: PropertyType<T, K>;\n /**\n * Commits a new value for this cell without entering edit mode. Available\n * when the column is editable. Used by interactive display widgets\n * (e.g. the built-in boolean checkbox) so they can toggle inline.\n *\n * Goes through the cancellable `cellValueChanging` event and follow-up\n * `cellValueChanged` event — same write path as an edit-mode commit.\n */\n commit?: (value: PropertyType<T, K>) => Promise<boolean>;\n}\n\n/**\n * See {@link BaseApexCellContext} for the full documentation.\n */\nexport type ApexCellContext<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseApexCellContext<T, K> : never;\n\n/**\n * Context object handed to a custom editor template.\n *\n * @remarks\n * Includes the cell's current `value` plus `commit` / `cancel` callbacks so\n * the editor can hand its result back to the grid. The custom editor is also\n * responsible for forwarding `Enter` / `Escape` to those callbacks.\n */\nexport interface BaseApexEditorContext<T extends object, K extends Keys<T> = Keys<T>>\n extends BaseApexCellContext<T, K> {\n /**\n * Commits `value` as the new cell value, going through the cancellable\n * `cellValueChanging` event and then `cellValueChanged`.\n *\n * @returns `true` if the value was applied, `false` if cancelled.\n */\n commit: (value: PropertyType<T, K>) => Promise<boolean>;\n /**\n * Discards the in-progress edit and exits edit mode.\n */\n cancel: () => void;\n}\n\n/**\n * See {@link BaseApexEditorContext} for the full documentation.\n */\nexport type ApexEditorContext<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseApexEditorContext<T, K> : never;\n\n/**\n * The edit trigger used to enter cell edit mode.\n *\n * @remarks\n * `'click'` enters edit on a single click on the cell; `'doubleClick'`\n * requires a double click. Defaults to `'doubleClick'`.\n */\nexport type EditTrigger = 'click' | 'doubleClick';\n\n/**\n * Edit mode for the grid.\n *\n * @remarks\n * `'cell'` — each cell is committed independently on blur or `Enter`.\n * `'row'` — all editable cells in the row enter edit mode together; changes\n * are batched and applied via {@link ApexGrid.commitEdit} or rolled back via\n * {@link ApexGrid.cancelEdit}.\n */\nexport type EditMode = 'cell' | 'row';\n\n/**\n * Selection mode for the grid.\n *\n * @remarks\n * `'single'` — at most one row may be selected at any time. New clicks\n * replace the existing selection.\n * `'multiple'` — multiple rows can be selected. Plain clicks replace the\n * selection, Ctrl/Cmd+click toggles a row additively, and Shift+click\n * selects a range from the previous anchor.\n */\nexport type SelectionMode = 'single' | 'multiple';\n\n/**\n * Grid-level row-selection configuration.\n */\nexport interface GridSelectionConfiguration {\n /**\n * Whether row selection is enabled. Disabled by default.\n */\n enabled?: boolean;\n /**\n * Single-row vs multi-row selection. Defaults to `'multiple'`.\n */\n mode?: SelectionMode;\n /**\n * Whether to render the built-in checkbox column at the start of every\n * row. When `false`, selection is still available via the public API\n * (`selectRow`, `selectedRows = ...`) and via Space on the active row.\n * Defaults to `false`.\n */\n showCheckboxColumn?: boolean;\n}\n\n/**\n * Context passed to {@link GridExpansionConfiguration.detailTemplate}.\n */\nexport interface ApexDetailContext<T extends object> {\n /** The row data for the expanded row. */\n data: T;\n /** The view-relative row index of the master row. */\n rowIndex: number;\n /** The grid element. Useful for emitting events back from the detail. */\n parent: ApexGrid<T>;\n}\n\n/**\n * Grid-level tree-data (nested rows) configuration.\n *\n * @remarks\n * Tree mode renders hierarchical data as nested rows that share the same\n * column layout — collapsible parents with indented children, the\n * flat-array \"tree data\" pattern. The data array stays flat; the grid derives the\n * hierarchy from {@link getDataPath} at runtime.\n *\n * This is distinct from {@link GridExpansionConfiguration} (master-detail),\n * which expands a row to show an arbitrary detail panel. Tree mode and\n * expansion mode can be enabled together, but the chevron column is\n * reserved by whichever is currently rendering the chevron — typically the\n * tree feature when both are enabled.\n *\n * @example\n * ```ts\n * grid.tree = {\n * enabled: true,\n * getDataPath: (row) => row.path,\n * };\n * ```\n */\nexport interface GridTreeConfiguration<T extends object> {\n /** Whether tree mode is enabled. Disabled by default. */\n enabled?: boolean;\n /**\n * Callback that returns the hierarchical path for a row. The path is a\n * sequence of segments from root to the row's own position — for example\n * `['Adrian']` for a CEO, `['Adrian', 'Bryan']` for a VP under Adrian,\n * and so on. Required when `enabled` is `true`.\n */\n getDataPath: (row: T) => readonly string[];\n /**\n * Which column displays the chevron + indentation. Defaults to the first\n * visible non-hidden data column.\n */\n groupColumnKey?: Keys<T>;\n /**\n * Initial expansion state:\n * - `false` (default): all rows collapsed.\n * - `true`: every row expanded.\n * - `number`: expand all rows up to and including the given depth (0 = roots only).\n */\n defaultExpanded?: boolean | number;\n /**\n * Pixels of indentation per depth level. Defaults to `20`.\n */\n childIndent?: number;\n}\n\n/**\n * Grid-level row-expansion (master-detail) configuration.\n */\nexport interface GridExpansionConfiguration<T extends object> {\n /**\n * Whether row expansion is enabled. Disabled by default.\n */\n enabled?: boolean;\n /**\n * Callback that produces the detail panel content for an expanded row.\n * Required when `enabled` is `true`.\n */\n detailTemplate?: (context: ApexDetailContext<T>) => TemplateResult | unknown;\n /**\n * Optional per-row predicate that gates which rows may be expanded. When\n * omitted, every row is expandable.\n */\n isExpandable?: (row: T) => boolean;\n /**\n * Whether to render the built-in chevron toggle column at the start of\n * every row (after the selection column, when present). Defaults to `true`.\n * Set to `false` to drive expansion entirely through the public API or a\n * custom cell template.\n */\n showToggleColumn?: boolean;\n}\n\n/**\n * Undo / redo history configuration for cell-data edits.\n */\nexport interface EditingHistoryConfiguration {\n /**\n * Whether undo / redo tracking is enabled. When `true`, every committed cell\n * edit (single, row-mode, and bulk paste / fill) is recorded and can be\n * reversed via {@link ApexGrid.undo} / {@link ApexGrid.redo} or the keyboard\n * (Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y).\n */\n enabled: boolean;\n /**\n * Maximum number of commands retained on the undo stack. Older commands are\n * evicted once the cap is exceeded. Defaults to `100`.\n */\n stackSize?: number;\n}\n\n/**\n * Grid-level row-pinning configuration.\n */\nexport interface GridRowPinningConfiguration {\n /**\n * Whether rows can be pinned to a sticky top / bottom band via\n * {@link ApexGrid.pinRow}. Disabled when omitted.\n */\n enabled: boolean;\n}\n\n/**\n * Grid-level row-reordering configuration.\n */\nexport interface GridRowReorderingConfiguration {\n /**\n * Whether rows can be reordered by drag, keyboard, or {@link ApexGrid.moveRow}.\n * A manual order, once set, is mutually exclusive with column sorting\n * (applying a sort clears it). Disabled when omitted.\n */\n enabled: boolean;\n /**\n * When `true`, a reorder also splices {@link ApexGrid.data} in place so the\n * source array reflects the new order. Defaults to `false`: the order lives in\n * the grid and the app persists it via the `rowMoved` event.\n */\n applyToData?: boolean;\n /**\n * Controls how a pointer drag is initiated.\n *\n * - `true` (default): a dedicated drag-handle (grip) cell is rendered at the\n * start of every reorderable row, and a drag only begins from that handle.\n * The rest of the row stays free for selection / editing.\n * - `false`: no handle is rendered and a drag begins by pressing anywhere on\n * the row (excluding interactive sub-parts like inputs and buttons).\n *\n * Either way the dragged row is shown as a floating ghost that follows the\n * cursor, and the keyboard reorder flow (grab with Space, move with arrows) is\n * unchanged.\n */\n handle?: boolean;\n}\n\n/**\n * Grid-level editing configuration.\n */\nexport interface GridEditingConfiguration {\n /**\n * Whether editing is enabled. Per-column opt-in still applies via\n * {@link BaseColumnConfiguration.editable}.\n */\n enabled?: boolean;\n /**\n * Whether each cell commits independently or whether the whole row is edited\n * as a batch. Defaults to `'cell'`.\n */\n mode?: EditMode;\n /**\n * The interaction that opens an editor. Defaults to `'doubleClick'`.\n */\n trigger?: EditTrigger;\n /**\n * Undo / redo history for cell-data edits. Disabled when omitted.\n */\n history?: EditingHistoryConfiguration;\n}\n\n/**\n * The parameters passed to a {@link DataPipelineHook} callback.\n */\nexport type DataPipelineParams<T extends object> = {\n /**\n * The current data state of the grid.\n */\n data: T[];\n /**\n * The grid component itself.\n */\n grid: ApexGrid<T>;\n /**\n * The type of data operation being performed.\n */\n type: 'sort' | 'filter' | 'quickFilter' | 'pagination';\n};\n\n/**\n * Callback function for customizing data operations in the grid.\n */\nexport type DataPipelineHook<T extends object> = (\n state: DataPipelineParams<T>\n) => T[] | Promise<T[]>;\n\n/**\n * Configuration for customizing the various data operations of the grid.\n */\nexport interface DataPipelineConfiguration<T extends object> {\n /**\n * Hook for customizing sort operations.\n */\n sort?: DataPipelineHook<T>;\n /**\n * Hook for customizing filter operations.\n */\n filter?: DataPipelineHook<T>;\n /**\n * Hook for customizing pagination operations.\n *\n * @remarks\n * The hook receives the filtered + sorted data slice for the grid to render and the current\n * pagination state. Return the page slice. For server-driven pagination, return the externally\n * fetched page and report the row total via {@link ApexGrid.totalItems}.\n */\n pagination?: DataPipelineHook<T>;\n /**\n * Hook for customizing quick (global) filter operations.\n *\n * @remarks\n * Called before column filtering. Return the records that match the {@link ApexGrid.quickFilter}\n * value. If omitted, the default substring matcher is used.\n */\n quickFilter?: DataPipelineHook<T>;\n}\n\n/**\n * The pagination mode for the grid.\n *\n * @remarks\n * `'local'` — the grid slices the in-memory {@link ApexGrid.dataView} by `page` and `pageSize`.\n * `'remote'` — the consumer drives data fetching; the grid emits paging events but does not\n * slice the data. Use together with {@link DataPipelineConfiguration.pagination} or by setting\n * `data` to the current page on `pageChanged`.\n */\nexport type PaginationMode = 'local' | 'remote';\n\n/**\n * Pagination configuration for the grid.\n */\nexport interface PaginationConfiguration {\n /**\n * Whether pagination is enabled.\n *\n * @remarks\n * When `false`, the grid renders no paginator and applies no slicing — the full\n * {@link ApexGrid.dataView} is virtualized as usual.\n */\n enabled?: boolean;\n /**\n * The pagination mode. Defaults to `'local'`.\n */\n mode?: PaginationMode;\n /**\n * The current page (zero-based). Defaults to `0`.\n */\n page?: number;\n /**\n * The number of records per page. Defaults to `25`.\n */\n pageSize?: number;\n /**\n * The list of page sizes offered in the paginator's page-size dropdown.\n * Defaults to `[10, 25, 50, 100]`.\n */\n pageSizeOptions?: number[];\n /**\n * In `'remote'` mode the consumer must supply the unfiltered row total so the paginator\n * can compute the page count. Ignored in `'local'` mode.\n */\n totalItems?: number;\n}\n\n/**\n * Resolved pagination state passed to controllers and event payloads.\n */\nexport interface PaginationState {\n /**\n * The current page (zero-based).\n */\n page: number;\n /**\n * The number of records per page.\n */\n pageSize: number;\n /**\n * The total number of pages.\n */\n pageCount: number;\n /**\n * The total number of records before pagination (after filter/sort).\n */\n totalItems: number;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/internal/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ReactiveControllerHost, TemplateResult } from 'lit';\nimport type ApexGridCell from '../components/cell.js';\nimport type { ApexGrid } from '../components/grid.js';\nimport type ApexGridHeader from '../components/header.js';\nimport type ApexGridRow from '../components/row.js';\nimport type { SortComparer } from '../operations/sort/types.js';\n\nexport type NavigationState = 'previous' | 'current';\nexport type GridHost<T extends object> = ReactiveControllerHost & ApexGrid<T>;\n\n/**\n * A custom action button contributed to the toolbar's trailing actions area.\n *\n * @remarks\n * The seam derived grids use to add toolbar buttons, mirroring the export-format\n * seam: the community grid contributes none (its {@link ApexGrid.toolbarActions}\n * returns `[]`), and the toolbar renders one button per entry, invoking\n * {@link ToolbarAction.run} on click.\n */\nexport interface ToolbarAction {\n /** Stable identifier, e.g. `'create-chart'`. */\n id: string;\n /** Button label. */\n label: string;\n /** Invoked when the button is clicked. */\n run(): void;\n}\n\n/**\n * Helper type for resolving keys of type T.\n */\nexport type Keys<T> = keyof T;\n\n/**\n * Helper type for resolving types of type T.\n */\nexport type BasePropertyType<T, K extends Keys<T> = Keys<T>> = T[K];\n\n/**\n * Helper type for resolving types of type T.\n */\nexport type PropertyType<T, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BasePropertyType<T, K> : never;\n\n/**\n * The data type — or, for the declarative built-ins (`'select'`, `'rating'`,\n * `'date'`, `'image'`), the presentation type — for the current column.\n *\n * @remarks\n * - `'string'` / `'number'` are the primitive data types. They drive the\n * default filter operands, the default editor, and the default sort\n * comparison.\n * - `'boolean'` stores `true` / `false`. In display mode the grid renders\n * a check-mark icon for `true` and a dimmed mark for `false`. In edit\n * mode the default editor is a native checkbox.\n * - `'select'` is a presentation type for columns that store one of a fixed\n * set of values. Supply the available options via\n * {@link BaseColumnConfiguration.options}. The cell renders the matching\n * option's label in display mode and a native `<select>` in edit mode.\n * For sorting / filtering, select columns behave as their underlying\n * value type (typically string).\n * - `'rating'` renders a numeric value (0..`max`) as filled stars in display\n * mode and as an interactive star picker in edit mode. Configure the star\n * count via {@link BaseColumnConfiguration.max} (defaults to `5`).\n * For sorting / filtering, rating columns behave as numbers.\n * - `'date'` renders values as locale-aware formatted dates in display mode\n * and a native `<input type=\"date\">` in edit mode. Accepts `Date`\n * instances, ISO strings, or millisecond timestamps as input and commits\n * back in the same shape. Configure the display format via\n * {@link BaseColumnConfiguration.format} (`'short' | 'medium' | 'long' |\n * 'full'`, default `'medium'`).\n * - `'image'` renders the value as an `<img>` source. Use\n * {@link BaseColumnConfiguration.shape} to pick between `'square'`\n * (default) and `'circle'`. The cell's default text editor is used for\n * editing the URL string when `editable: true` is set.\n *\n * The remaining types are premium presentation renderers over primitive\n * values; for sorting / filtering they behave as their underlying value type:\n * - `'currency'` formats a number via `Intl.NumberFormat` (tabular, right\n * aligned). Configure with {@link BaseColumnConfiguration.currency} /\n * {@link BaseColumnConfiguration.locale}. Editable via a number input.\n * - `'avatar'` renders the value's first letter in a tinted circle (hue is\n * derived from the value, stable per row).\n * - `'badge'` renders the value as a colored pill. Pick the look with\n * {@link BaseColumnConfiguration.badgeVariant}.\n * - `'progress'` renders a number (0..`max`, default `max` 100) as a health\n * bar; the fill color tiers at ≥80 / ≥65 / below.\n * - `'sparkline'` renders a `number[]` as an inline trend chart with an\n * optional delta label ({@link BaseColumnConfiguration.showDelta}).\n * - `'status'` renders a pill with a leading dot. The state is taken from\n * {@link BaseColumnConfiguration.statusVariant} or inferred from the value.\n */\nexport type DataType =\n | 'number'\n | 'string'\n | 'boolean'\n | 'select'\n | 'rating'\n | 'date'\n | 'image'\n | 'currency'\n | 'avatar'\n | 'badge'\n | 'progress'\n | 'sparkline'\n | 'status';\n\n/** Visual variant for a `type: 'badge'` pill. */\nexport type BadgeVariant = 'gold' | 'brand' | 'neutral' | 'muted';\n\n/** State for a `type: 'status'` badge. */\nexport type StatusVariant = 'active' | 'trial' | 'churn';\n\n/**\n * Display format presets for `'date'` columns. Map to\n * `Intl.DateTimeFormatOptions.dateStyle`.\n */\nexport type ColumnDateFormat = 'short' | 'medium' | 'long' | 'full';\n\n/**\n * An entry in a `'select'` column's `options` list. Bare values use\n * `String(value)` as their display label; the explicit form lets you give\n * a value a separate display label.\n */\nexport type ColumnSelectOption<V = unknown> = V | { value: V; label?: string };\n\n/**\n * Configures the sort behavior for the grid.\n */\nexport interface GridSortConfiguration {\n /**\n * Whether multiple sorting is enabled.\n */\n multiple: boolean;\n /**\n * Whether tri-state sorting is enabled.\n */\n triState: boolean;\n}\n\n/**\n * Extended sort configuration for a column.\n */\nexport interface BaseColumnSortConfiguration<T, K extends Keys<T> = Keys<T>> {\n /**\n * Whether the sort operations will be case sensitive.\n */\n caseSensitive?: boolean;\n /**\n * Custom comparer function for sort operations for this column.\n */\n comparer?: SortComparer<T, K>;\n}\n\n/**\n * See {@link BaseColumnSortConfiguration} for the full documentation.\n */\nexport type ColumnSortConfiguration<T, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseColumnSortConfiguration<T, K> : never;\n\n/**\n * Extended filter configuration for a column.\n */\nexport interface ColumnFilterConfiguration {\n /**\n * Whether the filter operations will be case sensitive.\n */\n caseSensitive?: boolean;\n}\n\n/**\n * Pin position for a column.\n *\n * @remarks\n * `'start'` pins the column to the leading edge of the grid (inline-start);\n * `'end'` pins it to the trailing edge. `null` or `undefined` means the column\n * is part of the scrollable region.\n */\nexport type PinPosition = 'start' | 'end' | null;\n\n/** Configuration object for grid columns. */\nexport interface BaseColumnConfiguration<T extends object, K extends Keys<T> = Keys<T>> {\n /**\n * The field for from the data the this column will reference.\n */\n key: K;\n /**\n * The type of data this column will reference.\n *\n * Affects the default filter operands if the column is with filtering enabled.\n *\n * @remarks\n * If not passed, `string` is assumed to be the default type.\n *\n */\n type?: DataType;\n /**\n * Optional text to display in the column header. By default, the column key is used\n * to render the header text.\n */\n headerText?: string;\n /**\n * Width for the current column.\n *\n * Accepts most CSS units for controlling width.\n *\n * @remarks\n * If not passed, the column will try to size itself based on the number of other\n * columns and the total width of the grid.\n *\n */\n width?: string;\n /**\n * Whether the column is hidden or not.\n */\n hidden?: boolean;\n /**\n * Whether this column is included when exporting via\n * {@link ApexGrid.exportToCSV} (or the enterprise grid's XLSX export).\n *\n * @remarks\n * Defaults to `true`. Set to `false` to omit a column from generated files\n * (useful for action columns, derived UI, or sensitive fields). The\n * grid-rendered selection checkbox column is never exported regardless of\n * this flag.\n */\n exportable?: boolean;\n /**\n * Pin the column to a side of the grid.\n *\n * @remarks\n * Pinned columns stay fixed during horizontal scroll. Use `'start'` (left in LTR,\n * right in RTL) for the leading edge or `'end'` for the trailing edge. The grid\n * renders columns in the order: `'start'`-pinned, unpinned, `'end'`-pinned, while\n * preserving the original array order inside each group. The `columns` array\n * itself is not mutated.\n */\n pinned?: PinPosition;\n /**\n * Whether this column can be reordered via drag-and-drop or the\n * {@link ApexGrid.moveColumn} API.\n *\n * @remarks\n * Has no effect unless the grid's `columnReordering` flag is `true`. When\n * unset, columns inherit the grid-wide flag. Reordering is constrained to the\n * column's own pinning group — start-pinned columns can only swap with other\n * start-pinned columns, and likewise for end-pinned and unpinned.\n */\n reorderable?: boolean;\n /**\n * Whether the the column can be resized or not.\n */\n resizable?: boolean;\n /**\n * Whether the column can be sorted or not.\n */\n sort?: ColumnSortConfiguration<T, K> | boolean;\n /**\n * Whether filter operation can be applied on the column or not.\n */\n filter?: ColumnFilterConfiguration | boolean;\n /**\n * Header template callback.\n */\n headerTemplate?: (params: ApexHeaderContext<T>) => TemplateResult | unknown;\n /**\n * The id of the {@link ColumnGroupConfiguration} this column belongs to.\n *\n * @remarks\n * Columns sharing a `group` id render under a single spanning header cell in\n * the group header row. Members must be **contiguous within one pin region**\n * (the grid warns and skips the spanning cell otherwise). Has no effect unless\n * {@link ApexGrid.columnGroups} defines a matching group.\n */\n group?: string;\n /**\n * Cell template callback.\n */\n cellTemplate?: (params: ApexCellContext<T, K>) => TemplateResult | unknown;\n /**\n * Whether values in this column can be edited inline.\n *\n * @remarks\n * Has no effect unless the grid's `editing.enabled` is `true`. The default\n * editor is chosen from the column's `type` (`'string'` → text input,\n * `'number'` → number input, `'boolean'` → checkbox). Supply\n * {@link BaseColumnConfiguration.editorTemplate} for full control.\n */\n editable?: boolean;\n /**\n * Custom editor template invoked while this column's cell is in edit mode.\n *\n * @remarks\n * The callback receives an {@link ApexEditorContext} that includes the cell\n * value plus `commit` / `cancel` helpers. Returning a focusable element is\n * recommended so keyboard handoff works.\n */\n editorTemplate?: (params: ApexEditorContext<T, K>) => TemplateResult | unknown;\n /**\n * Allows cells in this column to hold spreadsheet-style formulas.\n *\n * @remarks\n * An enterprise feature: the free core only carries this flag. With the\n * enterprise formula module active and the column also\n * {@link BaseColumnConfiguration.editable}, a cell whose edited text starts\n * with `=` is parsed, stored as a formula, and its computed result becomes the\n * cell value (so sorting, filtering, and aggregation keep working on the\n * value). Has no effect without that module. Default `false`.\n */\n allowFormula?: boolean;\n /**\n * Declarative validators run before a candidate value is written to this\n * column's cells.\n *\n * @remarks\n * Each validator receives the candidate value and a {@link ValidatorContext}\n * and returns an error message string (the cell is rejected) or `null` (it\n * passes). All validators run and every message is collected, so a single\n * failed commit can surface multiple errors. A failing commit keeps the\n * inline editor open, marks the cell `aria-invalid`, and emits\n * `cellValidationFailed`. Validation also covers bulk edits (paste / fill).\n * Use the built-in factories ({@link required}, {@link min}, {@link max},\n * {@link pattern}, {@link custom}) or supply your own function.\n */\n validators?: Validator<T, K>[];\n /**\n * Option list for columns with `type: 'select'`.\n *\n * @remarks\n * Each entry is either a bare value or an explicit `{ value, label }` pair.\n * The cell renders the matching option's `label` in display mode and a\n * native `<select>` of all options in edit mode. Has no effect on columns\n * with another `type`.\n */\n options?: ColumnSelectOption<BasePropertyType<T, K>>[];\n /**\n * Upper bound for `type: 'rating'` and `type: 'progress'`.\n *\n * @remarks\n * For `'rating'` this is the star count (default `5`); the displayed value is\n * clamped to `[0, max]`. For `'progress'` this is the value that fills the bar\n * to 100% (default `100`). Has no effect on columns with another `type`.\n */\n max?: number;\n /**\n * Display format for columns with `type: 'date'`.\n *\n * @remarks\n * Selects an `Intl.DateTimeFormatOptions.dateStyle` preset. Defaults to\n * `'medium'`. Has no effect on columns with another `type`.\n */\n format?: ColumnDateFormat;\n /**\n * Cropping shape for columns with `type: 'image'`.\n *\n * @remarks\n * `'square'` (default) renders the image at its native aspect. `'circle'`\n * crops to a circle (useful for avatars). Has no effect on columns with\n * another `type`.\n */\n shape?: 'square' | 'circle';\n /**\n * Alt text for `<img>` elements rendered by `type: 'image'` columns.\n *\n * @remarks\n * Defaults to the column key. Has no effect on columns with another\n * `type`.\n */\n alt?: string;\n /**\n * ISO 4217 currency code for `type: 'currency'` columns (e.g. `'USD'`,\n * `'EUR'`). Defaults to `'USD'`. Has no effect on columns with another\n * `type`.\n */\n currency?: string;\n /**\n * BCP 47 locale for `type: 'currency'` number formatting. Defaults to the\n * runtime locale. Has no effect on columns with another `type`.\n */\n locale?: string;\n /**\n * Visual variant for `type: 'badge'` columns. A literal applies to every\n * cell; a callback picks per value. Defaults to `'neutral'`. Has no effect\n * on columns with another `type`.\n */\n badgeVariant?: BadgeVariant | ((value: BasePropertyType<T, K>) => BadgeVariant);\n /**\n * State for `type: 'status'` columns. A literal applies to every cell; a\n * callback maps a value to a state. When omitted the state is inferred from\n * the value text. Has no effect on columns with another `type`.\n */\n statusVariant?: StatusVariant | ((value: BasePropertyType<T, K>) => StatusVariant);\n /**\n * Whether `type: 'sparkline'` columns render a trailing delta-% label.\n * Defaults to `true`. Has no effect on columns with another `type`.\n */\n showDelta?: boolean;\n}\n\n/**\n * See {@link BaseColumnConfiguration} for the full documentation.\n */\nexport type ColumnConfiguration<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseColumnConfiguration<T, K> : never;\n\n/**\n * Context passed to a {@link ColumnGroupConfiguration.headerTemplate}.\n */\nexport interface ApexColumnGroupContext {\n /** The group configuration being rendered. */\n group: ColumnGroupConfiguration;\n /** Number of (visible) member columns the group spans. */\n span: number;\n}\n\n/**\n * Configuration for a spanning group header over a contiguous run of columns\n * (see {@link BaseColumnConfiguration.group}).\n */\nexport interface ColumnGroupConfiguration {\n /** Unique group id, referenced by a column's {@link BaseColumnConfiguration.group}. */\n id: string;\n /** Text rendered in the spanning group header cell. */\n headerText: string;\n /**\n * Reserved for a future collapse affordance. Inert in v1 (static spanning\n * headers only).\n */\n collapsible?: boolean;\n /** Custom template for the group header cell, overriding `headerText`. */\n headerTemplate?: (context: ApexColumnGroupContext) => TemplateResult | unknown;\n}\n\n/**\n * Context passed to a {@link Validator} alongside the candidate value.\n */\nexport interface ValidatorContext<T extends object, K extends Keys<T> = Keys<T>> {\n /** The column configuration the value is being validated against. */\n column: ColumnConfiguration<T, K>;\n /**\n * The full data record being edited (a live reference). In a row-mode\n * commit it is the staged row instead: a copy of the record (same\n * prototype) with the row's staged values applied, so cross-field rules\n * see the row being saved. A validator that throws on the copy (one that\n * reads private class fields, say) is run again with the live record.\n */\n data: T;\n /**\n * The view-relative row index of the edited cell (`-1` for a pinned row or\n * a record on another page).\n */\n rowIndex: number;\n}\n\n/**\n * A single declarative validation rule for a column.\n *\n * @returns An error message string when the value is invalid, or `null` when\n * it passes.\n */\nexport type Validator<T extends object, K extends Keys<T> = Keys<T>> = (\n value: unknown,\n context: ValidatorContext<T, K>\n) => string | null;\n\nexport interface ActiveNode<T> {\n column: Keys<T>;\n row: number;\n}\n\n/**\n * Context object for the column header template callback.\n */\nexport interface ApexHeaderContext<T extends object> {\n /**\n * The header element parent of the template.\n */\n parent: ApexGridHeader<T>;\n /**\n * The current configuration for the column.\n */\n column: ColumnConfiguration<T>;\n}\n\n/**\n * Context object for the row cell template callback.\n */\nexport interface BaseApexCellContext<T extends object, K extends Keys<T> = Keys<T>> {\n /**\n * The cell element parent of the template.\n */\n parent: ApexGridCell<T>;\n /**\n * The row element containing the cell.\n */\n row: ApexGridRow<T>;\n /**\n * The current configuration for the column.\n */\n column: ColumnConfiguration<T, K>;\n /**\n * The value from the data source for this cell.\n */\n value: PropertyType<T, K>;\n /**\n * Commits a new value for this cell without entering edit mode. Available\n * when the column is editable. Used by interactive display widgets\n * (e.g. the built-in boolean checkbox) so they can toggle inline.\n *\n * Goes through the cancellable `cellValueChanging` event and follow-up\n * `cellValueChanged` event — same write path as an edit-mode commit.\n */\n commit?: (value: PropertyType<T, K>) => Promise<boolean>;\n}\n\n/**\n * See {@link BaseApexCellContext} for the full documentation.\n */\nexport type ApexCellContext<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseApexCellContext<T, K> : never;\n\n/**\n * Context object handed to a custom editor template.\n *\n * @remarks\n * Includes the cell's current `value` plus `commit` / `cancel` callbacks so\n * the editor can hand its result back to the grid. The custom editor is also\n * responsible for forwarding `Enter` / `Escape` to those callbacks.\n */\nexport interface BaseApexEditorContext<T extends object, K extends Keys<T> = Keys<T>>\n extends BaseApexCellContext<T, K> {\n /**\n * Commits `value` as the new cell value, going through the cancellable\n * `cellValueChanging` event and then `cellValueChanged`.\n *\n * @returns `true` if the value was applied, `false` if cancelled.\n */\n commit: (value: PropertyType<T, K>) => Promise<boolean>;\n /**\n * Discards the in-progress edit and exits edit mode.\n */\n cancel: () => void;\n}\n\n/**\n * See {@link BaseApexEditorContext} for the full documentation.\n */\nexport type ApexEditorContext<T extends object, K extends Keys<T> = Keys<T>> =\n K extends Keys<T> ? BaseApexEditorContext<T, K> : never;\n\n/**\n * The edit trigger used to enter cell edit mode.\n *\n * @remarks\n * `'click'` enters edit on a single click on the cell; `'doubleClick'`\n * requires a double click. Defaults to `'doubleClick'`.\n */\nexport type EditTrigger = 'click' | 'doubleClick';\n\n/**\n * Edit mode for the grid.\n *\n * @remarks\n * `'cell'` — each cell is committed independently on blur or `Enter`.\n * `'row'` — all editable cells in the row enter edit mode together; changes\n * are batched and applied via {@link ApexGrid.commitEdit} or rolled back via\n * {@link ApexGrid.cancelEdit}.\n */\nexport type EditMode = 'cell' | 'row';\n\n/**\n * Selection mode for the grid.\n *\n * @remarks\n * `'single'` — at most one row may be selected at any time. New clicks\n * replace the existing selection.\n * `'multiple'` — multiple rows can be selected. Plain clicks replace the\n * selection, Ctrl/Cmd+click toggles a row additively, and Shift+click\n * selects a range from the previous anchor.\n */\nexport type SelectionMode = 'single' | 'multiple';\n\n/**\n * Grid-level row-selection configuration.\n */\nexport interface GridSelectionConfiguration {\n /**\n * Whether row selection is enabled. Disabled by default.\n */\n enabled?: boolean;\n /**\n * Single-row vs multi-row selection. Defaults to `'multiple'`.\n */\n mode?: SelectionMode;\n /**\n * Whether to render the built-in checkbox column at the start of every\n * row. When `false`, selection is still available via the public API\n * (`selectRow`, `selectedRows = ...`) and via Space on the active row.\n * Defaults to `false`.\n */\n showCheckboxColumn?: boolean;\n}\n\n/**\n * Context passed to {@link GridExpansionConfiguration.detailTemplate}.\n */\nexport interface ApexDetailContext<T extends object> {\n /** The row data for the expanded row. */\n data: T;\n /** The view-relative row index of the master row. */\n rowIndex: number;\n /** The grid element. Useful for emitting events back from the detail. */\n parent: ApexGrid<T>;\n}\n\n/**\n * Grid-level tree-data (nested rows) configuration.\n *\n * @remarks\n * Tree mode renders hierarchical data as nested rows that share the same\n * column layout — collapsible parents with indented children, the\n * flat-array \"tree data\" pattern. The data array stays flat; the grid derives the\n * hierarchy from {@link getDataPath} at runtime.\n *\n * This is distinct from {@link GridExpansionConfiguration} (master-detail),\n * which expands a row to show an arbitrary detail panel. Tree mode and\n * expansion mode can be enabled together, but the chevron column is\n * reserved by whichever is currently rendering the chevron — typically the\n * tree feature when both are enabled.\n *\n * @example\n * ```ts\n * grid.tree = {\n * enabled: true,\n * getDataPath: (row) => row.path,\n * };\n * ```\n */\nexport interface GridTreeConfiguration<T extends object> {\n /** Whether tree mode is enabled. Disabled by default. */\n enabled?: boolean;\n /**\n * Callback that returns the hierarchical path for a row. The path is a\n * sequence of segments from root to the row's own position — for example\n * `['Adrian']` for a CEO, `['Adrian', 'Bryan']` for a VP under Adrian,\n * and so on. Required when `enabled` is `true`.\n */\n getDataPath: (row: T) => readonly string[];\n /**\n * Which column displays the chevron + indentation. Defaults to the first\n * visible non-hidden data column.\n */\n groupColumnKey?: Keys<T>;\n /**\n * Initial expansion state:\n * - `false` (default): all rows collapsed.\n * - `true`: every row expanded.\n * - `number`: expand all rows up to and including the given depth (0 = roots only).\n */\n defaultExpanded?: boolean | number;\n /**\n * Pixels of indentation per depth level. Defaults to `20`.\n */\n childIndent?: number;\n}\n\n/**\n * Grid-level row-expansion (master-detail) configuration.\n */\nexport interface GridExpansionConfiguration<T extends object> {\n /**\n * Whether row expansion is enabled. Disabled by default.\n */\n enabled?: boolean;\n /**\n * Callback that produces the detail panel content for an expanded row.\n * Required when `enabled` is `true`.\n */\n detailTemplate?: (context: ApexDetailContext<T>) => TemplateResult | unknown;\n /**\n * Optional per-row predicate that gates which rows may be expanded. When\n * omitted, every row is expandable.\n */\n isExpandable?: (row: T) => boolean;\n /**\n * Whether to render the built-in chevron toggle column at the start of\n * every row (after the selection column, when present). Defaults to `true`.\n * Set to `false` to drive expansion entirely through the public API or a\n * custom cell template.\n */\n showToggleColumn?: boolean;\n /**\n * Parts used inside the `detailTemplate` content to re-export, so\n * `apex-grid::part(name)` can style them from outside the grid. The panel\n * itself is always reachable as `detail-panel`.\n */\n exportParts?: ReadonlyArray<string>;\n}\n\n/**\n * Undo / redo history configuration for cell-data edits.\n */\nexport interface EditingHistoryConfiguration {\n /**\n * Whether undo / redo tracking is enabled. When `true`, every committed cell\n * edit (single, row-mode, and bulk paste / fill) is recorded and can be\n * reversed via {@link ApexGrid.undo} / {@link ApexGrid.redo} or the keyboard\n * (Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y).\n */\n enabled: boolean;\n /**\n * Maximum number of commands retained on the undo stack. Older commands are\n * evicted once the cap is exceeded. Defaults to `100`.\n */\n stackSize?: number;\n}\n\n/**\n * Grid-level row-pinning configuration.\n */\nexport interface GridRowPinningConfiguration {\n /**\n * Whether rows can be pinned to a sticky top / bottom band via\n * {@link ApexGrid.pinRow}. Disabled when omitted.\n */\n enabled: boolean;\n}\n\n/**\n * Grid-level row-reordering configuration.\n */\nexport interface GridRowReorderingConfiguration {\n /**\n * Whether rows can be reordered by drag, keyboard, or {@link ApexGrid.moveRow}.\n * A manual order, once set, is mutually exclusive with column sorting\n * (applying a sort clears it). Disabled when omitted.\n */\n enabled: boolean;\n /**\n * When `true`, a reorder also splices {@link ApexGrid.data} in place so the\n * source array reflects the new order. Defaults to `false`: the order lives in\n * the grid and the app persists it via the `rowMoved` event.\n */\n applyToData?: boolean;\n /**\n * Controls how a pointer drag is initiated.\n *\n * - `true` (default): a dedicated drag-handle (grip) cell is rendered at the\n * start of every reorderable row, and a drag only begins from that handle.\n * The rest of the row stays free for selection / editing.\n * - `false`: no handle is rendered and a drag begins by pressing anywhere on\n * the row (excluding interactive sub-parts like inputs and buttons).\n *\n * Either way the dragged row is shown as a floating ghost that follows the\n * cursor, and the keyboard reorder flow (grab with Space, move with arrows) is\n * unchanged.\n */\n handle?: boolean;\n}\n\n/**\n * Grid-level editing configuration.\n */\nexport interface GridEditingConfiguration {\n /**\n * Whether editing is enabled. Per-column opt-in still applies via\n * {@link BaseColumnConfiguration.editable}.\n */\n enabled?: boolean;\n /**\n * Whether each cell commits independently or whether the whole row is edited\n * as a batch. Defaults to `'cell'`.\n */\n mode?: EditMode;\n /**\n * The interaction that opens an editor. Defaults to `'doubleClick'`.\n */\n trigger?: EditTrigger;\n /**\n * Undo / redo history for cell-data edits. Disabled when omitted.\n */\n history?: EditingHistoryConfiguration;\n}\n\n/**\n * The parameters passed to a {@link DataPipelineHook} callback.\n */\nexport type DataPipelineParams<T extends object> = {\n /**\n * The current data state of the grid.\n */\n data: T[];\n /**\n * The grid component itself.\n */\n grid: ApexGrid<T>;\n /**\n * The type of data operation being performed.\n */\n type: 'sort' | 'filter' | 'quickFilter' | 'pagination';\n};\n\n/**\n * Callback function for customizing data operations in the grid.\n */\nexport type DataPipelineHook<T extends object> = (\n state: DataPipelineParams<T>\n) => T[] | Promise<T[]>;\n\n/**\n * Configuration for customizing the various data operations of the grid.\n */\nexport interface DataPipelineConfiguration<T extends object> {\n /**\n * Hook for customizing sort operations.\n */\n sort?: DataPipelineHook<T>;\n /**\n * Hook for customizing filter operations.\n */\n filter?: DataPipelineHook<T>;\n /**\n * Hook for customizing pagination operations.\n *\n * @remarks\n * The hook receives the filtered + sorted data slice for the grid to render and the current\n * pagination state. Return the page slice. For server-driven pagination, return the externally\n * fetched page and report the row total via {@link ApexGrid.totalItems}.\n */\n pagination?: DataPipelineHook<T>;\n /**\n * Hook for customizing quick (global) filter operations.\n *\n * @remarks\n * Called before column filtering. Return the records that match the {@link ApexGrid.quickFilter}\n * value. If omitted, the default substring matcher is used.\n */\n quickFilter?: DataPipelineHook<T>;\n}\n\n/**\n * The pagination mode for the grid.\n *\n * @remarks\n * `'local'` — the grid slices the in-memory {@link ApexGrid.dataView} by `page` and `pageSize`.\n * `'remote'` — the consumer drives data fetching; the grid emits paging events but does not\n * slice the data. Use together with {@link DataPipelineConfiguration.pagination} or by setting\n * `data` to the current page on `pageChanged`.\n */\nexport type PaginationMode = 'local' | 'remote';\n\n/**\n * Pagination configuration for the grid.\n */\nexport interface PaginationConfiguration {\n /**\n * Whether pagination is enabled.\n *\n * @remarks\n * When `false`, the grid renders no paginator and applies no slicing — the full\n * {@link ApexGrid.dataView} is virtualized as usual.\n */\n enabled?: boolean;\n /**\n * The pagination mode. Defaults to `'local'`.\n */\n mode?: PaginationMode;\n /**\n * The current page (zero-based). Defaults to `0`.\n */\n page?: number;\n /**\n * The number of records per page. Defaults to `25`.\n */\n pageSize?: number;\n /**\n * The list of page sizes offered in the paginator's page-size dropdown.\n * Defaults to `[10, 25, 50, 100]`.\n */\n pageSizeOptions?: number[];\n /**\n * In `'remote'` mode the consumer must supply the unfiltered row total so the paginator\n * can compute the page count. Ignored in `'local'` mode.\n */\n totalItems?: number;\n}\n\n/**\n * Resolved pagination state passed to controllers and event payloads.\n */\nexport interface PaginationState {\n /**\n * The current page (zero-based).\n */\n page: number;\n /**\n * The number of records per page.\n */\n pageSize: number;\n /**\n * The total number of pages.\n */\n pageCount: number;\n /**\n * The total number of records before pagination (after filter/sort).\n */\n totalItems: number;\n}\n"]}
|