@uwdata/mosaic-inputs 0.1.0 → 0.3.0
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/mosaic-inputs.js +1628 -676
- package/dist/mosaic-inputs.min.js +4 -4
- package/package.json +4 -4
- package/src/Menu.js +17 -6
- package/src/Search.js +10 -2
- package/src/Slider.js +8 -2
- package/src/Table.js +58 -36
- package/src/index.js +4 -4
- package/src/input.js +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uwdata/mosaic-inputs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Mosaic input components.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"inputs",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"prepublishOnly": "npm run test && npm run lint && npm run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@uwdata/mosaic-core": "^0.
|
|
29
|
-
"@uwdata/mosaic-sql": "^0.
|
|
28
|
+
"@uwdata/mosaic-core": "^0.3.0",
|
|
29
|
+
"@uwdata/mosaic-sql": "^0.3.0",
|
|
30
30
|
"isoformat": "^0.2.1"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "a8dd23fed4c7a24c0a2ee5261d1aabe4239ce574"
|
|
33
33
|
}
|
package/src/Menu.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { MosaicClient, isParam, isSelection } from '@uwdata/mosaic-core';
|
|
2
2
|
import { Query, eq, literal } from '@uwdata/mosaic-sql';
|
|
3
|
+
import { input } from './input.js';
|
|
3
4
|
|
|
4
5
|
const isObject = v => {
|
|
5
6
|
return v && typeof v === 'object' && !Array.isArray(v);
|
|
6
7
|
};
|
|
7
8
|
|
|
9
|
+
export const menu = options => input(Menu, options);
|
|
10
|
+
|
|
8
11
|
export class Menu extends MosaicClient {
|
|
9
12
|
constructor({
|
|
13
|
+
element,
|
|
10
14
|
filterBy,
|
|
11
15
|
from,
|
|
12
16
|
column,
|
|
@@ -22,7 +26,7 @@ export class Menu extends MosaicClient {
|
|
|
22
26
|
this.selection = as;
|
|
23
27
|
this.format = format;
|
|
24
28
|
|
|
25
|
-
this.element = document.createElement('div');
|
|
29
|
+
this.element = element ?? document.createElement('div');
|
|
26
30
|
this.element.setAttribute('class', 'input');
|
|
27
31
|
this.element.value = this;
|
|
28
32
|
|
|
@@ -36,13 +40,12 @@ export class Menu extends MosaicClient {
|
|
|
36
40
|
this.update();
|
|
37
41
|
}
|
|
38
42
|
value = value ?? this.selection?.value ?? this.data?.[0]?.value;
|
|
39
|
-
this.select.value = value;
|
|
40
43
|
if (this.selection?.value === undefined) this.publish(value);
|
|
41
44
|
this.element.appendChild(this.select);
|
|
42
45
|
|
|
43
46
|
if (this.selection) {
|
|
44
47
|
this.select.addEventListener('input', () => {
|
|
45
|
-
this.publish(this.selectedValue()
|
|
48
|
+
this.publish(this.selectedValue() ?? null);
|
|
46
49
|
});
|
|
47
50
|
if (!isSelection(this.selection)) {
|
|
48
51
|
this.selection.addEventListener('value', value => {
|
|
@@ -59,11 +62,19 @@ export class Menu extends MosaicClient {
|
|
|
59
62
|
const index = this.select.selectedIndex;
|
|
60
63
|
return this.data[index].value;
|
|
61
64
|
} else {
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
const index = this.data?.findIndex(opt => opt.value === value);
|
|
66
|
+
if (index >= 0) {
|
|
67
|
+
this.select.selectedIndex = index;
|
|
68
|
+
} else {
|
|
69
|
+
this.select.value = String(value);
|
|
70
|
+
}
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
73
|
|
|
74
|
+
reset() {
|
|
75
|
+
this.select.selectedIndex = this.from ? 0 : -1;
|
|
76
|
+
}
|
|
77
|
+
|
|
67
78
|
publish(value) {
|
|
68
79
|
const { selection, column } = this;
|
|
69
80
|
if (isSelection(selection)) {
|
|
@@ -104,7 +115,7 @@ export class Menu extends MosaicClient {
|
|
|
104
115
|
this.select.appendChild(opt);
|
|
105
116
|
}
|
|
106
117
|
if (this.selection) {
|
|
107
|
-
this.
|
|
118
|
+
this.selectedValue(this.selection?.value ?? '');
|
|
108
119
|
}
|
|
109
120
|
return this;
|
|
110
121
|
}
|
package/src/Search.js
CHANGED
|
@@ -2,17 +2,21 @@ import { MosaicClient, isParam, isSelection } from '@uwdata/mosaic-core';
|
|
|
2
2
|
import {
|
|
3
3
|
Query, regexp_matches, contains, prefix, suffix, literal
|
|
4
4
|
} from '@uwdata/mosaic-sql';
|
|
5
|
+
import { input } from './input.js';
|
|
5
6
|
|
|
6
7
|
const FUNCTIONS = { contains, prefix, suffix, regexp: regexp_matches };
|
|
7
8
|
let _id = 0;
|
|
8
9
|
|
|
10
|
+
export const search = options => input(Search, options);
|
|
11
|
+
|
|
9
12
|
export class Search extends MosaicClient {
|
|
10
13
|
constructor({
|
|
14
|
+
element,
|
|
11
15
|
filterBy,
|
|
12
16
|
from,
|
|
13
17
|
column,
|
|
14
18
|
label,
|
|
15
|
-
type,
|
|
19
|
+
type = 'contains',
|
|
16
20
|
as
|
|
17
21
|
} = {}) {
|
|
18
22
|
super(filterBy);
|
|
@@ -22,7 +26,7 @@ export class Search extends MosaicClient {
|
|
|
22
26
|
this.column = column;
|
|
23
27
|
this.selection = as;
|
|
24
28
|
|
|
25
|
-
this.element = document.createElement('div');
|
|
29
|
+
this.element = element ?? document.createElement('div');
|
|
26
30
|
this.element.setAttribute('class', 'input');
|
|
27
31
|
this.element.value = this;
|
|
28
32
|
|
|
@@ -53,6 +57,10 @@ export class Search extends MosaicClient {
|
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
reset() {
|
|
61
|
+
this.searchbox.value = '';
|
|
62
|
+
}
|
|
63
|
+
|
|
56
64
|
publish(value) {
|
|
57
65
|
const { selection, column, type } = this;
|
|
58
66
|
if (isSelection(selection)) {
|
package/src/Slider.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { MosaicClient, isParam, isSelection } from '@uwdata/mosaic-core';
|
|
2
2
|
import { Query, eq, literal, max, min } from '@uwdata/mosaic-sql';
|
|
3
|
+
import { input } from './input.js';
|
|
3
4
|
|
|
4
5
|
let _id = 0;
|
|
5
6
|
|
|
7
|
+
export const slider = options => input(Slider, options);
|
|
8
|
+
|
|
6
9
|
export class Slider extends MosaicClient {
|
|
7
10
|
constructor({
|
|
11
|
+
element,
|
|
8
12
|
filterBy,
|
|
9
13
|
as,
|
|
10
14
|
min,
|
|
@@ -13,7 +17,8 @@ export class Slider extends MosaicClient {
|
|
|
13
17
|
from,
|
|
14
18
|
column,
|
|
15
19
|
label = column,
|
|
16
|
-
value = as?.value
|
|
20
|
+
value = as?.value,
|
|
21
|
+
width
|
|
17
22
|
} = {}) {
|
|
18
23
|
super(filterBy);
|
|
19
24
|
this.id = 'slider_' + (++_id);
|
|
@@ -24,7 +29,7 @@ export class Slider extends MosaicClient {
|
|
|
24
29
|
this.max = max;
|
|
25
30
|
this.step = step;
|
|
26
31
|
|
|
27
|
-
this.element = document.createElement('div');
|
|
32
|
+
this.element = element || document.createElement('div');
|
|
28
33
|
this.element.setAttribute('class', 'input');
|
|
29
34
|
this.element.value = this;
|
|
30
35
|
|
|
@@ -38,6 +43,7 @@ export class Slider extends MosaicClient {
|
|
|
38
43
|
this.slider = document.createElement('input');
|
|
39
44
|
this.slider.setAttribute('id', this.id);
|
|
40
45
|
this.slider.setAttribute('type', 'range');
|
|
46
|
+
if (width != null) this.slider.style.width = `${+width}px`;
|
|
41
47
|
if (min != null) this.slider.setAttribute('min', min);
|
|
42
48
|
if (max != null) this.slider.setAttribute('max', max);
|
|
43
49
|
if (step != null) this.slider.setAttribute('step', step);
|
package/src/Table.js
CHANGED
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import { MosaicClient } from '@uwdata/mosaic-core';
|
|
1
|
+
import { MosaicClient, coordinator } from '@uwdata/mosaic-core';
|
|
2
2
|
import { Query, column, desc } from '@uwdata/mosaic-sql';
|
|
3
3
|
import { formatDate, formatLocaleAuto, formatLocaleNumber } from './util/format.js';
|
|
4
|
+
import { input } from './input.js';
|
|
4
5
|
|
|
5
6
|
let _id = -1;
|
|
6
7
|
|
|
8
|
+
export const table = options => input(Table, options);
|
|
9
|
+
|
|
7
10
|
export class Table extends MosaicClient {
|
|
8
11
|
constructor({
|
|
12
|
+
element,
|
|
9
13
|
filterBy,
|
|
10
14
|
from,
|
|
11
15
|
columns = ['*'],
|
|
16
|
+
align = {},
|
|
12
17
|
format,
|
|
13
|
-
rowBatch = 100,
|
|
14
18
|
width,
|
|
15
|
-
|
|
19
|
+
maxWidth,
|
|
20
|
+
height = 500,
|
|
21
|
+
rowBatch = 100,
|
|
16
22
|
} = {}) {
|
|
17
23
|
super(filterBy);
|
|
18
24
|
this.id = `table-${++_id}`;
|
|
19
25
|
this.from = from;
|
|
20
26
|
this.columns = columns;
|
|
21
27
|
this.format = format;
|
|
28
|
+
this.align = align;
|
|
29
|
+
this.widths = typeof width === 'object' ? width : {};
|
|
30
|
+
|
|
22
31
|
this.offset = 0;
|
|
23
32
|
this.limit = +rowBatch;
|
|
24
33
|
this.pending = false;
|
|
@@ -27,12 +36,11 @@ export class Table extends MosaicClient {
|
|
|
27
36
|
this.sortColumn = null;
|
|
28
37
|
this.sortDesc = false;
|
|
29
38
|
|
|
30
|
-
this.element = document.createElement('div');
|
|
39
|
+
this.element = element || document.createElement('div');
|
|
31
40
|
this.element.setAttribute('id', this.id);
|
|
32
41
|
this.element.value = this;
|
|
33
|
-
if (width) {
|
|
34
|
-
|
|
35
|
-
}
|
|
42
|
+
if (typeof width === 'number') this.element.style.width = `${width}px`;
|
|
43
|
+
if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
|
|
36
44
|
this.element.style.maxHeight = `${height}px`;
|
|
37
45
|
this.element.style.overflow = 'auto';
|
|
38
46
|
|
|
@@ -47,9 +55,7 @@ export class Table extends MosaicClient {
|
|
|
47
55
|
|
|
48
56
|
if (scrollHeight - scrollTop < 2 * clientHeight) {
|
|
49
57
|
this.pending = true;
|
|
50
|
-
this.offset
|
|
51
|
-
const query = this.queryInternal(this.filterBy?.predicate(this));
|
|
52
|
-
this.requestQuery(query);
|
|
58
|
+
this.requestData(this.offset + this.limit);
|
|
53
59
|
}
|
|
54
60
|
});
|
|
55
61
|
|
|
@@ -66,17 +72,28 @@ export class Table extends MosaicClient {
|
|
|
66
72
|
this.element.appendChild(this.style);
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
requestData(offset = 0) {
|
|
76
|
+
this.offset = offset;
|
|
77
|
+
|
|
78
|
+
// request next data batch
|
|
79
|
+
const query = this.query(this.filterBy?.predicate(this));
|
|
80
|
+
this.requestQuery(query);
|
|
81
|
+
|
|
82
|
+
// prefetch subsequent data batch
|
|
83
|
+
coordinator().prefetch(query.clone().offset(offset + this.limit));
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
fields() {
|
|
70
87
|
return this.columns.map(name => column(this.from, name));
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
this.
|
|
90
|
+
fieldInfo(info) {
|
|
91
|
+
this.schema = info;
|
|
75
92
|
|
|
76
93
|
const thead = this.head;
|
|
77
94
|
thead.innerHTML = '';
|
|
78
95
|
const tr = document.createElement('tr');
|
|
79
|
-
for (const { column } of
|
|
96
|
+
for (const { column } of info) {
|
|
80
97
|
const th = document.createElement('th');
|
|
81
98
|
th.addEventListener('click', evt => this.sort(evt, column));
|
|
82
99
|
th.appendChild(document.createElement('span'));
|
|
@@ -86,23 +103,22 @@ export class Table extends MosaicClient {
|
|
|
86
103
|
thead.appendChild(tr);
|
|
87
104
|
|
|
88
105
|
// get column formatters
|
|
89
|
-
this.formats = formatof(this.format,
|
|
106
|
+
this.formats = formatof(this.format, info);
|
|
90
107
|
|
|
91
108
|
// get column alignment style
|
|
92
|
-
this.style.innerText = tableCSS(
|
|
109
|
+
this.style.innerText = tableCSS(
|
|
110
|
+
this.id,
|
|
111
|
+
alignof(this.align, info),
|
|
112
|
+
widthof(this.widths, info)
|
|
113
|
+
);
|
|
93
114
|
|
|
94
115
|
return this;
|
|
95
116
|
}
|
|
96
117
|
|
|
97
|
-
query(filter) {
|
|
98
|
-
|
|
99
|
-
return this.queryInternal(filter);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
queryInternal(filter = []) {
|
|
103
|
-
const { from, limit, offset, stats, sortColumn, sortDesc } = this;
|
|
118
|
+
query(filter = []) {
|
|
119
|
+
const { from, limit, offset, schema, sortColumn, sortDesc } = this;
|
|
104
120
|
return Query.from(from)
|
|
105
|
-
.select(
|
|
121
|
+
.select(schema.map(s => s.column))
|
|
106
122
|
.where(filter)
|
|
107
123
|
.orderby(sortColumn ? (sortDesc ? desc(sortColumn) : sortColumn) : [])
|
|
108
124
|
.limit(limit)
|
|
@@ -120,15 +136,15 @@ export class Table extends MosaicClient {
|
|
|
120
136
|
}
|
|
121
137
|
|
|
122
138
|
update() {
|
|
123
|
-
const { body, formats, data,
|
|
124
|
-
const nf =
|
|
139
|
+
const { body, formats, data, schema, limit } = this;
|
|
140
|
+
const nf = schema.length;
|
|
125
141
|
|
|
126
142
|
let count = 0;
|
|
127
143
|
for (const row of data) {
|
|
128
144
|
++count;
|
|
129
145
|
const tr = document.createElement('tr');
|
|
130
146
|
for (let i = 0; i < nf; ++i) {
|
|
131
|
-
const value = row[
|
|
147
|
+
const value = row[schema[i].column];
|
|
132
148
|
const td = document.createElement('td');
|
|
133
149
|
td.innerText = value == null ? '' : formats[i](value);
|
|
134
150
|
tr.appendChild(td);
|
|
@@ -166,13 +182,12 @@ export class Table extends MosaicClient {
|
|
|
166
182
|
}
|
|
167
183
|
|
|
168
184
|
// issue query for sorted data
|
|
169
|
-
|
|
170
|
-
this.requestQuery(query);
|
|
185
|
+
this.requestData();
|
|
171
186
|
}
|
|
172
187
|
}
|
|
173
188
|
|
|
174
|
-
function formatof(base = {},
|
|
175
|
-
return
|
|
189
|
+
function formatof(base = {}, schema, locale) {
|
|
190
|
+
return schema.map(({ column, type }) => {
|
|
176
191
|
if (column in base) {
|
|
177
192
|
return base[column];
|
|
178
193
|
} else {
|
|
@@ -185,8 +200,8 @@ function formatof(base = {}, stats, locale) {
|
|
|
185
200
|
});
|
|
186
201
|
}
|
|
187
202
|
|
|
188
|
-
function alignof(base = {},
|
|
189
|
-
return
|
|
203
|
+
function alignof(base = {}, schema) {
|
|
204
|
+
return schema.map(({ column, type }) => {
|
|
190
205
|
if (column in base) {
|
|
191
206
|
return base[column];
|
|
192
207
|
} else if (type === 'number') {
|
|
@@ -197,11 +212,18 @@ function alignof(base = {}, stats) {
|
|
|
197
212
|
});
|
|
198
213
|
}
|
|
199
214
|
|
|
200
|
-
function
|
|
215
|
+
function widthof(base = {}, schema) {
|
|
216
|
+
return schema.map(({ column }) => base[column]);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function tableCSS(id, aligns, widths) {
|
|
201
220
|
const styles = [];
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
221
|
+
aligns.forEach((a, i) => {
|
|
222
|
+
const w = +widths[i];
|
|
223
|
+
if (a !== 'left' || w) {
|
|
224
|
+
const align = a !== 'left' ? `text-align:${a};` : '';
|
|
225
|
+
const width = w ? `width:${w}px;max-width:${w}px;` : '';
|
|
226
|
+
styles.push(`#${id} tr>:nth-child(${i+1}) {${align}${width}}`);
|
|
205
227
|
}
|
|
206
228
|
});
|
|
207
229
|
return styles.join(' ');
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Menu } from './Menu.js';
|
|
2
|
-
export { Search } from './Search.js';
|
|
3
|
-
export { Slider } from './Slider.js';
|
|
4
|
-
export { Table } from './Table.js';
|
|
1
|
+
export { Menu, menu } from './Menu.js';
|
|
2
|
+
export { Search, search } from './Search.js';
|
|
3
|
+
export { Slider, slider } from './Slider.js';
|
|
4
|
+
export { Table, table } from './Table.js';
|