apex-grid 1.1.0 → 2.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.
Files changed (206) hide show
  1. package/LICENSE +76 -5
  2. package/README.md +520 -10
  3. package/components/cell.d.ts +39 -0
  4. package/components/cell.js +334 -5
  5. package/components/cell.js.map +1 -1
  6. package/components/filter-row.d.ts +7 -5
  7. package/components/filter-row.js +151 -68
  8. package/components/filter-row.js.map +1 -1
  9. package/components/grid.d.ts +948 -1
  10. package/components/grid.js +403 -13
  11. package/components/grid.js.map +1 -1
  12. package/components/header-row.d.ts +21 -1
  13. package/components/header-row.js +140 -7
  14. package/components/header-row.js.map +1 -1
  15. package/components/header.d.ts +7 -0
  16. package/components/header.js +151 -25
  17. package/components/header.js.map +1 -1
  18. package/components/paginator.d.ts +56 -0
  19. package/components/paginator.js +148 -0
  20. package/components/paginator.js.map +1 -0
  21. package/components/row.d.ts +21 -2
  22. package/components/row.js +185 -10
  23. package/components/row.js.map +1 -1
  24. package/components/toolbar.d.ts +60 -0
  25. package/components/toolbar.js +275 -0
  26. package/components/toolbar.js.map +1 -0
  27. package/components/virtualizer.js +1 -1
  28. package/components/virtualizer.js.map +1 -1
  29. package/controllers/data-operation.d.ts +14 -0
  30. package/controllers/data-operation.js +19 -2
  31. package/controllers/data-operation.js.map +1 -1
  32. package/controllers/dom.d.ts +37 -1
  33. package/controllers/dom.js +176 -9
  34. package/controllers/dom.js.map +1 -1
  35. package/controllers/editing.d.ts +130 -0
  36. package/controllers/editing.js +197 -0
  37. package/controllers/editing.js.map +1 -0
  38. package/controllers/expansion.d.ts +68 -0
  39. package/controllers/expansion.js +126 -0
  40. package/controllers/expansion.js.map +1 -0
  41. package/controllers/navigation.d.ts +17 -6
  42. package/controllers/navigation.js +24 -8
  43. package/controllers/navigation.js.map +1 -1
  44. package/controllers/pagination.d.ts +102 -0
  45. package/controllers/pagination.js +106 -0
  46. package/controllers/pagination.js.map +1 -0
  47. package/controllers/reorder.d.ts +78 -0
  48. package/controllers/reorder.js +124 -0
  49. package/controllers/reorder.js.map +1 -0
  50. package/controllers/selection.d.ts +109 -0
  51. package/controllers/selection.js +168 -0
  52. package/controllers/selection.js.map +1 -0
  53. package/controllers/sort.js +28 -0
  54. package/controllers/sort.js.map +1 -1
  55. package/controllers/state.d.ts +32 -0
  56. package/controllers/state.js +37 -0
  57. package/controllers/state.js.map +1 -1
  58. package/controllers/tree.d.ts +87 -0
  59. package/controllers/tree.js +0 -0
  60. package/controllers/tree.js.map +1 -0
  61. package/custom-elements.json +6142 -992
  62. package/docs/assets/hierarchy.js +1 -1
  63. package/docs/assets/highlight.css +70 -14
  64. package/docs/assets/navigation.js +1 -1
  65. package/docs/assets/search.js +1 -1
  66. package/docs/classes/ApexGrid.html +316 -19
  67. package/docs/functions/setup.html +22 -0
  68. package/docs/hierarchy.html +1 -1
  69. package/docs/index.html +503 -9
  70. package/docs/interfaces/ApexCellValueChangedEvent.html +11 -0
  71. package/docs/interfaces/ApexCellValueChangingEvent.html +13 -0
  72. package/docs/interfaces/ApexColumnMovedEvent.html +8 -0
  73. package/docs/interfaces/ApexColumnMovingEvent.html +11 -0
  74. package/docs/interfaces/ApexColumnPinnedEvent.html +6 -0
  75. package/docs/interfaces/ApexColumnPinningEvent.html +8 -0
  76. package/docs/interfaces/ApexDetailContext.html +8 -0
  77. package/docs/interfaces/ApexFilteredEvent.html +1 -1
  78. package/docs/interfaces/ApexFilteringEvent.html +3 -3
  79. package/docs/interfaces/ApexGridEventMap.html +58 -7
  80. package/docs/interfaces/ApexHeaderContext.html +1 -1
  81. package/docs/interfaces/ApexPageChangedEvent.html +10 -0
  82. package/docs/interfaces/ApexPageChangingEvent.html +10 -0
  83. package/docs/interfaces/ApexQuickFilterChangedEvent.html +4 -0
  84. package/docs/interfaces/ApexQuickFilterChangingEvent.html +6 -0
  85. package/docs/interfaces/ApexRowEditEndedEvent.html +6 -0
  86. package/docs/interfaces/ApexRowEditStartedEvent.html +4 -0
  87. package/docs/interfaces/ApexRowExpandedEvent.html +8 -0
  88. package/docs/interfaces/ApexRowExpandingEvent.html +11 -0
  89. package/docs/interfaces/ApexRowSelectedEvent.html +8 -0
  90. package/docs/interfaces/ApexRowSelectingEvent.html +11 -0
  91. package/docs/interfaces/ApexTreeRowExpandedEvent.html +8 -0
  92. package/docs/interfaces/ApexTreeRowExpandingEvent.html +10 -0
  93. package/docs/interfaces/BaseApexCellContext.html +9 -3
  94. package/docs/interfaces/BaseApexEditorContext.html +19 -0
  95. package/docs/interfaces/BaseColumnConfiguration.html +65 -10
  96. package/docs/interfaces/BaseColumnSortConfiguration.html +1 -1
  97. package/docs/interfaces/BaseFilterExpression.html +1 -1
  98. package/docs/interfaces/BaseSortExpression.html +1 -1
  99. package/docs/interfaces/CSVExportOptions.html +22 -0
  100. package/docs/interfaces/ColumnFilterConfiguration.html +1 -1
  101. package/docs/interfaces/DataPipelineConfiguration.html +13 -4
  102. package/docs/interfaces/ExportOptions.html +15 -0
  103. package/docs/interfaces/GridEditingConfiguration.html +10 -0
  104. package/docs/interfaces/GridExpansionConfiguration.html +15 -0
  105. package/docs/interfaces/GridSelectionConfiguration.html +11 -0
  106. package/docs/interfaces/GridSortConfiguration.html +1 -1
  107. package/docs/interfaces/GridTreeConfiguration.html +33 -0
  108. package/docs/interfaces/PaginationConfiguration.html +18 -0
  109. package/docs/interfaces/PaginationState.html +10 -0
  110. package/docs/interfaces/XLSXExportOptions.html +17 -0
  111. package/docs/media/package.json +83 -0
  112. package/docs/media/publish.yml +111 -0
  113. package/docs/modules.html +1 -1
  114. package/docs/types/ApexCellContext.html +1 -1
  115. package/docs/types/ApexEditorContext.html +2 -0
  116. package/docs/types/BasePropertyType.html +1 -1
  117. package/docs/types/BaseSortComparer.html +1 -1
  118. package/docs/types/ColumnConfiguration.html +1 -1
  119. package/docs/types/ColumnDropPosition.html +2 -0
  120. package/docs/types/ColumnSortConfiguration.html +1 -1
  121. package/docs/types/DataPipelineHook.html +1 -1
  122. package/docs/types/DataPipelineParams.html +3 -3
  123. package/docs/types/DataType.html +30 -2
  124. package/docs/types/EditMode.html +6 -0
  125. package/docs/types/EditTrigger.html +4 -0
  126. package/docs/types/ExportCellValue.html +5 -0
  127. package/docs/types/ExportSource.html +8 -0
  128. package/docs/types/FilterCriteria.html +1 -1
  129. package/docs/types/FilterExpression.html +1 -1
  130. package/docs/types/Keys.html +1 -1
  131. package/docs/types/PaginationMode.html +6 -0
  132. package/docs/types/PinPosition.html +5 -0
  133. package/docs/types/PropertyType.html +1 -1
  134. package/docs/types/SelectionMode.html +7 -0
  135. package/docs/types/SortComparer.html +1 -1
  136. package/docs/types/SortExpression.html +1 -1
  137. package/docs/types/SortState.html +1 -1
  138. package/docs/types/SortingDirection.html +1 -1
  139. package/index.d.ts +5 -2
  140. package/index.js +1 -0
  141. package/index.js.map +1 -1
  142. package/internal/column-types.d.ts +94 -0
  143. package/internal/column-types.js +268 -0
  144. package/internal/column-types.js.map +1 -0
  145. package/internal/export.d.ts +106 -0
  146. package/internal/export.js +122 -0
  147. package/internal/export.js.map +1 -0
  148. package/internal/flip.d.ts +80 -0
  149. package/internal/flip.js +52 -0
  150. package/internal/flip.js.map +1 -0
  151. package/internal/icons.d.ts +24 -0
  152. package/internal/icons.js +134 -0
  153. package/internal/icons.js.map +1 -0
  154. package/internal/tags.d.ts +2 -0
  155. package/internal/tags.js +2 -0
  156. package/internal/tags.js.map +1 -1
  157. package/internal/theming.js +1 -1
  158. package/internal/theming.js.map +1 -1
  159. package/internal/types.d.ts +424 -3
  160. package/internal/types.js.map +1 -1
  161. package/internal/utils.d.ts +24 -1
  162. package/internal/utils.js +48 -7
  163. package/internal/utils.js.map +1 -1
  164. package/internal/xlsx.d.ts +22 -0
  165. package/internal/xlsx.js +228 -0
  166. package/internal/xlsx.js.map +1 -0
  167. package/operations/pagination.d.ts +19 -0
  168. package/operations/pagination.js +12 -0
  169. package/operations/pagination.js.map +1 -0
  170. package/operations/quick-filter.d.ts +21 -0
  171. package/operations/quick-filter.js +26 -0
  172. package/operations/quick-filter.js.map +1 -0
  173. package/package.json +6 -5
  174. package/setup.d.ts +58 -0
  175. package/setup.js +29 -0
  176. package/setup.js.map +1 -0
  177. package/styles/body-cell/body-cell.css.js +1 -1
  178. package/styles/body-cell/body-cell.css.js.map +1 -1
  179. package/styles/body-row/body-row.css.js +1 -1
  180. package/styles/body-row/body-row.css.js.map +1 -1
  181. package/styles/filter-row/filter-row.css.js +1 -1
  182. package/styles/filter-row/filter-row.css.js.map +1 -1
  183. package/styles/grid/_grid.base.css.js +1 -1
  184. package/styles/grid/_grid.base.css.js.map +1 -1
  185. package/styles/grid/themes/light/grid.bootstrap.css.js +1 -1
  186. package/styles/grid/themes/light/grid.bootstrap.css.js.map +1 -1
  187. package/styles/grid/themes/light/grid.fluent.css.js +1 -1
  188. package/styles/grid/themes/light/grid.fluent.css.js.map +1 -1
  189. package/styles/grid/themes/light/grid.indigo.css.js +1 -1
  190. package/styles/grid/themes/light/grid.indigo.css.js.map +1 -1
  191. package/styles/grid/themes/light/grid.material.css.js +1 -1
  192. package/styles/grid/themes/light/grid.material.css.js.map +1 -1
  193. package/styles/header-cell/header-cell.css.js +1 -1
  194. package/styles/header-cell/header-cell.css.js.map +1 -1
  195. package/styles/header-row/header-row.base.css.js +1 -1
  196. package/styles/header-row/header-row.base.css.js.map +1 -1
  197. package/styles/paginator/paginator.css.d.ts +1 -0
  198. package/styles/paginator/paginator.css.js +3 -0
  199. package/styles/paginator/paginator.css.js.map +1 -0
  200. package/styles/toolbar/toolbar.css.d.ts +1 -0
  201. package/styles/toolbar/toolbar.css.js +3 -0
  202. package/styles/toolbar/toolbar.css.js.map +1 -0
  203. package/styles.css +17 -0
  204. package/internal/icon-registry.d.ts +0 -1
  205. package/internal/icon-registry.js +0 -29
  206. package/internal/icon-registry.js.map +0 -1
@@ -5,7 +5,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { ContextProvider } from '@lit/context';
8
- import { IgcButtonComponent, IgcChipComponent, IgcDropdownComponent, IgcInputComponent, } from 'igniteui-webcomponents';
9
8
  import { html, nothing } from 'lit';
10
9
  import { eventOptions, property, query, queryAll, state } from 'lit/decorators.js';
11
10
  import { styleMap } from 'lit/directives/style-map.js';
@@ -13,12 +12,14 @@ import { DataOperationsController } from '../controllers/data-operation.js';
13
12
  import { GridDOMController } from '../controllers/dom.js';
14
13
  import { gridStateContext, StateController } from '../controllers/state.js';
15
14
  import { DEFAULT_COLUMN_CONFIG, PIPELINE } from '../internal/constants.js';
15
+ import { buildCSV, downloadBlob, getColumnLabel, resolveExportColumns, resolveExportRows, resolveExportValue, } from '../internal/export.js';
16
16
  import { EventEmitterBase } from '../internal/mixins/event-emitter.js';
17
17
  import { registerComponent } from '../internal/register.js';
18
18
  import { GRID_TAG } from '../internal/tags.js';
19
19
  import { addThemingController } from '../internal/theming.js';
20
- import { asArray, autoGenerateColumns, getFilterOperandsFor } from '../internal/utils.js';
20
+ import { asArray, autoGenerateColumns, getDisplayColumns, getFilterOperandsFor, } from '../internal/utils.js';
21
21
  import { watch } from '../internal/watch.js';
22
+ import { buildXLSX } from '../internal/xlsx.js';
22
23
  import { styles as bootstrap } from '../styles/grid/themes/light/grid.bootstrap.css.js';
23
24
  import { styles as fluent } from '../styles/grid/themes/light/grid.fluent.css.js';
24
25
  import { styles as indigo } from '../styles/grid/themes/light/grid.indigo.css.js';
@@ -26,7 +27,9 @@ import { styles as material } from '../styles/grid/themes/light/grid.material.cs
26
27
  import ApexGridCell from './cell.js';
27
28
  import ApexFilterRow from './filter-row.js';
28
29
  import ApexGridHeaderRow from './header-row.js';
30
+ import ApexGridPaginator from './paginator.js';
29
31
  import ApexGridRow from './row.js';
32
+ import ApexGridToolbar from './toolbar.js';
30
33
  import ApexVirtualizer from './virtualizer.js';
31
34
  export class ApexGrid extends EventEmitterBase {
32
35
  static get tagName() {
@@ -34,7 +37,73 @@ export class ApexGrid extends EventEmitterBase {
34
37
  }
35
38
  static { this.styles = bootstrap; }
36
39
  static register() {
37
- registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridHeaderRow, ApexFilterRow, IgcButtonComponent, IgcChipComponent, IgcInputComponent, IgcDropdownComponent);
40
+ registerComponent(ApexGrid, ApexVirtualizer, ApexGridRow, ApexGridHeaderRow, ApexFilterRow, ApexGridPaginator, ApexGridToolbar);
41
+ }
42
+ get selectedRows() {
43
+ return this.stateController.selection.selectedRows();
44
+ }
45
+ set selectedRows(rows) {
46
+ void this.stateController.selection.replaceSelection(rows);
47
+ }
48
+ selectRow(row) {
49
+ return this.stateController.selection.selectRow(row);
50
+ }
51
+ deselectRow(row) {
52
+ return this.stateController.selection.deselectRow(row);
53
+ }
54
+ toggleRowSelection(row) {
55
+ return this.stateController.selection.toggleRow(row);
56
+ }
57
+ selectAllRows() {
58
+ return this.stateController.selection.selectAll();
59
+ }
60
+ clearSelection() {
61
+ return this.stateController.selection.clear();
62
+ }
63
+ isRowSelected(row) {
64
+ return this.stateController.selection.isSelected(row);
65
+ }
66
+ get expandedRows() {
67
+ return this.stateController.expansion.expandedRows();
68
+ }
69
+ set expandedRows(rows) {
70
+ void this.stateController.expansion.replaceExpansion(rows);
71
+ }
72
+ expandRow(row) {
73
+ return this.stateController.expansion.expandRow(row);
74
+ }
75
+ collapseRow(row) {
76
+ return this.stateController.expansion.collapseRow(row);
77
+ }
78
+ toggleRowExpansion(row) {
79
+ return this.stateController.expansion.toggleRow(row);
80
+ }
81
+ expandAllRows() {
82
+ return this.stateController.expansion.expandAll();
83
+ }
84
+ collapseAllRows() {
85
+ return this.stateController.expansion.collapseAll();
86
+ }
87
+ isRowExpanded(row) {
88
+ return this.stateController.expansion.isExpanded(row);
89
+ }
90
+ toggleTreeRow(row) {
91
+ return this.stateController.tree.toggleRow(row);
92
+ }
93
+ expandTreeRow(row) {
94
+ return this.stateController.tree.expandRow(row);
95
+ }
96
+ collapseTreeRow(row) {
97
+ return this.stateController.tree.collapseRow(row);
98
+ }
99
+ expandAllTreeRows() {
100
+ return this.stateController.tree.expandAll();
101
+ }
102
+ collapseAllTreeRows() {
103
+ return this.stateController.tree.collapseAll();
104
+ }
105
+ isTreeRowExpanded(row) {
106
+ return this.stateController.tree.isExpanded(row);
38
107
  }
39
108
  set sortExpressions(expressions) {
40
109
  if (expressions.length) {
@@ -62,21 +131,79 @@ export class ApexGrid extends EventEmitterBase {
62
131
  get dataView() {
63
132
  return this.dataState;
64
133
  }
134
+ get displayColumns() {
135
+ return getDisplayColumns(this.columns);
136
+ }
65
137
  get totalItems() {
138
+ if (this.pagination?.mode === 'remote') {
139
+ return Math.max(0, this.pagination?.totalItems ?? 0);
140
+ }
66
141
  return this.dataState.length;
67
142
  }
143
+ get pageItems() {
144
+ if (!this.stateController.pagination.enabled)
145
+ return this.dataState;
146
+ if (this.pagination?.mode === 'remote')
147
+ return this.dataState;
148
+ const { page, pageSize } = this.stateController.pagination;
149
+ if (!pageSize)
150
+ return this.dataState;
151
+ const start = page * pageSize;
152
+ return this.dataState.slice(start, start + pageSize);
153
+ }
154
+ get page() {
155
+ return this.stateController.pagination.page;
156
+ }
157
+ set page(value) {
158
+ this.stateController.pagination.gotoPage(value);
159
+ }
160
+ get pageSize() {
161
+ return this.stateController.pagination.pageSize;
162
+ }
163
+ set pageSize(value) {
164
+ this.stateController.pagination.setPageSize(value);
165
+ }
166
+ get pageCount() {
167
+ return this.stateController.pagination.pageCount;
168
+ }
68
169
  watchColumns(_, newConfig = []) {
69
170
  this.columns = newConfig.map((config) => ({ ...DEFAULT_COLUMN_CONFIG, ...config }));
70
171
  }
71
172
  dataChanged() {
72
- this.dataState = structuredClone(this.data);
173
+ let next = [...this.data];
73
174
  autoGenerateColumns(this);
175
+ this.stateController?.tree?.resetForDataChange();
176
+ if (this.stateController?.tree?.enabled) {
177
+ next = this.stateController.tree.process(next);
178
+ }
179
+ this.dataState = next;
74
180
  if (this.hasUpdated) {
75
181
  this.pipeline();
76
182
  }
77
183
  }
78
184
  async pipeline() {
79
- this.dataState = await this.dataController.apply(structuredClone(this.data), this.stateController);
185
+ this.dataState = await this.dataController.apply([...this.data], this.stateController);
186
+ this.stateController.pagination.reclamp();
187
+ }
188
+ paginationChanged() {
189
+ const ctrl = this.stateController?.pagination;
190
+ if (!ctrl)
191
+ return;
192
+ const next = this.pagination ?? {};
193
+ if (typeof next.pageSize === 'number' && next.pageSize > 0) {
194
+ ctrl.pageSize = next.pageSize;
195
+ }
196
+ if (typeof next.page === 'number') {
197
+ ctrl.page = next.page;
198
+ }
199
+ if (this.hasUpdated) {
200
+ this.pipeline();
201
+ }
202
+ }
203
+ quickFilterChanged() {
204
+ if (this.hasUpdated) {
205
+ this.pipeline();
206
+ }
80
207
  }
81
208
  constructor() {
82
209
  super();
@@ -95,11 +222,33 @@ export class ApexGrid extends EventEmitterBase {
95
222
  multiple: true,
96
223
  triState: true,
97
224
  };
225
+ this.quickFilter = '';
226
+ this.showQuickFilter = false;
227
+ this.showExport = false;
228
+ this.columnReordering = false;
98
229
  addThemingController(this, {
99
230
  light: { bootstrap, material, fluent, indigo },
100
231
  dark: { bootstrap, material, fluent, indigo },
101
232
  });
102
233
  }
234
+ updated() {
235
+ this.setAttribute('role', this.stateController.tree.enabled ? 'treegrid' : 'grid');
236
+ const hasFilter = this.columns.some((column) => column.filter);
237
+ const headerRows = hasFilter ? 2 : 1;
238
+ this.setAttribute('aria-rowcount', String(headerRows + this.pageItems.length));
239
+ const visibleColumns = this.columns.filter((column) => !column.hidden).length;
240
+ const extras = (this.stateController.selection.showCheckboxColumn ? 1 : 0) +
241
+ (this.stateController.expansion.showToggleColumn ? 1 : 0);
242
+ this.setAttribute('aria-colcount', String(visibleColumns + extras));
243
+ }
244
+ firstUpdated() {
245
+ if (typeof getComputedStyle === 'function' && getComputedStyle(this).display !== 'grid') {
246
+ console.warn('[apex-grid] Host `display` has been overridden. The grid requires ' +
247
+ '`display: grid` for its internal track layout and will not render correctly. ' +
248
+ 'Remove any CSS rule that sets `display` on <apex-grid>. ' +
249
+ 'See: https://github.com/apexcharts/apexgrid#4-size-the-host');
250
+ }
251
+ }
103
252
  filter(config) {
104
253
  this.stateController.filtering.filter(asArray(config).map((each) => typeof each.condition === 'string'
105
254
  ?
@@ -119,20 +268,177 @@ export class ApexGrid extends EventEmitterBase {
119
268
  this.stateController.filtering.reset(key);
120
269
  this.requestUpdate(PIPELINE);
121
270
  }
271
+ gotoPage(page) {
272
+ return this.stateController.pagination.gotoPage(page);
273
+ }
274
+ setPageSize(size) {
275
+ return this.stateController.pagination.setPageSize(size);
276
+ }
277
+ nextPage() {
278
+ return this.stateController.pagination.nextPage();
279
+ }
280
+ previousPage() {
281
+ return this.stateController.pagination.previousPage();
282
+ }
283
+ firstPage() {
284
+ return this.stateController.pagination.firstPage();
285
+ }
286
+ lastPage() {
287
+ return this.stateController.pagination.lastPage();
288
+ }
289
+ async setQuickFilter(value) {
290
+ const next = value ?? '';
291
+ if (next === this.quickFilter)
292
+ return false;
293
+ const proceed = this.emitEvent('quickFilterChanging', {
294
+ detail: { value: this.quickFilter, nextValue: next },
295
+ cancelable: true,
296
+ });
297
+ if (!proceed)
298
+ return false;
299
+ this.quickFilter = next;
300
+ this.stateController.pagination.page = 0;
301
+ await this.updateComplete;
302
+ this.emitEvent('quickFilterChanged', { detail: { value: this.quickFilter } });
303
+ return true;
304
+ }
122
305
  getColumn(id) {
123
306
  return typeof id === 'number'
124
307
  ? this.columns.at(id)
125
308
  : this.columns.find(({ key }) => key === id);
126
309
  }
127
310
  updateColumns(columns) {
128
- for (const column of asArray(columns)) {
129
- const instance = this.columns.find((curr) => curr.key === column.key);
130
- if (instance) {
131
- Object.assign(instance, column);
132
- }
133
- }
311
+ const updates = new Map(asArray(columns).map((c) => [c.key, c]));
312
+ if (updates.size === 0)
313
+ return;
314
+ let touched = false;
315
+ const next = this.columns.map((column) => {
316
+ const patch = updates.get(column.key);
317
+ if (!patch)
318
+ return column;
319
+ touched = true;
320
+ return { ...column, ...patch };
321
+ });
322
+ if (!touched)
323
+ return;
324
+ this.columns = next;
134
325
  this.requestUpdate(PIPELINE);
135
326
  }
327
+ async pinColumn(key, position) {
328
+ const column = this.getColumn(key);
329
+ if (!column)
330
+ return false;
331
+ const previous = column.pinned ?? null;
332
+ const next = position ?? null;
333
+ if (previous === next)
334
+ return false;
335
+ const proceed = this.emitEvent('columnPinning', {
336
+ detail: { key, previous, next },
337
+ cancelable: true,
338
+ });
339
+ if (!proceed)
340
+ return false;
341
+ column.pinned = next ?? undefined;
342
+ this.columns = [...this.columns];
343
+ await this.updateComplete;
344
+ this.emitEvent('columnPinned', { detail: { key, pinned: next } });
345
+ return true;
346
+ }
347
+ unpinColumn(key) {
348
+ return this.pinColumn(key, null);
349
+ }
350
+ get editingCell() {
351
+ const active = this.stateController.editing.activeCell;
352
+ return active ? { rowIndex: active.rowIndex, columnKey: active.columnKey } : null;
353
+ }
354
+ get editingRow() {
355
+ return this.stateController.editing.activeRow?.rowIndex ?? null;
356
+ }
357
+ editCell(rowIndex, columnKey) {
358
+ return this.stateController.editing.editCell(rowIndex, columnKey);
359
+ }
360
+ editRow(rowIndex) {
361
+ return this.stateController.editing.editRow(rowIndex);
362
+ }
363
+ commitEdit() {
364
+ const editing = this.stateController.editing;
365
+ return editing.mode === 'row' ? editing.commitRow() : editing.commitCell();
366
+ }
367
+ cancelEdit() {
368
+ const editing = this.stateController.editing;
369
+ if (editing.mode === 'row') {
370
+ editing.cancelRow();
371
+ }
372
+ else {
373
+ editing.cancelCell();
374
+ }
375
+ }
376
+ exportToCSV(options = {}) {
377
+ const csv = buildCSV(this, options);
378
+ const filename = options.filename;
379
+ if (filename) {
380
+ downloadBlob(`${filename}.csv`, csv, 'text/csv;charset=utf-8;');
381
+ }
382
+ else if (filename === undefined) {
383
+ downloadBlob('data.csv', csv, 'text/csv;charset=utf-8;');
384
+ }
385
+ return csv;
386
+ }
387
+ exportToXLSX(options = {}) {
388
+ const columns = resolveExportColumns(this, options);
389
+ const rows = resolveExportRows(this, options.source);
390
+ const includeHeader = options.includeHeader ?? true;
391
+ const sheet = {
392
+ name: options.sheetName ?? 'Sheet1',
393
+ headers: includeHeader ? columns.map((column) => getColumnLabel(column)) : [],
394
+ rows: rows.map((row) => columns.map((column) => resolveExportValue(column, row, options))),
395
+ };
396
+ const bytes = buildXLSX(sheet);
397
+ const filename = options.filename;
398
+ const mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
399
+ if (filename) {
400
+ downloadBlob(`${filename}.xlsx`, bytes, mime);
401
+ }
402
+ else if (filename === undefined) {
403
+ downloadBlob('data.xlsx', bytes, mime);
404
+ }
405
+ return bytes;
406
+ }
407
+ async moveColumn(fromKey, toKey, position = 'before') {
408
+ if (fromKey === toKey)
409
+ return false;
410
+ const fromIndex = this.columns.findIndex((column) => column.key === fromKey);
411
+ const toIndex = this.columns.findIndex((column) => column.key === toKey);
412
+ if (fromIndex < 0 || toIndex < 0)
413
+ return false;
414
+ const source = this.columns[fromIndex];
415
+ const target = this.columns[toIndex];
416
+ if ((source.pinned ?? null) !== (target.pinned ?? null))
417
+ return false;
418
+ const proceed = this.emitEvent('columnMoving', {
419
+ detail: { key: fromKey, fromIndex, toKey, position },
420
+ cancelable: true,
421
+ });
422
+ if (!proceed)
423
+ return false;
424
+ const next = this.columns.slice();
425
+ const [moved] = next.splice(fromIndex, 1);
426
+ let insertIndex = next.findIndex((column) => column.key === toKey);
427
+ if (insertIndex < 0)
428
+ return false;
429
+ if (position === 'after')
430
+ insertIndex += 1;
431
+ next.splice(insertIndex, 0, moved);
432
+ if (next.every((column, index) => column === this.columns[index]))
433
+ return false;
434
+ this.columns = next;
435
+ await this.updateComplete;
436
+ const resolvedIndex = this.columns.findIndex((column) => column.key === fromKey);
437
+ this.emitEvent('columnMoved', {
438
+ detail: { key: fromKey, fromIndex, toIndex: resolvedIndex },
439
+ });
440
+ return true;
441
+ }
136
442
  bodyClickHandler(event) {
137
443
  const target = event.composedPath().find((el) => el instanceof ApexGridCell);
138
444
  if (target) {
@@ -151,14 +457,15 @@ export class ApexGrid extends EventEmitterBase {
151
457
  return html `
152
458
  <apex-grid-header-row
153
459
  style=${styleMap(this.DOM.columnSizes)}
154
- .columns=${this.columns}
460
+ .columns=${this.DOM.displayColumns}
461
+ .pinOffsets=${this.DOM.pinOffsets}
155
462
  ></apex-grid-header-row>
156
463
  `;
157
464
  }
158
465
  renderBody() {
159
466
  return html `
160
467
  <apex-virtualizer
161
- .items=${this.dataState}
468
+ .items=${this.pageItems}
162
469
  .renderItem=${this.DOM.rowRenderer}
163
470
  @click=${this.bodyClickHandler}
164
471
  @keydown=${this.bodyKeydownHandler}
@@ -170,14 +477,52 @@ export class ApexGrid extends EventEmitterBase {
170
477
  ? html `<apex-filter-row style=${styleMap(this.DOM.columnSizes)}></apex-filter-row>`
171
478
  : nothing;
172
479
  }
480
+ renderToolbar() {
481
+ if (!this.showQuickFilter && !this.showExport)
482
+ return nothing;
483
+ return html `<apex-grid-toolbar
484
+ .value=${this.quickFilter}
485
+ .showQuickFilter=${this.showQuickFilter}
486
+ .showExport=${this.showExport}
487
+ @apex-quick-filter=${(event) => {
488
+ event.stopPropagation();
489
+ this.setQuickFilter(event.detail);
490
+ }}
491
+ ></apex-grid-toolbar>`;
492
+ }
493
+ renderPaginator() {
494
+ if (!this.stateController.pagination.enabled)
495
+ return nothing;
496
+ const options = this.pagination?.pageSizeOptions && this.pagination.pageSizeOptions.length > 0
497
+ ? this.pagination.pageSizeOptions
498
+ : [10, 25, 50, 100];
499
+ return html `<apex-grid-paginator .pageSizeOptions=${options}></apex-grid-paginator>`;
500
+ }
501
+ renderLiveRegion() {
502
+ return html `<div
503
+ part="live-region"
504
+ role="status"
505
+ aria-live="polite"
506
+ aria-atomic="true"
507
+ style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;"
508
+ >
509
+ ${this.stateController.announcement}
510
+ </div>`;
511
+ }
173
512
  render() {
174
513
  return html `
175
514
  ${this.stateController.resizing.renderIndicator()}
515
+ ${this.renderToolbar()}
176
516
  ${this.renderHeaderRow()}
177
517
  ${this.renderFilterRow()}
178
518
  ${this.renderBody()}
519
+ ${this.renderPaginator()}
520
+ ${this.renderLiveRegion()}
179
521
  `;
180
522
  }
523
+ announce(message) {
524
+ this.stateController.setAnnouncement(message);
525
+ }
181
526
  }
182
527
  __decorate([
183
528
  query(ApexVirtualizer.tagName)
@@ -188,6 +533,12 @@ __decorate([
188
533
  __decorate([
189
534
  query(ApexFilterRow.tagName)
190
535
  ], ApexGrid.prototype, "filterRow", void 0);
536
+ __decorate([
537
+ query(ApexGridPaginator.tagName)
538
+ ], ApexGrid.prototype, "paginator", void 0);
539
+ __decorate([
540
+ query(ApexGridToolbar.tagName)
541
+ ], ApexGrid.prototype, "toolbar", void 0);
191
542
  __decorate([
192
543
  state()
193
544
  ], ApexGrid.prototype, "dataState", void 0);
@@ -209,12 +560,45 @@ __decorate([
209
560
  __decorate([
210
561
  property({ attribute: false })
211
562
  ], ApexGrid.prototype, "dataPipelineConfiguration", void 0);
563
+ __decorate([
564
+ property({ attribute: false })
565
+ ], ApexGrid.prototype, "pagination", void 0);
566
+ __decorate([
567
+ property({ type: String, attribute: 'quick-filter' })
568
+ ], ApexGrid.prototype, "quickFilter", void 0);
569
+ __decorate([
570
+ property({ type: Boolean, attribute: 'show-quick-filter' })
571
+ ], ApexGrid.prototype, "showQuickFilter", void 0);
572
+ __decorate([
573
+ property({ type: Boolean, attribute: 'show-export' })
574
+ ], ApexGrid.prototype, "showExport", void 0);
575
+ __decorate([
576
+ property({ type: Boolean, attribute: 'column-reordering' })
577
+ ], ApexGrid.prototype, "columnReordering", void 0);
578
+ __decorate([
579
+ property({ attribute: false })
580
+ ], ApexGrid.prototype, "editing", void 0);
581
+ __decorate([
582
+ property({ attribute: false })
583
+ ], ApexGrid.prototype, "selection", void 0);
584
+ __decorate([
585
+ property({ attribute: false })
586
+ ], ApexGrid.prototype, "expansion", void 0);
587
+ __decorate([
588
+ property({ attribute: false })
589
+ ], ApexGrid.prototype, "tree", void 0);
212
590
  __decorate([
213
591
  property({ attribute: false })
214
592
  ], ApexGrid.prototype, "sortExpressions", null);
215
593
  __decorate([
216
594
  property({ attribute: false })
217
595
  ], ApexGrid.prototype, "filterExpressions", null);
596
+ __decorate([
597
+ property({ attribute: false })
598
+ ], ApexGrid.prototype, "page", null);
599
+ __decorate([
600
+ property({ attribute: false })
601
+ ], ApexGrid.prototype, "pageSize", null);
218
602
  __decorate([
219
603
  watch('columns')
220
604
  ], ApexGrid.prototype, "watchColumns", null);
@@ -224,6 +608,12 @@ __decorate([
224
608
  __decorate([
225
609
  watch(PIPELINE)
226
610
  ], ApexGrid.prototype, "pipeline", null);
611
+ __decorate([
612
+ watch('pagination')
613
+ ], ApexGrid.prototype, "paginationChanged", null);
614
+ __decorate([
615
+ watch('quickFilter')
616
+ ], ApexGrid.prototype, "quickFilterChanged", null);
227
617
  __decorate([
228
618
  eventOptions({ capture: true })
229
619
  ], ApexGrid.prototype, "bodyClickHandler", null);