@parksw/sw-ui-components 0.0.1 → 0.0.2
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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/my-grid.d.ts +75 -0
- package/dist/my-grid.js +852 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
+
interface Column {
|
|
3
|
+
key: string;
|
|
4
|
+
header: string;
|
|
5
|
+
linkTemplate?: string;
|
|
6
|
+
width?: string;
|
|
7
|
+
align?: 'left' | 'center' | 'right';
|
|
8
|
+
}
|
|
9
|
+
export declare class MyGrid extends LitElement {
|
|
10
|
+
columns: Column[];
|
|
11
|
+
data: Record<string, unknown>[];
|
|
12
|
+
itemsPerPage: number;
|
|
13
|
+
columnReordering: boolean;
|
|
14
|
+
height: string;
|
|
15
|
+
enableColumnVisibility: boolean;
|
|
16
|
+
enableFilter: boolean;
|
|
17
|
+
rowClass?: (row: Record<string, unknown>) => string;
|
|
18
|
+
private _sortKey;
|
|
19
|
+
private _sortDirection;
|
|
20
|
+
private _draggedColumnIndex;
|
|
21
|
+
private _dragOverColumnIndex;
|
|
22
|
+
private _selectedRowId;
|
|
23
|
+
private _selectedColumnKey;
|
|
24
|
+
private _filterValues;
|
|
25
|
+
private _activeFilterColumn;
|
|
26
|
+
private _filterSearchTerm;
|
|
27
|
+
private _currentPage;
|
|
28
|
+
private _hiddenColumns;
|
|
29
|
+
private _showColumnMenu;
|
|
30
|
+
private _filterMenuSortDirection;
|
|
31
|
+
private _resizingColumnIndex;
|
|
32
|
+
private _startX;
|
|
33
|
+
private _startWidth;
|
|
34
|
+
constructor();
|
|
35
|
+
connectedCallback(): void;
|
|
36
|
+
disconnectedCallback(): void;
|
|
37
|
+
protected updated(changedProperties: PropertyValues): void;
|
|
38
|
+
private _handleDocumentClick;
|
|
39
|
+
private get _visibleColumns();
|
|
40
|
+
private get _gridColumnTemplate();
|
|
41
|
+
private _resetPage;
|
|
42
|
+
private _toggleColumnMenu;
|
|
43
|
+
private _toggleColumnVisibility;
|
|
44
|
+
private _handleItemsPerPageChange;
|
|
45
|
+
private _handleHeaderClick;
|
|
46
|
+
private _toggleFilterMenu;
|
|
47
|
+
private _toggleFilterMenuSort;
|
|
48
|
+
private _getUniqueValues;
|
|
49
|
+
private _isFilterActive;
|
|
50
|
+
private _handleFilterValueChange;
|
|
51
|
+
private _handleSelectAll;
|
|
52
|
+
private _handleFilterSearch;
|
|
53
|
+
private _handleResizeStart;
|
|
54
|
+
private _handleResizeMove;
|
|
55
|
+
private _handleResizeEnd;
|
|
56
|
+
private get _filteredData();
|
|
57
|
+
private get _sortedData();
|
|
58
|
+
private get _paginatedData();
|
|
59
|
+
private _handleCellClick;
|
|
60
|
+
private _handleDragStart;
|
|
61
|
+
private _handleDragOver;
|
|
62
|
+
private _handleDragLeave;
|
|
63
|
+
private _handleDrop;
|
|
64
|
+
private _handleDragEnd;
|
|
65
|
+
private _formatLink;
|
|
66
|
+
private _renderCell;
|
|
67
|
+
private _renderColumnMenu;
|
|
68
|
+
private _renderFilterMenu;
|
|
69
|
+
private _renderHeader;
|
|
70
|
+
private _renderBody;
|
|
71
|
+
private _renderPaginationControls;
|
|
72
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
73
|
+
static styles: import("lit").CSSResult;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
package/dist/my-grid.js
ADDED
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from 'lit';
|
|
8
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
9
|
+
import { when } from 'lit/directives/when.js';
|
|
10
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
11
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
12
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
13
|
+
let MyGrid = class MyGrid extends LitElement {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.columns = [];
|
|
17
|
+
this.data = [];
|
|
18
|
+
this.itemsPerPage = 10;
|
|
19
|
+
this.columnReordering = true;
|
|
20
|
+
this.height = 'auto';
|
|
21
|
+
this.enableColumnVisibility = true;
|
|
22
|
+
this.enableFilter = true;
|
|
23
|
+
this._sortKey = null;
|
|
24
|
+
this._sortDirection = 'asc';
|
|
25
|
+
this._draggedColumnIndex = null;
|
|
26
|
+
this._dragOverColumnIndex = null;
|
|
27
|
+
this._selectedRowId = null;
|
|
28
|
+
this._selectedColumnKey = null;
|
|
29
|
+
this._filterValues = {};
|
|
30
|
+
this._activeFilterColumn = null;
|
|
31
|
+
this._filterSearchTerm = '';
|
|
32
|
+
this._currentPage = 1;
|
|
33
|
+
this._hiddenColumns = new Set();
|
|
34
|
+
this._showColumnMenu = false;
|
|
35
|
+
this._filterMenuSortDirection = 'asc'; // New state for filter menu sort
|
|
36
|
+
// Resizing state
|
|
37
|
+
this._resizingColumnIndex = null;
|
|
38
|
+
this._startX = 0;
|
|
39
|
+
this._startWidth = 0;
|
|
40
|
+
this._handleDocumentClick = this._handleDocumentClick.bind(this);
|
|
41
|
+
this._handleResizeMove = this._handleResizeMove.bind(this);
|
|
42
|
+
this._handleResizeEnd = this._handleResizeEnd.bind(this);
|
|
43
|
+
}
|
|
44
|
+
connectedCallback() {
|
|
45
|
+
super.connectedCallback();
|
|
46
|
+
document.addEventListener('click', this._handleDocumentClick);
|
|
47
|
+
document.addEventListener('mousemove', this._handleResizeMove);
|
|
48
|
+
document.addEventListener('mouseup', this._handleResizeEnd);
|
|
49
|
+
}
|
|
50
|
+
disconnectedCallback() {
|
|
51
|
+
super.disconnectedCallback();
|
|
52
|
+
document.removeEventListener('click', this._handleDocumentClick);
|
|
53
|
+
document.removeEventListener('mousemove', this._handleResizeMove);
|
|
54
|
+
document.removeEventListener('mouseup', this._handleResizeEnd);
|
|
55
|
+
}
|
|
56
|
+
updated(changedProperties) {
|
|
57
|
+
super.updated(changedProperties);
|
|
58
|
+
if (changedProperties.has('enableFilter')) {
|
|
59
|
+
this._filterValues = {};
|
|
60
|
+
this._activeFilterColumn = null;
|
|
61
|
+
this._filterSearchTerm = '';
|
|
62
|
+
this._resetPage();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
_handleDocumentClick(_e) {
|
|
66
|
+
if (this._showColumnMenu) {
|
|
67
|
+
this._showColumnMenu = false;
|
|
68
|
+
}
|
|
69
|
+
if (this._activeFilterColumn) {
|
|
70
|
+
this._activeFilterColumn = null;
|
|
71
|
+
this._filterSearchTerm = '';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
get _visibleColumns() {
|
|
75
|
+
return this.columns.filter(col => !this._hiddenColumns.has(col.key));
|
|
76
|
+
}
|
|
77
|
+
get _gridColumnTemplate() {
|
|
78
|
+
let template = '';
|
|
79
|
+
if (this.enableColumnVisibility) {
|
|
80
|
+
template += '40px ';
|
|
81
|
+
}
|
|
82
|
+
template += this._visibleColumns.map(col => col.width || 'minmax(150px, 1fr)').join(' ');
|
|
83
|
+
return template;
|
|
84
|
+
}
|
|
85
|
+
_resetPage() { this._currentPage = 1; }
|
|
86
|
+
_toggleColumnMenu(e) {
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
this._showColumnMenu = !this._showColumnMenu;
|
|
89
|
+
this._activeFilterColumn = null;
|
|
90
|
+
}
|
|
91
|
+
_toggleColumnVisibility(key) {
|
|
92
|
+
const newHiddenColumns = new Set(this._hiddenColumns);
|
|
93
|
+
if (newHiddenColumns.has(key)) {
|
|
94
|
+
newHiddenColumns.delete(key);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
newHiddenColumns.add(key);
|
|
98
|
+
}
|
|
99
|
+
this._hiddenColumns = newHiddenColumns;
|
|
100
|
+
}
|
|
101
|
+
_handleItemsPerPageChange(e) {
|
|
102
|
+
const select = e.target;
|
|
103
|
+
this.itemsPerPage = Number(select.value);
|
|
104
|
+
this._resetPage();
|
|
105
|
+
}
|
|
106
|
+
_handleHeaderClick(key) {
|
|
107
|
+
if (this._sortKey === key) {
|
|
108
|
+
this._sortDirection = this._sortDirection === 'asc' ? 'desc' : 'asc';
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this._sortKey = key;
|
|
112
|
+
this._sortDirection = 'asc';
|
|
113
|
+
}
|
|
114
|
+
this._resetPage();
|
|
115
|
+
}
|
|
116
|
+
_toggleFilterMenu(e, key) {
|
|
117
|
+
e.stopPropagation();
|
|
118
|
+
if (this._activeFilterColumn === key) {
|
|
119
|
+
this._activeFilterColumn = null;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this._activeFilterColumn = key;
|
|
123
|
+
this._showColumnMenu = false;
|
|
124
|
+
this._filterMenuSortDirection = 'asc'; // Reset sort direction when opening menu
|
|
125
|
+
}
|
|
126
|
+
this._filterSearchTerm = '';
|
|
127
|
+
}
|
|
128
|
+
_toggleFilterMenuSort(e) {
|
|
129
|
+
e.stopPropagation();
|
|
130
|
+
this._filterMenuSortDirection = this._filterMenuSortDirection === 'asc' ? 'desc' : 'asc';
|
|
131
|
+
}
|
|
132
|
+
_getUniqueValues(key) {
|
|
133
|
+
const values = new Set(this.data.map(row => row[key]));
|
|
134
|
+
const sortedValues = Array.from(values).sort((a, b) => {
|
|
135
|
+
if (a === b)
|
|
136
|
+
return 0;
|
|
137
|
+
if (a == null)
|
|
138
|
+
return 1;
|
|
139
|
+
if (b == null)
|
|
140
|
+
return -1;
|
|
141
|
+
let comparison = 0;
|
|
142
|
+
if (typeof a === 'number' && typeof b === 'number') {
|
|
143
|
+
comparison = a - b;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Try to parse as date if string looks like date (YYYY-MM-DD)
|
|
147
|
+
const dateA = Date.parse(String(a));
|
|
148
|
+
const dateB = Date.parse(String(b));
|
|
149
|
+
if (!isNaN(dateA) && !isNaN(dateB) && String(a).includes('-') && String(b).includes('-')) {
|
|
150
|
+
comparison = dateA - dateB;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
comparison = String(a).localeCompare(String(b));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return this._filterMenuSortDirection === 'asc' ? comparison : -comparison;
|
|
157
|
+
});
|
|
158
|
+
return sortedValues;
|
|
159
|
+
}
|
|
160
|
+
_isFilterActive(key) {
|
|
161
|
+
return !!this._filterValues[key];
|
|
162
|
+
}
|
|
163
|
+
_handleFilterValueChange(key, value, checked) {
|
|
164
|
+
let currentFilters = this._filterValues[key];
|
|
165
|
+
if (!currentFilters) {
|
|
166
|
+
if (!checked) {
|
|
167
|
+
const allValues = this._getUniqueValues(key);
|
|
168
|
+
currentFilters = new Set(allValues);
|
|
169
|
+
currentFilters.delete(value);
|
|
170
|
+
this._filterValues = { ...this._filterValues, [key]: currentFilters };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
const newFilters = new Set(currentFilters);
|
|
175
|
+
if (checked) {
|
|
176
|
+
newFilters.add(value);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
newFilters.delete(value);
|
|
180
|
+
}
|
|
181
|
+
const allValues = this._getUniqueValues(key);
|
|
182
|
+
if (newFilters.size === allValues.length) {
|
|
183
|
+
const newFilterValues = { ...this._filterValues };
|
|
184
|
+
delete newFilterValues[key];
|
|
185
|
+
this._filterValues = newFilterValues;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this._filterValues = { ...this._filterValues, [key]: newFilters };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
this._resetPage();
|
|
192
|
+
}
|
|
193
|
+
_handleSelectAll(key, checked) {
|
|
194
|
+
if (checked) {
|
|
195
|
+
const newFilters = { ...this._filterValues };
|
|
196
|
+
delete newFilters[key];
|
|
197
|
+
this._filterValues = newFilters;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this._filterValues = { ...this._filterValues, [key]: new Set() };
|
|
201
|
+
}
|
|
202
|
+
this._resetPage();
|
|
203
|
+
}
|
|
204
|
+
_handleFilterSearch(e) {
|
|
205
|
+
const input = e.target;
|
|
206
|
+
this._filterSearchTerm = input.value;
|
|
207
|
+
}
|
|
208
|
+
// Resize Handlers
|
|
209
|
+
_handleResizeStart(e, index) {
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
e.stopPropagation();
|
|
212
|
+
this._resizingColumnIndex = index;
|
|
213
|
+
this._startX = e.pageX;
|
|
214
|
+
const headerCells = this.shadowRoot?.querySelectorAll('.header-cell');
|
|
215
|
+
const cellIndex = index + (this.enableColumnVisibility ? 1 : 0);
|
|
216
|
+
if (headerCells && headerCells[cellIndex]) {
|
|
217
|
+
const cell = headerCells[cellIndex];
|
|
218
|
+
this._startWidth = cell.getBoundingClientRect().width;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this._startWidth = 150;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
_handleResizeMove(e) {
|
|
225
|
+
if (this._resizingColumnIndex !== null) {
|
|
226
|
+
const diff = e.pageX - this._startX;
|
|
227
|
+
const newWidth = Math.max(50, this._startWidth + diff);
|
|
228
|
+
const visibleCol = this._visibleColumns[this._resizingColumnIndex];
|
|
229
|
+
const originalIndex = this.columns.findIndex(c => c.key === visibleCol.key);
|
|
230
|
+
if (originalIndex !== -1) {
|
|
231
|
+
const newColumns = [...this.columns];
|
|
232
|
+
newColumns[originalIndex] = { ...newColumns[originalIndex], width: `${newWidth}px` };
|
|
233
|
+
this.columns = newColumns;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
_handleResizeEnd() {
|
|
238
|
+
this._resizingColumnIndex = null;
|
|
239
|
+
}
|
|
240
|
+
get _filteredData() {
|
|
241
|
+
if (!this.enableFilter) {
|
|
242
|
+
return this.data;
|
|
243
|
+
}
|
|
244
|
+
let filtered = this.data;
|
|
245
|
+
const activeFilterKeys = Object.keys(this._filterValues);
|
|
246
|
+
if (activeFilterKeys.length > 0) {
|
|
247
|
+
filtered = filtered.filter(row => {
|
|
248
|
+
return activeFilterKeys.every(key => {
|
|
249
|
+
const filterSet = this._filterValues[key];
|
|
250
|
+
if (!filterSet || filterSet.size === 0)
|
|
251
|
+
return false;
|
|
252
|
+
if (filterSet)
|
|
253
|
+
return filterSet.has(row[key]);
|
|
254
|
+
return true;
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return filtered;
|
|
259
|
+
}
|
|
260
|
+
get _sortedData() {
|
|
261
|
+
const dataToSort = this._filteredData;
|
|
262
|
+
if (!this._sortKey)
|
|
263
|
+
return dataToSort;
|
|
264
|
+
return [...dataToSort].sort((a, b) => {
|
|
265
|
+
const valA = a[this._sortKey], valB = b[this._sortKey];
|
|
266
|
+
if (valA === valB)
|
|
267
|
+
return 0;
|
|
268
|
+
if (valA == null)
|
|
269
|
+
return 1;
|
|
270
|
+
if (valB == null)
|
|
271
|
+
return -1;
|
|
272
|
+
let comparison = 0;
|
|
273
|
+
if (typeof valA === 'string' && typeof valB === 'string')
|
|
274
|
+
comparison = valA.localeCompare(valB);
|
|
275
|
+
else if (typeof valA === 'number' && typeof valB === 'number')
|
|
276
|
+
comparison = valA - valB;
|
|
277
|
+
else
|
|
278
|
+
comparison = String(valA).localeCompare(String(valB));
|
|
279
|
+
return this._sortDirection === 'asc' ? comparison : -comparison;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
get _paginatedData() {
|
|
283
|
+
const start = (this._currentPage - 1) * this.itemsPerPage;
|
|
284
|
+
const end = start + this.itemsPerPage;
|
|
285
|
+
return this._sortedData.slice(start, end);
|
|
286
|
+
}
|
|
287
|
+
_handleCellClick(row, colKey) {
|
|
288
|
+
const rowId = row.id;
|
|
289
|
+
if (this._selectedRowId === rowId && this._selectedColumnKey === colKey) {
|
|
290
|
+
this._selectedRowId = null;
|
|
291
|
+
this._selectedColumnKey = null;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
this._selectedRowId = rowId;
|
|
295
|
+
this._selectedColumnKey = colKey;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
_handleDragStart(e, index) {
|
|
299
|
+
if (this._resizingColumnIndex !== null) {
|
|
300
|
+
e.preventDefault();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (!this.columnReordering) {
|
|
304
|
+
e.preventDefault();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
this._draggedColumnIndex = index;
|
|
308
|
+
if (e.dataTransfer) {
|
|
309
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
310
|
+
e.dataTransfer.setData('text/plain', index.toString());
|
|
311
|
+
const target = e.target;
|
|
312
|
+
e.dataTransfer.setDragImage(target, e.offsetX, e.offsetY);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
_handleDragOver(e, index) {
|
|
316
|
+
if (!this.columnReordering)
|
|
317
|
+
return;
|
|
318
|
+
e.preventDefault();
|
|
319
|
+
if (e.dataTransfer) {
|
|
320
|
+
e.dataTransfer.dropEffect = 'move';
|
|
321
|
+
}
|
|
322
|
+
if (this._draggedColumnIndex !== null && this._draggedColumnIndex !== index) {
|
|
323
|
+
this._dragOverColumnIndex = index;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
_handleDragLeave() {
|
|
327
|
+
if (!this.columnReordering)
|
|
328
|
+
return;
|
|
329
|
+
this._dragOverColumnIndex = null;
|
|
330
|
+
}
|
|
331
|
+
_handleDrop(e, dropIndex) {
|
|
332
|
+
if (!this.columnReordering)
|
|
333
|
+
return;
|
|
334
|
+
e.preventDefault();
|
|
335
|
+
if (e.dataTransfer) {
|
|
336
|
+
const draggedIndex = parseInt(e.dataTransfer.getData('text/plain'), 10);
|
|
337
|
+
if (this._draggedColumnIndex !== null && draggedIndex !== dropIndex) {
|
|
338
|
+
const visibleCols = [...this._visibleColumns];
|
|
339
|
+
const [draggedColumn] = visibleCols.splice(draggedIndex, 1);
|
|
340
|
+
visibleCols.splice(dropIndex, 0, draggedColumn);
|
|
341
|
+
const newColumns = [];
|
|
342
|
+
let visibleIndex = 0;
|
|
343
|
+
for (const col of this.columns) {
|
|
344
|
+
if (this._hiddenColumns.has(col.key)) {
|
|
345
|
+
newColumns.push(col);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
newColumns.push(visibleCols[visibleIndex++]);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
this.columns = newColumns;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
this._draggedColumnIndex = null;
|
|
355
|
+
this._dragOverColumnIndex = null;
|
|
356
|
+
}
|
|
357
|
+
_handleDragEnd() {
|
|
358
|
+
if (!this.columnReordering)
|
|
359
|
+
return;
|
|
360
|
+
this._draggedColumnIndex = null;
|
|
361
|
+
this._dragOverColumnIndex = null;
|
|
362
|
+
}
|
|
363
|
+
_formatLink(template, row) {
|
|
364
|
+
return template.replace(/{(\w+)}/g, (_match, key) => {
|
|
365
|
+
return row[key] !== undefined ? String(row[key]) : _match;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
_renderCell(row, col) {
|
|
369
|
+
const cellData = row[col.key];
|
|
370
|
+
if (col.linkTemplate) {
|
|
371
|
+
const href = this._formatLink(col.linkTemplate, row);
|
|
372
|
+
return html `<a href="${href}">${cellData}</a>`;
|
|
373
|
+
}
|
|
374
|
+
return cellData;
|
|
375
|
+
}
|
|
376
|
+
_renderColumnMenu() {
|
|
377
|
+
if (!this._showColumnMenu)
|
|
378
|
+
return null;
|
|
379
|
+
return html `
|
|
380
|
+
<div class="column-menu" @click=${(e) => e.stopPropagation()}>
|
|
381
|
+
${this.columns.map(col => html `
|
|
382
|
+
<label>
|
|
383
|
+
<input
|
|
384
|
+
type="checkbox"
|
|
385
|
+
.checked=${!this._hiddenColumns.has(col.key)}
|
|
386
|
+
@change=${() => this._toggleColumnVisibility(col.key)}
|
|
387
|
+
/>
|
|
388
|
+
${col.header}
|
|
389
|
+
</label>
|
|
390
|
+
`)}
|
|
391
|
+
</div>
|
|
392
|
+
`;
|
|
393
|
+
}
|
|
394
|
+
_renderFilterMenu(key, index) {
|
|
395
|
+
if (this._activeFilterColumn !== key)
|
|
396
|
+
return null;
|
|
397
|
+
const uniqueValues = this._getUniqueValues(key);
|
|
398
|
+
const filteredValues = uniqueValues.filter(v => String(v).toLowerCase().includes(this._filterSearchTerm.toLowerCase()));
|
|
399
|
+
const currentFilters = this._filterValues[key];
|
|
400
|
+
const isAllSelected = !currentFilters;
|
|
401
|
+
const isSelectAllChecked = isAllSelected || (!!currentFilters && filteredValues.every(v => currentFilters.has(v)));
|
|
402
|
+
const isRightAligned = index > this._visibleColumns.length - 3;
|
|
403
|
+
const menuClass = isRightAligned ? 'filter-menu right-aligned' : 'filter-menu';
|
|
404
|
+
return html `
|
|
405
|
+
<div class="${menuClass}" @click=${(e) => e.stopPropagation()}>
|
|
406
|
+
<div class="filter-search-container">
|
|
407
|
+
<input
|
|
408
|
+
type="text"
|
|
409
|
+
class="filter-search"
|
|
410
|
+
placeholder="Search..."
|
|
411
|
+
.value=${this._filterSearchTerm}
|
|
412
|
+
@input=${this._handleFilterSearch}
|
|
413
|
+
/>
|
|
414
|
+
<button class="filter-sort-btn" @click=${this._toggleFilterMenuSort} title="Sort Values">
|
|
415
|
+
${this._filterMenuSortDirection === 'asc' ? '▲' : '▼'}
|
|
416
|
+
</button>
|
|
417
|
+
</div>
|
|
418
|
+
<div class="filter-list">
|
|
419
|
+
<label>
|
|
420
|
+
<input
|
|
421
|
+
type="checkbox"
|
|
422
|
+
.checked=${isSelectAllChecked}
|
|
423
|
+
@change=${(e) => this._handleSelectAll(key, e.target.checked)}
|
|
424
|
+
/>
|
|
425
|
+
(Select All)
|
|
426
|
+
</label>
|
|
427
|
+
${filteredValues.map(value => html `
|
|
428
|
+
<label>
|
|
429
|
+
<input
|
|
430
|
+
type="checkbox"
|
|
431
|
+
.checked=${isAllSelected || (!!currentFilters && currentFilters.has(value))}
|
|
432
|
+
@change=${(e) => this._handleFilterValueChange(key, value, e.target.checked)}
|
|
433
|
+
/>
|
|
434
|
+
${String(value)}
|
|
435
|
+
</label>
|
|
436
|
+
`)}
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
`;
|
|
440
|
+
}
|
|
441
|
+
_renderHeader(gridStyles) {
|
|
442
|
+
return html `
|
|
443
|
+
<div class="grid-header">
|
|
444
|
+
<div class="grid-row" style=${styleMap(gridStyles)}>
|
|
445
|
+
${when(this.enableColumnVisibility, () => html `
|
|
446
|
+
<div class="grid-cell header-cell settings-cell" @click=${this._toggleColumnMenu}>
|
|
447
|
+
⚙️
|
|
448
|
+
${this._renderColumnMenu()}
|
|
449
|
+
</div>
|
|
450
|
+
`)}
|
|
451
|
+
${this._visibleColumns.map((col, index) => {
|
|
452
|
+
const headerClasses = {
|
|
453
|
+
'grid-cell': true,
|
|
454
|
+
'header-cell': true,
|
|
455
|
+
'drag-over': this._dragOverColumnIndex === index,
|
|
456
|
+
'reorderable': this.columnReordering,
|
|
457
|
+
'align-center': col.align === 'center',
|
|
458
|
+
'align-right': col.align === 'right',
|
|
459
|
+
};
|
|
460
|
+
return html `
|
|
461
|
+
<div
|
|
462
|
+
.draggable=${this.columnReordering}
|
|
463
|
+
class=${classMap(headerClasses)}
|
|
464
|
+
@click=${() => this._handleHeaderClick(col.key)}
|
|
465
|
+
@dragstart=${(e) => this._handleDragStart(e, index)}
|
|
466
|
+
@dragover=${(e) => this._handleDragOver(e, index)}
|
|
467
|
+
@dragleave=${this._handleDragLeave}
|
|
468
|
+
@drop=${(e) => this._handleDrop(e, index)}
|
|
469
|
+
@dragend=${this._handleDragEnd}
|
|
470
|
+
>
|
|
471
|
+
<span class="header-text">${col.header}</span>
|
|
472
|
+
<div class="header-icons">
|
|
473
|
+
${when(this.enableFilter, () => html `
|
|
474
|
+
<span class="filter-icon ${this._isFilterActive(col.key) ? 'active' : ''}" @click=${(e) => this._toggleFilterMenu(e, col.key)}>
|
|
475
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
476
|
+
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
|
|
477
|
+
</svg>
|
|
478
|
+
</span>
|
|
479
|
+
`)}
|
|
480
|
+
${this._sortKey === col.key ? html `<span class="sort-indicator">${this._sortDirection === 'asc' ? '▲' : '▼'}</span>` : ''}
|
|
481
|
+
</div>
|
|
482
|
+
${this._renderFilterMenu(col.key, index)}
|
|
483
|
+
<div class="resize-handle" @mousedown=${(e) => this._handleResizeStart(e, index)} @click=${(e) => e.stopPropagation()}></div>
|
|
484
|
+
</div>
|
|
485
|
+
`;
|
|
486
|
+
})}
|
|
487
|
+
</div>
|
|
488
|
+
</div>
|
|
489
|
+
`;
|
|
490
|
+
}
|
|
491
|
+
_renderBody(gridStyles) {
|
|
492
|
+
return html `
|
|
493
|
+
<div class="grid-body">
|
|
494
|
+
${repeat(this._paginatedData, (row) => row.id, (row) => {
|
|
495
|
+
const customRowClass = this.rowClass ? this.rowClass(row) : '';
|
|
496
|
+
return html `
|
|
497
|
+
<div class="grid-row ${customRowClass}" style=${styleMap(gridStyles)}>
|
|
498
|
+
${when(this.enableColumnVisibility, () => html `<div class="grid-cell data-cell"></div>`)}
|
|
499
|
+
${this._visibleColumns.map(col => {
|
|
500
|
+
const dataCellClasses = {
|
|
501
|
+
'grid-cell': true,
|
|
502
|
+
'data-cell': true,
|
|
503
|
+
selected: this._selectedRowId === row.id && this._selectedColumnKey === col.key,
|
|
504
|
+
'align-center': col.align === 'center',
|
|
505
|
+
'align-right': col.align === 'right',
|
|
506
|
+
[`col-${col.key}`]: true,
|
|
507
|
+
};
|
|
508
|
+
return html `
|
|
509
|
+
<div
|
|
510
|
+
title="${String(row[col.key] ?? '')}"
|
|
511
|
+
class=${classMap(dataCellClasses)}
|
|
512
|
+
@click=${() => this._handleCellClick(row, col.key)}
|
|
513
|
+
>
|
|
514
|
+
${this._renderCell(row, col)}
|
|
515
|
+
</div>
|
|
516
|
+
`;
|
|
517
|
+
})}
|
|
518
|
+
</div>
|
|
519
|
+
`;
|
|
520
|
+
})}
|
|
521
|
+
</div>
|
|
522
|
+
`;
|
|
523
|
+
}
|
|
524
|
+
_renderPaginationControls() {
|
|
525
|
+
const totalItems = this._sortedData.length;
|
|
526
|
+
const totalPages = Math.ceil(totalItems / this.itemsPerPage);
|
|
527
|
+
if (totalPages <= 1)
|
|
528
|
+
return '';
|
|
529
|
+
return html `
|
|
530
|
+
<div class="pagination">
|
|
531
|
+
<div class="pagination-group">
|
|
532
|
+
<button @click=${() => this._currentPage = 1} ?disabled=${this._currentPage === 1}><< First</button>
|
|
533
|
+
<button @click=${() => this._currentPage--} ?disabled=${this._currentPage === 1}>< Previous</button>
|
|
534
|
+
</div>
|
|
535
|
+
<div class="pagination-info">
|
|
536
|
+
<span>Page ${this._currentPage} of ${totalPages}</span>
|
|
537
|
+
</div>
|
|
538
|
+
<div class="pagination-group">
|
|
539
|
+
<button @click=${() => this._currentPage++} ?disabled=${this._currentPage === totalPages}>Next ></button>
|
|
540
|
+
<button @click=${() => this._currentPage = totalPages} ?disabled=${this._currentPage === totalPages}>Last >></button>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
`;
|
|
544
|
+
}
|
|
545
|
+
render() {
|
|
546
|
+
const wrapperStyles = { height: this.height };
|
|
547
|
+
const gridStyles = { 'grid-template-columns': this._gridColumnTemplate };
|
|
548
|
+
return html `
|
|
549
|
+
<div class="toolbar">
|
|
550
|
+
<div class="items-per-page">
|
|
551
|
+
<span>Rows per page:</span>
|
|
552
|
+
<select @change=${this._handleItemsPerPageChange} .value=${this.itemsPerPage.toString()}>
|
|
553
|
+
<option value="10">10</option>
|
|
554
|
+
<option value="20">20</option>
|
|
555
|
+
<option value="50">50</option>
|
|
556
|
+
</select>
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
<div class="grid-wrapper" style=${styleMap(wrapperStyles)}>
|
|
560
|
+
<div class="grid-container">
|
|
561
|
+
${this._renderHeader(gridStyles)}
|
|
562
|
+
${this._renderBody(gridStyles)}
|
|
563
|
+
</div>
|
|
564
|
+
</div>
|
|
565
|
+
${this._renderPaginationControls()}
|
|
566
|
+
`;
|
|
567
|
+
}
|
|
568
|
+
static { this.styles = css `
|
|
569
|
+
:host {
|
|
570
|
+
display: block;
|
|
571
|
+
font-family: sans-serif;
|
|
572
|
+
}
|
|
573
|
+
/* Default styles for all elements inside the component */
|
|
574
|
+
* {
|
|
575
|
+
box-sizing: border-box;
|
|
576
|
+
color: #000; /* Default text color black */
|
|
577
|
+
}
|
|
578
|
+
input, select, button {
|
|
579
|
+
background-color: #fff; /* Default background white */
|
|
580
|
+
color: #000; /* Default text color black */
|
|
581
|
+
border: 1px solid #ccc;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.toolbar {
|
|
585
|
+
margin-bottom: 8px;
|
|
586
|
+
display: flex;
|
|
587
|
+
justify-content: flex-end;
|
|
588
|
+
align-items: center;
|
|
589
|
+
}
|
|
590
|
+
.toolbar button { padding: 6px 12px; border-radius: 4px; background-color: #f8f8f8; cursor: pointer; }
|
|
591
|
+
.toolbar button:hover { background-color: #eee; }
|
|
592
|
+
|
|
593
|
+
.items-per-page {
|
|
594
|
+
display: flex;
|
|
595
|
+
align-items: center;
|
|
596
|
+
gap: 8px;
|
|
597
|
+
font-size: 0.9em;
|
|
598
|
+
}
|
|
599
|
+
.items-per-page select {
|
|
600
|
+
padding: 4px 8px;
|
|
601
|
+
border-radius: 4px;
|
|
602
|
+
cursor: pointer;
|
|
603
|
+
font-size: 1em;
|
|
604
|
+
color: #000;
|
|
605
|
+
}
|
|
606
|
+
.items-per-page select:hover {
|
|
607
|
+
border-color: #888;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.grid-wrapper {
|
|
611
|
+
overflow: auto;
|
|
612
|
+
border: 1px solid #ccc;
|
|
613
|
+
border-radius: 4px;
|
|
614
|
+
}
|
|
615
|
+
.grid-container {
|
|
616
|
+
display: inline-block;
|
|
617
|
+
min-width: 100%;
|
|
618
|
+
vertical-align: top;
|
|
619
|
+
}
|
|
620
|
+
.grid-header {
|
|
621
|
+
position: sticky;
|
|
622
|
+
top: 0;
|
|
623
|
+
z-index: 2;
|
|
624
|
+
background-color: #e8e8e8;
|
|
625
|
+
}
|
|
626
|
+
.grid-row {
|
|
627
|
+
display: grid;
|
|
628
|
+
border-bottom: 1px solid #ddd;
|
|
629
|
+
}
|
|
630
|
+
.grid-body .grid-row:last-of-type {
|
|
631
|
+
border-bottom: none;
|
|
632
|
+
}
|
|
633
|
+
.grid-cell {
|
|
634
|
+
padding: 12px 15px;
|
|
635
|
+
text-align: left;
|
|
636
|
+
color: #000;
|
|
637
|
+
overflow: hidden;
|
|
638
|
+
text-overflow: ellipsis;
|
|
639
|
+
white-space: nowrap;
|
|
640
|
+
border-right: 1px solid #ddd; /* Add right border */
|
|
641
|
+
}
|
|
642
|
+
.grid-cell:last-child {
|
|
643
|
+
border-right: none; /* Remove right border for last cell */
|
|
644
|
+
}
|
|
645
|
+
.grid-cell.align-center { justify-content: center; text-align: center; }
|
|
646
|
+
.grid-cell.align-right { justify-content: flex-end; text-align: right; }
|
|
647
|
+
|
|
648
|
+
.header-cell {
|
|
649
|
+
display: flex;
|
|
650
|
+
align-items: center;
|
|
651
|
+
justify-content: space-between;
|
|
652
|
+
font-weight: bold;
|
|
653
|
+
cursor: pointer;
|
|
654
|
+
user-select: none;
|
|
655
|
+
position: relative;
|
|
656
|
+
overflow: visible;
|
|
657
|
+
border-bottom: 1px solid #ccc; /* Add bottom border to header */
|
|
658
|
+
}
|
|
659
|
+
.header-text {
|
|
660
|
+
overflow: hidden;
|
|
661
|
+
text-overflow: ellipsis;
|
|
662
|
+
white-space: nowrap;
|
|
663
|
+
flex-grow: 1;
|
|
664
|
+
}
|
|
665
|
+
.header-icons {
|
|
666
|
+
display: flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
gap: 4px;
|
|
669
|
+
}
|
|
670
|
+
.sort-indicator {
|
|
671
|
+
flex-shrink: 0;
|
|
672
|
+
}
|
|
673
|
+
.filter-icon {
|
|
674
|
+
display: flex;
|
|
675
|
+
align-items: center;
|
|
676
|
+
justify-content: center;
|
|
677
|
+
width: 16px;
|
|
678
|
+
height: 16px;
|
|
679
|
+
color: #888; /* Default grey icon */
|
|
680
|
+
padding: 2px;
|
|
681
|
+
border-radius: 2px;
|
|
682
|
+
cursor: pointer;
|
|
683
|
+
}
|
|
684
|
+
.filter-icon:hover {
|
|
685
|
+
color: #000; /* Black icon on hover */
|
|
686
|
+
}
|
|
687
|
+
.filter-icon.active {
|
|
688
|
+
color: #007bff; /* Blue icon when active */
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.settings-cell {
|
|
692
|
+
justify-content: center;
|
|
693
|
+
position: relative;
|
|
694
|
+
overflow: visible;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.column-menu, .filter-menu {
|
|
698
|
+
position: absolute;
|
|
699
|
+
top: 100%;
|
|
700
|
+
left: 0;
|
|
701
|
+
background-color: white;
|
|
702
|
+
border: 1px solid #ccc;
|
|
703
|
+
border-radius: 4px;
|
|
704
|
+
padding: 8px;
|
|
705
|
+
z-index: 100;
|
|
706
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
707
|
+
min-width: 150px;
|
|
708
|
+
display: flex;
|
|
709
|
+
flex-direction: column;
|
|
710
|
+
gap: 4px;
|
|
711
|
+
max-height: 250px;
|
|
712
|
+
overflow-y: auto;
|
|
713
|
+
text-align: left;
|
|
714
|
+
font-weight: normal;
|
|
715
|
+
}
|
|
716
|
+
.filter-menu.right-aligned {
|
|
717
|
+
left: auto;
|
|
718
|
+
right: 0;
|
|
719
|
+
}
|
|
720
|
+
.column-menu label, .filter-menu label {
|
|
721
|
+
display: flex;
|
|
722
|
+
align-items: center;
|
|
723
|
+
gap: 8px;
|
|
724
|
+
cursor: pointer;
|
|
725
|
+
font-weight: normal;
|
|
726
|
+
white-space: nowrap;
|
|
727
|
+
padding: 2px 0;
|
|
728
|
+
}
|
|
729
|
+
.filter-search-container {
|
|
730
|
+
display: flex;
|
|
731
|
+
gap: 4px;
|
|
732
|
+
margin-bottom: 4px;
|
|
733
|
+
}
|
|
734
|
+
.filter-search {
|
|
735
|
+
width: 100%;
|
|
736
|
+
padding: 4px;
|
|
737
|
+
border-radius: 4px;
|
|
738
|
+
flex-grow: 1;
|
|
739
|
+
}
|
|
740
|
+
.filter-sort-btn {
|
|
741
|
+
padding: 4px 8px;
|
|
742
|
+
cursor: pointer;
|
|
743
|
+
font-size: 0.8em;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.data-cell { cursor: pointer; }
|
|
747
|
+
.data-cell.selected { background-color: #aedcff; }
|
|
748
|
+
.data-cell a { color: #007bff; text-decoration: none; }
|
|
749
|
+
.data-cell a:hover { text-decoration: underline; }
|
|
750
|
+
|
|
751
|
+
.header-cell.reorderable { cursor: grab; }
|
|
752
|
+
.header-cell.drag-over { background-color: #cceeff; }
|
|
753
|
+
|
|
754
|
+
.grid-body .grid-row:nth-of-type(even) { background-color: #f2f2f2; }
|
|
755
|
+
.grid-body .grid-row:hover { background-color: #e0e0e0; }
|
|
756
|
+
|
|
757
|
+
.pagination {
|
|
758
|
+
display: flex;
|
|
759
|
+
justify-content: space-between;
|
|
760
|
+
align-items: center;
|
|
761
|
+
padding: 12px 0;
|
|
762
|
+
font-size: 0.9em;
|
|
763
|
+
color: #000;
|
|
764
|
+
}
|
|
765
|
+
.pagination-group { display: flex; gap: 8px; }
|
|
766
|
+
.pagination button { padding: 6px 12px; border-radius: 4px; background-color: #f8f8f8; cursor: pointer; }
|
|
767
|
+
.pagination button:disabled { cursor: not-allowed; opacity: 0.5; }
|
|
768
|
+
|
|
769
|
+
.resize-handle {
|
|
770
|
+
position: absolute;
|
|
771
|
+
top: 0;
|
|
772
|
+
right: 0;
|
|
773
|
+
width: 5px;
|
|
774
|
+
height: 100%;
|
|
775
|
+
cursor: col-resize;
|
|
776
|
+
z-index: 1;
|
|
777
|
+
}
|
|
778
|
+
.resize-handle:hover {
|
|
779
|
+
background-color: #007bff;
|
|
780
|
+
}
|
|
781
|
+
`; }
|
|
782
|
+
};
|
|
783
|
+
__decorate([
|
|
784
|
+
property({ type: Array })
|
|
785
|
+
], MyGrid.prototype, "columns", void 0);
|
|
786
|
+
__decorate([
|
|
787
|
+
property({ type: Array })
|
|
788
|
+
], MyGrid.prototype, "data", void 0);
|
|
789
|
+
__decorate([
|
|
790
|
+
property({ type: Number })
|
|
791
|
+
], MyGrid.prototype, "itemsPerPage", void 0);
|
|
792
|
+
__decorate([
|
|
793
|
+
property({ type: Boolean })
|
|
794
|
+
], MyGrid.prototype, "columnReordering", void 0);
|
|
795
|
+
__decorate([
|
|
796
|
+
property({ type: String })
|
|
797
|
+
], MyGrid.prototype, "height", void 0);
|
|
798
|
+
__decorate([
|
|
799
|
+
property({ type: Boolean })
|
|
800
|
+
], MyGrid.prototype, "enableColumnVisibility", void 0);
|
|
801
|
+
__decorate([
|
|
802
|
+
property({ type: Boolean })
|
|
803
|
+
], MyGrid.prototype, "enableFilter", void 0);
|
|
804
|
+
__decorate([
|
|
805
|
+
property()
|
|
806
|
+
], MyGrid.prototype, "rowClass", void 0);
|
|
807
|
+
__decorate([
|
|
808
|
+
state()
|
|
809
|
+
], MyGrid.prototype, "_sortKey", void 0);
|
|
810
|
+
__decorate([
|
|
811
|
+
state()
|
|
812
|
+
], MyGrid.prototype, "_sortDirection", void 0);
|
|
813
|
+
__decorate([
|
|
814
|
+
state()
|
|
815
|
+
], MyGrid.prototype, "_draggedColumnIndex", void 0);
|
|
816
|
+
__decorate([
|
|
817
|
+
state()
|
|
818
|
+
], MyGrid.prototype, "_dragOverColumnIndex", void 0);
|
|
819
|
+
__decorate([
|
|
820
|
+
state()
|
|
821
|
+
], MyGrid.prototype, "_selectedRowId", void 0);
|
|
822
|
+
__decorate([
|
|
823
|
+
state()
|
|
824
|
+
], MyGrid.prototype, "_selectedColumnKey", void 0);
|
|
825
|
+
__decorate([
|
|
826
|
+
state()
|
|
827
|
+
], MyGrid.prototype, "_filterValues", void 0);
|
|
828
|
+
__decorate([
|
|
829
|
+
state()
|
|
830
|
+
], MyGrid.prototype, "_activeFilterColumn", void 0);
|
|
831
|
+
__decorate([
|
|
832
|
+
state()
|
|
833
|
+
], MyGrid.prototype, "_filterSearchTerm", void 0);
|
|
834
|
+
__decorate([
|
|
835
|
+
state()
|
|
836
|
+
], MyGrid.prototype, "_currentPage", void 0);
|
|
837
|
+
__decorate([
|
|
838
|
+
state()
|
|
839
|
+
], MyGrid.prototype, "_hiddenColumns", void 0);
|
|
840
|
+
__decorate([
|
|
841
|
+
state()
|
|
842
|
+
], MyGrid.prototype, "_showColumnMenu", void 0);
|
|
843
|
+
__decorate([
|
|
844
|
+
state()
|
|
845
|
+
], MyGrid.prototype, "_filterMenuSortDirection", void 0);
|
|
846
|
+
__decorate([
|
|
847
|
+
state()
|
|
848
|
+
], MyGrid.prototype, "_resizingColumnIndex", void 0);
|
|
849
|
+
MyGrid = __decorate([
|
|
850
|
+
customElement('my-grid')
|
|
851
|
+
], MyGrid);
|
|
852
|
+
export { MyGrid };
|