@spectric/ui 0.0.21 → 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 (45) hide show
  1. package/dist/components/dialog/dialog.d.ts +1 -0
  2. package/dist/components/pagination/pagination.d.ts +1 -1
  3. package/dist/components/query_bar/QueryBar.d.ts +30 -10
  4. package/dist/components/query_bar/dateTimePopup.d.ts +2 -0
  5. package/dist/components/query_bar/geojsonPopup.d.ts +2 -0
  6. package/dist/components/query_bar/querylanguage/kuery/functions/geospatial.d.ts +19 -0
  7. package/dist/components/query_bar/querylanguage/outputTypes/toCQL.d.ts +2 -1
  8. package/dist/components/query_bar/querylanguage/outputTypes/toMongo.d.ts +6 -1
  9. package/dist/components/symbols.d.ts +6 -0
  10. package/dist/components/table/cell.d.ts +1 -1
  11. package/dist/components/table/table.d.ts +5 -1
  12. package/dist/custom-elements.json +5 -5
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.es.js +4382 -2795
  15. package/dist/index.es.js.map +1 -1
  16. package/dist/index.umd.js +349 -248
  17. package/dist/index.umd.js.map +1 -1
  18. package/dist/style.css +1 -1
  19. package/package.json +6 -1
  20. package/src/components/dialog/dialog.css.ts +29 -29
  21. package/src/components/dialog/dialog.ts +3 -1
  22. package/src/components/input.ts +49 -39
  23. package/src/components/pagination/pagination.ts +167 -113
  24. package/src/components/query_bar/QueryBar.ts +438 -187
  25. package/src/components/query_bar/dateTimePopup.ts +54 -0
  26. package/src/components/query_bar/geojsonPopup.ts +44 -0
  27. package/src/components/query_bar/querylanguage/kuery/ast/_generated_/kuery.js +1836 -2745
  28. package/src/components/query_bar/querylanguage/kuery/ast/ast.ts +15 -13
  29. package/src/components/query_bar/querylanguage/kuery/ast/kuery.peg +92 -126
  30. package/src/components/query_bar/querylanguage/kuery/functions/geospatial.ts +25 -0
  31. package/src/components/query_bar/querylanguage/kuery/functions/index.ts +9 -7
  32. package/src/components/query_bar/querylanguage/outputTypes/toCQL.ts +56 -34
  33. package/src/components/query_bar/querylanguage/outputTypes/toMongo.ts +46 -34
  34. package/src/components/symbols.ts +6 -0
  35. package/src/components/table/__tests__/table.spec.ts +2 -2
  36. package/src/components/table/cell.ts +7 -3
  37. package/src/components/table/header.ts +3 -2
  38. package/src/components/table/table.css +4 -2
  39. package/src/components/table/table.ts +61 -5
  40. package/src/components/table/virtualBody.ts +8 -3
  41. package/src/components/tooltip/popover.ts +263 -225
  42. package/src/stories/Dialog.stories.ts +59 -0
  43. package/src/stories/QueryBar.stories.ts +46 -37
  44. package/src/stories/fixtures/data.ts +195 -36
  45. package/src/stories/table.stories.ts +70 -22
@@ -1,13 +1,21 @@
1
1
  /* eslint-disable @kbn/eslint/require-license-header */
2
- import { FieldTypes, KueryNode } from '../..';
3
- import { wildcardSymbol } from '../kuery/node_types/wildcard';
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 = 'wildcard';
7
- export type FunctionName = 'is' | 'and' | 'or' | 'not' | 'range' | 'exists' | 'nested';
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 = { "$and": children.map((c: KueryNode) => toMongo(c)) }
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 = valueArg.type === 'wildcard' && (valueArg.value as any) === '@kuery-wildcard@';
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)] = { "$eq": value }
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
- "$or": children
33
- .map((child: KueryNode) => {
34
- return toMongo(child);
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 = { "$ne": toMongo(fieldNameArg) }
50
+ query = { $ne: toMongo(fieldNameArg) };
43
51
  return query;
44
52
  };
45
53
 
46
54
  const AST_TO_CQL = {
47
- gt: '$gt',
48
- lt: '$lt',
49
- gte: '$gte',
50
- lte: '$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
- console.warn("TODO Implement nested search", node)
74
- return ""
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
 
@@ -0,0 +1,6 @@
1
+ export const EDIT = "🖉";
2
+ export const DELETE = "🗑";
3
+ export const ARROW_LEFT = "🠈";
4
+ export const ARROW_RIGHT = "🠊";
5
+ export const ARROW_UP = "🠉";
6
+ export const ARROW_DOWN = "🠋";
@@ -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--milti-select&viewMode=story"
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--milti-select&viewMode=story"
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
- _displayTooltip = () => {
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 witht he content because we are overflowing"
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(() => {
@@ -151,7 +155,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
151
155
  return html`
152
156
  <td
153
157
  style=${styleMap(this.styleRules)}
154
- @mouseenter=${this._displayTooltip}
158
+ @mouseenter=${this._displayOverflowTooltip}
155
159
  >
156
160
  ${filterButtons}
157
161
  <div class=${classes.join(" ")}>
@@ -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;
@@ -53,6 +53,7 @@ export type ColumnSettings<T> = {
53
53
  sortable?: boolean;
54
54
  sortDirection?: TableSortDirectionTypes;
55
55
  filterable?: boolean;
56
+ disableCellOverflowTooltip?: boolean;
56
57
  title?: DomRenderable | ((table: SpectricTableElement<T>) => DomRenderable);
57
58
  /**
58
59
  * Key to used for getting data from an object for a cell
@@ -237,7 +238,7 @@ export class SpectricTableElement<T = any>
237
238
  protected createRenderRoot(): HTMLElement | DocumentFragment {
238
239
  return this;
239
240
  }
240
- forceRefreshofSelectionColumn() {
241
+ private forceRefreshofSelectionColumn() {
241
242
  // Because lit reuses dom elements for speed/effeciency it wont update unless the props are a different object.
242
243
  // So we set the selection colum to a "new object" to force the rerender
243
244
  let index = this.columns.findIndex(
@@ -251,6 +252,9 @@ export class SpectricTableElement<T = any>
251
252
  this.selected = selected;
252
253
  this.forceRefreshofSelectionColumn();
253
254
  }
255
+ getSelected() {
256
+ return this.selected;
257
+ }
254
258
  deselectAll() {
255
259
  this.selected = [];
256
260
  this.forceRefreshofSelectionColumn();
@@ -261,6 +265,53 @@ export class SpectricTableElement<T = any>
261
265
  this.forceRefreshofSelectionColumn();
262
266
  this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }));
263
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);
274
+ }
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;
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
+ }
306
+ }
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
+ };
264
315
  _handleSelectAllChange = (e: DomEvent<HTMLInputElement>) => {
265
316
  e.stopPropagation();
266
317
  if (e.target.checked) {
@@ -314,6 +365,14 @@ export class SpectricTableElement<T = any>
314
365
  },
315
366
  };
316
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);
372
+ }
373
+ return a;
374
+ }, [] as T[]);
375
+ }
317
376
  if (changedProperties.has("columns")) {
318
377
  if (this.select !== TableSelectOptions.none) {
319
378
  if (!this.columns.find((col) => col[TABLE_CREATED_SELECTION_COLUMN])) {
@@ -333,10 +392,7 @@ export class SpectricTableElement<T = any>
333
392
  }
334
393
  protected render(): unknown {
335
394
  let columns = this.columns.filter((column) => !column.hidden);
336
- let rowHeight = this.rowHeight - TD_BorderAndPadding;
337
- if (rowHeight < this.fontSize + TD_BorderAndPadding) {
338
- rowHeight = this.fontSize + TD_BorderAndPadding;
339
- }
395
+ let rowHeight = this._getRowHeight();
340
396
  return html`
341
397
  <div
342
398
  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
- requestAnimationFrame(() => {
52
- this.startIndex = Math.floor(scrollTop / this.rowHeight);
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
  }