@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.
- package/dist/classes/DisposibleElement.d.ts +4 -2
- package/dist/components/Bitdisplay.d.ts +4 -4
- package/dist/components/Button.d.ts +1 -1
- package/dist/components/Header.d.ts +1 -1
- package/dist/components/input.d.ts +13 -12
- package/dist/components/splitview/splitview.d.ts +5 -5
- package/dist/components/table/body.d.ts +2 -1
- package/dist/components/table/cell.d.ts +1 -0
- package/dist/components/table/table.d.ts +10 -6
- package/dist/components/table/virtualBody.d.ts +49 -0
- package/dist/components/tooltip/tooltip.d.ts +15 -10
- package/dist/custom-elements.json +23 -9
- package/dist/index.es.js +1930 -1763
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +124 -91
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/classes/DisposibleElement.ts +15 -9
- package/src/components/Bitdisplay.ts +7 -7
- package/src/components/Button.ts +1 -1
- package/src/components/Header.ts +1 -1
- package/src/components/input.ts +18 -14
- package/src/components/splitview/splitview.ts +5 -5
- package/src/components/table/body.ts +13 -5
- package/src/components/table/cell.ts +4 -1
- package/src/components/table/header.ts +7 -2
- package/src/components/table/table.css +10 -6
- package/src/components/table/table.ts +45 -16
- package/src/components/table/virtualBody.css +13 -0
- package/src/components/table/virtualBody.ts +127 -0
- package/src/components/tooltip/tooltip.ts +36 -30
- package/src/docs/HTML-Vue-Python Integration.mdx +3 -3
- package/src/docs/html-include.png +0 -0
- package/src/docs/vue-example.png +0 -0
- package/src/docs/vue-include.png +0 -0
- package/src/stories/BitDisplay.stories.ts +2 -0
- package/src/stories/fixtures/data.ts +1 -1
- package/src/stories/pagination.stories.ts +2 -1
- 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,
|
|
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
|
|
23
|
+
delay?: number;
|
|
23
24
|
/**
|
|
24
25
|
* How long the fade in animation should run
|
|
25
26
|
*/
|
|
26
|
-
animationDuration
|
|
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
|
|
35
|
+
position?: TooltipPostionsTypes
|
|
35
36
|
/**
|
|
36
|
-
* Sets a max width for the contents
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-

|
|
5
|
+

|
|
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
|
-

|
|
12
|
+

|
|
13
13
|
Once setup hovering over spectric elements will provide documentation
|
|
14
|
-

|
|
14
|
+

|
|
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:
|
|
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="
|
|
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
|
}}
|