@spectric/ui 0.0.20 → 0.0.21
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/Banner.d.ts +1 -1
- package/dist/components/dialog/dialog.d.ts +1 -1
- package/dist/components/query_bar/QueryBar.d.ts +1 -1
- package/dist/components/table/cell.d.ts +1 -1
- package/dist/components/table/header.d.ts +2 -1
- package/dist/components/table/table.d.ts +10 -7
- package/dist/custom-elements.json +4 -4
- package/dist/index.es.js +876 -741
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +213 -138
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Banner.ts +46 -31
- package/src/components/dialog/dialog.ts +163 -135
- package/src/components/query_bar/QueryBar.ts +7 -2
- package/src/components/table/__tests__/table.spec.ts +143 -55
- package/src/components/table/cell.ts +185 -146
- package/src/components/table/header.ts +162 -152
- package/src/components/table/table.ts +362 -265
- package/src/components/table/virtualBody.ts +165 -115
|
@@ -2,17 +2,21 @@ import { html } from "lit";
|
|
|
2
2
|
import "../pagination";
|
|
3
3
|
import { customElement, property, state } from "lit/decorators.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
HTMLElementTagWithEvents,
|
|
6
|
+
ReactElementWithPropsAndEvents,
|
|
7
7
|
} from "../types";
|
|
8
8
|
import "./table.css";
|
|
9
9
|
import "./header.css";
|
|
10
10
|
export const TableHeaderElementTag = "spectric-table-header";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
ColumnSettings,
|
|
13
|
+
SpectricTableElement,
|
|
14
|
+
TableSortDirection,
|
|
15
|
+
} from "./table";
|
|
12
16
|
import { DisposableElement } from "../../classes";
|
|
13
17
|
|
|
14
18
|
interface HeaderProps<T> {
|
|
15
|
-
|
|
19
|
+
columns: ColumnSettings<T>[];
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -20,169 +24,175 @@ interface HeaderProps<T> {
|
|
|
20
24
|
*/
|
|
21
25
|
@customElement(TableHeaderElementTag)
|
|
22
26
|
export class TableHeaderElement<T>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
extends DisposableElement
|
|
28
|
+
implements HeaderProps<T>
|
|
29
|
+
{
|
|
30
|
+
@property({ type: Array, attribute: false })
|
|
31
|
+
columns: ColumnSettings<T>[] = [];
|
|
32
|
+
@state()
|
|
33
|
+
private _resizeStart?: { event: MouseEvent; column: ColumnSettings<T> };
|
|
34
|
+
@property({ type: Object, attribute: false })
|
|
35
|
+
table!: SpectricTableElement<T>;
|
|
36
|
+
constructor() {
|
|
37
|
+
super();
|
|
38
|
+
this.addDisposableListener(
|
|
39
|
+
() => document.body,
|
|
40
|
+
"mouseup",
|
|
41
|
+
this._handleResizeEnd
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
_handleSortChange = (column: ColumnSettings<T>) => {
|
|
48
|
+
if (this._resizeStart) {
|
|
49
|
+
return;
|
|
36
50
|
}
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
column = JSON.parse(JSON.stringify(column)); // Clone the column to not mutate the original object
|
|
52
|
+
if (!column.sortable) {
|
|
53
|
+
return;
|
|
39
54
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
if (
|
|
56
|
+
column.sortDirection === TableSortDirection.none ||
|
|
57
|
+
column.sortDirection === undefined
|
|
58
|
+
) {
|
|
59
|
+
column.sortDirection = TableSortDirection.ascending;
|
|
60
|
+
} else if (column.sortDirection === TableSortDirection.ascending) {
|
|
61
|
+
column.sortDirection = TableSortDirection.descending;
|
|
62
|
+
} else if (column.sortDirection === TableSortDirection.descending) {
|
|
63
|
+
column.sortDirection = TableSortDirection.none;
|
|
64
|
+
}
|
|
65
|
+
this.dispatchEvent(
|
|
66
|
+
new CustomEvent<ColumnSettings<T>>("sortChange", {
|
|
67
|
+
composed: true,
|
|
68
|
+
bubbles: true,
|
|
69
|
+
detail: column,
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
_handleResizeStart = (event: MouseEvent, column: ColumnSettings<T>) => {
|
|
74
|
+
this._resizeStart = { event, column };
|
|
75
|
+
};
|
|
76
|
+
_handleResizeEnd = (e: MouseEvent) => {
|
|
77
|
+
if (!this._resizeStart) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
let delta = e.pageX - this._resizeStart?.event.pageX;
|
|
81
|
+
if (this._resizeStart.column.width) {
|
|
82
|
+
this._resizeStart.column.width = this._resizeStart.column.width + delta;
|
|
83
|
+
} else {
|
|
84
|
+
let cell = (this._resizeStart.event.target as HTMLDivElement).closest(
|
|
85
|
+
"td"
|
|
86
|
+
) as HTMLTableCellElement;
|
|
87
|
+
this._resizeStart.column.width =
|
|
88
|
+
cell.getBoundingClientRect().width + delta;
|
|
89
|
+
}
|
|
90
|
+
this.dispatchEvent(
|
|
91
|
+
new CustomEvent("columnResize", { detail: this._resizeStart.column })
|
|
92
|
+
);
|
|
93
|
+
//We wrap this to ensure any sort events get fired before we are done FIXME?
|
|
94
|
+
requestAnimationFrame(() => {
|
|
95
|
+
this._resizeStart = undefined;
|
|
96
|
+
//Clear any text that got selected during column resize
|
|
97
|
+
if (window.getSelection) {
|
|
98
|
+
let selection = window.getSelection();
|
|
99
|
+
if (selection) {
|
|
100
|
+
selection.removeAllRanges();
|
|
82
101
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this._resizeStart = undefined;
|
|
89
|
-
//Clear any text that got selected during column resize
|
|
90
|
-
if (window.getSelection) {
|
|
91
|
-
let selection = window.getSelection();
|
|
92
|
-
if (selection) {
|
|
93
|
-
selection.removeAllRanges();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
};
|
|
98
|
-
protected render(): unknown {
|
|
99
|
-
return html`
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
protected render(): unknown {
|
|
106
|
+
return html`
|
|
100
107
|
<tr>
|
|
101
|
-
${this.columns.map(column => this.renderCell(column))}
|
|
108
|
+
${this.columns.map((column) => this.renderCell(column))}
|
|
102
109
|
</tr>
|
|
103
110
|
`;
|
|
111
|
+
}
|
|
112
|
+
private renderCell(column: ColumnSettings<T>) {
|
|
113
|
+
let classes = ["header-contents"];
|
|
114
|
+
if (column.filterable) {
|
|
115
|
+
//classes.push("filterable")
|
|
104
116
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (column.sortable) {
|
|
111
|
-
classes.push("sortable");
|
|
112
|
-
}
|
|
113
|
-
if (this._resizeStart) {
|
|
114
|
-
classes.push("resizing");
|
|
115
|
-
}
|
|
116
|
-
let columnWidth = column.width
|
|
117
|
-
? `min-width:${column.width}px;max-width:${column.width}px;`
|
|
118
|
-
: "";
|
|
119
|
-
let sortDirection =
|
|
120
|
-
column.sortDirection === TableSortDirection.ascending
|
|
121
|
-
? `🠉`
|
|
122
|
-
: column.sortDirection == TableSortDirection.descending
|
|
123
|
-
? `🠋`
|
|
124
|
-
: ``;
|
|
125
|
-
let sortClass = column.sortDirection || TableSortDirection.none;
|
|
126
|
-
let resizable =
|
|
127
|
-
column.allowResize || column.allowResize === undefined;
|
|
128
|
-
let resizeHandle = resizable
|
|
129
|
-
? html`<div
|
|
130
|
-
class="header-resize-handle"
|
|
131
|
-
@mousedown=${(e: MouseEvent) => {
|
|
132
|
-
this._handleResizeStart(e, column);
|
|
133
|
-
}}
|
|
134
|
-
@mouseup=${this._handleResizeEnd}
|
|
135
|
-
></div>`
|
|
136
|
-
: null
|
|
137
|
-
return html` <td
|
|
138
|
-
@click=${() => this._handleSortChange(column)}
|
|
139
|
-
style="${columnWidth}"
|
|
140
|
-
>
|
|
141
|
-
${resizeHandle}
|
|
142
|
-
<div class=${classes.join(" ")}>
|
|
143
|
-
${column.title || column.key}
|
|
144
|
-
<span class="sort-direction ${sortClass}">${sortDirection}</span>
|
|
145
|
-
</div>
|
|
146
|
-
</td>`;
|
|
117
|
+
if (column.sortable) {
|
|
118
|
+
classes.push("sortable");
|
|
119
|
+
}
|
|
120
|
+
if (this._resizeStart) {
|
|
121
|
+
classes.push("resizing");
|
|
147
122
|
}
|
|
123
|
+
let columnWidth = column.width
|
|
124
|
+
? `min-width:${column.width}px;max-width:${column.width}px;`
|
|
125
|
+
: "";
|
|
126
|
+
let sortDirection =
|
|
127
|
+
column.sortDirection === TableSortDirection.ascending
|
|
128
|
+
? `🠉`
|
|
129
|
+
: column.sortDirection == TableSortDirection.descending
|
|
130
|
+
? `🠋`
|
|
131
|
+
: ``;
|
|
132
|
+
let sortClass = column.sortDirection || TableSortDirection.none;
|
|
133
|
+
let resizable = column.allowResize || column.allowResize === undefined;
|
|
134
|
+
let resizeHandle = resizable
|
|
135
|
+
? html`<div
|
|
136
|
+
class="header-resize-handle"
|
|
137
|
+
@mousedown=${(e: MouseEvent) => {
|
|
138
|
+
this._handleResizeStart(e, column);
|
|
139
|
+
}}
|
|
140
|
+
@mouseup=${this._handleResizeEnd}
|
|
141
|
+
></div>`
|
|
142
|
+
: null;
|
|
143
|
+
let title = column.title || column.key;
|
|
144
|
+
if (typeof title == "function") {
|
|
145
|
+
title = title(this.table) || undefined;
|
|
146
|
+
}
|
|
147
|
+
return html` <td
|
|
148
|
+
@click=${() => this._handleSortChange(column)}
|
|
149
|
+
style="${columnWidth}"
|
|
150
|
+
>
|
|
151
|
+
${resizeHandle}
|
|
152
|
+
<div class=${classes.join(" ")}>
|
|
153
|
+
${title}
|
|
154
|
+
<span class="sort-direction ${sortClass}">${sortDirection}</span>
|
|
155
|
+
</div>
|
|
156
|
+
</td>`;
|
|
157
|
+
}
|
|
148
158
|
}
|
|
149
159
|
|
|
150
160
|
interface TableHeaderEvents {
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
sortChange: (event: CustomEvent<ColumnSettings<any>>) => void; //TODO sort events
|
|
162
|
+
columnResize: (event: CustomEvent<ColumnSettings<any>>) => void;
|
|
153
163
|
}
|
|
154
164
|
|
|
155
165
|
declare global {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
166
|
+
interface HTMLElementTagNameMap {
|
|
167
|
+
[TableHeaderElementTag]: HTMLElementTagWithEvents<
|
|
168
|
+
TableHeaderElement<any>,
|
|
169
|
+
TableHeaderEvents
|
|
170
|
+
>;
|
|
171
|
+
}
|
|
172
|
+
namespace JSX {
|
|
173
|
+
interface IntrinsicElements {
|
|
174
|
+
/**
|
|
175
|
+
* @see {@link DialogElement}
|
|
176
|
+
*/
|
|
177
|
+
[TableHeaderElementTag]: ReactElementWithPropsAndEvents<
|
|
178
|
+
TableHeaderElement<any>,
|
|
179
|
+
HeaderProps<any>,
|
|
180
|
+
TableHeaderEvents
|
|
181
|
+
>;
|
|
161
182
|
}
|
|
183
|
+
}
|
|
184
|
+
namespace React {
|
|
162
185
|
namespace JSX {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
namespace React {
|
|
175
|
-
namespace JSX {
|
|
176
|
-
interface IntrinsicElements {
|
|
177
|
-
/**
|
|
178
|
-
* @see {@link DialogElement}
|
|
179
|
-
*/
|
|
180
|
-
[TableHeaderElementTag]: ReactElementWithPropsAndEvents<
|
|
181
|
-
TableHeaderElement<any>,
|
|
182
|
-
HeaderProps<any>,
|
|
183
|
-
TableHeaderEvents
|
|
184
|
-
>;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
186
|
+
interface IntrinsicElements {
|
|
187
|
+
/**
|
|
188
|
+
* @see {@link DialogElement}
|
|
189
|
+
*/
|
|
190
|
+
[TableHeaderElementTag]: ReactElementWithPropsAndEvents<
|
|
191
|
+
TableHeaderElement<any>,
|
|
192
|
+
HeaderProps<any>,
|
|
193
|
+
TableHeaderEvents
|
|
194
|
+
>;
|
|
195
|
+
}
|
|
187
196
|
}
|
|
197
|
+
}
|
|
188
198
|
}
|