@spectric/ui 0.0.10 → 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/pagination/pagination.d.ts +5 -5
- 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 +2 -0
- package/dist/components/table/header.d.ts +2 -1
- package/dist/components/table/sorting.d.ts +5 -0
- package/dist/components/table/table.d.ts +51 -14
- package/dist/components/table/virtualBody.d.ts +49 -0
- package/dist/components/tooltip/tooltip.d.ts +17 -12
- package/dist/custom-elements.json +50 -16
- package/dist/index.es.js +2099 -1867
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +128 -93
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/once.d.ts +1 -0
- package/dist/utils/spread.d.ts +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 -15
- package/src/components/pagination/pagination.ts +7 -7
- package/src/components/query_bar/QueryBar.ts +26 -21
- package/src/components/splitview/splitview.ts +5 -5
- package/src/components/table/body.ts +13 -5
- package/src/components/table/cell.ts +9 -7
- package/src/components/table/header.ts +28 -4
- package/src/components/table/sorting.ts +34 -0
- package/src/components/table/table.css +60 -4
- package/src/components/table/table.ts +149 -33
- package/src/components/table/virtualBody.css +13 -0
- package/src/components/table/virtualBody.ts +127 -0
- package/src/components/tooltip/tooltip.ts +38 -32
- 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/ExampleContent.ts +15 -8
- package/src/stories/fixtures/data.ts +21 -10
- package/src/stories/pagination.stories.ts +2 -1
- package/src/stories/table.stories.ts +27 -5
- package/src/utils/once.ts +12 -0
- package/src/utils/spread.ts +3 -3
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}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%)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function once(func: Function): (...args: any[]) => any;
|
package/dist/utils/spread.d.ts
CHANGED
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,8 +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
|
-
console.log(this.checked, this.value)
|
|
307
|
-
this.dispatchEvent(new Event("change", { bubbles: true }))
|
|
308
311
|
}} icon size=${this.size || "xxsmall"} variant=${this.checked ? "primary" : "secondary"}>${this.checked ? '✓' : "\u00A0"}</spectric-button>
|
|
309
312
|
${this.invalid || this.helperText ? html`<spectric-tooltip text=${this.invalid || this.helperText}></spectric-tooltip>` : null}
|
|
310
313
|
${this.label}
|
|
@@ -8,12 +8,12 @@ import { ButtonSizesTypes } from '../Button';
|
|
|
8
8
|
export type { PaginationProps, PaginationChangeProps, PaginationEvents }
|
|
9
9
|
|
|
10
10
|
interface PaginationChangeProps {
|
|
11
|
-
page
|
|
12
|
-
pageSize
|
|
11
|
+
page?: number;
|
|
12
|
+
pageSize?: number;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
interface PaginationProps extends PaginationChangeProps {
|
|
16
|
-
size
|
|
16
|
+
size?: ButtonSizesTypes
|
|
17
17
|
totalItems?: number
|
|
18
18
|
pageSizeOptions?: number[]
|
|
19
19
|
}
|
|
@@ -93,8 +93,8 @@ export class PaginationElement extends LitElement implements PaginationProps {
|
|
|
93
93
|
${pageText}
|
|
94
94
|
</div>
|
|
95
95
|
<div>
|
|
96
|
-
<spectric-button size=${this.size} ?disabled=${this.page === 1} @click=${this._handlePageDown} icon
|
|
97
|
-
<spectric-button size=${this.size} ?disabled=${nextPageDisabled} @click=${this._handlePageUp} icon
|
|
96
|
+
<spectric-button size=${this.size} ?disabled=${this.page === 1} @click=${this._handlePageDown} icon>🠈</spectric-button>
|
|
97
|
+
<spectric-button size=${this.size} ?disabled=${nextPageDisabled} @click=${this._handlePageUp} icon>🠊</spectric-button>
|
|
98
98
|
</div>
|
|
99
99
|
</div>
|
|
100
100
|
`: null}
|
|
@@ -115,7 +115,7 @@ declare global {
|
|
|
115
115
|
namespace JSX {
|
|
116
116
|
interface IntrinsicElements {
|
|
117
117
|
/**
|
|
118
|
-
* @see {@link
|
|
118
|
+
* @see {@link PaginationElement}
|
|
119
119
|
*/
|
|
120
120
|
[PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>;
|
|
121
121
|
}
|
|
@@ -124,7 +124,7 @@ declare global {
|
|
|
124
124
|
namespace JSX {
|
|
125
125
|
interface IntrinsicElements {
|
|
126
126
|
/**
|
|
127
|
-
* @see {@link
|
|
127
|
+
* @see {@link PaginationElement}
|
|
128
128
|
*/
|
|
129
129
|
[PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>
|
|
130
130
|
}
|
|
@@ -133,32 +133,34 @@ export class SpectricQuery extends LitElement implements IQueryProps {
|
|
|
133
133
|
protected _input!: SpectricInput;
|
|
134
134
|
_parseQuery = (e: InputEvent | undefined = undefined) => {
|
|
135
135
|
let ast;
|
|
136
|
-
if (e && e?.currentTarget
|
|
136
|
+
if (e && e?.currentTarget) {
|
|
137
137
|
this.value = (e.currentTarget as HTMLInputElement).value
|
|
138
138
|
}
|
|
139
|
-
if (this.value
|
|
140
|
-
|
|
139
|
+
if (this.value) {
|
|
140
|
+
try {
|
|
141
|
+
if (e && e.data == "(") {
|
|
142
|
+
//Auto close parentheses or parsing and suggestions fail
|
|
143
|
+
this.value = this.value + " )"
|
|
144
|
+
this._input.setSelectionRange(this.value.length - 2, this.value.length - 2)
|
|
145
|
+
}
|
|
146
|
+
let value = this.value;
|
|
147
|
+
if (this._input.selectionStart !== null) {
|
|
148
|
+
value = value.substring(0, this._input.selectionStart) + "@kuery-cursor@" + value.substring(this._input.selectionStart)
|
|
149
|
+
}
|
|
150
|
+
//FIXME: make auto complete work well.
|
|
151
|
+
let suggestions = kuery.parse(value, { parseCursor: true, cursorSymbol: "@kuery-cursor@", allowLeadingWildcards: false }) as unknown as Suggestion;
|
|
152
|
+
this.autoComplete(suggestions)
|
|
153
|
+
} catch (error: any) {
|
|
154
|
+
// this.completions = []
|
|
155
|
+
// this._input.invalid = true;
|
|
156
|
+
// let [expect, _, arrow] = e.message.split("\n")
|
|
157
|
+
// this._input.invalidText = html`  ${arrow} ${expect}`;
|
|
158
|
+
return
|
|
159
|
+
}
|
|
141
160
|
}
|
|
142
161
|
try {
|
|
143
|
-
if (e && e.data == "(") {
|
|
144
|
-
//Auto close parentheses or parsing and suggestions fail
|
|
145
|
-
this.value = this.value + " )"
|
|
146
|
-
this._input.setSelectionRange(this.value.length - 2, this.value.length - 2)
|
|
147
|
-
}
|
|
148
|
-
let value = this.value;
|
|
149
|
-
if (this._input.selectionStart !== null) {
|
|
150
|
-
value = value.substring(0, this._input.selectionStart) + "@kuery-cursor@" + value.substring(this._input.selectionStart)
|
|
151
|
-
}
|
|
152
|
-
//FIXME: make auto complete work well.
|
|
153
|
-
let suggestions = kuery.parse(value, { parseCursor: true, cursorSymbol: "@kuery-cursor@", allowLeadingWildcards: false }) as unknown as Suggestion;
|
|
154
|
-
this.autoComplete(suggestions)
|
|
155
|
-
|
|
156
162
|
ast = kuery.parse(this.value, { allowLeadingWildcards: false });
|
|
157
|
-
} catch (
|
|
158
|
-
// this.completions = []
|
|
159
|
-
// this._input.invalid = true;
|
|
160
|
-
// let [expect, _, arrow] = e.message.split("\n")
|
|
161
|
-
// this._input.invalidText = html`  ${arrow} ${expect}`;
|
|
163
|
+
} catch (error: any) {
|
|
162
164
|
return
|
|
163
165
|
}
|
|
164
166
|
let output
|
|
@@ -288,6 +290,8 @@ export class SpectricQuery extends LitElement implements IQueryProps {
|
|
|
288
290
|
} else {
|
|
289
291
|
this.value = prefix + this.value.substring(completion.end)
|
|
290
292
|
}
|
|
293
|
+
//Important if the underlying inputs value hasn't been set the setSelectionRange will fail to set a range greater than the inputs current value
|
|
294
|
+
this._input.value = this.value
|
|
291
295
|
this._input.setSelectionRange(insertIndex, insertIndex)
|
|
292
296
|
if (completion.onSelect) {
|
|
293
297
|
let value = await completion.onSelect()
|
|
@@ -299,6 +303,7 @@ export class SpectricQuery extends LitElement implements IQueryProps {
|
|
|
299
303
|
this.completionIndex = 0;
|
|
300
304
|
this.completions = []
|
|
301
305
|
this._parseQuery()
|
|
306
|
+
this._input.focus()
|
|
302
307
|
}
|
|
303
308
|
_handleArrows = (e: KeyboardEvent) => {
|
|
304
309
|
if (e.key === "Escape") {
|
|
@@ -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>[];
|
|
@@ -43,7 +46,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
43
46
|
_handleFilterOut = () => {
|
|
44
47
|
let value = undefined;
|
|
45
48
|
if (this.column.key && typeof this.row === "object") {
|
|
46
|
-
value =
|
|
49
|
+
value = rowGetValue(this.row as Record<any, any>, this.column.key)
|
|
47
50
|
}
|
|
48
51
|
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
|
|
49
52
|
composed: true,
|
|
@@ -59,7 +62,7 @@ export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
|
59
62
|
_handleFilterFor = () => {
|
|
60
63
|
let value = undefined;
|
|
61
64
|
if (this.column.key && typeof this.row === "object") {
|
|
62
|
-
value =
|
|
65
|
+
value = rowGetValue(this.row as Record<any, any>, this.column.key)
|
|
63
66
|
}
|
|
64
67
|
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
|
|
65
68
|
composed: true,
|
|
@@ -75,10 +78,9 @@ 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
|
-
|
|
81
|
-
rendered = getValue(this.row as any, this.column.key)
|
|
83
|
+
rendered = rowGetValue(this.row as any, this.column.key)
|
|
82
84
|
} else {
|
|
83
85
|
rendered = html`error`
|
|
84
86
|
}
|
|
@@ -134,11 +136,11 @@ declare global {
|
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
const
|
|
139
|
+
export const rowGetValue = (context: Record<string, any>, key: string) => {
|
|
138
140
|
let path = key.split(".")
|
|
139
141
|
let value = context[path[0]]
|
|
140
142
|
if (path.length > 1) {
|
|
141
|
-
value =
|
|
143
|
+
value = rowGetValue(value, path.slice(1).join("."))
|
|
142
144
|
}
|
|
143
145
|
return value
|
|
144
146
|
}
|
|
@@ -4,7 +4,7 @@ import { customElement, property, } from 'lit/decorators.js';
|
|
|
4
4
|
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
5
5
|
import "./table.css"
|
|
6
6
|
export const TableHeaderElementTag = "spectric-table-header"
|
|
7
|
-
import { ColumnSettings } from './table';
|
|
7
|
+
import { ColumnSettings, TableSortDirection } from './table';
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
interface HeaderProps<T> {
|
|
@@ -22,8 +22,21 @@ export class TableHeaderElement<T> extends LitElement implements HeaderProps<T>
|
|
|
22
22
|
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
23
23
|
return this
|
|
24
24
|
}
|
|
25
|
+
_handleSortChange = (column: ColumnSettings<T>) => {
|
|
26
|
+
column = JSON.parse(JSON.stringify(column))// Clone the column to not mutate the original object
|
|
27
|
+
if (!column.sortable) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
if (column.sortDirection === TableSortDirection.none || column.sortDirection === undefined) {
|
|
31
|
+
column.sortDirection = TableSortDirection.ascending
|
|
32
|
+
} else if (column.sortDirection === TableSortDirection.ascending) {
|
|
33
|
+
column.sortDirection = TableSortDirection.decending
|
|
34
|
+
} else if (column.sortDirection === TableSortDirection.decending) {
|
|
35
|
+
column.sortDirection = TableSortDirection.none
|
|
36
|
+
}
|
|
37
|
+
this.dispatchEvent(new CustomEvent<ColumnSettings<T>>("sortChange", { detail: column }))
|
|
38
|
+
}
|
|
25
39
|
protected render(): unknown {
|
|
26
|
-
|
|
27
40
|
return html`
|
|
28
41
|
<tr>
|
|
29
42
|
${this.columns.map(column => {
|
|
@@ -31,7 +44,18 @@ export class TableHeaderElement<T> extends LitElement implements HeaderProps<T>
|
|
|
31
44
|
if (column.filterable) {
|
|
32
45
|
//classes.push("filterable")
|
|
33
46
|
}
|
|
34
|
-
|
|
47
|
+
if (column.sortable) {
|
|
48
|
+
classes.push("sortable")
|
|
49
|
+
}
|
|
50
|
+
let columnWidth = column.width ? `width:${column.width}px;` : ""
|
|
51
|
+
let sortDirection = column.sortDirection === TableSortDirection.ascending ? `🠉` : column.sortDirection == TableSortDirection.decending ? `🠋` : ``
|
|
52
|
+
let sortClass = column.sortDirection || TableSortDirection.none
|
|
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>`
|
|
35
59
|
})}
|
|
36
60
|
</tr>
|
|
37
61
|
`
|
|
@@ -39,7 +63,7 @@ export class TableHeaderElement<T> extends LitElement implements HeaderProps<T>
|
|
|
39
63
|
}
|
|
40
64
|
|
|
41
65
|
interface TableHeaderEvents {
|
|
42
|
-
'
|
|
66
|
+
'sortChange': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
declare global {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { once } from "../../utils/once";
|
|
2
|
+
import { rowGetValue } from "./cell";
|
|
3
|
+
import { ColumnSettings, TableSortDirection } from "./table";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a chain of sort functions so you can perform multi column sorting.
|
|
7
|
+
*/
|
|
8
|
+
export const createSortChain = <T>(sorts: ColumnSettings<T>[]) => {
|
|
9
|
+
return sorts.map(({ key, sortDirection, compareFn }) => {
|
|
10
|
+
return (a: T, b: T) => {
|
|
11
|
+
if (!key) {
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
14
|
+
let v1 = rowGetValue(a as Record<string, any>, key)
|
|
15
|
+
let v2 = rowGetValue(b as Record<string, any>, key)
|
|
16
|
+
if (compareFn) {
|
|
17
|
+
return compareFn(a, b)
|
|
18
|
+
}
|
|
19
|
+
if (typeof v1 === "number" || typeof v1 === "bigint" || typeof v1 === "boolean") {
|
|
20
|
+
//@ts-ignore
|
|
21
|
+
let sort: number = v1 - v2 as unknown as number
|
|
22
|
+
if (sortDirection === TableSortDirection.decending) {
|
|
23
|
+
sort = sort * -1
|
|
24
|
+
}
|
|
25
|
+
return sort
|
|
26
|
+
} else if (typeof v1 === "string") {
|
|
27
|
+
return v1.localeCompare(v2) * (sortDirection === TableSortDirection.decending ? -1 : 1)
|
|
28
|
+
}
|
|
29
|
+
once(() => { console.error(`Unable to sort type ${typeof v1}`) })
|
|
30
|
+
return undefined
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|