@spectric/ui 0.0.21 → 0.0.23
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/dialog/dialog.d.ts +1 -0
- package/dist/components/pagination/pagination.d.ts +1 -1
- package/dist/components/query_bar/QueryBar.d.ts +30 -10
- 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 +1 -1
- package/dist/components/table/table.d.ts +14 -1
- package/dist/custom-elements.json +6 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.es.js +4405 -2803
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +361 -252
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +6 -1
- package/src/components/dialog/dialog.css.ts +29 -29
- package/src/components/dialog/dialog.ts +3 -1
- package/src/components/input.css +5 -0
- package/src/components/input.ts +50 -41
- package/src/components/pagination/pagination.ts +167 -113
- package/src/components/query_bar/QueryBar.ts +438 -187
- 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 +2 -2
- package/src/components/table/cell.ts +28 -11
- package/src/components/table/header.ts +3 -2
- package/src/components/table/table.css +11 -4
- package/src/components/table/table.ts +75 -5
- package/src/components/table/virtualBody.ts +8 -3
- 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 +229 -37
- package/src/stories/table.stories.ts +77 -29
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @kbn/eslint/require-license-header */
|
|
2
|
-
import { FieldTypes, KueryNode } from
|
|
3
|
-
import { wildcardSymbol } from
|
|
2
|
+
import { FieldTypes, KueryNode } from "../..";
|
|
3
|
+
import { wildcardSymbol } from "../kuery/node_types/wildcard";
|
|
4
|
+
import { wktToGeoJSON } from "@terraformer/wkt";
|
|
4
5
|
|
|
5
6
|
export const KQL_WILDCARD_SYMBOL = wildcardSymbol;
|
|
6
|
-
export const KQL_NODE_TYPE_WILDCARD =
|
|
7
|
-
export type FunctionName =
|
|
7
|
+
export const KQL_NODE_TYPE_WILDCARD = "wildcard";
|
|
8
|
+
export type FunctionName =
|
|
9
|
+
| "is"
|
|
10
|
+
| "and"
|
|
11
|
+
| "or"
|
|
12
|
+
| "not"
|
|
13
|
+
| "range"
|
|
14
|
+
| "exists"
|
|
15
|
+
| "nested";
|
|
8
16
|
const and = (node: KueryNode) => {
|
|
9
17
|
const children = node.arguments || [];
|
|
10
|
-
let query: any = {
|
|
18
|
+
let query: any = { $and: children.map((c: KueryNode) => toMongo(c)) };
|
|
11
19
|
|
|
12
20
|
return query;
|
|
13
21
|
};
|
|
@@ -17,62 +25,65 @@ const is = (node: KueryNode) => {
|
|
|
17
25
|
} = node;
|
|
18
26
|
|
|
19
27
|
let value = toMongo(valueArg);
|
|
20
|
-
const isExistsQuery =
|
|
28
|
+
const isExistsQuery =
|
|
29
|
+
valueArg.type === "wildcard" &&
|
|
30
|
+
(valueArg.value as any) === "@kuery-wildcard@";
|
|
21
31
|
if (isExistsQuery) {
|
|
22
|
-
return exists(node)
|
|
32
|
+
return exists(node);
|
|
23
33
|
}
|
|
24
|
-
let query: any = {}
|
|
25
|
-
query[toMongo(fieldNameArg)] = {
|
|
34
|
+
let query: any = {};
|
|
35
|
+
query[toMongo(fieldNameArg)] = { $eq: value };
|
|
26
36
|
return query;
|
|
27
37
|
};
|
|
28
38
|
|
|
29
39
|
const or = (node: KueryNode) => {
|
|
30
40
|
const children = node.arguments || [];
|
|
31
41
|
return {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
42
|
+
$or: children.map((child: KueryNode) => {
|
|
43
|
+
return toMongo(child);
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
38
46
|
};
|
|
39
47
|
const not = (node: KueryNode) => {
|
|
40
48
|
const [fieldNameArg] = node.arguments;
|
|
41
49
|
let query: any = {};
|
|
42
|
-
query = {
|
|
50
|
+
query = { $ne: toMongo(fieldNameArg) };
|
|
43
51
|
return query;
|
|
44
52
|
};
|
|
45
53
|
|
|
46
54
|
const AST_TO_CQL = {
|
|
47
|
-
gt:
|
|
48
|
-
lt:
|
|
49
|
-
gte:
|
|
50
|
-
lte:
|
|
55
|
+
gt: "$gt",
|
|
56
|
+
lt: "$lt",
|
|
57
|
+
gte: "$gte",
|
|
58
|
+
lte: "$lte",
|
|
51
59
|
};
|
|
52
60
|
const range = (node: KueryNode) => {
|
|
53
61
|
const [fieldNameArg, operator] = node.arguments;
|
|
54
|
-
let valueArg = operator.value
|
|
62
|
+
let valueArg = operator.value;
|
|
55
63
|
// @ts-ignore
|
|
56
64
|
const opsign = AST_TO_CQL[operator.name];
|
|
57
65
|
let value = toMongo(valueArg);
|
|
58
66
|
|
|
59
|
-
let query: any = {}
|
|
60
|
-
query[fieldNameArg.value] = {}
|
|
61
|
-
query[fieldNameArg.value][opsign] = value
|
|
62
|
-
return query
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
let query: any = {};
|
|
68
|
+
query[fieldNameArg.value] = {};
|
|
69
|
+
query[fieldNameArg.value][opsign] = value;
|
|
70
|
+
return query;
|
|
65
71
|
};
|
|
66
72
|
const exists = (node: KueryNode) => {
|
|
67
73
|
const [fieldNameArg] = node.arguments;
|
|
68
|
-
return { [toMongo(fieldNameArg)]: { $ne: null } }
|
|
74
|
+
return { [toMongo(fieldNameArg)]: { $ne: null } };
|
|
69
75
|
};
|
|
70
76
|
|
|
71
77
|
const nested = (node: KueryNode) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
console.warn("TODO Implement nested search", node);
|
|
79
|
+
return "";
|
|
80
|
+
};
|
|
81
|
+
const geospatial = (node: KueryNode) => {
|
|
82
|
+
const [fieldName, operator, value] = node.arguments;
|
|
83
|
+
if (operator == "within") {
|
|
84
|
+
return { [fieldName.value]: { $geoWithin: wktToGeoJSON(value.value) } };
|
|
85
|
+
}
|
|
86
|
+
};
|
|
76
87
|
export const functions = {
|
|
77
88
|
is,
|
|
78
89
|
and,
|
|
@@ -80,7 +91,8 @@ export const functions = {
|
|
|
80
91
|
not,
|
|
81
92
|
range,
|
|
82
93
|
exists,
|
|
83
|
-
nested
|
|
94
|
+
nested,
|
|
95
|
+
geospatial,
|
|
84
96
|
};
|
|
85
97
|
const nodeTypes = {
|
|
86
98
|
function: (node: KueryNode) => {
|
|
@@ -92,7 +104,7 @@ const nodeTypes = {
|
|
|
92
104
|
},
|
|
93
105
|
wildcard: (node: KueryNode) => {
|
|
94
106
|
const { value } = node;
|
|
95
|
-
return `/${value.split(KQL_WILDCARD_SYMBOL).join(
|
|
107
|
+
return `/${value.split(KQL_WILDCARD_SYMBOL).join(".*")}/`;
|
|
96
108
|
},
|
|
97
109
|
};
|
|
98
110
|
|
|
@@ -28,7 +28,7 @@ test.beforeEach(async ({ page }) => {
|
|
|
28
28
|
test.describe("Spectric Table Tests", () => {
|
|
29
29
|
test("MultiSelect Table Select All/Deselect All ", async ({ page }) => {
|
|
30
30
|
await page.goto(
|
|
31
|
-
"http://localhost:6006/iframe.html?globals=&args=&id=spectric-ui-components-ui-table--
|
|
31
|
+
"http://localhost:6006/iframe.html?globals=&args=&id=spectric-ui-components-ui-table--multi-select&viewMode=story"
|
|
32
32
|
);
|
|
33
33
|
let tableLocator = page.locator("spectric-table");
|
|
34
34
|
tableLocator.waitFor();
|
|
@@ -149,7 +149,7 @@ test.describe("Spectric Table Tests", () => {
|
|
|
149
149
|
page,
|
|
150
150
|
}) => {
|
|
151
151
|
await page.goto(
|
|
152
|
-
"http://localhost:6006/iframe.html?globals=&args=&id=spectric-ui-components-ui-table--
|
|
152
|
+
"http://localhost:6006/iframe.html?globals=&args=&id=spectric-ui-components-ui-table--multi-select&viewMode=story"
|
|
153
153
|
);
|
|
154
154
|
let tableLocator = page.locator("spectric-table");
|
|
155
155
|
await tableLocator.waitFor();
|
|
@@ -79,7 +79,11 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
79
79
|
column: this.column,
|
|
80
80
|
});
|
|
81
81
|
};
|
|
82
|
-
|
|
82
|
+
_displayOverflowTooltip = () => {
|
|
83
|
+
if (this.column.disableCellOverflowTooltip) {
|
|
84
|
+
this.overflow = null;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
83
87
|
let div = this.querySelector("div.cell-contents");
|
|
84
88
|
let span = this.querySelector("span");
|
|
85
89
|
if (div && span) {
|
|
@@ -90,7 +94,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
90
94
|
divBounds.width * divBounds.height
|
|
91
95
|
) {
|
|
92
96
|
console.log(
|
|
93
|
-
"We need to show a tooltip
|
|
97
|
+
"We need to show a tooltip with the content because we are overflowing"
|
|
94
98
|
);
|
|
95
99
|
this.overflow = this.getRenderedValue();
|
|
96
100
|
this.updateComplete.then(() => {
|
|
@@ -118,16 +122,16 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
118
122
|
protected render(): unknown {
|
|
119
123
|
let rendered = this.getRenderedValue();
|
|
120
124
|
let classes = ["cell-contents"];
|
|
121
|
-
if (this.column.filterable) {
|
|
122
|
-
classes.push("
|
|
125
|
+
if (this.column.filterable || this.column.cellActions?.length) {
|
|
126
|
+
classes.push("hasActions");
|
|
123
127
|
}
|
|
124
|
-
|
|
128
|
+
const buttonSize = this.table.getCellActionButtonSize();
|
|
125
129
|
let filterButtons = cache(
|
|
126
130
|
this.column.filterable
|
|
127
|
-
? html
|
|
131
|
+
? html`
|
|
128
132
|
<spectric-button
|
|
129
133
|
@click=${this._handleFilterOut}
|
|
130
|
-
size
|
|
134
|
+
.size=${buttonSize}
|
|
131
135
|
variant="text"
|
|
132
136
|
icon
|
|
133
137
|
tooltip="Filter Out Value"
|
|
@@ -135,15 +139,26 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
135
139
|
>
|
|
136
140
|
<spectric-button
|
|
137
141
|
@click=${this._handleFilterFor}
|
|
138
|
-
size
|
|
142
|
+
.size=${buttonSize}
|
|
139
143
|
variant="text"
|
|
140
144
|
icon
|
|
141
145
|
tooltip="Filter For Value"
|
|
142
146
|
>+</spectric-button
|
|
143
147
|
>
|
|
144
|
-
|
|
148
|
+
`
|
|
145
149
|
: null
|
|
146
150
|
);
|
|
151
|
+
|
|
152
|
+
let actions = (this.column.cellActions || []).map((action) => {
|
|
153
|
+
return html`<spectric-button
|
|
154
|
+
@click=${() => action.onClick(this.row, this.column)}
|
|
155
|
+
.size=${buttonSize}
|
|
156
|
+
variant="text"
|
|
157
|
+
icon
|
|
158
|
+
.tooltip=${action.tooltip}
|
|
159
|
+
>${action.icon}</spectric-button
|
|
160
|
+
>`;
|
|
161
|
+
});
|
|
147
162
|
this.styleRules = {
|
|
148
163
|
width: this.column.width ? this.column.width + "px" : null,
|
|
149
164
|
whiteSpace: this.column.whiteSpace || null,
|
|
@@ -151,9 +166,11 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
151
166
|
return html`
|
|
152
167
|
<td
|
|
153
168
|
style=${styleMap(this.styleRules)}
|
|
154
|
-
@mouseenter=${this.
|
|
169
|
+
@mouseenter=${this._displayOverflowTooltip}
|
|
155
170
|
>
|
|
156
|
-
${
|
|
171
|
+
<div class="table-cell-actions ${buttonSize}">
|
|
172
|
+
${actions} ${filterButtons}
|
|
173
|
+
</div>
|
|
157
174
|
<div class=${classes.join(" ")}>
|
|
158
175
|
${this.overflow
|
|
159
176
|
? html`<spectric-tooltip .text=${this.overflow}></spectric-tooltip>`
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
TableSortDirection,
|
|
15
15
|
} from "./table";
|
|
16
16
|
import { DisposableElement } from "../../classes";
|
|
17
|
+
import { ARROW_DOWN, ARROW_UP } from "../symbols";
|
|
17
18
|
|
|
18
19
|
interface HeaderProps<T> {
|
|
19
20
|
columns: ColumnSettings<T>[];
|
|
@@ -125,9 +126,9 @@ export class TableHeaderElement<T>
|
|
|
125
126
|
: "";
|
|
126
127
|
let sortDirection =
|
|
127
128
|
column.sortDirection === TableSortDirection.ascending
|
|
128
|
-
?
|
|
129
|
+
? ARROW_UP
|
|
129
130
|
: column.sortDirection == TableSortDirection.descending
|
|
130
|
-
?
|
|
131
|
+
? ARROW_DOWN
|
|
131
132
|
: ``;
|
|
132
133
|
let sortClass = column.sortDirection || TableSortDirection.none;
|
|
133
134
|
let resizable = column.allowResize || column.allowResize === undefined;
|
|
@@ -20,14 +20,16 @@ spectric-table spectric-table-virtual-body tr:hover{
|
|
|
20
20
|
background-color: color-mix(in srgb, var(--spectric-primary, #1ea7fd), transparent 70%)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
spectric-table tr {
|
|
23
|
+
spectric-table spectric-table-virtual-body tr {
|
|
24
24
|
height: var(--rowHeight);
|
|
25
25
|
}
|
|
26
26
|
spectric-table td{
|
|
27
|
-
height: var(--rowHeight);
|
|
28
27
|
padding:1px;
|
|
29
28
|
border: 1px solid transparent;
|
|
30
29
|
}
|
|
30
|
+
spectric-table spectric-table-virtual-body td{
|
|
31
|
+
height: var(--rowHeight);
|
|
32
|
+
}
|
|
31
33
|
|
|
32
34
|
spectric-table div[role="table"]{
|
|
33
35
|
display: table;
|
|
@@ -42,7 +44,7 @@ spectric-table-cell td{
|
|
|
42
44
|
position: relative;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
spectric-table td:hover:has(.
|
|
47
|
+
spectric-table td:hover:has(.hasActions) {
|
|
46
48
|
border: 1px solid var(--spectric-primary, #1ea7fd);
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -52,9 +54,14 @@ spectric-table-cell .table-cell-actions{
|
|
|
52
54
|
width: 100%;
|
|
53
55
|
flex-direction: row-reverse;
|
|
54
56
|
visibility: hidden;
|
|
55
|
-
top: -10px;
|
|
56
57
|
z-index: 1;
|
|
57
58
|
}
|
|
59
|
+
spectric-table-cell .table-cell-actions.tiny{
|
|
60
|
+
top: -10px;
|
|
61
|
+
}
|
|
62
|
+
spectric-table-cell .table-cell-actions.xxsmall{
|
|
63
|
+
top: -16px;
|
|
64
|
+
}
|
|
58
65
|
spectric-table-cell td:hover .table-cell-actions{
|
|
59
66
|
visibility: unset;
|
|
60
67
|
}
|
|
@@ -14,6 +14,7 @@ import { spreadProps } from "../../utils/spread";
|
|
|
14
14
|
import { PaginationChangeProps, PaginationProps } from "../pagination";
|
|
15
15
|
import { FilterEvent } from "./cell";
|
|
16
16
|
import { createSortChain } from "./sorting";
|
|
17
|
+
import { ButtonSizesTypes } from "../Button";
|
|
17
18
|
|
|
18
19
|
export type { TableProps, TableEvents };
|
|
19
20
|
|
|
@@ -41,6 +42,11 @@ export enum TableSortDirection {
|
|
|
41
42
|
none = "none",
|
|
42
43
|
}
|
|
43
44
|
export type TableSortDirectionTypes = `${TableSortDirection}`;
|
|
45
|
+
export type CellAction<T> = {
|
|
46
|
+
tooltip: DomRenderable;
|
|
47
|
+
icon: DomRenderable;
|
|
48
|
+
onClick: (row: T, column: ColumnSettings<T>) => void;
|
|
49
|
+
};
|
|
44
50
|
export type ColumnSettings<T> = {
|
|
45
51
|
[TABLE_CREATED_SELECTION_COLUMN]?: boolean;
|
|
46
52
|
width?: number;
|
|
@@ -53,6 +59,8 @@ export type ColumnSettings<T> = {
|
|
|
53
59
|
sortable?: boolean;
|
|
54
60
|
sortDirection?: TableSortDirectionTypes;
|
|
55
61
|
filterable?: boolean;
|
|
62
|
+
disableCellOverflowTooltip?: boolean;
|
|
63
|
+
cellActions?: CellAction<T>[];
|
|
56
64
|
title?: DomRenderable | ((table: SpectricTableElement<T>) => DomRenderable);
|
|
57
65
|
/**
|
|
58
66
|
* Key to used for getting data from an object for a cell
|
|
@@ -125,6 +133,11 @@ export class SpectricTableElement<T = any>
|
|
|
125
133
|
*/
|
|
126
134
|
@property({ type: Number, reflect: true })
|
|
127
135
|
fontSize: number = 16;
|
|
136
|
+
|
|
137
|
+
protected cellActionButtonSize: ButtonSizesTypes = "xxsmall";
|
|
138
|
+
getCellActionButtonSize() {
|
|
139
|
+
return this.cellActionButtonSize;
|
|
140
|
+
}
|
|
128
141
|
static getDefaultDataSorterAndPaginatior<T>(data: T[]) {
|
|
129
142
|
return (props: TableDataOptions<T>) => {
|
|
130
143
|
//let sorts = props.columns.filter(column => column.sortable && column.sortDirection && column.sortDirection !== TableSortDirection.none)
|
|
@@ -237,7 +250,7 @@ export class SpectricTableElement<T = any>
|
|
|
237
250
|
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
238
251
|
return this;
|
|
239
252
|
}
|
|
240
|
-
forceRefreshofSelectionColumn() {
|
|
253
|
+
private forceRefreshofSelectionColumn() {
|
|
241
254
|
// Because lit reuses dom elements for speed/effeciency it wont update unless the props are a different object.
|
|
242
255
|
// So we set the selection colum to a "new object" to force the rerender
|
|
243
256
|
let index = this.columns.findIndex(
|
|
@@ -251,6 +264,9 @@ export class SpectricTableElement<T = any>
|
|
|
251
264
|
this.selected = selected;
|
|
252
265
|
this.forceRefreshofSelectionColumn();
|
|
253
266
|
}
|
|
267
|
+
getSelected() {
|
|
268
|
+
return this.selected;
|
|
269
|
+
}
|
|
254
270
|
deselectAll() {
|
|
255
271
|
this.selected = [];
|
|
256
272
|
this.forceRefreshofSelectionColumn();
|
|
@@ -261,6 +277,53 @@ export class SpectricTableElement<T = any>
|
|
|
261
277
|
this.forceRefreshofSelectionColumn();
|
|
262
278
|
this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }));
|
|
263
279
|
}
|
|
280
|
+
async scrollToRow(row: T | number) {
|
|
281
|
+
let index: number = -1;
|
|
282
|
+
if (Number.isInteger(row)) {
|
|
283
|
+
index = row as number;
|
|
284
|
+
} else {
|
|
285
|
+
index = this.data.findIndex((value) => value === row);
|
|
286
|
+
}
|
|
287
|
+
if (index !== -1) {
|
|
288
|
+
let body = this.querySelector("spectric-table-virtual-body");
|
|
289
|
+
let wrapper = this.querySelector(".table-wrapper")!;
|
|
290
|
+
let scrollPosition = index * this._getRowHeight();
|
|
291
|
+
wrapper.scrollTo({
|
|
292
|
+
top: scrollPosition,
|
|
293
|
+
behavior: "smooth",
|
|
294
|
+
});
|
|
295
|
+
//Wait for the smooth scroll to complete. Scroll to doesn't return a promise so we must manually check periodically
|
|
296
|
+
for (let wait = 0; wait < 100; wait++) {
|
|
297
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
298
|
+
if (wrapper.scrollTop == scrollPosition) {
|
|
299
|
+
console.log("Scroll complete");
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (body) {
|
|
304
|
+
//Highlight the row we scrolled to
|
|
305
|
+
requestAnimationFrame(() => {
|
|
306
|
+
let rows = [...body.querySelectorAll("tr")];
|
|
307
|
+
rows = rows.filter(
|
|
308
|
+
(row) => row.querySelector("spectric-table-cell")?.index === index
|
|
309
|
+
);
|
|
310
|
+
if (rows.length) {
|
|
311
|
+
rows[0].animate(
|
|
312
|
+
[{ backgroundColor: "red" }, { backgroundColor: "unset" }],
|
|
313
|
+
{ duration: 200, iterations: 5 }
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
_getRowHeight = () => {
|
|
321
|
+
let rowHeight = this.rowHeight - TD_BorderAndPadding;
|
|
322
|
+
if (rowHeight < this.fontSize + TD_BorderAndPadding) {
|
|
323
|
+
rowHeight = this.fontSize + TD_BorderAndPadding;
|
|
324
|
+
}
|
|
325
|
+
return rowHeight;
|
|
326
|
+
};
|
|
264
327
|
_handleSelectAllChange = (e: DomEvent<HTMLInputElement>) => {
|
|
265
328
|
e.stopPropagation();
|
|
266
329
|
if (e.target.checked) {
|
|
@@ -271,6 +334,8 @@ export class SpectricTableElement<T = any>
|
|
|
271
334
|
};
|
|
272
335
|
private selectColumnConfig: ColumnSettings<T> = {
|
|
273
336
|
[TABLE_CREATED_SELECTION_COLUMN]: true,
|
|
337
|
+
allowResize: false,
|
|
338
|
+
filterable: false,
|
|
274
339
|
width: 39,
|
|
275
340
|
title: (table) => {
|
|
276
341
|
return table.select === "multi"
|
|
@@ -314,6 +379,14 @@ export class SpectricTableElement<T = any>
|
|
|
314
379
|
},
|
|
315
380
|
};
|
|
316
381
|
protected update(changedProperties: PropertyValues): void {
|
|
382
|
+
if (changedProperties.has("data")) {
|
|
383
|
+
this.selected = this.data.reduce((a, row) => {
|
|
384
|
+
if (this.selected.includes(row)) {
|
|
385
|
+
a.push(row);
|
|
386
|
+
}
|
|
387
|
+
return a;
|
|
388
|
+
}, [] as T[]);
|
|
389
|
+
}
|
|
317
390
|
if (changedProperties.has("columns")) {
|
|
318
391
|
if (this.select !== TableSelectOptions.none) {
|
|
319
392
|
if (!this.columns.find((col) => col[TABLE_CREATED_SELECTION_COLUMN])) {
|
|
@@ -333,10 +406,7 @@ export class SpectricTableElement<T = any>
|
|
|
333
406
|
}
|
|
334
407
|
protected render(): unknown {
|
|
335
408
|
let columns = this.columns.filter((column) => !column.hidden);
|
|
336
|
-
let rowHeight = this.
|
|
337
|
-
if (rowHeight < this.fontSize + TD_BorderAndPadding) {
|
|
338
|
-
rowHeight = this.fontSize + TD_BorderAndPadding;
|
|
339
|
-
}
|
|
409
|
+
let rowHeight = this._getRowHeight();
|
|
340
410
|
return html`
|
|
341
411
|
<div
|
|
342
412
|
class="table-wrapper"
|
|
@@ -43,14 +43,19 @@ export class TableVirtualBodyElement<T>
|
|
|
43
43
|
columnsMeasured: boolean = false;
|
|
44
44
|
constructor() {
|
|
45
45
|
super();
|
|
46
|
+
let lastScroll = 0;
|
|
46
47
|
this.addDisposableListener(
|
|
47
48
|
() => this.table.querySelector(".table-wrapper")!,
|
|
48
49
|
"scroll",
|
|
49
50
|
() => {
|
|
50
51
|
const scrollTop = this.table.querySelector(".table-wrapper")!.scrollTop;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
// Prevent changing the start index if the scroll hasn't changed more than at at least 1/4 a row
|
|
53
|
+
// I think I have bad math that is causing a new scroll event due to a couple pixel height difference after I create the spacers
|
|
54
|
+
if (Math.abs(lastScroll - scrollTop) <= this.rowHeight / 4) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
lastScroll = scrollTop;
|
|
58
|
+
this.startIndex = Math.floor(scrollTop / this.rowHeight);
|
|
54
59
|
}
|
|
55
60
|
);
|
|
56
61
|
}
|