baseui 10.9.0 → 10.9.1
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/data-table/column-numerical.js +355 -307
- package/data-table/column-numerical.js.flow +287 -273
- package/data-table/constants.js +11 -17
- package/data-table/constants.js.flow +8 -11
- package/data-table/data-table.js +50 -53
- package/data-table/data-table.js.flow +13 -18
- package/data-table/filter-shell.js +4 -27
- package/data-table/filter-shell.js.flow +9 -33
- package/data-table/locale.js +2 -4
- package/data-table/locale.js.flow +2 -6
- package/data-table/measure-column-widths.js +121 -83
- package/data-table/measure-column-widths.js.flow +109 -87
- package/es/data-table/column-numerical.js +317 -245
- package/es/data-table/constants.js +8 -12
- package/es/data-table/data-table.js +16 -18
- package/es/data-table/filter-shell.js +4 -26
- package/es/data-table/locale.js +2 -4
- package/es/data-table/measure-column-widths.js +86 -75
- package/es/form-control/form-control.js +58 -7
- package/es/form-control/styled-components.js +27 -6
- package/es/popover/popover.js +1 -1
- package/esm/data-table/column-numerical.js +353 -304
- package/esm/data-table/constants.js +8 -12
- package/esm/data-table/data-table.js +50 -53
- package/esm/data-table/filter-shell.js +4 -26
- package/esm/data-table/locale.js +2 -4
- package/esm/data-table/measure-column-widths.js +121 -83
- package/esm/form-control/form-control.js +60 -9
- package/esm/form-control/styled-components.js +23 -3
- package/esm/popover/popover.js +1 -1
- package/form-control/form-control.js +61 -8
- package/form-control/form-control.js.flow +82 -10
- package/form-control/index.d.ts +1 -0
- package/form-control/styled-components.js +27 -5
- package/form-control/styled-components.js.flow +25 -3
- package/form-control/types.js.flow +20 -8
- package/package.json +1 -2
- package/popover/popover.js +1 -1
- package/popover/popover.js.flow +1 -1
|
@@ -11,12 +11,11 @@ import { Button, SIZE } from '../button/index.js';
|
|
|
11
11
|
import { ButtonGroup, MODE } from '../button-group/index.js';
|
|
12
12
|
import { Input, SIZE as INPUT_SIZE } from '../input/index.js';
|
|
13
13
|
import { useStyletron } from '../styles/index.js';
|
|
14
|
+
import { ParagraphXSmall } from '../typography/index.js';
|
|
14
15
|
import Column from './column.js';
|
|
15
|
-
import { COLUMNS, NUMERICAL_FORMATS,
|
|
16
|
+
import { COLUMNS, NUMERICAL_FORMATS, NUMERICAL_OPERATIONS } from './constants.js';
|
|
16
17
|
import FilterShell from './filter-shell.js';
|
|
17
18
|
import { LocaleContext } from '../locale/index.js';
|
|
18
|
-
import { bin, max as maxFunc, extent, scaleLinear, median, bisector } from 'd3';
|
|
19
|
-
import { Slider } from '../slider/index.js';
|
|
20
19
|
|
|
21
20
|
function roundToFixed(value, precision) {
|
|
22
21
|
const k = Math.pow(10, precision);
|
|
@@ -63,170 +62,250 @@ function validateInput(input) {
|
|
|
63
62
|
return Boolean(parseFloat(input)) || input === '' || input === '-';
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
xScale,
|
|
79
|
-
yScale
|
|
80
|
-
} = React.useMemo(() => {
|
|
81
|
-
const bins = bin().thresholds(Math.min(data.length, MAX_BIN_COUNT))(data);
|
|
82
|
-
const xScale = scaleLinear().domain([bins[0].x0, bins[bins.length - 1].x1]).range([0, HISTOGRAM_SIZE.width]).clamp(true);
|
|
83
|
-
const yScale = scaleLinear().domain([0, maxFunc(bins, d => d.length)]).nice().range([HISTOGRAM_SIZE.height, 0]);
|
|
84
|
-
return {
|
|
85
|
-
bins,
|
|
86
|
-
xScale,
|
|
87
|
-
yScale
|
|
88
|
-
};
|
|
89
|
-
}, [data]); // We need to find the index of bar which is nearest to the given single value
|
|
90
|
-
|
|
91
|
-
const singleIndexNearest = React.useMemo(() => {
|
|
92
|
-
if (isRange) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return bisect.center(bins, lower);
|
|
97
|
-
}, [isRange, data, lower, upper]);
|
|
98
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
99
|
-
className: css({
|
|
100
|
-
display: 'flex',
|
|
101
|
-
marginTop: theme.sizing.scale600,
|
|
102
|
-
marginLeft: theme.sizing.scale200,
|
|
103
|
-
marginRight: 0,
|
|
104
|
-
marginBottom: theme.sizing.scale400,
|
|
105
|
-
justifyContent: 'space-between',
|
|
106
|
-
overflow: 'visible'
|
|
107
|
-
})
|
|
108
|
-
}, /*#__PURE__*/React.createElement("svg", HISTOGRAM_SIZE, bins.map((d, index) => {
|
|
109
|
-
const x = xScale(d.x0) + 1;
|
|
110
|
-
const y = yScale(d.length);
|
|
111
|
-
const width = Math.max(0, xScale(d.x1) - xScale(d.x0) - 1);
|
|
112
|
-
const height = yScale(0) - yScale(d.length);
|
|
113
|
-
let included;
|
|
114
|
-
|
|
115
|
-
if (singleIndexNearest != null) {
|
|
116
|
-
included = index === singleIndexNearest;
|
|
65
|
+
function filterParamsToInitialState(filterParams) {
|
|
66
|
+
if (filterParams) {
|
|
67
|
+
if (filterParams.comparisons.length > 1) {
|
|
68
|
+
if (filterParams.comparisons[0].operation === NUMERICAL_OPERATIONS.LT && filterParams.comparisons[1].operation === NUMERICAL_OPERATIONS.GT) {
|
|
69
|
+
return {
|
|
70
|
+
exclude: !filterParams.exclude,
|
|
71
|
+
comparatorIndex: 0,
|
|
72
|
+
operatorIndex: 4,
|
|
73
|
+
right: filterParams.comparisons[1].value.toString(),
|
|
74
|
+
left: filterParams.comparisons[0].value.toString()
|
|
75
|
+
};
|
|
76
|
+
}
|
|
117
77
|
} else {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
78
|
+
const comparison = filterParams.comparisons[0];
|
|
79
|
+
|
|
80
|
+
if (comparison.operation === NUMERICAL_OPERATIONS.LT) {
|
|
81
|
+
return {
|
|
82
|
+
exclude: filterParams.exclude,
|
|
83
|
+
comparatorIndex: 0,
|
|
84
|
+
operatorIndex: 0,
|
|
85
|
+
left: '',
|
|
86
|
+
right: comparison.value.toString()
|
|
87
|
+
};
|
|
88
|
+
} else if (comparison.operation === NUMERICAL_OPERATIONS.GT) {
|
|
89
|
+
return {
|
|
90
|
+
exclude: filterParams.exclude,
|
|
91
|
+
comparatorIndex: 0,
|
|
92
|
+
operatorIndex: 1,
|
|
93
|
+
left: comparison.value.toString(),
|
|
94
|
+
right: ''
|
|
95
|
+
};
|
|
96
|
+
} else if (comparison.operation === NUMERICAL_OPERATIONS.LTE) {
|
|
97
|
+
return {
|
|
98
|
+
exclude: filterParams.exclude,
|
|
99
|
+
comparatorIndex: 0,
|
|
100
|
+
operatorIndex: 2,
|
|
101
|
+
left: '',
|
|
102
|
+
right: comparison.value.toString()
|
|
103
|
+
};
|
|
104
|
+
} else if (comparison.operation === NUMERICAL_OPERATIONS.GTE) {
|
|
105
|
+
return {
|
|
106
|
+
exclude: filterParams.exclude,
|
|
107
|
+
comparatorIndex: 0,
|
|
108
|
+
operatorIndex: 3,
|
|
109
|
+
left: comparison.value.toString(),
|
|
110
|
+
right: ''
|
|
111
|
+
};
|
|
112
|
+
} else if (comparison.operation === NUMERICAL_OPERATIONS.EQ) {
|
|
113
|
+
return {
|
|
114
|
+
exclude: filterParams.exclude,
|
|
115
|
+
comparatorIndex: 1,
|
|
116
|
+
operatorIndex: 0,
|
|
117
|
+
left: comparison.value.toString(),
|
|
118
|
+
right: ''
|
|
119
|
+
};
|
|
120
|
+
}
|
|
125
121
|
}
|
|
122
|
+
}
|
|
126
123
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
})));
|
|
136
|
-
});
|
|
124
|
+
return {
|
|
125
|
+
exclude: false,
|
|
126
|
+
comparatorIndex: 0,
|
|
127
|
+
operatorIndex: 0,
|
|
128
|
+
left: '',
|
|
129
|
+
right: ''
|
|
130
|
+
};
|
|
131
|
+
}
|
|
137
132
|
|
|
138
133
|
function NumericalFilter(props) {
|
|
139
134
|
const [css, theme] = useStyletron();
|
|
140
135
|
const locale = React.useContext(LocaleContext);
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// TODO look into allowing semantic names, similar to the radio component. Tricky part would be backwards compat
|
|
154
|
-
|
|
155
|
-
const [comparatorIndex, setComparatorIndex] = React.useState(() => {
|
|
156
|
-
switch (initialState.excludeKind) {
|
|
157
|
-
case 'value':
|
|
158
|
-
return 1;
|
|
159
|
-
|
|
160
|
-
case 'range':
|
|
161
|
-
default:
|
|
162
|
-
// fallthrough
|
|
163
|
-
return 0;
|
|
136
|
+
const initialState = filterParamsToInitialState(props.filterParams);
|
|
137
|
+
const [exclude, setExclude] = React.useState(initialState.exclude);
|
|
138
|
+
const [comparatorIndex, setComparatorIndex] = React.useState(initialState.comparatorIndex);
|
|
139
|
+
const [operatorIndex, setOperatorIndex] = React.useState(initialState.operatorIndex);
|
|
140
|
+
const [left, setLeft] = React.useState(initialState.left);
|
|
141
|
+
const [right, setRight] = React.useState(initialState.right);
|
|
142
|
+
const isRange = comparatorIndex === 0;
|
|
143
|
+
const min = React.useMemo(() => Math.min(...props.data), [props.data]);
|
|
144
|
+
const max = React.useMemo(() => Math.max(...props.data), [props.data]);
|
|
145
|
+
React.useEffect(() => {
|
|
146
|
+
if (!left) {
|
|
147
|
+
setLeft(min.toString());
|
|
164
148
|
}
|
|
165
|
-
}); // We use the d3 function to get the extent as it's a little more robust to null, -Infinity, etc.
|
|
166
|
-
|
|
167
|
-
const [min, max] = React.useMemo(() => extent(props.data), [props.data]);
|
|
168
|
-
const [lv, setLower] = React.useState(() => roundToFixed(initialState.lowerValue || min, precision));
|
|
169
|
-
const [uv, setUpper] = React.useState(() => roundToFixed(initialState.upperValue || max, precision)); // We keep a separate value for the single select, to give a user the ability to toggle between
|
|
170
|
-
// the range and single values without losing their previous input.
|
|
171
149
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
// if we don't do this, a user can't input partial numbers, e.g. "-", or "3."
|
|
150
|
+
if (!right) {
|
|
151
|
+
setRight(max.toString());
|
|
152
|
+
}
|
|
153
|
+
}, []);
|
|
154
|
+
const [leftDisabled, rightDisabled] = React.useMemo(() => {
|
|
155
|
+
if (!isRange) return [false, false];
|
|
179
156
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return [isRange ? lv : sv, uv];
|
|
184
|
-
} // once the user is done inputting.
|
|
185
|
-
// we validate then format to the given precision
|
|
157
|
+
switch (operatorIndex) {
|
|
158
|
+
case 4:
|
|
159
|
+
return [false, false];
|
|
186
160
|
|
|
161
|
+
case 0:
|
|
162
|
+
case 2:
|
|
163
|
+
return [true, false];
|
|
187
164
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return [roundToFixed(l, precision), roundToFixed(h, precision)];
|
|
192
|
-
}, [isRange, focused, sv, lv, uv, precision]); // We bound the values within our min and max even if a user enters a huge number
|
|
165
|
+
case 1:
|
|
166
|
+
case 3:
|
|
167
|
+
return [false, true];
|
|
193
168
|
|
|
194
|
-
|
|
169
|
+
default:
|
|
170
|
+
return [true, true];
|
|
171
|
+
}
|
|
172
|
+
}, [operatorIndex, isRange]);
|
|
173
|
+
const leftInputRef = React.useRef(null);
|
|
174
|
+
const rightInputRef = React.useRef(null);
|
|
175
|
+
React.useEffect(() => {
|
|
176
|
+
if (!leftDisabled && leftInputRef.current) {
|
|
177
|
+
leftInputRef.current.focus({
|
|
178
|
+
preventScroll: true
|
|
179
|
+
});
|
|
180
|
+
} else if (!rightDisabled && rightInputRef.current) {
|
|
181
|
+
rightInputRef.current.focus({
|
|
182
|
+
preventScroll: true
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}, [leftDisabled, rightDisabled, comparatorIndex]);
|
|
186
|
+
React.useEffect(() => {
|
|
187
|
+
switch (operatorIndex) {
|
|
188
|
+
case 4:
|
|
189
|
+
default:
|
|
190
|
+
break;
|
|
195
191
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
192
|
+
case 1:
|
|
193
|
+
case 3:
|
|
194
|
+
setRight(max.toString());
|
|
195
|
+
break;
|
|
199
196
|
|
|
197
|
+
case 0:
|
|
198
|
+
case 2:
|
|
199
|
+
setLeft(min.toString());
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}, [operatorIndex]);
|
|
200
203
|
return /*#__PURE__*/React.createElement(FilterShell, {
|
|
201
204
|
exclude: exclude,
|
|
202
205
|
onExcludeChange: () => setExclude(!exclude),
|
|
203
|
-
excludeKind: excludeKind,
|
|
204
206
|
onApply: () => {
|
|
205
207
|
if (isRange) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
208
|
+
switch (operatorIndex) {
|
|
209
|
+
case 0:
|
|
210
|
+
{
|
|
211
|
+
const value = parseFloat(right);
|
|
212
|
+
const operation = NUMERICAL_OPERATIONS.LT;
|
|
213
|
+
props.setFilter({
|
|
214
|
+
comparisons: [{
|
|
215
|
+
value,
|
|
216
|
+
operation
|
|
217
|
+
}],
|
|
218
|
+
description: `< ${value}`,
|
|
219
|
+
exclude
|
|
220
|
+
});
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
case 1:
|
|
225
|
+
{
|
|
226
|
+
const value = parseFloat(left);
|
|
227
|
+
const operation = NUMERICAL_OPERATIONS.GT;
|
|
228
|
+
props.setFilter({
|
|
229
|
+
comparisons: [{
|
|
230
|
+
value,
|
|
231
|
+
operation
|
|
232
|
+
}],
|
|
233
|
+
description: `> ${value}`,
|
|
234
|
+
exclude
|
|
235
|
+
});
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
case 2:
|
|
240
|
+
{
|
|
241
|
+
const value = parseFloat(right);
|
|
242
|
+
const operation = NUMERICAL_OPERATIONS.LTE;
|
|
243
|
+
props.setFilter({
|
|
244
|
+
comparisons: [{
|
|
245
|
+
value,
|
|
246
|
+
operation
|
|
247
|
+
}],
|
|
248
|
+
description: `≤ ${value}`,
|
|
249
|
+
exclude
|
|
250
|
+
});
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case 3:
|
|
255
|
+
{
|
|
256
|
+
const value = parseFloat(left);
|
|
257
|
+
const operation = NUMERICAL_OPERATIONS.GTE;
|
|
258
|
+
props.setFilter({
|
|
259
|
+
comparisons: [{
|
|
260
|
+
value,
|
|
261
|
+
operation
|
|
262
|
+
}],
|
|
263
|
+
description: `≥ ${value}`,
|
|
264
|
+
exclude
|
|
265
|
+
});
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
case 4:
|
|
270
|
+
{
|
|
271
|
+
// 'between' case is interesting since if we want less than 10 plus greater than 5
|
|
272
|
+
// comparators, the filter will include _all_ numbers.
|
|
273
|
+
const leftValue = parseFloat(left);
|
|
274
|
+
const rightValue = parseFloat(right);
|
|
275
|
+
props.setFilter({
|
|
276
|
+
comparisons: [{
|
|
277
|
+
value: leftValue,
|
|
278
|
+
operation: NUMERICAL_OPERATIONS.LT
|
|
279
|
+
}, {
|
|
280
|
+
value: rightValue,
|
|
281
|
+
operation: NUMERICAL_OPERATIONS.GT
|
|
282
|
+
}],
|
|
283
|
+
description: `≥ ${leftValue} & ≤ ${rightValue}`,
|
|
284
|
+
exclude: !exclude
|
|
285
|
+
});
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
default:
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
215
292
|
} else {
|
|
216
|
-
const value = parseFloat(
|
|
293
|
+
const value = parseFloat(left);
|
|
294
|
+
const operation = NUMERICAL_OPERATIONS.EQ;
|
|
217
295
|
props.setFilter({
|
|
296
|
+
comparisons: [{
|
|
297
|
+
value,
|
|
298
|
+
operation
|
|
299
|
+
}],
|
|
218
300
|
description: `= ${value}`,
|
|
219
|
-
exclude
|
|
220
|
-
lowerValue: inputValueLower,
|
|
221
|
-
upperValue: inputValueLower,
|
|
222
|
-
excludeKind
|
|
301
|
+
exclude
|
|
223
302
|
});
|
|
224
303
|
}
|
|
225
304
|
|
|
226
305
|
props.close();
|
|
227
306
|
}
|
|
228
307
|
}, /*#__PURE__*/React.createElement(ButtonGroup, {
|
|
229
|
-
size: SIZE.
|
|
308
|
+
size: SIZE.compact,
|
|
230
309
|
mode: MODE.radio,
|
|
231
310
|
selected: comparatorIndex,
|
|
232
311
|
onClick: (_, index) => setComparatorIndex(index),
|
|
@@ -247,8 +326,7 @@ function NumericalFilter(props) {
|
|
|
247
326
|
width: '100%'
|
|
248
327
|
}
|
|
249
328
|
}
|
|
250
|
-
}
|
|
251
|
-
"aria-label": locale.datatable.numericalFilterRange
|
|
329
|
+
}
|
|
252
330
|
}, locale.datatable.numericalFilterRange), /*#__PURE__*/React.createElement(Button, {
|
|
253
331
|
type: "button",
|
|
254
332
|
overrides: {
|
|
@@ -257,140 +335,112 @@ function NumericalFilter(props) {
|
|
|
257
335
|
width: '100%'
|
|
258
336
|
}
|
|
259
337
|
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
isRange: isRange,
|
|
267
|
-
exclude: exclude,
|
|
268
|
-
precision: props.options.precision
|
|
269
|
-
}), /*#__PURE__*/React.createElement("div", {
|
|
270
|
-
className: css({
|
|
271
|
-
display: 'flex',
|
|
272
|
-
justifyContent: 'space-between'
|
|
273
|
-
})
|
|
274
|
-
}, /*#__PURE__*/React.createElement(Slider // The slider throws errors when switching between single and two values
|
|
275
|
-
// when it tries to read getThumbDistance on a thumb which is not there anymore
|
|
276
|
-
// if we create a new instance these errors are prevented.
|
|
277
|
-
, {
|
|
278
|
-
key: isRange.toString(),
|
|
279
|
-
min: min,
|
|
280
|
-
max: max,
|
|
281
|
-
value: sliderValue,
|
|
282
|
-
onChange: ({
|
|
283
|
-
value
|
|
284
|
-
}) => {
|
|
285
|
-
if (!value) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (isRange) {
|
|
290
|
-
const [lowerValue, upperValue] = value;
|
|
291
|
-
setLower(lowerValue);
|
|
292
|
-
setUpper(upperValue);
|
|
293
|
-
} else {
|
|
294
|
-
const [singleValue] = value;
|
|
295
|
-
setSingle(singleValue);
|
|
296
|
-
}
|
|
297
|
-
},
|
|
338
|
+
}
|
|
339
|
+
}, locale.datatable.numericalFilterSingleValue)), isRange && /*#__PURE__*/React.createElement(ButtonGroup, {
|
|
340
|
+
size: SIZE.compact,
|
|
341
|
+
mode: MODE.radio,
|
|
342
|
+
selected: operatorIndex,
|
|
343
|
+
onClick: (_, index) => setOperatorIndex(index),
|
|
298
344
|
overrides: {
|
|
299
|
-
InnerThumb: function InnerThumb({
|
|
300
|
-
$value,
|
|
301
|
-
$thumbIndex
|
|
302
|
-
}) {
|
|
303
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, $value[$thumbIndex]);
|
|
304
|
-
},
|
|
305
|
-
TickBar: ({
|
|
306
|
-
$min,
|
|
307
|
-
$max
|
|
308
|
-
}) => null,
|
|
309
|
-
// we don't want the ticks
|
|
310
|
-
ThumbValue: () => null,
|
|
311
345
|
Root: {
|
|
312
|
-
style: () => ({
|
|
313
|
-
// Aligns the center of the slider handles with the histogram bars
|
|
314
|
-
width: 'calc(100% + 14px)',
|
|
315
|
-
margin: '0 -7px'
|
|
316
|
-
})
|
|
317
|
-
},
|
|
318
|
-
InnerTrack: {
|
|
319
346
|
style: ({
|
|
320
347
|
$theme
|
|
321
|
-
}) => {
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
// For range selection we use the color as is, but when selecting the single value,
|
|
325
|
-
// we don't want the track standing out, so mute its color
|
|
326
|
-
background: theme.colors.mono400
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
Thumb: {
|
|
332
|
-
style: () => ({
|
|
333
|
-
// Slider handles are small enough to visually be centered within each histogram bar
|
|
334
|
-
height: '18px',
|
|
335
|
-
width: '18px',
|
|
336
|
-
fontSize: '0px'
|
|
348
|
+
}) => ({
|
|
349
|
+
marginBottom: $theme.sizing.scale500
|
|
337
350
|
})
|
|
338
351
|
}
|
|
339
352
|
}
|
|
340
|
-
}
|
|
353
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
354
|
+
type: "button",
|
|
355
|
+
overrides: {
|
|
356
|
+
BaseButton: {
|
|
357
|
+
style: {
|
|
358
|
+
width: '100%'
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}, "<"), /*#__PURE__*/React.createElement(Button, {
|
|
363
|
+
type: "button",
|
|
364
|
+
overrides: {
|
|
365
|
+
BaseButton: {
|
|
366
|
+
style: {
|
|
367
|
+
width: '100%'
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}, ">"), /*#__PURE__*/React.createElement(Button, {
|
|
372
|
+
type: "button",
|
|
373
|
+
overrides: {
|
|
374
|
+
BaseButton: {
|
|
375
|
+
style: {
|
|
376
|
+
width: '100%'
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}, "\u2264"), /*#__PURE__*/React.createElement(Button, {
|
|
381
|
+
type: "button",
|
|
382
|
+
overrides: {
|
|
383
|
+
BaseButton: {
|
|
384
|
+
style: {
|
|
385
|
+
width: '100%'
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}, "\u2265"), /*#__PURE__*/React.createElement(Button, {
|
|
390
|
+
type: "button",
|
|
391
|
+
overrides: {
|
|
392
|
+
BaseButton: {
|
|
393
|
+
style: {
|
|
394
|
+
width: '100%'
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}, "=")), /*#__PURE__*/React.createElement("div", {
|
|
399
|
+
className: css({
|
|
400
|
+
display: 'flex',
|
|
401
|
+
justifyContent: 'space-between',
|
|
402
|
+
marginLeft: theme.sizing.scale300,
|
|
403
|
+
marginRight: theme.sizing.scale300
|
|
404
|
+
})
|
|
405
|
+
}, /*#__PURE__*/React.createElement(ParagraphXSmall, null, format(min, props.options)), ' ', /*#__PURE__*/React.createElement(ParagraphXSmall, null, format(max, props.options))), /*#__PURE__*/React.createElement("div", {
|
|
341
406
|
className: css({
|
|
342
407
|
display: 'flex',
|
|
343
|
-
marginTop: theme.sizing.scale400,
|
|
344
|
-
// This % gap is visually appealing given the filter box width
|
|
345
|
-
gap: '30%',
|
|
346
408
|
justifyContent: 'space-between'
|
|
347
409
|
})
|
|
348
410
|
}, /*#__PURE__*/React.createElement(Input, {
|
|
349
|
-
|
|
350
|
-
max: max,
|
|
351
|
-
size: INPUT_SIZE.mini,
|
|
411
|
+
size: INPUT_SIZE.compact,
|
|
352
412
|
overrides: {
|
|
353
413
|
Root: {
|
|
354
414
|
style: {
|
|
355
|
-
width: '100%'
|
|
415
|
+
width: isRange ? '152px' : '100%'
|
|
356
416
|
}
|
|
357
417
|
}
|
|
358
418
|
},
|
|
359
|
-
|
|
419
|
+
disabled: leftDisabled,
|
|
420
|
+
inputRef: leftInputRef,
|
|
421
|
+
value: left,
|
|
360
422
|
onChange: event => {
|
|
361
423
|
if (validateInput(event.target.value)) {
|
|
362
|
-
|
|
363
|
-
setLower(event.target.value) : // $FlowFixMe - we know it is a number by now
|
|
364
|
-
setSingle(event.target.value);
|
|
424
|
+
setLeft(event.target.value);
|
|
365
425
|
}
|
|
366
|
-
}
|
|
367
|
-
onFocus: () => setFocus(true),
|
|
368
|
-
onBlur: () => setFocus(false)
|
|
426
|
+
}
|
|
369
427
|
}), isRange && /*#__PURE__*/React.createElement(Input, {
|
|
370
|
-
|
|
371
|
-
max: max,
|
|
372
|
-
size: INPUT_SIZE.mini,
|
|
428
|
+
size: INPUT_SIZE.compact,
|
|
373
429
|
overrides: {
|
|
374
|
-
Input: {
|
|
375
|
-
style: {
|
|
376
|
-
textAlign: 'right'
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
430
|
Root: {
|
|
380
431
|
style: {
|
|
381
|
-
width: '
|
|
432
|
+
width: '152px'
|
|
382
433
|
}
|
|
383
434
|
}
|
|
384
435
|
},
|
|
385
|
-
|
|
436
|
+
disabled: rightDisabled,
|
|
437
|
+
inputRef: rightInputRef,
|
|
438
|
+
value: right,
|
|
386
439
|
onChange: event => {
|
|
387
440
|
if (validateInput(event.target.value)) {
|
|
388
|
-
|
|
389
|
-
setUpper(event.target.value);
|
|
441
|
+
setRight(event.target.value);
|
|
390
442
|
}
|
|
391
|
-
}
|
|
392
|
-
onFocus: () => setFocus(true),
|
|
393
|
-
onBlur: () => setFocus(false)
|
|
443
|
+
}
|
|
394
444
|
})));
|
|
395
445
|
}
|
|
396
446
|
|
|
@@ -435,8 +485,30 @@ function NumericalColumn(options) {
|
|
|
435
485
|
kind: COLUMNS.NUMERICAL,
|
|
436
486
|
buildFilter: function (params) {
|
|
437
487
|
return function (data) {
|
|
438
|
-
const
|
|
439
|
-
|
|
488
|
+
const included = params.comparisons.some(c => {
|
|
489
|
+
const left = roundToFixed(data, normalizedOptions.precision);
|
|
490
|
+
const right = roundToFixed(c.value, normalizedOptions.precision);
|
|
491
|
+
|
|
492
|
+
switch (c.operation) {
|
|
493
|
+
case NUMERICAL_OPERATIONS.EQ:
|
|
494
|
+
return left === right;
|
|
495
|
+
|
|
496
|
+
case NUMERICAL_OPERATIONS.GT:
|
|
497
|
+
return left > right;
|
|
498
|
+
|
|
499
|
+
case NUMERICAL_OPERATIONS.GTE:
|
|
500
|
+
return left >= right;
|
|
501
|
+
|
|
502
|
+
case NUMERICAL_OPERATIONS.LT:
|
|
503
|
+
return left < right;
|
|
504
|
+
|
|
505
|
+
case NUMERICAL_OPERATIONS.LTE:
|
|
506
|
+
return left <= right;
|
|
507
|
+
|
|
508
|
+
default:
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
});
|
|
440
512
|
return params.exclude ? !included : included;
|
|
441
513
|
};
|
|
442
514
|
},
|
|
@@ -19,6 +19,13 @@ export const NUMERICAL_FORMATS = Object.freeze({
|
|
|
19
19
|
ACCOUNTING: 'ACCOUNTING',
|
|
20
20
|
PERCENTAGE: 'PERCENTAGE'
|
|
21
21
|
});
|
|
22
|
+
export const NUMERICAL_OPERATIONS = Object.freeze({
|
|
23
|
+
EQ: 'EQ',
|
|
24
|
+
GT: 'GT',
|
|
25
|
+
GTE: 'GTE',
|
|
26
|
+
LT: 'LT',
|
|
27
|
+
LTE: 'LTE'
|
|
28
|
+
});
|
|
22
29
|
export const DATETIME_OPERATIONS = Object.freeze({
|
|
23
30
|
RANGE_DATETIME: 'RANGE_DATETIME',
|
|
24
31
|
RANGE_DATE: 'RANGE_DATE',
|
|
@@ -32,15 +39,4 @@ export const DATETIME_OPERATIONS = Object.freeze({
|
|
|
32
39
|
export const SORT_DIRECTIONS = Object.freeze({
|
|
33
40
|
ASC: 'ASC',
|
|
34
41
|
DESC: 'DESC'
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export const FILTER_SHELL_WIDTH = '320px'; // Depends on FILTER_SHELL_WIDTH
|
|
38
|
-
|
|
39
|
-
export const HISTOGRAM_SIZE = {
|
|
40
|
-
width: 308,
|
|
41
|
-
height: 120
|
|
42
|
-
}; // Arguably visually appealing within the given width.
|
|
43
|
-
// Smaller and we don't have enough detail per bar.
|
|
44
|
-
// Larger and the bars are too granular and don't align well with the slider steps
|
|
45
|
-
|
|
46
|
-
export const MAX_BIN_COUNT = 50;
|
|
42
|
+
});
|