apex-grid 1.1.0 → 3.0.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/LICENSE +76 -5
- package/README.md +523 -10
- package/components/cell.d.ts +39 -0
- package/components/cell.js +334 -5
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +7 -5
- package/components/filter-row.js +151 -68
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +955 -4
- package/components/grid.js +412 -40
- package/components/grid.js.map +1 -1
- package/components/header-row.d.ts +21 -1
- package/components/header-row.js +140 -7
- package/components/header-row.js.map +1 -1
- package/components/header.d.ts +7 -0
- package/components/header.js +151 -31
- package/components/header.js.map +1 -1
- package/components/paginator.d.ts +56 -0
- package/components/paginator.js +148 -0
- package/components/paginator.js.map +1 -0
- package/components/row.d.ts +21 -2
- package/components/row.js +185 -10
- package/components/row.js.map +1 -1
- package/components/toolbar.d.ts +60 -0
- package/components/toolbar.js +259 -0
- package/components/toolbar.js.map +1 -0
- package/components/virtualizer.js +1 -1
- package/components/virtualizer.js.map +1 -1
- package/controllers/data-operation.d.ts +14 -0
- package/controllers/data-operation.js +19 -2
- package/controllers/data-operation.js.map +1 -1
- package/controllers/dom.d.ts +37 -1
- package/controllers/dom.js +176 -9
- package/controllers/dom.js.map +1 -1
- package/controllers/editing.d.ts +130 -0
- package/controllers/editing.js +197 -0
- package/controllers/editing.js.map +1 -0
- package/controllers/expansion.d.ts +68 -0
- package/controllers/expansion.js +126 -0
- package/controllers/expansion.js.map +1 -0
- package/controllers/navigation.d.ts +17 -6
- package/controllers/navigation.js +24 -8
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.d.ts +102 -0
- package/controllers/pagination.js +106 -0
- package/controllers/pagination.js.map +1 -0
- package/controllers/reorder.d.ts +78 -0
- package/controllers/reorder.js +124 -0
- package/controllers/reorder.js.map +1 -0
- package/controllers/selection.d.ts +109 -0
- package/controllers/selection.js +168 -0
- package/controllers/selection.js.map +1 -0
- package/controllers/sort.js +28 -0
- package/controllers/sort.js.map +1 -1
- package/controllers/state.d.ts +47 -1
- package/controllers/state.js +48 -1
- package/controllers/state.js.map +1 -1
- package/controllers/tree.d.ts +87 -0
- package/controllers/tree.js +0 -0
- package/controllers/tree.js.map +1 -0
- package/custom-elements.json +6491 -1355
- package/define.js.map +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +77 -14
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/main.js +4 -4
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/assets/style.css +3 -3
- package/docs/classes/ApexGrid.html +320 -24
- package/docs/functions/setup.html +16 -0
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +543 -9
- package/docs/interfaces/ApexCellValueChangedEvent.html +11 -0
- package/docs/interfaces/ApexCellValueChangingEvent.html +13 -0
- package/docs/interfaces/ApexColumnMovedEvent.html +8 -0
- package/docs/interfaces/ApexColumnMovingEvent.html +11 -0
- package/docs/interfaces/ApexColumnPinnedEvent.html +6 -0
- package/docs/interfaces/ApexColumnPinningEvent.html +8 -0
- package/docs/interfaces/ApexDetailContext.html +8 -0
- package/docs/interfaces/ApexFilteredEvent.html +4 -4
- package/docs/interfaces/ApexFilteringEvent.html +4 -4
- package/docs/interfaces/ApexGridEventMap.html +60 -9
- package/docs/interfaces/ApexHeaderContext.html +4 -4
- package/docs/interfaces/ApexPageChangedEvent.html +10 -0
- package/docs/interfaces/ApexPageChangingEvent.html +10 -0
- package/docs/interfaces/ApexQuickFilterChangedEvent.html +4 -0
- package/docs/interfaces/ApexQuickFilterChangingEvent.html +6 -0
- package/docs/interfaces/ApexRowEditEndedEvent.html +6 -0
- package/docs/interfaces/ApexRowEditStartedEvent.html +4 -0
- package/docs/interfaces/ApexRowExpandedEvent.html +8 -0
- package/docs/interfaces/ApexRowExpandingEvent.html +11 -0
- package/docs/interfaces/ApexRowSelectedEvent.html +8 -0
- package/docs/interfaces/ApexRowSelectingEvent.html +11 -0
- package/docs/interfaces/ApexTreeRowExpandedEvent.html +8 -0
- package/docs/interfaces/ApexTreeRowExpandingEvent.html +10 -0
- package/docs/interfaces/BaseApexCellContext.html +12 -6
- package/docs/interfaces/BaseApexEditorContext.html +19 -0
- package/docs/interfaces/BaseColumnConfiguration.html +88 -14
- package/docs/interfaces/BaseColumnSortConfiguration.html +4 -4
- package/docs/interfaces/BaseFilterExpression.html +5 -5
- package/docs/interfaces/BaseSortExpression.html +4 -4
- package/docs/interfaces/CSVExportOptions.html +22 -0
- package/docs/interfaces/ColumnFilterConfiguration.html +3 -3
- package/docs/interfaces/DataPipelineConfiguration.html +13 -4
- package/docs/interfaces/ExportFormat.html +10 -0
- package/docs/interfaces/ExportOptions.html +15 -0
- package/docs/interfaces/GridEditingConfiguration.html +10 -0
- package/docs/interfaces/GridExpansionConfiguration.html +15 -0
- package/docs/interfaces/GridSelectionConfiguration.html +11 -0
- package/docs/interfaces/GridSortConfiguration.html +4 -4
- package/docs/interfaces/GridTreeConfiguration.html +33 -0
- package/docs/interfaces/PaginationConfiguration.html +18 -0
- package/docs/interfaces/PaginationState.html +10 -0
- package/docs/media/LICENSE +80 -0
- package/docs/media/_tokens.scss +106 -0
- package/docs/media/package.json +85 -0
- package/docs/modules.html +1 -1
- package/docs/types/ApexCellContext.html +2 -2
- package/docs/types/ApexEditorContext.html +2 -0
- package/docs/types/BasePropertyType.html +2 -2
- package/docs/types/BaseSortComparer.html +2 -2
- package/docs/types/ColumnConfiguration.html +2 -2
- package/docs/types/ColumnDropPosition.html +2 -0
- package/docs/types/ColumnSortConfiguration.html +2 -2
- package/docs/types/DataPipelineHook.html +2 -2
- package/docs/types/DataPipelineParams.html +5 -5
- package/docs/types/DataType.html +47 -2
- package/docs/types/EditMode.html +6 -0
- package/docs/types/EditTrigger.html +4 -0
- package/docs/types/ExportCellValue.html +5 -0
- package/docs/types/ExportSource.html +8 -0
- package/docs/types/FilterCriteria.html +2 -2
- package/docs/types/FilterExpression.html +2 -2
- package/docs/types/Keys.html +2 -2
- package/docs/types/PaginationMode.html +6 -0
- package/docs/types/PinPosition.html +5 -0
- package/docs/types/PropertyType.html +2 -2
- package/docs/types/SelectionMode.html +7 -0
- package/docs/types/SortComparer.html +2 -2
- package/docs/types/SortExpression.html +2 -2
- package/docs/types/SortState.html +2 -2
- package/docs/types/SortingDirection.html +1 -1
- package/index.d.ts +5 -2
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/internal/column-types.d.ts +94 -0
- package/internal/column-types.js +428 -0
- package/internal/column-types.js.map +1 -0
- package/internal/export.d.ts +114 -0
- package/internal/export.js +122 -0
- package/internal/export.js.map +1 -0
- package/internal/feature-module.d.ts +27 -0
- package/internal/feature-module.js +2 -0
- package/internal/feature-module.js.map +1 -0
- package/internal/flip.d.ts +80 -0
- package/internal/flip.js +52 -0
- package/internal/flip.js.map +1 -0
- package/internal/icons.d.ts +31 -0
- package/internal/icons.js +145 -0
- package/internal/icons.js.map +1 -0
- package/internal/index.d.ts +20 -0
- package/internal/index.js +6 -0
- package/internal/index.js.map +1 -0
- package/internal/tags.d.ts +2 -0
- package/internal/tags.js +2 -0
- package/internal/tags.js.map +1 -1
- package/internal/types.d.ts +473 -3
- package/internal/types.js.map +1 -1
- package/internal/utils.d.ts +24 -1
- package/internal/utils.js +48 -7
- package/internal/utils.js.map +1 -1
- package/operations/filter/tree.d.ts +1 -1
- package/operations/filter/types.js.map +1 -1
- package/operations/pagination.d.ts +19 -0
- package/operations/pagination.js +12 -0
- package/operations/pagination.js.map +1 -0
- package/operations/quick-filter.d.ts +21 -0
- package/operations/quick-filter.js +26 -0
- package/operations/quick-filter.js.map +1 -0
- package/operations/sort/types.js.map +1 -1
- package/package.json +10 -5
- package/setup.d.ts +51 -0
- package/setup.js +31 -0
- package/setup.js.map +1 -0
- package/styles/_checkbox.css.js +3 -0
- package/styles/_checkbox.css.js.map +1 -0
- package/styles/_tokens.css.js +3 -0
- package/styles/_tokens.css.js.map +1 -0
- 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 +3 -0
- package/styles/body-cell/cell-renderers.css.js.map +1 -0
- package/styles/body-row/body-row.css.js +1 -1
- package/styles/body-row/body-row.css.js.map +1 -1
- 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 +3 -0
- package/styles/grid/grid.css.js.map +1 -0
- 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.d.ts +1 -0
- package/styles/paginator/paginator.css.js +3 -0
- package/styles/paginator/paginator.css.js.map +1 -0
- package/styles/toolbar/toolbar.css.d.ts +1 -0
- package/styles/toolbar/toolbar.css.js +3 -0
- package/styles/toolbar/toolbar.css.js.map +1 -0
- package/styles.css +17 -0
- package/internal/icon-registry.d.ts +0 -1
- package/internal/icon-registry.js +0 -29
- package/internal/icon-registry.js.map +0 -1
- package/internal/theming.d.ts +0 -34
- package/internal/theming.js +0 -123
- package/internal/theming.js.map +0 -1
- package/styles/grid/themes/light/grid.bootstrap.css.js +0 -3
- package/styles/grid/themes/light/grid.bootstrap.css.js.map +0 -1
- package/styles/grid/themes/light/grid.fluent.css.js +0 -3
- package/styles/grid/themes/light/grid.fluent.css.js.map +0 -1
- package/styles/grid/themes/light/grid.indigo.css.js +0 -3
- package/styles/grid/themes/light/grid.indigo.css.js.map +0 -1
- package/styles/grid/themes/light/grid.material.css.js +0 -3
- package/styles/grid/themes/light/grid.material.css.js.map +0 -1
- /package/styles/{grid/themes/light/grid.bootstrap.css.d.ts → _checkbox.css.d.ts} +0 -0
- /package/styles/{grid/themes/light/grid.fluent.css.d.ts → _tokens.css.d.ts} +0 -0
- /package/styles/{grid/themes/light/grid.indigo.css.d.ts → body-cell/cell-renderers.css.d.ts} +0 -0
- /package/styles/grid/{themes/light/grid.material.css.d.ts → grid.css.d.ts} +0 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
export const DEFAULT_SELECTION_CONFIG = Object.freeze({
|
|
2
|
+
enabled: false,
|
|
3
|
+
mode: 'multiple',
|
|
4
|
+
showCheckboxColumn: false,
|
|
5
|
+
});
|
|
6
|
+
export class SelectionController {
|
|
7
|
+
constructor(host) {
|
|
8
|
+
this.host = host;
|
|
9
|
+
this.selected = new Set();
|
|
10
|
+
this.anchor = null;
|
|
11
|
+
this.host.addController(this);
|
|
12
|
+
}
|
|
13
|
+
hostConnected() { }
|
|
14
|
+
get enabled() {
|
|
15
|
+
return Boolean(this.host.selection?.enabled);
|
|
16
|
+
}
|
|
17
|
+
get mode() {
|
|
18
|
+
return this.host.selection?.mode ?? DEFAULT_SELECTION_CONFIG.mode;
|
|
19
|
+
}
|
|
20
|
+
get showCheckboxColumn() {
|
|
21
|
+
return (this.enabled &&
|
|
22
|
+
(this.host.selection?.showCheckboxColumn ?? DEFAULT_SELECTION_CONFIG.showCheckboxColumn));
|
|
23
|
+
}
|
|
24
|
+
isSelected(row) {
|
|
25
|
+
return this.selected.has(row);
|
|
26
|
+
}
|
|
27
|
+
selectedRows() {
|
|
28
|
+
return Array.from(this.selected);
|
|
29
|
+
}
|
|
30
|
+
allSelected() {
|
|
31
|
+
const view = this.host.dataView;
|
|
32
|
+
if (view.length === 0)
|
|
33
|
+
return false;
|
|
34
|
+
return view.every((row) => this.selected.has(row));
|
|
35
|
+
}
|
|
36
|
+
someSelected() {
|
|
37
|
+
if (this.selected.size === 0)
|
|
38
|
+
return false;
|
|
39
|
+
if (this.allSelected())
|
|
40
|
+
return false;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
async toggleRow(row) {
|
|
44
|
+
if (!this.enabled)
|
|
45
|
+
return false;
|
|
46
|
+
const next = new Set(this.selected);
|
|
47
|
+
if (next.has(row)) {
|
|
48
|
+
next.delete(row);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
if (this.mode === 'single')
|
|
52
|
+
next.clear();
|
|
53
|
+
next.add(row);
|
|
54
|
+
}
|
|
55
|
+
this.anchor = next.has(row) ? row : null;
|
|
56
|
+
return this.#commit(next);
|
|
57
|
+
}
|
|
58
|
+
async selectRow(row) {
|
|
59
|
+
if (!this.enabled)
|
|
60
|
+
return false;
|
|
61
|
+
const next = new Set(this.mode === 'single' ? [] : this.selected);
|
|
62
|
+
next.add(row);
|
|
63
|
+
this.anchor = row;
|
|
64
|
+
return this.#commit(next);
|
|
65
|
+
}
|
|
66
|
+
async deselectRow(row) {
|
|
67
|
+
if (!this.enabled)
|
|
68
|
+
return false;
|
|
69
|
+
if (!this.selected.has(row))
|
|
70
|
+
return true;
|
|
71
|
+
const next = new Set(this.selected);
|
|
72
|
+
next.delete(row);
|
|
73
|
+
return this.#commit(next);
|
|
74
|
+
}
|
|
75
|
+
async additiveToggle(row) {
|
|
76
|
+
if (!this.enabled)
|
|
77
|
+
return false;
|
|
78
|
+
if (this.mode === 'single')
|
|
79
|
+
return this.toggleRow(row);
|
|
80
|
+
const next = new Set(this.selected);
|
|
81
|
+
if (next.has(row)) {
|
|
82
|
+
next.delete(row);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
next.add(row);
|
|
86
|
+
}
|
|
87
|
+
this.anchor = next.has(row) ? row : this.anchor;
|
|
88
|
+
return this.#commit(next);
|
|
89
|
+
}
|
|
90
|
+
async rangeToggle(row) {
|
|
91
|
+
if (!this.enabled)
|
|
92
|
+
return false;
|
|
93
|
+
if (this.mode === 'single' || !this.anchor) {
|
|
94
|
+
return this.selectRow(row);
|
|
95
|
+
}
|
|
96
|
+
const pageItems = this.host.pageItems;
|
|
97
|
+
const startIdx = pageItems.indexOf(this.anchor);
|
|
98
|
+
const endIdx = pageItems.indexOf(row);
|
|
99
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
100
|
+
return this.selectRow(row);
|
|
101
|
+
}
|
|
102
|
+
const [lo, hi] = startIdx < endIdx ? [startIdx, endIdx] : [endIdx, startIdx];
|
|
103
|
+
const next = new Set(this.selected);
|
|
104
|
+
for (let i = lo; i <= hi; i++) {
|
|
105
|
+
next.add(pageItems[i]);
|
|
106
|
+
}
|
|
107
|
+
return this.#commit(next);
|
|
108
|
+
}
|
|
109
|
+
async selectAll() {
|
|
110
|
+
if (!this.enabled || this.mode === 'single')
|
|
111
|
+
return false;
|
|
112
|
+
const next = new Set(this.host.dataView);
|
|
113
|
+
return this.#commit(next);
|
|
114
|
+
}
|
|
115
|
+
async clear() {
|
|
116
|
+
if (this.selected.size === 0)
|
|
117
|
+
return true;
|
|
118
|
+
return this.#commit(new Set());
|
|
119
|
+
}
|
|
120
|
+
async replaceSelection(rows) {
|
|
121
|
+
if (!this.enabled)
|
|
122
|
+
return false;
|
|
123
|
+
const next = new Set(this.mode === 'single' ? rows.slice(0, 1) : rows);
|
|
124
|
+
return this.#commit(next);
|
|
125
|
+
}
|
|
126
|
+
async #commit(next) {
|
|
127
|
+
const added = [];
|
|
128
|
+
const removed = [];
|
|
129
|
+
for (const row of next) {
|
|
130
|
+
if (!this.selected.has(row))
|
|
131
|
+
added.push(row);
|
|
132
|
+
}
|
|
133
|
+
for (const row of this.selected) {
|
|
134
|
+
if (!next.has(row))
|
|
135
|
+
removed.push(row);
|
|
136
|
+
}
|
|
137
|
+
if (added.length === 0 && removed.length === 0)
|
|
138
|
+
return true;
|
|
139
|
+
const proceed = this.host.emitEvent('rowSelecting', {
|
|
140
|
+
detail: {
|
|
141
|
+
added,
|
|
142
|
+
removed,
|
|
143
|
+
current: Array.from(this.selected),
|
|
144
|
+
next: Array.from(next),
|
|
145
|
+
},
|
|
146
|
+
cancelable: true,
|
|
147
|
+
});
|
|
148
|
+
if (!proceed)
|
|
149
|
+
return false;
|
|
150
|
+
this.selected = next;
|
|
151
|
+
this.host.requestUpdate();
|
|
152
|
+
const total = this.selected.size;
|
|
153
|
+
if (total === 0) {
|
|
154
|
+
this.host.announce('Selection cleared');
|
|
155
|
+
}
|
|
156
|
+
else if (added.length === 1 && removed.length === 0 && total === 1) {
|
|
157
|
+
this.host.announce('1 row selected');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
this.host.announce(`${total} rows selected`);
|
|
161
|
+
}
|
|
162
|
+
this.host.emitEvent('rowSelected', {
|
|
163
|
+
detail: { added, removed, selected: Array.from(this.selected) },
|
|
164
|
+
});
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +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('Selection cleared');\n } else if (added.length === 1 && removed.length === 0 && total === 1) {\n this.host.announce('1 row selected');\n } else {\n this.host.announce(`${total} rows selected`);\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.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PIPELINE } from '../internal/constants.js';
|
|
2
|
+
import { awaitChildUpdates, playKeyedFlip } from '../internal/flip.js';
|
|
2
3
|
import { asArray } from '../internal/utils.js';
|
|
3
4
|
export class SortController {
|
|
4
5
|
constructor(host) {
|
|
@@ -63,10 +64,37 @@ export class SortController {
|
|
|
63
64
|
if (!this.#isMultipleSort) {
|
|
64
65
|
this.reset();
|
|
65
66
|
}
|
|
67
|
+
const beforeRects = this.#captureRowRects();
|
|
66
68
|
this._sort(expression);
|
|
67
69
|
await this.host.updateComplete;
|
|
70
|
+
await awaitChildUpdates(this.host.rows);
|
|
71
|
+
this.#playRowFlip(beforeRects);
|
|
72
|
+
this.#announce(expression, column);
|
|
68
73
|
this.#emitSortedEvent(expression);
|
|
69
74
|
}
|
|
75
|
+
#announce(expression, column) {
|
|
76
|
+
const label = column.headerText ?? String(column.key);
|
|
77
|
+
const message = expression.direction === 'none'
|
|
78
|
+
? `Sort cleared on ${label}`
|
|
79
|
+
: `Sorted by ${label} ${expression.direction}`;
|
|
80
|
+
this.host.announce(message);
|
|
81
|
+
}
|
|
82
|
+
#captureRowRects() {
|
|
83
|
+
const entries = [];
|
|
84
|
+
for (const row of this.host.rows) {
|
|
85
|
+
const el = row;
|
|
86
|
+
entries.push({ key: row.data, rect: el.getBoundingClientRect() });
|
|
87
|
+
}
|
|
88
|
+
return entries;
|
|
89
|
+
}
|
|
90
|
+
#playRowFlip(before) {
|
|
91
|
+
const rows = this.host.rows;
|
|
92
|
+
const byData = new Map();
|
|
93
|
+
for (const row of rows) {
|
|
94
|
+
byData.set(row.data, row);
|
|
95
|
+
}
|
|
96
|
+
playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');
|
|
97
|
+
}
|
|
70
98
|
prepareExpression({ key, sort: options }) {
|
|
71
99
|
if (this.state.has(key)) {
|
|
72
100
|
const expr = this.state.get(key);
|
package/controllers/sort.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/controllers/sort.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
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>) {\n const expression = this.prepareExpression(column);\n\n if (!this.#emitSortingEvent(expression)) {\n return;\n }\n\n if (!this.#isMultipleSort) {\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 ? `Sort cleared on ${label}`\n : `Sorted by ${label} ${expression.direction}`;\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 protected _sort(expressions: SortExpression<T> | SortExpression<T>[]) {\n for (const expr of asArray(expressions)) {\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"]}
|
package/controllers/state.d.ts
CHANGED
|
@@ -1,21 +1,67 @@
|
|
|
1
1
|
import type { ReactiveController } from 'lit';
|
|
2
|
+
import type { GridFeatureModule } from '../internal/feature-module.js';
|
|
2
3
|
import type { ActiveNode, GridHost } from '../internal/types.js';
|
|
4
|
+
import { EditingController } from './editing.js';
|
|
5
|
+
import { ExpansionController } from './expansion.js';
|
|
3
6
|
import { FilterController } from './filter.js';
|
|
4
7
|
import { NavigationController } from './navigation.js';
|
|
8
|
+
import { PaginationController } from './pagination.js';
|
|
9
|
+
import { ReorderController } from './reorder.js';
|
|
5
10
|
import { ResizeController } from './resize.js';
|
|
11
|
+
import { SelectionController } from './selection.js';
|
|
6
12
|
import { SortController } from './sort.js';
|
|
13
|
+
import { TreeController } from './tree.js';
|
|
7
14
|
export declare class StateController<T extends object> implements ReactiveController {
|
|
15
|
+
#private;
|
|
8
16
|
host: GridHost<T>;
|
|
17
|
+
private extraModules;
|
|
9
18
|
sorting: SortController<T>;
|
|
10
19
|
filtering: FilterController<T>;
|
|
11
20
|
navigation: NavigationController<T>;
|
|
12
21
|
resizing: ResizeController<T>;
|
|
22
|
+
pagination: PaginationController<T>;
|
|
23
|
+
reordering: ReorderController<T>;
|
|
24
|
+
editing: EditingController<T>;
|
|
25
|
+
selection: SelectionController<T>;
|
|
26
|
+
expansion: ExpansionController<T>;
|
|
27
|
+
tree: TreeController<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Optional feature controllers contributed by {@link GridFeatureModule}s,
|
|
30
|
+
* keyed by module id. Empty for the community `<apex-grid>` element; populated
|
|
31
|
+
* by derived grids (e.g. `@apexcharts/grid-enterprise`) that pass modules to
|
|
32
|
+
* the constructor.
|
|
33
|
+
*/
|
|
34
|
+
readonly modules: Map<string, ReactiveController>;
|
|
35
|
+
/**
|
|
36
|
+
* Current message in the grid's polite live region. Bound by the host's
|
|
37
|
+
* `renderLiveRegion()` template; mutated through {@link setAnnouncement}
|
|
38
|
+
* so screen readers re-announce on every change.
|
|
39
|
+
*/
|
|
40
|
+
announcement: string;
|
|
41
|
+
/**
|
|
42
|
+
* Updates the polite live region's text. Repeats are forced to fire by
|
|
43
|
+
* appending a zero-width space — screen readers ignore unchanged content,
|
|
44
|
+
* so two identical sort announcements wouldn't otherwise be read aloud.
|
|
45
|
+
*/
|
|
46
|
+
setAnnouncement(message: string): void;
|
|
13
47
|
get active(): ActiveNode<T>;
|
|
14
48
|
set active(node: ActiveNode<T>);
|
|
15
49
|
get headerRow(): import("../components/header-row.js").default<T>;
|
|
16
50
|
get scrollContainer(): import("../components/virtualizer.js").default;
|
|
17
|
-
|
|
51
|
+
get paginator(): import("../components/paginator.js").default<T>;
|
|
52
|
+
get toolbar(): import("../components/toolbar.js").default<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Cumulative pin offsets (in px) keyed by column key. Populated by the
|
|
55
|
+
* {@link GridDOMController} after each layout.
|
|
56
|
+
*/
|
|
57
|
+
get pinOffsets(): Map<unknown, number>;
|
|
58
|
+
constructor(host: GridHost<T>, extraModules?: ReadonlyArray<GridFeatureModule<T>>);
|
|
18
59
|
protected init(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Look up a feature controller contributed by a {@link GridFeatureModule},
|
|
62
|
+
* by its module id. Returns `undefined` when no such module is registered.
|
|
63
|
+
*/
|
|
64
|
+
module<C extends ReactiveController>(id: string): C | undefined;
|
|
19
65
|
hostConnected(): void;
|
|
20
66
|
hostUpdate(): void;
|
|
21
67
|
}
|
package/controllers/state.js
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import { createContext } from '@lit/context';
|
|
2
|
+
import { EditingController } from './editing.js';
|
|
3
|
+
import { ExpansionController } from './expansion.js';
|
|
2
4
|
import { FilterController } from './filter.js';
|
|
3
5
|
import { NavigationController } from './navigation.js';
|
|
6
|
+
import { PaginationController } from './pagination.js';
|
|
7
|
+
import { ReorderController } from './reorder.js';
|
|
4
8
|
import { ResizeController } from './resize.js';
|
|
9
|
+
import { SelectionController } from './selection.js';
|
|
5
10
|
import { SortController } from './sort.js';
|
|
11
|
+
import { TreeController } from './tree.js';
|
|
6
12
|
export class StateController {
|
|
13
|
+
#announceToken;
|
|
14
|
+
setAnnouncement(message) {
|
|
15
|
+
if (!message) {
|
|
16
|
+
this.announcement = '';
|
|
17
|
+
this.host.requestUpdate();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.#announceToken = (this.#announceToken + 1) % 2;
|
|
21
|
+
this.announcement = this.#announceToken ? message : `${message} `;
|
|
22
|
+
this.host.requestUpdate();
|
|
23
|
+
}
|
|
7
24
|
get active() {
|
|
8
25
|
return this.navigation.active;
|
|
9
26
|
}
|
|
@@ -16,8 +33,22 @@ export class StateController {
|
|
|
16
33
|
get scrollContainer() {
|
|
17
34
|
return this.host.scrollContainer;
|
|
18
35
|
}
|
|
19
|
-
|
|
36
|
+
get paginator() {
|
|
37
|
+
return this.host.paginator;
|
|
38
|
+
}
|
|
39
|
+
get toolbar() {
|
|
40
|
+
return this.host.toolbar;
|
|
41
|
+
}
|
|
42
|
+
get pinOffsets() {
|
|
43
|
+
const dom = this.host.DOM;
|
|
44
|
+
return dom?.pinOffsets ?? new Map();
|
|
45
|
+
}
|
|
46
|
+
constructor(host, extraModules = []) {
|
|
20
47
|
this.host = host;
|
|
48
|
+
this.extraModules = extraModules;
|
|
49
|
+
this.modules = new Map();
|
|
50
|
+
this.announcement = '';
|
|
51
|
+
this.#announceToken = 0;
|
|
21
52
|
this.host.addController(this);
|
|
22
53
|
this.init();
|
|
23
54
|
}
|
|
@@ -26,11 +57,27 @@ export class StateController {
|
|
|
26
57
|
this.filtering = new FilterController(this.host);
|
|
27
58
|
this.navigation = new NavigationController(this.host);
|
|
28
59
|
this.resizing = new ResizeController(this.host);
|
|
60
|
+
this.pagination = new PaginationController(this.host);
|
|
61
|
+
this.reordering = new ReorderController(this.host);
|
|
62
|
+
this.editing = new EditingController(this.host);
|
|
63
|
+
this.selection = new SelectionController(this.host);
|
|
64
|
+
this.expansion = new ExpansionController(this.host);
|
|
65
|
+
this.tree = new TreeController(this.host);
|
|
66
|
+
for (const module of this.extraModules) {
|
|
67
|
+
if (this.modules.has(module.id))
|
|
68
|
+
continue;
|
|
69
|
+
this.modules.set(module.id, module.create(this.host));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
module(id) {
|
|
73
|
+
return this.modules.get(id);
|
|
29
74
|
}
|
|
30
75
|
hostConnected() { }
|
|
31
76
|
hostUpdate() {
|
|
32
77
|
this.headerRow?.requestUpdate();
|
|
33
78
|
this.scrollContainer?.requestUpdate();
|
|
79
|
+
this.paginator?.requestUpdate();
|
|
80
|
+
this.toolbar?.requestUpdate();
|
|
34
81
|
}
|
|
35
82
|
}
|
|
36
83
|
export const gridStateContext = createContext('gridStateController');
|
package/controllers/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/controllers/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/controllers/state.ts"],"names":[],"mappings":"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","sourcesContent":["import { createContext } from '@lit/context';\nimport type { ReactiveController } from 'lit';\nimport type { GridFeatureModule } from '../internal/feature-module.js';\nimport type { ActiveNode, GridHost } from '../internal/types.js';\nimport { EditingController } from './editing.js';\nimport { ExpansionController } from './expansion.js';\nimport { FilterController } from './filter.js';\nimport { NavigationController } from './navigation.js';\nimport { PaginationController } from './pagination.js';\nimport { ReorderController } from './reorder.js';\nimport { ResizeController } from './resize.js';\nimport { SelectionController } from './selection.js';\nimport { SortController } from './sort.js';\nimport { TreeController } from './tree.js';\n\nexport class StateController<T extends object> implements ReactiveController {\n public sorting!: SortController<T>;\n public filtering!: FilterController<T>;\n public navigation!: NavigationController<T>;\n public resizing!: ResizeController<T>;\n public pagination!: PaginationController<T>;\n public reordering!: ReorderController<T>;\n public editing!: EditingController<T>;\n public selection!: SelectionController<T>;\n public expansion!: ExpansionController<T>;\n public tree!: TreeController<T>;\n\n /**\n * Optional feature controllers contributed by {@link GridFeatureModule}s,\n * keyed by module id. Empty for the community `<apex-grid>` element; populated\n * by derived grids (e.g. `@apexcharts/grid-enterprise`) that pass modules to\n * the constructor.\n */\n public readonly modules = new Map<string, ReactiveController>();\n\n /**\n * Current message in the grid's polite live region. Bound by the host's\n * `renderLiveRegion()` template; mutated through {@link setAnnouncement}\n * so screen readers re-announce on every change.\n */\n public announcement = '';\n #announceToken = 0;\n\n /**\n * Updates the polite live region's text. Repeats are forced to fire by\n * appending a zero-width space — screen readers ignore unchanged content,\n * so two identical sort announcements wouldn't otherwise be read aloud.\n */\n public setAnnouncement(message: string): void {\n if (!message) {\n this.announcement = '';\n this.host.requestUpdate();\n return;\n }\n this.#announceToken = (this.#announceToken + 1) % 2;\n this.announcement = this.#announceToken ? message : `${message} `;\n this.host.requestUpdate();\n }\n\n public get active() {\n return this.navigation.active;\n }\n\n public set active(node: ActiveNode<T>) {\n this.navigation.active = node;\n }\n\n public get headerRow() {\n // @ts-expect-error - Protected member access\n return this.host.headerRow;\n }\n\n public get scrollContainer() {\n // @ts-expect-error - Protected member access\n return this.host.scrollContainer;\n }\n\n public get paginator() {\n // @ts-expect-error - Protected member access\n return this.host.paginator;\n }\n\n public get toolbar() {\n // @ts-expect-error - Protected member access\n return this.host.toolbar;\n }\n\n /**\n * Cumulative pin offsets (in px) keyed by column key. Populated by the\n * {@link GridDOMController} after each layout.\n */\n public get pinOffsets(): Map<unknown, number> {\n // @ts-expect-error - Protected member access\n const dom = this.host.DOM as { pinOffsets?: Map<unknown, number> } | undefined;\n return dom?.pinOffsets ?? new Map();\n }\n\n constructor(\n public host: GridHost<T>,\n private extraModules: ReadonlyArray<GridFeatureModule<T>> = []\n ) {\n this.host.addController(this);\n this.init();\n }\n\n protected init() {\n this.sorting = new SortController(this.host);\n this.filtering = new FilterController(this.host);\n this.navigation = new NavigationController(this.host);\n this.resizing = new ResizeController(this.host);\n this.pagination = new PaginationController(this.host);\n this.reordering = new ReorderController(this.host);\n this.editing = new EditingController(this.host);\n this.selection = new SelectionController(this.host);\n this.expansion = new ExpansionController(this.host);\n this.tree = new TreeController(this.host);\n\n for (const module of this.extraModules) {\n if (this.modules.has(module.id)) continue;\n this.modules.set(module.id, module.create(this.host));\n }\n }\n\n /**\n * Look up a feature controller contributed by a {@link GridFeatureModule},\n * by its module id. Returns `undefined` when no such module is registered.\n */\n public module<C extends ReactiveController>(id: string): C | undefined {\n return this.modules.get(id) as C | undefined;\n }\n\n public hostConnected() {}\n\n public hostUpdate(): void {\n this.headerRow?.requestUpdate();\n this.scrollContainer?.requestUpdate();\n this.paginator?.requestUpdate();\n this.toolbar?.requestUpdate();\n }\n}\n\nexport const gridStateContext = createContext<StateController<any>>('gridStateController');\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ReactiveController } from 'lit';
|
|
2
|
+
import type { GridHost, Keys } from '../internal/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Default pixel indentation per depth level for the tree group column.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_TREE_INDENT = 20;
|
|
7
|
+
/**
|
|
8
|
+
* Tree metadata exposed to renderers. One entry per row that ends up in the
|
|
9
|
+
* flat output.
|
|
10
|
+
*/
|
|
11
|
+
export interface TreeRowMeta {
|
|
12
|
+
depth: number;
|
|
13
|
+
hasChildren: boolean;
|
|
14
|
+
/** Stable key for the row (path-joined string). Useful for keyed reconciliation. */
|
|
15
|
+
key: string;
|
|
16
|
+
/** Last path segment — used as the group-column label for synthesized parents. */
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Reactive controller backing tree (nested-row) data.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Tree mode keeps the data array flat. Each row's hierarchy is derived from a
|
|
24
|
+
* user-supplied `getDataPath` callback (AG Grid's "tree data" pattern). The
|
|
25
|
+
* controller:
|
|
26
|
+
*
|
|
27
|
+
* 1. Builds an in-memory tree from the post-sort, post-filter rows.
|
|
28
|
+
* 2. Synthesizes parent nodes for any path level that lacks a backing row.
|
|
29
|
+
* 3. Walks the tree honouring the current expansion set and emits a flat
|
|
30
|
+
* list of rows in display order.
|
|
31
|
+
* 4. Records per-row metadata (depth, hasChildren) that the cell renderer
|
|
32
|
+
* reads to draw the chevron + indentation.
|
|
33
|
+
*
|
|
34
|
+
* Expansion state is split into two sets — `expanded` for rows that have
|
|
35
|
+
* backing data (keyed by reference, so it survives sort/filter), and
|
|
36
|
+
* `expandedKeys` for synthesized parents (keyed by their path string).
|
|
37
|
+
*/
|
|
38
|
+
export declare class TreeController<T extends object> implements ReactiveController {
|
|
39
|
+
#private;
|
|
40
|
+
protected host: GridHost<T>;
|
|
41
|
+
expanded: Set<T>;
|
|
42
|
+
expandedKeys: Set<string>;
|
|
43
|
+
constructor(host: GridHost<T>);
|
|
44
|
+
hostConnected(): void;
|
|
45
|
+
/** Whether tree mode is enabled at the grid level. */
|
|
46
|
+
get enabled(): boolean;
|
|
47
|
+
/** The configured indentation, in pixels, per depth level. */
|
|
48
|
+
get childIndent(): number;
|
|
49
|
+
/**
|
|
50
|
+
* The column key that displays the chevron + indentation. Resolves to the
|
|
51
|
+
* configured `groupColumnKey`, falling back to the first visible data column.
|
|
52
|
+
*/
|
|
53
|
+
get groupColumnKey(): Keys<T> | undefined;
|
|
54
|
+
isGroupColumn(key: Keys<T>): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Per-row metadata. Populated as a side effect of {@link process}; reading
|
|
57
|
+
* before the first pipeline pass returns `undefined`.
|
|
58
|
+
*/
|
|
59
|
+
getMeta(row: T): TreeRowMeta | undefined;
|
|
60
|
+
getDepth(row: T): number;
|
|
61
|
+
hasChildren(row: T): boolean;
|
|
62
|
+
isSynthesized(row: T): boolean;
|
|
63
|
+
/** Group-column label override for synthesized parent rows. */
|
|
64
|
+
getLabel(row: T): string | null;
|
|
65
|
+
isExpanded(row: T): boolean;
|
|
66
|
+
/** Toggles the expansion state of a tree row. */
|
|
67
|
+
toggleRow(row: T): Promise<boolean>;
|
|
68
|
+
expandRow(row: T): Promise<boolean>;
|
|
69
|
+
collapseRow(row: T): Promise<boolean>;
|
|
70
|
+
/** Expands every parent in the current tree. */
|
|
71
|
+
expandAll(): Promise<boolean>;
|
|
72
|
+
/** Collapses every currently-expanded row. */
|
|
73
|
+
collapseAll(): Promise<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Pipeline entry point. Called by {@link DataOperationsController.apply}
|
|
76
|
+
* after sort/filter/quickFilter. Builds the tree, applies the configured
|
|
77
|
+
* defaults the first time we see this data, and returns rows in
|
|
78
|
+
* display-order with any synthesized parents inserted.
|
|
79
|
+
*/
|
|
80
|
+
process(input: ReadonlyArray<T>): T[];
|
|
81
|
+
/**
|
|
82
|
+
* Resets cached metadata + defaults flag so the next pipeline pass
|
|
83
|
+
* re-applies `defaultExpanded`. Called from the data watcher when the
|
|
84
|
+
* input array is replaced wholesale.
|
|
85
|
+
*/
|
|
86
|
+
resetForDataChange(): void;
|
|
87
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/controllers/tree.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAKzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAGtC,MAAM,WAAW,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAkDnD,MAAM,OAAO,cAAc;IAIzB,KAAK,CAAiC;IACtC,cAAc,CAAkC;IAEhD,cAAc,CAAwB;IAEtC,gBAAgB,CAAS;IAEzB,SAAS,CAA4B;IAErC,YAAsB,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QAZhC,aAAQ,GAAW,IAAI,GAAG,EAAE,CAAC;QAC7B,iBAAY,GAAgB,IAAI,GAAG,EAAE,CAAC;QAE7C,UAAK,GAAG,IAAI,OAAO,EAAkB,CAAC;QACtC,mBAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;QAEhD,mBAAc,GAAG,IAAI,GAAG,EAAa,CAAC;QAEtC,qBAAgB,GAAG,KAAK,CAAC;QAEzB,cAAS,GAAuB,IAAI,CAAC;QAGnC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAEM,aAAa,KAAI,CAAC;IAGzB,IAAW,OAAO;QAChB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACzE,CAAC;IAGD,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,IAAI,mBAAmB,CAAC;IAC5D,CAAC;IAMD,IAAW,cAAc;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QAClD,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;QAClC,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxF,OAAO,SAAS,EAAE,GAAG,CAAC;IACxB,CAAC;IAEM,aAAa,CAAC,GAAY;QAC/B,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,KAAK,GAAG,CAAC;IACrD,CAAC;IAMM,OAAO,CAAC,GAAM;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAEM,QAAQ,CAAC,GAAM;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IACzC,CAAC;IAEM,WAAW,CAAC,GAAM;QACvB,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAEM,aAAa,CAAC,GAAM;QACzB,OAAQ,GAAmC,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACpE,CAAC;IAGM,QAAQ,CAAC,GAAM;QACpB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;IAC5C,CAAC;IAEM,UAAU,CAAC,GAAM;QACtB,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;YACrC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAClD,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAGM,KAAK,CAAC,SAAS,CAAC,GAAM;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACnE,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,GAAM;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACzC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;gBACrC,IAAI,GAAG;oBAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,GAAM;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;gBACrC,IAAI,GAAG;oBAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAGM,KAAK,CAAC,SAAS;QACpB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACzC,MAAM,KAAK,GAAG,CAAC,IAAiB,EAAE,EAAE;gBAClC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9C,IAAI,IAAI,CAAC,IAAI;wBAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;wBAClC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,CAAC;gBACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;oBAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAClD,CAAC,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAGM,KAAK,CAAC,WAAW;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1E,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACzC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjB,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IAQM,OAAO,CAAC,KAAuB;QACpC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAY,CAAC;QAEvC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAK,CAAC,WAAW,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAGtB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAOM,kBAAkB;QACvB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAIhC,CAAC;IAID,UAAU,CAAC,IAAsB,EAAE,WAA0C;QAC3E,MAAM,IAAI,GAAgB;YACxB,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,EAAE;YACR,GAAG,EAAE,EAAE;YACP,KAAK,EAAE,CAAC,CAAC;YACT,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,EAAE;SACb,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC7C,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAEpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEjD,IAAI,MAAM,GAAG,IAAI,CAAC;YAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,IAAI,GAAG;wBACL,IAAI,EAAE,IAAI;wBACV,IAAI,EAAE,GAAG;wBACT,GAAG;wBACH,KAAK,EAAE,CAAC;wBACR,MAAM;wBACN,QAAQ,EAAE,EAAE;qBACb,CAAC;oBACF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;oBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7B,CAAC;gBACD,IAAI,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAI9B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;gBAClB,CAAC;gBACD,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,cAAc,CAAC,IAAiB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC;QAChD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK;YAAE,OAAO;QACvD,MAAM,aAAa,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QACvF,MAAM,KAAK,GAAG,CAAC,IAAiB,EAAE,EAAE;YAClC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,aAAa,EAAE,CAAC;gBAC7E,IAAI,IAAI,CAAC,IAAI;oBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;oBACvC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;gBAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,YAAY,CAAC,IAAiB;QAK5B,MAAM,KAAK,GAAG,CAAC,IAAiB,EAAE,EAAE;YAClC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAgB;oBACxB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;oBACrC,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;iBAC7C,CAAC;gBACF,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;gBAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,IAAiB;QACxB,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,CAAC,IAAiB,EAAE,EAAE;YACjC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBAGN,IAAI,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACpD,IAAI,CAAC,WAAW,EAAE,CAAC;wBACjB,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAM,CAAC;wBACvC,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,WAAW,EAAE;4BAC9C,KAAK,EAAE,IAAI;4BACX,UAAU,EAAE,KAAK;yBAClB,CAAC,CAAC;wBACH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;oBACjD,CAAC;oBACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAE,CAAC,CAAC;oBAChE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YACD,MAAM,QAAQ,GACZ,IAAI,KAAK,IAAI;gBACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/E,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;oBAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACjD,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,CAAC;QACX,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAyD;QACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE3B,MAAM,WAAW,GACf,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/F,MAAM,WAAW,GACf,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,IAAI;YACxC,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAE9C,MAAM,KAAK,GAAQ,EAAE,CAAC;QACtB,MAAM,OAAO,GAAQ,EAAE,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,QAAQ;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzE,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE3E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE;YACtD,MAAM,EAAE;gBACN,KAAK;gBACL,OAAO;gBACP,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAClC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;aAC3B;YACD,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAE3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;QAE7B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAElC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE;YACrC,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;SAChE,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { GridHost, Keys } from '../internal/types.js';\nimport { getDisplayColumns } from '../internal/utils.js';\n\n/**\n * Default pixel indentation per depth level for the tree group column.\n */\nexport const DEFAULT_TREE_INDENT = 20;\n\n/** Sentinel value used to mark synthesized parents (those that exist only as a path segment, with no backing row). */\nconst SYNTHESIZED = Symbol('synthesized-tree-row');\n\n/**\n * Internal tree node. Built from the flat data + `getDataPath` callback;\n * lives only for the duration of one pipeline pass.\n */\ninterface TreeNode<T extends object> {\n /** The backing row when one exists at this path, else `null` (synthesized parent). */\n data: T | null;\n /** Path segments from root to this node. */\n path: readonly string[];\n /** `path.join('\u0000')` — used as stable string identity for synthesized nodes. */\n key: string;\n depth: number;\n parent: TreeNode<T> | null;\n children: TreeNode<T>[];\n}\n\n/**\n * Tree metadata exposed to renderers. One entry per row that ends up in the\n * flat output.\n */\nexport interface TreeRowMeta {\n depth: number;\n hasChildren: boolean;\n /** Stable key for the row (path-joined string). Useful for keyed reconciliation. */\n key: string;\n /** Last path segment — used as the group-column label for synthesized parents. */\n label: string;\n}\n\n/**\n * Reactive controller backing tree (nested-row) data.\n *\n * @remarks\n * Tree mode keeps the data array flat. Each row's hierarchy is derived from a\n * user-supplied `getDataPath` callback (AG Grid's \"tree data\" pattern). The\n * controller:\n *\n * 1. Builds an in-memory tree from the post-sort, post-filter rows.\n * 2. Synthesizes parent nodes for any path level that lacks a backing row.\n * 3. Walks the tree honouring the current expansion set and emits a flat\n * list of rows in display order.\n * 4. Records per-row metadata (depth, hasChildren) that the cell renderer\n * reads to draw the chevron + indentation.\n *\n * Expansion state is split into two sets — `expanded` for rows that have\n * backing data (keyed by reference, so it survives sort/filter), and\n * `expandedKeys` for synthesized parents (keyed by their path string).\n */\nexport class TreeController<T extends object> implements ReactiveController {\n public expanded: Set<T> = new Set();\n public expandedKeys: Set<string> = new Set();\n\n #meta = new WeakMap<T, TreeRowMeta>();\n #syntheticMeta = new Map<string, TreeRowMeta>();\n /** Synthesized parent placeholder rows so consumers still get a `T`-shaped object. */\n #syntheticRows = new Map<string, T>();\n /** Whether `defaultExpanded` has been applied once for the current data set. */\n #defaultsApplied = false;\n /** Most recently built root node. Used to walk the full tree for expand-all. */\n #lastRoot: TreeNode<T> | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /** Whether tree mode is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.tree?.enabled && this.host.tree?.getDataPath);\n }\n\n /** The configured indentation, in pixels, per depth level. */\n public get childIndent(): number {\n return this.host.tree?.childIndent ?? DEFAULT_TREE_INDENT;\n }\n\n /**\n * The column key that displays the chevron + indentation. Resolves to the\n * configured `groupColumnKey`, falling back to the first visible data column.\n */\n public get groupColumnKey(): Keys<T> | undefined {\n const configured = this.host.tree?.groupColumnKey;\n if (configured) return configured;\n const displayed = getDisplayColumns(this.host.columns).find((column) => !column.hidden);\n return displayed?.key;\n }\n\n public isGroupColumn(key: Keys<T>): boolean {\n return this.enabled && this.groupColumnKey === key;\n }\n\n /**\n * Per-row metadata. Populated as a side effect of {@link process}; reading\n * before the first pipeline pass returns `undefined`.\n */\n public getMeta(row: T): TreeRowMeta | undefined {\n return this.#meta.get(row);\n }\n\n public getDepth(row: T): number {\n return this.#meta.get(row)?.depth ?? 0;\n }\n\n public hasChildren(row: T): boolean {\n return Boolean(this.#meta.get(row)?.hasChildren);\n }\n\n public isSynthesized(row: T): boolean {\n return (row as { [SYNTHESIZED]?: boolean })[SYNTHESIZED] === true;\n }\n\n /** Group-column label override for synthesized parent rows. */\n public getLabel(row: T): string | null {\n if (!this.isSynthesized(row)) return null;\n return this.#meta.get(row)?.label ?? null;\n }\n\n public isExpanded(row: T): boolean {\n if (this.isSynthesized(row)) {\n const key = this.#meta.get(row)?.key;\n return key ? this.expandedKeys.has(key) : false;\n }\n return this.expanded.has(row);\n }\n\n /** Toggles the expansion state of a tree row. */\n public async toggleRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (!this.hasChildren(row)) return false;\n const wasExpanded = this.isExpanded(row);\n return wasExpanded ? this.collapseRow(row) : this.expandRow(row);\n }\n\n public async expandRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (!this.hasChildren(row)) return false;\n if (this.isExpanded(row)) return true;\n return this.#commit((nextData, nextKeys) => {\n if (this.isSynthesized(row)) {\n const key = this.#meta.get(row)?.key;\n if (key) nextKeys.add(key);\n } else {\n nextData.add(row);\n }\n });\n }\n\n public async collapseRow(row: T): Promise<boolean> {\n if (!this.enabled) return false;\n if (!this.isExpanded(row)) return true;\n return this.#commit((nextData, nextKeys) => {\n if (this.isSynthesized(row)) {\n const key = this.#meta.get(row)?.key;\n if (key) nextKeys.delete(key);\n } else {\n nextData.delete(row);\n }\n });\n }\n\n /** Expands every parent in the current tree. */\n public async expandAll(): Promise<boolean> {\n if (!this.enabled) return false;\n const root = this.#lastRoot;\n if (!root) return false;\n return this.#commit((nextData, nextKeys) => {\n const visit = (node: TreeNode<T>) => {\n if (node !== root && node.children.length > 0) {\n if (node.data) nextData.add(node.data);\n else nextKeys.add(node.key);\n }\n for (const child of node.children) visit(child);\n };\n visit(root);\n });\n }\n\n /** Collapses every currently-expanded row. */\n public async collapseAll(): Promise<boolean> {\n if (!this.enabled) return false;\n if (this.expanded.size === 0 && this.expandedKeys.size === 0) return true;\n return this.#commit((nextData, nextKeys) => {\n nextData.clear();\n nextKeys.clear();\n });\n }\n\n /**\n * Pipeline entry point. Called by {@link DataOperationsController.apply}\n * after sort/filter/quickFilter. Builds the tree, applies the configured\n * defaults the first time we see this data, and returns rows in\n * display-order with any synthesized parents inserted.\n */\n public process(input: ReadonlyArray<T>): T[] {\n if (!this.enabled) return input as T[];\n\n const getDataPath = this.host.tree!.getDataPath;\n const root = this.#buildTree(input, getDataPath);\n this.#lastRoot = root;\n\n // Apply defaultExpanded once per data set.\n if (!this.#defaultsApplied) {\n this.#applyDefaults(root);\n this.#defaultsApplied = true;\n }\n\n this.#refreshMeta(root);\n return this.#flatten(root);\n }\n\n /**\n * Resets cached metadata + defaults flag so the next pipeline pass\n * re-applies `defaultExpanded`. Called from the data watcher when the\n * input array is replaced wholesale.\n */\n public resetForDataChange(): void {\n this.#defaultsApplied = false;\n // Don't clear `expanded`/`expandedKeys`; consumers may want them to\n // survive across pipeline passes. If a wholesale data swap orphans\n // references, those entries are simply ignored on the next pass.\n }\n\n // --- internals ---------------------------------------------------------\n\n #buildTree(rows: ReadonlyArray<T>, getDataPath: (row: T) => readonly string[]): TreeNode<T> {\n const root: TreeNode<T> = {\n data: null,\n path: [],\n key: '',\n depth: -1,\n parent: null,\n children: [],\n };\n const byKey = new Map<string, TreeNode<T>>();\n byKey.set('', root);\n\n for (const row of rows) {\n const fullPath = getDataPath(row);\n if (!fullPath || fullPath.length === 0) continue;\n\n let parent = root;\n for (let i = 0; i < fullPath.length; i++) {\n const sub = fullPath.slice(0, i + 1);\n const key = sub.join('\u0000');\n let node = byKey.get(key);\n if (!node) {\n node = {\n data: null,\n path: sub,\n key,\n depth: i,\n parent,\n children: [],\n };\n byKey.set(key, node);\n parent.children.push(node);\n }\n if (i === fullPath.length - 1) {\n // The terminal segment is the actual record. If we previously\n // saw a child path that synthesized this level, attach the data\n // now.\n node.data = row;\n }\n parent = node;\n }\n }\n\n return root;\n }\n\n #applyDefaults(root: TreeNode<T>): void {\n const setting = this.host.tree?.defaultExpanded;\n if (setting === undefined || setting === false) return;\n const expandToDepth = typeof setting === 'number' ? setting : Number.POSITIVE_INFINITY;\n const visit = (node: TreeNode<T>) => {\n if (node !== root && node.children.length > 0 && node.depth <= expandToDepth) {\n if (node.data) this.expanded.add(node.data);\n else this.expandedKeys.add(node.key);\n }\n for (const child of node.children) visit(child);\n };\n visit(root);\n }\n\n #refreshMeta(root: TreeNode<T>): void {\n // Recompute meta for every node in the tree, both synthesized and\n // backed. The metadata is fresh each pipeline pass since depth or\n // hasChildren may have changed (rows reordered, filter dropped a\n // descendant, etc.).\n const visit = (node: TreeNode<T>) => {\n if (node !== root) {\n const meta: TreeRowMeta = {\n depth: node.depth,\n hasChildren: node.children.length > 0,\n key: node.key,\n label: node.path[node.path.length - 1] ?? '',\n };\n if (node.data) {\n this.#meta.set(node.data, meta);\n } else {\n this.#syntheticMeta.set(node.key, meta);\n }\n }\n for (const child of node.children) visit(child);\n };\n visit(root);\n }\n\n #flatten(root: TreeNode<T>): T[] {\n const out: T[] = [];\n const walk = (node: TreeNode<T>) => {\n if (node !== root) {\n if (node.data) {\n out.push(node.data);\n } else {\n // Synthesize a `T`-shaped placeholder so callers don't trip on\n // `null` rows. The placeholder carries the SYNTHESIZED marker.\n let placeholder = this.#syntheticRows.get(node.key);\n if (!placeholder) {\n placeholder = Object.create(null) as T;\n Object.defineProperty(placeholder, SYNTHESIZED, {\n value: true,\n enumerable: false,\n });\n this.#syntheticRows.set(node.key, placeholder);\n }\n this.#meta.set(placeholder, this.#syntheticMeta.get(node.key)!);\n out.push(placeholder);\n }\n }\n const expanded =\n node === root ||\n (node.data ? this.expanded.has(node.data) : this.expandedKeys.has(node.key));\n if (expanded) {\n for (const child of node.children) walk(child);\n }\n };\n walk(root);\n return out;\n }\n\n async #commit(mutate: (nextData: Set<T>, nextKeys: Set<string>) => void): Promise<boolean> {\n const nextData = new Set(this.expanded);\n const nextKeys = new Set(this.expandedKeys);\n mutate(nextData, nextKeys);\n\n const dataChanged =\n nextData.size !== this.expanded.size || [...nextData].some((row) => !this.expanded.has(row));\n const keysChanged =\n nextKeys.size !== this.expandedKeys.size ||\n [...nextKeys].some((key) => !this.expandedKeys.has(key));\n if (!dataChanged && !keysChanged) return true;\n\n const added: T[] = [];\n const removed: T[] = [];\n for (const row of nextData) if (!this.expanded.has(row)) added.push(row);\n for (const row of this.expanded) if (!nextData.has(row)) removed.push(row);\n\n const proceed = this.host.emitEvent('treeRowExpanding', {\n detail: {\n added,\n removed,\n current: Array.from(this.expanded),\n next: Array.from(nextData),\n },\n cancelable: true,\n });\n if (!proceed) return false;\n\n this.expanded = nextData;\n this.expandedKeys = nextKeys;\n // Re-run the pipeline so the flat output reflects the new expansion set.\n this.host.requestUpdate(PIPELINE);\n\n this.host.emitEvent('treeRowExpanded', {\n detail: { added, removed, expanded: Array.from(this.expanded) },\n });\n return true;\n }\n}\n"]}
|