@spectric/ui 0.0.7 → 0.0.8
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/components/Button.d.ts +8 -3
- package/dist/components/index.d.ts +2 -0
- package/dist/components/pagination/index.d.ts +1 -0
- package/dist/components/pagination/pagination.d.ts +60 -0
- package/dist/components/table/body.d.ts +44 -0
- package/dist/components/table/cell.d.ts +53 -0
- package/dist/components/table/header.d.ts +42 -0
- package/dist/components/table/index.d.ts +1 -0
- package/dist/components/table/table.d.ts +90 -0
- package/dist/custom-elements.json +103 -4
- package/dist/index.es.js +1439 -1130
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +180 -74
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Button.ts +12 -4
- package/src/components/button.css.ts +66 -0
- package/src/components/index.ts +3 -1
- package/src/components/pagination/index.ts +1 -0
- package/src/components/pagination/pagination.css +10 -0
- package/src/components/pagination/pagination.ts +133 -0
- package/src/components/table/body.ts +69 -0
- package/src/components/table/cell.ts +117 -0
- package/src/components/table/header.ts +68 -0
- package/src/components/table/index.ts +1 -0
- package/src/components/table/table.css +36 -0
- package/src/components/table/table.ts +131 -0
- package/src/stories/Button.stories.ts +3 -2
- package/src/stories/pagination.stories.ts +63 -0
- package/src/stories/table.stories.ts +74 -0
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 spectric-button{position:absolute;right:4px;bottom:3px}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}
|
|
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 spectric-button{position:absolute;right:4px;bottom:3px}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-header{display:table-header-group}spectric-table div[role=table]{display:table}spectric-table-body{display:table-row-group}spectric-table-cell{display:contents}spectric-table-cell td{position:relative}spectric-table .filterable{padding-top:10px}spectric-table-cell .table-cell-actions{position:absolute;display:flex;width:100%;flex-direction:row-reverse;visibility:hidden}spectric-table-cell td:hover .table-cell-actions{visibility:unset}
|
package/package.json
CHANGED
package/src/components/Button.ts
CHANGED
|
@@ -9,13 +9,17 @@ export enum ButtonSizes {
|
|
|
9
9
|
large = "large",
|
|
10
10
|
medium = "medium",
|
|
11
11
|
small = "small",
|
|
12
|
+
xsmall = "xsmall",
|
|
13
|
+
xxsmall = "xxsmall",
|
|
14
|
+
tiny = "tiny"
|
|
12
15
|
}
|
|
13
|
-
type ButtonSizesTypes = `${ButtonSizes}`
|
|
16
|
+
export type ButtonSizesTypes = `${ButtonSizes}`
|
|
14
17
|
export enum ButtonVariants {
|
|
15
18
|
primary = "primary",
|
|
16
19
|
secondary = "secondary",
|
|
17
|
-
text = "text"
|
|
20
|
+
text = "text",
|
|
18
21
|
}
|
|
22
|
+
|
|
19
23
|
type ButtonVariantsTypes = `${ButtonVariants}`
|
|
20
24
|
export interface ButtonProps {
|
|
21
25
|
/** Is this the principal call to action on the page? */
|
|
@@ -28,6 +32,7 @@ export interface ButtonProps {
|
|
|
28
32
|
/* should the button be disabled*/
|
|
29
33
|
disabled: boolean;
|
|
30
34
|
danger?: boolean;
|
|
35
|
+
icon?: boolean
|
|
31
36
|
}
|
|
32
37
|
const MODES = {
|
|
33
38
|
"primary": 'spectric-button--primary',
|
|
@@ -46,14 +51,17 @@ export class SpectricButton extends LitElement implements ButtonProps {
|
|
|
46
51
|
@property({ type: String, reflect: true })
|
|
47
52
|
backgroundColor?: string | undefined;
|
|
48
53
|
@property({ type: String, reflect: true })
|
|
49
|
-
size:
|
|
54
|
+
size: ButtonSizesTypes = "small";
|
|
50
55
|
@property({ type: String, reflect: true })
|
|
51
56
|
label?: string = "";
|
|
52
57
|
@property({ type: Boolean, reflect: true })
|
|
53
58
|
danger = false;
|
|
59
|
+
@property({ type: Boolean, reflect: true })
|
|
60
|
+
icon: boolean = false;
|
|
61
|
+
|
|
54
62
|
connectedCallback(): void {
|
|
55
63
|
super.connectedCallback()
|
|
56
|
-
this.addEventListener("click", this._onClick)
|
|
64
|
+
this.addEventListener("click", this._onClick, { capture: true })
|
|
57
65
|
}
|
|
58
66
|
disconnectedCallback(): void {
|
|
59
67
|
super.disconnectedCallback()
|
|
@@ -78,6 +78,53 @@ export default css`
|
|
|
78
78
|
box-shadow: 0 0 30px white inset;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
:host([icon]) .spectric-button {
|
|
82
|
+
padding: unset;
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* :host([icon][size="small"]){
|
|
89
|
+
height:12px;
|
|
90
|
+
width:12px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
:host([icon][size="medium"]){
|
|
94
|
+
height:14px;
|
|
95
|
+
width:14px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:host([icon][size="large"]){
|
|
99
|
+
width: 48px;
|
|
100
|
+
height: 48px;
|
|
101
|
+
} */
|
|
102
|
+
:host([icon][size="tiny"]) .spectric-button{
|
|
103
|
+
width: 10px;
|
|
104
|
+
height: 10px;
|
|
105
|
+
}
|
|
106
|
+
:host([icon][size="xxsmall"]) .spectric-button{
|
|
107
|
+
width: 20px;
|
|
108
|
+
height: 20px;
|
|
109
|
+
}
|
|
110
|
+
:host([icon][size="xsmall"]) .spectric-button{
|
|
111
|
+
width: 28px;
|
|
112
|
+
height: 28px;
|
|
113
|
+
}
|
|
114
|
+
:host([icon][size="small"]) .spectric-button{
|
|
115
|
+
width: 34px;
|
|
116
|
+
height: 34px;
|
|
117
|
+
}
|
|
118
|
+
:host([icon][size="medium"]) .spectric-button{
|
|
119
|
+
width: 40px;
|
|
120
|
+
height: 40px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
:host([icon][size="large"]) .spectric-button{
|
|
124
|
+
width: 48px;
|
|
125
|
+
height: 48px;
|
|
126
|
+
}
|
|
127
|
+
|
|
81
128
|
.spectric-button:disabled{
|
|
82
129
|
cursor: not-allowed;
|
|
83
130
|
pointer-events: none;
|
|
@@ -145,6 +192,25 @@ opacity:1
|
|
|
145
192
|
background-color: transparent;
|
|
146
193
|
color: var(--text-secondary);
|
|
147
194
|
}
|
|
195
|
+
.spectric-button--tiny {
|
|
196
|
+
font-size: 10px;
|
|
197
|
+
line-height: 10px;
|
|
198
|
+
height: 10px;
|
|
199
|
+
display: flex;
|
|
200
|
+
align-content: center;
|
|
201
|
+
align-items: center;
|
|
202
|
+
}
|
|
203
|
+
.spectric-button--xxsmall {
|
|
204
|
+
padding: 5px 6px;
|
|
205
|
+
font-size: 10px;
|
|
206
|
+
line-height: 8px;
|
|
207
|
+
}
|
|
208
|
+
.spectric-button--xsmall {
|
|
209
|
+
padding: 5px 8px;
|
|
210
|
+
font-size: 10px;
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
line-height: 14px;
|
|
213
|
+
}
|
|
148
214
|
.spectric-button--small {
|
|
149
215
|
padding: 5px 10px;
|
|
150
216
|
font-size: 12px;
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./pagination"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { html, LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import "../Button";
|
|
3
|
+
import { customElement, property, } from 'lit/decorators.js';
|
|
4
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
5
|
+
export const PaginationElementTag = "spectric-pagination"
|
|
6
|
+
import "./pagination.css"
|
|
7
|
+
import { ButtonSizesTypes } from '../Button';
|
|
8
|
+
export type { PaginationProps, PaginationChangeProps, PaginationEvents }
|
|
9
|
+
|
|
10
|
+
interface PaginationChangeProps {
|
|
11
|
+
page: number;
|
|
12
|
+
pageSize: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PaginationProps extends PaginationChangeProps {
|
|
16
|
+
size: ButtonSizesTypes
|
|
17
|
+
totalItems?: number
|
|
18
|
+
pageSizeOptions?: number[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log("Pagination")
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pagination Element
|
|
25
|
+
*/
|
|
26
|
+
@customElement(PaginationElementTag)
|
|
27
|
+
export class PaginationElement extends LitElement implements PaginationProps {
|
|
28
|
+
@property({ type: Number, reflect: true })
|
|
29
|
+
page: number = 1;
|
|
30
|
+
|
|
31
|
+
@property({ type: Number, reflect: true })
|
|
32
|
+
pageSize: number = 10;
|
|
33
|
+
|
|
34
|
+
@property({ type: Number, reflect: true })
|
|
35
|
+
totalItems?: number;
|
|
36
|
+
|
|
37
|
+
@property({ type: Array })
|
|
38
|
+
pageSizeOptions = [10, 20, 50, 100, 1000];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Size of the pagination buttons
|
|
42
|
+
*/
|
|
43
|
+
@property({ type: String, reflect: true })
|
|
44
|
+
size: ButtonSizesTypes = "small"
|
|
45
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
46
|
+
return this
|
|
47
|
+
}
|
|
48
|
+
protected updated(_changedProperties: PropertyValues): void {
|
|
49
|
+
if (_changedProperties.has("pageSize") && !this.pageSizeOptions.includes(this.pageSize)) {
|
|
50
|
+
this.pageSizeOptions = [...this.pageSizeOptions, this.pageSize].sort((a, b) => a - b)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
private _handlePageUp = () => {
|
|
54
|
+
this.page += 1
|
|
55
|
+
this._emitChange()
|
|
56
|
+
}
|
|
57
|
+
private _handlePageDown = () => {
|
|
58
|
+
this.page -= 1
|
|
59
|
+
this._emitChange()
|
|
60
|
+
}
|
|
61
|
+
private _handleSizeChange = (e: any) => {
|
|
62
|
+
let value = parseInt(e.target.value)
|
|
63
|
+
this.pageSize = value
|
|
64
|
+
this._emitChange()
|
|
65
|
+
}
|
|
66
|
+
private _emitChange = () => {
|
|
67
|
+
let { page, pageSize } = this
|
|
68
|
+
this.dispatchEvent(new CustomEvent<PaginationChangeProps>("change", { detail: { page, pageSize } }))
|
|
69
|
+
}
|
|
70
|
+
protected render(): unknown {
|
|
71
|
+
let nextPage = (this.page) * this.pageSize
|
|
72
|
+
let nextPageDisabled = true
|
|
73
|
+
|
|
74
|
+
if (this.totalItems && nextPage < this.totalItems) {
|
|
75
|
+
nextPageDisabled = false
|
|
76
|
+
}
|
|
77
|
+
let pageText = ""
|
|
78
|
+
if (this.totalItems) {
|
|
79
|
+
pageText = `${this.page} of ${Math.ceil(this.totalItems / this.pageSize)}`
|
|
80
|
+
}
|
|
81
|
+
return html`
|
|
82
|
+
<div class="spectric-pagination-container">
|
|
83
|
+
<div>
|
|
84
|
+
<!-- TODO/FIXME Make a select component and use it for cross browser styling-->
|
|
85
|
+
<select @change=${this._handleSizeChange} .value=${String(this.pageSize)}>
|
|
86
|
+
${this.pageSizeOptions.map(size => html`<option .value=${String(size)} class=${String(size) === String(this.pageSize) ? "selected" : ""}>${size}</option>`)}
|
|
87
|
+
</select>
|
|
88
|
+
</div>
|
|
89
|
+
${this.totalItems ? html`
|
|
90
|
+
<div class="spectric-pagination-text">${`Items ${(this.page - 1) * this.pageSize}-${Math.min(this.page * this.pageSize, this.totalItems)} of ${this.totalItems}`}</div>
|
|
91
|
+
<div class="spectric-pagination-container">
|
|
92
|
+
<div>
|
|
93
|
+
${pageText}
|
|
94
|
+
</div>
|
|
95
|
+
<div>
|
|
96
|
+
<spectric-button size=${this.size} ?disabled=${this.page === 1} @click=${this._handlePageDown}><</spectric-button>
|
|
97
|
+
<spectric-button size=${this.size} ?disabled=${nextPageDisabled} @click=${this._handlePageUp}>></spectric-button>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
`: null}
|
|
101
|
+
</div>
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface PaginationEvents {
|
|
107
|
+
'change': (event: CustomEvent<PaginationChangeProps>) => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare global {
|
|
111
|
+
interface HTMLElementTagNameMap {
|
|
112
|
+
[PaginationElementTag]: HTMLElementTagWithEvents<PaginationElement, PaginationEvents>
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
namespace JSX {
|
|
116
|
+
interface IntrinsicElements {
|
|
117
|
+
/**
|
|
118
|
+
* @see {@link DialogElement}
|
|
119
|
+
*/
|
|
120
|
+
[PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
namespace React {
|
|
124
|
+
namespace JSX {
|
|
125
|
+
interface IntrinsicElements {
|
|
126
|
+
/**
|
|
127
|
+
* @see {@link DialogElement}
|
|
128
|
+
*/
|
|
129
|
+
[PaginationElementTag]: ReactElementWithPropsAndEvents<PaginationElement, PaginationProps, PaginationEvents>
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import { customElement, property, } from 'lit/decorators.js';
|
|
3
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
4
|
+
export const TableBodyElementTag = "spectric-table-body"
|
|
5
|
+
import "./cell"
|
|
6
|
+
import { ColumnSettings, TableElement } from './table';
|
|
7
|
+
|
|
8
|
+
interface BodyProps<T> {
|
|
9
|
+
columns: ColumnSettings<T>[]
|
|
10
|
+
data: T[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Pagination Element
|
|
16
|
+
*/
|
|
17
|
+
@customElement(TableBodyElementTag)
|
|
18
|
+
export class TableBodyElement<T> extends LitElement implements BodyProps<T> {
|
|
19
|
+
@property({ type: Array, attribute: false })
|
|
20
|
+
data: T[] = [];
|
|
21
|
+
@property({ type: Array, attribute: false })
|
|
22
|
+
columns: ColumnSettings<T>[] = [];
|
|
23
|
+
table!: TableElement<T>
|
|
24
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
25
|
+
return this
|
|
26
|
+
}
|
|
27
|
+
protected render(): unknown {
|
|
28
|
+
return html`
|
|
29
|
+
<body>
|
|
30
|
+
${this.data.map((row: any) => {
|
|
31
|
+
return html`<tr>${this.columns.map(col => {
|
|
32
|
+
return html`<spectric-table-cell .column=${col} .row=${row}></spectric-table-cell>`
|
|
33
|
+
})}</tr>`
|
|
34
|
+
})}
|
|
35
|
+
</body>
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface TableBodyEvents {
|
|
43
|
+
//'sort': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare global {
|
|
47
|
+
interface HTMLElementTagNameMap {
|
|
48
|
+
[TableBodyElementTag]: HTMLElementTagWithEvents<TableBodyElement<any>, TableBodyEvents>
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
namespace JSX {
|
|
52
|
+
interface IntrinsicElements {
|
|
53
|
+
/**
|
|
54
|
+
* @see {@link DialogElement}
|
|
55
|
+
*/
|
|
56
|
+
[TableBodyElementTag]: ReactElementWithPropsAndEvents<TableBodyElement<any>, BodyProps<any>, TableBodyEvents>;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
namespace React {
|
|
60
|
+
namespace JSX {
|
|
61
|
+
interface IntrinsicElements {
|
|
62
|
+
/**
|
|
63
|
+
* @see {@link DialogElement}
|
|
64
|
+
*/
|
|
65
|
+
[TableBodyElementTag]: ReactElementWithPropsAndEvents<TableBodyElement<any>, BodyProps<any>, TableBodyEvents>
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import { customElement, property, } from 'lit/decorators.js';
|
|
3
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
4
|
+
export const TableCellElementTag = "spectric-table-cell"
|
|
5
|
+
import { ColumnSettings, TableElement } from './table';
|
|
6
|
+
|
|
7
|
+
interface CellProps<T> {
|
|
8
|
+
column: ColumnSettings<T>
|
|
9
|
+
row: T
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type FilterEvent<T> = {
|
|
13
|
+
value?: T,
|
|
14
|
+
include: boolean
|
|
15
|
+
column: ColumnSettings<T>
|
|
16
|
+
row: T
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Pagination Element
|
|
21
|
+
*/
|
|
22
|
+
@customElement(TableCellElementTag)
|
|
23
|
+
export class TableCellElement<T> extends LitElement implements CellProps<T> {
|
|
24
|
+
@property({ type: Object, attribute: false })
|
|
25
|
+
row!: T;
|
|
26
|
+
@property({ type: Object, attribute: false })
|
|
27
|
+
column!: ColumnSettings<T>;
|
|
28
|
+
table!: TableElement<T>
|
|
29
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
30
|
+
return this
|
|
31
|
+
}
|
|
32
|
+
_handleFilterOut = () => {
|
|
33
|
+
let value = undefined;
|
|
34
|
+
if (this.column.key && typeof this.row === "object") {
|
|
35
|
+
value = (this.row as Record<any, any>)[this.column.key]
|
|
36
|
+
}
|
|
37
|
+
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
|
|
38
|
+
composed: true,
|
|
39
|
+
bubbles: true,
|
|
40
|
+
detail: {
|
|
41
|
+
include: false,
|
|
42
|
+
row: this.row,
|
|
43
|
+
value,
|
|
44
|
+
column: this.column
|
|
45
|
+
}
|
|
46
|
+
}))
|
|
47
|
+
}
|
|
48
|
+
_handleFilterFor = () => {
|
|
49
|
+
let value = undefined;
|
|
50
|
+
if (this.column.key && typeof this.row === "object") {
|
|
51
|
+
value = (this.row as Record<any, any>)[this.column.key]
|
|
52
|
+
}
|
|
53
|
+
this.dispatchEvent(new CustomEvent<FilterEvent<T>>("filter", {
|
|
54
|
+
composed: true,
|
|
55
|
+
bubbles: true,
|
|
56
|
+
detail: {
|
|
57
|
+
include: true,
|
|
58
|
+
row: this.row,
|
|
59
|
+
value,
|
|
60
|
+
column: this.column
|
|
61
|
+
}
|
|
62
|
+
}))
|
|
63
|
+
}
|
|
64
|
+
protected render(): unknown {
|
|
65
|
+
let rendered
|
|
66
|
+
if (this.column.render) {
|
|
67
|
+
rendered = this.column.render(this.row, this.table)
|
|
68
|
+
} else if (this.column.key && typeof this.row === 'object') {
|
|
69
|
+
rendered = (this.row as Record<any, any>)[this.column.key]
|
|
70
|
+
} else {
|
|
71
|
+
rendered = html`error`
|
|
72
|
+
}
|
|
73
|
+
let classes = ["cell-contents"]
|
|
74
|
+
if (this.column.filterable) {
|
|
75
|
+
classes.push("filterable")
|
|
76
|
+
}
|
|
77
|
+
let filterButtons = html`<div class="table-cell-actions"><spectric-button @click=${this._handleFilterOut} size="tiny" variant="text" icon>-</spectric-button><spectric-button @click=${this._handleFilterFor} size="tiny" variant="text" icon>+</spectric-button></div>`
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
return html`
|
|
81
|
+
<td>
|
|
82
|
+
${this.column.filterable ? filterButtons : null}
|
|
83
|
+
<div class=${classes.join(" ")}>${rendered}</div>
|
|
84
|
+
</td>
|
|
85
|
+
`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface TableBodyEvents {
|
|
91
|
+
'filter': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO filter events
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
declare global {
|
|
95
|
+
interface HTMLElementTagNameMap {
|
|
96
|
+
[TableCellElementTag]: HTMLElementTagWithEvents<TableCellElement<any>, TableBodyEvents>
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
namespace JSX {
|
|
100
|
+
interface IntrinsicElements {
|
|
101
|
+
/**
|
|
102
|
+
* @see {@link DialogElement}
|
|
103
|
+
*/
|
|
104
|
+
[TableCellElementTag]: ReactElementWithPropsAndEvents<TableCellElement<any>, CellProps<any>, TableBodyEvents>;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
namespace React {
|
|
108
|
+
namespace JSX {
|
|
109
|
+
interface IntrinsicElements {
|
|
110
|
+
/**
|
|
111
|
+
* @see {@link DialogElement}
|
|
112
|
+
*/
|
|
113
|
+
[TableCellElementTag]: ReactElementWithPropsAndEvents<TableCellElement<any>, CellProps<any>, TableBodyEvents>
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import "../pagination";
|
|
3
|
+
import { customElement, property, } from 'lit/decorators.js';
|
|
4
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from '../types';
|
|
5
|
+
import "./table.css"
|
|
6
|
+
export const TableHeaderElementTag = "spectric-table-header"
|
|
7
|
+
import { ColumnSettings } from './table';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
interface HeaderProps<T> {
|
|
11
|
+
columns: ColumnSettings<T>[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Pagination Element
|
|
16
|
+
*/
|
|
17
|
+
@customElement(TableHeaderElementTag)
|
|
18
|
+
export class TableHeaderElement<T> extends LitElement implements HeaderProps<T> {
|
|
19
|
+
@property({ type: Array, attribute: false })
|
|
20
|
+
columns: ColumnSettings<T>[] = [];
|
|
21
|
+
|
|
22
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
23
|
+
return this
|
|
24
|
+
}
|
|
25
|
+
protected render(): unknown {
|
|
26
|
+
|
|
27
|
+
return html`
|
|
28
|
+
<tr>
|
|
29
|
+
${this.columns.map(column => {
|
|
30
|
+
let classes = ["header-contents"]
|
|
31
|
+
if (column.filterable) {
|
|
32
|
+
//classes.push("filterable")
|
|
33
|
+
}
|
|
34
|
+
return html`<td><div class=${classes.join(" ")}>${column.title || column.key}</div></td>`
|
|
35
|
+
})}
|
|
36
|
+
</tr>
|
|
37
|
+
`
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface TableHeaderEvents {
|
|
42
|
+
'sort': (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare global {
|
|
46
|
+
interface HTMLElementTagNameMap {
|
|
47
|
+
[TableHeaderElementTag]: HTMLElementTagWithEvents<TableHeaderElement<any>, TableHeaderEvents>
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
namespace JSX {
|
|
51
|
+
interface IntrinsicElements {
|
|
52
|
+
/**
|
|
53
|
+
* @see {@link DialogElement}
|
|
54
|
+
*/
|
|
55
|
+
[TableHeaderElementTag]: ReactElementWithPropsAndEvents<TableHeaderElement<any>, HeaderProps<any>, TableHeaderEvents>;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
namespace React {
|
|
59
|
+
namespace JSX {
|
|
60
|
+
interface IntrinsicElements {
|
|
61
|
+
/**
|
|
62
|
+
* @see {@link DialogElement}
|
|
63
|
+
*/
|
|
64
|
+
[TableHeaderElementTag]: ReactElementWithPropsAndEvents<TableHeaderElement<any>, HeaderProps<any>, TableHeaderEvents>
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./table"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
spectric-table{
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
}
|
|
5
|
+
spectric-table tr{
|
|
6
|
+
text-align: center;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
spectric-table-header{
|
|
10
|
+
display: table-header-group;
|
|
11
|
+
}
|
|
12
|
+
spectric-table div[role="table"]{
|
|
13
|
+
display: table;
|
|
14
|
+
}
|
|
15
|
+
spectric-table-body {
|
|
16
|
+
display: table-row-group;
|
|
17
|
+
}
|
|
18
|
+
spectric-table-cell{
|
|
19
|
+
display: contents;
|
|
20
|
+
}
|
|
21
|
+
spectric-table-cell td{
|
|
22
|
+
position: relative;
|
|
23
|
+
}
|
|
24
|
+
spectric-table .filterable {
|
|
25
|
+
padding-top: 10px;
|
|
26
|
+
}
|
|
27
|
+
spectric-table-cell .table-cell-actions{
|
|
28
|
+
position: absolute;
|
|
29
|
+
display: flex;
|
|
30
|
+
width: 100%;
|
|
31
|
+
flex-direction: row-reverse;
|
|
32
|
+
visibility: hidden;
|
|
33
|
+
}
|
|
34
|
+
spectric-table-cell td:hover .table-cell-actions{
|
|
35
|
+
visibility: unset;
|
|
36
|
+
}
|