@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
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
spectric-input{--input-color: var(--spectric-input-color, #f4f4f4);--border-radius: var(--spectric-border-radius, .4em);--input-bottom: var(--spectric-input-bottom, var(--spectric-button-primary, #a8a8a8));--input-bottom-focused: var(--primary, #1ea7fd);--text-on-color: var(--spectric-text-on-color, #ffffff);--text-on-color-disabled: var(--spectric-text-on-color-disabled, #8d8d8d);--text-placeholder: rgba(22, 22, 22, .4);--text-primary: var(--spectric-text-primary, #161616);--text-secondary: var(--spectric-text-secondary, #525252)}spectric-input .inputWrapper{color:var(--text-secondary)}spectric-input .inputWrapper input{box-sizing:border-box;margin:0;vertical-align:baseline;font-size:.875rem;font-weight:400;line-height:1.28572;letter-spacing:.16px;outline:transparent solid 2px;outline-offset:-2px;border:none;padding:0 1rem;background-color:var(--input-color);color:var(--text-primary, #161616);font-family:inherit;inline-size:100%;block-size:2.5rem}spectric-input .inputWrapper .inputContainer:active:after,spectric-input .inputContainer:focus-within:after{border-bottom-color:var(--input-bottom-focused);width:calc(100% - 5px);transition:width .4s ease-in-out}spectric-input .inputWrapper input:read-only{background-color:transparent;border-bottom-color:var(--border-disabled)}spectric-input .inputContainer{position:relative;border-radius:var(--border-radius);overflow:hidden}spectric-input .inputContainer:after{content:"";width:0px;transition:background-color .4s cubic-bezier(.2,0,.38,.9),border-bottom-color .4s cubic-bezier(.2,0,.38,.9);border-bottom-color:var(--input-bottom);border-bottom-style:solid;border-bottom-width:1px;position:absolute;left:2.5px;bottom:0}spectric-input #helper-text{height:18px}spectric-input[variant=password] spectric-button{position:absolute;right:4px;bottom:3px}spectric-input .checkbox{display:flex;justify-self:center}spectric-query{font-family:monospace}spectric-query .autocomplete{color:var(--spectric-text-primary, #161616);border-radius:0em 0em var(--spectric-border-radius, .4em) var(--spectric-border-radius, .4em);background-color:var(--spectric-background, #ffffff);border:1px solid var(--spectric-background-hover, rgba(141, 141, 141, .12));max-height:300px;border-top:0px;margin:-18px 0 0;position:fixed;top:anchor(bottom);justify-self:anchor-center;text-align:center}spectric-query .autocomplete .optiontype{float:left;max-width:10px}spectric-query .autocomplete .label{position:absolute;right:0}spectric-query .autocomplete .option.active,spectric-query .autocomplete .option:hover{background-color:var(--spectric-background-hover, rgba(141, 141, 141, .12));border-bottom:1px solid var(--primary, #1ea7fd)}spectric-query .autocomplete .option{border-bottom:1px solid transparent;padding:8px}.query-bar-date-quick-select{display:flex;justify-content:space-evenly}spectric-pagination .spectric-pagination-container{display:flex;justify-content:space-between;align-items:center}spectric-pagination .spectric-pagination-text{flex-grow:1;text-align:center}spectric-table{display:flex;flex-direction:column;overflow:hidden}spectric-table .table-wrapper{overflow:auto;flex-grow:1}spectric-table tr{text-align:center}spectric-table
|
|
1
|
+
spectric-input{--input-color: var(--spectric-input-color, #f4f4f4);--border-radius: var(--spectric-border-radius, .4em);--input-bottom: var(--spectric-input-bottom, var(--spectric-button-primary, #a8a8a8));--input-bottom-focused: var(--primary, #1ea7fd);--text-on-color: var(--spectric-text-on-color, #ffffff);--text-on-color-disabled: var(--spectric-text-on-color-disabled, #8d8d8d);--text-placeholder: rgba(22, 22, 22, .4);--text-primary: var(--spectric-text-primary, #161616);--text-secondary: var(--spectric-text-secondary, #525252)}spectric-input .inputWrapper{color:var(--text-secondary)}spectric-input .inputWrapper input{box-sizing:border-box;margin:0;vertical-align:baseline;font-size:.875rem;font-weight:400;line-height:1.28572;letter-spacing:.16px;outline:transparent solid 2px;outline-offset:-2px;border:none;padding:0 1rem;background-color:var(--input-color);color:var(--text-primary, #161616);font-family:inherit;inline-size:100%;block-size:2.5rem}spectric-input .inputWrapper .inputContainer:active:after,spectric-input .inputContainer:focus-within:after{border-bottom-color:var(--input-bottom-focused);width:calc(100% - 5px);transition:width .4s ease-in-out}spectric-input .inputWrapper input:read-only{background-color:transparent;border-bottom-color:var(--border-disabled)}spectric-input .inputContainer{position:relative;border-radius:var(--border-radius);overflow:hidden}spectric-input .inputContainer:after{content:"";width:0px;transition:background-color .4s cubic-bezier(.2,0,.38,.9),border-bottom-color .4s cubic-bezier(.2,0,.38,.9);border-bottom-color:var(--input-bottom);border-bottom-style:solid;border-bottom-width:1px;position:absolute;left:2.5px;bottom:0}spectric-input #helper-text{height:18px}spectric-input[variant=password] spectric-button{position:absolute;right:4px;bottom:3px}spectric-input .checkbox{display:flex;justify-self:center}spectric-query{font-family:monospace}spectric-query .autocomplete{color:var(--spectric-text-primary, #161616);border-radius:0em 0em var(--spectric-border-radius, .4em) var(--spectric-border-radius, .4em);background-color:var(--spectric-background, #ffffff);border:1px solid var(--spectric-background-hover, rgba(141, 141, 141, .12));max-height:300px;border-top:0px;margin:-18px 0 0;position:fixed;top:anchor(bottom);justify-self:anchor-center;text-align:center}spectric-query .autocomplete .optiontype{float:left;max-width:10px}spectric-query .autocomplete .label{position:absolute;right:0}spectric-query .autocomplete .option.active,spectric-query .autocomplete .option:hover{background-color:var(--spectric-background-hover, rgba(141, 141, 141, .12));border-bottom:1px solid var(--primary, #1ea7fd)}spectric-query .autocomplete .option{border-bottom:1px solid transparent;padding:8px}.query-bar-date-quick-select{display:flex;justify-content:space-evenly}spectric-pagination .spectric-pagination-container{display:flex;justify-content:space-between;align-items:center}spectric-pagination .spectric-pagination-text{flex-grow:1;text-align:center}spectric-table{display:flex;flex-direction:column;overflow:hidden}spectric-table .table-wrapper{overflow:auto;flex-grow:1;position:relative}spectric-table tr{text-align:center}spectric-table tr.odd{background-color:color-mix(in srgb,var(--spectric-primary, #1ea7fd),transparent 90%)}spectric-table tr:hover{background-color:color-mix(in srgb,var(--spectric-primary, #1ea7fd),transparent 70%)}spectric-table-header{display:table-header-group;font-weight:700;position:sticky;top:0;left:0;z-index:1;background:var(--spectric-background, #ffffff)}spectric-table-header td{vertical-align:middle}spectric-table tr{line-height:var(--rowHeight)}spectric-table td{height:var(--rowHeight)}spectric-table-header .header-contents{position:relative}spectric-table-header .header-contents .sort-direction{position:absolute;right:0}spectric-table-header .header-contents.sortable{cursor:pointer}spectric-table-header .header-contents.sortable:hover .sort-direction.none:before{content:"⮁"}spectric-table div[role=table]{display:table;min-width:100%}spectric-table-cell{display:contents;vertical-align:middle}spectric-table-cell td{position:relative}spectric-table td:hover:has(.filterable){border:1px solid var(--spectric-primary, #1ea7fd)}spectric-table td{border:1px solid transparent}spectric-table-cell .table-cell-actions{position:absolute;display:flex;width:100%;flex-direction:row-reverse;visibility:hidden;top:-10px}spectric-table-cell td:hover .table-cell-actions{visibility:unset}spectric-table .table-checkbox-single spectric-button{--button-border-radius: 50%}spectric-input.table-checkbox-single[checked] spectric-button{--text-on-color: transparent;border-radius:50%;position:relative}spectric-input.table-checkbox-single[checked] spectric-button:before{position:absolute;content:" ";height:50%;width:50%;left:25%;top:25%;border-radius:50%;z-index:1;box-shadow:0 0 0 4px var(--input-color)}spectric-table-body{display:table-row-group}spectric-table-virtual-body{display:contents}spectric-table-virtual-body .virtual-scroll-spacer td{padding:0;border:0px}.spectric-tooltip-portal{position:fixed;z-index:9999;pointer-events:none;--spectric-tooltip-background: color-mix(in srgb,var(--spectric-background-inverse,#f4f4f4) 100%,var(--spectric-primary,#1ea7fd) 90%) }.spectric-tooltip-portal .tooltip-container{display:flex;justify-content:center;align-items:center}.spectric-tooltip-portal.top .tooltip-container{flex-direction:column-reverse}.spectric-tooltip-portal.bottom .tooltip-container{flex-direction:column}.spectric-tooltip-portal.left .tooltip-container{flex-direction:row-reverse}.spectric-tooltip-portal .tooltip-content{background:var(--spectric-tooltip-background);border-radius:var(--spectric-border-radius,.4em);box-shadow:0 0 .01em .01em color-mix(in srgb,var(--spectric-background-hover,rgba(141, 141, 141, .12)) 90%,var(--spectric-text-on-color,#ffffff) 90%);padding:.2em;color:var(--spectric-text-on-color,#ffffff)}.spectric-tooltip-portal .tooltip-caret{background:var(--spectric-tooltip-background)}.spectric-tooltip-portal.top .tooltip-caret,.spectric-tooltip-portal.bottom .tooltip-caret{inline-size:.75rem;block-size:.374rem}.spectric-tooltip-portal.left .tooltip-caret,.spectric-tooltip-portal.right .tooltip-caret{inline-size:.375rem;block-size:.75rem}.spectric-tooltip-portal.top .tooltip-caret{clip-path:polygon(0 0,50% 100%,100% 0)}.spectric-tooltip-portal.bottom .tooltip-caret{clip-path:polygon(0 100%,50% 0,100% 100%)}.spectric-tooltip-portal.left .tooltip-caret{clip-path:polygon(0 0,100% 50%,0 100%)}.spectric-tooltip-portal.right .tooltip-caret{clip-path:polygon(0 50%,100% 0,100% 100%)}
|
package/package.json
CHANGED
|
@@ -3,16 +3,17 @@ import { LitElement } from "lit-element/lit-element.js";
|
|
|
3
3
|
export interface IDisposable {
|
|
4
4
|
dispose(): void;
|
|
5
5
|
}
|
|
6
|
+
type DisposableTarget = HTMLElement | Promise<HTMLElement> | (() => HTMLElement)
|
|
7
|
+
let listeners = 0;
|
|
6
8
|
class DomListener implements IDisposable {
|
|
7
9
|
|
|
8
10
|
private _handler?: (e: any) => void;
|
|
9
11
|
private _node?: EventTarget;
|
|
10
|
-
private __target?: EventTarget | Promise<EventTarget>
|
|
11
12
|
private readonly _type: string;
|
|
12
13
|
private readonly _options: boolean | AddEventListenerOptions;
|
|
13
14
|
|
|
14
|
-
constructor(node:
|
|
15
|
-
|
|
15
|
+
constructor(node: DisposableTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {
|
|
16
|
+
|
|
16
17
|
this._handler = handler;
|
|
17
18
|
this._type = type;
|
|
18
19
|
this._handler = handler;
|
|
@@ -26,10 +27,15 @@ class DomListener implements IDisposable {
|
|
|
26
27
|
this._node = targetNode
|
|
27
28
|
this._node.addEventListener(this._type, this._handler, this._options);
|
|
28
29
|
})
|
|
30
|
+
} else if (typeof node === "function") {
|
|
31
|
+
this._node = node()
|
|
32
|
+
this._node.addEventListener(this._type, this._handler, this._options);
|
|
29
33
|
} else {
|
|
30
34
|
this._node = node
|
|
31
35
|
this._node.addEventListener(this._type, this._handler, this._options);
|
|
32
36
|
}
|
|
37
|
+
listeners += 1
|
|
38
|
+
//console.log(listeners)
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
dispose(): void {
|
|
@@ -38,19 +44,19 @@ class DomListener implements IDisposable {
|
|
|
38
44
|
return;
|
|
39
45
|
}
|
|
40
46
|
if (this._node) {
|
|
41
|
-
|
|
47
|
+
listeners -= 1
|
|
42
48
|
this._node.removeEventListener(this._type, this._handler, this._options);
|
|
43
49
|
}
|
|
44
50
|
// Prevent leakers from holding on to the dom or handler func
|
|
45
|
-
this.__target = undefined;
|
|
46
51
|
this._node = undefined;
|
|
47
52
|
this._handler = undefined;
|
|
53
|
+
//console.log(listeners)
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
export class DisposableElement extends LitElement {
|
|
51
57
|
private readonly _disposables = new Set<IDisposable>();
|
|
52
58
|
private _isDisposed = false;
|
|
53
|
-
private _disposableListeners: { target:
|
|
59
|
+
private _disposableListeners: { target: DisposableTarget, event: string, handler: any }[] = []
|
|
54
60
|
private _connected: boolean = false;
|
|
55
61
|
/**
|
|
56
62
|
* Creates listeners on a target that will automatically get cleaned up when the element is removed from the DOM. This prevents memory leaks.
|
|
@@ -58,9 +64,9 @@ export class DisposableElement extends LitElement {
|
|
|
58
64
|
* @param event The event name
|
|
59
65
|
* @param handler The event handler
|
|
60
66
|
*/
|
|
61
|
-
public addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(target:
|
|
62
|
-
public addDisposableListener<K extends keyof SpectricGlobalEvents>(target:
|
|
63
|
-
public addDisposableListener(target:
|
|
67
|
+
public addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(target: DisposableTarget, event: K, handler: (event: GlobalEventHandlersEventMap[K]) => void): void
|
|
68
|
+
public addDisposableListener<K extends keyof SpectricGlobalEvents>(target: DisposableTarget, event: K, handler: SpectricGlobalEvents[K]): void
|
|
69
|
+
public addDisposableListener(target: DisposableTarget, event: string, handler: any): void {
|
|
64
70
|
let exists = this._disposableListeners.find(d => d.event === event && d.target === target && d.handler === handler)
|
|
65
71
|
if (exists) {
|
|
66
72
|
console.warn("Event handler already exists best practice is to add the this in the constructor")
|
|
@@ -12,13 +12,13 @@ export interface BitDisplayProps {
|
|
|
12
12
|
/** Array buffer to display */
|
|
13
13
|
arrayBuffer: ArrayBuffer;
|
|
14
14
|
/** Bits per line */
|
|
15
|
-
frameWidth
|
|
15
|
+
frameWidth?: number;
|
|
16
16
|
/** How many pixels per bit */
|
|
17
|
-
scale
|
|
17
|
+
scale?: number;
|
|
18
18
|
/** Width of the display canvas */
|
|
19
|
-
width
|
|
19
|
+
width?: number;
|
|
20
20
|
/** Height of the display canvas */
|
|
21
|
-
height
|
|
21
|
+
height?: number;
|
|
22
22
|
|
|
23
23
|
}
|
|
24
24
|
type Position = {
|
|
@@ -340,7 +340,7 @@ export class BitDisplayCanvas extends DisposableElement implements BitDisplayPro
|
|
|
340
340
|
id="viewport"
|
|
341
341
|
${ref(this.refs.viewport)}
|
|
342
342
|
@scroll=${this.handleScroll}
|
|
343
|
-
style=${`width:${width}px;height:${height}px;overflow:auto;position:relative`}
|
|
343
|
+
style=${`width:${width + SCROLLBAR_SIZE.width}px;height:${height + SCROLLBAR_SIZE.height}px;overflow:auto;position:relative`}
|
|
344
344
|
>
|
|
345
345
|
<div
|
|
346
346
|
id="fakescrolldiv"
|
|
@@ -350,8 +350,8 @@ export class BitDisplayCanvas extends DisposableElement implements BitDisplayPro
|
|
|
350
350
|
</div>
|
|
351
351
|
<canvas
|
|
352
352
|
${ref(this.refs.canvas)}
|
|
353
|
-
width=${width
|
|
354
|
-
height=${height
|
|
353
|
+
width=${width}
|
|
354
|
+
height=${height}
|
|
355
355
|
></canvas>
|
|
356
356
|
`
|
|
357
357
|
|
package/src/components/Button.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface ButtonProps {
|
|
|
29
29
|
/** What background color to use */
|
|
30
30
|
backgroundColor?: string;
|
|
31
31
|
/** How large should the button be? */
|
|
32
|
-
size
|
|
32
|
+
size?: ButtonSizesTypes;
|
|
33
33
|
label?: string,
|
|
34
34
|
/* should the button be disabled*/
|
|
35
35
|
disabled?: boolean;
|
package/src/components/Header.ts
CHANGED
package/src/components/input.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html, LitElement, TemplateResult } from 'lit';
|
|
1
|
+
import { html, LitElement, PropertyValues, TemplateResult } from 'lit';
|
|
2
2
|
import "./input.css"
|
|
3
3
|
import { customElement, property, query } from 'lit/decorators.js';
|
|
4
4
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
@@ -23,32 +23,32 @@ export enum InputVariants {
|
|
|
23
23
|
type InputVariantsTypes = `${InputVariants}`
|
|
24
24
|
export interface InputProps {
|
|
25
25
|
/** Input type */
|
|
26
|
-
variant
|
|
26
|
+
variant?: InputVariantsTypes;
|
|
27
27
|
/**Label to display above the input */
|
|
28
|
-
label
|
|
28
|
+
label?: string,
|
|
29
29
|
/**placeholder text to display*/
|
|
30
|
-
placeholder
|
|
30
|
+
placeholder?: string,
|
|
31
31
|
/* should be disabled?*/
|
|
32
|
-
disabled
|
|
32
|
+
disabled?: boolean,
|
|
33
33
|
/* should be readonly*/
|
|
34
|
-
readonly
|
|
34
|
+
readonly?: boolean,
|
|
35
35
|
/**
|
|
36
36
|
* The helper text.
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
-
helperText
|
|
39
|
+
helperText?: string,
|
|
40
40
|
/**
|
|
41
41
|
* Specify if the currently value is invalid.
|
|
42
42
|
*/
|
|
43
|
-
invalid
|
|
43
|
+
invalid?: boolean,
|
|
44
44
|
/**
|
|
45
45
|
* Message which is displayed if the value is invalid.
|
|
46
46
|
*/
|
|
47
|
-
invalidText
|
|
47
|
+
invalidText?: string | TemplateResult<1>,
|
|
48
48
|
/**
|
|
49
49
|
* Max character count allowed for input. This is needed in order for enableCounter to display
|
|
50
50
|
*/
|
|
51
|
-
maxCount
|
|
51
|
+
maxCount?: number,
|
|
52
52
|
/**
|
|
53
53
|
* Boolean property to set the required status
|
|
54
54
|
*/
|
|
@@ -71,7 +71,7 @@ export interface InputProps {
|
|
|
71
71
|
/**
|
|
72
72
|
* The sets the autocomplete for the input.
|
|
73
73
|
*/
|
|
74
|
-
autocomplete
|
|
74
|
+
autocomplete?: HTMLInputElement['autocomplete'];
|
|
75
75
|
}
|
|
76
76
|
@customElement('spectric-input')
|
|
77
77
|
export class SpectricInput extends LitElement implements InputProps {
|
|
@@ -148,7 +148,7 @@ export class SpectricInput extends LitElement implements InputProps {
|
|
|
148
148
|
@property()
|
|
149
149
|
pattern = '';
|
|
150
150
|
@property({ type: Number, reflect: true })
|
|
151
|
-
maxCount:
|
|
151
|
+
maxCount: number = 0;
|
|
152
152
|
/**
|
|
153
153
|
* The internal value.
|
|
154
154
|
*/
|
|
@@ -158,7 +158,7 @@ export class SpectricInput extends LitElement implements InputProps {
|
|
|
158
158
|
* The sets the autocomplete for the input.
|
|
159
159
|
*/
|
|
160
160
|
@property({ reflect: true })
|
|
161
|
-
autocomplete: HTMLInputElement['autocomplete'] = "";
|
|
161
|
+
autocomplete: HTMLInputElement['autocomplete'] = "off";
|
|
162
162
|
get selectionStart() {
|
|
163
163
|
if (!this._input) {
|
|
164
164
|
return null
|
|
@@ -227,6 +227,11 @@ export class SpectricInput extends LitElement implements InputProps {
|
|
|
227
227
|
this._showPassword = !this._showPassword;
|
|
228
228
|
this.requestUpdate()
|
|
229
229
|
}
|
|
230
|
+
protected updated(changedProperties: PropertyValues): void {
|
|
231
|
+
if (changedProperties.has("checked")) {
|
|
232
|
+
this.dispatchEvent(new Event("change", { bubbles: true }))
|
|
233
|
+
}
|
|
234
|
+
}
|
|
230
235
|
protected render(): unknown {
|
|
231
236
|
switch (this.variant) {
|
|
232
237
|
case InputVariants.Text:
|
|
@@ -303,7 +308,6 @@ export class SpectricInput extends LitElement implements InputProps {
|
|
|
303
308
|
<spectric-button @click=${() => {
|
|
304
309
|
this.checked = !this.checked;
|
|
305
310
|
this.value = Boolean(this.checked);
|
|
306
|
-
this.dispatchEvent(new Event("change", { bubbles: true }))
|
|
307
311
|
}} icon size=${this.size || "xxsmall"} variant=${this.checked ? "primary" : "secondary"}>${this.checked ? '✓' : "\u00A0"}</spectric-button>
|
|
308
312
|
${this.invalid || this.helperText ? html`<spectric-tooltip text=${this.invalid || this.helperText}></spectric-tooltip>` : null}
|
|
309
313
|
${this.label}
|
|
@@ -12,15 +12,15 @@ export enum Orientations {
|
|
|
12
12
|
}
|
|
13
13
|
export interface SplitViewProps {
|
|
14
14
|
/** Controls the orientation of the splitter handle */
|
|
15
|
-
orientation
|
|
15
|
+
orientation?: `${Orientations}`;
|
|
16
16
|
/** the percentage to split the view default: 50*/
|
|
17
17
|
percentage?: number
|
|
18
18
|
/** Should the splitter handle be invisible? */
|
|
19
19
|
invisible?: boolean
|
|
20
20
|
/** Clamps the minimum split percentage default: 10 */
|
|
21
|
-
min
|
|
21
|
+
min?: number
|
|
22
22
|
/** Clamps the maximum split percentage default: 90 */
|
|
23
|
-
max
|
|
23
|
+
max?: number
|
|
24
24
|
/** save and load split state to localstorage splitter must have an id attribute default: true */
|
|
25
25
|
useSavedState?: boolean
|
|
26
26
|
}
|
|
@@ -40,8 +40,8 @@ export class SplitView extends DisposableElement implements SplitViewProps {
|
|
|
40
40
|
@property({ type: Boolean }) invisible: SplitViewProps['invisible'] = false;
|
|
41
41
|
static styles = style
|
|
42
42
|
|
|
43
|
-
@property({ type: Number, reflect: true }) min:
|
|
44
|
-
@property({ type: Number, reflect: true }) max:
|
|
43
|
+
@property({ type: Number, reflect: true }) min: number = 10;
|
|
44
|
+
@property({ type: Number, reflect: true }) max: number = 90;
|
|
45
45
|
@property({ type: Boolean, reflect: true }) useSavedState: SplitViewProps['useSavedState'] = true;
|
|
46
46
|
|
|
47
47
|
@state()
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { html, LitElement } from 'lit';
|
|
1
|
+
import { html, LitElement, PropertyValues } from 'lit';
|
|
2
2
|
import { customElement, property, } from 'lit/decorators.js';
|
|
3
3
|
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
4
4
|
export const TableBodyElementTag = "spectric-table-body"
|
|
5
5
|
import "./cell"
|
|
6
6
|
import { ColumnSettings, TableElement } from './table';
|
|
7
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
7
8
|
|
|
8
9
|
interface BodyProps<T> {
|
|
9
10
|
columns: ColumnSettings<T>[]
|
|
@@ -24,14 +25,21 @@ export class TableBodyElement<T> extends LitElement implements BodyProps<T> {
|
|
|
24
25
|
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
25
26
|
return this
|
|
26
27
|
}
|
|
28
|
+
protected firstUpdated(_changedProperties: PropertyValues): void {
|
|
29
|
+
if (this.data.length > 100) {
|
|
30
|
+
console.warn("Table is rendering excessive amounts of data to the DOM you should set rowHeight and use a virtualized scroll or use pagination")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
27
33
|
protected render(): unknown {
|
|
28
34
|
return html`
|
|
29
35
|
<body>
|
|
30
|
-
${this.data
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
36
|
+
${repeat(this.data, (row, index) => html`
|
|
37
|
+
<tr class="${index % 2 === 0 ? "odd" : ""}">
|
|
38
|
+
${repeat(this.columns, (col) => {
|
|
39
|
+
return html`<spectric-table-cell .column=${col} .index=${index} .row=${row} .columns=${this.columns}></spectric-table-cell>`
|
|
34
40
|
})}
|
|
41
|
+
</tr>`)}
|
|
42
|
+
|
|
35
43
|
</body>
|
|
36
44
|
`
|
|
37
45
|
|
|
@@ -23,6 +23,9 @@ export type FilterEvent<T> = {
|
|
|
23
23
|
export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
24
24
|
@property({ type: Object, attribute: false })
|
|
25
25
|
row!: T;
|
|
26
|
+
|
|
27
|
+
@property({ type: Number, attribute: false })
|
|
28
|
+
index!: number;
|
|
26
29
|
@property({ type: Object, attribute: false })
|
|
27
30
|
column!: ColumnSettings<T>;
|
|
28
31
|
columns!: ColumnSettings<T>[];
|
|
@@ -75,7 +78,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
75
78
|
protected render(): unknown {
|
|
76
79
|
let rendered
|
|
77
80
|
if (this.column.render) {
|
|
78
|
-
rendered = this.column.render(this.row, this.table)
|
|
81
|
+
rendered = this.column.render(this.row, this.index, this.table)
|
|
79
82
|
} else if (this.column.key && typeof this.row === 'object') {
|
|
80
83
|
rendered = rowGetValue(this.row as any, this.column.key)
|
|
81
84
|
} else {
|
|
@@ -37,7 +37,6 @@ export class TableHeaderElement<T> extends LitElement implements HeaderProps<T>
|
|
|
37
37
|
this.dispatchEvent(new CustomEvent<ColumnSettings<T>>("sortChange", { detail: column }))
|
|
38
38
|
}
|
|
39
39
|
protected render(): unknown {
|
|
40
|
-
|
|
41
40
|
return html`
|
|
42
41
|
<tr>
|
|
43
42
|
${this.columns.map(column => {
|
|
@@ -48,9 +47,15 @@ export class TableHeaderElement<T> extends LitElement implements HeaderProps<T>
|
|
|
48
47
|
if (column.sortable) {
|
|
49
48
|
classes.push("sortable")
|
|
50
49
|
}
|
|
50
|
+
let columnWidth = column.width ? `width:${column.width}px;` : ""
|
|
51
51
|
let sortDirection = column.sortDirection === TableSortDirection.ascending ? `🠉` : column.sortDirection == TableSortDirection.decending ? `🠋` : ``
|
|
52
52
|
let sortClass = column.sortDirection || TableSortDirection.none
|
|
53
|
-
return html
|
|
53
|
+
return html`
|
|
54
|
+
<td @click=${() => this._handleSortChange(column)} style="${columnWidth}">
|
|
55
|
+
<div class=${classes.join(" ")} >${column.title || column.key}
|
|
56
|
+
<span class="sort-direction ${sortClass}">${sortDirection}</span>
|
|
57
|
+
</div>
|
|
58
|
+
</td>`
|
|
54
59
|
})}
|
|
55
60
|
</tr>
|
|
56
61
|
`
|
|
@@ -6,15 +6,16 @@ spectric-table{
|
|
|
6
6
|
spectric-table .table-wrapper{
|
|
7
7
|
overflow: auto;
|
|
8
8
|
flex-grow: 1;
|
|
9
|
+
position: relative;
|
|
9
10
|
}
|
|
10
11
|
spectric-table tr{
|
|
11
12
|
text-align: center;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
spectric-table
|
|
15
|
+
spectric-table tr.odd{
|
|
15
16
|
background-color: color-mix(in srgb, var(--spectric-primary, #1ea7fd), transparent 90%);
|
|
16
17
|
}
|
|
17
|
-
spectric-table
|
|
18
|
+
spectric-table tr:hover{
|
|
18
19
|
background-color: color-mix(in srgb, var(--spectric-primary, #1ea7fd), transparent 70%)
|
|
19
20
|
}
|
|
20
21
|
spectric-table-header{
|
|
@@ -29,7 +30,12 @@ spectric-table-header{
|
|
|
29
30
|
spectric-table-header td {
|
|
30
31
|
vertical-align: middle;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
spectric-table tr {
|
|
34
|
+
line-height: var(--rowHeight);
|
|
35
|
+
}
|
|
36
|
+
spectric-table td{
|
|
37
|
+
height: var(--rowHeight);
|
|
38
|
+
}
|
|
33
39
|
spectric-table-header .header-contents {
|
|
34
40
|
position: relative;
|
|
35
41
|
}
|
|
@@ -49,9 +55,7 @@ spectric-table div[role="table"]{
|
|
|
49
55
|
display: table;
|
|
50
56
|
min-width: 100%;
|
|
51
57
|
}
|
|
52
|
-
|
|
53
|
-
display: table-row-group;
|
|
54
|
-
}
|
|
58
|
+
|
|
55
59
|
spectric-table-cell{
|
|
56
60
|
display: contents;
|
|
57
61
|
vertical-align: middle;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { html, LitElement, TemplateResult } from 'lit';
|
|
1
|
+
import { html, LitElement, PropertyValues, render, TemplateResult } from 'lit';
|
|
2
2
|
import "../pagination";
|
|
3
3
|
import "./header"
|
|
4
4
|
import "./body"
|
|
5
5
|
import { customElement, property, state, } from 'lit/decorators.js';
|
|
6
6
|
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
7
|
+
import "./virtualBody"
|
|
7
8
|
import "./table.css"
|
|
8
9
|
export const TableElementTag = "spectric-table"
|
|
9
10
|
import { spreadProps } from '../../utils/spread';
|
|
10
11
|
import { PaginationChangeProps, PaginationProps } from '../pagination';
|
|
11
12
|
import { FilterEvent } from './cell';
|
|
12
13
|
import { createSortChain } from './sorting';
|
|
14
|
+
|
|
13
15
|
export type { TableProps, TableEvents }
|
|
14
16
|
|
|
15
17
|
export type DomRenderable = HTMLElement | TemplateResult | string | number | null
|
|
@@ -45,7 +47,7 @@ export type ColumnSettings<T> = {
|
|
|
45
47
|
/**
|
|
46
48
|
* Render function to render a table cell for displaying custom html
|
|
47
49
|
*/
|
|
48
|
-
render?: (row: T, table: TableElement<T>) => DomRenderable
|
|
50
|
+
render?: (row: T, index: number, table: TableElement<T>) => DomRenderable
|
|
49
51
|
/**
|
|
50
52
|
* Custom comparator function for sorting
|
|
51
53
|
*/
|
|
@@ -60,6 +62,7 @@ interface TableProps<T> extends TableDataOptions<T> {
|
|
|
60
62
|
data: T[]
|
|
61
63
|
select: TableSelectOptionsTypes
|
|
62
64
|
sort?: TableSortOptionTypes
|
|
65
|
+
rowHeight?: number
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
type DomEvent<T> = Event & {
|
|
@@ -83,6 +86,12 @@ export class TableElement<T> extends LitElement implements TableProps<T> {
|
|
|
83
86
|
@property({ type: String, reflect: true })
|
|
84
87
|
sort: TableSortOptionTypes = TableSortOption.single;
|
|
85
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Needed for virtualization
|
|
91
|
+
*/
|
|
92
|
+
@property({ type: Number, reflect: true })
|
|
93
|
+
rowHeight: number = 25;
|
|
94
|
+
|
|
86
95
|
static getDefaultDataSorterAndPaginatior<T>(data: T[]) {
|
|
87
96
|
return (props: TableDataOptions<T>) => {
|
|
88
97
|
let sorts = props.columns.filter(column => column.sortable && column.sortDirection && column.sortDirection !== TableSortDirection.none)
|
|
@@ -166,37 +175,57 @@ export class TableElement<T> extends LitElement implements TableProps<T> {
|
|
|
166
175
|
}
|
|
167
176
|
this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }))
|
|
168
177
|
}
|
|
178
|
+
protected update(changedProperties: PropertyValues): void {
|
|
179
|
+
if (changedProperties.has("select")) {
|
|
180
|
+
if (this.select === "single" && this.selected.length > 1) {
|
|
181
|
+
this.selected = [this.selected[0]]
|
|
182
|
+
this.dispatchEvent(new CustomEvent("selected", { detail: [...this.selected] }))
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
super.update(changedProperties)
|
|
186
|
+
}
|
|
169
187
|
protected render(): unknown {
|
|
170
188
|
let columns = this.columns.filter(column => !column.hidden)
|
|
171
189
|
if (this.select !== TableSelectOptions.none) {
|
|
172
190
|
columns.unshift({
|
|
173
191
|
title: this.select === "multi" ? html`<spectric-input variant="checkbox" @change=${this._handleSelectAllChange} .helperText=${"Select All"}></spectric-input>` : null,
|
|
174
192
|
render: (row) => {
|
|
175
|
-
|
|
193
|
+
let container = document.createElement("div")
|
|
194
|
+
let checked = this.selected.includes(row)
|
|
195
|
+
let template = html`<spectric-input variant="checkbox" class="table-checkbox-${this.select}" ${spreadProps({ checked })} @change=${(e: DomEvent<HTMLInputElement>) => {
|
|
176
196
|
e.stopPropagation()
|
|
177
|
-
|
|
178
|
-
|
|
197
|
+
let index = this.selected.findIndex(value => value === row)
|
|
198
|
+
if (e.target.checked && index !== -1) {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
else if (!e.target.checked && index === -1) {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
else if (!e.target.checked && index !== -1) {
|
|
205
|
+
this.selected.splice(index, 1)
|
|
179
206
|
}
|
|
180
207
|
if (e.target.checked) {
|
|
181
|
-
this.
|
|
182
|
-
|
|
183
|
-
} else {
|
|
184
|
-
let index = this.selected.findIndex(value => value === row)
|
|
185
|
-
if (index !== -1) {
|
|
186
|
-
this.selected.splice(index, 1)
|
|
187
|
-
this.dispatchEvent(new CustomEvent("selected", { detail: this.selected }))
|
|
208
|
+
if (this.select === "single") {
|
|
209
|
+
this.selected = []
|
|
188
210
|
}
|
|
211
|
+
this.selected.push(row)
|
|
189
212
|
}
|
|
213
|
+
this.dispatchEvent(new CustomEvent("selected", { detail: [...this.selected] }))
|
|
190
214
|
}}></spectric-input>`
|
|
215
|
+
render(template, container)
|
|
216
|
+
return template
|
|
191
217
|
}
|
|
192
218
|
})
|
|
193
219
|
}
|
|
194
|
-
|
|
220
|
+
const tdBorderAndPadding = 4;
|
|
195
221
|
return html`
|
|
196
|
-
<div class="table-wrapper">
|
|
222
|
+
<div class="table-wrapper" style="--rowHeight:${this.rowHeight - tdBorderAndPadding}px">
|
|
197
223
|
<div role="table">
|
|
198
224
|
<spectric-table-header .columns=${columns} @sortChange=${this._handleSortChange}></spectric-table-header>
|
|
199
|
-
|
|
225
|
+
${this.rowHeight >= 25 && this.data.length >= 100 ?
|
|
226
|
+
html`<spectric-table-virtual-body .columns=${columns} .data=${this.data} .table=${this} .rowHeight=${this.rowHeight}></spectric-table-virtual-body>` :
|
|
227
|
+
html`<spectric-table-body .columns=${columns} .data=${this.data} .table=${this}></spectric-table-body>`
|
|
228
|
+
}
|
|
200
229
|
</div>
|
|
201
230
|
</div>
|
|
202
231
|
${this.pagination ? html`<spectric-pagination ${spreadProps(this.pagination)} @change=${this._handlePaginationChange}></spectric-pagination>` : null}
|
|
@@ -205,7 +234,7 @@ export class TableElement<T> extends LitElement implements TableProps<T> {
|
|
|
205
234
|
}
|
|
206
235
|
|
|
207
236
|
interface TableEvents {
|
|
208
|
-
'change': (event: CustomEvent<
|
|
237
|
+
'change': (event: CustomEvent<TableDataOptions<any>>) => void;
|
|
209
238
|
'filter': (event: CustomEvent<FilterEvent<any>>) => void;
|
|
210
239
|
}
|
|
211
240
|
|