apex-grid 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +29 -0
- package/components/cell.d.ts +2 -2
- package/components/cell.js +30 -2
- package/components/cell.js.map +1 -1
- package/components/filter-row.js +65 -6
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +5 -0
- package/components/grid.js +34 -2
- package/components/grid.js.map +1 -1
- package/components/header.js +80 -9
- package/components/header.js.map +1 -1
- package/controllers/expansion.js +4 -4
- package/controllers/expansion.js.map +1 -1
- package/controllers/filter.js +11 -0
- package/controllers/filter.js.map +1 -1
- package/controllers/history.js +11 -4
- package/controllers/history.js.map +1 -1
- package/controllers/navigation.d.ts +34 -2
- package/controllers/navigation.js +92 -3
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.js +1 -1
- package/controllers/pagination.js.map +1 -1
- package/controllers/row-pin.js +2 -2
- package/controllers/row-pin.js.map +1 -1
- package/controllers/row-reorder.js +6 -6
- package/controllers/row-reorder.js.map +1 -1
- package/controllers/selection.js +3 -3
- package/controllers/selection.js.map +1 -1
- package/controllers/sort.js +4 -2
- package/controllers/sort.js.map +1 -1
- package/custom-elements.json +223 -7
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/functions/localize.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +62 -1
- package/docs/interfaces/BaseApexCellContext.html +1 -1
- package/docs/interfaces/BaseApexEditorContext.html +1 -1
- package/docs/interfaces/CSVExportOptions.html +1 -1
- package/docs/interfaces/ExportOptions.html +1 -1
- package/docs/interfaces/PaginationState.html +1 -1
- package/docs/media/package.json +2 -2
- package/docs/variables/EN_LOCALE.html +2 -2
- package/i18n/en.d.ts +95 -1
- package/i18n/en.js +95 -1
- package/i18n/en.js.map +1 -1
- package/i18n/es.js +95 -1
- package/i18n/es.js.map +1 -1
- package/internal/column-types.js +1 -1
- package/internal/column-types.js.map +1 -1
- package/package.json +1 -1
- package/styles/body-cell/body-cell.css.js +1 -1
- package/styles/body-cell/body-cell.css.js.map +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ReactiveController } from 'lit';
|
|
2
|
-
import type { ActiveNode, GridHost, Keys } from '../internal/types.js';
|
|
2
|
+
import type { ActiveNode, ColumnConfiguration, GridHost, Keys } from '../internal/types.js';
|
|
3
3
|
export declare class NavigationController<T extends object> implements ReactiveController {
|
|
4
4
|
protected host: GridHost<T>;
|
|
5
|
-
protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
|
|
5
|
+
protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
|
|
6
6
|
protected get virtualizer(): import("../components/virtualizer.js").default;
|
|
7
7
|
protected state: Map<import("../internal/types.js").NavigationState, ActiveNode<any>>;
|
|
8
8
|
protected _active: Readonly<ActiveNode<any>>;
|
|
@@ -22,11 +22,33 @@ export declare class NavigationController<T extends object> implements ReactiveC
|
|
|
22
22
|
protected getPreviousColumn(key: Keys<T>): Keys<T>;
|
|
23
23
|
protected getNextColumn(key: Keys<T>): Keys<T>;
|
|
24
24
|
protected scrollToCell(node: ActiveNode<T>): void;
|
|
25
|
+
protected findActiveCell(): import("../components/cell.js").default<T> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Moves real DOM focus to the active cell (the grid body's roving tab stop),
|
|
28
|
+
* so screen readers track keyboard navigation. Waits for the host render to
|
|
29
|
+
* commit the cell's `active` state, then retries once on the next frame to
|
|
30
|
+
* cover virtualizer re-materialization after a long jump. No-op while no
|
|
31
|
+
* cell is active (the scroll container keeps focus as the entry point).
|
|
32
|
+
*/
|
|
33
|
+
focusActiveCell(): void;
|
|
25
34
|
get active(): ActiveNode<T>;
|
|
26
35
|
set active(node: ActiveNode<T>);
|
|
27
36
|
constructor(host: GridHost<T>);
|
|
37
|
+
/** Home moves to the first cell in the row (ARIA grid pattern). */
|
|
28
38
|
protected home(): void;
|
|
39
|
+
/** End moves to the last cell in the row (ARIA grid pattern). */
|
|
29
40
|
protected end(): void;
|
|
41
|
+
/** Ctrl/Cmd+Home moves to the first cell of the grid. */
|
|
42
|
+
protected ctrlHome(): void;
|
|
43
|
+
/** Ctrl/Cmd+End moves to the last cell of the grid. */
|
|
44
|
+
protected ctrlEnd(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Rows per Page Up/Down step, derived from the host viewport and the height
|
|
47
|
+
* of a rendered row (fallback: 10 rows when nothing is measurable yet).
|
|
48
|
+
*/
|
|
49
|
+
protected pageStep(): number;
|
|
50
|
+
protected pageUp(): void;
|
|
51
|
+
protected pageDown(): void;
|
|
30
52
|
protected arrowDown(): void;
|
|
31
53
|
protected arrowUp(): void;
|
|
32
54
|
protected arrowLeft(): void;
|
|
@@ -34,6 +56,16 @@ export declare class NavigationController<T extends object> implements ReactiveC
|
|
|
34
56
|
protected toggleSelection(): void;
|
|
35
57
|
hostConnected(): void;
|
|
36
58
|
hostDisconnected(): void;
|
|
59
|
+
protected get editing(): {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
isEditable(column: ColumnConfiguration<T>): boolean;
|
|
62
|
+
editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean>;
|
|
63
|
+
} | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Enter / F2 on the active cell opens its editor (the keyboard path into
|
|
66
|
+
* edit mode). Returns `true` when the event was consumed.
|
|
67
|
+
*/
|
|
68
|
+
protected handleEditKey(event: KeyboardEvent): boolean;
|
|
37
69
|
protected get rowReorder(): {
|
|
38
70
|
enabled: boolean;
|
|
39
71
|
isGrabbing: boolean;
|
|
@@ -39,6 +39,24 @@ export class NavigationController {
|
|
|
39
39
|
?.scrollIntoView({ block: 'nearest' });
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
findActiveCell() {
|
|
43
|
+
const row = Array.from(this.virtualizer.querySelectorAll(GRID_ROW_TAG)).find((el) => el.index === this.active.row);
|
|
44
|
+
return row?.cells.find((cell) => cell.column.key === this.active.column);
|
|
45
|
+
}
|
|
46
|
+
focusActiveCell() {
|
|
47
|
+
const node = this.state.get('current');
|
|
48
|
+
if (!node || node === SENTINEL_NODE)
|
|
49
|
+
return;
|
|
50
|
+
void (async () => {
|
|
51
|
+
await this.host.updateComplete;
|
|
52
|
+
let cell = this.findActiveCell();
|
|
53
|
+
if (!cell) {
|
|
54
|
+
await new Promise(requestAnimationFrame);
|
|
55
|
+
cell = this.findActiveCell();
|
|
56
|
+
}
|
|
57
|
+
cell?.focus({ preventScroll: true });
|
|
58
|
+
})();
|
|
59
|
+
}
|
|
42
60
|
get active() {
|
|
43
61
|
return this._active;
|
|
44
62
|
}
|
|
@@ -57,6 +75,8 @@ export class NavigationController {
|
|
|
57
75
|
ArrowRight: this.arrowRight,
|
|
58
76
|
Home: this.home,
|
|
59
77
|
End: this.end,
|
|
78
|
+
PageUp: this.pageUp,
|
|
79
|
+
PageDown: this.pageDown,
|
|
60
80
|
' ': this.toggleSelection,
|
|
61
81
|
}));
|
|
62
82
|
this.state = NAVIGATION_STATE;
|
|
@@ -64,11 +84,45 @@ export class NavigationController {
|
|
|
64
84
|
this.host.addController(this);
|
|
65
85
|
}
|
|
66
86
|
home() {
|
|
67
|
-
this.active = Object.assign(this.nextNode, {
|
|
68
|
-
this.
|
|
87
|
+
this.active = Object.assign(this.nextNode, { column: this.firstColumn });
|
|
88
|
+
this.scrollToCell(this.active);
|
|
69
89
|
}
|
|
70
90
|
end() {
|
|
71
|
-
|
|
91
|
+
const last = this.visibleColumns.at(-1)?.key ?? this.firstColumn;
|
|
92
|
+
this.active = Object.assign(this.nextNode, { column: last });
|
|
93
|
+
this.scrollToCell(this.active);
|
|
94
|
+
}
|
|
95
|
+
ctrlHome() {
|
|
96
|
+
this.active = { column: this.firstColumn, row: 0 };
|
|
97
|
+
this.virtualizer.element(0)?.scrollIntoView({ block: 'nearest' });
|
|
98
|
+
this.scrollToCell(this.active);
|
|
99
|
+
}
|
|
100
|
+
ctrlEnd() {
|
|
101
|
+
const row = Math.max(0, this.host.pageItems.length - 1);
|
|
102
|
+
const last = this.visibleColumns.at(-1)?.key ?? this.firstColumn;
|
|
103
|
+
this.active = { column: last, row };
|
|
104
|
+
this.virtualizer.element(row)?.scrollIntoView({ block: 'nearest' });
|
|
105
|
+
this.scrollToCell(this.active);
|
|
106
|
+
}
|
|
107
|
+
pageStep() {
|
|
108
|
+
const rowEl = this.virtualizer.element(this.nextNode.row);
|
|
109
|
+
const rowHeight = rowEl?.offsetHeight || 0;
|
|
110
|
+
const viewport = this.host.clientHeight || 0;
|
|
111
|
+
if (!rowHeight || !viewport)
|
|
112
|
+
return 10;
|
|
113
|
+
const rows = Math.floor(viewport / rowHeight) - 1;
|
|
114
|
+
return rows > 0 ? rows : 10;
|
|
115
|
+
}
|
|
116
|
+
pageUp() {
|
|
117
|
+
const next = this.nextNode;
|
|
118
|
+
this.active = Object.assign(next, { row: Math.max(0, next.row - this.pageStep()) });
|
|
119
|
+
this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });
|
|
120
|
+
}
|
|
121
|
+
pageDown() {
|
|
122
|
+
const next = this.nextNode;
|
|
123
|
+
this.active = Object.assign(next, {
|
|
124
|
+
row: Math.min(this.host.pageItems.length - 1, next.row + this.pageStep()),
|
|
125
|
+
});
|
|
72
126
|
this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });
|
|
73
127
|
}
|
|
74
128
|
arrowDown() {
|
|
@@ -104,6 +158,27 @@ export class NavigationController {
|
|
|
104
158
|
this.active = SENTINEL_NODE;
|
|
105
159
|
this.state = NAVIGATION_STATE;
|
|
106
160
|
}
|
|
161
|
+
get editing() {
|
|
162
|
+
return this.host.stateController.editing;
|
|
163
|
+
}
|
|
164
|
+
handleEditKey(event) {
|
|
165
|
+
if (event.key !== 'Enter' && event.key !== 'F2')
|
|
166
|
+
return false;
|
|
167
|
+
if (event.ctrlKey || event.metaKey || event.altKey)
|
|
168
|
+
return false;
|
|
169
|
+
const node = this.state.get('current');
|
|
170
|
+
if (!node || node === SENTINEL_NODE)
|
|
171
|
+
return false;
|
|
172
|
+
const editing = this.editing;
|
|
173
|
+
if (!editing?.enabled)
|
|
174
|
+
return false;
|
|
175
|
+
const column = this.host.getColumn(this.active.column);
|
|
176
|
+
if (!column || !editing.isEditable(column))
|
|
177
|
+
return false;
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
void editing.editCell(this.active.row, this.active.column);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
107
182
|
get rowReorder() {
|
|
108
183
|
return this.host.stateController.rowReorder;
|
|
109
184
|
}
|
|
@@ -157,10 +232,24 @@ export class NavigationController {
|
|
|
157
232
|
this.host.redo();
|
|
158
233
|
return;
|
|
159
234
|
}
|
|
235
|
+
if (event.key === 'Home' || event.key === 'End') {
|
|
236
|
+
event.preventDefault();
|
|
237
|
+
if (event.key === 'Home') {
|
|
238
|
+
this.ctrlHome();
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.ctrlEnd();
|
|
242
|
+
}
|
|
243
|
+
this.focusActiveCell();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
160
246
|
}
|
|
247
|
+
if (this.handleEditKey(event))
|
|
248
|
+
return;
|
|
161
249
|
if (this.handlers.has(event.key)) {
|
|
162
250
|
event.preventDefault();
|
|
163
251
|
this.handlers.get(event.key).call(this);
|
|
252
|
+
this.focusActiveCell();
|
|
164
253
|
}
|
|
165
254
|
}
|
|
166
255
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/controllers/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type ApexGridRow from '../components/row.js';\nimport { NAVIGATION_STATE, SENTINEL_NODE } from '../internal/constants.js';\nimport { GRID_ROW_TAG } from '../internal/tags.js';\nimport type { ActiveNode, GridHost, Keys } from '../internal/types.js';\nimport { getDisplayColumns } from '../internal/utils.js';\n\nexport class NavigationController<T extends object> implements ReactiveController {\n protected handlers = new Map(\n Object.entries({\n ArrowDown: this.arrowDown,\n ArrowUp: this.arrowUp,\n ArrowLeft: this.arrowLeft,\n ArrowRight: this.arrowRight,\n Home: this.home,\n End: this.end,\n ' ': this.toggleSelection,\n })\n );\n\n protected get virtualizer() {\n // @ts-expect-error - Protected member access\n return this.host.scrollContainer;\n }\n\n protected state = NAVIGATION_STATE;\n protected _active = SENTINEL_NODE;\n\n protected get nextNode() {\n const node = this.state.get('current')!;\n return node === SENTINEL_NODE\n ? { column: this.firstColumn, row: 0 }\n : ({ ...node } as ActiveNode<T>);\n }\n\n protected get columns(): Array<{ key: Keys<T>; hidden?: boolean }> {\n return getDisplayColumns(this.host.columns) as unknown as Array<{\n key: Keys<T>;\n hidden?: boolean;\n }>;\n }\n\n protected get visibleColumns() {\n return this.columns.filter((column) => !column.hidden);\n }\n\n protected get firstColumn(): Keys<T> {\n const first = this.visibleColumns.at(0);\n return (first?.key ?? (this.host.columns[0]?.key as Keys<T>)) as Keys<T>;\n }\n\n protected getPreviousColumn(key: Keys<T>): Keys<T> {\n const columns = this.visibleColumns;\n const idx = columns.findIndex((column) => column.key === key);\n return columns[Math.max(idx - 1, 0)].key;\n }\n\n protected getNextColumn(key: Keys<T>): Keys<T> {\n const columns = this.visibleColumns;\n const idx = columns.findIndex((column) => column.key === key);\n return columns[Math.min(idx + 1, columns.length - 1)].key;\n }\n\n protected scrollToCell(node: ActiveNode<T>) {\n const row = Array.from(this.virtualizer.querySelectorAll(GRID_ROW_TAG)).find(\n (row) => (row as unknown as ApexGridRow<T>).index === node.row\n ) as unknown as ApexGridRow<T>;\n\n if (row) {\n row.cells\n .find((cell) => cell.column.key === node.column)\n ?.scrollIntoView({ block: 'nearest' });\n }\n }\n\n public get active() {\n return this._active as ActiveNode<T>;\n }\n\n public set active(node: ActiveNode<T>) {\n this._active = node;\n this.state.set('previous', this._active);\n this.state.set('current', node);\n this.host.requestUpdate();\n }\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n protected home() {\n this.active = Object.assign(this.nextNode, { row: 0 });\n this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected end() {\n this.active = Object.assign(this.nextNode, { row: this.host.pageItems.length - 1 });\n this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowDown() {\n const next = this.nextNode;\n\n this.active = Object.assign(next, {\n row: Math.min(next.row + 1, this.host.pageItems.length - 1),\n });\n this.virtualizer.element(next.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowUp() {\n const next = this.nextNode;\n this.active = Object.assign(next, { row: Math.max(0, next.row - 1) });\n this.virtualizer.element(next.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowLeft() {\n const next = this.nextNode;\n this.active = Object.assign(next, { column: this.getPreviousColumn(next.column) });\n this.scrollToCell(this.active);\n }\n\n protected arrowRight() {\n const next = this.nextNode;\n this.active = Object.assign(next, { column: this.getNextColumn(next.column) });\n this.scrollToCell(this.active);\n }\n\n protected toggleSelection() {\n // Space on the focused grid toggles selection of the active row.\n // No-op when selection is disabled or there's no active row.\n const data = this.host.pageItems[this.active.row] as T | undefined;\n if (!data) return;\n void this.host.toggleRowSelection(data);\n }\n\n public hostConnected() {}\n\n public hostDisconnected() {\n this.active = SENTINEL_NODE as ActiveNode<T>;\n this.state = NAVIGATION_STATE;\n }\n\n protected get rowReorder() {\n // @ts-expect-error - protected member access\n return this.host.stateController.rowReorder as\n | {\n enabled: boolean;\n isGrabbing: boolean;\n grab(rowIndex: number): boolean;\n moveGrabbed(direction: -1 | 1): number;\n drop(): void;\n cancelGrab(): void;\n }\n | undefined;\n }\n\n /**\n * Keyboard row reorder: Space grabs the active row, arrows move it, Space /\n * Enter drops, Escape cancels. Returns `true` when the event was consumed.\n * Only active when `rowReordering.enabled` (so it never shadows Space-to-select\n * on grids without reordering).\n */\n protected handleReorderKey(event: KeyboardEvent): boolean {\n const reorder = this.rowReorder;\n if (!reorder?.enabled) return false;\n\n if (reorder.isGrabbing) {\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n const next = reorder.moveGrabbed(event.key === 'ArrowDown' ? 1 : -1);\n if (next >= 0) {\n this.active = Object.assign(this.nextNode, { row: next });\n this.virtualizer.element(next)?.scrollIntoView({ block: 'nearest' });\n }\n return true;\n }\n case ' ':\n case 'Enter':\n event.preventDefault();\n reorder.drop();\n return true;\n case 'Escape':\n event.preventDefault();\n reorder.cancelGrab();\n return true;\n default:\n return false;\n }\n }\n\n if (event.key === ' ' && this.active.row >= 0) {\n event.preventDefault();\n return reorder.grab(this.active.row);\n }\n return false;\n }\n\n public navigate(event: KeyboardEvent) {\n if (this.handleReorderKey(event)) return;\n // Undo / redo: Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl/Cmd+Y. Only fires when the\n // grid body (not an open editor) has focus, so a text editor's native undo\n // is never hijacked.\n if ((event.ctrlKey || event.metaKey) && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'z' && !event.shiftKey) {\n event.preventDefault();\n this.host.undo();\n return;\n }\n if ((key === 'z' && event.shiftKey) || key === 'y') {\n event.preventDefault();\n this.host.redo();\n return;\n }\n }\n if (this.handlers.has(event.key)) {\n event.preventDefault();\n this.handlers.get(event.key)!.call(this);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/controllers/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type ApexGridRow from '../components/row.js';\nimport { NAVIGATION_STATE, SENTINEL_NODE } from '../internal/constants.js';\nimport { GRID_ROW_TAG } from '../internal/tags.js';\nimport type { ActiveNode, ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { getDisplayColumns } from '../internal/utils.js';\n\nexport class NavigationController<T extends object> implements ReactiveController {\n protected handlers = new Map(\n Object.entries({\n ArrowDown: this.arrowDown,\n ArrowUp: this.arrowUp,\n ArrowLeft: this.arrowLeft,\n ArrowRight: this.arrowRight,\n Home: this.home,\n End: this.end,\n PageUp: this.pageUp,\n PageDown: this.pageDown,\n ' ': this.toggleSelection,\n })\n );\n\n protected get virtualizer() {\n // @ts-expect-error - Protected member access\n return this.host.scrollContainer;\n }\n\n protected state = NAVIGATION_STATE;\n protected _active = SENTINEL_NODE;\n\n protected get nextNode() {\n const node = this.state.get('current')!;\n return node === SENTINEL_NODE\n ? { column: this.firstColumn, row: 0 }\n : ({ ...node } as ActiveNode<T>);\n }\n\n protected get columns(): Array<{ key: Keys<T>; hidden?: boolean }> {\n return getDisplayColumns(this.host.columns) as unknown as Array<{\n key: Keys<T>;\n hidden?: boolean;\n }>;\n }\n\n protected get visibleColumns() {\n return this.columns.filter((column) => !column.hidden);\n }\n\n protected get firstColumn(): Keys<T> {\n const first = this.visibleColumns.at(0);\n return (first?.key ?? (this.host.columns[0]?.key as Keys<T>)) as Keys<T>;\n }\n\n protected getPreviousColumn(key: Keys<T>): Keys<T> {\n const columns = this.visibleColumns;\n const idx = columns.findIndex((column) => column.key === key);\n return columns[Math.max(idx - 1, 0)].key;\n }\n\n protected getNextColumn(key: Keys<T>): Keys<T> {\n const columns = this.visibleColumns;\n const idx = columns.findIndex((column) => column.key === key);\n return columns[Math.min(idx + 1, columns.length - 1)].key;\n }\n\n protected scrollToCell(node: ActiveNode<T>) {\n const row = Array.from(this.virtualizer.querySelectorAll(GRID_ROW_TAG)).find(\n (row) => (row as unknown as ApexGridRow<T>).index === node.row\n ) as unknown as ApexGridRow<T>;\n\n if (row) {\n row.cells\n .find((cell) => cell.column.key === node.column)\n ?.scrollIntoView({ block: 'nearest' });\n }\n }\n\n protected findActiveCell() {\n const row = Array.from(this.virtualizer.querySelectorAll(GRID_ROW_TAG)).find(\n (el) => (el as unknown as ApexGridRow<T>).index === this.active.row\n ) as unknown as ApexGridRow<T> | undefined;\n return row?.cells.find((cell) => cell.column.key === this.active.column);\n }\n\n /**\n * Moves real DOM focus to the active cell (the grid body's roving tab stop),\n * so screen readers track keyboard navigation. Waits for the host render to\n * commit the cell's `active` state, then retries once on the next frame to\n * cover virtualizer re-materialization after a long jump. No-op while no\n * cell is active (the scroll container keeps focus as the entry point).\n */\n public focusActiveCell(): void {\n const node = this.state.get('current');\n if (!node || node === SENTINEL_NODE) return;\n void (async () => {\n await this.host.updateComplete;\n let cell = this.findActiveCell();\n if (!cell) {\n await new Promise(requestAnimationFrame);\n cell = this.findActiveCell();\n }\n cell?.focus({ preventScroll: true });\n })();\n }\n\n public get active() {\n return this._active as ActiveNode<T>;\n }\n\n public set active(node: ActiveNode<T>) {\n this._active = node;\n this.state.set('previous', this._active);\n this.state.set('current', node);\n this.host.requestUpdate();\n }\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n /** Home moves to the first cell in the row (ARIA grid pattern). */\n protected home() {\n this.active = Object.assign(this.nextNode, { column: this.firstColumn });\n this.scrollToCell(this.active);\n }\n\n /** End moves to the last cell in the row (ARIA grid pattern). */\n protected end() {\n const last = this.visibleColumns.at(-1)?.key ?? this.firstColumn;\n this.active = Object.assign(this.nextNode, { column: last });\n this.scrollToCell(this.active);\n }\n\n /** Ctrl/Cmd+Home moves to the first cell of the grid. */\n protected ctrlHome() {\n this.active = { column: this.firstColumn, row: 0 } as ActiveNode<T>;\n this.virtualizer.element(0)?.scrollIntoView({ block: 'nearest' });\n this.scrollToCell(this.active);\n }\n\n /** Ctrl/Cmd+End moves to the last cell of the grid. */\n protected ctrlEnd() {\n const row = Math.max(0, this.host.pageItems.length - 1);\n const last = this.visibleColumns.at(-1)?.key ?? this.firstColumn;\n this.active = { column: last, row } as ActiveNode<T>;\n this.virtualizer.element(row)?.scrollIntoView({ block: 'nearest' });\n this.scrollToCell(this.active);\n }\n\n /**\n * Rows per Page Up/Down step, derived from the host viewport and the height\n * of a rendered row (fallback: 10 rows when nothing is measurable yet).\n */\n protected pageStep(): number {\n const rowEl = this.virtualizer.element(this.nextNode.row) as HTMLElement | undefined;\n const rowHeight = rowEl?.offsetHeight || 0;\n const viewport = (this.host as unknown as HTMLElement).clientHeight || 0;\n if (!rowHeight || !viewport) return 10;\n const rows = Math.floor(viewport / rowHeight) - 1;\n return rows > 0 ? rows : 10;\n }\n\n protected pageUp() {\n const next = this.nextNode;\n this.active = Object.assign(next, { row: Math.max(0, next.row - this.pageStep()) });\n this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected pageDown() {\n const next = this.nextNode;\n this.active = Object.assign(next, {\n row: Math.min(this.host.pageItems.length - 1, next.row + this.pageStep()),\n });\n this.virtualizer.element(this.active.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowDown() {\n const next = this.nextNode;\n\n this.active = Object.assign(next, {\n row: Math.min(next.row + 1, this.host.pageItems.length - 1),\n });\n this.virtualizer.element(next.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowUp() {\n const next = this.nextNode;\n this.active = Object.assign(next, { row: Math.max(0, next.row - 1) });\n this.virtualizer.element(next.row)?.scrollIntoView({ block: 'nearest' });\n }\n\n protected arrowLeft() {\n const next = this.nextNode;\n this.active = Object.assign(next, { column: this.getPreviousColumn(next.column) });\n this.scrollToCell(this.active);\n }\n\n protected arrowRight() {\n const next = this.nextNode;\n this.active = Object.assign(next, { column: this.getNextColumn(next.column) });\n this.scrollToCell(this.active);\n }\n\n protected toggleSelection() {\n // Space on the focused grid toggles selection of the active row.\n // No-op when selection is disabled or there's no active row.\n const data = this.host.pageItems[this.active.row] as T | undefined;\n if (!data) return;\n void this.host.toggleRowSelection(data);\n }\n\n public hostConnected() {}\n\n public hostDisconnected() {\n this.active = SENTINEL_NODE as ActiveNode<T>;\n this.state = NAVIGATION_STATE;\n }\n\n protected get editing() {\n // @ts-expect-error - protected member access\n return this.host.stateController.editing as\n | {\n enabled: boolean;\n isEditable(column: ColumnConfiguration<T>): boolean;\n editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean>;\n }\n | undefined;\n }\n\n /**\n * Enter / F2 on the active cell opens its editor (the keyboard path into\n * edit mode). Returns `true` when the event was consumed.\n */\n protected handleEditKey(event: KeyboardEvent): boolean {\n if (event.key !== 'Enter' && event.key !== 'F2') return false;\n if (event.ctrlKey || event.metaKey || event.altKey) return false;\n const node = this.state.get('current');\n if (!node || node === SENTINEL_NODE) return false;\n const editing = this.editing;\n if (!editing?.enabled) return false;\n const column = this.host.getColumn(this.active.column);\n if (!column || !editing.isEditable(column)) return false;\n event.preventDefault();\n void editing.editCell(this.active.row, this.active.column);\n return true;\n }\n\n protected get rowReorder() {\n // @ts-expect-error - protected member access\n return this.host.stateController.rowReorder as\n | {\n enabled: boolean;\n isGrabbing: boolean;\n grab(rowIndex: number): boolean;\n moveGrabbed(direction: -1 | 1): number;\n drop(): void;\n cancelGrab(): void;\n }\n | undefined;\n }\n\n /**\n * Keyboard row reorder: Space grabs the active row, arrows move it, Space /\n * Enter drops, Escape cancels. Returns `true` when the event was consumed.\n * Only active when `rowReordering.enabled` (so it never shadows Space-to-select\n * on grids without reordering).\n */\n protected handleReorderKey(event: KeyboardEvent): boolean {\n const reorder = this.rowReorder;\n if (!reorder?.enabled) return false;\n\n if (reorder.isGrabbing) {\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n const next = reorder.moveGrabbed(event.key === 'ArrowDown' ? 1 : -1);\n if (next >= 0) {\n this.active = Object.assign(this.nextNode, { row: next });\n this.virtualizer.element(next)?.scrollIntoView({ block: 'nearest' });\n }\n return true;\n }\n case ' ':\n case 'Enter':\n event.preventDefault();\n reorder.drop();\n return true;\n case 'Escape':\n event.preventDefault();\n reorder.cancelGrab();\n return true;\n default:\n return false;\n }\n }\n\n if (event.key === ' ' && this.active.row >= 0) {\n event.preventDefault();\n return reorder.grab(this.active.row);\n }\n return false;\n }\n\n public navigate(event: KeyboardEvent) {\n if (this.handleReorderKey(event)) return;\n // Undo / redo: Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl/Cmd+Y. Only fires when the\n // grid body (not an open editor) has focus, so a text editor's native undo\n // is never hijacked.\n if ((event.ctrlKey || event.metaKey) && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'z' && !event.shiftKey) {\n event.preventDefault();\n this.host.undo();\n return;\n }\n if ((key === 'z' && event.shiftKey) || key === 'y') {\n event.preventDefault();\n this.host.redo();\n return;\n }\n // Ctrl/Cmd+Home / Ctrl/Cmd+End jump to the grid corners (ARIA grid pattern).\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n if (event.key === 'Home') {\n this.ctrlHome();\n } else {\n this.ctrlEnd();\n }\n this.focusActiveCell();\n return;\n }\n }\n if (this.handleEditKey(event)) return;\n if (this.handlers.has(event.key)) {\n event.preventDefault();\n this.handlers.get(event.key)!.call(this);\n // Real focus follows the active cell so AT tracks the movement.\n this.focusActiveCell();\n }\n }\n}\n"]}
|
|
@@ -60,7 +60,7 @@ export class PaginationController {
|
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
#emitChanged() {
|
|
63
|
-
this.host.announce(
|
|
63
|
+
this.host.announce(this.host.localize('announce.page', { page: this.page + 1, total: this.pageCount }));
|
|
64
64
|
return this.host.emitEvent('pageChanged', { detail: this.state });
|
|
65
65
|
}
|
|
66
66
|
async gotoPage(page) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/controllers/pagination.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/controllers/pagination.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { GridHost, PaginationState } from '../internal/types.js';\n\n/**\n * Default pagination state used when no `pagination` configuration is provided.\n */\nexport const DEFAULT_PAGINATION = Object.freeze({\n mode: 'local' as const,\n page: 0,\n pageSize: 25,\n pageSizeOptions: Object.freeze([10, 25, 50, 100]) as readonly number[],\n});\n\n/**\n * Reactive controller that owns the grid's pagination state.\n *\n * @remarks\n * Exposes a state machine for the current `page` and `pageSize`, derives `pageCount`\n * from the host's data, and emits the cancellable `pageChanging` + `pageChanged`\n * events on the grid host. Page slicing itself is performed by\n * {@link PaginationDataOperation} so the controller does not mutate `dataView`.\n */\nexport class PaginationController<T extends object> implements ReactiveController {\n /**\n * The current zero-based page index.\n */\n public page: number = DEFAULT_PAGINATION.page;\n\n /**\n * The current page size.\n */\n public pageSize: number = DEFAULT_PAGINATION.pageSize;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether pagination is enabled on the host grid.\n */\n public get enabled(): boolean {\n return Boolean(this.host.pagination?.enabled);\n }\n\n /**\n * The total number of records before pagination is applied.\n *\n * @remarks\n * For `'local'` mode this is the post-filter, post-sort dataset length. For `'remote'`\n * mode the consumer must supply the value via `pagination.totalItems`.\n */\n public get totalItems(): number {\n const cfg = this.host.pagination;\n if (cfg?.mode === 'remote') {\n return Math.max(0, cfg?.totalItems ?? 0);\n }\n // @ts-expect-error - protected member access\n return this.host.dataState?.length ?? 0;\n }\n\n /**\n * The total number of pages for the current data view and `pageSize`.\n *\n * @remarks\n * Always at least `1` so a paginator can render a sensible \"1 / 1\" label for empty data.\n */\n public get pageCount(): number {\n if (!this.pageSize) return 1;\n return Math.max(1, Math.ceil(this.totalItems / this.pageSize));\n }\n\n /**\n * Returns the resolved {@link PaginationState} for the current host.\n */\n public get state(): PaginationState {\n return {\n page: this.page,\n pageSize: this.pageSize,\n pageCount: this.pageCount,\n totalItems: this.totalItems,\n };\n }\n\n /**\n * Clamps a candidate `page` index into the valid `[0, pageCount - 1]` range.\n *\n * @param page - The candidate page index.\n */\n public clamp(page: number): number {\n if (!Number.isFinite(page)) return 0;\n return Math.min(Math.max(0, Math.trunc(page)), Math.max(0, this.pageCount - 1));\n }\n\n /**\n * Re-clamps the current page after the dataset size (or `pageSize`) changes.\n *\n * @remarks\n * Called from the grid pipeline so paging never points past the last valid page.\n * Mutates `page` in place and requests a re-render when the value changes.\n */\n public reclamp(): void {\n const next = this.clamp(this.page);\n if (next !== this.page) {\n this.page = next;\n this.host.requestUpdate();\n }\n }\n\n #emitChanging(nextPage: number, nextPageSize: number) {\n return this.host.emitEvent('pageChanging', {\n detail: {\n page: this.page,\n pageSize: this.pageSize,\n nextPage,\n nextPageSize,\n },\n cancelable: true,\n });\n }\n\n #emitChanged() {\n this.host.announce(\n this.host.localize('announce.page', { page: this.page + 1, total: this.pageCount })\n );\n return this.host.emitEvent('pageChanged', { detail: this.state });\n }\n\n /**\n * Navigates to `page`, emitting the cancellable `pageChanging` event first and\n * the `pageChanged` event after the pipeline has applied.\n *\n * @param page - The target zero-based page index. Out-of-range values are clamped.\n * @returns `true` if the change was applied, `false` if it was cancelled or a no-op.\n */\n public async gotoPage(page: number): Promise<boolean> {\n const next = this.clamp(page);\n if (next === this.page) return false;\n\n if (!this.#emitChanging(next, this.pageSize)) {\n return false;\n }\n\n this.page = next;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.#emitChanged();\n return true;\n }\n\n /**\n * Sets the current page size and resets to the first page.\n *\n * @param size - The new page size. Must be a positive integer.\n * @returns `true` if the change was applied, `false` if it was cancelled or a no-op.\n */\n public async setPageSize(size: number): Promise<boolean> {\n const next = Math.max(1, Math.trunc(size));\n if (next === this.pageSize) return false;\n\n if (!this.#emitChanging(0, next)) {\n return false;\n }\n\n this.pageSize = next;\n this.page = 0;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.#emitChanged();\n return true;\n }\n\n /**\n * Navigates to the next page if not already on the last one.\n */\n public nextPage() {\n return this.gotoPage(this.page + 1);\n }\n\n /**\n * Navigates to the previous page if not already on the first one.\n */\n public previousPage() {\n return this.gotoPage(this.page - 1);\n }\n\n /**\n * Navigates to the first page.\n */\n public firstPage() {\n return this.gotoPage(0);\n }\n\n /**\n * Navigates to the last page.\n */\n public lastPage() {\n return this.gotoPage(this.pageCount - 1);\n }\n}\n"]}
|
package/controllers/row-pin.js
CHANGED
|
@@ -35,7 +35,7 @@ export class RowPinController {
|
|
|
35
35
|
this.#top.delete(row);
|
|
36
36
|
this.#bottom.delete(row);
|
|
37
37
|
(position === 'top' ? this.#top : this.#bottom).add(row);
|
|
38
|
-
this.#commit(row, position,
|
|
38
|
+
this.#commit(row, position, this.host.localize(position === 'top' ? 'announce.rowPinnedTop' : 'announce.rowPinnedBottom'));
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
41
|
unpinRow(row) {
|
|
@@ -45,7 +45,7 @@ export class RowPinController {
|
|
|
45
45
|
return false;
|
|
46
46
|
this.#top.delete(row);
|
|
47
47
|
this.#bottom.delete(row);
|
|
48
|
-
this.#commit(row, null, '
|
|
48
|
+
this.#commit(row, null, this.host.localize('announce.rowUnpinned'));
|
|
49
49
|
return true;
|
|
50
50
|
}
|
|
51
51
|
clear() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"row-pin.js","sourceRoot":"","sources":["../../src/controllers/row-pin.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,gBAAgB;IAC3B,IAAI,GAAW,IAAI,GAAG,EAAE,CAAC;IACzB,OAAO,GAAW,IAAI,GAAG,EAAE,CAAC;IAE5B,YAAsB,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QACrC,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,UAAU,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAGD,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;IACrD,CAAC;IAGM,cAAc,CAAC,GAAM;QAC1B,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAGM,QAAQ,CAAC,GAAM;QACpB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;IAGD,IAAW,UAAU;QACnB,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5D,CAAC;IAQM,MAAM,CAAC,GAAM,EAAE,QAAwB;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"row-pin.js","sourceRoot":"","sources":["../../src/controllers/row-pin.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,gBAAgB;IAC3B,IAAI,GAAW,IAAI,GAAG,EAAE,CAAC;IACzB,OAAO,GAAW,IAAI,GAAG,EAAE,CAAC;IAE5B,YAAsB,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QACrC,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,UAAU,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAGD,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;IACrD,CAAC;IAGM,cAAc,CAAC,GAAM;QAC1B,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAGM,QAAQ,CAAC,GAAM;QACpB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;IAGD,IAAW,UAAU;QACnB,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5D,CAAC;IAQM,MAAM,CAAC,GAAM,EAAE,QAAwB;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,CACV,GAAG,EACH,QAAQ,EACR,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAC9F,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAQM,QAAQ,CAAC,GAAM;QACpB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAEhD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAGM,KAAK;QACV,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QAChC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAOM,OAAO,CAAC,GAAqB,EAAE,MAAwB;QAC5D,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAED,YAAY,CAAC,GAAM,EAAE,QAA+B;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE;YACvC,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE;YACzB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAM,EAAE,QAA+B,EAAE,OAAe;QAC9D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;CACF","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { GridHost } from '../internal/types.js';\n\n/** Where a row is pinned, or `null` when it scrolls with the body. */\nexport type RowPinPosition = 'top' | 'bottom';\n\n/**\n * Reactive controller backing row pinning.\n *\n * @remarks\n * Pinned rows are lifted out of the scrollable body and rendered in sticky\n * bands above (`'top'`) or below (`'bottom'`) the virtualized rows. State is\n * reference-based: the controller holds a `Set` of row data references per band,\n * so pins survive sort / filter / pagination as long as those preserve row\n * identity (the default in-place pipeline does). Replacing {@link ApexGrid.data}\n * wholesale should be followed by re-pinning or {@link clear}.\n *\n * Mutations go through the cancellable `rowPinning` event and emit a follow-up\n * `rowPinned` event, mirroring selection / expansion.\n */\nexport class RowPinController<T extends object> implements ReactiveController {\n #top: Set<T> = new Set();\n #bottom: Set<T> = new Set();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /** Whether row pinning is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.rowPinning?.enabled);\n }\n\n /** Whether any row is currently pinned. */\n public get hasPinnedRows(): boolean {\n return this.#top.size > 0 || this.#bottom.size > 0;\n }\n\n /** The band `row` is pinned to, or `null` when it is not pinned. */\n public pinnedPosition(row: T): RowPinPosition | null {\n if (this.#top.has(row)) return 'top';\n if (this.#bottom.has(row)) return 'bottom';\n return null;\n }\n\n /** Whether `row` is pinned to either band. */\n public isPinned(row: T): boolean {\n return this.#top.has(row) || this.#bottom.has(row);\n }\n\n /** Pinned rows per band, in the order they were pinned. */\n public get pinnedRows(): { top: T[]; bottom: T[] } {\n return { top: [...this.#top], bottom: [...this.#bottom] };\n }\n\n /**\n * Pins `row` to the given band. Moves it between bands when already pinned\n * elsewhere. No-op (returns `true`) when it is already pinned there.\n *\n * @returns `true` when applied, `false` when disabled or cancelled.\n */\n public pinRow(row: T, position: RowPinPosition): boolean {\n if (!this.enabled) return false;\n if (this.pinnedPosition(row) === position) return true;\n if (!this.#emitPinning(row, position)) return false;\n\n this.#top.delete(row);\n this.#bottom.delete(row);\n (position === 'top' ? this.#top : this.#bottom).add(row);\n this.#commit(\n row,\n position,\n this.host.localize(position === 'top' ? 'announce.rowPinnedTop' : 'announce.rowPinnedBottom')\n );\n return true;\n }\n\n /**\n * Unpins `row` from whichever band holds it. No-op (returns `true`) when it is\n * not pinned.\n *\n * @returns `true` when applied, `false` when cancelled.\n */\n public unpinRow(row: T): boolean {\n if (!this.isPinned(row)) return true;\n if (!this.#emitPinning(row, null)) return false;\n\n this.#top.delete(row);\n this.#bottom.delete(row);\n this.#commit(row, null, this.host.localize('announce.rowUnpinned'));\n return true;\n }\n\n /** Clears every pin in both bands. */\n public clear(): void {\n if (!this.hasPinnedRows) return;\n this.#top.clear();\n this.#bottom.clear();\n this.host.requestUpdate();\n }\n\n /**\n * Restores pinned rows from explicit per-band reference lists (state restore),\n * replacing any current pins. Silent: emits no `rowPinning` / `rowPinned` and\n * preserves the given order within each band.\n */\n public restore(top: ReadonlyArray<T>, bottom: ReadonlyArray<T>): void {\n this.#top = new Set(top);\n this.#bottom = new Set(bottom);\n this.host.requestUpdate();\n }\n\n #emitPinning(row: T, position: RowPinPosition | null): boolean {\n return this.host.emitEvent('rowPinning', {\n detail: { row, position },\n cancelable: true,\n });\n }\n\n #commit(row: T, position: RowPinPosition | null, message: string): void {\n this.host.requestUpdate();\n this.host.announce(message);\n this.host.emitEvent('rowPinned', { detail: { row, position } });\n }\n}\n"]}
|
|
@@ -101,7 +101,7 @@ export class RowReorderController {
|
|
|
101
101
|
this.#order = null;
|
|
102
102
|
this.host.requestUpdate(PIPELINE);
|
|
103
103
|
if (announce)
|
|
104
|
-
this.host.announce('
|
|
104
|
+
this.host.announce(this.host.localize('announce.manualOrderCleared'));
|
|
105
105
|
}
|
|
106
106
|
moveRow(from, to, position = 'before') {
|
|
107
107
|
const view = this.host.pageItems;
|
|
@@ -214,7 +214,7 @@ export class RowReorderController {
|
|
|
214
214
|
this.grabbed = row;
|
|
215
215
|
this.#preGrab = this.#order ? [...this.#order] : null;
|
|
216
216
|
this.host.requestUpdate();
|
|
217
|
-
this.host.announce(
|
|
217
|
+
this.host.announce(this.host.localize('announce.rowGrabbed'));
|
|
218
218
|
return true;
|
|
219
219
|
}
|
|
220
220
|
moveGrabbed(direction) {
|
|
@@ -232,7 +232,7 @@ export class RowReorderController {
|
|
|
232
232
|
if (!ok)
|
|
233
233
|
return -1;
|
|
234
234
|
void this.#flipAfterUpdate(before);
|
|
235
|
-
this.host.announce(
|
|
235
|
+
this.host.announce(this.host.localize('announce.rowMovedTo', { position: target + 1 }));
|
|
236
236
|
return target;
|
|
237
237
|
}
|
|
238
238
|
drop() {
|
|
@@ -241,7 +241,7 @@ export class RowReorderController {
|
|
|
241
241
|
this.grabbed = null;
|
|
242
242
|
this.#preGrab = null;
|
|
243
243
|
this.host.requestUpdate();
|
|
244
|
-
this.host.announce('
|
|
244
|
+
this.host.announce(this.host.localize('announce.rowDropped'));
|
|
245
245
|
}
|
|
246
246
|
cancelGrab() {
|
|
247
247
|
if (!this.grabbed)
|
|
@@ -250,7 +250,7 @@ export class RowReorderController {
|
|
|
250
250
|
this.#order = this.#preGrab;
|
|
251
251
|
this.#preGrab = null;
|
|
252
252
|
this.host.requestUpdate(PIPELINE);
|
|
253
|
-
this.host.announce('
|
|
253
|
+
this.host.announce(this.host.localize('announce.reorderCancelled'));
|
|
254
254
|
}
|
|
255
255
|
#commit(source, target, position, options = {}) {
|
|
256
256
|
if (!this.enabled || !source || !target || source === target)
|
|
@@ -281,7 +281,7 @@ export class RowReorderController {
|
|
|
281
281
|
}
|
|
282
282
|
this.host.requestUpdate(PIPELINE);
|
|
283
283
|
if (!options.silent)
|
|
284
|
-
this.host.announce('
|
|
284
|
+
this.host.announce(this.host.localize('announce.rowMoved'));
|
|
285
285
|
this.host.emitEvent('rowMoved', { detail: { from, to, data: source } });
|
|
286
286
|
return true;
|
|
287
287
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"row-reorder.js","sourceRoot":"","sources":["../../src/controllers/row-reorder.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 { GridHost } from '../internal/types.js';\n\n/** Where a moved row lands relative to its target. */\nexport type RowDropPosition = 'before' | 'after';\n\n/** Pixels the pointer must travel before a row drag engages. */\nconst DRAG_THRESHOLD_PX = 4;\n\n/** A single cell snapshot used to paint the floating row ghost. */\nexport interface RowGhostCell {\n /** The cell's rendered text at grab time. */\n text: string;\n /** The cell's rendered width (px), so the ghost matches the column layout. */\n width: number;\n /** The cell's computed `text-align`, so numbers stay right-aligned in the ghost. */\n align: string;\n}\n\n/** Everything the row hands the controller to seed the floating ghost. */\nexport interface RowGhostInit {\n /** The source row's bounding rect at grab time. */\n rect: DOMRect;\n /** Pointer position at grab time (to keep the grab point under the cursor). */\n clientX: number;\n clientY: number;\n /** Per-cell snapshot of the row's visible content. */\n cells: RowGhostCell[];\n}\n\n/**\n * Live state for the floating \"ghost\" row that trails the cursor during a\n * pointer drag. Mirrors {@link ReorderController}'s column ghost: the source\n * row stays in the grid (and live-swaps), the ghost is a purely visual proxy.\n */\nexport interface RowGhostState {\n /** Ghost position (viewport-relative top-left, in CSS pixels). */\n x: number;\n y: number;\n /** Ghost size, fixed at the source row's initial bounding rect. */\n width: number;\n height: number;\n /** Cursor offset within the ghost so the grab point stays under the cursor. */\n pointerOffsetX: number;\n pointerOffsetY: number;\n /** Snapshot of the row's visible cells. */\n cells: ReadonlyArray<RowGhostCell>;\n}\n\n/**\n * Reactive controller backing row drag-reorder and a manual row order.\n *\n * @remarks\n * Row order is normally derived (filter → sort). This controller adds a\n * **manual order**: an explicit sequence of row references applied as a\n * pipeline step after sort. While a manual order is active, sorting is mutually\n * exclusive (applying a sort clears the manual order). State is reference-based,\n * so it survives the in-place pipeline.\n *\n * Reordering happens through {@link moveRow} (pointer live-swap during a drag,\n * the keyboard grab/move flow, or the public API). Each move goes through the\n * cancellable `rowMoving` event and emits a follow-up `rowMoved`, then animates\n * with a Y-axis FLIP. Pinned rows (F4) are never the drag source and reorder\n * only within the unpinned body set.\n *\n * Persistence: by default the order lives in this controller and the app\n * persists via `rowMoved`. With `rowReordering.applyToData` the move also\n * splices {@link ApexGrid.data} in place (and clears the manual order, since the\n * data array then carries the order).\n */\nexport class RowReorderController<T extends object> implements ReactiveController {\n /** Manual order of row references, or `null` for the natural (sorted) order. */\n #order: T[] | null = null;\n\n /** Order snapshot captured at keyboard-grab time, for Escape-to-cancel. */\n #preGrab: T[] | null = null;\n\n /** The row currently being pointer-dragged, or `null`. */\n public dragging: T | null = null;\n\n /**\n * Live floating-ghost state during a pointer drag, or `null`. Surfaced to the\n * grid, which renders the ghost at the top of its shadow tree (outside the\n * virtualizer) so `position: fixed` tracks the viewport cleanly.\n */\n public ghost: RowGhostState | null = null;\n\n /** The row currently grabbed for keyboard reorder, or `null`. */\n public grabbed: T | null = null;\n\n /** Re-entrancy guard so a slow swap can't trigger a second mid-drag. */\n #swapping = false;\n\n /**\n * In-flight pointer-drag gesture. The move/up listeners live on the **grid\n * host** (a stable element), not the row, so a live-swap that recycles the\n * source row's DOM can't tear the drag down mid-gesture.\n */\n #pending: {\n data: T;\n getGhost: () => RowGhostInit;\n startX: number;\n startY: number;\n pointerId: number;\n } | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n /** The grid host as a DOM event target (it is always an `HTMLElement`). */\n get #hostElement(): HTMLElement {\n return this.host as unknown as HTMLElement;\n }\n\n public hostConnected() {}\n\n /** Whether row reordering is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.rowReordering?.enabled);\n }\n\n /**\n * Whether a pointer drag must start from the dedicated grip handle (the\n * default), rather than from anywhere on the row. Driven by\n * `rowReordering.handle` (defaults to `true`).\n */\n public get handleMode(): boolean {\n return this.enabled && this.host.rowReordering?.handle !== false;\n }\n\n /**\n * Whether the leading grip-handle column is rendered. Only in handle mode, and\n * only while reordering is enabled.\n */\n public get showHandleColumn(): boolean {\n return this.handleMode;\n }\n\n /** Whether moves also splice {@link ApexGrid.data} in place. */\n public get applyToData(): boolean {\n return Boolean(this.host.rowReordering?.applyToData);\n }\n\n /** Whether a manual order is currently active. */\n public get hasManualOrder(): boolean {\n return this.#order !== null;\n }\n\n /** Whether a row is currently grabbed for keyboard reorder. */\n public get isGrabbing(): boolean {\n return this.grabbed !== null;\n }\n\n /**\n * Pipeline step: reorders the (post-filter, post-sort) rows by the manual\n * order. Rows absent from the manual order (e.g. newly added) keep their\n * incoming relative order at the end. Identity pass-through when inactive.\n */\n public apply(rows: T[]): T[] {\n if (!this.#order) return rows;\n const rank = new Map<T, number>();\n this.#order.forEach((row, i) => {\n rank.set(row, i);\n });\n return [...rows].sort((a, b) => {\n const ra = rank.has(a) ? (rank.get(a) as number) : Number.POSITIVE_INFINITY;\n const rb = rank.has(b) ? (rank.get(b) as number) : Number.POSITIVE_INFINITY;\n return ra - rb;\n });\n }\n\n /**\n * The current manual order as a copy of its row references, or `null` for the\n * derived order. Consumed by `ApexGrid.getState`.\n */\n public getManualOrder(): T[] | null {\n return this.#order ? [...this.#order] : null;\n }\n\n /**\n * Restores a manual order from a list of row references (state restore). Pass\n * `null` (or an empty list) to clear it. Silent: emits no `rowMoving` /\n * `rowMoved` and does not animate; re-runs the pipeline.\n */\n public restoreManualOrder(order: T[] | null): void {\n this.#order = order?.length ? [...order] : null;\n this.host.requestUpdate(PIPELINE);\n }\n\n /**\n * Clears the manual order (e.g. when a sort is applied). Re-runs the pipeline.\n */\n public clearManualOrder(announce = false): void {\n if (!this.#order) return;\n this.#order = null;\n this.host.requestUpdate(PIPELINE);\n if (announce) this.host.announce('Manual row order cleared');\n }\n\n /**\n * Moves the row at view index `from` relative to the row at view index `to`.\n * Indices are into {@link ApexGrid.pageItems}.\n *\n * @returns `true` when applied, `false` when disabled, out of range, or\n * cancelled via `rowMoving`.\n */\n public moveRow(from: number, to: number, position: RowDropPosition = 'before'): boolean {\n const view = this.host.pageItems;\n const before = this.#captureRowRects();\n const ok = this.#commit(view[from] as T, view[to] as T, position);\n if (ok) void this.#flipAfterUpdate(before);\n return ok;\n }\n\n // --- pointer drag -------------------------------------------------------\n\n /**\n * Begins a pointer drag from `source`. When `ghost` is supplied (the pointer\n * path always does), seeds the floating ghost from the source row's rect and\n * the grab point so it stays anchored under the cursor.\n */\n public startDrag(source: T, ghost?: RowGhostInit): void {\n if (!this.enabled) return;\n this.dragging = source;\n this.ghost = ghost\n ? {\n x: ghost.rect.left,\n y: ghost.rect.top,\n width: ghost.rect.width,\n height: ghost.rect.height,\n pointerOffsetX: ghost.clientX - ghost.rect.left,\n pointerOffsetY: ghost.clientY - ghost.rect.top,\n cells: ghost.cells,\n }\n : null;\n this.host.requestUpdate();\n }\n\n /** Moves the floating ghost to track the cursor. No-op without an active ghost. */\n public moveGhost(clientX: number, clientY: number): void {\n if (!this.ghost) return;\n this.ghost = {\n ...this.ghost,\n x: clientX - this.ghost.pointerOffsetX,\n y: clientY - this.ghost.pointerOffsetY,\n };\n this.host.requestUpdate();\n }\n\n /**\n * Called on pointer-move during a drag: live-swaps the dragged row past the\n * body row currently under `clientY` once the cursor crosses its midpoint.\n */\n public dragOver(clientY: number): void {\n if (!this.dragging || this.#swapping) return;\n const target = this.#bodyRowAt(clientY);\n if (!target || target.data === this.dragging) return;\n\n const view = this.host.pageItems;\n const sourceIdx = view.indexOf(this.dragging);\n const targetIdx = view.indexOf(target.data);\n if (sourceIdx === -1 || targetIdx === -1) return;\n\n const rect = target.element.getBoundingClientRect();\n const midpoint = rect.top + rect.height / 2;\n let position: RowDropPosition;\n if (sourceIdx < targetIdx) {\n if (clientY < midpoint) return; // dragging down — wait for the midpoint\n position = 'after';\n } else {\n if (clientY > midpoint) return; // dragging up\n position = 'before';\n }\n void this.#dragSwap(target.data, position);\n }\n\n /** Ends the pointer drag. The order is already final (live-swapped). */\n public endDrag(): void {\n if (!this.dragging) return;\n this.dragging = null;\n this.ghost = null;\n this.host.requestUpdate();\n }\n\n /**\n * Arms a pointer drag from a row press. Called by the row on `pointerdown`\n * (from the grip in handle mode, or anywhere in whole-row mode). The move /\n * up / cancel listeners are bound to the **grid host**, so the gesture is\n * immune to the source row's DOM being recycled by a live-swap. `getGhost` is\n * a thunk the controller invokes once, the instant the drag engages, to\n * snapshot the row's cells (the row is still in place then).\n */\n public armPointerDrag(data: T, getGhost: () => RowGhostInit, event: PointerEvent): void {\n const pinned = this.host.pinnedRows;\n if (!this.enabled || pinned.top.includes(data) || pinned.bottom.includes(data)) return;\n this.#pending = {\n data,\n getGhost,\n startX: event.clientX,\n startY: event.clientY,\n pointerId: event.pointerId,\n };\n const host = this.#hostElement;\n host.addEventListener('pointermove', this.#onHostPointerMove);\n host.addEventListener('pointerup', this.#onHostPointerUp);\n host.addEventListener('pointercancel', this.#onHostPointerUp);\n }\n\n #onHostPointerMove = (event: PointerEvent): void => {\n const pending = this.#pending;\n if (!pending || event.pointerId !== pending.pointerId) return;\n if (!this.dragging) {\n const dx = event.clientX - pending.startX;\n const dy = event.clientY - pending.startY;\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD_PX) return;\n // Capture on the stable host so moves keep arriving even when the cursor\n // leaves the grid, and so the source row reflowing can't drop the pointer.\n try {\n this.#hostElement.setPointerCapture(pending.pointerId);\n } catch {\n /* a synthetic pointer id may not be capturable; hit-testing still works */\n }\n this.startDrag(pending.data, pending.getGhost());\n }\n this.moveGhost(event.clientX, event.clientY);\n this.dragOver(event.clientY);\n };\n\n #onHostPointerUp = (event: PointerEvent): void => {\n const pending = this.#pending;\n if (!pending || event.pointerId !== pending.pointerId) return;\n const host = this.#hostElement;\n host.removeEventListener('pointermove', this.#onHostPointerMove);\n host.removeEventListener('pointerup', this.#onHostPointerUp);\n host.removeEventListener('pointercancel', this.#onHostPointerUp);\n try {\n if (host.hasPointerCapture(pending.pointerId)) host.releasePointerCapture(pending.pointerId);\n } catch {\n /* capture was never taken or already released */\n }\n this.#pending = null;\n this.endDrag();\n };\n\n async #dragSwap(target: T, position: RowDropPosition): Promise<void> {\n if (this.#swapping) return;\n this.#swapping = true;\n try {\n const before = this.#captureRowRects();\n if (this.#commit(this.dragging as T, target, position)) {\n await this.host.updateComplete;\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(before);\n }\n } finally {\n this.#swapping = false;\n }\n }\n\n // --- keyboard grab ------------------------------------------------------\n\n /** Grabs the row at view index `rowIndex` for keyboard reorder. */\n public grab(rowIndex: number): boolean {\n if (!this.enabled) return false;\n const row = this.host.pageItems[rowIndex] as T | undefined;\n if (!row) return false;\n this.grabbed = row;\n this.#preGrab = this.#order ? [...this.#order] : null;\n this.host.requestUpdate();\n this.host.announce('Row grabbed. Use arrow keys to move, Enter to drop, Escape to cancel.');\n return true;\n }\n\n /**\n * Moves the grabbed row one position in `direction`. Returns the grabbed\n * row's new view index, or `-1` when it can't move (no grab / at the edge).\n */\n public moveGrabbed(direction: -1 | 1): number {\n if (!this.grabbed) return -1;\n const view = this.host.pageItems;\n const current = view.indexOf(this.grabbed);\n const target = current + direction;\n if (current === -1 || target < 0 || target >= view.length) return -1;\n const before = this.#captureRowRects();\n const ok = this.#commit(this.grabbed, view[target] as T, direction > 0 ? 'after' : 'before', {\n silent: true,\n });\n if (!ok) return -1;\n void this.#flipAfterUpdate(before);\n this.host.announce(`Row moved to position ${target + 1}`);\n return target;\n }\n\n /** Drops the grabbed row, keeping its moves. */\n public drop(): void {\n if (!this.grabbed) return;\n this.grabbed = null;\n this.#preGrab = null;\n this.host.requestUpdate();\n this.host.announce('Row dropped');\n }\n\n /** Cancels the grab, reverting to the order captured when it was grabbed. */\n public cancelGrab(): void {\n if (!this.grabbed) return;\n this.grabbed = null;\n this.#order = this.#preGrab;\n this.#preGrab = null;\n this.host.requestUpdate(PIPELINE);\n this.host.announce('Reorder cancelled');\n }\n\n // --- internals ----------------------------------------------------------\n\n /**\n * The core order mutation: validates, emits `rowMoving` (cancellable),\n * updates the manual order (or splices data when `applyToData`), re-runs the\n * pipeline, and emits `rowMoved`. Does not animate.\n */\n #commit(\n source: T | undefined,\n target: T | undefined,\n position: RowDropPosition,\n options: { silent?: boolean } = {}\n ): boolean {\n if (!this.enabled || !source || !target || source === target) return false;\n const view = this.host.pageItems;\n const from = view.indexOf(source);\n const to = view.indexOf(target);\n\n const proceed = this.host.emitEvent('rowMoving', {\n detail: { from, to, data: source },\n cancelable: true,\n });\n if (!proceed) return false;\n\n const baseline = this.#order ?? [...(this.host.dataView as ReadonlyArray<T>)];\n const next = baseline.filter((row) => row !== source);\n let index = next.indexOf(target);\n if (index === -1) return false;\n if (position === 'after') index += 1;\n next.splice(index, 0, source);\n\n if (this.applyToData) {\n this.#spliceData(next);\n this.#order = null; // the data array now carries the order\n } else {\n this.#order = next;\n }\n\n this.host.requestUpdate(PIPELINE);\n if (!options.silent) this.host.announce('Row moved');\n this.host.emitEvent('rowMoved', { detail: { from, to, data: source } });\n return true;\n }\n\n /** Reorders {@link ApexGrid.data} in place to match `order`. */\n #spliceData(order: ReadonlyArray<T>): void {\n const rank = new Map<T, number>();\n order.forEach((row, i) => {\n rank.set(row, i);\n });\n (this.host.data as T[]).sort((a, b) => {\n const ra = rank.has(a) ? (rank.get(a) as number) : Number.POSITIVE_INFINITY;\n const rb = rank.has(b) ? (rank.get(b) as number) : Number.POSITIVE_INFINITY;\n return ra - rb;\n });\n }\n\n /** The rendered body row (non-pinned) whose box contains `clientY`. */\n #bodyRowAt(clientY: number): { data: T; element: HTMLElement } | null {\n const pinned = this.host.pinnedRows;\n for (const row of this.host.rows) {\n if (pinned.top.includes(row.data) || pinned.bottom.includes(row.data)) continue;\n const element = row as unknown as HTMLElement;\n const rect = element.getBoundingClientRect();\n if (clientY >= rect.top && clientY < rect.bottom) return { data: row.data, element };\n }\n return null;\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 async #flipAfterUpdate(before: ReadonlyArray<KeyedFlipEntry<T>>): Promise<void> {\n await this.host.updateComplete;\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(before);\n }\n\n #playRowFlip(before: ReadonlyArray<KeyedFlipEntry<T>>): void {\n const byData = new Map<T, HTMLElement>();\n for (const row of this.host.rows) {\n byData.set(row.data, row as unknown as HTMLElement);\n }\n playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"row-reorder.js","sourceRoot":"","sources":["../../src/controllers/row-reorder.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 { GridHost } from '../internal/types.js';\n\n/** Where a moved row lands relative to its target. */\nexport type RowDropPosition = 'before' | 'after';\n\n/** Pixels the pointer must travel before a row drag engages. */\nconst DRAG_THRESHOLD_PX = 4;\n\n/** A single cell snapshot used to paint the floating row ghost. */\nexport interface RowGhostCell {\n /** The cell's rendered text at grab time. */\n text: string;\n /** The cell's rendered width (px), so the ghost matches the column layout. */\n width: number;\n /** The cell's computed `text-align`, so numbers stay right-aligned in the ghost. */\n align: string;\n}\n\n/** Everything the row hands the controller to seed the floating ghost. */\nexport interface RowGhostInit {\n /** The source row's bounding rect at grab time. */\n rect: DOMRect;\n /** Pointer position at grab time (to keep the grab point under the cursor). */\n clientX: number;\n clientY: number;\n /** Per-cell snapshot of the row's visible content. */\n cells: RowGhostCell[];\n}\n\n/**\n * Live state for the floating \"ghost\" row that trails the cursor during a\n * pointer drag. Mirrors {@link ReorderController}'s column ghost: the source\n * row stays in the grid (and live-swaps), the ghost is a purely visual proxy.\n */\nexport interface RowGhostState {\n /** Ghost position (viewport-relative top-left, in CSS pixels). */\n x: number;\n y: number;\n /** Ghost size, fixed at the source row's initial bounding rect. */\n width: number;\n height: number;\n /** Cursor offset within the ghost so the grab point stays under the cursor. */\n pointerOffsetX: number;\n pointerOffsetY: number;\n /** Snapshot of the row's visible cells. */\n cells: ReadonlyArray<RowGhostCell>;\n}\n\n/**\n * Reactive controller backing row drag-reorder and a manual row order.\n *\n * @remarks\n * Row order is normally derived (filter → sort). This controller adds a\n * **manual order**: an explicit sequence of row references applied as a\n * pipeline step after sort. While a manual order is active, sorting is mutually\n * exclusive (applying a sort clears the manual order). State is reference-based,\n * so it survives the in-place pipeline.\n *\n * Reordering happens through {@link moveRow} (pointer live-swap during a drag,\n * the keyboard grab/move flow, or the public API). Each move goes through the\n * cancellable `rowMoving` event and emits a follow-up `rowMoved`, then animates\n * with a Y-axis FLIP. Pinned rows (F4) are never the drag source and reorder\n * only within the unpinned body set.\n *\n * Persistence: by default the order lives in this controller and the app\n * persists via `rowMoved`. With `rowReordering.applyToData` the move also\n * splices {@link ApexGrid.data} in place (and clears the manual order, since the\n * data array then carries the order).\n */\nexport class RowReorderController<T extends object> implements ReactiveController {\n /** Manual order of row references, or `null` for the natural (sorted) order. */\n #order: T[] | null = null;\n\n /** Order snapshot captured at keyboard-grab time, for Escape-to-cancel. */\n #preGrab: T[] | null = null;\n\n /** The row currently being pointer-dragged, or `null`. */\n public dragging: T | null = null;\n\n /**\n * Live floating-ghost state during a pointer drag, or `null`. Surfaced to the\n * grid, which renders the ghost at the top of its shadow tree (outside the\n * virtualizer) so `position: fixed` tracks the viewport cleanly.\n */\n public ghost: RowGhostState | null = null;\n\n /** The row currently grabbed for keyboard reorder, or `null`. */\n public grabbed: T | null = null;\n\n /** Re-entrancy guard so a slow swap can't trigger a second mid-drag. */\n #swapping = false;\n\n /**\n * In-flight pointer-drag gesture. The move/up listeners live on the **grid\n * host** (a stable element), not the row, so a live-swap that recycles the\n * source row's DOM can't tear the drag down mid-gesture.\n */\n #pending: {\n data: T;\n getGhost: () => RowGhostInit;\n startX: number;\n startY: number;\n pointerId: number;\n } | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n /** The grid host as a DOM event target (it is always an `HTMLElement`). */\n get #hostElement(): HTMLElement {\n return this.host as unknown as HTMLElement;\n }\n\n public hostConnected() {}\n\n /** Whether row reordering is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.rowReordering?.enabled);\n }\n\n /**\n * Whether a pointer drag must start from the dedicated grip handle (the\n * default), rather than from anywhere on the row. Driven by\n * `rowReordering.handle` (defaults to `true`).\n */\n public get handleMode(): boolean {\n return this.enabled && this.host.rowReordering?.handle !== false;\n }\n\n /**\n * Whether the leading grip-handle column is rendered. Only in handle mode, and\n * only while reordering is enabled.\n */\n public get showHandleColumn(): boolean {\n return this.handleMode;\n }\n\n /** Whether moves also splice {@link ApexGrid.data} in place. */\n public get applyToData(): boolean {\n return Boolean(this.host.rowReordering?.applyToData);\n }\n\n /** Whether a manual order is currently active. */\n public get hasManualOrder(): boolean {\n return this.#order !== null;\n }\n\n /** Whether a row is currently grabbed for keyboard reorder. */\n public get isGrabbing(): boolean {\n return this.grabbed !== null;\n }\n\n /**\n * Pipeline step: reorders the (post-filter, post-sort) rows by the manual\n * order. Rows absent from the manual order (e.g. newly added) keep their\n * incoming relative order at the end. Identity pass-through when inactive.\n */\n public apply(rows: T[]): T[] {\n if (!this.#order) return rows;\n const rank = new Map<T, number>();\n this.#order.forEach((row, i) => {\n rank.set(row, i);\n });\n return [...rows].sort((a, b) => {\n const ra = rank.has(a) ? (rank.get(a) as number) : Number.POSITIVE_INFINITY;\n const rb = rank.has(b) ? (rank.get(b) as number) : Number.POSITIVE_INFINITY;\n return ra - rb;\n });\n }\n\n /**\n * The current manual order as a copy of its row references, or `null` for the\n * derived order. Consumed by `ApexGrid.getState`.\n */\n public getManualOrder(): T[] | null {\n return this.#order ? [...this.#order] : null;\n }\n\n /**\n * Restores a manual order from a list of row references (state restore). Pass\n * `null` (or an empty list) to clear it. Silent: emits no `rowMoving` /\n * `rowMoved` and does not animate; re-runs the pipeline.\n */\n public restoreManualOrder(order: T[] | null): void {\n this.#order = order?.length ? [...order] : null;\n this.host.requestUpdate(PIPELINE);\n }\n\n /**\n * Clears the manual order (e.g. when a sort is applied). Re-runs the pipeline.\n */\n public clearManualOrder(announce = false): void {\n if (!this.#order) return;\n this.#order = null;\n this.host.requestUpdate(PIPELINE);\n if (announce) this.host.announce(this.host.localize('announce.manualOrderCleared'));\n }\n\n /**\n * Moves the row at view index `from` relative to the row at view index `to`.\n * Indices are into {@link ApexGrid.pageItems}.\n *\n * @returns `true` when applied, `false` when disabled, out of range, or\n * cancelled via `rowMoving`.\n */\n public moveRow(from: number, to: number, position: RowDropPosition = 'before'): boolean {\n const view = this.host.pageItems;\n const before = this.#captureRowRects();\n const ok = this.#commit(view[from] as T, view[to] as T, position);\n if (ok) void this.#flipAfterUpdate(before);\n return ok;\n }\n\n // --- pointer drag -------------------------------------------------------\n\n /**\n * Begins a pointer drag from `source`. When `ghost` is supplied (the pointer\n * path always does), seeds the floating ghost from the source row's rect and\n * the grab point so it stays anchored under the cursor.\n */\n public startDrag(source: T, ghost?: RowGhostInit): void {\n if (!this.enabled) return;\n this.dragging = source;\n this.ghost = ghost\n ? {\n x: ghost.rect.left,\n y: ghost.rect.top,\n width: ghost.rect.width,\n height: ghost.rect.height,\n pointerOffsetX: ghost.clientX - ghost.rect.left,\n pointerOffsetY: ghost.clientY - ghost.rect.top,\n cells: ghost.cells,\n }\n : null;\n this.host.requestUpdate();\n }\n\n /** Moves the floating ghost to track the cursor. No-op without an active ghost. */\n public moveGhost(clientX: number, clientY: number): void {\n if (!this.ghost) return;\n this.ghost = {\n ...this.ghost,\n x: clientX - this.ghost.pointerOffsetX,\n y: clientY - this.ghost.pointerOffsetY,\n };\n this.host.requestUpdate();\n }\n\n /**\n * Called on pointer-move during a drag: live-swaps the dragged row past the\n * body row currently under `clientY` once the cursor crosses its midpoint.\n */\n public dragOver(clientY: number): void {\n if (!this.dragging || this.#swapping) return;\n const target = this.#bodyRowAt(clientY);\n if (!target || target.data === this.dragging) return;\n\n const view = this.host.pageItems;\n const sourceIdx = view.indexOf(this.dragging);\n const targetIdx = view.indexOf(target.data);\n if (sourceIdx === -1 || targetIdx === -1) return;\n\n const rect = target.element.getBoundingClientRect();\n const midpoint = rect.top + rect.height / 2;\n let position: RowDropPosition;\n if (sourceIdx < targetIdx) {\n if (clientY < midpoint) return; // dragging down — wait for the midpoint\n position = 'after';\n } else {\n if (clientY > midpoint) return; // dragging up\n position = 'before';\n }\n void this.#dragSwap(target.data, position);\n }\n\n /** Ends the pointer drag. The order is already final (live-swapped). */\n public endDrag(): void {\n if (!this.dragging) return;\n this.dragging = null;\n this.ghost = null;\n this.host.requestUpdate();\n }\n\n /**\n * Arms a pointer drag from a row press. Called by the row on `pointerdown`\n * (from the grip in handle mode, or anywhere in whole-row mode). The move /\n * up / cancel listeners are bound to the **grid host**, so the gesture is\n * immune to the source row's DOM being recycled by a live-swap. `getGhost` is\n * a thunk the controller invokes once, the instant the drag engages, to\n * snapshot the row's cells (the row is still in place then).\n */\n public armPointerDrag(data: T, getGhost: () => RowGhostInit, event: PointerEvent): void {\n const pinned = this.host.pinnedRows;\n if (!this.enabled || pinned.top.includes(data) || pinned.bottom.includes(data)) return;\n this.#pending = {\n data,\n getGhost,\n startX: event.clientX,\n startY: event.clientY,\n pointerId: event.pointerId,\n };\n const host = this.#hostElement;\n host.addEventListener('pointermove', this.#onHostPointerMove);\n host.addEventListener('pointerup', this.#onHostPointerUp);\n host.addEventListener('pointercancel', this.#onHostPointerUp);\n }\n\n #onHostPointerMove = (event: PointerEvent): void => {\n const pending = this.#pending;\n if (!pending || event.pointerId !== pending.pointerId) return;\n if (!this.dragging) {\n const dx = event.clientX - pending.startX;\n const dy = event.clientY - pending.startY;\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD_PX) return;\n // Capture on the stable host so moves keep arriving even when the cursor\n // leaves the grid, and so the source row reflowing can't drop the pointer.\n try {\n this.#hostElement.setPointerCapture(pending.pointerId);\n } catch {\n /* a synthetic pointer id may not be capturable; hit-testing still works */\n }\n this.startDrag(pending.data, pending.getGhost());\n }\n this.moveGhost(event.clientX, event.clientY);\n this.dragOver(event.clientY);\n };\n\n #onHostPointerUp = (event: PointerEvent): void => {\n const pending = this.#pending;\n if (!pending || event.pointerId !== pending.pointerId) return;\n const host = this.#hostElement;\n host.removeEventListener('pointermove', this.#onHostPointerMove);\n host.removeEventListener('pointerup', this.#onHostPointerUp);\n host.removeEventListener('pointercancel', this.#onHostPointerUp);\n try {\n if (host.hasPointerCapture(pending.pointerId)) host.releasePointerCapture(pending.pointerId);\n } catch {\n /* capture was never taken or already released */\n }\n this.#pending = null;\n this.endDrag();\n };\n\n async #dragSwap(target: T, position: RowDropPosition): Promise<void> {\n if (this.#swapping) return;\n this.#swapping = true;\n try {\n const before = this.#captureRowRects();\n if (this.#commit(this.dragging as T, target, position)) {\n await this.host.updateComplete;\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(before);\n }\n } finally {\n this.#swapping = false;\n }\n }\n\n // --- keyboard grab ------------------------------------------------------\n\n /** Grabs the row at view index `rowIndex` for keyboard reorder. */\n public grab(rowIndex: number): boolean {\n if (!this.enabled) return false;\n const row = this.host.pageItems[rowIndex] as T | undefined;\n if (!row) return false;\n this.grabbed = row;\n this.#preGrab = this.#order ? [...this.#order] : null;\n this.host.requestUpdate();\n this.host.announce(this.host.localize('announce.rowGrabbed'));\n return true;\n }\n\n /**\n * Moves the grabbed row one position in `direction`. Returns the grabbed\n * row's new view index, or `-1` when it can't move (no grab / at the edge).\n */\n public moveGrabbed(direction: -1 | 1): number {\n if (!this.grabbed) return -1;\n const view = this.host.pageItems;\n const current = view.indexOf(this.grabbed);\n const target = current + direction;\n if (current === -1 || target < 0 || target >= view.length) return -1;\n const before = this.#captureRowRects();\n const ok = this.#commit(this.grabbed, view[target] as T, direction > 0 ? 'after' : 'before', {\n silent: true,\n });\n if (!ok) return -1;\n void this.#flipAfterUpdate(before);\n this.host.announce(this.host.localize('announce.rowMovedTo', { position: target + 1 }));\n return target;\n }\n\n /** Drops the grabbed row, keeping its moves. */\n public drop(): void {\n if (!this.grabbed) return;\n this.grabbed = null;\n this.#preGrab = null;\n this.host.requestUpdate();\n this.host.announce(this.host.localize('announce.rowDropped'));\n }\n\n /** Cancels the grab, reverting to the order captured when it was grabbed. */\n public cancelGrab(): void {\n if (!this.grabbed) return;\n this.grabbed = null;\n this.#order = this.#preGrab;\n this.#preGrab = null;\n this.host.requestUpdate(PIPELINE);\n this.host.announce(this.host.localize('announce.reorderCancelled'));\n }\n\n // --- internals ----------------------------------------------------------\n\n /**\n * The core order mutation: validates, emits `rowMoving` (cancellable),\n * updates the manual order (or splices data when `applyToData`), re-runs the\n * pipeline, and emits `rowMoved`. Does not animate.\n */\n #commit(\n source: T | undefined,\n target: T | undefined,\n position: RowDropPosition,\n options: { silent?: boolean } = {}\n ): boolean {\n if (!this.enabled || !source || !target || source === target) return false;\n const view = this.host.pageItems;\n const from = view.indexOf(source);\n const to = view.indexOf(target);\n\n const proceed = this.host.emitEvent('rowMoving', {\n detail: { from, to, data: source },\n cancelable: true,\n });\n if (!proceed) return false;\n\n const baseline = this.#order ?? [...(this.host.dataView as ReadonlyArray<T>)];\n const next = baseline.filter((row) => row !== source);\n let index = next.indexOf(target);\n if (index === -1) return false;\n if (position === 'after') index += 1;\n next.splice(index, 0, source);\n\n if (this.applyToData) {\n this.#spliceData(next);\n this.#order = null; // the data array now carries the order\n } else {\n this.#order = next;\n }\n\n this.host.requestUpdate(PIPELINE);\n if (!options.silent) this.host.announce(this.host.localize('announce.rowMoved'));\n this.host.emitEvent('rowMoved', { detail: { from, to, data: source } });\n return true;\n }\n\n /** Reorders {@link ApexGrid.data} in place to match `order`. */\n #spliceData(order: ReadonlyArray<T>): void {\n const rank = new Map<T, number>();\n order.forEach((row, i) => {\n rank.set(row, i);\n });\n (this.host.data as T[]).sort((a, b) => {\n const ra = rank.has(a) ? (rank.get(a) as number) : Number.POSITIVE_INFINITY;\n const rb = rank.has(b) ? (rank.get(b) as number) : Number.POSITIVE_INFINITY;\n return ra - rb;\n });\n }\n\n /** The rendered body row (non-pinned) whose box contains `clientY`. */\n #bodyRowAt(clientY: number): { data: T; element: HTMLElement } | null {\n const pinned = this.host.pinnedRows;\n for (const row of this.host.rows) {\n if (pinned.top.includes(row.data) || pinned.bottom.includes(row.data)) continue;\n const element = row as unknown as HTMLElement;\n const rect = element.getBoundingClientRect();\n if (clientY >= rect.top && clientY < rect.bottom) return { data: row.data, element };\n }\n return null;\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 async #flipAfterUpdate(before: ReadonlyArray<KeyedFlipEntry<T>>): Promise<void> {\n await this.host.updateComplete;\n await awaitChildUpdates(this.host.rows);\n this.#playRowFlip(before);\n }\n\n #playRowFlip(before: ReadonlyArray<KeyedFlipEntry<T>>): void {\n const byData = new Map<T, HTMLElement>();\n for (const row of this.host.rows) {\n byData.set(row.data, row as unknown as HTMLElement);\n }\n playKeyedFlip(before, (data) => byData.get(data) ?? null, 'y');\n }\n}\n"]}
|
package/controllers/selection.js
CHANGED
|
@@ -151,13 +151,13 @@ export class SelectionController {
|
|
|
151
151
|
this.host.requestUpdate();
|
|
152
152
|
const total = this.selected.size;
|
|
153
153
|
if (total === 0) {
|
|
154
|
-
this.host.announce('
|
|
154
|
+
this.host.announce(this.host.localize('announce.selectionCleared'));
|
|
155
155
|
}
|
|
156
156
|
else if (added.length === 1 && removed.length === 0 && total === 1) {
|
|
157
|
-
this.host.announce('
|
|
157
|
+
this.host.announce(this.host.localize('announce.rowSelected'));
|
|
158
158
|
}
|
|
159
159
|
else {
|
|
160
|
-
this.host.announce(
|
|
160
|
+
this.host.announce(this.host.localize('announce.rowsSelected', { count: total }));
|
|
161
161
|
}
|
|
162
162
|
this.host.emitEvent('rowSelected', {
|
|
163
163
|
detail: { added, removed, selected: Array.from(this.selected) },
|