@spectric/ui 0.0.20 → 0.0.22
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/components/Banner.d.ts +1 -1
- package/dist/components/dialog/dialog.d.ts +2 -1
- package/dist/components/pagination/pagination.d.ts +1 -1
- package/dist/components/query_bar/QueryBar.d.ts +31 -11
- package/dist/components/query_bar/dateTimePopup.d.ts +2 -0
- package/dist/components/query_bar/geojsonPopup.d.ts +2 -0
- package/dist/components/query_bar/querylanguage/kuery/functions/geospatial.d.ts +19 -0
- package/dist/components/query_bar/querylanguage/outputTypes/toCQL.d.ts +2 -1
- package/dist/components/query_bar/querylanguage/outputTypes/toMongo.d.ts +6 -1
- package/dist/components/symbols.d.ts +6 -0
- package/dist/components/table/cell.d.ts +2 -2
- package/dist/components/table/header.d.ts +2 -1
- package/dist/components/table/table.d.ts +14 -7
- package/dist/custom-elements.json +8 -8
- package/dist/index.d.ts +4 -0
- package/dist/index.es.js +4556 -2834
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +424 -248
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +6 -1
- package/src/components/Banner.ts +46 -31
- package/src/components/dialog/dialog.css.ts +29 -29
- package/src/components/dialog/dialog.ts +165 -135
- package/src/components/input.ts +49 -39
- package/src/components/pagination/pagination.ts +167 -113
- package/src/components/query_bar/QueryBar.ts +441 -185
- package/src/components/query_bar/dateTimePopup.ts +54 -0
- package/src/components/query_bar/geojsonPopup.ts +44 -0
- package/src/components/query_bar/querylanguage/kuery/ast/_generated_/kuery.js +1836 -2745
- package/src/components/query_bar/querylanguage/kuery/ast/ast.ts +15 -13
- package/src/components/query_bar/querylanguage/kuery/ast/kuery.peg +92 -126
- package/src/components/query_bar/querylanguage/kuery/functions/geospatial.ts +25 -0
- package/src/components/query_bar/querylanguage/kuery/functions/index.ts +9 -7
- package/src/components/query_bar/querylanguage/outputTypes/toCQL.ts +56 -34
- package/src/components/query_bar/querylanguage/outputTypes/toMongo.ts +46 -34
- package/src/components/symbols.ts +6 -0
- package/src/components/table/__tests__/table.spec.ts +143 -55
- package/src/components/table/cell.ts +188 -145
- package/src/components/table/header.ts +163 -152
- package/src/components/table/table.css +4 -2
- package/src/components/table/table.ts +415 -262
- package/src/components/table/virtualBody.ts +170 -115
- package/src/components/tooltip/popover.ts +263 -225
- package/src/stories/Dialog.stories.ts +59 -0
- package/src/stories/QueryBar.stories.ts +46 -37
- package/src/stories/fixtures/data.ts +195 -36
- package/src/stories/table.stories.ts +70 -22
|
@@ -1,315 +1,468 @@
|
|
|
1
|
-
import { html, LitElement, PropertyValues,
|
|
1
|
+
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
|
2
2
|
import "../pagination";
|
|
3
|
-
import "./header"
|
|
4
|
-
import "./body"
|
|
5
|
-
import { customElement, property, state
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import {
|
|
3
|
+
import "./header";
|
|
4
|
+
import "./body";
|
|
5
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
6
|
+
import {
|
|
7
|
+
HTMLElementTagWithEvents,
|
|
8
|
+
ReactElementWithPropsAndEvents,
|
|
9
|
+
} from "../types";
|
|
10
|
+
import "./virtualBody";
|
|
11
|
+
import "./table.css";
|
|
12
|
+
export const TableElementTag = "spectric-table";
|
|
13
|
+
import { spreadProps } from "../../utils/spread";
|
|
14
|
+
import { PaginationChangeProps, PaginationProps } from "../pagination";
|
|
15
|
+
import { FilterEvent } from "./cell";
|
|
16
|
+
import { createSortChain } from "./sorting";
|
|
14
17
|
|
|
15
|
-
export type { TableProps, TableEvents }
|
|
18
|
+
export type { TableProps, TableEvents };
|
|
16
19
|
|
|
17
|
-
export type DomRenderable =
|
|
20
|
+
export type DomRenderable =
|
|
21
|
+
| HTMLElement
|
|
22
|
+
| TemplateResult
|
|
23
|
+
| string
|
|
24
|
+
| number
|
|
25
|
+
| null
|
|
26
|
+
| undefined;
|
|
18
27
|
export enum TableSelectOptions {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
multi = "multi",
|
|
29
|
+
single = "single",
|
|
30
|
+
none = "none",
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
export enum TableSortOption {
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
multi = "multi",
|
|
35
|
+
single = "single",
|
|
27
36
|
}
|
|
28
|
-
export type TableSortOptionTypes = `${TableSortOption}
|
|
37
|
+
export type TableSortOptionTypes = `${TableSortOption}`;
|
|
29
38
|
export enum TableSortDirection {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
ascending = "ascending",
|
|
40
|
+
descending = "descending",
|
|
41
|
+
none = "none",
|
|
33
42
|
}
|
|
34
|
-
export type TableSortDirectionTypes = `${TableSortDirection}
|
|
43
|
+
export type TableSortDirectionTypes = `${TableSortDirection}`;
|
|
35
44
|
export type ColumnSettings<T> = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
[TABLE_CREATED_SELECTION_COLUMN]?: boolean;
|
|
46
|
+
width?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Enabled/disables resizing by dragging column header Default true
|
|
49
|
+
*/
|
|
50
|
+
allowResize?: boolean;
|
|
51
|
+
whiteSpace?: "nowrap";
|
|
52
|
+
hidden?: boolean;
|
|
53
|
+
sortable?: boolean;
|
|
54
|
+
sortDirection?: TableSortDirectionTypes;
|
|
55
|
+
filterable?: boolean;
|
|
56
|
+
disableCellOverflowTooltip?: boolean;
|
|
57
|
+
title?: DomRenderable | ((table: SpectricTableElement<T>) => DomRenderable);
|
|
58
|
+
/**
|
|
59
|
+
* Key to used for getting data from an object for a cell
|
|
60
|
+
*/
|
|
61
|
+
key?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Render function to render a table cell for displaying custom html
|
|
64
|
+
*/
|
|
65
|
+
render?: (
|
|
66
|
+
row: T,
|
|
67
|
+
index: number,
|
|
68
|
+
table: SpectricTableElement<T>
|
|
69
|
+
) => DomRenderable;
|
|
70
|
+
/**
|
|
71
|
+
* Custom comparator function for sorting
|
|
72
|
+
*/
|
|
73
|
+
compareFn?: ((a: T, b: T) => number) | undefined;
|
|
74
|
+
};
|
|
75
|
+
export type TableSelectOptionsTypes = `${TableSelectOptions}`;
|
|
62
76
|
export interface TableDataOptions<T> {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
pagination?: PaginationProps;
|
|
78
|
+
columns: ColumnSettings<T>[];
|
|
79
|
+
sortOrder?: string[];
|
|
66
80
|
}
|
|
67
81
|
interface TableProps<T> extends TableDataOptions<T> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
data: T[];
|
|
83
|
+
select: TableSelectOptionsTypes;
|
|
84
|
+
sort?: TableSortOptionTypes;
|
|
85
|
+
rowHeight?: number;
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
export type DomEvent<T> = Event & {
|
|
75
|
-
|
|
76
|
-
}
|
|
89
|
+
target: T;
|
|
90
|
+
};
|
|
77
91
|
|
|
78
92
|
export const TD_BorderAndPadding = 4;
|
|
79
|
-
const TABLE_CREATED_SELECTION_COLUMN = Symbol(
|
|
93
|
+
const TABLE_CREATED_SELECTION_COLUMN = Symbol(
|
|
94
|
+
"spectric-table-selection-column"
|
|
95
|
+
);
|
|
80
96
|
/**
|
|
81
97
|
* React example
|
|
82
98
|
* <iframe width="100%" height="400px" src="https://stackblitz.com/edit/react-ts-2ue7azag?ctl=1&embed=1&file=App.tsx&hideExplorer=1&hideNavigation=1"/>
|
|
83
99
|
*
|
|
84
100
|
*/
|
|
85
101
|
@customElement(TableElementTag)
|
|
86
|
-
export class SpectricTableElement<T = any>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
export class SpectricTableElement<T = any>
|
|
103
|
+
extends LitElement
|
|
104
|
+
implements TableProps<T>
|
|
105
|
+
{
|
|
106
|
+
@property({ type: Array, attribute: false })
|
|
107
|
+
data: T[] = [];
|
|
108
|
+
@property({ type: Object, attribute: false })
|
|
109
|
+
pagination?: PaginationProps;
|
|
110
|
+
@property({ attribute: false })
|
|
111
|
+
columns: ColumnSettings<T>[] = [];
|
|
112
|
+
@property({ type: String, reflect: true })
|
|
113
|
+
select: TableSelectOptionsTypes = TableSelectOptions.none;
|
|
114
|
+
@property({ type: String, reflect: true })
|
|
115
|
+
sort: TableSortOptionTypes = TableSortOption.single;
|
|
97
116
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return 0
|
|
126
|
-
})
|
|
117
|
+
@property({ type: Array, reflect: false })
|
|
118
|
+
sortOrder: string[] = [];
|
|
119
|
+
/**
|
|
120
|
+
* Needed for virtualization
|
|
121
|
+
*/
|
|
122
|
+
@property({ type: Number, reflect: true })
|
|
123
|
+
rowHeight: number = 25;
|
|
124
|
+
/**
|
|
125
|
+
* Needed for virtualization
|
|
126
|
+
*/
|
|
127
|
+
@property({ type: Number, reflect: true })
|
|
128
|
+
fontSize: number = 16;
|
|
129
|
+
static getDefaultDataSorterAndPaginatior<T>(data: T[]) {
|
|
130
|
+
return (props: TableDataOptions<T>) => {
|
|
131
|
+
//let sorts = props.columns.filter(column => column.sortable && column.sortDirection && column.sortDirection !== TableSortDirection.none)
|
|
132
|
+
let sorts = (props.sortOrder || []).map(
|
|
133
|
+
(key) =>
|
|
134
|
+
props.columns.find((col) => col.key === key) as ColumnSettings<T>
|
|
135
|
+
);
|
|
136
|
+
let rows = [...data]; // Need to copy the array to prevent mutating the ordering of the original data
|
|
137
|
+
if (sorts.length) {
|
|
138
|
+
let sortChain = createSortChain(sorts);
|
|
139
|
+
rows.sort((a, b) => {
|
|
140
|
+
for (let sort of sortChain) {
|
|
141
|
+
let result = sort(a, b);
|
|
142
|
+
if (result) {
|
|
143
|
+
return result;
|
|
127
144
|
}
|
|
145
|
+
}
|
|
146
|
+
return 0;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
128
149
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
150
|
+
if (!props.pagination) {
|
|
151
|
+
return rows;
|
|
152
|
+
}
|
|
153
|
+
let { page, pageSize } = props.pagination;
|
|
154
|
+
if (!page || !pageSize) {
|
|
155
|
+
return rows;
|
|
156
|
+
}
|
|
157
|
+
return !props.pagination
|
|
158
|
+
? rows
|
|
159
|
+
: rows.slice((page - 1) * pageSize, page * pageSize);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
139
162
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
163
|
+
private _handlePaginationChange = (e: CustomEvent<PaginationChangeProps>) => {
|
|
164
|
+
if (this.pagination) {
|
|
165
|
+
let pagination = { ...this.pagination, ...e.detail };
|
|
143
166
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let columnSetting = e.detail
|
|
155
|
-
let column = this.columns.find(col => col.key == columnSetting.key)
|
|
156
|
-
if (!column || column.key === undefined) {
|
|
157
|
-
console.warn("Unable to find sort column")
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
if (this.sort == TableSortOption.single) {
|
|
161
|
-
//Single column sort so we reset the sort direction for all columns
|
|
162
|
-
this.columns.forEach(col => {
|
|
163
|
-
col.sortDirection = TableSortDirection.none
|
|
164
|
-
})
|
|
165
|
-
this.sortOrder = []
|
|
166
|
-
}
|
|
167
|
-
column.sortDirection = columnSetting.sortDirection;
|
|
168
|
-
if (!column.sortDirection || column.sortDirection === "none") {
|
|
169
|
-
let index = this.sortOrder.findIndex(col => col === column.key)
|
|
170
|
-
if (index !== -1) {
|
|
171
|
-
this.sortOrder.splice(index, 1)
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
let index = this.sortOrder.findIndex(col => col === column.key)
|
|
175
|
-
if (index === -1) {
|
|
176
|
-
this.sortOrder = [...this.sortOrder, column.key]
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
this.columns = [...this.columns]
|
|
180
|
-
this._emitChange()
|
|
167
|
+
let { totalItems, page, pageSize } = pagination;
|
|
168
|
+
if (
|
|
169
|
+
totalItems &&
|
|
170
|
+
page &&
|
|
171
|
+
pageSize &&
|
|
172
|
+
(page - 1) * pageSize > totalItems
|
|
173
|
+
) {
|
|
174
|
+
pagination.page = 1;
|
|
175
|
+
}
|
|
176
|
+
this.pagination = pagination;
|
|
181
177
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
178
|
+
this.dispatchEvent(
|
|
179
|
+
new CustomEvent<PaginationChangeProps>("paginationChange", {
|
|
180
|
+
detail: e.detail,
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
this._emitChange();
|
|
184
|
+
};
|
|
185
|
+
private _handleSortChange = (e: CustomEvent<ColumnSettings<T>>) => {
|
|
186
|
+
let columnSetting = e.detail;
|
|
187
|
+
let column = this.columns.find((col) => col.key == columnSetting.key);
|
|
188
|
+
if (!column || column.key === undefined) {
|
|
189
|
+
console.warn("Unable to find sort column");
|
|
190
|
+
return;
|
|
188
191
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
private __DO_NOT_USE_filter = () => {
|
|
196
|
-
//This is only here to auto document events that bubble up from lower components
|
|
197
|
-
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter"))
|
|
198
|
-
this.dispatchEvent(new CustomEvent<ColumnSettings<T>>("sortChange"))
|
|
192
|
+
if (this.sort == TableSortOption.single) {
|
|
193
|
+
//Single column sort so we reset the sort direction for all columns
|
|
194
|
+
this.columns.forEach((col) => {
|
|
195
|
+
col.sortDirection = TableSortDirection.none;
|
|
196
|
+
});
|
|
197
|
+
this.sortOrder = [];
|
|
199
198
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
column.sortDirection = columnSetting.sortDirection;
|
|
200
|
+
if (!column.sortDirection || column.sortDirection === "none") {
|
|
201
|
+
let index = this.sortOrder.findIndex((col) => col === column.key);
|
|
202
|
+
if (index !== -1) {
|
|
203
|
+
this.sortOrder.splice(index, 1);
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
let index = this.sortOrder.findIndex((col) => col === column.key);
|
|
207
|
+
if (index === -1) {
|
|
208
|
+
this.sortOrder = [...this.sortOrder, column.key];
|
|
209
|
+
}
|
|
204
210
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
211
|
+
this.columns = [...this.columns];
|
|
212
|
+
this._emitChange();
|
|
213
|
+
};
|
|
214
|
+
private _handleColumnResize = (e: CustomEvent<ColumnSettings<T>>) => {
|
|
215
|
+
let columnSetting = e.detail;
|
|
216
|
+
let index = this.columns.findIndex((col) => col.key == columnSetting.key);
|
|
217
|
+
this.columns[index] = { ...this.columns[index] };
|
|
218
|
+
this.columns = [...this.columns];
|
|
219
|
+
this._emitChange();
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
private _emitChange = () => {
|
|
223
|
+
let { pagination, columns, sortOrder } = this;
|
|
224
|
+
this.dispatchEvent(
|
|
225
|
+
new CustomEvent<TableDataOptions<T>>("change", {
|
|
226
|
+
detail: { pagination, columns, sortOrder },
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
//@ts-ignore
|
|
231
|
+
private __DO_NOT_USE_filter = () => {
|
|
232
|
+
//This is only here to auto document events that bubble up from lower components
|
|
233
|
+
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter"));
|
|
234
|
+
this.dispatchEvent(new CustomEvent<ColumnSettings<T>>("sortChange"));
|
|
235
|
+
};
|
|
236
|
+
@state()
|
|
237
|
+
private selected: T[] = [];
|
|
238
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
private forceRefreshofSelectionColumn() {
|
|
242
|
+
// Because lit reuses dom elements for speed/effeciency it wont update unless the props are a different object.
|
|
243
|
+
// So we set the selection colum to a "new object" to force the rerender
|
|
244
|
+
let index = this.columns.findIndex(
|
|
245
|
+
(col) => col[TABLE_CREATED_SELECTION_COLUMN]
|
|
246
|
+
);
|
|
247
|
+
if (index !== -1) {
|
|
248
|
+
this.columns[index] = { ...this.selectColumnConfig };
|
|
208
249
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
250
|
+
}
|
|
251
|
+
setSelected(selected: T[]) {
|
|
252
|
+
this.selected = selected;
|
|
253
|
+
this.forceRefreshofSelectionColumn();
|
|
254
|
+
}
|
|
255
|
+
getSelected() {
|
|
256
|
+
return this.selected;
|
|
257
|
+
}
|
|
258
|
+
deselectAll() {
|
|
259
|
+
this.selected = [];
|
|
260
|
+
this.forceRefreshofSelectionColumn();
|
|
261
|
+
this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }));
|
|
262
|
+
}
|
|
263
|
+
selectAll() {
|
|
264
|
+
this.selected = [...this.data];
|
|
265
|
+
this.forceRefreshofSelectionColumn();
|
|
266
|
+
this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }));
|
|
267
|
+
}
|
|
268
|
+
async scrollToRow(row: T | number) {
|
|
269
|
+
let index: number = -1;
|
|
270
|
+
if (Number.isInteger(row)) {
|
|
271
|
+
index = row as number;
|
|
272
|
+
} else {
|
|
273
|
+
index = this.data.findIndex((value) => value === row);
|
|
212
274
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
275
|
+
if (index !== -1) {
|
|
276
|
+
let body = this.querySelector("spectric-table-virtual-body");
|
|
277
|
+
let wrapper = this.querySelector(".table-wrapper")!;
|
|
278
|
+
let scrollPosition = index * this._getRowHeight();
|
|
279
|
+
wrapper.scrollTo({
|
|
280
|
+
top: scrollPosition,
|
|
281
|
+
behavior: "smooth",
|
|
282
|
+
});
|
|
283
|
+
//Wait for the smooth scroll to complete. Scroll to doesn't return a promise so we must manually check periodically
|
|
284
|
+
for (let wait = 0; wait < 100; wait++) {
|
|
285
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
286
|
+
if (wrapper.scrollTop == scrollPosition) {
|
|
287
|
+
console.log("Scroll complete");
|
|
288
|
+
break;
|
|
219
289
|
}
|
|
290
|
+
}
|
|
291
|
+
if (body) {
|
|
292
|
+
//Highlight the row we scrolled to
|
|
293
|
+
requestAnimationFrame(() => {
|
|
294
|
+
let rows = [...body.querySelectorAll("tr")];
|
|
295
|
+
rows = rows.filter(
|
|
296
|
+
(row) => row.querySelector("spectric-table-cell")?.index === index
|
|
297
|
+
);
|
|
298
|
+
if (rows.length) {
|
|
299
|
+
rows[0].animate(
|
|
300
|
+
[{ backgroundColor: "red" }, { backgroundColor: "unset" }],
|
|
301
|
+
{ duration: 200, iterations: 5 }
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
220
306
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
307
|
+
}
|
|
308
|
+
_getRowHeight = () => {
|
|
309
|
+
let rowHeight = this.rowHeight - TD_BorderAndPadding;
|
|
310
|
+
if (rowHeight < this.fontSize + TD_BorderAndPadding) {
|
|
311
|
+
rowHeight = this.fontSize + TD_BorderAndPadding;
|
|
312
|
+
}
|
|
313
|
+
return rowHeight;
|
|
314
|
+
};
|
|
315
|
+
_handleSelectAllChange = (e: DomEvent<HTMLInputElement>) => {
|
|
316
|
+
e.stopPropagation();
|
|
317
|
+
if (e.target.checked) {
|
|
318
|
+
this.selectAll();
|
|
319
|
+
} else {
|
|
320
|
+
this.deselectAll();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
private selectColumnConfig: ColumnSettings<T> = {
|
|
324
|
+
[TABLE_CREATED_SELECTION_COLUMN]: true,
|
|
325
|
+
width: 39,
|
|
326
|
+
title: (table) => {
|
|
327
|
+
return table.select === "multi"
|
|
328
|
+
? html`<spectric-input
|
|
329
|
+
variant="checkbox"
|
|
330
|
+
@change=${table._handleSelectAllChange}
|
|
331
|
+
.helperText=${"Select All"}
|
|
332
|
+
></spectric-input>`
|
|
333
|
+
: null;
|
|
334
|
+
},
|
|
335
|
+
render: (row: T, _index, table) => {
|
|
336
|
+
let checked = table.selected.includes(row);
|
|
337
|
+
let template = html`<spectric-input
|
|
338
|
+
variant="checkbox"
|
|
339
|
+
class="table-checkbox-${table.select}"
|
|
340
|
+
.helperText=${""}
|
|
341
|
+
${spreadProps({ checked })}
|
|
342
|
+
@change=${(e: DomEvent<HTMLInputElement>) => {
|
|
343
|
+
e.stopPropagation();
|
|
344
|
+
let index = table.selected.findIndex((value) => value === row);
|
|
345
|
+
if (e.target.checked && index !== -1) {
|
|
346
|
+
return;
|
|
347
|
+
} else if (!e.target.checked && index === -1) {
|
|
348
|
+
return;
|
|
349
|
+
} else if (!e.target.checked && index !== -1) {
|
|
350
|
+
table.selected.splice(index, 1);
|
|
351
|
+
}
|
|
352
|
+
if (e.target.checked) {
|
|
353
|
+
if (table.select === "single") {
|
|
354
|
+
table.selected = [];
|
|
355
|
+
table.forceRefreshofSelectionColumn();
|
|
262
356
|
}
|
|
357
|
+
table.selected.push(row);
|
|
358
|
+
}
|
|
359
|
+
table.dispatchEvent(
|
|
360
|
+
new CustomEvent("selected", { detail: [...table.selected] })
|
|
361
|
+
);
|
|
362
|
+
}}
|
|
363
|
+
></spectric-input>`;
|
|
364
|
+
return template;
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
protected update(changedProperties: PropertyValues): void {
|
|
368
|
+
if (changedProperties.has("data")) {
|
|
369
|
+
this.selected = this.data.reduce((a, row) => {
|
|
370
|
+
if (this.selected.includes(row)) {
|
|
371
|
+
a.push(row);
|
|
263
372
|
}
|
|
264
|
-
|
|
373
|
+
return a;
|
|
374
|
+
}, [] as T[]);
|
|
265
375
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
rowHeight = this.fontSize + TD_BorderAndPadding
|
|
376
|
+
if (changedProperties.has("columns")) {
|
|
377
|
+
if (this.select !== TableSelectOptions.none) {
|
|
378
|
+
if (!this.columns.find((col) => col[TABLE_CREATED_SELECTION_COLUMN])) {
|
|
379
|
+
this.columns.unshift(this.selectColumnConfig);
|
|
271
380
|
}
|
|
272
|
-
|
|
273
|
-
<div class="table-wrapper" style="--rowHeight:${rowHeight}px;--fontSize:${this.fontSize}px;--lineClamp:${Math.floor(rowHeight / this.fontSize)}">
|
|
274
|
-
<div role="table">
|
|
275
|
-
<spectric-table-header .columns=${columns} @sortChange=${this._handleSortChange} @columnResize=${this._handleColumnResize}></spectric-table-header>
|
|
276
|
-
<spectric-table-virtual-body .columns=${columns} .data=${this.data} .table=${this} .rowHeight=${rowHeight}></spectric-table-virtual-body>
|
|
277
|
-
</div>
|
|
278
|
-
</div>
|
|
279
|
-
${this.pagination ? html`<spectric-pagination ${spreadProps(this.pagination)} @change=${this._handlePaginationChange}></spectric-pagination>` : null}
|
|
280
|
-
`;
|
|
381
|
+
}
|
|
281
382
|
}
|
|
383
|
+
if (changedProperties.has("select")) {
|
|
384
|
+
if (this.select === "single" && this.selected.length > 1) {
|
|
385
|
+
this.selected = [this.selected[0]];
|
|
386
|
+
this.dispatchEvent(
|
|
387
|
+
new CustomEvent("selected", { detail: [...this.selected] })
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
super.update(changedProperties);
|
|
392
|
+
}
|
|
393
|
+
protected render(): unknown {
|
|
394
|
+
let columns = this.columns.filter((column) => !column.hidden);
|
|
395
|
+
let rowHeight = this._getRowHeight();
|
|
396
|
+
return html`
|
|
397
|
+
<div
|
|
398
|
+
class="table-wrapper"
|
|
399
|
+
style="--rowHeight:${rowHeight}px;--fontSize:${this
|
|
400
|
+
.fontSize}px;--lineClamp:${Math.floor(rowHeight / this.fontSize)}"
|
|
401
|
+
>
|
|
402
|
+
<div role="table">
|
|
403
|
+
<spectric-table-header
|
|
404
|
+
.columns=${columns}
|
|
405
|
+
.table=${this}
|
|
406
|
+
@sortChange=${this._handleSortChange}
|
|
407
|
+
@columnResize=${this._handleColumnResize}
|
|
408
|
+
></spectric-table-header>
|
|
409
|
+
<spectric-table-virtual-body
|
|
410
|
+
.columns=${columns}
|
|
411
|
+
.data=${this.data}
|
|
412
|
+
.table=${this}
|
|
413
|
+
.rowHeight=${rowHeight}
|
|
414
|
+
></spectric-table-virtual-body>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
${this.pagination
|
|
418
|
+
? html`<spectric-pagination
|
|
419
|
+
${spreadProps(this.pagination)}
|
|
420
|
+
@change=${this._handlePaginationChange}
|
|
421
|
+
></spectric-pagination>`
|
|
422
|
+
: null}
|
|
423
|
+
`;
|
|
424
|
+
}
|
|
282
425
|
}
|
|
283
426
|
|
|
284
427
|
interface TableEvents {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
428
|
+
change: (event: CustomEvent<TableDataOptions<any>>) => void;
|
|
429
|
+
paginationChange: (event: CustomEvent<PaginationChangeProps>) => void;
|
|
430
|
+
filter: (event: CustomEvent<FilterEvent<any>>) => void;
|
|
431
|
+
sortChange: (event: CustomEvent<ColumnSettings<any>>) => void;
|
|
432
|
+
selected: (event: CustomEvent<any[]>) => void;
|
|
290
433
|
}
|
|
291
434
|
|
|
292
435
|
declare global {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
436
|
+
interface HTMLElementTagNameMap {
|
|
437
|
+
[TableElementTag]: HTMLElementTagWithEvents<
|
|
438
|
+
SpectricTableElement<any>,
|
|
439
|
+
TableEvents
|
|
440
|
+
>;
|
|
441
|
+
}
|
|
442
|
+
namespace JSX {
|
|
443
|
+
interface IntrinsicElements {
|
|
444
|
+
/**
|
|
445
|
+
* @see {@link TableElement}
|
|
446
|
+
*/
|
|
447
|
+
[TableElementTag]: ReactElementWithPropsAndEvents<
|
|
448
|
+
SpectricTableElement<any>,
|
|
449
|
+
TableProps<any>,
|
|
450
|
+
TableEvents
|
|
451
|
+
>;
|
|
296
452
|
}
|
|
453
|
+
}
|
|
454
|
+
namespace React {
|
|
297
455
|
namespace JSX {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* @see {@link TableElement}
|
|
310
|
-
*/
|
|
311
|
-
[TableElementTag]: ReactElementWithPropsAndEvents<SpectricTableElement<any>, TableProps<any>, TableEvents>
|
|
312
|
-
}
|
|
313
|
-
}
|
|
456
|
+
interface IntrinsicElements {
|
|
457
|
+
/**
|
|
458
|
+
* @see {@link TableElement}
|
|
459
|
+
*/
|
|
460
|
+
[TableElementTag]: ReactElementWithPropsAndEvents<
|
|
461
|
+
SpectricTableElement<any>,
|
|
462
|
+
TableProps<any>,
|
|
463
|
+
TableEvents
|
|
464
|
+
>;
|
|
465
|
+
}
|
|
314
466
|
}
|
|
467
|
+
}
|
|
315
468
|
}
|