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
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import type { ReactiveController } from 'lit';
|
|
2
2
|
import type { GridHost } from '../internal/types.js';
|
|
3
3
|
import FilterDataOperation from '../operations/filter.js';
|
|
4
|
+
import QuickFilterDataOperation from '../operations/quick-filter.js';
|
|
4
5
|
import SortDataOperation from '../operations/sort.js';
|
|
5
6
|
import type { StateController } from './state.js';
|
|
6
7
|
export declare class DataOperationsController<T extends object> implements ReactiveController {
|
|
7
8
|
protected host: GridHost<T>;
|
|
8
9
|
protected sorting: SortDataOperation<T>;
|
|
9
10
|
protected filtering: FilterDataOperation<T>;
|
|
11
|
+
protected quickFiltering: QuickFilterDataOperation<T>;
|
|
10
12
|
constructor(host: GridHost<T>);
|
|
11
13
|
hostConnected(): void;
|
|
12
14
|
protected get hasCustomSort(): boolean;
|
|
13
15
|
protected get hasCustomFilter(): boolean;
|
|
16
|
+
protected get hasCustomQuickFilter(): boolean;
|
|
14
17
|
protected get customFilter(): import("../index.js").DataPipelineHook<T>;
|
|
15
18
|
protected get customSort(): import("../index.js").DataPipelineHook<T>;
|
|
19
|
+
protected get customQuickFilter(): import("../index.js").DataPipelineHook<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Applies the quick-filter (global search), column-filter, and sort steps of the
|
|
22
|
+
* data pipeline.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* The returned dataset is the full post-filter, post-sort view. Pagination is
|
|
26
|
+
* intentionally not applied here so callers can derive `totalItems` and the
|
|
27
|
+
* paginator's `pageCount` from a stable value. The grid slices the page for
|
|
28
|
+
* the virtualizer at render time.
|
|
29
|
+
*/
|
|
16
30
|
apply(data: T[], state: StateController<T>): Promise<T[]>;
|
|
17
31
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { isDefined } from '../internal/is-defined.js';
|
|
2
2
|
import FilterDataOperation from '../operations/filter.js';
|
|
3
|
+
import QuickFilterDataOperation from '../operations/quick-filter.js';
|
|
3
4
|
import SortDataOperation from '../operations/sort.js';
|
|
4
5
|
export class DataOperationsController {
|
|
5
6
|
constructor(host) {
|
|
6
7
|
this.host = host;
|
|
7
8
|
this.sorting = new SortDataOperation();
|
|
8
9
|
this.filtering = new FilterDataOperation();
|
|
10
|
+
this.quickFiltering = new QuickFilterDataOperation();
|
|
9
11
|
this.host.addController(this);
|
|
10
12
|
}
|
|
11
13
|
hostConnected() { }
|
|
@@ -15,21 +17,36 @@ export class DataOperationsController {
|
|
|
15
17
|
get hasCustomFilter() {
|
|
16
18
|
return isDefined(this.host.dataPipelineConfiguration?.filter);
|
|
17
19
|
}
|
|
20
|
+
get hasCustomQuickFilter() {
|
|
21
|
+
return isDefined(this.host.dataPipelineConfiguration?.quickFilter);
|
|
22
|
+
}
|
|
18
23
|
get customFilter() {
|
|
19
24
|
return this.host.dataPipelineConfiguration.filter;
|
|
20
25
|
}
|
|
21
26
|
get customSort() {
|
|
22
27
|
return this.host.dataPipelineConfiguration.sort;
|
|
23
28
|
}
|
|
29
|
+
get customQuickFilter() {
|
|
30
|
+
return this.host.dataPipelineConfiguration.quickFilter;
|
|
31
|
+
}
|
|
24
32
|
async apply(data, state) {
|
|
25
33
|
const { filtering, sorting } = state;
|
|
26
34
|
let transformed;
|
|
35
|
+
const quickFilterTerm = (this.host.quickFilter ?? '').trim();
|
|
36
|
+
transformed = this.hasCustomQuickFilter
|
|
37
|
+
? await this.customQuickFilter({ data, grid: this.host, type: 'quickFilter' })
|
|
38
|
+
: quickFilterTerm
|
|
39
|
+
? this.quickFiltering.apply(data, quickFilterTerm, this.host.columns)
|
|
40
|
+
: data;
|
|
27
41
|
transformed = this.hasCustomFilter
|
|
28
|
-
? await this.customFilter({ data, grid: this.host, type: 'filter' })
|
|
29
|
-
: this.filtering.apply(
|
|
42
|
+
? await this.customFilter({ data: transformed, grid: this.host, type: 'filter' })
|
|
43
|
+
: this.filtering.apply(transformed, filtering.state);
|
|
30
44
|
transformed = this.hasCustomSort
|
|
31
45
|
? await this.customSort({ data: transformed, grid: this.host, type: 'sort' })
|
|
32
46
|
: this.sorting.apply(transformed, sorting.state);
|
|
47
|
+
if (state.tree.enabled) {
|
|
48
|
+
transformed = state.tree.process(transformed);
|
|
49
|
+
}
|
|
33
50
|
return transformed;
|
|
34
51
|
}
|
|
35
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-operation.js","sourceRoot":"","sources":["../../src/controllers/data-operation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,OAAO,mBAAmB,MAAM,yBAAyB,CAAC;AAC1D,OAAO,iBAAiB,MAAM,uBAAuB,CAAC;AAGtD,MAAM,OAAO,wBAAwB;
|
|
1
|
+
{"version":3,"file":"data-operation.js","sourceRoot":"","sources":["../../src/controllers/data-operation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { isDefined } from '../internal/is-defined.js';\nimport type { GridHost } from '../internal/types.js';\nimport FilterDataOperation from '../operations/filter.js';\nimport QuickFilterDataOperation from '../operations/quick-filter.js';\nimport SortDataOperation from '../operations/sort.js';\nimport type { StateController } from './state.js';\n\nexport class DataOperationsController<T extends object> implements ReactiveController {\n protected sorting = new SortDataOperation<T>();\n protected filtering = new FilterDataOperation<T>();\n protected quickFiltering = new QuickFilterDataOperation<T>();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n protected get hasCustomSort() {\n return isDefined(this.host.dataPipelineConfiguration?.sort);\n }\n\n protected get hasCustomFilter() {\n return isDefined(this.host.dataPipelineConfiguration?.filter);\n }\n\n protected get hasCustomQuickFilter() {\n return isDefined(this.host.dataPipelineConfiguration?.quickFilter);\n }\n\n protected get customFilter() {\n return this.host.dataPipelineConfiguration!.filter!;\n }\n\n protected get customSort() {\n return this.host.dataPipelineConfiguration!.sort!;\n }\n\n protected get customQuickFilter() {\n return this.host.dataPipelineConfiguration!.quickFilter!;\n }\n\n /**\n * Applies the quick-filter (global search), column-filter, and sort steps of the\n * data pipeline.\n *\n * @remarks\n * The returned dataset is the full post-filter, post-sort view. Pagination is\n * intentionally not applied here so callers can derive `totalItems` and the\n * paginator's `pageCount` from a stable value. The grid slices the page for\n * the virtualizer at render time.\n */\n public async apply(data: T[], state: StateController<T>) {\n const { filtering, sorting } = state;\n let transformed: T[];\n\n const quickFilterTerm = (this.host.quickFilter ?? '').trim();\n transformed = this.hasCustomQuickFilter\n ? await this.customQuickFilter({ data, grid: this.host, type: 'quickFilter' })\n : quickFilterTerm\n ? this.quickFiltering.apply(data, quickFilterTerm, this.host.columns)\n : data;\n\n transformed = this.hasCustomFilter\n ? await this.customFilter({ data: transformed, grid: this.host, type: 'filter' })\n : this.filtering.apply(transformed, filtering.state);\n\n transformed = this.hasCustomSort\n ? await this.customSort({ data: transformed, grid: this.host, type: 'sort' })\n : this.sorting.apply(transformed, sorting.state);\n\n // Tree mode flattens the post-sort rows according to the current\n // expansion set. Disabled is a no-op pass-through, so flat tables keep\n // their existing behaviour untouched.\n if (state.tree.enabled) {\n transformed = state.tree.process(transformed);\n }\n\n return transformed;\n }\n}\n"]}
|
package/controllers/dom.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RenderItemFunction } from '@lit-labs/virtualizer/virtualize.js';
|
|
2
2
|
import { type ReactiveController } from 'lit';
|
|
3
3
|
import { type StyleInfo } from 'lit/directives/style-map.js';
|
|
4
|
-
import type { GridHost } from '../internal/types.js';
|
|
4
|
+
import type { ColumnConfiguration, GridHost } from '../internal/types.js';
|
|
5
5
|
import type { StateController } from './state.js';
|
|
6
6
|
export declare class GridDOMController<T extends object> implements ReactiveController {
|
|
7
7
|
#private;
|
|
@@ -9,11 +9,47 @@ export declare class GridDOMController<T extends object> implements ReactiveCont
|
|
|
9
9
|
protected state: StateController<T>;
|
|
10
10
|
constructor(host: GridHost<T>, state: StateController<T>);
|
|
11
11
|
get container(): import("../components/virtualizer.js").default;
|
|
12
|
+
/**
|
|
13
|
+
* Visual render order: `'start'`-pinned columns first, then unpinned, then
|
|
14
|
+
* `'end'`-pinned. The user-supplied `columns` array is never mutated.
|
|
15
|
+
*/
|
|
16
|
+
get displayColumns(): Array<ColumnConfiguration<T>>;
|
|
12
17
|
columnSizes: StyleInfo;
|
|
18
|
+
/**
|
|
19
|
+
* The resolved inline-start (for `'start'` pin) or inline-end (for `'end'` pin)
|
|
20
|
+
* pixel offset per pinned column key. Populated after layout by
|
|
21
|
+
* {@link recomputePinOffsets}.
|
|
22
|
+
*/
|
|
23
|
+
pinOffsets: Map<keyof T, number>;
|
|
13
24
|
rowRenderer: RenderItemFunction<T>;
|
|
14
25
|
hostConnected(): Promise<void>;
|
|
15
26
|
hostUpdate(): void;
|
|
27
|
+
hostUpdated(): void;
|
|
28
|
+
hostDisconnected(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Writes the grid host's `clientWidth` into `--apex-host-width`. Used by the
|
|
31
|
+
* toolbar and paginator to clamp their width to the visible viewport so
|
|
32
|
+
* horizontal scrolling doesn't drag them off-screen.
|
|
33
|
+
*/
|
|
34
|
+
recomputeHostWidth(): void;
|
|
16
35
|
setScrollOffset(): void;
|
|
17
36
|
protected setGridColumnSizes(): void;
|
|
18
37
|
getActiveRowStyles(index: number): StyleInfo;
|
|
38
|
+
/**
|
|
39
|
+
* Measures the rendered widths of pinned header cells and writes cumulative
|
|
40
|
+
* inline-start / inline-end pixel offsets into {@link pinOffsets}. Called after
|
|
41
|
+
* each grid update and whenever a header cell is resized.
|
|
42
|
+
*/
|
|
43
|
+
recomputePinOffsets(): void;
|
|
44
|
+
protected observeHeaderCells(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Writes the cumulative height of the sticky top rows into CSS custom
|
|
47
|
+
* properties used by the header/filter rows for their `inset-block-start`
|
|
48
|
+
* offsets. The toolbar is always at `top: 0`; the header sits below it
|
|
49
|
+
* (`--apex-row-top-header`) and the filter sits below the header
|
|
50
|
+
* (`--apex-row-top-filter`). Writes are skipped when the values haven't
|
|
51
|
+
* changed so the ResizeObserver feedback loop terminates.
|
|
52
|
+
*/
|
|
53
|
+
recomputeStickyRowOffsets(): void;
|
|
54
|
+
protected observeStickyRows(): void;
|
|
19
55
|
}
|
package/controllers/dom.js
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
3
|
-
import {
|
|
4
|
-
import { applyColumnWidths } from '../internal/utils.js';
|
|
3
|
+
import { applyColumnWidths, getDisplayColumns } from '../internal/utils.js';
|
|
5
4
|
export class GridDOMController {
|
|
6
5
|
constructor(host, state) {
|
|
7
6
|
this.host = host;
|
|
8
7
|
this.state = state;
|
|
9
8
|
this.#initialSize = () => {
|
|
10
|
-
setTimeout(() =>
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
this.setScrollOffset();
|
|
11
|
+
this.recomputePinOffsets();
|
|
12
|
+
this.recomputeStickyRowOffsets();
|
|
13
|
+
});
|
|
11
14
|
};
|
|
15
|
+
this.#resizeObserver = null;
|
|
16
|
+
this.#observedHeaders = new Set();
|
|
17
|
+
this.#stickyRowObserver = null;
|
|
18
|
+
this.#observedStickyRows = new Set();
|
|
12
19
|
this.columnSizes = {};
|
|
20
|
+
this.pinOffsets = new Map();
|
|
13
21
|
this.rowRenderer = (data, index) => {
|
|
22
|
+
const editingCell = this.state.editing.activeCell;
|
|
23
|
+
const editingKey = editingCell?.rowIndex === index ? editingCell.columnKey : null;
|
|
24
|
+
const hasFilter = this.host.columns.some((column) => column.filter);
|
|
25
|
+
const ariaRowOffset = hasFilter ? 2 : 1;
|
|
14
26
|
return html `
|
|
15
27
|
<apex-grid-row
|
|
16
28
|
part="row"
|
|
@@ -18,37 +30,192 @@ export class GridDOMController {
|
|
|
18
30
|
.index=${index}
|
|
19
31
|
.activeNode=${this.state.active}
|
|
20
32
|
.data=${data}
|
|
21
|
-
.columns=${this.
|
|
33
|
+
.columns=${this.displayColumns}
|
|
34
|
+
.pinOffsets=${this.pinOffsets}
|
|
35
|
+
.editingKey=${editingKey}
|
|
36
|
+
.ariaRowOffset=${ariaRowOffset}
|
|
22
37
|
>
|
|
23
38
|
</apex-grid-row>
|
|
24
39
|
`;
|
|
25
40
|
};
|
|
41
|
+
this.#lastHeaderTop = -1;
|
|
42
|
+
this.#lastFilterTop = -1;
|
|
43
|
+
this.#lastHostWidth = -1;
|
|
44
|
+
this.#hostWidthObserver = null;
|
|
26
45
|
this.host.addController(this);
|
|
27
46
|
}
|
|
28
47
|
#initialSize;
|
|
48
|
+
#resizeObserver;
|
|
49
|
+
#observedHeaders;
|
|
50
|
+
#stickyRowObserver;
|
|
51
|
+
#observedStickyRows;
|
|
29
52
|
get container() {
|
|
30
53
|
return this.host.scrollContainer;
|
|
31
54
|
}
|
|
55
|
+
get displayColumns() {
|
|
56
|
+
return getDisplayColumns(this.host.columns);
|
|
57
|
+
}
|
|
32
58
|
async hostConnected() {
|
|
33
|
-
registerGridIcons();
|
|
34
59
|
this.setGridColumnSizes();
|
|
35
60
|
await this.host.updateComplete;
|
|
36
|
-
this
|
|
61
|
+
this.#initialSize();
|
|
62
|
+
if (typeof ResizeObserver !== 'undefined' && !this.#hostWidthObserver) {
|
|
63
|
+
this.#hostWidthObserver = new ResizeObserver(() => {
|
|
64
|
+
requestAnimationFrame(() => this.recomputeHostWidth());
|
|
65
|
+
});
|
|
66
|
+
this.#hostWidthObserver.observe(this.host);
|
|
67
|
+
}
|
|
68
|
+
this.recomputeHostWidth();
|
|
37
69
|
}
|
|
38
70
|
hostUpdate() {
|
|
39
71
|
this.setScrollOffset();
|
|
40
72
|
this.setGridColumnSizes();
|
|
41
73
|
}
|
|
74
|
+
hostUpdated() {
|
|
75
|
+
this.recomputePinOffsets();
|
|
76
|
+
this.observeHeaderCells();
|
|
77
|
+
this.recomputeStickyRowOffsets();
|
|
78
|
+
this.observeStickyRows();
|
|
79
|
+
}
|
|
80
|
+
hostDisconnected() {
|
|
81
|
+
this.#resizeObserver?.disconnect();
|
|
82
|
+
this.#resizeObserver = null;
|
|
83
|
+
this.#observedHeaders.clear();
|
|
84
|
+
this.#stickyRowObserver?.disconnect();
|
|
85
|
+
this.#stickyRowObserver = null;
|
|
86
|
+
this.#observedStickyRows.clear();
|
|
87
|
+
this.#hostWidthObserver?.disconnect();
|
|
88
|
+
this.#hostWidthObserver = null;
|
|
89
|
+
}
|
|
90
|
+
recomputeHostWidth() {
|
|
91
|
+
const host = this.host;
|
|
92
|
+
const width = host.clientWidth;
|
|
93
|
+
if (width === this.#lastHostWidth)
|
|
94
|
+
return;
|
|
95
|
+
host.style.setProperty('--apex-host-width', `${width}px`);
|
|
96
|
+
this.#lastHostWidth = width;
|
|
97
|
+
}
|
|
42
98
|
setScrollOffset() {
|
|
43
|
-
|
|
44
|
-
this.host.style.setProperty('--scrollbar-offset', `${size}px`);
|
|
99
|
+
this.host.style.setProperty('--scrollbar-offset', '0px');
|
|
45
100
|
}
|
|
46
101
|
setGridColumnSizes() {
|
|
47
|
-
this.columnSizes = applyColumnWidths(this.
|
|
102
|
+
this.columnSizes = applyColumnWidths(this.displayColumns, {
|
|
103
|
+
showSelectionColumn: this.state.selection.showCheckboxColumn,
|
|
104
|
+
showExpansionColumn: this.state.expansion.showToggleColumn,
|
|
105
|
+
});
|
|
48
106
|
}
|
|
49
107
|
getActiveRowStyles(index) {
|
|
50
108
|
const { row } = this.state.active;
|
|
51
109
|
return row === index ? { 'z-index': '3' } : {};
|
|
52
110
|
}
|
|
111
|
+
recomputePinOffsets() {
|
|
112
|
+
const headerRow = this.host.headerRow;
|
|
113
|
+
if (!headerRow?.headers)
|
|
114
|
+
return;
|
|
115
|
+
const next = new Map();
|
|
116
|
+
const headersByKey = new Map();
|
|
117
|
+
for (const header of headerRow.headers) {
|
|
118
|
+
headersByKey.set(header.column.key, header.getBoundingClientRect());
|
|
119
|
+
}
|
|
120
|
+
let leftAccum = 0;
|
|
121
|
+
for (const column of this.displayColumns) {
|
|
122
|
+
if (column.hidden)
|
|
123
|
+
continue;
|
|
124
|
+
if (column.pinned !== 'start')
|
|
125
|
+
break;
|
|
126
|
+
next.set(column.key, leftAccum);
|
|
127
|
+
const rect = headersByKey.get(column.key);
|
|
128
|
+
leftAccum += rect?.width ?? 0;
|
|
129
|
+
}
|
|
130
|
+
let rightAccum = 0;
|
|
131
|
+
for (let i = this.displayColumns.length - 1; i >= 0; i--) {
|
|
132
|
+
const column = this.displayColumns[i];
|
|
133
|
+
if (column.hidden)
|
|
134
|
+
continue;
|
|
135
|
+
if (column.pinned !== 'end')
|
|
136
|
+
break;
|
|
137
|
+
next.set(column.key, rightAccum);
|
|
138
|
+
const rect = headersByKey.get(column.key);
|
|
139
|
+
rightAccum += rect?.width ?? 0;
|
|
140
|
+
}
|
|
141
|
+
if (!offsetsEqual(this.pinOffsets, next)) {
|
|
142
|
+
this.pinOffsets = next;
|
|
143
|
+
this.host.requestUpdate();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
observeHeaderCells() {
|
|
147
|
+
const headerRow = this.host.headerRow;
|
|
148
|
+
if (!headerRow?.headers)
|
|
149
|
+
return;
|
|
150
|
+
if (!this.#resizeObserver) {
|
|
151
|
+
this.#resizeObserver = new ResizeObserver(() => {
|
|
152
|
+
requestAnimationFrame(() => this.recomputePinOffsets());
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const next = new Set(headerRow.headers);
|
|
156
|
+
for (const element of this.#observedHeaders) {
|
|
157
|
+
if (!next.has(element))
|
|
158
|
+
this.#resizeObserver.unobserve(element);
|
|
159
|
+
}
|
|
160
|
+
for (const element of next) {
|
|
161
|
+
if (!this.#observedHeaders.has(element))
|
|
162
|
+
this.#resizeObserver.observe(element);
|
|
163
|
+
}
|
|
164
|
+
this.#observedHeaders = next;
|
|
165
|
+
}
|
|
166
|
+
#lastHeaderTop;
|
|
167
|
+
#lastFilterTop;
|
|
168
|
+
#lastHostWidth;
|
|
169
|
+
#hostWidthObserver;
|
|
170
|
+
recomputeStickyRowOffsets() {
|
|
171
|
+
const root = this.host.shadowRoot;
|
|
172
|
+
if (!root)
|
|
173
|
+
return;
|
|
174
|
+
const toolbar = root.querySelector('apex-grid-toolbar');
|
|
175
|
+
const header = root.querySelector('apex-grid-header-row');
|
|
176
|
+
const toolbarH = toolbar?.offsetHeight ?? 0;
|
|
177
|
+
const headerH = header?.offsetHeight ?? 0;
|
|
178
|
+
const headerTop = toolbarH;
|
|
179
|
+
const filterTop = toolbarH + headerH;
|
|
180
|
+
if (headerTop !== this.#lastHeaderTop) {
|
|
181
|
+
this.host.style.setProperty('--apex-row-top-header', `${headerTop}px`);
|
|
182
|
+
this.#lastHeaderTop = headerTop;
|
|
183
|
+
}
|
|
184
|
+
if (filterTop !== this.#lastFilterTop) {
|
|
185
|
+
this.host.style.setProperty('--apex-row-top-filter', `${filterTop}px`);
|
|
186
|
+
this.#lastFilterTop = filterTop;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
observeStickyRows() {
|
|
190
|
+
const root = this.host.shadowRoot;
|
|
191
|
+
if (!root)
|
|
192
|
+
return;
|
|
193
|
+
const toolbar = root.querySelector('apex-grid-toolbar');
|
|
194
|
+
const header = root.querySelector('apex-grid-header-row');
|
|
195
|
+
if (!this.#stickyRowObserver) {
|
|
196
|
+
this.#stickyRowObserver = new ResizeObserver(() => {
|
|
197
|
+
requestAnimationFrame(() => this.recomputeStickyRowOffsets());
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const next = new Set([toolbar, header].filter((el) => !!el));
|
|
201
|
+
for (const element of this.#observedStickyRows) {
|
|
202
|
+
if (!next.has(element))
|
|
203
|
+
this.#stickyRowObserver.unobserve(element);
|
|
204
|
+
}
|
|
205
|
+
for (const element of next) {
|
|
206
|
+
if (!this.#observedStickyRows.has(element))
|
|
207
|
+
this.#stickyRowObserver.observe(element);
|
|
208
|
+
}
|
|
209
|
+
this.#observedStickyRows = next;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function offsetsEqual(a, b) {
|
|
213
|
+
if (a.size !== b.size)
|
|
214
|
+
return false;
|
|
215
|
+
for (const [key, value] of a) {
|
|
216
|
+
if (b.get(key) !== value)
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
53
220
|
}
|
|
54
221
|
//# sourceMappingURL=dom.js.map
|
package/controllers/dom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/controllers/dom.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAA2B,MAAM,KAAK,CAAC;AACpD,OAAO,EAAkB,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,OAAO,iBAAiB;IAC5B,YACY,IAAiB,EACjB,KAAyB;QADzB,SAAI,GAAJ,IAAI,CAAa;QACjB,UAAK,GAAL,KAAK,CAAoB;QAKrC,iBAAY,GAAG,GAAG,EAAE;YAClB,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QAC3C,CAAC,CAAC;QAOK,gBAAW,GAAc,EAAE,CAAC;QAE5B,gBAAW,GAA0B,CAAC,IAAO,EAAE,KAAa,EAAE,EAAE;YACrE,OAAO,IAAI,CAAA;;;gBAGC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;iBACnE,KAAK;sBACA,IAAI,CAAC,KAAK,CAAC,MAAM;gBACvB,IAAI;mBACD,IAAI,CAAC,IAAI,CAAC,OAAO;;;KAG/B,CAAC;QACJ,CAAC,CAAC;QA1BA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,YAAY,CAEV;IAEF,IAAW,SAAS;QAElB,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;IACnC,CAAC;IAkBM,KAAK,CAAC,aAAa;QACxB,iBAAiB,EAAE,CAAC;QACpB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAG1B,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1F,CAAC;IAEM,UAAU;QACf,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAEM,eAAe;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,oBAAoB,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;IACjE,CAAC;IAES,kBAAkB;QAC1B,IAAI,CAAC,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC;IAEM,kBAAkB,CAAC,KAAa;QACrC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAClC,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;CACF","sourcesContent":["import type { RenderItemFunction } from '@lit-labs/virtualizer/virtualize.js';\nimport { html, type ReactiveController } from 'lit';\nimport { type StyleInfo, styleMap } from 'lit/directives/style-map.js';\nimport { registerGridIcons } from '../internal/icon-registry.js';\nimport type { GridHost } from '../internal/types.js';\nimport { applyColumnWidths } from '../internal/utils.js';\nimport type { StateController } from './state.js';\n\nexport class GridDOMController<T extends object> implements ReactiveController {\n constructor(\n protected host: GridHost<T>,\n protected state: StateController<T>\n ) {\n this.host.addController(this);\n }\n\n #initialSize = () => {\n setTimeout(() => this.setScrollOffset());\n };\n\n public get container() {\n // @ts-expect-error: protected member access\n return this.host.scrollContainer;\n }\n\n public columnSizes: StyleInfo = {};\n\n public rowRenderer: RenderItemFunction<T> = (data: T, index: number) => {\n return html`\n <apex-grid-row\n part=\"row\"\n style=${styleMap({ ...this.columnSizes, ...this.getActiveRowStyles(index) })}\n .index=${index}\n .activeNode=${this.state.active}\n .data=${data}\n .columns=${this.host.columns}\n >\n </apex-grid-row>\n `;\n };\n\n public async hostConnected() {\n registerGridIcons();\n this.setGridColumnSizes();\n // Wait for the initial paint of the virtualizer and recalculate the scrollbar offset\n // for the next one\n await this.host.updateComplete;\n this.container.addEventListener('visibilityChanged', this.#initialSize, { once: true });\n }\n\n public hostUpdate(): void {\n this.setScrollOffset();\n this.setGridColumnSizes();\n }\n\n public setScrollOffset() {\n const size = this.container ? this.container.offsetWidth - this.container.clientWidth : 0;\n this.host.style.setProperty('--scrollbar-offset', `${size}px`);\n }\n\n protected setGridColumnSizes() {\n this.columnSizes = applyColumnWidths(this.host.columns);\n }\n\n public getActiveRowStyles(index: number): StyleInfo {\n const { row } = this.state.active;\n return row === index ? { 'z-index': '3' } : {};\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/controllers/dom.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RenderItemFunction } from '@lit-labs/virtualizer/virtualize.js';\nimport { html, type ReactiveController } from 'lit';\nimport { type StyleInfo, styleMap } from 'lit/directives/style-map.js';\nimport type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { applyColumnWidths, getDisplayColumns } from '../internal/utils.js';\nimport type { StateController } from './state.js';\n\nexport class GridDOMController<T extends object> implements ReactiveController {\n constructor(\n protected host: GridHost<T>,\n protected state: StateController<T>\n ) {\n this.host.addController(this);\n }\n\n #initialSize = () => {\n setTimeout(() => {\n this.setScrollOffset();\n this.recomputePinOffsets();\n this.recomputeStickyRowOffsets();\n });\n };\n\n #resizeObserver: ResizeObserver | null = null;\n #observedHeaders = new Set<Element>();\n #stickyRowObserver: ResizeObserver | null = null;\n #observedStickyRows = new Set<Element>();\n\n public get container() {\n // @ts-expect-error: protected member access\n return this.host.scrollContainer;\n }\n\n /**\n * Visual render order: `'start'`-pinned columns first, then unpinned, then\n * `'end'`-pinned. The user-supplied `columns` array is never mutated.\n */\n public get displayColumns(): Array<ColumnConfiguration<T>> {\n return getDisplayColumns(this.host.columns);\n }\n\n public columnSizes: StyleInfo = {};\n\n /**\n * The resolved inline-start (for `'start'` pin) or inline-end (for `'end'` pin)\n * pixel offset per pinned column key. Populated after layout by\n * {@link recomputePinOffsets}.\n */\n public pinOffsets = new Map<Keys<T>, number>();\n\n public rowRenderer: RenderItemFunction<T> = (data: T, index: number) => {\n const editingCell = this.state.editing.activeCell;\n const editingKey = editingCell?.rowIndex === index ? editingCell.columnKey : null;\n // aria-rowindex offset: header row is always row 1; filter row (when\n // any column has a filter configured) sits at row 2; body rows start\n // immediately after.\n const hasFilter = this.host.columns.some((column) => column.filter);\n const ariaRowOffset = hasFilter ? 2 : 1;\n return html`\n <apex-grid-row\n part=\"row\"\n style=${styleMap({ ...this.columnSizes, ...this.getActiveRowStyles(index) })}\n .index=${index}\n .activeNode=${this.state.active}\n .data=${data}\n .columns=${this.displayColumns}\n .pinOffsets=${this.pinOffsets}\n .editingKey=${editingKey}\n .ariaRowOffset=${ariaRowOffset}\n >\n </apex-grid-row>\n `;\n };\n\n public async hostConnected() {\n this.setGridColumnSizes();\n // Wait for the initial paint of the virtualizer and recalculate the scrollbar offset\n // for the next one\n await this.host.updateComplete;\n this.#initialSize();\n if (typeof ResizeObserver !== 'undefined' && !this.#hostWidthObserver) {\n this.#hostWidthObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeHostWidth());\n });\n this.#hostWidthObserver.observe(this.host as HTMLElement);\n }\n this.recomputeHostWidth();\n }\n\n public hostUpdate(): void {\n this.setScrollOffset();\n this.setGridColumnSizes();\n }\n\n public hostUpdated(): void {\n this.recomputePinOffsets();\n this.observeHeaderCells();\n this.recomputeStickyRowOffsets();\n this.observeStickyRows();\n }\n\n public hostDisconnected(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n this.#observedHeaders.clear();\n this.#stickyRowObserver?.disconnect();\n this.#stickyRowObserver = null;\n this.#observedStickyRows.clear();\n this.#hostWidthObserver?.disconnect();\n this.#hostWidthObserver = null;\n }\n\n /**\n * Writes the grid host's `clientWidth` into `--apex-host-width`. Used by the\n * toolbar and paginator to clamp their width to the visible viewport so\n * horizontal scrolling doesn't drag them off-screen.\n */\n public recomputeHostWidth(): void {\n const host = this.host as HTMLElement;\n const width = host.clientWidth;\n if (width === this.#lastHostWidth) return;\n host.style.setProperty('--apex-host-width', `${width}px`);\n this.#lastHostWidth = width;\n }\n\n public setScrollOffset() {\n // The grid host now owns vertical scrolling, so the historic per-row\n // padding-inline-end compensation is no longer needed. Keep the CSS var\n // set to `0` for forward compatibility with consumer themes that read it.\n this.host.style.setProperty('--scrollbar-offset', '0px');\n }\n\n protected setGridColumnSizes() {\n this.columnSizes = applyColumnWidths(this.displayColumns, {\n showSelectionColumn: this.state.selection.showCheckboxColumn,\n showExpansionColumn: this.state.expansion.showToggleColumn,\n });\n }\n\n public getActiveRowStyles(index: number): StyleInfo {\n const { row } = this.state.active;\n return row === index ? { 'z-index': '3' } : {};\n }\n\n /**\n * Measures the rendered widths of pinned header cells and writes cumulative\n * inline-start / inline-end pixel offsets into {@link pinOffsets}. Called after\n * each grid update and whenever a header cell is resized.\n */\n public recomputePinOffsets(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as\n | {\n headers?: Array<{\n column: ColumnConfiguration<T>;\n getBoundingClientRect: () => DOMRect;\n }>;\n }\n | undefined;\n if (!headerRow?.headers) return;\n\n const next = new Map<Keys<T>, number>();\n const headersByKey = new Map<Keys<T>, DOMRect>();\n for (const header of headerRow.headers) {\n headersByKey.set(header.column.key as Keys<T>, header.getBoundingClientRect());\n }\n\n let leftAccum = 0;\n for (const column of this.displayColumns) {\n if (column.hidden) continue;\n if (column.pinned !== 'start') break;\n next.set(column.key as Keys<T>, leftAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n leftAccum += rect?.width ?? 0;\n }\n\n let rightAccum = 0;\n for (let i = this.displayColumns.length - 1; i >= 0; i--) {\n const column = this.displayColumns[i];\n if (column.hidden) continue;\n if (column.pinned !== 'end') break;\n next.set(column.key as Keys<T>, rightAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n rightAccum += rect?.width ?? 0;\n }\n\n if (!offsetsEqual(this.pinOffsets, next)) {\n this.pinOffsets = next;\n this.host.requestUpdate();\n }\n }\n\n protected observeHeaderCells(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as { headers?: Array<Element> } | undefined;\n if (!headerRow?.headers) return;\n\n if (!this.#resizeObserver) {\n this.#resizeObserver = new ResizeObserver(() => {\n // Defer to a new frame so any layout writes can't synchronously feed back\n // into this observer (which makes the browser raise the benign\n // \"ResizeObserver loop completed\" warning).\n requestAnimationFrame(() => this.recomputePinOffsets());\n });\n }\n\n const next = new Set<Element>(headerRow.headers);\n for (const element of this.#observedHeaders) {\n if (!next.has(element)) this.#resizeObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedHeaders.has(element)) this.#resizeObserver.observe(element);\n }\n this.#observedHeaders = next;\n }\n\n #lastHeaderTop = -1;\n #lastFilterTop = -1;\n #lastHostWidth = -1;\n #hostWidthObserver: ResizeObserver | null = null;\n\n /**\n * Writes the cumulative height of the sticky top rows into CSS custom\n * properties used by the header/filter rows for their `inset-block-start`\n * offsets. The toolbar is always at `top: 0`; the header sits below it\n * (`--apex-row-top-header`) and the filter sits below the header\n * (`--apex-row-top-filter`). Writes are skipped when the values haven't\n * changed so the ResizeObserver feedback loop terminates.\n */\n public recomputeStickyRowOffsets(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n\n const toolbarH = toolbar?.offsetHeight ?? 0;\n const headerH = header?.offsetHeight ?? 0;\n const headerTop = toolbarH;\n const filterTop = toolbarH + headerH;\n\n if (headerTop !== this.#lastHeaderTop) {\n this.host.style.setProperty('--apex-row-top-header', `${headerTop}px`);\n this.#lastHeaderTop = headerTop;\n }\n if (filterTop !== this.#lastFilterTop) {\n this.host.style.setProperty('--apex-row-top-filter', `${filterTop}px`);\n this.#lastFilterTop = filterTop;\n }\n }\n\n protected observeStickyRows(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n\n if (!this.#stickyRowObserver) {\n this.#stickyRowObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeStickyRowOffsets());\n });\n }\n\n const next = new Set<Element>([toolbar, header].filter((el): el is HTMLElement => !!el));\n for (const element of this.#observedStickyRows) {\n if (!next.has(element)) this.#stickyRowObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedStickyRows.has(element)) this.#stickyRowObserver.observe(element);\n }\n this.#observedStickyRows = next;\n }\n}\n\nfunction offsetsEqual<K>(a: Map<K, number>, b: Map<K, number>): boolean {\n if (a.size !== b.size) return false;\n for (const [key, value] of a) {\n if (b.get(key) !== value) return false;\n }\n return true;\n}\n"]}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { ReactiveController } from 'lit';
|
|
2
|
+
import type { ColumnConfiguration, EditMode, EditTrigger, GridHost, Keys } from '../internal/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The default editing configuration used when the grid has none set.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_EDITING_CONFIG: Readonly<{
|
|
7
|
+
enabled: false;
|
|
8
|
+
mode: EditMode;
|
|
9
|
+
trigger: EditTrigger;
|
|
10
|
+
}>;
|
|
11
|
+
interface ActiveCell<T> {
|
|
12
|
+
rowIndex: number;
|
|
13
|
+
columnKey: Keys<T>;
|
|
14
|
+
/**
|
|
15
|
+
* Live reference to the underlying record (preserved through the pipeline so
|
|
16
|
+
* the source array can be mutated on commit).
|
|
17
|
+
*/
|
|
18
|
+
data: T;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Reactive controller backing inline cell + row editing.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* Holds the currently active cell / row, pending values for row-mode edits,
|
|
25
|
+
* and is responsible for emitting the cancellable `cellValueChanging` event
|
|
26
|
+
* and follow-up `cellValueChanged` event. The actual data mutation writes
|
|
27
|
+
* through to {@link ApexGrid.data} so changes survive pipeline runs and
|
|
28
|
+
* propagate to consumers that own the source array.
|
|
29
|
+
*/
|
|
30
|
+
export declare class EditingController<T extends object> implements ReactiveController {
|
|
31
|
+
protected host: GridHost<T>;
|
|
32
|
+
/** The cell currently in edit mode, or `null`. */
|
|
33
|
+
activeCell: ActiveCell<T> | null;
|
|
34
|
+
/** The row currently in edit mode (row mode only), or `null`. */
|
|
35
|
+
activeRow: {
|
|
36
|
+
rowIndex: number;
|
|
37
|
+
data: T;
|
|
38
|
+
} | null;
|
|
39
|
+
/**
|
|
40
|
+
* Pending values keyed by column for the currently editing row. Populated in
|
|
41
|
+
* row mode as the user edits individual cells; flushed on
|
|
42
|
+
* {@link commitRow}.
|
|
43
|
+
*/
|
|
44
|
+
pending: Map<Keys<T>, unknown>;
|
|
45
|
+
constructor(host: GridHost<T>);
|
|
46
|
+
hostConnected(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Whether editing is enabled at the grid level.
|
|
49
|
+
*/
|
|
50
|
+
get enabled(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The resolved edit mode (`'cell'` if unset).
|
|
53
|
+
*/
|
|
54
|
+
get mode(): EditMode;
|
|
55
|
+
/**
|
|
56
|
+
* The resolved edit trigger (`'doubleClick'` if unset).
|
|
57
|
+
*/
|
|
58
|
+
get trigger(): EditTrigger;
|
|
59
|
+
/**
|
|
60
|
+
* Whether the given column can be edited.
|
|
61
|
+
*/
|
|
62
|
+
isEditable(column: ColumnConfiguration<T>): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Whether the cell `(rowIndex, columnKey)` is currently in edit mode.
|
|
65
|
+
*/
|
|
66
|
+
isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Whether the given row is currently in edit mode (row mode).
|
|
69
|
+
*/
|
|
70
|
+
isRowEditing(rowIndex: number): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell
|
|
73
|
+
* already in edit mode (in cell mode); in row mode it switches the active
|
|
74
|
+
* cell within the same row and rejects cross-row moves.
|
|
75
|
+
*
|
|
76
|
+
* @returns `true` if edit started, `false` if rejected (column not editable
|
|
77
|
+
* or row-mode constraint violated).
|
|
78
|
+
*/
|
|
79
|
+
editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Begins editing the given row in row mode. Emits `rowEditStarted` on
|
|
82
|
+
* success. No-op in cell mode.
|
|
83
|
+
*/
|
|
84
|
+
editRow(rowIndex: number): Promise<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Commits a candidate value for the currently editing cell. In cell mode the
|
|
87
|
+
* value is written through to {@link ApexGrid.data}; in row mode it is staged
|
|
88
|
+
* in {@link pending} until {@link commitRow} is called.
|
|
89
|
+
*
|
|
90
|
+
* @param value - The candidate value.
|
|
91
|
+
* @returns `true` if accepted (or staged), `false` if rejected by
|
|
92
|
+
* `cellValueChanging.preventDefault()`.
|
|
93
|
+
*/
|
|
94
|
+
commitCell(value?: unknown): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Writes `value` directly to the cell at `(rowIndex, columnKey)` without
|
|
97
|
+
* entering edit mode. Used by interactive display widgets (e.g. the boolean
|
|
98
|
+
* checkbox) that handle their own input. Goes through the same
|
|
99
|
+
* `cellValueChanging` / `cellValueChanged` event path as a normal commit.
|
|
100
|
+
*
|
|
101
|
+
* @returns `true` if the value was applied, `false` if rejected by
|
|
102
|
+
* `cellValueChanging.preventDefault()` or the column is not editable.
|
|
103
|
+
*/
|
|
104
|
+
commitImmediate(rowIndex: number, columnKey: Keys<T>, value: unknown): Promise<boolean>;
|
|
105
|
+
/**
|
|
106
|
+
* Discards the current cell edit without writing. In row mode the row edit
|
|
107
|
+
* stays open.
|
|
108
|
+
*/
|
|
109
|
+
cancelCell(): void;
|
|
110
|
+
/**
|
|
111
|
+
* Commits all pending edits for the currently editing row. Emits
|
|
112
|
+
* `cellValueChanging` for every changed cell and `rowEditEnded` at the end.
|
|
113
|
+
*
|
|
114
|
+
* @returns `true` if the row was applied, `false` if any cell change was
|
|
115
|
+
* cancelled (the row remains in edit mode in that case).
|
|
116
|
+
*/
|
|
117
|
+
commitRow(): Promise<boolean>;
|
|
118
|
+
/**
|
|
119
|
+
* Discards every pending edit for the active row and exits row edit mode.
|
|
120
|
+
* Emits `rowEditEnded` with `committed: false`.
|
|
121
|
+
*/
|
|
122
|
+
cancelRow(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Returns the current pending or committed value for `(rowIndex, columnKey)`.
|
|
125
|
+
* Cells in row mode read this so unstaged-but-pending values are reflected
|
|
126
|
+
* during the edit.
|
|
127
|
+
*/
|
|
128
|
+
getValue(rowIndex: number, columnKey: Keys<T>): unknown;
|
|
129
|
+
}
|
|
130
|
+
export {};
|