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