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
package/controllers/selection.js
CHANGED
|
@@ -28,10 +28,14 @@ export class SelectionController {
|
|
|
28
28
|
return Array.from(this.selected);
|
|
29
29
|
}
|
|
30
30
|
allSelected() {
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
31
|
+
const records = this.#records();
|
|
32
|
+
if (records.length === 0)
|
|
33
33
|
return false;
|
|
34
|
-
|
|
34
|
+
for (const row of records) {
|
|
35
|
+
if (!this.selected.has(row))
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
35
39
|
}
|
|
36
40
|
someSelected() {
|
|
37
41
|
if (this.selected.size === 0)
|
|
@@ -41,7 +45,7 @@ export class SelectionController {
|
|
|
41
45
|
return true;
|
|
42
46
|
}
|
|
43
47
|
async toggleRow(row) {
|
|
44
|
-
if (!this.enabled)
|
|
48
|
+
if (!this.enabled || !this.#isDataRow(row))
|
|
45
49
|
return false;
|
|
46
50
|
const next = new Set(this.selected);
|
|
47
51
|
if (next.has(row)) {
|
|
@@ -56,7 +60,7 @@ export class SelectionController {
|
|
|
56
60
|
return this.#commit(next);
|
|
57
61
|
}
|
|
58
62
|
async selectRow(row) {
|
|
59
|
-
if (!this.enabled)
|
|
63
|
+
if (!this.enabled || !this.#isDataRow(row))
|
|
60
64
|
return false;
|
|
61
65
|
const next = new Set(this.mode === 'single' ? [] : this.selected);
|
|
62
66
|
next.add(row);
|
|
@@ -73,7 +77,7 @@ export class SelectionController {
|
|
|
73
77
|
return this.#commit(next);
|
|
74
78
|
}
|
|
75
79
|
async additiveToggle(row) {
|
|
76
|
-
if (!this.enabled)
|
|
80
|
+
if (!this.enabled || !this.#isDataRow(row))
|
|
77
81
|
return false;
|
|
78
82
|
if (this.mode === 'single')
|
|
79
83
|
return this.toggleRow(row);
|
|
@@ -88,7 +92,7 @@ export class SelectionController {
|
|
|
88
92
|
return this.#commit(next);
|
|
89
93
|
}
|
|
90
94
|
async rangeToggle(row) {
|
|
91
|
-
if (!this.enabled)
|
|
95
|
+
if (!this.enabled || !this.#isDataRow(row))
|
|
92
96
|
return false;
|
|
93
97
|
if (this.mode === 'single' || !this.anchor) {
|
|
94
98
|
return this.selectRow(row);
|
|
@@ -102,15 +106,15 @@ export class SelectionController {
|
|
|
102
106
|
const [lo, hi] = startIdx < endIdx ? [startIdx, endIdx] : [endIdx, startIdx];
|
|
103
107
|
const next = new Set(this.selected);
|
|
104
108
|
for (let i = lo; i <= hi; i++) {
|
|
105
|
-
|
|
109
|
+
if (this.#isDataRow(pageItems[i]))
|
|
110
|
+
next.add(pageItems[i]);
|
|
106
111
|
}
|
|
107
112
|
return this.#commit(next);
|
|
108
113
|
}
|
|
109
114
|
async selectAll() {
|
|
110
115
|
if (!this.enabled || this.mode === 'single')
|
|
111
116
|
return false;
|
|
112
|
-
|
|
113
|
-
return this.#commit(next);
|
|
117
|
+
return this.#commit(new Set(this.#records()));
|
|
114
118
|
}
|
|
115
119
|
async clear() {
|
|
116
120
|
if (this.selected.size === 0)
|
|
@@ -120,9 +124,20 @@ export class SelectionController {
|
|
|
120
124
|
async replaceSelection(rows) {
|
|
121
125
|
if (!this.enabled)
|
|
122
126
|
return false;
|
|
123
|
-
const
|
|
127
|
+
const records = this.#state?.dataRows(rows) ?? rows;
|
|
128
|
+
const next = new Set(this.mode === 'single' ? records.slice(0, 1) : records);
|
|
124
129
|
return this.#commit(next);
|
|
125
130
|
}
|
|
131
|
+
get #state() {
|
|
132
|
+
return this.host.stateController;
|
|
133
|
+
}
|
|
134
|
+
#records() {
|
|
135
|
+
const view = this.host.dataView;
|
|
136
|
+
return this.#state?.viewRecords(view) ?? view;
|
|
137
|
+
}
|
|
138
|
+
#isDataRow(row) {
|
|
139
|
+
return this.#state?.isDataRow(row) ?? true;
|
|
140
|
+
}
|
|
126
141
|
async #commit(next) {
|
|
127
142
|
const added = [];
|
|
128
143
|
const removed = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/controllers/selection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { GridHost, SelectionMode } from '../internal/types.js';\n\n/**\n * The default selection configuration used when the grid has none set.\n */\nexport const DEFAULT_SELECTION_CONFIG = Object.freeze({\n enabled: false,\n mode: 'multiple' as SelectionMode,\n showCheckboxColumn: false,\n});\n\n/**\n * Reactive controller backing row selection.\n *\n * @remarks\n * Selection state is reference-based — the controller holds a `Set` of row\n * data references so the selection survives sort / filter / pagination as\n * long as those operations preserve identities (the default in-place\n * pipeline does). Replacing {@link ApexGrid.data} wholesale will invalidate\n * any selected rows that are no longer present in the new array; consumers\n * should call {@link clear} or re-apply selection after such a change.\n *\n * Mutations go through the cancellable `rowSelecting` event and emit a\n * follow-up `rowSelected` event, mirroring the pattern used by editing.\n */\nexport class SelectionController<T extends object> implements ReactiveController {\n /** Set of currently selected row data references. */\n public selected: Set<T> = new Set();\n\n /**\n * Anchor row for Shift+click range selection. Set whenever a single row\n * is toggled / picked so a follow-up Shift+click knows where to start.\n */\n public anchor: T | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether selection is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.selection?.enabled);\n }\n\n /**\n * The resolved selection mode (`'multiple'` if unset).\n */\n public get mode(): SelectionMode {\n return this.host.selection?.mode ?? DEFAULT_SELECTION_CONFIG.mode;\n }\n\n /**\n * Whether to render the built-in checkbox column.\n */\n public get showCheckboxColumn(): boolean {\n return (\n this.enabled &&\n (this.host.selection?.showCheckboxColumn ?? DEFAULT_SELECTION_CONFIG.showCheckboxColumn)\n );\n }\n\n /**\n * Whether the given row is currently selected.\n */\n public isSelected(row: T): boolean {\n return this.selected.has(row);\n }\n\n /**\n * Returns the currently selected rows in insertion order.\n */\n public selectedRows(): T[] {\n return Array.from(this.selected);\n }\n\n /**\n * Whether every row in the current view ({@link ApexGrid.dataView}) is\n * selected. Used by the header checkbox to render its \"all\" state.\n */\n public allSelected(): boolean {\n const view = this.host.dataView;\n if (view.length === 0) return false;\n return view.every((row) => this.selected.has(row as T));\n }\n\n /**\n * Whether some — but not all — rows in the current view are selected.\n * Used to render the header checkbox in its indeterminate state.\n */\n public someSelected(): boolean {\n if (this.selected.size === 0) return false;\n if (this.allSelected()) return false;\n return true;\n }\n\n /**\n * Toggles selection of `row`. In `'single'` mode this either selects the\n * row (replacing any previous selection) or deselects it if it was the\n * only selected row.\n */\n public async toggleRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n const next = new Set(this.selected);\n if (next.has(row)) {\n next.delete(row);\n } else {\n if (this.mode === 'single') next.clear();\n next.add(row);\n }\n this.anchor = next.has(row) ? row : null;\n return this.#commit(next);\n }\n\n /**\n * Adds `row` to the selection. In `'single'` mode the existing selection\n * is cleared first.\n */\n public async selectRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n const next = new Set(this.mode === 'single' ? [] : this.selected);\n next.add(row);\n this.anchor = row;\n return this.#commit(next);\n }\n\n /**\n * Removes `row` from the selection.\n */\n public async deselectRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (!this.selected.has(row)) return true;\n const next = new Set(this.selected);\n next.delete(row);\n return this.#commit(next);\n }\n\n /**\n * Adds `row` to the selection without affecting other selected rows\n * (`'multiple'` mode only). In `'single'` mode this behaves like\n * {@link selectRow}.\n */\n public async additiveToggle(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (this.mode === 'single') return this.toggleRow(row);\n const next = new Set(this.selected);\n if (next.has(row)) {\n next.delete(row);\n } else {\n next.add(row);\n }\n this.anchor = next.has(row) ? row : this.anchor;\n return this.#commit(next);\n }\n\n /**\n * Selects every row between {@link anchor} and `row` (inclusive) in the\n * current page view. No-op in `'single'` mode or when no anchor is set —\n * in those cases the call falls back to a plain {@link selectRow}.\n */\n public async rangeToggle(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (this.mode === 'single' || !this.anchor) {\n return this.selectRow(row);\n }\n const pageItems = this.host.pageItems as ReadonlyArray<T>;\n const startIdx = pageItems.indexOf(this.anchor);\n const endIdx = pageItems.indexOf(row);\n if (startIdx === -1 || endIdx === -1) {\n return this.selectRow(row);\n }\n const [lo, hi] = startIdx < endIdx ? [startIdx, endIdx] : [endIdx, startIdx];\n const next = new Set(this.selected);\n for (let i = lo; i <= hi; i++) {\n next.add(pageItems[i] as T);\n }\n return this.#commit(next);\n }\n\n /**\n * Selects every row currently in view ({@link ApexGrid.dataView}). No-op\n * in `'single'` mode.\n */\n public async selectAll(): Promise<boolean> {\n if (!this.enabled || this.mode === 'single') return false;\n const next = new Set(this.host.dataView as ReadonlyArray<T>);\n return this.#commit(next);\n }\n\n /**\n * Clears the selection.\n */\n public async clear(): Promise<boolean> {\n if (this.selected.size === 0) return true;\n return this.#commit(new Set());\n }\n\n /**\n * Replaces the current selection with `rows`. Used by the public\n * {@link ApexGrid.selectedRows} setter so callers can drive selection\n * programmatically. Single-mode keeps at most one row.\n */\n public async replaceSelection(rows: ReadonlyArray<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const next = new Set(this.mode === 'single' ? rows.slice(0, 1) : rows);\n return this.#commit(next);\n }\n\n async #commit(next: Set<T>): Promise<boolean> {\n const added: T[] = [];\n const removed: T[] = [];\n for (const row of next) {\n if (!this.selected.has(row)) added.push(row);\n }\n for (const row of this.selected) {\n if (!next.has(row)) removed.push(row);\n }\n if (added.length === 0 && removed.length === 0) return true;\n\n const proceed = this.host.emitEvent('rowSelecting', {\n detail: {\n added,\n removed,\n current: Array.from(this.selected),\n next: Array.from(next),\n },\n cancelable: true,\n });\n if (!proceed) return false;\n\n this.selected = next;\n this.host.requestUpdate();\n\n const total = this.selected.size;\n if (total === 0) {\n this.host.announce(this.host.localize('announce.selectionCleared'));\n } else if (added.length === 1 && removed.length === 0 && total === 1) {\n this.host.announce(this.host.localize('announce.rowSelected'));\n } else {\n this.host.announce(this.host.localize('announce.rowsSelected', { count: total }));\n }\n\n this.host.emitEvent('rowSelected', {\n detail: { added, removed, selected: Array.from(this.selected) },\n });\n return true;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/controllers/selection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { GridHost, SelectionMode } from '../internal/types.js';\nimport type { StateController } from './state.js';\n\n/**\n * The default selection configuration used when the grid has none set.\n */\nexport const DEFAULT_SELECTION_CONFIG = Object.freeze({\n enabled: false,\n mode: 'multiple' as SelectionMode,\n showCheckboxColumn: false,\n});\n\n/**\n * Reactive controller backing row selection.\n *\n * @remarks\n * Selection state is reference-based — the controller holds a `Set` of row\n * data references so the selection survives sort / filter / pagination as\n * long as those operations preserve identities (the default in-place\n * pipeline does). Replacing {@link ApexGrid.data} wholesale will invalidate\n * any selected rows that are no longer present in the new array; consumers\n * should call {@link clear} or re-apply selection after such a change.\n *\n * Only data records are selectable: rows a feature module synthesizes into the\n * view (group headers, a grand-total row; see {@link StateController.isDataRow})\n * are skipped by every mutation and ignored by {@link allSelected}.\n *\n * Mutations go through the cancellable `rowSelecting` event and emit a\n * follow-up `rowSelected` event, mirroring the pattern used by editing.\n */\nexport class SelectionController<T extends object> implements ReactiveController {\n /** Set of currently selected row data references. */\n public selected: Set<T> = new Set();\n\n /**\n * Anchor row for Shift+click range selection. Set whenever a single row\n * is toggled / picked so a follow-up Shift+click knows where to start.\n */\n public anchor: T | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether selection is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.selection?.enabled);\n }\n\n /**\n * The resolved selection mode (`'multiple'` if unset).\n */\n public get mode(): SelectionMode {\n return this.host.selection?.mode ?? DEFAULT_SELECTION_CONFIG.mode;\n }\n\n /**\n * Whether to render the built-in checkbox column.\n */\n public get showCheckboxColumn(): boolean {\n return (\n this.enabled &&\n (this.host.selection?.showCheckboxColumn ?? DEFAULT_SELECTION_CONFIG.showCheckboxColumn)\n );\n }\n\n /**\n * Whether the given row is currently selected.\n */\n public isSelected(row: T): boolean {\n return this.selected.has(row);\n }\n\n /**\n * Returns the currently selected rows in insertion order.\n */\n public selectedRows(): T[] {\n return Array.from(this.selected);\n }\n\n /**\n * Whether every data record the current view covers is selected, including\n * the leaves of collapsed groups (see {@link StateController.viewRecords}).\n * `false` when the view covers none. Used by the header checkbox to render\n * its \"all\" state.\n */\n public allSelected(): boolean {\n const records = this.#records();\n if (records.length === 0) return false;\n for (const row of records) {\n if (!this.selected.has(row)) return false;\n }\n return true;\n }\n\n /**\n * Whether some — but not all — rows in the current view are selected.\n * Used to render the header checkbox in its indeterminate state.\n */\n public someSelected(): boolean {\n if (this.selected.size === 0) return false;\n if (this.allSelected()) return false;\n return true;\n }\n\n /**\n * Toggles selection of `row`. In `'single'` mode this either selects the\n * row (replacing any previous selection) or deselects it if it was the\n * only selected row.\n */\n public async toggleRow(row: T): Promise<boolean> {\n if (!this.enabled || !this.#isDataRow(row)) return false;\n const next = new Set(this.selected);\n if (next.has(row)) {\n next.delete(row);\n } else {\n if (this.mode === 'single') next.clear();\n next.add(row);\n }\n this.anchor = next.has(row) ? row : null;\n return this.#commit(next);\n }\n\n /**\n * Adds `row` to the selection. In `'single'` mode the existing selection\n * is cleared first.\n */\n public async selectRow(row: T): Promise<boolean> {\n if (!this.enabled || !this.#isDataRow(row)) return false;\n const next = new Set(this.mode === 'single' ? [] : this.selected);\n next.add(row);\n this.anchor = row;\n return this.#commit(next);\n }\n\n /**\n * Removes `row` from the selection.\n */\n public async deselectRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (!this.selected.has(row)) return true;\n const next = new Set(this.selected);\n next.delete(row);\n return this.#commit(next);\n }\n\n /**\n * Adds `row` to the selection without affecting other selected rows\n * (`'multiple'` mode only). In `'single'` mode this behaves like\n * {@link selectRow}.\n */\n public async additiveToggle(row: T): Promise<boolean> {\n if (!this.enabled || !this.#isDataRow(row)) return false;\n if (this.mode === 'single') return this.toggleRow(row);\n const next = new Set(this.selected);\n if (next.has(row)) {\n next.delete(row);\n } else {\n next.add(row);\n }\n this.anchor = next.has(row) ? row : this.anchor;\n return this.#commit(next);\n }\n\n /**\n * Selects every row between {@link anchor} and `row` (inclusive) in the\n * current page view. No-op in `'single'` mode or when no anchor is set —\n * in those cases the call falls back to a plain {@link selectRow}.\n */\n public async rangeToggle(row: T): Promise<boolean> {\n if (!this.enabled || !this.#isDataRow(row)) return false;\n if (this.mode === 'single' || !this.anchor) {\n return this.selectRow(row);\n }\n const pageItems = this.host.pageItems as ReadonlyArray<T>;\n const startIdx = pageItems.indexOf(this.anchor);\n const endIdx = pageItems.indexOf(row);\n if (startIdx === -1 || endIdx === -1) {\n return this.selectRow(row);\n }\n const [lo, hi] = startIdx < endIdx ? [startIdx, endIdx] : [endIdx, startIdx];\n const next = new Set(this.selected);\n for (let i = lo; i <= hi; i++) {\n if (this.#isDataRow(pageItems[i])) next.add(pageItems[i]);\n }\n return this.#commit(next);\n }\n\n /**\n * Selects every data record the current view ({@link ApexGrid.dataView})\n * covers, including the leaves of collapsed groups. No-op in `'single'`\n * mode.\n */\n public async selectAll(): Promise<boolean> {\n if (!this.enabled || this.mode === 'single') return false;\n return this.#commit(new Set(this.#records()));\n }\n\n /**\n * Clears the selection.\n */\n public async clear(): Promise<boolean> {\n if (this.selected.size === 0) return true;\n return this.#commit(new Set());\n }\n\n /**\n * Replaces the current selection with `rows`. Used by the public\n * {@link ApexGrid.selectedRows} setter so callers can drive selection\n * programmatically. Single-mode keeps at most one row.\n */\n public async replaceSelection(rows: ReadonlyArray<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const records = this.#state?.dataRows(rows) ?? rows;\n const next = new Set(this.mode === 'single' ? records.slice(0, 1) : records);\n return this.#commit(next);\n }\n\n /** The owning state controller; absent only while the grid is constructing. */\n get #state(): StateController<T> | undefined {\n return (this.host as unknown as { stateController?: StateController<T> }).stateController;\n }\n\n /** The data records the current view covers, collapsed group leaves included. */\n #records(): ReadonlyArray<T> {\n const view = this.host.dataView as ReadonlyArray<T>;\n return this.#state?.viewRecords(view) ?? view;\n }\n\n #isDataRow(row: T): boolean {\n return this.#state?.isDataRow(row) ?? true;\n }\n\n async #commit(next: Set<T>): Promise<boolean> {\n const added: T[] = [];\n const removed: T[] = [];\n for (const row of next) {\n if (!this.selected.has(row)) added.push(row);\n }\n for (const row of this.selected) {\n if (!next.has(row)) removed.push(row);\n }\n if (added.length === 0 && removed.length === 0) return true;\n\n const proceed = this.host.emitEvent('rowSelecting', {\n detail: {\n added,\n removed,\n current: Array.from(this.selected),\n next: Array.from(next),\n },\n cancelable: true,\n });\n if (!proceed) return false;\n\n this.selected = next;\n this.host.requestUpdate();\n\n const total = this.selected.size;\n if (total === 0) {\n this.host.announce(this.host.localize('announce.selectionCleared'));\n } else if (added.length === 1 && removed.length === 0 && total === 1) {\n this.host.announce(this.host.localize('announce.rowSelected'));\n } else {\n this.host.announce(this.host.localize('announce.rowsSelected', { count: total }));\n }\n\n this.host.emitEvent('rowSelected', {\n detail: { added, removed, selected: Array.from(this.selected) },\n });\n return true;\n }\n}\n"]}
|
package/controllers/sort.d.ts
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
import type { ReactiveController } from 'lit';
|
|
2
2
|
import type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js';
|
|
3
|
-
import type { SortExpression, SortState } from '../operations/sort/types.js';
|
|
3
|
+
import type { SortExpression, SortingDirection, SortState } from '../operations/sort/types.js';
|
|
4
4
|
export declare class SortController<T extends object> implements ReactiveController {
|
|
5
5
|
#private;
|
|
6
6
|
protected host: GridHost<T>;
|
|
7
7
|
constructor(host: GridHost<T>);
|
|
8
8
|
state: SortState<T>;
|
|
9
9
|
sortFromHeaderClick(column: ColumnConfiguration<T>, additive?: boolean): Promise<void>;
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The one path for a sort the user starts from the UI (header click, column
|
|
12
|
+
* menu): fires the cancelable `sorting` event, replaces the sort unless the
|
|
13
|
+
* gesture is additive in multi-sort mode, announces, then fires `sorted`.
|
|
14
|
+
* Without a `direction` the column steps to its next direction.
|
|
15
|
+
*/
|
|
16
|
+
sortFromUI(column: ColumnConfiguration<T>, { direction, additive }?: {
|
|
17
|
+
direction?: SortingDirection;
|
|
18
|
+
additive?: boolean;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* The expression a UI sort would apply. Always a fresh object: the stored
|
|
22
|
+
* entry is only replaced once the `sorting` event is not cancelled.
|
|
23
|
+
*/
|
|
24
|
+
prepareExpression({ key, sort: options }: ColumnConfiguration<T>, direction?: SortingDirection): SortExpression<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Whether the UI offers sorting on `column`: it declares `sort` and no
|
|
27
|
+
* manual row order is active (sorting and a manual order are mutually
|
|
28
|
+
* exclusive). The one rule for every sort affordance, built in or a module's.
|
|
29
|
+
*/
|
|
30
|
+
isSortable(column: ColumnConfiguration<T>): boolean;
|
|
11
31
|
reset(key?: Keys<T>): void;
|
|
12
32
|
protected _sort(expressions: SortExpression<T> | SortExpression<T>[]): void;
|
|
13
33
|
sort(expressions: SortExpression<T> | SortExpression<T>[]): void;
|
package/controllers/sort.js
CHANGED
|
@@ -14,23 +14,22 @@ export class SortController {
|
|
|
14
14
|
return this.host.sortConfiguration.triState;
|
|
15
15
|
}
|
|
16
16
|
#resolveSortOptions(options) {
|
|
17
|
-
const expr = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
const expr = {};
|
|
18
|
+
if (options && typeof options === 'object') {
|
|
19
|
+
if (options.caseSensitive !== undefined)
|
|
20
|
+
expr.caseSensitive = options.caseSensitive;
|
|
21
|
+
if (options.comparer !== undefined)
|
|
22
|
+
expr.comparer = options.comparer;
|
|
23
23
|
}
|
|
24
|
-
return
|
|
25
|
-
caseSensitive: options.caseSensitive,
|
|
26
|
-
comparer: options.comparer,
|
|
27
|
-
});
|
|
24
|
+
return expr;
|
|
28
25
|
}
|
|
29
26
|
#createDefaultExpression(key) {
|
|
30
27
|
const options = this.host.getColumn(key)?.sort;
|
|
31
28
|
return {
|
|
32
29
|
key,
|
|
33
30
|
direction: 'ascending',
|
|
31
|
+
caseSensitive: false,
|
|
32
|
+
comparer: undefined,
|
|
34
33
|
...this.#resolveSortOptions(options),
|
|
35
34
|
};
|
|
36
35
|
}
|
|
@@ -56,8 +55,11 @@ export class SortController {
|
|
|
56
55
|
? this.reset(expression.key)
|
|
57
56
|
: this.state.set(expression.key, { ...expression });
|
|
58
57
|
}
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
sortFromHeaderClick(column, additive = false) {
|
|
59
|
+
return this.sortFromUI(column, { additive });
|
|
60
|
+
}
|
|
61
|
+
async sortFromUI(column, { direction, additive = false } = {}) {
|
|
62
|
+
const expression = this.prepareExpression(column, direction);
|
|
61
63
|
if (!this.#emitSortingEvent(expression)) {
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
@@ -66,7 +68,7 @@ export class SortController {
|
|
|
66
68
|
}
|
|
67
69
|
const beforeRects = this.#captureRowRects();
|
|
68
70
|
this._sort(expression);
|
|
69
|
-
await this.host.
|
|
71
|
+
await this.host.pipelineSettled();
|
|
70
72
|
await awaitChildUpdates(this.host.rows);
|
|
71
73
|
this.#playRowFlip(beforeRects);
|
|
72
74
|
this.#announce(expression, column);
|
|
@@ -97,15 +99,16 @@ export class SortController {
|
|
|
97
99
|
}
|
|
98
100
|
playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');
|
|
99
101
|
}
|
|
100
|
-
prepareExpression({ key, sort: options }) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
prepareExpression({ key, sort: options }, direction) {
|
|
103
|
+
const expr = this.state.get(key);
|
|
104
|
+
return {
|
|
105
|
+
...(expr ?? this.#createDefaultExpression(key)),
|
|
106
|
+
direction: direction ?? this.#orderBy(expr?.direction),
|
|
107
|
+
...this.#resolveSortOptions(options),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
isSortable(column) {
|
|
111
|
+
return Boolean(column.sort) && !this.#rowReorder?.hasManualOrder;
|
|
109
112
|
}
|
|
110
113
|
reset(key) {
|
|
111
114
|
key ? this.state.delete(key) : this.state.clear();
|
|
@@ -125,7 +128,10 @@ export class SortController {
|
|
|
125
128
|
this.host.requestUpdate(PIPELINE);
|
|
126
129
|
}
|
|
127
130
|
sort(expressions) {
|
|
128
|
-
this._sort(asArray(expressions).map((expr) =>
|
|
131
|
+
this._sort(asArray(expressions).map((expr) => ({
|
|
132
|
+
...(this.state.get(expr.key) ?? this.#createDefaultExpression(expr.key)),
|
|
133
|
+
...expr,
|
|
134
|
+
})));
|
|
129
135
|
}
|
|
130
136
|
hostConnected() { }
|
|
131
137
|
}
|
package/controllers/sort.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/controllers/sort.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport { awaitChildUpdates, type KeyedFlipEntry, playKeyedFlip } from '../internal/flip.js';\nimport type {\n ColumnConfiguration,\n ColumnSortConfiguration,\n GridHost,\n Keys,\n} from '../internal/types.js';\nimport { asArray } from '../internal/utils.js';\nimport type { SortExpression, SortingDirection, SortState } from '../operations/sort/types.js';\n\nexport class SortController<T extends object> implements ReactiveController {\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public state: SortState<T> = new Map();\n\n get #isMultipleSort() {\n return this.host.sortConfiguration.multiple;\n }\n\n get #isTriStateSort() {\n return this.host.sortConfiguration.triState;\n }\n\n #resolveSortOptions(options?: boolean | ColumnSortConfiguration<T>) {\n const expr: Pick<SortExpression<T>, 'caseSensitive' | 'comparer'> = {\n caseSensitive: false,\n comparer: undefined,\n };\n\n if (!options || typeof options === 'boolean') {\n return expr as Partial<SortExpression<T>>;\n }\n\n return Object.assign(expr, {\n caseSensitive: options.caseSensitive,\n comparer: options.comparer,\n }) as Partial<SortExpression<T>>;\n }\n\n #createDefaultExpression(key: Keys<T>) {\n const options = this.host.getColumn(key)?.sort;\n\n return {\n key,\n direction: 'ascending',\n ...this.#resolveSortOptions(options),\n } as SortExpression<T>;\n }\n\n #orderBy(dir?: SortingDirection): SortingDirection {\n return this.#isTriStateSort\n ? dir === 'ascending'\n ? 'descending'\n : dir === 'descending'\n ? 'none'\n : 'ascending'\n : dir === 'ascending'\n ? 'descending'\n : 'ascending';\n }\n\n #emitSortingEvent(detail: SortExpression<T>) {\n return this.host.emitEvent('sorting', { detail, cancelable: true });\n }\n\n #emitSortedEvent(detail: SortExpression<T>) {\n return this.host.emitEvent('sorted', { detail });\n }\n\n #setExpression(expression: SortExpression<T>) {\n expression.direction === 'none'\n ? this.reset(expression.key)\n : this.state.set(expression.key, { ...expression });\n }\n\n public async sortFromHeaderClick(column: ColumnConfiguration<T>, additive = false) {\n const expression = this.prepareExpression(column);\n\n if (!this.#emitSortingEvent(expression)) {\n return;\n }\n\n // A plain click sorts by this column alone, clearing any other sorted\n // columns. Only a Ctrl/Cmd+click while multi-sort is enabled keeps the\n // existing sort keys and appends this column as an additional, lower-\n // priority sort. Without this gate every plain click would accumulate a\n // key, so a second column added behind a unique primary column would not\n // change the visible order at all.\n if (!this.#isMultipleSort || !additive) {\n this.reset();\n }\n\n // Capture visible-row rects keyed by data identity BEFORE the pipeline\n // runs. After the new render the virtualizer will have repositioned\n // rows; we use those captured rects as the \"First\" of a FLIP and\n // animate each row from its old viewport position back to identity.\n const beforeRects = this.#captureRowRects();\n\n this._sort(expression);\n\n await this.host.updateComplete;\n // Wait for body row updates so the new data is committed to each row\n // element before measuring the \"Last\" rect — otherwise the captured-\n // before and measured-after rects match and the animation no-ops.\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(beforeRects);\n this.#announce(expression, column);\n this.#emitSortedEvent(expression);\n }\n\n #announce(expression: SortExpression<T>, column: ColumnConfiguration<T>) {\n const label = column.headerText ?? String(column.key);\n const message =\n expression.direction === 'none'\n ? this.host.localize('announce.sortCleared', { label })\n : this.host.localize(\n expression.direction === 'ascending'\n ? 'announce.sortedAscending'\n : 'announce.sortedDescending',\n { label }\n );\n this.host.announce(message);\n }\n\n #captureRowRects(): KeyedFlipEntry<T>[] {\n const entries: KeyedFlipEntry<T>[] = [];\n for (const row of this.host.rows) {\n const el = row as unknown as HTMLElement;\n entries.push({ key: row.data, rect: el.getBoundingClientRect() });\n }\n return entries;\n }\n\n #playRowFlip(before: ReadonlyArray<KeyedFlipEntry<T>>) {\n // After sort, the same data may be rendered by a different `<apex-grid-row>`\n // DOM element (virtualizer recycles rows). Resolve by data identity.\n const rows = this.host.rows;\n const byData = new Map<T, HTMLElement>();\n for (const row of rows) {\n byData.set(row.data, row as unknown as HTMLElement);\n }\n playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');\n }\n\n public prepareExpression({ key, sort: options }: ColumnConfiguration<T>): SortExpression<T> {\n if (this.state.has(key)) {\n const expr = this.state.get(key)!;\n\n return Object.assign(expr, {\n direction: this.#orderBy(expr.direction),\n ...this.#resolveSortOptions(options),\n });\n }\n\n // Initial state\n return this.#createDefaultExpression(key);\n }\n\n public reset(key?: Keys<T>) {\n key ? this.state.delete(key) : this.state.clear();\n }\n\n get #rowReorder() {\n // @ts-expect-error - protected member access\n return this.host.stateController.rowReorder as\n | { hasManualOrder: boolean; clearManualOrder(announce?: boolean): void }\n | undefined;\n }\n\n protected _sort(expressions: SortExpression<T> | SortExpression<T>[]) {\n const exprs = asArray(expressions);\n // Applying a sort is mutually exclusive with a manual row order (F5):\n // a real sort (any non-`none` direction) clears it, with an announcement.\n const reorder = this.#rowReorder;\n if (reorder?.hasManualOrder && exprs.some((expr) => expr.direction !== 'none')) {\n reorder.clearManualOrder(true);\n }\n\n for (const expr of exprs) {\n this.#setExpression(expr);\n }\n\n this.host.requestUpdate(PIPELINE);\n }\n\n public sort(expressions: SortExpression<T> | SortExpression<T>[]) {\n this._sort(\n asArray(expressions).map((expr) =>\n Object.assign(this.state.get(expr.key) ?? this.#createDefaultExpression(expr.key), expr)\n )\n );\n }\n\n public hostConnected() {}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/controllers/sort.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport { awaitChildUpdates, type KeyedFlipEntry, playKeyedFlip } from '../internal/flip.js';\nimport type {\n ColumnConfiguration,\n ColumnSortConfiguration,\n GridHost,\n Keys,\n} from '../internal/types.js';\nimport { asArray } from '../internal/utils.js';\nimport type { SortExpression, SortingDirection, SortState } from '../operations/sort/types.js';\n\nexport class SortController<T extends object> implements ReactiveController {\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public state: SortState<T> = new Map();\n\n get #isMultipleSort() {\n return this.host.sortConfiguration.multiple;\n }\n\n get #isTriStateSort() {\n return this.host.sortConfiguration.triState;\n }\n\n /**\n * Only the options the column config actually sets, so a header click keeps a\n * comparer or caseSensitive that came in through `grid.sort()` when the column\n * itself does not define one. The trade-off: a comparer later removed from\n * the column config stays on the stored expression until that column's sort\n * is cleared, because its origin is not tracked.\n */\n #resolveSortOptions(options?: boolean | ColumnSortConfiguration<T>) {\n const expr: Partial<SortExpression<T>> = {};\n if (options && typeof options === 'object') {\n if (options.caseSensitive !== undefined) expr.caseSensitive = options.caseSensitive;\n if (options.comparer !== undefined) expr.comparer = options.comparer as any;\n }\n return expr;\n }\n\n #createDefaultExpression(key: Keys<T>) {\n const options = this.host.getColumn(key)?.sort;\n\n return {\n key,\n direction: 'ascending',\n caseSensitive: false,\n comparer: undefined,\n ...this.#resolveSortOptions(options),\n } as SortExpression<T>;\n }\n\n #orderBy(dir?: SortingDirection): SortingDirection {\n return this.#isTriStateSort\n ? dir === 'ascending'\n ? 'descending'\n : dir === 'descending'\n ? 'none'\n : 'ascending'\n : dir === 'ascending'\n ? 'descending'\n : 'ascending';\n }\n\n #emitSortingEvent(detail: SortExpression<T>) {\n return this.host.emitEvent('sorting', { detail, cancelable: true });\n }\n\n #emitSortedEvent(detail: SortExpression<T>) {\n return this.host.emitEvent('sorted', { detail });\n }\n\n #setExpression(expression: SortExpression<T>) {\n expression.direction === 'none'\n ? this.reset(expression.key)\n : this.state.set(expression.key, { ...expression });\n }\n\n public sortFromHeaderClick(column: ColumnConfiguration<T>, additive = false) {\n return this.sortFromUI(column, { additive });\n }\n\n /**\n * The one path for a sort the user starts from the UI (header click, column\n * menu): fires the cancelable `sorting` event, replaces the sort unless the\n * gesture is additive in multi-sort mode, announces, then fires `sorted`.\n * Without a `direction` the column steps to its next direction.\n */\n public async sortFromUI(\n column: ColumnConfiguration<T>,\n { direction, additive = false }: { direction?: SortingDirection; additive?: boolean } = {}\n ) {\n const expression = this.prepareExpression(column, direction);\n\n if (!this.#emitSortingEvent(expression)) {\n return;\n }\n\n // A plain click sorts by this column alone, clearing any other sorted\n // columns. Only a Ctrl/Cmd+click while multi-sort is enabled keeps the\n // existing sort keys and appends this column as an additional, lower-\n // priority sort. Without this gate every plain click would accumulate a\n // key, so a second column added behind a unique primary column would not\n // change the visible order at all.\n if (!this.#isMultipleSort || !additive) {\n this.reset();\n }\n\n // Capture visible-row rects keyed by data identity BEFORE the pipeline\n // runs. After the new render the virtualizer will have repositioned\n // rows; we use those captured rects as the \"First\" of a FLIP and\n // animate each row from its old viewport position back to identity.\n const beforeRects = this.#captureRowRects();\n\n this._sort(expression);\n\n // @ts-expect-error - protected member access\n await this.host.pipelineSettled();\n // Wait for body row updates so the new data is committed to each row\n // element before measuring the \"Last\" rect — otherwise the captured-\n // before and measured-after rects match and the animation no-ops.\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(beforeRects);\n this.#announce(expression, column);\n this.#emitSortedEvent(expression);\n }\n\n #announce(expression: SortExpression<T>, column: ColumnConfiguration<T>) {\n const label = column.headerText ?? String(column.key);\n const message =\n expression.direction === 'none'\n ? this.host.localize('announce.sortCleared', { label })\n : this.host.localize(\n expression.direction === 'ascending'\n ? 'announce.sortedAscending'\n : 'announce.sortedDescending',\n { label }\n );\n this.host.announce(message);\n }\n\n #captureRowRects(): KeyedFlipEntry<T>[] {\n const entries: KeyedFlipEntry<T>[] = [];\n for (const row of this.host.rows) {\n const el = row as unknown as HTMLElement;\n entries.push({ key: row.data, rect: el.getBoundingClientRect() });\n }\n return entries;\n }\n\n #playRowFlip(before: ReadonlyArray<KeyedFlipEntry<T>>) {\n // After sort, the same data may be rendered by a different `<apex-grid-row>`\n // DOM element (virtualizer recycles rows). Resolve by data identity.\n const rows = this.host.rows;\n const byData = new Map<T, HTMLElement>();\n for (const row of rows) {\n byData.set(row.data, row as unknown as HTMLElement);\n }\n playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');\n }\n\n /**\n * The expression a UI sort would apply. Always a fresh object: the stored\n * entry is only replaced once the `sorting` event is not cancelled.\n */\n public prepareExpression(\n { key, sort: options }: ColumnConfiguration<T>,\n direction?: SortingDirection\n ): SortExpression<T> {\n const expr = this.state.get(key);\n\n return {\n ...(expr ?? this.#createDefaultExpression(key)),\n direction: direction ?? this.#orderBy(expr?.direction),\n ...this.#resolveSortOptions(options),\n } as SortExpression<T>;\n }\n\n /**\n * Whether the UI offers sorting on `column`: it declares `sort` and no\n * manual row order is active (sorting and a manual order are mutually\n * exclusive). The one rule for every sort affordance, built in or a module's.\n */\n public isSortable(column: ColumnConfiguration<T>): boolean {\n return Boolean(column.sort) && !this.#rowReorder?.hasManualOrder;\n }\n\n public reset(key?: Keys<T>) {\n key ? this.state.delete(key) : this.state.clear();\n }\n\n get #rowReorder() {\n // @ts-expect-error - protected member access\n return this.host.stateController.rowReorder as\n | { hasManualOrder: boolean; clearManualOrder(announce?: boolean): void }\n | undefined;\n }\n\n protected _sort(expressions: SortExpression<T> | SortExpression<T>[]) {\n const exprs = asArray(expressions);\n // Applying a sort is mutually exclusive with a manual row order (F5):\n // a real sort (any non-`none` direction) clears it, with an announcement.\n const reorder = this.#rowReorder;\n if (reorder?.hasManualOrder && exprs.some((expr) => expr.direction !== 'none')) {\n reorder.clearManualOrder(true);\n }\n\n for (const expr of exprs) {\n this.#setExpression(expr);\n }\n\n this.host.requestUpdate(PIPELINE);\n }\n\n public sort(expressions: SortExpression<T> | SortExpression<T>[]) {\n this._sort(\n asArray(expressions).map(\n (expr) =>\n ({\n ...(this.state.get(expr.key) ?? this.#createDefaultExpression(expr.key)),\n ...expr,\n }) as SortExpression<T>\n )\n );\n }\n\n public hostConnected() {}\n}\n"]}
|
package/controllers/state.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactiveController } from 'lit';
|
|
2
2
|
import type { GridLocaleKey, LocaleParams } from '../i18n/index.js';
|
|
3
|
-
import { type CellDecoration, type CellDecoratorContext, type CellInteraction, type GridFeatureModule, type PresentedRow, type RowPresenterContext } from '../internal/feature-module.js';
|
|
4
|
-
import type { ActiveNode, GridHost } from '../internal/types.js';
|
|
3
|
+
import { type CellDecoration, type CellDecoratorContext, type CellInteraction, type GridFeatureModule, type PresentedRow, type RowAria, type RowPresenterContext } from '../internal/feature-module.js';
|
|
4
|
+
import type { ActiveNode, ColumnConfiguration, GridHost } from '../internal/types.js';
|
|
5
5
|
import { EditingController } from './editing.js';
|
|
6
6
|
import { ExpansionController } from './expansion.js';
|
|
7
7
|
import { FilterController } from './filter.js';
|
|
@@ -57,12 +57,19 @@ export declare class StateController<T extends object> implements ReactiveContro
|
|
|
57
57
|
* {@link ApexGrid.localize} so components can localize via `this.state`.
|
|
58
58
|
*/
|
|
59
59
|
localize(key: GridLocaleKey, params?: LocaleParams, fallback?: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* Whether `column` holds numbers (`'number'`, `'currency'`, `'rating'`,
|
|
62
|
+
* `'progress'`), so it filters with the number operands and a numeric term.
|
|
63
|
+
* The one numeric-type rule the core filter applies; features that classify
|
|
64
|
+
* columns should read it here rather than keep their own list.
|
|
65
|
+
*/
|
|
66
|
+
isNumericColumn(column: Pick<ColumnConfiguration<T>, 'type'>): boolean;
|
|
60
67
|
get active(): ActiveNode<T>;
|
|
61
68
|
set active(node: ActiveNode<T>);
|
|
62
69
|
get headerRow(): import("../components/header-row.js").default<T>;
|
|
63
70
|
get scrollContainer(): import("../components/virtualizer.js").default;
|
|
64
|
-
get paginator(): import("../
|
|
65
|
-
get toolbar(): import("../
|
|
71
|
+
get paginator(): import("../index.js").ApexGridPaginator<T>;
|
|
72
|
+
get toolbar(): import("../index.js").ApexGridToolbar<T>;
|
|
66
73
|
/**
|
|
67
74
|
* Cumulative pin offsets (in px) keyed by column key. Populated by the
|
|
68
75
|
* {@link GridDOMController} after each layout.
|
|
@@ -77,18 +84,64 @@ export declare class StateController<T extends object> implements ReactiveContro
|
|
|
77
84
|
module<C extends ReactiveController>(id: string): C | undefined;
|
|
78
85
|
/**
|
|
79
86
|
* Runs the post-pipeline row transforms contributed by feature modules
|
|
80
|
-
* implementing {@link RowTransformer}, in
|
|
81
|
-
*
|
|
82
|
-
*
|
|
87
|
+
* implementing {@link RowTransformer}, in ascending
|
|
88
|
+
* {@link RowTransformer.transformOrder} (registration order breaks ties).
|
|
89
|
+
* Returns the input unchanged when no such module is registered, so the
|
|
90
|
+
* community grid path is a no-op pass-through.
|
|
83
91
|
*/
|
|
84
92
|
applyModuleTransforms(rows: T[]): T[];
|
|
93
|
+
/**
|
|
94
|
+
* Whether `row` is a data record, as opposed to a row a feature module
|
|
95
|
+
* synthesized into the view (a group header, a grand-total row). Every
|
|
96
|
+
* consumer that treats the view as records (selection, export, paste, charts,
|
|
97
|
+
* keyboard actions) should skip rows for which this is `false`. A row is
|
|
98
|
+
* synthetic when any {@link RowTransformer} claims it through
|
|
99
|
+
* {@link RowTransformer.isSyntheticRow}. Always `true` for the community grid,
|
|
100
|
+
* which registers no modules, at the cost of one length check.
|
|
101
|
+
*/
|
|
102
|
+
isDataRow(row: T): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* The data records of `rows` (see {@link isDataRow}), in order. Returns `rows`
|
|
105
|
+
* itself, not a copy, when no module synthesizes rows (the community grid).
|
|
106
|
+
*/
|
|
107
|
+
dataRows(rows: ReadonlyArray<T>): ReadonlyArray<T>;
|
|
108
|
+
/**
|
|
109
|
+
* Every data record `rows` (a view) covers, in order: its data rows plus the
|
|
110
|
+
* records a synthesized row hides through
|
|
111
|
+
* {@link RowTransformer.hiddenRecords} (a collapsed group's leaves). This is
|
|
112
|
+
* what Select all selects and a `'view'` export writes. Returns `rows`
|
|
113
|
+
* itself when no module synthesizes rows (the community grid).
|
|
114
|
+
*/
|
|
115
|
+
viewRecords(rows: ReadonlyArray<T>): ReadonlyArray<T>;
|
|
85
116
|
/**
|
|
86
117
|
* Asks feature modules implementing {@link RowPresenter} whether they render
|
|
87
118
|
* the given row as full-width custom content (e.g. a group header). Returns
|
|
88
119
|
* the first non-null result, or `null` when no module owns the row.
|
|
89
120
|
*/
|
|
90
121
|
presentRow(row: T, ctx: RowPresenterContext<T>): PresentedRow | null;
|
|
122
|
+
/**
|
|
123
|
+
* Asks feature modules implementing {@link RowAriaProvider} for ARIA
|
|
124
|
+
* tree/expansion semantics on a normal (cell-rendered) row — e.g. pivoting's
|
|
125
|
+
* expandable parent rows. Returns the first non-null result, or `null`.
|
|
126
|
+
*/
|
|
127
|
+
describeRow(row: T, ctx: RowPresenterContext<T>): RowAria | null;
|
|
128
|
+
/**
|
|
129
|
+
* The coordinate-hint label a module gives a row ({@link CoordinateLabeler}),
|
|
130
|
+
* `null` for none, or `undefined` when no module labels rows (the gutter then
|
|
131
|
+
* shows the view position). Only asked while `coordinateHints` is on.
|
|
132
|
+
*/
|
|
133
|
+
rowCoordinate(row: T): string | null | undefined;
|
|
134
|
+
/** The coordinate-hint letter a module gives a column; see {@link rowCoordinate}. */
|
|
135
|
+
columnCoordinate(key: string): string | null | undefined;
|
|
91
136
|
get decorationVersion(): number;
|
|
137
|
+
/**
|
|
138
|
+
* Monotonic token the grid bumps once per data pipeline run, forwarded to
|
|
139
|
+
* each body row and cell, so a cell whose output reads more than its own
|
|
140
|
+
* value (a `cellTemplate` reading other row fields, the tree group cell's
|
|
141
|
+
* chevron) re-renders after an edit, a data change or a tree toggle,
|
|
142
|
+
* although its own value binding did not change.
|
|
143
|
+
*/
|
|
144
|
+
dataVersion: number;
|
|
92
145
|
/**
|
|
93
146
|
* Signals that {@link CellDecorator} output may have changed. Bumps the
|
|
94
147
|
* {@link decorationVersion} and requests a host update so cells re-run their
|
|
@@ -124,10 +177,12 @@ export declare class StateController<T extends object> implements ReactiveContro
|
|
|
124
177
|
serializeModuleState(): Record<string, unknown>;
|
|
125
178
|
/**
|
|
126
179
|
* Dispatches previously-serialized state back to the matching feature modules
|
|
127
|
-
* (by id) that implement {@link SerializableModule}
|
|
128
|
-
*
|
|
180
|
+
* (by id) that implement {@link SerializableModule}, in registration order.
|
|
181
|
+
* Returns the ids in `data` that no registered module consumed, so the caller
|
|
182
|
+
* can report them instead of counting them as applied. Used by
|
|
183
|
+
* `ApexGrid.setState`.
|
|
129
184
|
*/
|
|
130
|
-
restoreModuleState(data: Record<string, unknown> | undefined):
|
|
185
|
+
restoreModuleState(data: Record<string, unknown> | undefined): string[];
|
|
131
186
|
hostConnected(): void;
|
|
132
187
|
hostUpdate(): void;
|
|
133
188
|
}
|
package/controllers/state.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext } from '@lit/context';
|
|
2
|
-
import { isCellDecorator, isCellInteractionHandler, isColumnMenuProvider, isRowPresenter, isRowTransformer, isSerializableModule, } from '../internal/feature-module.js';
|
|
2
|
+
import { isCellDecorator, isCellInteractionHandler, isColumnMenuProvider, isCoordinateLabeler, isRowAriaProvider, isRowPresenter, isRowTransformer, isSerializableModule, } from '../internal/feature-module.js';
|
|
3
|
+
import { isNumericColumn } from '../internal/utils.js';
|
|
3
4
|
import { EditingController } from './editing.js';
|
|
4
5
|
import { ExpansionController } from './expansion.js';
|
|
5
6
|
import { FilterController } from './filter.js';
|
|
@@ -28,6 +29,9 @@ export class StateController {
|
|
|
28
29
|
localize(key, params, fallback) {
|
|
29
30
|
return this.host.localize(key, params, fallback);
|
|
30
31
|
}
|
|
32
|
+
isNumericColumn(column) {
|
|
33
|
+
return isNumericColumn(column);
|
|
34
|
+
}
|
|
31
35
|
get active() {
|
|
32
36
|
return this.navigation.active;
|
|
33
37
|
}
|
|
@@ -56,7 +60,10 @@ export class StateController {
|
|
|
56
60
|
this.modules = new Map();
|
|
57
61
|
this.announcement = '';
|
|
58
62
|
this.#announceToken = 0;
|
|
63
|
+
this.#transformers = [];
|
|
64
|
+
this.#synthesizers = [];
|
|
59
65
|
this.#decorationVersion = 0;
|
|
66
|
+
this.dataVersion = 0;
|
|
60
67
|
this.host.addController(this);
|
|
61
68
|
this.init();
|
|
62
69
|
}
|
|
@@ -79,19 +86,61 @@ export class StateController {
|
|
|
79
86
|
continue;
|
|
80
87
|
this.modules.set(module.id, module.create(this.host, this));
|
|
81
88
|
}
|
|
89
|
+
if (this.modules.size) {
|
|
90
|
+
const transformers = [];
|
|
91
|
+
for (const controller of this.modules.values()) {
|
|
92
|
+
if (isRowTransformer(controller))
|
|
93
|
+
transformers.push(controller);
|
|
94
|
+
}
|
|
95
|
+
transformers.sort((a, b) => (a.transformOrder ?? 0) - (b.transformOrder ?? 0));
|
|
96
|
+
this.#transformers = transformers;
|
|
97
|
+
this.#synthesizers = transformers.filter((t) => typeof t.isSyntheticRow === 'function');
|
|
98
|
+
}
|
|
82
99
|
}
|
|
100
|
+
#transformers;
|
|
101
|
+
#synthesizers;
|
|
83
102
|
module(id) {
|
|
84
103
|
return this.modules.get(id);
|
|
85
104
|
}
|
|
86
105
|
applyModuleTransforms(rows) {
|
|
87
106
|
let result = rows;
|
|
88
|
-
for (const
|
|
89
|
-
|
|
90
|
-
result = controller.processRows(result);
|
|
91
|
-
}
|
|
107
|
+
for (const transformer of this.#transformers) {
|
|
108
|
+
result = transformer.processRows(result);
|
|
92
109
|
}
|
|
93
110
|
return result;
|
|
94
111
|
}
|
|
112
|
+
isDataRow(row) {
|
|
113
|
+
for (const transformer of this.#synthesizers) {
|
|
114
|
+
if (transformer.isSyntheticRow(row))
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
dataRows(rows) {
|
|
120
|
+
if (this.#synthesizers.length === 0)
|
|
121
|
+
return rows;
|
|
122
|
+
return rows.filter((row) => this.isDataRow(row));
|
|
123
|
+
}
|
|
124
|
+
viewRecords(rows) {
|
|
125
|
+
if (this.#synthesizers.length === 0)
|
|
126
|
+
return rows;
|
|
127
|
+
const out = [];
|
|
128
|
+
for (const row of rows) {
|
|
129
|
+
if (this.isDataRow(row)) {
|
|
130
|
+
out.push(row);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const transformer of this.#synthesizers) {
|
|
134
|
+
const hidden = transformer.hiddenRecords?.(row);
|
|
135
|
+
if (!hidden?.length)
|
|
136
|
+
continue;
|
|
137
|
+
for (const record of hidden)
|
|
138
|
+
out.push(record);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
95
144
|
presentRow(row, ctx) {
|
|
96
145
|
for (const controller of this.modules.values()) {
|
|
97
146
|
if (isRowPresenter(controller)) {
|
|
@@ -102,6 +151,36 @@ export class StateController {
|
|
|
102
151
|
}
|
|
103
152
|
return null;
|
|
104
153
|
}
|
|
154
|
+
describeRow(row, ctx) {
|
|
155
|
+
for (const controller of this.modules.values()) {
|
|
156
|
+
if (isRowAriaProvider(controller)) {
|
|
157
|
+
const aria = controller.describeRow(row, ctx);
|
|
158
|
+
if (aria)
|
|
159
|
+
return aria;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
rowCoordinate(row) {
|
|
165
|
+
for (const controller of this.modules.values()) {
|
|
166
|
+
if (isCoordinateLabeler(controller)) {
|
|
167
|
+
const label = controller.rowCoordinate(row);
|
|
168
|
+
if (label !== undefined)
|
|
169
|
+
return label;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
columnCoordinate(key) {
|
|
175
|
+
for (const controller of this.modules.values()) {
|
|
176
|
+
if (isCoordinateLabeler(controller)) {
|
|
177
|
+
const label = controller.columnCoordinate(key);
|
|
178
|
+
if (label !== undefined)
|
|
179
|
+
return label;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
105
184
|
#decorationVersion;
|
|
106
185
|
get decorationVersion() {
|
|
107
186
|
return this.#decorationVersion;
|
|
@@ -149,12 +228,13 @@ export class StateController {
|
|
|
149
228
|
}
|
|
150
229
|
restoreModuleState(data) {
|
|
151
230
|
if (!data)
|
|
152
|
-
return;
|
|
231
|
+
return [];
|
|
153
232
|
for (const [id, controller] of this.modules) {
|
|
154
233
|
if (isSerializableModule(controller) && Object.hasOwn(data, id)) {
|
|
155
234
|
controller.restoreState(data[id]);
|
|
156
235
|
}
|
|
157
236
|
}
|
|
237
|
+
return Object.keys(data).filter((id) => !isSerializableModule(this.modules.get(id)));
|
|
158
238
|
}
|
|
159
239
|
hostConnected() { }
|
|
160
240
|
hostUpdate() {
|