@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.
Files changed (48) hide show
  1. package/dist/components/Banner.d.ts +1 -1
  2. package/dist/components/dialog/dialog.d.ts +2 -1
  3. package/dist/components/pagination/pagination.d.ts +1 -1
  4. package/dist/components/query_bar/QueryBar.d.ts +31 -11
  5. package/dist/components/query_bar/dateTimePopup.d.ts +2 -0
  6. package/dist/components/query_bar/geojsonPopup.d.ts +2 -0
  7. package/dist/components/query_bar/querylanguage/kuery/functions/geospatial.d.ts +19 -0
  8. package/dist/components/query_bar/querylanguage/outputTypes/toCQL.d.ts +2 -1
  9. package/dist/components/query_bar/querylanguage/outputTypes/toMongo.d.ts +6 -1
  10. package/dist/components/symbols.d.ts +6 -0
  11. package/dist/components/table/cell.d.ts +2 -2
  12. package/dist/components/table/header.d.ts +2 -1
  13. package/dist/components/table/table.d.ts +14 -7
  14. package/dist/custom-elements.json +8 -8
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.es.js +4556 -2834
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.umd.js +424 -248
  19. package/dist/index.umd.js.map +1 -1
  20. package/dist/style.css +1 -1
  21. package/package.json +6 -1
  22. package/src/components/Banner.ts +46 -31
  23. package/src/components/dialog/dialog.css.ts +29 -29
  24. package/src/components/dialog/dialog.ts +165 -135
  25. package/src/components/input.ts +49 -39
  26. package/src/components/pagination/pagination.ts +167 -113
  27. package/src/components/query_bar/QueryBar.ts +441 -185
  28. package/src/components/query_bar/dateTimePopup.ts +54 -0
  29. package/src/components/query_bar/geojsonPopup.ts +44 -0
  30. package/src/components/query_bar/querylanguage/kuery/ast/_generated_/kuery.js +1836 -2745
  31. package/src/components/query_bar/querylanguage/kuery/ast/ast.ts +15 -13
  32. package/src/components/query_bar/querylanguage/kuery/ast/kuery.peg +92 -126
  33. package/src/components/query_bar/querylanguage/kuery/functions/geospatial.ts +25 -0
  34. package/src/components/query_bar/querylanguage/kuery/functions/index.ts +9 -7
  35. package/src/components/query_bar/querylanguage/outputTypes/toCQL.ts +56 -34
  36. package/src/components/query_bar/querylanguage/outputTypes/toMongo.ts +46 -34
  37. package/src/components/symbols.ts +6 -0
  38. package/src/components/table/__tests__/table.spec.ts +143 -55
  39. package/src/components/table/cell.ts +188 -145
  40. package/src/components/table/header.ts +163 -152
  41. package/src/components/table/table.css +4 -2
  42. package/src/components/table/table.ts +415 -262
  43. package/src/components/table/virtualBody.ts +170 -115
  44. package/src/components/tooltip/popover.ts +263 -225
  45. package/src/stories/Dialog.stories.ts +59 -0
  46. package/src/stories/QueryBar.stories.ts +46 -37
  47. package/src/stories/fixtures/data.ts +195 -36
  48. package/src/stories/table.stories.ts +70 -22
@@ -1,315 +1,468 @@
1
- import { html, LitElement, PropertyValues, render, TemplateResult } from 'lit';
1
+ import { html, LitElement, PropertyValues, TemplateResult } from "lit";
2
2
  import "../pagination";
3
- import "./header"
4
- import "./body"
5
- import { customElement, property, state, } from 'lit/decorators.js';
6
- import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
7
- import "./virtualBody"
8
- import "./table.css"
9
- export const TableElementTag = "spectric-table"
10
- import { spreadProps } from '../../utils/spread';
11
- import { PaginationChangeProps, PaginationProps } from '../pagination';
12
- import { FilterEvent } from './cell';
13
- import { createSortChain } from './sorting';
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 = HTMLElement | TemplateResult | string | number | null
20
+ export type DomRenderable =
21
+ | HTMLElement
22
+ | TemplateResult
23
+ | string
24
+ | number
25
+ | null
26
+ | undefined;
18
27
  export enum TableSelectOptions {
19
- multi = "multi",
20
- single = "single",
21
- none = "none"
28
+ multi = "multi",
29
+ single = "single",
30
+ none = "none",
22
31
  }
23
32
 
24
33
  export enum TableSortOption {
25
- multi = "multi",
26
- single = "single",
34
+ multi = "multi",
35
+ single = "single",
27
36
  }
28
- export type TableSortOptionTypes = `${TableSortOption}`
37
+ export type TableSortOptionTypes = `${TableSortOption}`;
29
38
  export enum TableSortDirection {
30
- ascending = "ascending",
31
- descending = "descending",
32
- none = "none"
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
- [TABLE_CREATED_SELECTION_COLUMN]?: boolean
37
- width?: number
38
- /**
39
- * Enabled/disables resizing by dragging column header Default true
40
- */
41
- allowResize?: boolean
42
- whiteSpace?: "nowrap";
43
- hidden?: boolean
44
- sortable?: boolean
45
- sortDirection?: TableSortDirectionTypes
46
- filterable?: boolean
47
- title?: DomRenderable
48
- /**
49
- * Key to used for getting data from an object for a cell
50
- */
51
- key?: string
52
- /**
53
- * Render function to render a table cell for displaying custom html
54
- */
55
- render?: (row: T, index: number, table: SpectricTableElement<T>) => DomRenderable
56
- /**
57
- * Custom comparator function for sorting
58
- */
59
- compareFn?: ((a: T, b: T) => number) | undefined
60
- }
61
- export type TableSelectOptionsTypes = `${TableSelectOptions}`
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
- pagination?: PaginationProps
64
- columns: ColumnSettings<T>[]
65
- sortOrder?: string[]
77
+ pagination?: PaginationProps;
78
+ columns: ColumnSettings<T>[];
79
+ sortOrder?: string[];
66
80
  }
67
81
  interface TableProps<T> extends TableDataOptions<T> {
68
- data: T[]
69
- select: TableSelectOptionsTypes
70
- sort?: TableSortOptionTypes
71
- rowHeight?: number
82
+ data: T[];
83
+ select: TableSelectOptionsTypes;
84
+ sort?: TableSortOptionTypes;
85
+ rowHeight?: number;
72
86
  }
73
87
 
74
88
  export type DomEvent<T> = Event & {
75
- target: T
76
- }
89
+ target: T;
90
+ };
77
91
 
78
92
  export const TD_BorderAndPadding = 4;
79
- const TABLE_CREATED_SELECTION_COLUMN = Symbol("spectric-table-selection-column")
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> extends LitElement implements TableProps<T> {
87
- @property({ type: Array, attribute: false })
88
- data: T[] = [];
89
- @property({ type: Object, attribute: false })
90
- pagination?: PaginationProps;
91
- @property({ attribute: false })
92
- columns: ColumnSettings<T>[] = [];
93
- @property({ type: String, reflect: true })
94
- select: TableSelectOptionsTypes = TableSelectOptions.none;
95
- @property({ type: String, reflect: true })
96
- sort: TableSortOptionTypes = TableSortOption.single;
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
- @property({ type: Array, reflect: false })
99
- sortOrder: string[] = [];
100
- /**
101
- * Needed for virtualization
102
- */
103
- @property({ type: Number, reflect: true })
104
- rowHeight: number = 25;
105
- /**
106
- * Needed for virtualization
107
- */
108
- @property({ type: Number, reflect: true })
109
- fontSize: number = 16;
110
-
111
- static getDefaultDataSorterAndPaginatior<T>(data: T[]) {
112
- return (props: TableDataOptions<T>) => {
113
- //let sorts = props.columns.filter(column => column.sortable && column.sortDirection && column.sortDirection !== TableSortDirection.none)
114
- let sorts = (props.sortOrder || []).map(key => props.columns.find(col => col.key === key) as ColumnSettings<T>)
115
- let rows = [...data] // Need to copy the array to prevent mutating the ordering of the original data
116
- if (sorts.length) {
117
- let sortChain = createSortChain(sorts)
118
- rows.sort((a, b) => {
119
- for (let sort of sortChain) {
120
- let result = sort(a, b)
121
- if (result) {
122
- return result
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
- if (!props.pagination) {
130
- return rows
131
- }
132
- let { page, pageSize } = props.pagination
133
- if (!page || !pageSize) {
134
- return rows
135
- }
136
- return !props.pagination ? rows : rows.slice((page - 1) * pageSize, (page) * pageSize)
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
- private _handlePaginationChange = (e: CustomEvent<PaginationChangeProps>) => {
141
- if (this.pagination) {
142
- let pagination = { ...this.pagination, ...e.detail }
163
+ private _handlePaginationChange = (e: CustomEvent<PaginationChangeProps>) => {
164
+ if (this.pagination) {
165
+ let pagination = { ...this.pagination, ...e.detail };
143
166
 
144
- let { totalItems, page, pageSize } = pagination
145
- if (totalItems && page && pageSize && ((page - 1) * pageSize) > totalItems) {
146
- pagination.page = 1
147
- }
148
- this.pagination = pagination
149
- }
150
- this.dispatchEvent(new CustomEvent<PaginationChangeProps>("paginationChange", { detail: e.detail }))
151
- this._emitChange()
152
- };
153
- private _handleSortChange = (e: CustomEvent<ColumnSettings<T>>) => {
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
- private _handleColumnResize = (e: CustomEvent<ColumnSettings<T>>) => {
183
- let columnSetting = e.detail
184
- let index = this.columns.findIndex(col => col.key == columnSetting.key)
185
- this.columns[index] = { ...this.columns[index] }
186
- this.columns = [...this.columns]
187
- this._emitChange()
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
- private _emitChange = () => {
191
- let { pagination, columns, sortOrder } = this
192
- this.dispatchEvent(new CustomEvent<TableDataOptions<T>>("change", { detail: { pagination, columns, sortOrder } }))
193
- }
194
- //@ts-ignore
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
- @state()
201
- private selected: T[] = [];
202
- protected createRenderRoot(): HTMLElement | DocumentFragment {
203
- return this
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
- deselectAll() {
206
- this.selected = []
207
- this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }))
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
- selectAll() {
210
- this.selected = [...this.data]
211
- this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }))
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
- _handleSelectAllChange = (e: DomEvent<HTMLInputElement>) => {
214
- e.stopPropagation()
215
- if (e.target.checked) {
216
- this.selectAll()
217
- } else {
218
- this.deselectAll()
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
- protected update(changedProperties: PropertyValues): void {
222
- if (changedProperties.has("columns")) {
223
- if (this.select !== TableSelectOptions.none) {
224
- if (!this.columns.find(col => col[TABLE_CREATED_SELECTION_COLUMN])) {
225
- this.columns.unshift({
226
- [TABLE_CREATED_SELECTION_COLUMN]: true,
227
- title: this.select === "multi" ? html`<spectric-input variant="checkbox" @change=${this._handleSelectAllChange} .helperText=${"Select All"}></spectric-input>` : null,
228
- render: (row) => {
229
- let container = document.createElement("div")
230
- let checked = this.selected.includes(row)
231
- let template = html`<spectric-input variant="checkbox" class="table-checkbox-${this.select}" .helperText=${""} ${spreadProps({ checked })} @change=${(e: DomEvent<HTMLInputElement>) => {
232
- e.stopPropagation()
233
- let index = this.selected.findIndex(value => value === row)
234
- if (e.target.checked && index !== -1) {
235
- return
236
- }
237
- else if (!e.target.checked && index === -1) {
238
- return
239
- }
240
- else if (!e.target.checked && index !== -1) {
241
- this.selected.splice(index, 1)
242
- }
243
- if (e.target.checked) {
244
- if (this.select === "single") {
245
- this.selected = []
246
- }
247
- this.selected.push(row)
248
- }
249
- this.dispatchEvent(new CustomEvent("selected", { detail: [...this.selected] }))
250
- }}></spectric-input>`
251
- render(template, container)
252
- return template
253
- }
254
- })
255
- }
256
- }
257
- }
258
- if (changedProperties.has("select")) {
259
- if (this.select === "single" && this.selected.length > 1) {
260
- this.selected = [this.selected[0]]
261
- this.dispatchEvent(new CustomEvent("selected", { detail: [...this.selected] }))
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
- super.update(changedProperties)
373
+ return a;
374
+ }, [] as T[]);
265
375
  }
266
- protected render(): unknown {
267
- let columns = this.columns.filter(column => !column.hidden)
268
- let rowHeight = this.rowHeight - TD_BorderAndPadding;
269
- if (rowHeight < this.fontSize + TD_BorderAndPadding) {
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
- return html`
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
- 'change': (event: CustomEvent<TableDataOptions<any>>) => void;
286
- 'paginationChange': (event: CustomEvent<PaginationChangeProps>) => void;
287
- 'filter': (event: CustomEvent<FilterEvent<any>>) => void;
288
- 'sortChange': (event: CustomEvent<ColumnSettings<any>>) => void;
289
- 'selected': (event: CustomEvent<any[]>) => void;
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
- interface HTMLElementTagNameMap {
294
- [TableElementTag]: HTMLElementTagWithEvents<SpectricTableElement<any>, TableEvents>
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
- interface IntrinsicElements {
299
- /**
300
- * @see {@link TableElement}
301
- */
302
- [TableElementTag]: ReactElementWithPropsAndEvents<SpectricTableElement<any>, TableProps<any>, TableEvents>;
303
- }
304
- }
305
- namespace React {
306
- namespace JSX {
307
- interface IntrinsicElements {
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
  }