@techsio/ui-kit 0.37.1 → 0.39.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.
Files changed (28) hide show
  1. package/dist/molecules/chart.js +393 -0
  2. package/dist/organisms/data-table.fields.js +720 -0
  3. package/dist/organisms/data-table.helpers.js +168 -0
  4. package/dist/organisms/data-table.js +1736 -0
  5. package/dist/organisms/table.js +7 -3
  6. package/dist/src/molecules/chart.d.ts +64 -0
  7. package/dist/src/molecules/chart.d.ts.map +1 -0
  8. package/dist/src/molecules/switch.d.ts +3 -3
  9. package/dist/src/molecules/toast.d.ts +3 -3
  10. package/dist/src/organisms/data-table.d.ts +357 -0
  11. package/dist/src/organisms/data-table.d.ts.map +1 -0
  12. package/dist/src/organisms/data-table.fields.d.ts +119 -0
  13. package/dist/src/organisms/data-table.fields.d.ts.map +1 -0
  14. package/dist/src/organisms/data-table.helpers.d.ts +240 -0
  15. package/dist/src/organisms/data-table.helpers.d.ts.map +1 -0
  16. package/dist/src/organisms/table.d.ts +15 -7
  17. package/dist/src/organisms/table.d.ts.map +1 -1
  18. package/dist/stories/changelog/changelog.stories.d.ts.map +1 -1
  19. package/dist/stories/molecules/chart.stories.d.ts +24 -0
  20. package/dist/stories/molecules/chart.stories.d.ts.map +1 -0
  21. package/dist/stories/organisms/data-table.stories.d.ts +145 -0
  22. package/dist/stories/organisms/data-table.stories.d.ts.map +1 -0
  23. package/dist/stories/organisms/table.stories.d.ts +7 -0
  24. package/dist/stories/organisms/table.stories.d.ts.map +1 -1
  25. package/package.json +14 -1
  26. package/src/tokens/components/components.css +2 -0
  27. package/src/tokens/components/molecules/_chart.css +98 -0
  28. package/src/tokens/components/organisms/_data-table.css +51 -0
@@ -0,0 +1,720 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { ActionIcon } from "../atoms/action-icon.js";
3
+ import { Input } from "../atoms/input.js";
4
+ import { NumericInput } from "../atoms/numeric-input.js";
5
+ import { Combobox } from "../molecules/combobox.js";
6
+ import { Menu } from "../molecules/menu.js";
7
+ import { Select } from "../molecules/select.js";
8
+ import { Switch } from "../molecules/switch.js";
9
+ const isBlank = (v)=>null == v || "" === v;
10
+ const TEXT_FILTER_OPERATORS = [
11
+ {
12
+ label: "Contains",
13
+ value: "contains"
14
+ },
15
+ {
16
+ label: "Does not contain",
17
+ value: "notContains"
18
+ },
19
+ {
20
+ label: "Equals",
21
+ value: "equals"
22
+ },
23
+ {
24
+ label: "Does not equal",
25
+ value: "notEquals"
26
+ },
27
+ {
28
+ label: "Starts with",
29
+ value: "startsWith"
30
+ },
31
+ {
32
+ label: "Ends with",
33
+ value: "endsWith"
34
+ },
35
+ {
36
+ label: "Is empty",
37
+ value: "empty"
38
+ },
39
+ {
40
+ label: "Is not empty",
41
+ value: "notEmpty"
42
+ }
43
+ ];
44
+ const NUMBER_FILTER_OPERATORS = [
45
+ {
46
+ label: "=",
47
+ value: "equals"
48
+ },
49
+ {
50
+ label: "≠",
51
+ value: "notEquals"
52
+ },
53
+ {
54
+ label: ">",
55
+ value: "gt"
56
+ },
57
+ {
58
+ label: "≥",
59
+ value: "gte"
60
+ },
61
+ {
62
+ label: "<",
63
+ value: "lt"
64
+ },
65
+ {
66
+ label: "≤",
67
+ value: "lte"
68
+ },
69
+ {
70
+ label: "Between",
71
+ value: "between"
72
+ },
73
+ {
74
+ label: "Is empty",
75
+ value: "empty"
76
+ },
77
+ {
78
+ label: "Is not empty",
79
+ value: "notEmpty"
80
+ }
81
+ ];
82
+ const TEXT_OPS = TEXT_FILTER_OPERATORS;
83
+ const NUMBER_OPS = NUMBER_FILTER_OPERATORS;
84
+ const BOOLEAN_FILTER_ITEMS = [
85
+ {
86
+ label: "All",
87
+ value: ""
88
+ },
89
+ {
90
+ label: "Yes",
91
+ value: "true"
92
+ },
93
+ {
94
+ label: "No",
95
+ value: "false"
96
+ }
97
+ ];
98
+ const HHMM_RE = /^(\d{1,2}):(\d{2})/;
99
+ const toSelectItems = (options)=>options.map((o)=>({
100
+ label: o.label,
101
+ value: o.value
102
+ }));
103
+ function columnLabel(column) {
104
+ const header = column.columnDef.header;
105
+ return "string" == typeof header && header ? header : column.id;
106
+ }
107
+ function selectMinWidthCh(items, placeholder) {
108
+ const longest = items.reduce((max, item)=>Math.max(max, String(item.label ?? item.value).length), placeholder?.length ?? 0);
109
+ return `${longest + 7}ch`;
110
+ }
111
+ function FieldSelect({ items, value, ariaLabel, placeholder, disabled, size = "sm", invalid, onChange }) {
112
+ return /*#__PURE__*/ jsx("div", {
113
+ style: {
114
+ minWidth: selectMinWidthCh(items, placeholder)
115
+ },
116
+ children: /*#__PURE__*/ jsxs(Select, {
117
+ disabled: disabled,
118
+ items: items,
119
+ onValueChange: (d)=>onChange(d.value[0] ?? ""),
120
+ size: size,
121
+ validateStatus: invalid ? "error" : "default",
122
+ value: void 0 === value ? void 0 : [
123
+ value
124
+ ],
125
+ children: [
126
+ /*#__PURE__*/ jsx(Select.Control, {
127
+ children: /*#__PURE__*/ jsx(Select.Trigger, {
128
+ "aria-label": ariaLabel,
129
+ children: /*#__PURE__*/ jsx(Select.ValueText, {
130
+ placeholder: placeholder
131
+ })
132
+ })
133
+ }),
134
+ /*#__PURE__*/ jsx(Select.Positioner, {
135
+ children: /*#__PURE__*/ jsx(Select.Content, {
136
+ children: items.map((item)=>/*#__PURE__*/ jsxs(Select.Item, {
137
+ item: item,
138
+ children: [
139
+ /*#__PURE__*/ jsx(Select.ItemText, {}),
140
+ /*#__PURE__*/ jsx(Select.ItemIndicator, {})
141
+ ]
142
+ }, item.value))
143
+ })
144
+ })
145
+ ]
146
+ })
147
+ });
148
+ }
149
+ function FilterConditionMenu({ operators, operatorLabels, value, onChange, disabled, size, columnName }) {
150
+ const labelled = operators.map((o)=>({
151
+ ...o,
152
+ label: operatorLabels?.[o.value] ?? o.label
153
+ }));
154
+ const active = labelled.find((o)=>o.value === value);
155
+ return /*#__PURE__*/ jsx(Menu, {
156
+ "aria-label": `Filter condition for ${columnName}`,
157
+ customTrigger: /*#__PURE__*/ jsx(ActionIcon, {
158
+ "aria-label": `Filter condition for ${columnName}: ${active?.label ?? value}`,
159
+ disabled: disabled,
160
+ icon: "icon-[mdi--filter-variant]",
161
+ size: size,
162
+ tone: "neutral"
163
+ }),
164
+ items: labelled.map((o)=>({
165
+ type: "radio",
166
+ value: o.value,
167
+ label: o.label,
168
+ name: `filter-operator-${columnName}`,
169
+ checked: o.value === value
170
+ })),
171
+ onSelect: (d)=>onChange(d.value),
172
+ size: size
173
+ });
174
+ }
175
+ const DEFAULT_FILTER_RENDERERS = {
176
+ string: ({ column, value, setValue, disabled, size, operatorLabels })=>{
177
+ const v = value ?? {};
178
+ const operator = v.operator ?? "contains";
179
+ const activeLabel = operatorLabels?.[operator] ?? TEXT_OPS.find((o)=>o.value === operator)?.label;
180
+ const needsValue = "empty" !== operator && "notEmpty" !== operator;
181
+ return /*#__PURE__*/ jsxs(Fragment, {
182
+ children: [
183
+ /*#__PURE__*/ jsx(Input, {
184
+ "aria-label": `Filter value for ${columnLabel(column)}`,
185
+ className: "flex-1",
186
+ disabled: disabled || !needsValue,
187
+ onChange: (e)=>setValue({
188
+ ...v,
189
+ operator,
190
+ value: e.target.value
191
+ }),
192
+ placeholder: needsValue ? "Value" : activeLabel,
193
+ size: size,
194
+ value: needsValue ? v.value ?? "" : ""
195
+ }),
196
+ /*#__PURE__*/ jsx(FilterConditionMenu, {
197
+ columnName: columnLabel(column),
198
+ disabled: disabled,
199
+ onChange: (op)=>setValue({
200
+ ...v,
201
+ operator: op
202
+ }),
203
+ operatorLabels: operatorLabels,
204
+ operators: TEXT_OPS,
205
+ size: size,
206
+ value: operator
207
+ })
208
+ ]
209
+ });
210
+ },
211
+ int: (ctx)=>DEFAULT_FILTER_RENDERERS.number(ctx),
212
+ number: ({ column, value, setValue, disabled, size, operatorLabels })=>{
213
+ const v = value ?? {};
214
+ const operator = v.operator ?? "equals";
215
+ const needsValue = "empty" !== operator && "notEmpty" !== operator;
216
+ const activeLabel = operatorLabels?.[operator] ?? NUMBER_FILTER_OPERATORS.find((o)=>o.value === operator)?.label;
217
+ let valuePlaceholder = activeLabel;
218
+ if (needsValue) valuePlaceholder = "between" === operator ? "From" : "Value";
219
+ return /*#__PURE__*/ jsxs(Fragment, {
220
+ children: [
221
+ /*#__PURE__*/ jsx(Input, {
222
+ "aria-label": `Filter value for ${columnLabel(column)}`,
223
+ className: "flex-1",
224
+ disabled: disabled || !needsValue,
225
+ onChange: (e)=>setValue({
226
+ ...v,
227
+ operator,
228
+ value: e.target.value
229
+ }),
230
+ placeholder: valuePlaceholder,
231
+ size: size,
232
+ type: needsValue ? "number" : "text",
233
+ value: needsValue ? v.value ?? "" : ""
234
+ }),
235
+ "between" === operator && /*#__PURE__*/ jsx(Input, {
236
+ "aria-label": `Filter upper bound for ${columnLabel(column)}`,
237
+ className: "flex-1",
238
+ disabled: disabled,
239
+ onChange: (e)=>setValue({
240
+ ...v,
241
+ operator,
242
+ to: e.target.value
243
+ }),
244
+ placeholder: "To",
245
+ size: size,
246
+ type: "number",
247
+ value: v.to ?? ""
248
+ }),
249
+ /*#__PURE__*/ jsx(FilterConditionMenu, {
250
+ columnName: columnLabel(column),
251
+ disabled: disabled,
252
+ onChange: (op)=>setValue("between" === op ? {
253
+ ...v,
254
+ operator: op
255
+ } : {
256
+ operator: op,
257
+ value: v.value
258
+ }),
259
+ operatorLabels: operatorLabels,
260
+ operators: NUMBER_OPS,
261
+ size: size,
262
+ value: operator
263
+ })
264
+ ]
265
+ });
266
+ },
267
+ boolean: ({ column, value, setValue, disabled, size })=>{
268
+ const v = value ?? {};
269
+ const current = void 0 === v.value ? "" : String(v.value);
270
+ return /*#__PURE__*/ jsx(FieldSelect, {
271
+ ariaLabel: `Filter ${columnLabel(column)}`,
272
+ disabled: disabled,
273
+ items: BOOLEAN_FILTER_ITEMS,
274
+ onChange: (next)=>setValue("" === next ? void 0 : {
275
+ value: "true" === next
276
+ }),
277
+ placeholder: "All",
278
+ size: size,
279
+ value: current
280
+ });
281
+ },
282
+ enum: ({ column, value, setValue, disabled, options, size })=>{
283
+ const v = value ?? {};
284
+ const current = v.values?.[0] ?? "";
285
+ return /*#__PURE__*/ jsx(FieldSelect, {
286
+ ariaLabel: `Filter ${columnLabel(column)}`,
287
+ disabled: disabled,
288
+ items: [
289
+ {
290
+ label: "All",
291
+ value: ""
292
+ },
293
+ ...toSelectItems(options)
294
+ ],
295
+ onChange: (next)=>setValue(next ? {
296
+ values: [
297
+ next
298
+ ]
299
+ } : void 0),
300
+ placeholder: "All",
301
+ size: size,
302
+ value: current
303
+ });
304
+ },
305
+ multiEnum: ({ column, value, setValue, disabled, options, size })=>{
306
+ const v = value ?? {};
307
+ return /*#__PURE__*/ jsx(Combobox, {
308
+ disabled: disabled,
309
+ items: options,
310
+ multiple: true,
311
+ onChange: (next)=>{
312
+ const arr = Array.isArray(next) ? next : [
313
+ next
314
+ ].filter(Boolean);
315
+ setValue(arr.length ? {
316
+ values: arr
317
+ } : void 0);
318
+ },
319
+ placeholder: `Filter ${columnLabel(column)}`,
320
+ size: size,
321
+ value: v.values ?? []
322
+ });
323
+ },
324
+ date: ({ column, value, setValue, disabled, size })=>{
325
+ const v = value ?? {};
326
+ return /*#__PURE__*/ jsx(Input, {
327
+ "aria-label": `Filter ${columnLabel(column)}`,
328
+ disabled: disabled,
329
+ onChange: (e)=>setValue(e.target.value ? {
330
+ from: e.target.value,
331
+ to: e.target.value
332
+ } : void 0),
333
+ size: size,
334
+ type: "date",
335
+ value: v.from ?? ""
336
+ });
337
+ },
338
+ datetime: ({ column, value, setValue, disabled, size })=>{
339
+ const v = value ?? {};
340
+ return /*#__PURE__*/ jsx(Input, {
341
+ "aria-label": `Filter ${columnLabel(column)}`,
342
+ disabled: disabled,
343
+ onChange: (e)=>setValue(e.target.value ? {
344
+ from: e.target.value
345
+ } : void 0),
346
+ size: size,
347
+ type: "datetime-local",
348
+ value: v.from ?? ""
349
+ });
350
+ },
351
+ time: ({ column, value, setValue, disabled, size })=>{
352
+ const v = value ?? {};
353
+ const patch = (next)=>setValue(next.from || next.to ? next : void 0);
354
+ return /*#__PURE__*/ jsxs(Fragment, {
355
+ children: [
356
+ /*#__PURE__*/ jsx(Input, {
357
+ "aria-label": `Filter ${columnLabel(column)} from`,
358
+ disabled: disabled,
359
+ onChange: (e)=>patch({
360
+ ...v,
361
+ from: e.target.value
362
+ }),
363
+ size: size,
364
+ type: "time",
365
+ value: v.from ?? ""
366
+ }),
367
+ /*#__PURE__*/ jsx(Input, {
368
+ "aria-label": `Filter ${columnLabel(column)} to`,
369
+ disabled: disabled,
370
+ onChange: (e)=>patch({
371
+ ...v,
372
+ to: e.target.value
373
+ }),
374
+ size: size,
375
+ type: "time",
376
+ value: v.to ?? ""
377
+ })
378
+ ]
379
+ });
380
+ },
381
+ dateRange: ({ column, value, setValue, disabled, size })=>{
382
+ const v = value ?? {};
383
+ const patch = (next)=>setValue(next.from || next.to ? next : void 0);
384
+ return /*#__PURE__*/ jsxs(Fragment, {
385
+ children: [
386
+ /*#__PURE__*/ jsx(Input, {
387
+ "aria-label": `Filter ${columnLabel(column)} from`,
388
+ disabled: disabled,
389
+ onChange: (e)=>patch({
390
+ ...v,
391
+ from: e.target.value
392
+ }),
393
+ size: size,
394
+ type: "date",
395
+ value: v.from ?? ""
396
+ }),
397
+ /*#__PURE__*/ jsx(Input, {
398
+ "aria-label": `Filter ${columnLabel(column)} to`,
399
+ disabled: disabled,
400
+ min: v.from || void 0,
401
+ onChange: (e)=>patch({
402
+ ...v,
403
+ to: e.target.value
404
+ }),
405
+ size: size,
406
+ type: "date",
407
+ value: v.to ?? ""
408
+ })
409
+ ]
410
+ });
411
+ },
412
+ custom: ()=>null
413
+ };
414
+ const editorKeyHandlers = (commit, cancel)=>({
415
+ onKeyDown: (e)=>{
416
+ if ("Enter" === e.key) {
417
+ e.preventDefault();
418
+ commit();
419
+ } else if ("Escape" === e.key) {
420
+ e.preventDefault();
421
+ cancel();
422
+ }
423
+ }
424
+ });
425
+ function dateLikeEditor(inputType) {
426
+ return ({ column, value, setValue, disabled, error, commit, cancel, size, errorId })=>/*#__PURE__*/ jsx(Input, {
427
+ "aria-describedby": error ? errorId : void 0,
428
+ "aria-invalid": error ? true : void 0,
429
+ "aria-label": `Edit ${columnLabel(column)}`,
430
+ disabled: disabled,
431
+ onChange: (e)=>setValue(e.target.value),
432
+ size: size,
433
+ type: inputType,
434
+ value: value ?? "",
435
+ ...editorKeyHandlers(commit, cancel)
436
+ });
437
+ }
438
+ const DEFAULT_EDITOR_RENDERERS = {
439
+ string: ({ column, value, setValue, disabled, error, commit, cancel, size, errorId })=>/*#__PURE__*/ jsx(Input, {
440
+ "aria-describedby": error ? errorId : void 0,
441
+ "aria-invalid": error ? true : void 0,
442
+ "aria-label": `Edit ${columnLabel(column)}`,
443
+ disabled: disabled,
444
+ onChange: (e)=>setValue(e.target.value),
445
+ size: size,
446
+ value: value ?? "",
447
+ ...editorKeyHandlers(commit, cancel)
448
+ }),
449
+ int: (ctx)=>DEFAULT_EDITOR_RENDERERS.number(ctx),
450
+ number: ({ column, value, setValue, disabled, commit, cancel, size, error, errorId })=>/*#__PURE__*/ jsx(NumericInput, {
451
+ describedBy: error ? errorId : void 0,
452
+ disabled: disabled,
453
+ invalid: !!error,
454
+ onChange: (next)=>setValue(Number.isNaN(next) ? void 0 : next),
455
+ size: size,
456
+ value: "number" != typeof value || Number.isNaN(value) ? void 0 : value,
457
+ ...editorKeyHandlers(commit, cancel),
458
+ children: /*#__PURE__*/ jsxs(NumericInput.Control, {
459
+ children: [
460
+ /*#__PURE__*/ jsx(NumericInput.Input, {
461
+ "aria-invalid": error ? true : void 0,
462
+ "aria-label": `Edit ${columnLabel(column)}`
463
+ }),
464
+ /*#__PURE__*/ jsxs(NumericInput.TriggerContainer, {
465
+ children: [
466
+ /*#__PURE__*/ jsx(NumericInput.IncrementTrigger, {}),
467
+ /*#__PURE__*/ jsx(NumericInput.DecrementTrigger, {})
468
+ ]
469
+ })
470
+ ]
471
+ })
472
+ }),
473
+ boolean: ({ column, value, setValue, disabled, error })=>/*#__PURE__*/ jsx(Switch, {
474
+ checked: Boolean(value),
475
+ disabled: disabled,
476
+ onCheckedChange: setValue,
477
+ validateStatus: error ? "error" : "default",
478
+ children: /*#__PURE__*/ jsx("span", {
479
+ className: "sr-only",
480
+ children: `Edit ${columnLabel(column)}`
481
+ })
482
+ }),
483
+ enum: ({ column, value, setValue, disabled, options, error, size })=>/*#__PURE__*/ jsx(FieldSelect, {
484
+ ariaLabel: `Edit ${columnLabel(column)}`,
485
+ disabled: disabled,
486
+ invalid: !!error,
487
+ items: toSelectItems(options),
488
+ onChange: setValue,
489
+ size: size,
490
+ value: value ?? ""
491
+ }),
492
+ multiEnum: ({ column, value, setValue, disabled, options, error, size })=>/*#__PURE__*/ jsx(Combobox, {
493
+ disabled: disabled,
494
+ items: options,
495
+ multiple: true,
496
+ onChange: (next)=>setValue(Array.isArray(next) ? next : [
497
+ next
498
+ ]),
499
+ placeholder: `Edit ${columnLabel(column)}`,
500
+ size: size,
501
+ validateStatus: error ? "error" : "default",
502
+ value: value ?? []
503
+ }),
504
+ date: dateLikeEditor("date"),
505
+ datetime: dateLikeEditor("datetime-local"),
506
+ time: dateLikeEditor("time"),
507
+ dateRange: ({ column, value, setValue, disabled, error, errorId, commit, cancel, size })=>{
508
+ const v = value ?? {};
509
+ return /*#__PURE__*/ jsxs(Fragment, {
510
+ children: [
511
+ /*#__PURE__*/ jsx(Input, {
512
+ "aria-describedby": error ? errorId : void 0,
513
+ "aria-invalid": error ? true : void 0,
514
+ "aria-label": `Edit ${columnLabel(column)} from`,
515
+ disabled: disabled,
516
+ onChange: (e)=>setValue({
517
+ ...v,
518
+ from: e.target.value
519
+ }),
520
+ size: size,
521
+ type: "date",
522
+ value: v.from ?? "",
523
+ ...editorKeyHandlers(commit, cancel)
524
+ }),
525
+ /*#__PURE__*/ jsx(Input, {
526
+ "aria-describedby": error ? errorId : void 0,
527
+ "aria-invalid": error ? true : void 0,
528
+ "aria-label": `Edit ${columnLabel(column)} to`,
529
+ disabled: disabled,
530
+ min: v.from || void 0,
531
+ onChange: (e)=>setValue({
532
+ ...v,
533
+ to: e.target.value
534
+ }),
535
+ size: size,
536
+ type: "date",
537
+ value: v.to ?? "",
538
+ ...editorKeyHandlers(commit, cancel)
539
+ })
540
+ ]
541
+ });
542
+ },
543
+ custom: ()=>null
544
+ };
545
+ function matchText(cell, f) {
546
+ const operator = f.operator ?? "contains";
547
+ if ("empty" === operator) return isBlank(cell);
548
+ if ("notEmpty" === operator) return !isBlank(cell);
549
+ if (isBlank(f.value)) return true;
550
+ const text = String(cell ?? "").toLowerCase();
551
+ const q = String(f.value).toLowerCase();
552
+ switch(operator){
553
+ case "equals":
554
+ return text === q;
555
+ case "notEquals":
556
+ return text !== q;
557
+ case "notContains":
558
+ return !text.includes(q);
559
+ case "startsWith":
560
+ return text.startsWith(q);
561
+ case "endsWith":
562
+ return text.endsWith(q);
563
+ default:
564
+ return text.includes(q);
565
+ }
566
+ }
567
+ function matchBetween(n, cellHasNoNumber, f) {
568
+ let lo = Number(f.value);
569
+ let hi = Number(f.to);
570
+ const hasLo = !(isBlank(f.value) || Number.isNaN(lo));
571
+ const hasHi = !(isBlank(f.to) || Number.isNaN(hi));
572
+ if (!(hasLo || hasHi)) return true;
573
+ if (cellHasNoNumber) return false;
574
+ if (hasLo && hasHi && lo > hi) [lo, hi] = [
575
+ hi,
576
+ lo
577
+ ];
578
+ if (hasLo && n < lo) return false;
579
+ return !(hasHi && n > hi);
580
+ }
581
+ function matchNumber(cell, f) {
582
+ const operator = f.operator ?? "equals";
583
+ if ("empty" === operator) return isBlank(cell);
584
+ if ("notEmpty" === operator) return !isBlank(cell);
585
+ const n = Number(cell);
586
+ const cellHasNoNumber = isBlank(cell) || Number.isNaN(n);
587
+ if ("between" === operator) return matchBetween(n, cellHasNoNumber, f);
588
+ if (isBlank(f.value)) return true;
589
+ const target = Number(f.value);
590
+ if (Number.isNaN(target)) return true;
591
+ if ("notEquals" === operator) return cellHasNoNumber || n !== target;
592
+ if (cellHasNoNumber) return false;
593
+ switch(operator){
594
+ case "gt":
595
+ return n > target;
596
+ case "gte":
597
+ return n >= target;
598
+ case "lt":
599
+ return n < target;
600
+ case "lte":
601
+ return n <= target;
602
+ default:
603
+ return n === target;
604
+ }
605
+ }
606
+ const END_OF_DAY_MS = 86399999;
607
+ const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
608
+ const time = (v)=>{
609
+ const raw = String(v);
610
+ const t = new Date(DATE_ONLY_RE.test(raw) ? `${raw}T00:00:00` : raw).getTime();
611
+ return Number.isNaN(t) ? void 0 : t;
612
+ };
613
+ const endOfBound = (v)=>{
614
+ const t = time(v);
615
+ if (void 0 === t) return;
616
+ return DATE_ONLY_RE.test(String(v)) ? t + END_OF_DAY_MS : t;
617
+ };
618
+ function matchRangeOverlap(cell, f) {
619
+ const cellFrom = time(cell.from) ?? -1 / 0;
620
+ const cellTo = cell.to ? endOfBound(cell.to) ?? 1 / 0 : 1 / 0;
621
+ const filterFrom = f.from ? time(f.from) ?? -1 / 0 : -1 / 0;
622
+ const filterTo = f.to ? endOfBound(f.to) ?? 1 / 0 : 1 / 0;
623
+ return cellFrom <= filterTo && cellTo >= filterFrom;
624
+ }
625
+ function matchDateRange(cell, f) {
626
+ if (isBlank(f.from) && isBlank(f.to)) return true;
627
+ if (isBlank(cell)) return false;
628
+ if ("object" == typeof cell && ("from" in cell || "to" in cell)) return matchRangeOverlap(cell, f);
629
+ const t = time(cell);
630
+ if (void 0 === t) return false;
631
+ return withinDateBounds(t, f);
632
+ }
633
+ function withinDateBounds(t, f) {
634
+ const from = f.from ? time(f.from) : void 0;
635
+ if (void 0 !== from && t < from) return false;
636
+ const to = f.to ? endOfBound(f.to) : void 0;
637
+ return !(void 0 !== to && t > to);
638
+ }
639
+ function toMinutes(value) {
640
+ if (isBlank(value)) return;
641
+ const s = String(value);
642
+ const hhmm = s.match(HHMM_RE);
643
+ if (hhmm) return 60 * Number(hhmm[1]) + Number(hhmm[2]);
644
+ const d = new Date(s);
645
+ return Number.isNaN(d.getTime()) ? void 0 : 60 * d.getHours() + d.getMinutes();
646
+ }
647
+ function matchTime(cell, f) {
648
+ const from = toMinutes(f.from);
649
+ const to = toMinutes(f.to);
650
+ if (void 0 === from && void 0 === to) return true;
651
+ const t = toMinutes(cell);
652
+ if (void 0 === t) return false;
653
+ if (void 0 !== from && void 0 !== to && from > to) return t >= from || t <= to;
654
+ if (void 0 !== from && t < from) return false;
655
+ if (void 0 !== to && t > to) return false;
656
+ return true;
657
+ }
658
+ function normalizeFilterValue(type, filterValue) {
659
+ if (Array.isArray(filterValue)) return {
660
+ values: filterValue.map(String)
661
+ };
662
+ if ("object" == typeof filterValue) return filterValue;
663
+ if ("enum" === type || "multiEnum" === type) return {
664
+ values: [
665
+ String(filterValue)
666
+ ]
667
+ };
668
+ if ("boolean" === type) return {
669
+ value: true === filterValue || "true" === filterValue
670
+ };
671
+ if ("date" === type || "datetime" === type || "dateRange" === type || "time" === type) {
672
+ const bound = String(filterValue);
673
+ return {
674
+ from: bound,
675
+ to: bound
676
+ };
677
+ }
678
+ return {
679
+ value: String(filterValue)
680
+ };
681
+ }
682
+ function typedFilterMatch(type, cell, rawFilterValue) {
683
+ if (null == rawFilterValue) return true;
684
+ const filterValue = normalizeFilterValue(type, rawFilterValue);
685
+ switch(type){
686
+ case "boolean":
687
+ {
688
+ const f = filterValue;
689
+ return void 0 === f.value ? true : Boolean(cell) === f.value;
690
+ }
691
+ case "enum":
692
+ {
693
+ const f = filterValue;
694
+ return f.values?.length ? f.values.includes(String(cell)) : true;
695
+ }
696
+ case "multiEnum":
697
+ {
698
+ const f = filterValue;
699
+ if (!f.values?.length) return true;
700
+ const arr = Array.isArray(cell) ? cell.map(String) : [
701
+ String(cell)
702
+ ];
703
+ return f.values.some((v)=>arr.includes(v));
704
+ }
705
+ case "int":
706
+ case "number":
707
+ return matchNumber(cell, filterValue);
708
+ case "time":
709
+ return matchTime(cell, filterValue);
710
+ case "date":
711
+ case "datetime":
712
+ case "dateRange":
713
+ return matchDateRange(cell, filterValue);
714
+ case "custom":
715
+ return matchNumber(cell, filterValue);
716
+ default:
717
+ return matchText(cell, filterValue);
718
+ }
719
+ }
720
+ export { DEFAULT_EDITOR_RENDERERS, DEFAULT_FILTER_RENDERERS, FieldSelect, NUMBER_FILTER_OPERATORS, TEXT_FILTER_OPERATORS, columnLabel, isBlank, matchBetween, typedFilterMatch };