@uwdata/mosaic-inputs 0.12.2 → 0.14.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 +39 -10
- package/src/Search.js +37 -10
- package/src/Slider.js +42 -10
- package/src/Table.js +81 -13
- package/src/input.js +36 -3
- package/vitest.config.ts +3 -0
- package/dist/mosaic-inputs.js +0 -7047
- package/dist/mosaic-inputs.min.js +0 -2
package/src/Table.js
CHANGED
|
@@ -1,16 +1,77 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Selection, clausePoints, coordinator, isParam, isSelection, toDataColumns } from '@uwdata/mosaic-core';
|
|
2
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
|
});
|
|
@@ -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