@uwdata/mosaic-inputs 0.12.1 → 0.13.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/types/Menu.d.ts +79 -0
- package/dist/types/Search.d.ts +69 -0
- package/dist/types/Slider.d.ts +84 -0
- package/dist/types/Table.d.ts +116 -0
- package/dist/types/index-types.d.ts +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/input.d.ts +28 -0
- package/dist/types/util/format.d.ts +8 -0
- package/package.json +8 -11
- package/src/Menu.js +44 -15
- package/src/Search.js +37 -10
- package/src/Slider.js +42 -10
- package/src/Table.js +84 -16
- package/src/input.js +36 -3
- package/vitest.config.ts +3 -0
- package/dist/mosaic-inputs.js +0 -7043
- package/dist/mosaic-inputs.min.js +0 -2
package/src/Slider.js
CHANGED
|
@@ -1,12 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Param, Selection, clauseInterval, clausePoint, isParam, isSelection } from '@uwdata/mosaic-core';
|
|
2
2
|
import { Query, max, min } from '@uwdata/mosaic-sql';
|
|
3
|
-
import { input } from './input.js';
|
|
3
|
+
import { Input, input } from './input.js';
|
|
4
4
|
|
|
5
5
|
let _id = 0;
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Create a new slider input instance.
|
|
9
|
+
* @param {object} [options] Options object
|
|
10
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
11
|
+
* place the slider elements. If undefined, a new `div` element is created.
|
|
12
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
13
|
+
* table indicated by the *from* option.
|
|
14
|
+
* @param {Param} [options.as] The output param or selection. A selection
|
|
15
|
+
* clause is added based on the currently selected slider option.
|
|
16
|
+
* @param {string} [options.field] The database column name to use within
|
|
17
|
+
* generated selection clause predicates. Defaults to the *column* option.
|
|
18
|
+
* @param {'point' | 'interval'} [options.select] The type of selection clause
|
|
19
|
+
* predicate to generate if the **as** option is a Selection. If `'point'`
|
|
20
|
+
* (the default), the selection predicate is an equality check for the slider
|
|
21
|
+
* value. If `'interval'`, the predicate checks an interval from the minimum
|
|
22
|
+
* to the current slider value.
|
|
23
|
+
* @param {number} [options.min] The minimum slider value.
|
|
24
|
+
* @param {number} [options.max] The maximum slider value.
|
|
25
|
+
* @param {number} [options.step] The slider step, the amount to increment
|
|
26
|
+
* between consecutive values.
|
|
27
|
+
* @param {number} [options.value] The initial slider value.
|
|
28
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
29
|
+
* source for this widget. Used in conjunction with the *column* option.
|
|
30
|
+
* The minimum and maximum values of the column determine the slider range.
|
|
31
|
+
* @param {string} [options.column] The name of a database column whose values
|
|
32
|
+
* determine the slider range. Used in conjunction with the *from* option.
|
|
33
|
+
* The minimum and maximum values of the column determine the slider range.
|
|
34
|
+
* @param {string} [options.label] A text label for this input.
|
|
35
|
+
* @param {number} [options.width] The width of the slider in screen pixels.
|
|
36
|
+
* @returns {HTMLElement} The container element for a slider input.
|
|
37
|
+
*/
|
|
7
38
|
export const slider = options => input(Slider, options);
|
|
8
39
|
|
|
9
|
-
|
|
40
|
+
/**
|
|
41
|
+
* A HTML range-based slider input.
|
|
42
|
+
* @extends {Input}
|
|
43
|
+
*/
|
|
44
|
+
export class Slider extends Input {
|
|
10
45
|
/**
|
|
11
46
|
* Create a new slider input.
|
|
12
47
|
* @param {object} [options] Options object
|
|
@@ -52,7 +87,7 @@ export class Slider extends MosaicClient {
|
|
|
52
87
|
field = column,
|
|
53
88
|
width
|
|
54
89
|
} = {}) {
|
|
55
|
-
super(filterBy);
|
|
90
|
+
super(filterBy, element);
|
|
56
91
|
this.id = 'slider_' + (++_id);
|
|
57
92
|
this.from = from;
|
|
58
93
|
this.column = column || 'value';
|
|
@@ -63,10 +98,6 @@ export class Slider extends MosaicClient {
|
|
|
63
98
|
this.max = max;
|
|
64
99
|
this.step = step;
|
|
65
100
|
|
|
66
|
-
this.element = element || document.createElement('div');
|
|
67
|
-
this.element.setAttribute('class', 'input');
|
|
68
|
-
Object.defineProperty(this.element, 'value', { value: this });
|
|
69
|
-
|
|
70
101
|
if (label) {
|
|
71
102
|
const desc = document.createElement('label');
|
|
72
103
|
desc.setAttribute('for', this.id);
|
|
@@ -165,8 +196,9 @@ export class Slider extends MosaicClient {
|
|
|
165
196
|
}
|
|
166
197
|
|
|
167
198
|
activate() {
|
|
168
|
-
|
|
169
|
-
|
|
199
|
+
if (isSelection(this.selection)) {
|
|
200
|
+
this.selection.activate(this.clause(0));
|
|
201
|
+
}
|
|
170
202
|
}
|
|
171
203
|
|
|
172
204
|
publish(value) {
|
package/src/Table.js
CHANGED
|
@@ -1,16 +1,77 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Query,
|
|
1
|
+
import { Selection, clausePoints, coordinator, isParam, isSelection, toDataColumns } from '@uwdata/mosaic-core';
|
|
2
|
+
import { Query, desc } from '@uwdata/mosaic-sql';
|
|
3
3
|
import { formatDate, formatLocaleAuto, formatLocaleNumber } from './util/format.js';
|
|
4
|
-
import { input } from './input.js';
|
|
4
|
+
import { Input, input } from './input.js';
|
|
5
5
|
|
|
6
6
|
let _id = -1;
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Create a new table input instance.
|
|
10
|
+
* @param {object} options Options object
|
|
11
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
12
|
+
* place the table element. If undefined, a new `div` element is created.
|
|
13
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
14
|
+
* table indicated by the *from* option.
|
|
15
|
+
* @param {Selection} [options.as] The output selection. A selection
|
|
16
|
+
* clause is added for the currently selected table row.
|
|
17
|
+
* @param {{ [name: string]: 'left' | 'right' | 'center' }} [options.align]
|
|
18
|
+
* An object that maps column names to horiztonal text alignment values. If
|
|
19
|
+
* unspecified, alignment is determined based on the column data type.
|
|
20
|
+
* @param {{ [name: string]: (value: any) => string }} [options.format] An
|
|
21
|
+
* object that maps column names to format functions to use for that
|
|
22
|
+
* column's data. Each format function takes a value as input and generates
|
|
23
|
+
* formatted text to show in the table.
|
|
24
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
25
|
+
* source for this widget. Used in conjunction with the *columns* option.
|
|
26
|
+
* @param {string[]} [options.columns] The name of database columns to include
|
|
27
|
+
* in the table component. If unspecified, all columns are included.
|
|
28
|
+
* Used in conjunction with the *from* option.
|
|
29
|
+
* @param {number | { [name: string]: number }} [options.width] If a number,
|
|
30
|
+
* sets the desired width of the table, in pixels. If an object, is used to
|
|
31
|
+
* set explicit pixel widts for each named column included in the object.
|
|
32
|
+
* @param {number} [options.maxWidth] The maximum width of the table, in pixels.
|
|
33
|
+
* @param {number} [options.height] The desired height of the table, in pixels.
|
|
34
|
+
* @param {number} [options.rowBatch] The number of rows to request per query
|
|
35
|
+
* batch. The batch size will be used to prefetch data beyond the currently
|
|
36
|
+
* visible range.
|
|
37
|
+
* @returns {HTMLElement} The container element for a table component.
|
|
38
|
+
*/
|
|
8
39
|
export const table = options => input(Table, options);
|
|
9
40
|
|
|
10
|
-
|
|
41
|
+
/**
|
|
42
|
+
* A HTML table based table component.
|
|
43
|
+
* @extends {Input}
|
|
44
|
+
*/
|
|
45
|
+
export class Table extends Input {
|
|
11
46
|
/**
|
|
12
47
|
* Create a new Table instance.
|
|
13
48
|
* @param {object} options Options object
|
|
49
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
50
|
+
* place the table element. If undefined, a new `div` element is created.
|
|
51
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
52
|
+
* table indicated by the *from* option.
|
|
53
|
+
* @param {Selection} [options.as] The output selection. A selection
|
|
54
|
+
* clause is added for the currently selected table row.
|
|
55
|
+
* @param {{ [name: string]: 'left' | 'right' | 'center' }} [options.align]
|
|
56
|
+
* An object that maps column names to horiztonal text alignment values. If
|
|
57
|
+
* unspecified, alignment is determined based on the column data type.
|
|
58
|
+
* @param {{ [name: string]: (value: any) => string }} [options.format] An
|
|
59
|
+
* object that maps column names to format functions to use for that
|
|
60
|
+
* column's data. Each format function takes a value as input and generates
|
|
61
|
+
* formatted text to show in the table.
|
|
62
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
63
|
+
* source for this widget. Used in conjunction with the *columns* option.
|
|
64
|
+
* @param {string[]} [options.columns] The name of database columns to include
|
|
65
|
+
* in the table component. If unspecified, all columns are included.
|
|
66
|
+
* Used in conjunction with the *from* option.
|
|
67
|
+
* @param {number | { [name: string]: number }} [options.width] If a number,
|
|
68
|
+
* sets the desired width of the table, in pixels. If an object, is used to
|
|
69
|
+
* set explicit pixel widts for each named column included in the object.
|
|
70
|
+
* @param {number} [options.maxWidth] The maximum width of the table, in pixels.
|
|
71
|
+
* @param {number} [options.height] The desired height of the table, in pixels.
|
|
72
|
+
* @param {number} [options.rowBatch] The number of rows to request per query
|
|
73
|
+
* batch. The batch size will be used to prefetch data beyond the currently
|
|
74
|
+
* visible range.
|
|
14
75
|
*/
|
|
15
76
|
constructor({
|
|
16
77
|
element,
|
|
@@ -25,8 +86,11 @@ export class Table extends MosaicClient {
|
|
|
25
86
|
rowBatch = 100,
|
|
26
87
|
as
|
|
27
88
|
} = {}) {
|
|
28
|
-
super(filterBy);
|
|
89
|
+
super(filterBy, element, null);
|
|
90
|
+
|
|
29
91
|
this.id = `table-${++_id}`;
|
|
92
|
+
this.element.setAttribute('id', this.id);
|
|
93
|
+
|
|
30
94
|
this.from = from;
|
|
31
95
|
this.columns = columns;
|
|
32
96
|
this.format = format;
|
|
@@ -40,7 +104,7 @@ export class Table extends MosaicClient {
|
|
|
40
104
|
|
|
41
105
|
this.offset = 0;
|
|
42
106
|
this.limit = +rowBatch;
|
|
43
|
-
this.
|
|
107
|
+
this.isPending = false;
|
|
44
108
|
|
|
45
109
|
this.selection = as;
|
|
46
110
|
this.currentRow = -1;
|
|
@@ -49,9 +113,6 @@ export class Table extends MosaicClient {
|
|
|
49
113
|
this.sortColumn = null;
|
|
50
114
|
this.sortDesc = false;
|
|
51
115
|
|
|
52
|
-
this.element = element || document.createElement('div');
|
|
53
|
-
this.element.setAttribute('id', this.id);
|
|
54
|
-
Object.defineProperty(this.element, 'value', { value: this });
|
|
55
116
|
if (typeof width === 'number') this.element.style.width = `${width}px`;
|
|
56
117
|
if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
|
|
57
118
|
this.element.style.maxHeight = `${height}px`;
|
|
@@ -59,15 +120,16 @@ export class Table extends MosaicClient {
|
|
|
59
120
|
|
|
60
121
|
let prevScrollTop = -1;
|
|
61
122
|
this.element.addEventListener('scroll', evt => {
|
|
62
|
-
const {
|
|
123
|
+
const { isPending, loaded } = this;
|
|
124
|
+
// @ts-ignore
|
|
63
125
|
const { scrollHeight, scrollTop, clientHeight } = evt.target;
|
|
64
126
|
|
|
65
127
|
const back = scrollTop < prevScrollTop;
|
|
66
128
|
prevScrollTop = scrollTop;
|
|
67
|
-
if (back ||
|
|
129
|
+
if (back || isPending || loaded) return;
|
|
68
130
|
|
|
69
131
|
if (scrollHeight - scrollTop < 2 * clientHeight) {
|
|
70
|
-
this.
|
|
132
|
+
this.isPending = true;
|
|
71
133
|
this.requestData(this.offset + this.limit);
|
|
72
134
|
}
|
|
73
135
|
});
|
|
@@ -125,8 +187,8 @@ export class Table extends MosaicClient {
|
|
|
125
187
|
}
|
|
126
188
|
|
|
127
189
|
fields() {
|
|
128
|
-
const
|
|
129
|
-
return this.columns.map(
|
|
190
|
+
const table = this.sourceTable();
|
|
191
|
+
return this.columns.map(column => ({ column, table }));
|
|
130
192
|
}
|
|
131
193
|
|
|
132
194
|
fieldInfo(info) {
|
|
@@ -168,7 +230,7 @@ export class Table extends MosaicClient {
|
|
|
168
230
|
}
|
|
169
231
|
|
|
170
232
|
queryResult(data) {
|
|
171
|
-
if (!this.
|
|
233
|
+
if (!this.isPending) {
|
|
172
234
|
// data is not from an internal request, so reset table
|
|
173
235
|
this.loaded = false;
|
|
174
236
|
this.data = [];
|
|
@@ -204,10 +266,16 @@ export class Table extends MosaicClient {
|
|
|
204
266
|
this.loaded = true;
|
|
205
267
|
}
|
|
206
268
|
|
|
207
|
-
this.
|
|
269
|
+
this.isPending = false;
|
|
208
270
|
return this;
|
|
209
271
|
}
|
|
210
272
|
|
|
273
|
+
activate() {
|
|
274
|
+
if (isSelection(this.selection)) {
|
|
275
|
+
this.selection.activate(this.clause([]));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
211
279
|
sort(event, column) {
|
|
212
280
|
if (column === this.sortColumn) {
|
|
213
281
|
this.sortDesc = !this.sortDesc;
|
package/src/input.js
CHANGED
|
@@ -1,7 +1,40 @@
|
|
|
1
|
-
import { coordinator } from '@uwdata/mosaic-core';
|
|
1
|
+
import { coordinator, MosaicClient } from '@uwdata/mosaic-core';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Instantiate an input, register it with the coordinator, and
|
|
5
|
+
* return the corresponding HTML element.
|
|
6
|
+
* @template {new (...args: any) => Input} T
|
|
7
|
+
* @param {T} InputClass
|
|
8
|
+
* @param {ConstructorParameters<T>} params
|
|
9
|
+
* @returns {HTMLElement} The container element of the input.
|
|
10
|
+
*/
|
|
11
|
+
export function input(InputClass, ...params) {
|
|
12
|
+
const input = new InputClass(...params);
|
|
5
13
|
coordinator().connect(input);
|
|
6
14
|
return input.element;
|
|
7
15
|
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Base class for input components.
|
|
19
|
+
* @import {Activatable} from '@uwdata/mosaic-core'
|
|
20
|
+
* @implements {Activatable}
|
|
21
|
+
*/
|
|
22
|
+
export class Input extends MosaicClient {
|
|
23
|
+
/**
|
|
24
|
+
* Create a new input instance.
|
|
25
|
+
* @param {import('@uwdata/mosaic-core').Selection} [filterBy] A selection
|
|
26
|
+
* with which to filter backing data that parameterizes this input.
|
|
27
|
+
* @param {HTMLElement} [element] Optional container HTML element to use.
|
|
28
|
+
* @param {string} [className] A class name to set on the container element.
|
|
29
|
+
*/
|
|
30
|
+
constructor(filterBy, element, className = 'input') {
|
|
31
|
+
super(filterBy);
|
|
32
|
+
this.element = element || document.createElement('div');
|
|
33
|
+
if (className) this.element.setAttribute('class', className);
|
|
34
|
+
Object.defineProperty(this.element, 'value', { value: this });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
activate() {
|
|
38
|
+
// subclasses should override
|
|
39
|
+
}
|
|
40
|
+
}
|
package/vitest.config.ts
ADDED