@spectric/ui 0.0.11 → 0.0.12

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 (40) hide show
  1. package/dist/classes/DisposibleElement.d.ts +4 -2
  2. package/dist/components/Bitdisplay.d.ts +4 -4
  3. package/dist/components/Button.d.ts +1 -1
  4. package/dist/components/Header.d.ts +1 -1
  5. package/dist/components/input.d.ts +13 -12
  6. package/dist/components/splitview/splitview.d.ts +5 -5
  7. package/dist/components/table/body.d.ts +2 -1
  8. package/dist/components/table/cell.d.ts +1 -0
  9. package/dist/components/table/table.d.ts +10 -6
  10. package/dist/components/table/virtualBody.d.ts +49 -0
  11. package/dist/components/tooltip/tooltip.d.ts +15 -10
  12. package/dist/custom-elements.json +23 -9
  13. package/dist/index.es.js +1930 -1763
  14. package/dist/index.es.js.map +1 -1
  15. package/dist/index.umd.js +124 -91
  16. package/dist/index.umd.js.map +1 -1
  17. package/dist/style.css +1 -1
  18. package/package.json +1 -1
  19. package/src/classes/DisposibleElement.ts +15 -9
  20. package/src/components/Bitdisplay.ts +7 -7
  21. package/src/components/Button.ts +1 -1
  22. package/src/components/Header.ts +1 -1
  23. package/src/components/input.ts +18 -14
  24. package/src/components/splitview/splitview.ts +5 -5
  25. package/src/components/table/body.ts +13 -5
  26. package/src/components/table/cell.ts +4 -1
  27. package/src/components/table/header.ts +7 -2
  28. package/src/components/table/table.css +10 -6
  29. package/src/components/table/table.ts +45 -16
  30. package/src/components/table/virtualBody.css +13 -0
  31. package/src/components/table/virtualBody.ts +127 -0
  32. package/src/components/tooltip/tooltip.ts +36 -30
  33. package/src/docs/HTML-Vue-Python Integration.mdx +3 -3
  34. package/src/docs/html-include.png +0 -0
  35. package/src/docs/vue-example.png +0 -0
  36. package/src/docs/vue-include.png +0 -0
  37. package/src/stories/BitDisplay.stories.ts +2 -0
  38. package/src/stories/fixtures/data.ts +1 -1
  39. package/src/stories/pagination.stories.ts +2 -1
  40. package/src/stories/table.stories.ts +4 -2
@@ -0,0 +1,127 @@
1
+ import { html } from 'lit';
2
+ import { customElement, property, } from 'lit/decorators.js';
3
+ import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
4
+ export const TableBodyElementTag = "spectric-table-virtual-body"
5
+ import "./cell"
6
+ import { ColumnSettings, TableElement } from './table';
7
+ import { repeat } from 'lit/directives/repeat.js';
8
+ import { DisposableElement } from '../../classes/DisposibleElement';
9
+ import "./virtualBody.css"
10
+ interface BodyProps<T> {
11
+ columns: ColumnSettings<T>[]
12
+ data: T[]
13
+ rowHeight: number
14
+ }
15
+
16
+
17
+ /**
18
+ * Table Body Element
19
+ */
20
+ @customElement(TableBodyElementTag)
21
+ export class TableVirtualBodyElement<T> extends DisposableElement implements BodyProps<T> {
22
+ @property({ type: Array, attribute: false })
23
+ data: T[] = [];
24
+ @property({ type: Array, attribute: false })
25
+ columns: ColumnSettings<T>[] = [];
26
+ @property({ type: Number, attribute: false })
27
+ rowHeight: number = 30;
28
+
29
+ @property({ type: Number, state: true })
30
+ startIndex: number = 0
31
+
32
+ table!: TableElement<T>
33
+ constructor() {
34
+ super()
35
+ this.addDisposableListener(() => this.table.querySelector(".table-wrapper")!, "scroll", () => {
36
+ const scrollTop = this.table.querySelector(".table-wrapper")!.scrollTop;
37
+ requestAnimationFrame(() => {
38
+ this.startIndex = Math.floor(scrollTop / this.rowHeight);
39
+ })
40
+ })
41
+ }
42
+ protected firstUpdated(): void {
43
+ this.columns.forEach(col => {
44
+ if (!col.width) {
45
+ console.warn("When using virtual scrolling it is recomended to set the width of the columns to prevent columns widths from jittering during scroll")
46
+ }
47
+ })
48
+ }
49
+ protected createRenderRoot(): HTMLElement | DocumentFragment {
50
+ return this
51
+ }
52
+ protected render(): unknown {
53
+ let totalRows = this.data.length
54
+ let buffer = 10 // Have a buffer of rows to prevent column jitter
55
+ let headerHeight = this.table.querySelector("spectric-table-header")!.clientHeight
56
+ let viewport = this.table.querySelector(".table-wrapper")!
57
+ let startIndex = Math.max(this.startIndex - buffer, 0) //pad the front with 10 rows
58
+ const rowsThatFit = Math.ceil((viewport.clientHeight - headerHeight) / this.rowHeight);
59
+ const endIndex = Math.min(startIndex + rowsThatFit + buffer, totalRows);
60
+ const visibleRows = endIndex - startIndex
61
+ let totalHeight = totalRows * this.rowHeight
62
+ let beforeHeight = (startIndex * this.rowHeight) + (viewport.scrollTop - (startIndex * this.rowHeight))
63
+ if (endIndex === totalRows) {
64
+ beforeHeight = (startIndex * this.rowHeight)
65
+ }
66
+ let visibleHeight = (visibleRows * this.rowHeight)
67
+ let afterHeight = totalHeight - beforeHeight - visibleHeight
68
+ let spacerElementBefore = this.startIndex != 0 ? html`
69
+ <tr style="height:${beforeHeight}px" class="virtual-scroll-spacer">
70
+ <td colspan="${this.columns.length}"></td></tr>` : null
71
+
72
+ let spacerElementAfter = html`
73
+ <tr style="height:${afterHeight}px" class="virtual-scroll-spacer">
74
+ <td colspan="${this.columns.length}"></td></tr>`
75
+ return html`
76
+ <div style="height:${totalHeight}px;position: absolute;overflow-x: hidden;overflow-y: hidden;z-index:-1;width:1px;"></div>
77
+ <tbody>
78
+ ${spacerElementBefore}
79
+ </tbody>
80
+ <div style="display:table-row-group;max-height:${visibleHeight}px; overflow:hidden;">
81
+
82
+ ${repeat(this.data.slice(Math.max(startIndex, 0), endIndex), (row, index) => html`
83
+ <tr class="${(index + startIndex) % 2 === 0 ? "odd" : ""}">
84
+ ${repeat(this.columns, (col) => {
85
+ return html`<spectric-table-cell .column=${col} .row=${row} .index=${index + startIndex} .columns=${this.columns}></spectric-table-cell>`
86
+ })}
87
+ </tr>`)
88
+ }
89
+ </div>
90
+ <tbody>
91
+ ${afterHeight > 0 ? spacerElementAfter : null}
92
+ </tbody>
93
+
94
+ `
95
+
96
+ }
97
+
98
+ }
99
+
100
+ interface TableBodyEvents {
101
+ //'sort': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
102
+ }
103
+
104
+ declare global {
105
+ interface HTMLElementTagNameMap {
106
+ [TableBodyElementTag]: HTMLElementTagWithEvents<TableVirtualBodyElement<any>, TableBodyEvents>
107
+
108
+ }
109
+ namespace JSX {
110
+ interface IntrinsicElements {
111
+ /**
112
+ * @see {@link DialogElement}
113
+ */
114
+ [TableBodyElementTag]: ReactElementWithPropsAndEvents<TableVirtualBodyElement<any>, BodyProps<any>, TableBodyEvents>;
115
+ }
116
+ }
117
+ namespace React {
118
+ namespace JSX {
119
+ interface IntrinsicElements {
120
+ /**
121
+ * @see {@link DialogElement}
122
+ */
123
+ [TableBodyElementTag]: ReactElementWithPropsAndEvents<TableVirtualBodyElement<any>, BodyProps<any>, TableBodyEvents>
124
+ }
125
+ }
126
+ }
127
+ }
@@ -3,8 +3,9 @@ import { customElement, property } from 'lit/decorators.js';
3
3
  import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
4
4
  import "./tooltip.css"
5
5
  export const TooltipElementTag = "spectric-tooltip"
6
- import { css, CSSResultGroup, html, LitElement, render } from "lit-element";
6
+ import { css, CSSResultGroup, html, render } from "lit-element";
7
7
  import { DomRenderable } from "../table";
8
+ import { DisposableElement } from '../../classes/DisposibleElement';
8
9
  export type { TooltipProps, TooltipEvents }
9
10
  export enum TooltipPostions {
10
11
  top = "top",
@@ -19,11 +20,11 @@ interface TooltipProps {
19
20
  /**
20
21
  * How long you need to hover before the tooltip displays
21
22
  */
22
- delay: number;
23
+ delay?: number;
23
24
  /**
24
25
  * How long the fade in animation should run
25
26
  */
26
- animationDuration: number;
27
+ animationDuration?: number;
27
28
  /**
28
29
  * Tooltip contents
29
30
  */
@@ -31,18 +32,18 @@ interface TooltipProps {
31
32
  /**
32
33
  * Where to anchor the tooltip
33
34
  */
34
- position: TooltipPostionsTypes
35
+ position?: TooltipPostionsTypes
35
36
  /**
36
- * Sets a max width for the contents (default:300) you can disable this by setting to 0 or -1
37
+ * Sets a max width for the contents you can disable this by setting to 0 or -1
37
38
  */
38
39
  maxWidth?: number
39
40
  /**
40
- * Container the tool tip will be attached to. (default:document.body)
41
+ * Container the tool tip will be attached to.
41
42
  */
42
43
  portalTarget?: HTMLElement
43
44
 
44
45
  /**
45
- * The element that triggers the tooltip. (default:node.parentElement) This is used for special cases like in the shadow dom if you want to target a host element instead of the immediate parent element
46
+ * The element that triggers the tooltip. This is used for special cases like in the shadow dom if you want to target a host element instead of the immediate parent element
46
47
  */
47
48
  triggerTarget?: HTMLElement
48
49
  }
@@ -51,7 +52,7 @@ interface TooltipProps {
51
52
  * Spectric tooltip will add a tooltip to any container
52
53
  */
53
54
  @customElement(TooltipElementTag)
54
- export class TooltipElement extends LitElement implements TooltipProps {
55
+ export class TooltipElement extends DisposableElement implements TooltipProps {
55
56
  @property({ type: Number, reflect: true })
56
57
  delay: number = 100;
57
58
  @property({ type: Number, reflect: true })
@@ -72,25 +73,26 @@ export class TooltipElement extends LitElement implements TooltipProps {
72
73
  portalTarget: HTMLElement = document.body
73
74
  private timer?: number;
74
75
  private open: boolean = false;
75
- mouseframe?: number;
76
+ private mouseframe?: number;
77
+ /**
78
+ * @default parentElement
79
+ */
76
80
  @property({ attribute: false })
77
- triggerTarget?: HTMLElement;
81
+ triggerTarget!: HTMLElement;
78
82
  private get target() {
79
83
  return this.triggerTarget || this.parentElement
80
84
  }
85
+ constructor() {
86
+ super()
87
+ this.addDisposableListener(() => this.target, "mousemove", this._getMousePosition)
88
+ this.addDisposableListener(() => this.target, "mouseover", this.showToolTip)
89
+ this.addDisposableListener(() => this.target, "mouseleave", this._hideTooltip)
90
+ }
81
91
  connectedCallback(): void {
82
92
  super.connectedCallback()
83
- if (this.target) {
84
- this.target.addEventListener("mousemove", this._getMousePosition)
85
- this.target.addEventListener("mouseover", this.showToolTip)
86
- this.target.addEventListener("mouseleave", this._hideTooltip)
87
- }
88
93
  }
89
94
  disconnectedCallback(): void {
90
- super.connectedCallback()
91
- this.target?.removeEventListener("mousemove", this._getMousePosition)
92
- this.target?.removeEventListener("mouseover", this.showToolTip)
93
- this.target?.removeEventListener("mouseleave", this._hideTooltip)
95
+ super.disconnectedCallback()
94
96
  this.portalElement.remove()
95
97
  }
96
98
  private _getMousePosition = (ev: MouseEvent) => {
@@ -153,39 +155,43 @@ export class TooltipElement extends LitElement implements TooltipProps {
153
155
  }
154
156
  const bounds = this.target.getBoundingClientRect()
155
157
  const portalBounds = this.portalElement.getBoundingClientRect()
156
- if (this.target !== document.body)
158
+ if (this.target !== document.body) {
157
159
  if (this.maxWidth && this.maxWidth > 0) {
158
160
  portalBounds.width = Math.min(portalBounds.width, this.maxWidth)
159
161
  }
162
+ }
163
+ let location: {
164
+ left: string;
165
+ top: string;
166
+ };
160
167
  if (this.position === "mouse" && this.mouseLocation) {
161
168
  this.mouseframe = undefined
162
- const location = { left: this.mouseLocation.left + 10 + "px", top: this.mouseLocation.top - (portalBounds.height / 2) + "px" }
163
- this.applyStyle({ ...styles, ...location })
169
+ location = { left: this.mouseLocation.left + 10 + "px", top: this.mouseLocation.top - (portalBounds.height / 2) + "px" }
164
170
  } else if (this.position === "top") {
165
- const location = {
171
+ location = {
166
172
  top: bounds.top - portalBounds.height + "px",
167
173
  left: (bounds.left + (bounds.width / 2)) - (portalBounds.width / 2) + "px"
168
174
  }
169
- this.applyStyle({ ...styles, ...location })
170
175
  } else if (this.position === "bottom") {
171
- const location = {
176
+ location = {
172
177
  top: bounds.bottom + "px",
173
178
  left: (bounds.left + (bounds.width / 2)) - (portalBounds.width / 2) + "px"
174
179
  }
175
- this.applyStyle({ ...styles, ...location })
176
180
  } else if (this.position === "left") {
177
- const location = {
181
+ location = {
178
182
  top: Math.max(0, bounds.top + bounds.height / 2 - portalBounds.height / 2) + "px",
179
183
  left: bounds.left - (portalBounds.width) + "px"
180
184
  }
181
- this.applyStyle({ ...styles, ...location })
182
185
  } else if (this.position === "right") {
183
- const location = {
186
+ location = {
184
187
  top: Math.max(0, bounds.top + bounds.height / 2 - portalBounds.height / 2) + "px",
185
188
  left: bounds.right + "px"
186
189
  }
187
- this.applyStyle({ ...styles, ...location })
190
+ } else {
191
+ location = { left: "0px", top: "0px" };
192
+ console.error("Unknown position... Maybe we sould implement auto?")
188
193
  }
194
+ this.applyStyle({ ...styles, ...location })
189
195
  if (this.position !== "mouse") {
190
196
  this.portalElement.animate({ opacity: [0, 1] }, { duration: this.animationDuration })
191
197
  }
@@ -2,16 +2,16 @@
2
2
 
3
3
  Add the dist/custom-element.json to the html.languge settings
4
4
  https://code.visualstudio.com/docs/languages/html#_html-custom-data
5
- ![Add spectric custom elements](html-include.png)
5
+ ![Add spectric custom elements](./html-include.png)
6
6
 
7
7
  # VUE Integration
8
8
 
9
9
  Complete steps to include custom elements in the HTML language server
10
10
  then
11
11
  Add the HTML language server in the @ext:Vue.volar extention
12
- ![Add the HTML language server in the @ext:Vue.volar extention](vue-include.png)
12
+ ![Add the HTML language server in the @ext:Vue.volar extention](./vue-include.png)
13
13
  Once setup hovering over spectric elements will provide documentation
14
- ![alt text](vue-example.png)
14
+ ![alt text](./vue-example.png)
15
15
 
16
16
  # Python Jinja
17
17
 
Binary file
Binary file
Binary file
@@ -44,6 +44,8 @@ const meta = {
44
44
  Int16-e: ${pad(dataview.getInt16(0, true))}
45
45
  UInt16-E: ${pad(dataview.getUint16(0, false))} 0x${dataview.getUint16(0, false).toString(16)}
46
46
  Int16-e: ${pad(dataview.getUint16(0, true))} 0x${dataview.getUint16(0, true).toString(16)}
47
+ F32-e: ${pad(dataview.getFloat32(0, true))}
48
+ F32-E: ${pad(dataview.getFloat32(0, false))}
47
49
  </pre>`: null}
48
50
  `},
49
51
 
@@ -56,7 +56,7 @@ export const tabledata: TestData[] = [
56
56
  { name: "Matt", company: "Spectric Labs", "contact": "912-1230", location: { "country": "UK", state: "VA" }, years: 24 },
57
57
  { name: "Grant", company: "Spectric Labs", "contact": "123-4567", location: { "country": "US", state: "VA" }, years: 100 },]
58
58
  export const tablecolumns: ColumnSettings<TestData>[] = [
59
- { "title": "Company", key: "company" },
59
+ { "title": "Company", key: "company", width: 200 },
60
60
  { "title": "Name", key: "name", sortable: true },
61
61
  { "title": "Contact", key: "contact" },
62
62
  { "title": "Country", key: "location.country", filterable: true },
@@ -5,6 +5,7 @@ import { html } from "lit";
5
5
  import '../components';
6
6
  import { ifDefined } from "lit/directives/if-defined.js";
7
7
  import { useArgs } from "@storybook/client-api";
8
+ import { ButtonSizes } from "../components";
8
9
  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
9
10
  const meta = {
10
11
  title: "UI/Pagination",
@@ -29,7 +30,7 @@ const meta = {
29
30
  argTypes: {
30
31
  size: {
31
32
  control: { type: 'select' },
32
- options: ['small', 'medium', 'large'],
33
+ options: Object.values(ButtonSizes),
33
34
  },
34
35
  },
35
36
  args: {
@@ -8,7 +8,7 @@ import { useArgs } from "@storybook/client-api";
8
8
  import { FilterEvent, rowGetValue } from "../components/table/cell";
9
9
  import { tablecolumns, tabledata } from "./fixtures/data";
10
10
  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
11
- const data = JSON.parse(JSON.stringify(tabledata))
11
+ const data = JSON.parse(JSON.stringify([...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata, ...tabledata,]))
12
12
  const columns = tablecolumns
13
13
  const getData = TableElement.getDefaultDataSorterAndPaginatior<typeof tabledata[0]>(data)
14
14
  const meta = {
@@ -20,12 +20,14 @@ const meta = {
20
20
 
21
21
  return html`
22
22
  <spectric-table
23
- style="max-height: 150px;"
23
+ style="height: 150px;"
24
24
  .pagination=${args.pagination}
25
25
  .columns=${args.columns}
26
26
  .data=${getData(args)}
27
27
  select=${ifDefined(args.select)}
28
28
  sort=${ifDefined(args.sort)}
29
+ rowHeight=${ifDefined(args.rowHeight)}
30
+ @selected=${(e) => console.log(e)}
29
31
  @filter=${(e: CustomEvent<FilterEvent<any>>) => {
30
32
  alert(`filter ${e.detail.include ? "for" : "out"} event value ${e.detail.value}`)
31
33
  }}