@bmsuisse/datagrid 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.
- package/README.md +24 -0
- package/dist/index.d.ts +158 -10
- package/dist/index.js +646 -412
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -147,6 +147,72 @@ function evaluateFilter(row, filter) {
|
|
|
147
147
|
return evaluateLeaf(row, filter);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// src/filter/labels.tsx
|
|
151
|
+
import { createContext, useContext, useMemo } from "react";
|
|
152
|
+
import { jsx } from "react/jsx-runtime";
|
|
153
|
+
var defaultFilterLabels = {
|
|
154
|
+
filterAriaLabel: (header) => `Filter ${header}`,
|
|
155
|
+
searchPlaceholder: (header) => `Search ${header.toLowerCase()}...`,
|
|
156
|
+
selectAll: "Select all",
|
|
157
|
+
selectAllOfGroup: (group) => `Select all of ${group}`,
|
|
158
|
+
noMatches: "No matches.",
|
|
159
|
+
selectedCount: (count) => `${count} selected`,
|
|
160
|
+
stringPlaceholder: (header) => `Filter ${header.toLowerCase()}...`,
|
|
161
|
+
stringContains: "Contains",
|
|
162
|
+
stringIs: "Is",
|
|
163
|
+
stringStartsWith: "Starts with",
|
|
164
|
+
stringEndsWith: "Ends with",
|
|
165
|
+
operatorAriaLabel: (header) => `${header} filter operator`,
|
|
166
|
+
booleanAll: "All",
|
|
167
|
+
booleanYes: "Yes",
|
|
168
|
+
booleanNo: "No",
|
|
169
|
+
booleanAriaLabel: (header) => `${header} filter`,
|
|
170
|
+
minPlaceholder: "Min",
|
|
171
|
+
maxPlaceholder: "Max",
|
|
172
|
+
valuePlaceholder: "Value",
|
|
173
|
+
rangeSeparator: "to",
|
|
174
|
+
minimumAriaLabel: (header) => `${header} minimum`,
|
|
175
|
+
maximumAriaLabel: (header) => `${header} maximum`,
|
|
176
|
+
minimumSliderAriaLabel: (header) => `${header} minimum (slider)`,
|
|
177
|
+
maximumSliderAriaLabel: (header) => `${header} maximum (slider)`,
|
|
178
|
+
numberGreaterThan: "Greater than",
|
|
179
|
+
numberGreaterThanOrEqual: "Greater than or equal to",
|
|
180
|
+
numberLessThan: "Less than",
|
|
181
|
+
numberLessThanOrEqual: "Less than or equal to",
|
|
182
|
+
numberEquals: "Equals",
|
|
183
|
+
numberNotEquals: "Does not equal",
|
|
184
|
+
numberBetween: "Between",
|
|
185
|
+
clear: "Clear",
|
|
186
|
+
loading: "Loading\u2026",
|
|
187
|
+
loadFailed: "Couldn't load values.",
|
|
188
|
+
retry: "Retry",
|
|
189
|
+
dateToday: "Today",
|
|
190
|
+
dateLast7Days: "Last 7 days",
|
|
191
|
+
dateThisMonth: "This month",
|
|
192
|
+
dateCustom: "Custom"
|
|
193
|
+
};
|
|
194
|
+
function mergeFilterLabels(base, overrides) {
|
|
195
|
+
if (!overrides) return base;
|
|
196
|
+
const merged = { ...base };
|
|
197
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
198
|
+
if (value !== void 0) merged[key] = value;
|
|
199
|
+
}
|
|
200
|
+
return merged;
|
|
201
|
+
}
|
|
202
|
+
var FilterLabelsContext = createContext(defaultFilterLabels);
|
|
203
|
+
function FilterLabelsProvider({
|
|
204
|
+
labels,
|
|
205
|
+
children
|
|
206
|
+
}) {
|
|
207
|
+
const parent = useContext(FilterLabelsContext);
|
|
208
|
+
const value = useMemo(() => mergeFilterLabels(parent, labels), [parent, labels]);
|
|
209
|
+
return /* @__PURE__ */ jsx(FilterLabelsContext.Provider, { value, children });
|
|
210
|
+
}
|
|
211
|
+
function useFilterLabels(overrides) {
|
|
212
|
+
const fromContext = useContext(FilterLabelsContext);
|
|
213
|
+
return useMemo(() => mergeFilterLabels(fromContext, overrides), [fromContext, overrides]);
|
|
214
|
+
}
|
|
215
|
+
|
|
150
216
|
// src/filter/BooleanFilter.tsx
|
|
151
217
|
import { FunnelIcon } from "@heroicons/react/24/outline";
|
|
152
218
|
|
|
@@ -166,7 +232,7 @@ function stopRowClick(event) {
|
|
|
166
232
|
}
|
|
167
233
|
|
|
168
234
|
// src/components/ui/button.tsx
|
|
169
|
-
import { jsx } from "react/jsx-runtime";
|
|
235
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
170
236
|
var buttonVariants = cva(
|
|
171
237
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
|
172
238
|
{
|
|
@@ -193,7 +259,7 @@ var Button = forwardRef(
|
|
|
193
259
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
194
260
|
const Comp = asChild ? Slot : "button";
|
|
195
261
|
const variantClass = buttonVariants({ variant, size });
|
|
196
|
-
return /* @__PURE__ */
|
|
262
|
+
return /* @__PURE__ */ jsx2(Comp, { className: className ? cn(variantClass, className) : variantClass, ref, ...props });
|
|
197
263
|
}
|
|
198
264
|
);
|
|
199
265
|
Button.displayName = "Button";
|
|
@@ -201,10 +267,10 @@ Button.displayName = "Button";
|
|
|
201
267
|
// src/components/ui/popover.tsx
|
|
202
268
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
203
269
|
import { forwardRef as forwardRef2 } from "react";
|
|
204
|
-
import { jsx as
|
|
270
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
205
271
|
var Popover = PopoverPrimitive.Root;
|
|
206
272
|
var PopoverTrigger = PopoverPrimitive.Trigger;
|
|
207
|
-
var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }, ref) => /* @__PURE__ */
|
|
273
|
+
var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }, ref) => /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx3(
|
|
208
274
|
PopoverPrimitive.Content,
|
|
209
275
|
{
|
|
210
276
|
ref,
|
|
@@ -222,9 +288,9 @@ PopoverContent.displayName = "PopoverContent";
|
|
|
222
288
|
|
|
223
289
|
// src/components/ui/select.tsx
|
|
224
290
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
225
|
-
import {
|
|
291
|
+
import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/outline";
|
|
226
292
|
import { forwardRef as forwardRef3 } from "react";
|
|
227
|
-
import { jsx as
|
|
293
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
228
294
|
var Select = SelectPrimitive.Root;
|
|
229
295
|
var SelectValue = SelectPrimitive.Value;
|
|
230
296
|
var SelectTrigger = forwardRef3(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
@@ -238,12 +304,12 @@ var SelectTrigger = forwardRef3(({ className, children, ...props }, ref) => /* @
|
|
|
238
304
|
...props,
|
|
239
305
|
children: [
|
|
240
306
|
children,
|
|
241
|
-
/* @__PURE__ */
|
|
307
|
+
/* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "h-4 w-4 opacity-50" }) })
|
|
242
308
|
]
|
|
243
309
|
}
|
|
244
310
|
));
|
|
245
311
|
SelectTrigger.displayName = "SelectTrigger";
|
|
246
|
-
var SelectContent = forwardRef3(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */
|
|
312
|
+
var SelectContent = forwardRef3(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
|
|
247
313
|
SelectPrimitive.Content,
|
|
248
314
|
{
|
|
249
315
|
ref,
|
|
@@ -254,7 +320,7 @@ var SelectContent = forwardRef3(({ className, children, position = "popper", ...
|
|
|
254
320
|
className
|
|
255
321
|
),
|
|
256
322
|
...props,
|
|
257
|
-
children: /* @__PURE__ */
|
|
323
|
+
children: /* @__PURE__ */ jsx4(SelectPrimitive.Viewport, { className: "p-1", children })
|
|
258
324
|
}
|
|
259
325
|
) }));
|
|
260
326
|
SelectContent.displayName = "SelectContent";
|
|
@@ -268,19 +334,19 @@ var SelectItem = forwardRef3(({ className, children, ...props }, ref) => /* @__P
|
|
|
268
334
|
),
|
|
269
335
|
...props,
|
|
270
336
|
children: [
|
|
271
|
-
/* @__PURE__ */
|
|
272
|
-
/* @__PURE__ */
|
|
337
|
+
/* @__PURE__ */ jsx4("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx4(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx4(CheckIcon, { className: "h-4 w-4" }) }) }),
|
|
338
|
+
/* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { children })
|
|
273
339
|
]
|
|
274
340
|
}
|
|
275
341
|
));
|
|
276
342
|
SelectItem.displayName = "SelectItem";
|
|
277
343
|
|
|
278
344
|
// src/filter/BooleanFilter.tsx
|
|
279
|
-
import { jsx as
|
|
345
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
280
346
|
var BOOLEAN_CHOICES = [
|
|
281
|
-
{ value: "all",
|
|
282
|
-
{ value: "yes",
|
|
283
|
-
{ value: "no",
|
|
347
|
+
{ value: "all", labelKey: "booleanAll" },
|
|
348
|
+
{ value: "yes", labelKey: "booleanYes" },
|
|
349
|
+
{ value: "no", labelKey: "booleanNo" }
|
|
284
350
|
];
|
|
285
351
|
function choiceOf(value) {
|
|
286
352
|
if (!value) return "all";
|
|
@@ -300,11 +366,13 @@ function BooleanFilter({
|
|
|
300
366
|
column,
|
|
301
367
|
value,
|
|
302
368
|
onChange,
|
|
303
|
-
bare = false
|
|
369
|
+
bare = false,
|
|
370
|
+
labels: labelOverrides
|
|
304
371
|
}) {
|
|
372
|
+
const labels = useFilterLabels(labelOverrides);
|
|
305
373
|
const choice = choiceOf(value);
|
|
306
374
|
const isFiltered = choice !== "all";
|
|
307
|
-
const summary = choice === "yes" ?
|
|
375
|
+
const summary = choice === "yes" ? labels.booleanYes : choice === "no" ? labels.booleanNo : "";
|
|
308
376
|
function emit(next) {
|
|
309
377
|
if (next === "all") {
|
|
310
378
|
onChange(void 0);
|
|
@@ -321,36 +389,36 @@ function BooleanFilter({
|
|
|
321
389
|
if (match) emit(match);
|
|
322
390
|
},
|
|
323
391
|
children: [
|
|
324
|
-
/* @__PURE__ */
|
|
325
|
-
/* @__PURE__ */
|
|
392
|
+
/* @__PURE__ */ jsx5(SelectTrigger, { "aria-label": labels.booleanAriaLabel(column.header), children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
|
|
393
|
+
/* @__PURE__ */ jsx5(SelectContent, { children: BOOLEAN_CHOICES.map((option) => /* @__PURE__ */ jsx5(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
|
|
326
394
|
]
|
|
327
395
|
}
|
|
328
396
|
);
|
|
329
397
|
if (bare) {
|
|
330
|
-
return /* @__PURE__ */
|
|
398
|
+
return /* @__PURE__ */ jsx5("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
331
399
|
}
|
|
332
400
|
return /* @__PURE__ */ jsxs2(Popover, { children: [
|
|
333
|
-
/* @__PURE__ */
|
|
401
|
+
/* @__PURE__ */ jsx5(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
|
|
334
402
|
Button,
|
|
335
403
|
{
|
|
336
404
|
variant: "outline",
|
|
337
405
|
size: "sm",
|
|
338
406
|
className: cn("gap-1", isFiltered ? "max-w-[140px] px-2" : "w-8 justify-center px-0"),
|
|
339
|
-
"aria-label":
|
|
407
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
340
408
|
"data-testid": `filter-${column.id}`,
|
|
341
409
|
children: [
|
|
342
|
-
/* @__PURE__ */
|
|
410
|
+
/* @__PURE__ */ jsx5(
|
|
343
411
|
FunnelIcon,
|
|
344
412
|
{
|
|
345
413
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
346
414
|
"aria-hidden": true
|
|
347
415
|
}
|
|
348
416
|
),
|
|
349
|
-
isFiltered && /* @__PURE__ */
|
|
417
|
+
isFiltered && /* @__PURE__ */ jsx5("span", { className: "truncate", children: summary })
|
|
350
418
|
]
|
|
351
419
|
}
|
|
352
420
|
) }),
|
|
353
|
-
/* @__PURE__ */
|
|
421
|
+
/* @__PURE__ */ jsx5(PopoverContent, { className: "w-40 p-2", children: panel })
|
|
354
422
|
] });
|
|
355
423
|
}
|
|
356
424
|
|
|
@@ -359,13 +427,18 @@ import { CalendarDaysIcon } from "@heroicons/react/24/outline";
|
|
|
359
427
|
import { endOfDay, endOfMonth, format, parseISO as parseISO2, startOfDay, startOfMonth, subDays } from "date-fns";
|
|
360
428
|
|
|
361
429
|
// src/components/ui/calendar.tsx
|
|
362
|
-
import {
|
|
430
|
+
import {
|
|
431
|
+
ChevronDownIcon as ChevronDownIcon2,
|
|
432
|
+
ChevronLeftIcon,
|
|
433
|
+
ChevronRightIcon,
|
|
434
|
+
ChevronUpIcon
|
|
435
|
+
} from "@heroicons/react/24/outline";
|
|
363
436
|
import { useEffect, useRef } from "react";
|
|
364
437
|
import { DayPicker, getDefaultClassNames } from "react-day-picker";
|
|
365
|
-
import { jsx as
|
|
438
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
366
439
|
function Calendar({ className, classNames, ...props }) {
|
|
367
440
|
const defaultClassNames = getDefaultClassNames();
|
|
368
|
-
return /* @__PURE__ */
|
|
441
|
+
return /* @__PURE__ */ jsx6(
|
|
369
442
|
DayPicker,
|
|
370
443
|
{
|
|
371
444
|
className: cn("w-fit", className),
|
|
@@ -415,15 +488,15 @@ function Calendar({ className, classNames, ...props }) {
|
|
|
415
488
|
},
|
|
416
489
|
components: {
|
|
417
490
|
Chevron: ({ className: chevronClassName, orientation }) => {
|
|
418
|
-
const Icon2 = orientation === "up" ? ChevronUpIcon : orientation === "down" ?
|
|
419
|
-
return /* @__PURE__ */
|
|
491
|
+
const Icon2 = orientation === "up" ? ChevronUpIcon : orientation === "down" ? ChevronDownIcon2 : orientation === "right" ? ChevronRightIcon : ChevronLeftIcon;
|
|
492
|
+
return /* @__PURE__ */ jsx6(Icon2, { className: cn("h-4 w-4", chevronClassName), "aria-hidden": true });
|
|
420
493
|
},
|
|
421
494
|
DayButton: ({ className: dayClassName, day: _day, modifiers, ...dayProps }) => {
|
|
422
495
|
const ref = useRef(null);
|
|
423
496
|
useEffect(() => {
|
|
424
497
|
if (modifiers.focused) ref.current?.focus();
|
|
425
498
|
}, [modifiers.focused]);
|
|
426
|
-
return /* @__PURE__ */
|
|
499
|
+
return /* @__PURE__ */ jsx6(
|
|
427
500
|
"button",
|
|
428
501
|
{
|
|
429
502
|
ref,
|
|
@@ -447,21 +520,21 @@ function Calendar({ className, classNames, ...props }) {
|
|
|
447
520
|
}
|
|
448
521
|
|
|
449
522
|
// src/filter/DateRangeFilter.tsx
|
|
450
|
-
import { jsx as
|
|
523
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
451
524
|
var PRESETS = [
|
|
452
525
|
{
|
|
453
526
|
key: "today",
|
|
454
|
-
|
|
527
|
+
labelKey: "dateToday",
|
|
455
528
|
range: (today) => ({ from: startOfDay(today), to: endOfDay(today) })
|
|
456
529
|
},
|
|
457
530
|
{
|
|
458
531
|
key: "last7",
|
|
459
|
-
|
|
532
|
+
labelKey: "dateLast7Days",
|
|
460
533
|
range: (today) => ({ from: startOfDay(subDays(today, 6)), to: endOfDay(today) })
|
|
461
534
|
},
|
|
462
535
|
{
|
|
463
536
|
key: "thisMonth",
|
|
464
|
-
|
|
537
|
+
labelKey: "dateThisMonth",
|
|
465
538
|
range: (today) => ({ from: startOfMonth(today), to: endOfMonth(today) })
|
|
466
539
|
}
|
|
467
540
|
];
|
|
@@ -486,8 +559,11 @@ function DateRangeFilter({
|
|
|
486
559
|
value,
|
|
487
560
|
onChange,
|
|
488
561
|
today = /* @__PURE__ */ new Date(),
|
|
489
|
-
bare = false
|
|
562
|
+
bare = false,
|
|
563
|
+
labels: labelOverrides
|
|
490
564
|
}) {
|
|
565
|
+
const labels = useFilterLabels(labelOverrides);
|
|
566
|
+
const locale = labels.dateLocale ? { locale: labels.dateLocale } : void 0;
|
|
491
567
|
const range = rangeOf(value);
|
|
492
568
|
function emit(next) {
|
|
493
569
|
if (!next?.from || !next.to) {
|
|
@@ -502,56 +578,56 @@ function DateRangeFilter({
|
|
|
502
578
|
});
|
|
503
579
|
}
|
|
504
580
|
const isFiltered = range?.from !== void 0;
|
|
505
|
-
const summary = range?.from ? range.to ? `${format(range.from, "PP")} - ${format(range.to, "PP")}` : format(range.from, "PP") : "";
|
|
581
|
+
const summary = range?.from ? range.to ? `${format(range.from, "PP", locale)} - ${format(range.to, "PP", locale)}` : format(range.from, "PP", locale) : "";
|
|
506
582
|
const panel = /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
507
583
|
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-2", children: [
|
|
508
|
-
PRESETS.map((preset) => /* @__PURE__ */
|
|
584
|
+
PRESETS.map((preset) => /* @__PURE__ */ jsx7(
|
|
509
585
|
Button,
|
|
510
586
|
{
|
|
511
587
|
type: "button",
|
|
512
588
|
variant: "outline",
|
|
513
589
|
size: "sm",
|
|
514
590
|
onClick: () => emit(preset.range(today)),
|
|
515
|
-
children: preset.
|
|
591
|
+
children: labels[preset.labelKey]
|
|
516
592
|
},
|
|
517
593
|
preset.key
|
|
518
594
|
)),
|
|
519
|
-
/* @__PURE__ */
|
|
595
|
+
/* @__PURE__ */ jsx7(Button, { type: "button", variant: "outline", size: "sm", onClick: () => emit(void 0), children: labels.dateCustom })
|
|
520
596
|
] }),
|
|
521
|
-
/* @__PURE__ */
|
|
597
|
+
/* @__PURE__ */ jsx7(Calendar, { mode: "range", selected: range, onSelect: emit, numberOfMonths: 2, locale: labels.dateLocale })
|
|
522
598
|
] });
|
|
523
599
|
if (bare) {
|
|
524
|
-
return /* @__PURE__ */
|
|
600
|
+
return /* @__PURE__ */ jsx7("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
525
601
|
}
|
|
526
602
|
return /* @__PURE__ */ jsxs3(Popover, { children: [
|
|
527
|
-
/* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ jsx7(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
|
|
528
604
|
Button,
|
|
529
605
|
{
|
|
530
606
|
variant: "outline",
|
|
531
607
|
size: "sm",
|
|
532
608
|
className: cn("gap-1", isFiltered ? "max-w-[220px] px-2" : "w-8 justify-center px-0"),
|
|
533
|
-
"aria-label":
|
|
609
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
534
610
|
"data-testid": `filter-${column.id}`,
|
|
535
611
|
children: [
|
|
536
|
-
/* @__PURE__ */
|
|
537
|
-
isFiltered && /* @__PURE__ */
|
|
612
|
+
/* @__PURE__ */ jsx7(CalendarDaysIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-70", "aria-hidden": true }),
|
|
613
|
+
isFiltered && /* @__PURE__ */ jsx7("span", { className: "truncate", children: summary })
|
|
538
614
|
]
|
|
539
615
|
}
|
|
540
616
|
) }),
|
|
541
|
-
/* @__PURE__ */
|
|
617
|
+
/* @__PURE__ */ jsx7(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: panel })
|
|
542
618
|
] });
|
|
543
619
|
}
|
|
544
620
|
|
|
545
621
|
// src/filter/EnumFilter.tsx
|
|
546
622
|
import { FunnelIcon as FunnelIcon2 } from "@heroicons/react/24/outline";
|
|
547
|
-
import { useMemo, useState } from "react";
|
|
623
|
+
import { useMemo as useMemo2, useState } from "react";
|
|
548
624
|
|
|
549
625
|
// src/components/ui/checkbox.tsx
|
|
550
626
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
551
|
-
import {
|
|
627
|
+
import { CheckIcon as CheckIcon2, MinusIcon } from "@heroicons/react/24/outline";
|
|
552
628
|
import { forwardRef as forwardRef4 } from "react";
|
|
553
|
-
import { jsx as
|
|
554
|
-
var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */
|
|
629
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
630
|
+
var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
|
|
555
631
|
CheckboxPrimitive.Root,
|
|
556
632
|
{
|
|
557
633
|
ref,
|
|
@@ -564,16 +640,16 @@ var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx
|
|
|
564
640
|
className
|
|
565
641
|
),
|
|
566
642
|
...props,
|
|
567
|
-
children: /* @__PURE__ */
|
|
643
|
+
children: /* @__PURE__ */ jsx8(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx8(MinusIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(CheckIcon2, { className: "h-3 w-3" }) })
|
|
568
644
|
}
|
|
569
645
|
));
|
|
570
646
|
Checkbox.displayName = "Checkbox";
|
|
571
647
|
|
|
572
648
|
// src/components/ui/input.tsx
|
|
573
649
|
import { forwardRef as forwardRef5 } from "react";
|
|
574
|
-
import { jsx as
|
|
650
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
575
651
|
var Input = forwardRef5(({ className, type, ...props }, ref) => {
|
|
576
|
-
return /* @__PURE__ */
|
|
652
|
+
return /* @__PURE__ */ jsx9(
|
|
577
653
|
"input",
|
|
578
654
|
{
|
|
579
655
|
type,
|
|
@@ -589,7 +665,7 @@ var Input = forwardRef5(({ className, type, ...props }, ref) => {
|
|
|
589
665
|
Input.displayName = "Input";
|
|
590
666
|
|
|
591
667
|
// src/filter/EnumFilter.tsx
|
|
592
|
-
import { jsx as
|
|
668
|
+
import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
593
669
|
function selectedValuesOf(value) {
|
|
594
670
|
if (!value || value.operator !== "in" || !Array.isArray(value.value)) return [];
|
|
595
671
|
return value.value.filter((entry) => typeof entry === "string");
|
|
@@ -622,16 +698,18 @@ function EnumFilter({
|
|
|
622
698
|
column,
|
|
623
699
|
value,
|
|
624
700
|
onChange,
|
|
625
|
-
bare = false
|
|
701
|
+
bare = false,
|
|
702
|
+
labels: labelOverrides
|
|
626
703
|
}) {
|
|
704
|
+
const labels = useFilterLabels(labelOverrides);
|
|
627
705
|
const [search, setSearch] = useState("");
|
|
628
706
|
const selected = selectedValuesOf(value);
|
|
629
|
-
const visibleOptions =
|
|
707
|
+
const visibleOptions = useMemo2(() => {
|
|
630
708
|
const term = search.trim().toLowerCase();
|
|
631
709
|
if (!term) return column.options;
|
|
632
710
|
return column.options.filter((option) => option.label.toLowerCase().includes(term));
|
|
633
711
|
}, [column.options, search]);
|
|
634
|
-
const renderChunks =
|
|
712
|
+
const renderChunks = useMemo2(() => buildRenderChunks(visibleOptions), [visibleOptions]);
|
|
635
713
|
function emit(next) {
|
|
636
714
|
onChange(next.length === 0 ? void 0 : { field: column.id, operator: "in", value: next });
|
|
637
715
|
}
|
|
@@ -662,7 +740,7 @@ function EnumFilter({
|
|
|
662
740
|
{
|
|
663
741
|
className: "flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
|
|
664
742
|
children: [
|
|
665
|
-
/* @__PURE__ */
|
|
743
|
+
/* @__PURE__ */ jsx10(
|
|
666
744
|
Checkbox,
|
|
667
745
|
{
|
|
668
746
|
checked: selected.includes(option.value),
|
|
@@ -676,29 +754,29 @@ function EnumFilter({
|
|
|
676
754
|
);
|
|
677
755
|
}
|
|
678
756
|
const isFiltered = selected.length > 0;
|
|
679
|
-
const summary =
|
|
757
|
+
const summary = labels.selectedCount(selected.length);
|
|
680
758
|
const panel = /* @__PURE__ */ jsxs4("div", { className: bare ? "flex w-full flex-col gap-2" : "flex w-64 flex-col gap-2 p-2", children: [
|
|
681
|
-
/* @__PURE__ */
|
|
759
|
+
/* @__PURE__ */ jsx10(
|
|
682
760
|
Input,
|
|
683
761
|
{
|
|
684
|
-
placeholder:
|
|
762
|
+
placeholder: labels.searchPlaceholder(column.header),
|
|
685
763
|
value: search,
|
|
686
764
|
onChange: (event) => setSearch(event.target.value)
|
|
687
765
|
}
|
|
688
766
|
),
|
|
689
767
|
/* @__PURE__ */ jsxs4("label", { className: "flex items-center gap-2 border-b px-1 pb-2 text-sm", children: [
|
|
690
|
-
/* @__PURE__ */
|
|
768
|
+
/* @__PURE__ */ jsx10(
|
|
691
769
|
Checkbox,
|
|
692
770
|
{
|
|
693
771
|
checked: someVisibleSelected ? "indeterminate" : allVisibleSelected,
|
|
694
772
|
disabled: visibleValues.length === 0,
|
|
695
773
|
onCheckedChange: toggleSelectAllVisible,
|
|
696
|
-
"aria-label":
|
|
774
|
+
"aria-label": labels.selectAll
|
|
697
775
|
}
|
|
698
776
|
),
|
|
699
|
-
|
|
777
|
+
labels.selectAll
|
|
700
778
|
] }),
|
|
701
|
-
/* @__PURE__ */
|
|
779
|
+
/* @__PURE__ */ jsx10("div", { className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: renderChunks.length === 0 ? /* @__PURE__ */ jsx10("p", { className: "py-2 text-center text-sm text-muted-foreground", children: labels.noMatches }) : renderChunks.map((chunk) => {
|
|
702
780
|
if (chunk.kind === "single") return renderOption(chunk.row.option);
|
|
703
781
|
const headerState = groupCheckState(visibleOptions, selected, chunk.group);
|
|
704
782
|
return (
|
|
@@ -713,12 +791,12 @@ function EnumFilter({
|
|
|
713
791
|
"data-group-header": true,
|
|
714
792
|
className: "sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground",
|
|
715
793
|
children: [
|
|
716
|
-
/* @__PURE__ */
|
|
794
|
+
/* @__PURE__ */ jsx10(
|
|
717
795
|
Checkbox,
|
|
718
796
|
{
|
|
719
797
|
checked: headerState === "indeterminate" ? "indeterminate" : headerState === "checked",
|
|
720
798
|
onCheckedChange: () => toggleGroup(chunk.group),
|
|
721
|
-
"aria-label":
|
|
799
|
+
"aria-label": labels.selectAllOfGroup(chunk.group)
|
|
722
800
|
}
|
|
723
801
|
),
|
|
724
802
|
chunk.group
|
|
@@ -731,30 +809,30 @@ function EnumFilter({
|
|
|
731
809
|
}) })
|
|
732
810
|
] });
|
|
733
811
|
if (bare) {
|
|
734
|
-
return /* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsx10("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
735
813
|
}
|
|
736
814
|
return /* @__PURE__ */ jsxs4(Popover, { children: [
|
|
737
|
-
/* @__PURE__ */
|
|
815
|
+
/* @__PURE__ */ jsx10(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
|
|
738
816
|
Button,
|
|
739
817
|
{
|
|
740
818
|
variant: "outline",
|
|
741
819
|
size: "sm",
|
|
742
820
|
className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
|
|
743
|
-
"aria-label":
|
|
821
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
744
822
|
"data-testid": `filter-${column.id}`,
|
|
745
823
|
children: [
|
|
746
|
-
/* @__PURE__ */
|
|
824
|
+
/* @__PURE__ */ jsx10(
|
|
747
825
|
FunnelIcon2,
|
|
748
826
|
{
|
|
749
827
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
750
828
|
"aria-hidden": true
|
|
751
829
|
}
|
|
752
830
|
),
|
|
753
|
-
isFiltered && /* @__PURE__ */
|
|
831
|
+
isFiltered && /* @__PURE__ */ jsx10("span", { className: "truncate", children: summary })
|
|
754
832
|
]
|
|
755
833
|
}
|
|
756
834
|
) }),
|
|
757
|
-
/* @__PURE__ */
|
|
835
|
+
/* @__PURE__ */ jsx10(PopoverContent, { className: "w-64 p-2", children: panel })
|
|
758
836
|
] });
|
|
759
837
|
}
|
|
760
838
|
|
|
@@ -897,15 +975,15 @@ function descriptorFor(field, range) {
|
|
|
897
975
|
}
|
|
898
976
|
|
|
899
977
|
// src/filter/NumberComparisonFilter.tsx
|
|
900
|
-
import { Fragment, jsx as
|
|
978
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
901
979
|
var NUMBER_OPERATORS = [
|
|
902
|
-
{ value: "gt",
|
|
903
|
-
{ value: "gte",
|
|
904
|
-
{ value: "lt",
|
|
905
|
-
{ value: "lte",
|
|
906
|
-
{ value: "eq",
|
|
907
|
-
{ value: "neq",
|
|
908
|
-
{ value: "between",
|
|
980
|
+
{ value: "gt", labelKey: "numberGreaterThan" },
|
|
981
|
+
{ value: "gte", labelKey: "numberGreaterThanOrEqual" },
|
|
982
|
+
{ value: "lt", labelKey: "numberLessThan" },
|
|
983
|
+
{ value: "lte", labelKey: "numberLessThanOrEqual" },
|
|
984
|
+
{ value: "eq", labelKey: "numberEquals" },
|
|
985
|
+
{ value: "neq", labelKey: "numberNotEquals" },
|
|
986
|
+
{ value: "between", labelKey: "numberBetween" }
|
|
909
987
|
];
|
|
910
988
|
var OPERATOR_SYMBOL = {
|
|
911
989
|
gt: ">",
|
|
@@ -939,8 +1017,10 @@ function NumberComparisonFilter({
|
|
|
939
1017
|
column,
|
|
940
1018
|
value,
|
|
941
1019
|
onChange,
|
|
942
|
-
bare = true
|
|
1020
|
+
bare = true,
|
|
1021
|
+
labels: labelOverrides
|
|
943
1022
|
}) {
|
|
1023
|
+
const labels = useFilterLabels(labelOverrides);
|
|
944
1024
|
const initial = stateFromValue(value);
|
|
945
1025
|
const [operator, setOperator] = useState2(initial.operator);
|
|
946
1026
|
const [text, setText] = useState2(initial.text);
|
|
@@ -994,20 +1074,20 @@ function NumberComparisonFilter({
|
|
|
994
1074
|
emit(nextOperator, text, text2);
|
|
995
1075
|
},
|
|
996
1076
|
children: [
|
|
997
|
-
/* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
1077
|
+
/* @__PURE__ */ jsx11(SelectTrigger, { id: operatorId, "aria-label": labels.operatorAriaLabel(column.header), children: /* @__PURE__ */ jsx11(SelectValue, {}) }),
|
|
1078
|
+
/* @__PURE__ */ jsx11(SelectContent, { children: NUMBER_OPERATORS.map((option) => /* @__PURE__ */ jsx11(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
|
|
999
1079
|
]
|
|
1000
1080
|
}
|
|
1001
1081
|
),
|
|
1002
1082
|
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
1003
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsx11(
|
|
1004
1084
|
Input,
|
|
1005
1085
|
{
|
|
1006
1086
|
id: valueId,
|
|
1007
1087
|
type: "number",
|
|
1008
1088
|
className: "min-w-0",
|
|
1009
|
-
"aria-label": isBetween ?
|
|
1010
|
-
placeholder: isBetween ?
|
|
1089
|
+
"aria-label": isBetween ? labels.minimumAriaLabel(column.header) : column.header,
|
|
1090
|
+
placeholder: isBetween ? labels.minPlaceholder : labels.valuePlaceholder,
|
|
1011
1091
|
value: text,
|
|
1012
1092
|
onChange: (event) => {
|
|
1013
1093
|
setText(event.target.value);
|
|
@@ -1016,14 +1096,14 @@ function NumberComparisonFilter({
|
|
|
1016
1096
|
}
|
|
1017
1097
|
),
|
|
1018
1098
|
isBetween && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1019
|
-
/* @__PURE__ */
|
|
1020
|
-
/* @__PURE__ */
|
|
1099
|
+
/* @__PURE__ */ jsx11("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
|
|
1100
|
+
/* @__PURE__ */ jsx11(
|
|
1021
1101
|
Input,
|
|
1022
1102
|
{
|
|
1023
1103
|
type: "number",
|
|
1024
1104
|
className: "min-w-0",
|
|
1025
|
-
"aria-label":
|
|
1026
|
-
placeholder:
|
|
1105
|
+
"aria-label": labels.maximumAriaLabel(column.header),
|
|
1106
|
+
placeholder: labels.maxPlaceholder,
|
|
1027
1107
|
value: text2,
|
|
1028
1108
|
onChange: (event) => {
|
|
1029
1109
|
setText2(event.target.value);
|
|
@@ -1035,37 +1115,37 @@ function NumberComparisonFilter({
|
|
|
1035
1115
|
] })
|
|
1036
1116
|
] });
|
|
1037
1117
|
if (bare) {
|
|
1038
|
-
return /* @__PURE__ */
|
|
1118
|
+
return /* @__PURE__ */ jsx11("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
1039
1119
|
}
|
|
1040
1120
|
return /* @__PURE__ */ jsxs5(Popover, { children: [
|
|
1041
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsx11(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
|
|
1042
1122
|
Button,
|
|
1043
1123
|
{
|
|
1044
1124
|
variant: "outline",
|
|
1045
1125
|
size: "sm",
|
|
1046
1126
|
className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
|
|
1047
|
-
"aria-label":
|
|
1127
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
1048
1128
|
"data-testid": `filter-${column.id}`,
|
|
1049
1129
|
children: [
|
|
1050
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx11(
|
|
1051
1131
|
FunnelIcon3,
|
|
1052
1132
|
{
|
|
1053
1133
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
1054
1134
|
"aria-hidden": true
|
|
1055
1135
|
}
|
|
1056
1136
|
),
|
|
1057
|
-
isFiltered && /* @__PURE__ */
|
|
1137
|
+
isFiltered && /* @__PURE__ */ jsx11("span", { className: "truncate", children: summary })
|
|
1058
1138
|
]
|
|
1059
1139
|
}
|
|
1060
1140
|
) }),
|
|
1061
|
-
/* @__PURE__ */
|
|
1141
|
+
/* @__PURE__ */ jsx11(PopoverContent, { className: "w-auto p-3", children: panel })
|
|
1062
1142
|
] });
|
|
1063
1143
|
}
|
|
1064
1144
|
|
|
1065
1145
|
// src/filter/NumberRangeFilter.tsx
|
|
1066
1146
|
import { FunnelIcon as FunnelIcon4 } from "@heroicons/react/24/outline";
|
|
1067
1147
|
import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
|
|
1068
|
-
import { jsx as
|
|
1148
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1069
1149
|
function parseNumber2(raw) {
|
|
1070
1150
|
if (raw.trim() === "") return void 0;
|
|
1071
1151
|
const parsed = Number(raw);
|
|
@@ -1075,8 +1155,10 @@ function NumberRangeFilter({
|
|
|
1075
1155
|
column,
|
|
1076
1156
|
value,
|
|
1077
1157
|
onChange,
|
|
1078
|
-
bare = false
|
|
1158
|
+
bare = false,
|
|
1159
|
+
labels: labelOverrides
|
|
1079
1160
|
}) {
|
|
1161
|
+
const labels = useFilterLabels(labelOverrides);
|
|
1080
1162
|
const initial = rangeOf2(value);
|
|
1081
1163
|
const [minText, setMinText] = useState3(initial.min?.toString() ?? "");
|
|
1082
1164
|
const [maxText, setMaxText] = useState3(initial.max?.toString() ?? "");
|
|
@@ -1102,13 +1184,13 @@ function NumberRangeFilter({
|
|
|
1102
1184
|
const isFiltered = min !== void 0 || max !== void 0;
|
|
1103
1185
|
const summary = min !== void 0 && max !== void 0 ? `${defaultFormat(column, min)} \u2013 ${defaultFormat(column, max)}` : min !== void 0 ? `\u2265 ${defaultFormat(column, min)}` : max !== void 0 ? `\u2264 ${defaultFormat(column, max)}` : "";
|
|
1104
1186
|
const panel = /* @__PURE__ */ jsxs6("div", { className: "flex w-full max-w-[220px] items-center gap-2", children: [
|
|
1105
|
-
/* @__PURE__ */
|
|
1187
|
+
/* @__PURE__ */ jsx12(
|
|
1106
1188
|
Input,
|
|
1107
1189
|
{
|
|
1108
1190
|
id: minId,
|
|
1109
1191
|
type: "number",
|
|
1110
|
-
"aria-label":
|
|
1111
|
-
placeholder:
|
|
1192
|
+
"aria-label": labels.minimumAriaLabel(column.header),
|
|
1193
|
+
placeholder: labels.minPlaceholder,
|
|
1112
1194
|
className: "min-w-0",
|
|
1113
1195
|
value: minText,
|
|
1114
1196
|
onChange: (event) => {
|
|
@@ -1117,14 +1199,14 @@ function NumberRangeFilter({
|
|
|
1117
1199
|
}
|
|
1118
1200
|
}
|
|
1119
1201
|
),
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1202
|
+
/* @__PURE__ */ jsx12("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
|
|
1203
|
+
/* @__PURE__ */ jsx12(
|
|
1122
1204
|
Input,
|
|
1123
1205
|
{
|
|
1124
1206
|
id: maxId,
|
|
1125
1207
|
type: "number",
|
|
1126
|
-
"aria-label":
|
|
1127
|
-
placeholder:
|
|
1208
|
+
"aria-label": labels.maximumAriaLabel(column.header),
|
|
1209
|
+
placeholder: labels.maxPlaceholder,
|
|
1128
1210
|
className: "min-w-0",
|
|
1129
1211
|
value: maxText,
|
|
1130
1212
|
onChange: (event) => {
|
|
@@ -1135,37 +1217,37 @@ function NumberRangeFilter({
|
|
|
1135
1217
|
)
|
|
1136
1218
|
] });
|
|
1137
1219
|
if (bare) {
|
|
1138
|
-
return /* @__PURE__ */
|
|
1220
|
+
return /* @__PURE__ */ jsx12("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
1139
1221
|
}
|
|
1140
1222
|
return /* @__PURE__ */ jsxs6(Popover, { children: [
|
|
1141
|
-
/* @__PURE__ */
|
|
1223
|
+
/* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
|
|
1142
1224
|
Button,
|
|
1143
1225
|
{
|
|
1144
1226
|
variant: "outline",
|
|
1145
1227
|
size: "sm",
|
|
1146
1228
|
className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
|
|
1147
|
-
"aria-label":
|
|
1229
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
1148
1230
|
"data-testid": `filter-${column.id}`,
|
|
1149
1231
|
children: [
|
|
1150
|
-
/* @__PURE__ */
|
|
1232
|
+
/* @__PURE__ */ jsx12(
|
|
1151
1233
|
FunnelIcon4,
|
|
1152
1234
|
{
|
|
1153
1235
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
1154
1236
|
"aria-hidden": true
|
|
1155
1237
|
}
|
|
1156
1238
|
),
|
|
1157
|
-
isFiltered && /* @__PURE__ */
|
|
1239
|
+
isFiltered && /* @__PURE__ */ jsx12("span", { className: "truncate", children: summary })
|
|
1158
1240
|
]
|
|
1159
1241
|
}
|
|
1160
1242
|
) }),
|
|
1161
|
-
/* @__PURE__ */
|
|
1243
|
+
/* @__PURE__ */ jsx12(PopoverContent, { className: "w-auto p-3", children: panel })
|
|
1162
1244
|
] });
|
|
1163
1245
|
}
|
|
1164
1246
|
|
|
1165
1247
|
// src/filter/NumberHistogramFilter.tsx
|
|
1166
|
-
import { FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
|
|
1167
|
-
import { useCallback, useEffect as useEffect4, useMemo as
|
|
1168
|
-
import { jsx as
|
|
1248
|
+
import { ExclamationTriangleIcon, FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
|
|
1249
|
+
import { useCallback, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
|
|
1250
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1169
1251
|
var BAR_HEIGHT_PX = 56;
|
|
1170
1252
|
var DEFAULT_BUCKETS = 24;
|
|
1171
1253
|
function tLog(v) {
|
|
@@ -1182,35 +1264,42 @@ function NumberHistogramFilter({
|
|
|
1182
1264
|
loadValues,
|
|
1183
1265
|
format: format2 = (v) => v.toLocaleString(),
|
|
1184
1266
|
buckets = DEFAULT_BUCKETS,
|
|
1185
|
-
bare = true
|
|
1267
|
+
bare = true,
|
|
1268
|
+
labels: labelOverrides
|
|
1186
1269
|
}) {
|
|
1270
|
+
const labels = useFilterLabels(labelOverrides);
|
|
1187
1271
|
const [openState, setOpen] = useState4(false);
|
|
1188
1272
|
const open = bare || openState;
|
|
1189
1273
|
const trackRef = useRef4(null);
|
|
1190
1274
|
const [minOnTop, setMinOnTop] = useState4(false);
|
|
1191
1275
|
const [loadedValues, setLoadedValues] = useState4([]);
|
|
1192
1276
|
const [loading, setLoading] = useState4(false);
|
|
1277
|
+
const [loadError, setLoadError] = useState4(void 0);
|
|
1278
|
+
const [retryKey, setRetryKey] = useState4(0);
|
|
1193
1279
|
const { min, max } = rangeOf2(value);
|
|
1194
1280
|
useEffect4(() => {
|
|
1195
1281
|
if (!open || !loadValues) return;
|
|
1196
1282
|
let cancelled = false;
|
|
1197
1283
|
setLoading(true);
|
|
1284
|
+
setLoadError(void 0);
|
|
1198
1285
|
loadValues().then((values) => {
|
|
1199
1286
|
if (!cancelled) setLoadedValues(values);
|
|
1287
|
+
}).catch((err) => {
|
|
1288
|
+
if (!cancelled) setLoadError(err instanceof Error ? err.message : String(err));
|
|
1200
1289
|
}).finally(() => {
|
|
1201
1290
|
if (!cancelled) setLoading(false);
|
|
1202
1291
|
});
|
|
1203
1292
|
return () => {
|
|
1204
1293
|
cancelled = true;
|
|
1205
1294
|
};
|
|
1206
|
-
}, [open, loadValues]);
|
|
1295
|
+
}, [open, loadValues, retryKey]);
|
|
1207
1296
|
const sourceValues = allValues ?? loadedValues;
|
|
1208
|
-
const nums =
|
|
1297
|
+
const nums = useMemo3(
|
|
1209
1298
|
() => open ? sourceValues.filter((v) => v != null) : [],
|
|
1210
1299
|
[sourceValues, open]
|
|
1211
1300
|
);
|
|
1212
|
-
const dataMin =
|
|
1213
|
-
const dataMax =
|
|
1301
|
+
const dataMin = useMemo3(() => nums.reduce((a, b) => Math.min(a, b), Infinity), [nums]);
|
|
1302
|
+
const dataMax = useMemo3(() => nums.reduce((a, b) => Math.max(a, b), -Infinity), [nums]);
|
|
1214
1303
|
const activeMin = min ?? dataMin;
|
|
1215
1304
|
const activeMax = max ?? dataMax;
|
|
1216
1305
|
const [minText, setMinText] = useState4("");
|
|
@@ -1227,7 +1316,7 @@ function NumberHistogramFilter({
|
|
|
1227
1316
|
(v) => logDataMax === logDataMin ? 0 : (tLog(v) - logDataMin) / (logDataMax - logDataMin) * 100,
|
|
1228
1317
|
[logDataMin, logDataMax]
|
|
1229
1318
|
);
|
|
1230
|
-
const histBars =
|
|
1319
|
+
const histBars = useMemo3(() => {
|
|
1231
1320
|
if (!nums.length || dataMin === dataMax || !Number.isFinite(dataMin) || !Number.isFinite(dataMax)) return [];
|
|
1232
1321
|
const step = (logDataMax - logDataMin) / buckets;
|
|
1233
1322
|
const counts = Array(buckets).fill(0);
|
|
@@ -1266,8 +1355,22 @@ function NumberHistogramFilter({
|
|
|
1266
1355
|
const isFiltered = value !== void 0;
|
|
1267
1356
|
const summary = isFiltered ? `${format2(activeMin)} \u2013 ${format2(activeMax)}` : "";
|
|
1268
1357
|
const panel = /* @__PURE__ */ jsxs7("div", { className: bare ? "flex w-full flex-col gap-3" : "flex w-80 flex-col gap-3", children: [
|
|
1269
|
-
loading && /* @__PURE__ */
|
|
1270
|
-
|
|
1358
|
+
loading && /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", "data-testid": `filter-${column.id}-loading`, children: labels.loading }),
|
|
1359
|
+
loadError !== void 0 && !loading && /* @__PURE__ */ jsxs7(
|
|
1360
|
+
"span",
|
|
1361
|
+
{
|
|
1362
|
+
role: "alert",
|
|
1363
|
+
title: loadError,
|
|
1364
|
+
className: "flex items-center gap-1.5 text-xs text-destructive",
|
|
1365
|
+
"data-testid": `filter-${column.id}-error`,
|
|
1366
|
+
children: [
|
|
1367
|
+
/* @__PURE__ */ jsx13(ExclamationTriangleIcon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }),
|
|
1368
|
+
labels.loadFailed,
|
|
1369
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "underline underline-offset-2", onClick: () => setRetryKey((k) => k + 1), children: labels.retry })
|
|
1370
|
+
]
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-end gap-px", style: { height: BAR_HEIGHT_PX }, "data-testid": `filter-${column.id}-histogram`, children: histBars.map((bar, i) => /* @__PURE__ */ jsx13(
|
|
1271
1374
|
"div",
|
|
1272
1375
|
{
|
|
1273
1376
|
className: cn("flex-1 rounded-sm", bar.active ? "bg-primary/70" : "bg-muted-foreground/20"),
|
|
@@ -1276,11 +1379,11 @@ function NumberHistogramFilter({
|
|
|
1276
1379
|
i
|
|
1277
1380
|
)) }),
|
|
1278
1381
|
/* @__PURE__ */ jsxs7("div", { ref: trackRef, className: "relative h-5", onMouseMove: handleTrackHover, children: [
|
|
1279
|
-
/* @__PURE__ */
|
|
1382
|
+
/* @__PURE__ */ jsx13(
|
|
1280
1383
|
"input",
|
|
1281
1384
|
{
|
|
1282
1385
|
type: "range",
|
|
1283
|
-
"aria-label":
|
|
1386
|
+
"aria-label": labels.minimumSliderAriaLabel(column.header),
|
|
1284
1387
|
min: logDataMin,
|
|
1285
1388
|
max: logDataMax,
|
|
1286
1389
|
step: logStep,
|
|
@@ -1290,11 +1393,11 @@ function NumberHistogramFilter({
|
|
|
1290
1393
|
style: { zIndex: minOnTop ? 5 : 3 }
|
|
1291
1394
|
}
|
|
1292
1395
|
),
|
|
1293
|
-
/* @__PURE__ */
|
|
1396
|
+
/* @__PURE__ */ jsx13(
|
|
1294
1397
|
"input",
|
|
1295
1398
|
{
|
|
1296
1399
|
type: "range",
|
|
1297
|
-
"aria-label":
|
|
1400
|
+
"aria-label": labels.maximumSliderAriaLabel(column.header),
|
|
1298
1401
|
min: logDataMin,
|
|
1299
1402
|
max: logDataMax,
|
|
1300
1403
|
step: logStep,
|
|
@@ -1304,14 +1407,14 @@ function NumberHistogramFilter({
|
|
|
1304
1407
|
style: { zIndex: minOnTop ? 3 : 5 }
|
|
1305
1408
|
}
|
|
1306
1409
|
),
|
|
1307
|
-
/* @__PURE__ */
|
|
1410
|
+
/* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute top-1/2 h-1.5 w-full -translate-y-1/2 rounded-full bg-muted", children: /* @__PURE__ */ jsx13(
|
|
1308
1411
|
"div",
|
|
1309
1412
|
{
|
|
1310
1413
|
className: "absolute h-full rounded-full bg-primary",
|
|
1311
1414
|
style: { left: `${logPct(activeMin)}%`, right: `${100 - logPct(activeMax)}%` }
|
|
1312
1415
|
}
|
|
1313
1416
|
) }),
|
|
1314
|
-
[activeMin, activeMax].map((v, i) => /* @__PURE__ */
|
|
1417
|
+
[activeMin, activeMax].map((v, i) => /* @__PURE__ */ jsx13(
|
|
1315
1418
|
"div",
|
|
1316
1419
|
{
|
|
1317
1420
|
className: "pointer-events-none absolute top-1/2 h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-primary bg-background shadow",
|
|
@@ -1321,12 +1424,12 @@ function NumberHistogramFilter({
|
|
|
1321
1424
|
))
|
|
1322
1425
|
] }),
|
|
1323
1426
|
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
1324
|
-
/* @__PURE__ */
|
|
1427
|
+
/* @__PURE__ */ jsx13(
|
|
1325
1428
|
Input,
|
|
1326
1429
|
{
|
|
1327
1430
|
type: "text",
|
|
1328
1431
|
inputMode: "numeric",
|
|
1329
|
-
"aria-label":
|
|
1432
|
+
"aria-label": labels.minimumAriaLabel(column.header),
|
|
1330
1433
|
value: minText,
|
|
1331
1434
|
onChange: (event) => {
|
|
1332
1435
|
setMinText(event.target.value);
|
|
@@ -1335,13 +1438,13 @@ function NumberHistogramFilter({
|
|
|
1335
1438
|
}
|
|
1336
1439
|
}
|
|
1337
1440
|
),
|
|
1338
|
-
/* @__PURE__ */
|
|
1339
|
-
/* @__PURE__ */
|
|
1441
|
+
/* @__PURE__ */ jsx13("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
|
|
1442
|
+
/* @__PURE__ */ jsx13(
|
|
1340
1443
|
Input,
|
|
1341
1444
|
{
|
|
1342
1445
|
type: "text",
|
|
1343
1446
|
inputMode: "numeric",
|
|
1344
|
-
"aria-label":
|
|
1447
|
+
"aria-label": labels.maximumAriaLabel(column.header),
|
|
1345
1448
|
value: maxText,
|
|
1346
1449
|
onChange: (event) => {
|
|
1347
1450
|
setMaxText(event.target.value);
|
|
@@ -1351,33 +1454,33 @@ function NumberHistogramFilter({
|
|
|
1351
1454
|
}
|
|
1352
1455
|
)
|
|
1353
1456
|
] }),
|
|
1354
|
-
isFiltered && /* @__PURE__ */
|
|
1457
|
+
isFiltered && /* @__PURE__ */ jsx13(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onChange(void 0), children: labels.clear })
|
|
1355
1458
|
] });
|
|
1356
1459
|
if (bare) {
|
|
1357
|
-
return /* @__PURE__ */
|
|
1460
|
+
return /* @__PURE__ */ jsx13("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
1358
1461
|
}
|
|
1359
1462
|
return /* @__PURE__ */ jsxs7(Popover, { open, onOpenChange: setOpen, children: [
|
|
1360
|
-
/* @__PURE__ */
|
|
1463
|
+
/* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
|
|
1361
1464
|
Button,
|
|
1362
1465
|
{
|
|
1363
1466
|
variant: "outline",
|
|
1364
1467
|
size: "sm",
|
|
1365
1468
|
className: cn("gap-1", isFiltered ? "max-w-[200px] px-2" : "w-8 justify-center px-0"),
|
|
1366
|
-
"aria-label":
|
|
1469
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
1367
1470
|
"data-testid": `filter-${column.id}`,
|
|
1368
1471
|
children: [
|
|
1369
|
-
/* @__PURE__ */
|
|
1472
|
+
/* @__PURE__ */ jsx13(
|
|
1370
1473
|
FunnelIcon5,
|
|
1371
1474
|
{
|
|
1372
1475
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
1373
1476
|
"aria-hidden": true
|
|
1374
1477
|
}
|
|
1375
1478
|
),
|
|
1376
|
-
isFiltered && /* @__PURE__ */
|
|
1479
|
+
isFiltered && /* @__PURE__ */ jsx13("span", { className: "truncate", children: summary })
|
|
1377
1480
|
]
|
|
1378
1481
|
}
|
|
1379
1482
|
) }),
|
|
1380
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ jsx13(PopoverContent, { className: "w-80", children: panel })
|
|
1381
1484
|
] });
|
|
1382
1485
|
}
|
|
1383
1486
|
|
|
@@ -1429,20 +1532,22 @@ function facetedNumberValues(data, column, filter) {
|
|
|
1429
1532
|
// src/filter/StringFilter.tsx
|
|
1430
1533
|
import { FunnelIcon as FunnelIcon6 } from "@heroicons/react/24/outline";
|
|
1431
1534
|
import { useEffect as useEffect5, useId as useId3, useState as useState5 } from "react";
|
|
1432
|
-
import { jsx as
|
|
1535
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1433
1536
|
var STRING_OPERATORS = [
|
|
1434
|
-
{ value: "contains",
|
|
1435
|
-
{ value: "eq",
|
|
1436
|
-
{ value: "startsWith",
|
|
1437
|
-
{ value: "endsWith",
|
|
1537
|
+
{ value: "contains", labelKey: "stringContains" },
|
|
1538
|
+
{ value: "eq", labelKey: "stringIs" },
|
|
1539
|
+
{ value: "startsWith", labelKey: "stringStartsWith" },
|
|
1540
|
+
{ value: "endsWith", labelKey: "stringEndsWith" }
|
|
1438
1541
|
];
|
|
1439
1542
|
var DEFAULT_OPERATOR2 = "contains";
|
|
1440
1543
|
function StringFilter({
|
|
1441
1544
|
column,
|
|
1442
1545
|
value,
|
|
1443
1546
|
onChange,
|
|
1444
|
-
bare = false
|
|
1547
|
+
bare = false,
|
|
1548
|
+
labels: labelOverrides
|
|
1445
1549
|
}) {
|
|
1550
|
+
const labels = useFilterLabels(labelOverrides);
|
|
1446
1551
|
const [operator, setOperator] = useState5(value?.operator ?? DEFAULT_OPERATOR2);
|
|
1447
1552
|
const text = typeof value?.value === "string" ? value.value : "";
|
|
1448
1553
|
const inputId = useId3();
|
|
@@ -1469,66 +1574,66 @@ function StringFilter({
|
|
|
1469
1574
|
emit(nextOperator, text);
|
|
1470
1575
|
},
|
|
1471
1576
|
children: [
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
1577
|
+
/* @__PURE__ */ jsx14(SelectTrigger, { "aria-label": labels.operatorAriaLabel(column.header), children: /* @__PURE__ */ jsx14(SelectValue, {}) }),
|
|
1578
|
+
/* @__PURE__ */ jsx14(SelectContent, { children: STRING_OPERATORS.map((option) => /* @__PURE__ */ jsx14(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
|
|
1474
1579
|
]
|
|
1475
1580
|
}
|
|
1476
1581
|
),
|
|
1477
|
-
/* @__PURE__ */
|
|
1582
|
+
/* @__PURE__ */ jsx14(
|
|
1478
1583
|
Input,
|
|
1479
1584
|
{
|
|
1480
1585
|
id: inputId,
|
|
1481
1586
|
value: text,
|
|
1482
|
-
placeholder:
|
|
1587
|
+
placeholder: labels.stringPlaceholder(column.header),
|
|
1483
1588
|
onChange: (event) => emit(operator, event.target.value)
|
|
1484
1589
|
}
|
|
1485
1590
|
)
|
|
1486
1591
|
] });
|
|
1487
1592
|
if (bare) {
|
|
1488
|
-
return /* @__PURE__ */
|
|
1593
|
+
return /* @__PURE__ */ jsx14("div", { "data-testid": `filter-${column.id}`, children: panel });
|
|
1489
1594
|
}
|
|
1490
1595
|
return /* @__PURE__ */ jsxs8(Popover, { children: [
|
|
1491
|
-
/* @__PURE__ */
|
|
1596
|
+
/* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
|
|
1492
1597
|
Button,
|
|
1493
1598
|
{
|
|
1494
1599
|
variant: "outline",
|
|
1495
1600
|
size: "sm",
|
|
1496
1601
|
className: cn("gap-1", isFiltered ? "max-w-[160px] px-2" : "w-8 justify-center px-0"),
|
|
1497
|
-
"aria-label":
|
|
1602
|
+
"aria-label": labels.filterAriaLabel(column.header),
|
|
1498
1603
|
"data-testid": `filter-${column.id}`,
|
|
1499
1604
|
children: [
|
|
1500
|
-
/* @__PURE__ */
|
|
1605
|
+
/* @__PURE__ */ jsx14(
|
|
1501
1606
|
FunnelIcon6,
|
|
1502
1607
|
{
|
|
1503
1608
|
className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
|
|
1504
1609
|
"aria-hidden": true
|
|
1505
1610
|
}
|
|
1506
1611
|
),
|
|
1507
|
-
isFiltered && /* @__PURE__ */
|
|
1612
|
+
isFiltered && /* @__PURE__ */ jsx14("span", { className: "truncate", children: text })
|
|
1508
1613
|
]
|
|
1509
1614
|
}
|
|
1510
1615
|
) }),
|
|
1511
|
-
/* @__PURE__ */
|
|
1616
|
+
/* @__PURE__ */ jsx14(PopoverContent, { className: "w-auto p-3", children: panel })
|
|
1512
1617
|
] });
|
|
1513
1618
|
}
|
|
1514
1619
|
|
|
1515
1620
|
// src/filter/registry.tsx
|
|
1516
|
-
import { jsx as
|
|
1621
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1517
1622
|
function renderDefaultFilterWidget(column, value, onChange) {
|
|
1518
1623
|
const bare = column.filterDisplay !== "row";
|
|
1519
1624
|
switch (column.type) {
|
|
1520
1625
|
case "string":
|
|
1521
|
-
return /* @__PURE__ */
|
|
1626
|
+
return /* @__PURE__ */ jsx15(StringFilter, { column, value, onChange, bare });
|
|
1522
1627
|
case "enum":
|
|
1523
|
-
return /* @__PURE__ */
|
|
1628
|
+
return /* @__PURE__ */ jsx15(EnumFilter, { column, value, onChange, bare });
|
|
1524
1629
|
case "boolean":
|
|
1525
|
-
return /* @__PURE__ */
|
|
1630
|
+
return /* @__PURE__ */ jsx15(BooleanFilter, { column, value, onChange, bare });
|
|
1526
1631
|
case "number":
|
|
1527
1632
|
case "currency":
|
|
1528
|
-
return /* @__PURE__ */
|
|
1633
|
+
return /* @__PURE__ */ jsx15(NumberRangeFilter, { column, value, onChange, bare });
|
|
1529
1634
|
case "date":
|
|
1530
1635
|
case "datetime":
|
|
1531
|
-
return /* @__PURE__ */
|
|
1636
|
+
return /* @__PURE__ */ jsx15(DateRangeFilter, { column, value, onChange, bare });
|
|
1532
1637
|
}
|
|
1533
1638
|
}
|
|
1534
1639
|
|
|
@@ -1538,13 +1643,13 @@ function editErrorId(rowId, columnId) {
|
|
|
1538
1643
|
}
|
|
1539
1644
|
|
|
1540
1645
|
// src/edit/EditFieldError.tsx
|
|
1541
|
-
import { jsx as
|
|
1646
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1542
1647
|
function EditFieldError({ id, message }) {
|
|
1543
|
-
return /* @__PURE__ */
|
|
1648
|
+
return /* @__PURE__ */ jsx16("span", { id, className: "mt-0.5 block text-xs text-destructive", children: message });
|
|
1544
1649
|
}
|
|
1545
1650
|
|
|
1546
1651
|
// src/edit/BooleanEditor.tsx
|
|
1547
|
-
import { jsx as
|
|
1652
|
+
import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1548
1653
|
function toBoolean(value) {
|
|
1549
1654
|
if (typeof value === "boolean") return value;
|
|
1550
1655
|
if (typeof value === "string") return value.trim().toLowerCase() === "true";
|
|
@@ -1565,7 +1670,7 @@ function BooleanEditor({
|
|
|
1565
1670
|
// `mt-0.5` already provides the same spacing every other editor gets;
|
|
1566
1671
|
// adding both would double it for this one editor only.
|
|
1567
1672
|
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center", children: [
|
|
1568
|
-
/* @__PURE__ */
|
|
1673
|
+
/* @__PURE__ */ jsx17(
|
|
1569
1674
|
Checkbox,
|
|
1570
1675
|
{
|
|
1571
1676
|
"aria-label": `Edit ${column.header}`,
|
|
@@ -1577,14 +1682,14 @@ function BooleanEditor({
|
|
|
1577
1682
|
onCheckedChange: (next) => onChange(next === true)
|
|
1578
1683
|
}
|
|
1579
1684
|
),
|
|
1580
|
-
error && /* @__PURE__ */
|
|
1685
|
+
error && /* @__PURE__ */ jsx17(EditFieldError, { id: errorId, message: error })
|
|
1581
1686
|
] })
|
|
1582
1687
|
);
|
|
1583
1688
|
}
|
|
1584
1689
|
|
|
1585
1690
|
// src/edit/DateEditor.tsx
|
|
1586
1691
|
import { format as formatDate, parseISO as parseISO4 } from "date-fns";
|
|
1587
|
-
import { jsx as
|
|
1692
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1588
1693
|
function inputValueOf(value, columnType) {
|
|
1589
1694
|
const date = toDate(value);
|
|
1590
1695
|
if (!date) return "";
|
|
@@ -1600,7 +1705,7 @@ function DateEditor({
|
|
|
1600
1705
|
}) {
|
|
1601
1706
|
const errorId = editErrorId(rowId, column.id);
|
|
1602
1707
|
return /* @__PURE__ */ jsxs10("div", { children: [
|
|
1603
|
-
/* @__PURE__ */
|
|
1708
|
+
/* @__PURE__ */ jsx18(
|
|
1604
1709
|
Input,
|
|
1605
1710
|
{
|
|
1606
1711
|
type: column.type === "datetime" ? "datetime-local" : "date",
|
|
@@ -1615,12 +1720,12 @@ function DateEditor({
|
|
|
1615
1720
|
onChange: (event) => onChange(event.target.value === "" ? null : parseISO4(event.target.value))
|
|
1616
1721
|
}
|
|
1617
1722
|
),
|
|
1618
|
-
error && /* @__PURE__ */
|
|
1723
|
+
error && /* @__PURE__ */ jsx18(EditFieldError, { id: errorId, message: error })
|
|
1619
1724
|
] });
|
|
1620
1725
|
}
|
|
1621
1726
|
|
|
1622
1727
|
// src/edit/EnumEditor.tsx
|
|
1623
|
-
import { jsx as
|
|
1728
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1624
1729
|
function EnumEditor({
|
|
1625
1730
|
column,
|
|
1626
1731
|
rowId,
|
|
@@ -1641,7 +1746,7 @@ function EnumEditor({
|
|
|
1641
1746
|
open,
|
|
1642
1747
|
onOpenChange,
|
|
1643
1748
|
children: [
|
|
1644
|
-
/* @__PURE__ */
|
|
1749
|
+
/* @__PURE__ */ jsx19(
|
|
1645
1750
|
SelectTrigger,
|
|
1646
1751
|
{
|
|
1647
1752
|
className: "h-8",
|
|
@@ -1650,14 +1755,14 @@ function EnumEditor({
|
|
|
1650
1755
|
"aria-describedby": error ? errorId : void 0,
|
|
1651
1756
|
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1652
1757
|
autoFocus,
|
|
1653
|
-
children: /* @__PURE__ */
|
|
1758
|
+
children: /* @__PURE__ */ jsx19(SelectValue, {})
|
|
1654
1759
|
}
|
|
1655
1760
|
),
|
|
1656
|
-
/* @__PURE__ */
|
|
1761
|
+
/* @__PURE__ */ jsx19(SelectContent, { children: column.options.map((option) => /* @__PURE__ */ jsx19(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
1657
1762
|
]
|
|
1658
1763
|
}
|
|
1659
1764
|
),
|
|
1660
|
-
error && /* @__PURE__ */
|
|
1765
|
+
error && /* @__PURE__ */ jsx19(EditFieldError, { id: errorId, message: error })
|
|
1661
1766
|
] });
|
|
1662
1767
|
}
|
|
1663
1768
|
|
|
@@ -1666,9 +1771,9 @@ import { useLayoutEffect, useRef as useRef5 } from "react";
|
|
|
1666
1771
|
|
|
1667
1772
|
// src/components/ui/textarea.tsx
|
|
1668
1773
|
import { forwardRef as forwardRef6 } from "react";
|
|
1669
|
-
import { jsx as
|
|
1774
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1670
1775
|
var Textarea = forwardRef6(({ className, ...props }, ref) => {
|
|
1671
|
-
return /* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsx20(
|
|
1672
1777
|
"textarea",
|
|
1673
1778
|
{
|
|
1674
1779
|
className: cn(
|
|
@@ -1683,7 +1788,7 @@ var Textarea = forwardRef6(({ className, ...props }, ref) => {
|
|
|
1683
1788
|
Textarea.displayName = "Textarea";
|
|
1684
1789
|
|
|
1685
1790
|
// src/edit/MultilineStringEditor.tsx
|
|
1686
|
-
import { jsx as
|
|
1791
|
+
import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1687
1792
|
function MultilineStringEditor({
|
|
1688
1793
|
column,
|
|
1689
1794
|
rowId,
|
|
@@ -1707,7 +1812,7 @@ function MultilineStringEditor({
|
|
|
1707
1812
|
}
|
|
1708
1813
|
}, [text]);
|
|
1709
1814
|
return /* @__PURE__ */ jsxs12("div", { children: [
|
|
1710
|
-
/* @__PURE__ */
|
|
1815
|
+
/* @__PURE__ */ jsx21(
|
|
1711
1816
|
Textarea,
|
|
1712
1817
|
{
|
|
1713
1818
|
ref: textareaRef,
|
|
@@ -1724,13 +1829,13 @@ function MultilineStringEditor({
|
|
|
1724
1829
|
}
|
|
1725
1830
|
}
|
|
1726
1831
|
),
|
|
1727
|
-
error && /* @__PURE__ */
|
|
1832
|
+
error && /* @__PURE__ */ jsx21(EditFieldError, { id: errorId, message: error })
|
|
1728
1833
|
] });
|
|
1729
1834
|
}
|
|
1730
1835
|
|
|
1731
1836
|
// src/edit/NumberEditor.tsx
|
|
1732
1837
|
import { useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
|
|
1733
|
-
import { jsx as
|
|
1838
|
+
import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1734
1839
|
function textFromValue(value) {
|
|
1735
1840
|
return value === null || value === void 0 ? "" : String(value);
|
|
1736
1841
|
}
|
|
@@ -1751,7 +1856,7 @@ function NumberEditor({
|
|
|
1751
1856
|
setText(textFromValue(value));
|
|
1752
1857
|
}, [value]);
|
|
1753
1858
|
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
1754
|
-
/* @__PURE__ */
|
|
1859
|
+
/* @__PURE__ */ jsx22(
|
|
1755
1860
|
Input,
|
|
1756
1861
|
{
|
|
1757
1862
|
type: "number",
|
|
@@ -1770,12 +1875,12 @@ function NumberEditor({
|
|
|
1770
1875
|
}
|
|
1771
1876
|
}
|
|
1772
1877
|
),
|
|
1773
|
-
error && /* @__PURE__ */
|
|
1878
|
+
error && /* @__PURE__ */ jsx22(EditFieldError, { id: errorId, message: error })
|
|
1774
1879
|
] });
|
|
1775
1880
|
}
|
|
1776
1881
|
|
|
1777
1882
|
// src/edit/StringEditor.tsx
|
|
1778
|
-
import { jsx as
|
|
1883
|
+
import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1779
1884
|
function StringEditor({
|
|
1780
1885
|
column,
|
|
1781
1886
|
rowId,
|
|
@@ -1786,7 +1891,7 @@ function StringEditor({
|
|
|
1786
1891
|
}) {
|
|
1787
1892
|
const errorId = editErrorId(rowId, column.id);
|
|
1788
1893
|
return /* @__PURE__ */ jsxs14("div", { children: [
|
|
1789
|
-
/* @__PURE__ */
|
|
1894
|
+
/* @__PURE__ */ jsx23(
|
|
1790
1895
|
Input,
|
|
1791
1896
|
{
|
|
1792
1897
|
className: "h-8",
|
|
@@ -1799,26 +1904,26 @@ function StringEditor({
|
|
|
1799
1904
|
onChange: (event) => onChange(event.target.value)
|
|
1800
1905
|
}
|
|
1801
1906
|
),
|
|
1802
|
-
error && /* @__PURE__ */
|
|
1907
|
+
error && /* @__PURE__ */ jsx23(EditFieldError, { id: errorId, message: error })
|
|
1803
1908
|
] });
|
|
1804
1909
|
}
|
|
1805
1910
|
|
|
1806
1911
|
// src/edit/registry.tsx
|
|
1807
|
-
import { jsx as
|
|
1912
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1808
1913
|
function renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus) {
|
|
1809
1914
|
switch (column.type) {
|
|
1810
1915
|
case "string":
|
|
1811
|
-
return column.multiline ? /* @__PURE__ */
|
|
1916
|
+
return column.multiline ? /* @__PURE__ */ jsx24(MultilineStringEditor, { column, rowId, value, onChange, error, autoFocus }) : /* @__PURE__ */ jsx24(StringEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1812
1917
|
case "enum":
|
|
1813
|
-
return /* @__PURE__ */
|
|
1918
|
+
return /* @__PURE__ */ jsx24(EnumEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1814
1919
|
case "boolean":
|
|
1815
|
-
return /* @__PURE__ */
|
|
1920
|
+
return /* @__PURE__ */ jsx24(BooleanEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1816
1921
|
case "number":
|
|
1817
1922
|
case "currency":
|
|
1818
|
-
return /* @__PURE__ */
|
|
1923
|
+
return /* @__PURE__ */ jsx24(NumberEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1819
1924
|
case "date":
|
|
1820
1925
|
case "datetime":
|
|
1821
|
-
return /* @__PURE__ */
|
|
1926
|
+
return /* @__PURE__ */ jsx24(DateEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1822
1927
|
}
|
|
1823
1928
|
}
|
|
1824
1929
|
|
|
@@ -1931,7 +2036,7 @@ function useEditingState(editing, getRowId) {
|
|
|
1931
2036
|
}
|
|
1932
2037
|
|
|
1933
2038
|
// src/edit/renderEditableCell.tsx
|
|
1934
|
-
import { jsx as
|
|
2039
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1935
2040
|
function renderEditableCell(column, row, rawValue, ctx) {
|
|
1936
2041
|
const staticContent = (value2) => column.cell ? column.cell(value2, row) : defaultFormat(column, value2);
|
|
1937
2042
|
if (!ctx || !isEditable(column, row)) return staticContent(rawValue);
|
|
@@ -1943,7 +2048,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
|
|
|
1943
2048
|
const autoFocus = ctx.autoFocusTarget?.rowId === rowId && ctx.autoFocusTarget.columnId === column.id;
|
|
1944
2049
|
const onChange = (next) => ctx.onEdit(column, row, next);
|
|
1945
2050
|
const editor = column.renderEditCell ? column.renderEditCell(value, row, onChange, error, autoFocus) : renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus);
|
|
1946
|
-
return /* @__PURE__ */
|
|
2051
|
+
return /* @__PURE__ */ jsx25(
|
|
1947
2052
|
"div",
|
|
1948
2053
|
{
|
|
1949
2054
|
onKeyDown: (event) => {
|
|
@@ -1956,7 +2061,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
|
|
|
1956
2061
|
}
|
|
1957
2062
|
);
|
|
1958
2063
|
}
|
|
1959
|
-
return /* @__PURE__ */
|
|
2064
|
+
return /* @__PURE__ */ jsx25(
|
|
1960
2065
|
"span",
|
|
1961
2066
|
{
|
|
1962
2067
|
role: "button",
|
|
@@ -1979,7 +2084,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
|
|
|
1979
2084
|
}
|
|
1980
2085
|
|
|
1981
2086
|
// src/edit/EditingBar.tsx
|
|
1982
|
-
import { jsx as
|
|
2087
|
+
import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1983
2088
|
function resolveEditLabel(label, changedRowCount, fallback) {
|
|
1984
2089
|
if (label === void 0) return fallback(changedRowCount);
|
|
1985
2090
|
return typeof label === "function" ? label(changedRowCount) : label;
|
|
@@ -2017,7 +2122,7 @@ function EditingBar({
|
|
|
2017
2122
|
] })
|
|
2018
2123
|
] }),
|
|
2019
2124
|
/* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
|
|
2020
|
-
/* @__PURE__ */
|
|
2125
|
+
/* @__PURE__ */ jsx26(
|
|
2021
2126
|
Button,
|
|
2022
2127
|
{
|
|
2023
2128
|
type: "button",
|
|
@@ -2029,7 +2134,7 @@ function EditingBar({
|
|
|
2029
2134
|
children: resolveEditLabel(editing.discardLabel, pendingRowCount, () => "Discard")
|
|
2030
2135
|
}
|
|
2031
2136
|
),
|
|
2032
|
-
/* @__PURE__ */
|
|
2137
|
+
/* @__PURE__ */ jsx26(
|
|
2033
2138
|
Button,
|
|
2034
2139
|
{
|
|
2035
2140
|
type: "button",
|
|
@@ -2131,15 +2236,15 @@ function extendRangeForFillToCellRange(base, target, rowIds, columnIds, rowIndex
|
|
|
2131
2236
|
}
|
|
2132
2237
|
|
|
2133
2238
|
// src/cell-editing/useCellSelection.ts
|
|
2134
|
-
import { useCallback as useCallback2, useMemo as
|
|
2239
|
+
import { useCallback as useCallback2, useMemo as useMemo4, useRef as useRef8, useState as useState8 } from "react";
|
|
2135
2240
|
function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
|
|
2136
2241
|
const [selection, setSelectionState] = useState8(void 0);
|
|
2137
2242
|
const [isDragging, setIsDragging] = useState8(false);
|
|
2138
2243
|
const [dragFocus, setDragFocus] = useState8(void 0);
|
|
2139
2244
|
const draggingRef = useRef8(false);
|
|
2140
2245
|
const dragFocusRef = useRef8(void 0);
|
|
2141
|
-
const rowIndex =
|
|
2142
|
-
const columnIndex =
|
|
2246
|
+
const rowIndex = useMemo4(() => buildIndexMap(rowIds), [rowIds]);
|
|
2247
|
+
const columnIndex = useMemo4(() => buildIndexMap(columnIds), [columnIds]);
|
|
2143
2248
|
const startSelection = useCallback2((cell, options) => {
|
|
2144
2249
|
setSelectionState((prev) => options?.extend && prev ? { anchor: prev.anchor, focus: cell } : { anchor: cell, focus: cell });
|
|
2145
2250
|
draggingRef.current = true;
|
|
@@ -2193,7 +2298,7 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
|
|
|
2193
2298
|
setDragFocus(void 0);
|
|
2194
2299
|
setSelectionState(void 0);
|
|
2195
2300
|
}, []);
|
|
2196
|
-
const effectiveRange =
|
|
2301
|
+
const effectiveRange = useMemo4(() => {
|
|
2197
2302
|
if (!selection) return void 0;
|
|
2198
2303
|
if (isDragging && dragFocus) return { anchor: selection.anchor, focus: dragFocus };
|
|
2199
2304
|
return selection;
|
|
@@ -2229,7 +2334,7 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
|
|
|
2229
2334
|
setSelectionState(finalRange);
|
|
2230
2335
|
return { sourceRange, finalRange };
|
|
2231
2336
|
}, [rowIds, columnIds, rowIndex, columnIndex]);
|
|
2232
|
-
const fillPreviewRange =
|
|
2337
|
+
const fillPreviewRange = useMemo4(() => {
|
|
2233
2338
|
if (!isFillDragging || !selection || !fillTarget) return void 0;
|
|
2234
2339
|
return extendRangeForFillToCellRange(selection, fillTarget, rowIds, columnIds, rowIndex, columnIndex);
|
|
2235
2340
|
}, [isFillDragging, selection, fillTarget, rowIds, columnIds, rowIndex, columnIndex]);
|
|
@@ -2367,7 +2472,7 @@ function useCellEditingState(cellEditing, getRowId) {
|
|
|
2367
2472
|
}
|
|
2368
2473
|
|
|
2369
2474
|
// src/cell-editing/renderCellModeCell.tsx
|
|
2370
|
-
import { jsx as
|
|
2475
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2371
2476
|
function isAtomicEditorType(type) {
|
|
2372
2477
|
return type === "enum" || type === "boolean" || type === "date" || type === "datetime";
|
|
2373
2478
|
}
|
|
@@ -2378,7 +2483,7 @@ function renderCellModeCell(column, row, rawValue, ctx) {
|
|
|
2378
2483
|
const value = ctx.resolveValue(rowId, column.id, rawValue);
|
|
2379
2484
|
const isThisCellEditing = ctx.editingCell?.rowId === rowId && ctx.editingCell.columnId === column.id && isEditable(column, row);
|
|
2380
2485
|
if (!isThisCellEditing) {
|
|
2381
|
-
return /* @__PURE__ */
|
|
2486
|
+
return /* @__PURE__ */ jsx27("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: staticContent(value) });
|
|
2382
2487
|
}
|
|
2383
2488
|
const isAtomic = isAtomicEditorType(column.type);
|
|
2384
2489
|
const error = ctx.getError(rowId, column.id);
|
|
@@ -2418,12 +2523,12 @@ function renderCellModeCell(column, row, rawValue, ctx) {
|
|
|
2418
2523
|
if (validate(currentValue)) ctx.onCancelEdit();
|
|
2419
2524
|
else ctx.onCommitEdit(row, value);
|
|
2420
2525
|
}
|
|
2421
|
-
return /* @__PURE__ */
|
|
2526
|
+
return /* @__PURE__ */ jsx27("div", { onKeyDown: handleKeyDown, onBlur: handleBlur, children: editor });
|
|
2422
2527
|
}
|
|
2423
2528
|
|
|
2424
2529
|
// src/cell-editing/SelectionOverlay.tsx
|
|
2425
2530
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef10, useState as useState10 } from "react";
|
|
2426
|
-
import { Fragment as Fragment2, jsx as
|
|
2531
|
+
import { Fragment as Fragment2, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2427
2532
|
function cellSelector(rowId, columnId) {
|
|
2428
2533
|
const escape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
|
|
2429
2534
|
return `[data-cell-row="${escape(rowId)}"][data-cell-col="${escape(columnId)}"]`;
|
|
@@ -2478,7 +2583,7 @@ function SelectionOverlay({
|
|
|
2478
2583
|
}, [containerRef.current]);
|
|
2479
2584
|
if (!rect) return null;
|
|
2480
2585
|
return /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
2481
|
-
/* @__PURE__ */
|
|
2586
|
+
/* @__PURE__ */ jsx28(
|
|
2482
2587
|
"div",
|
|
2483
2588
|
{
|
|
2484
2589
|
"data-testid": "cell-selection-overlay",
|
|
@@ -2487,7 +2592,7 @@ function SelectionOverlay({
|
|
|
2487
2592
|
style: { top: rect.top, left: rect.left, width: rect.width, height: rect.height }
|
|
2488
2593
|
}
|
|
2489
2594
|
),
|
|
2490
|
-
previewRect && /* @__PURE__ */
|
|
2595
|
+
previewRect && /* @__PURE__ */ jsx28(
|
|
2491
2596
|
"div",
|
|
2492
2597
|
{
|
|
2493
2598
|
"data-testid": "cell-fill-preview-overlay",
|
|
@@ -2496,7 +2601,7 @@ function SelectionOverlay({
|
|
|
2496
2601
|
style: { top: previewRect.top, left: previewRect.left, width: previewRect.width, height: previewRect.height }
|
|
2497
2602
|
}
|
|
2498
2603
|
),
|
|
2499
|
-
onFillHandleMouseDown && /* @__PURE__ */
|
|
2604
|
+
onFillHandleMouseDown && /* @__PURE__ */ jsx28(
|
|
2500
2605
|
"div",
|
|
2501
2606
|
{
|
|
2502
2607
|
"data-testid": "cell-fill-handle",
|
|
@@ -2701,17 +2806,17 @@ function computeFillChanges(sourceRange, finalRange, rowIds, columnIds, columns,
|
|
|
2701
2806
|
}
|
|
2702
2807
|
|
|
2703
2808
|
// src/column-selector/ColumnSelector.tsx
|
|
2704
|
-
import {
|
|
2809
|
+
import { Bars2Icon, ViewColumnsIcon } from "@heroicons/react/24/outline";
|
|
2705
2810
|
import { useEffect as useEffect8, useState as useState11 } from "react";
|
|
2706
2811
|
|
|
2707
2812
|
// src/components/ui/dialog.tsx
|
|
2708
2813
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
2709
|
-
import {
|
|
2814
|
+
import { XMarkIcon } from "@heroicons/react/24/outline";
|
|
2710
2815
|
import { forwardRef as forwardRef7 } from "react";
|
|
2711
|
-
import { jsx as
|
|
2816
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2712
2817
|
var Dialog = DialogPrimitive.Root;
|
|
2713
2818
|
var DialogTrigger = DialogPrimitive.Trigger;
|
|
2714
|
-
var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */
|
|
2819
|
+
var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(
|
|
2715
2820
|
DialogPrimitive.Overlay,
|
|
2716
2821
|
{
|
|
2717
2822
|
ref,
|
|
@@ -2721,7 +2826,7 @@ var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ *
|
|
|
2721
2826
|
));
|
|
2722
2827
|
DialogOverlay.displayName = "DialogOverlay";
|
|
2723
2828
|
var DialogContent = forwardRef7(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs17(DialogPrimitive.Portal, { children: [
|
|
2724
|
-
/* @__PURE__ */
|
|
2829
|
+
/* @__PURE__ */ jsx29(DialogOverlay, {}),
|
|
2725
2830
|
/* @__PURE__ */ jsxs17(
|
|
2726
2831
|
DialogPrimitive.Content,
|
|
2727
2832
|
{
|
|
@@ -2734,8 +2839,8 @@ var DialogContent = forwardRef7(({ className, children, ...props }, ref) => /* @
|
|
|
2734
2839
|
children: [
|
|
2735
2840
|
children,
|
|
2736
2841
|
/* @__PURE__ */ jsxs17(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
|
|
2737
|
-
/* @__PURE__ */
|
|
2738
|
-
/* @__PURE__ */
|
|
2842
|
+
/* @__PURE__ */ jsx29(XMarkIcon, { className: "h-4 w-4" }),
|
|
2843
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Close" })
|
|
2739
2844
|
] })
|
|
2740
2845
|
]
|
|
2741
2846
|
}
|
|
@@ -2745,10 +2850,10 @@ DialogContent.displayName = "DialogContent";
|
|
|
2745
2850
|
var DialogHeader = ({
|
|
2746
2851
|
className,
|
|
2747
2852
|
...props
|
|
2748
|
-
}) => /* @__PURE__ */
|
|
2749
|
-
var DialogTitle = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */
|
|
2853
|
+
}) => /* @__PURE__ */ jsx29("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
2854
|
+
var DialogTitle = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
|
|
2750
2855
|
DialogTitle.displayName = "DialogTitle";
|
|
2751
|
-
var DialogDescription = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */
|
|
2856
|
+
var DialogDescription = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(
|
|
2752
2857
|
DialogPrimitive.Description,
|
|
2753
2858
|
{
|
|
2754
2859
|
ref,
|
|
@@ -2857,7 +2962,7 @@ function canHideGroup(columns, visibility, groupColumnIds) {
|
|
|
2857
2962
|
}
|
|
2858
2963
|
|
|
2859
2964
|
// src/column-selector/ColumnSelector.tsx
|
|
2860
|
-
import { jsx as
|
|
2965
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2861
2966
|
function ColumnSelector({
|
|
2862
2967
|
columns,
|
|
2863
2968
|
visibility,
|
|
@@ -2903,11 +3008,11 @@ function ColumnSelector({
|
|
|
2903
3008
|
if (persistKey) writePersistedColumnOrder(persistKey, next);
|
|
2904
3009
|
}
|
|
2905
3010
|
return /* @__PURE__ */ jsxs18(Dialog, { open, onOpenChange, children: [
|
|
2906
|
-
/* @__PURE__ */
|
|
3011
|
+
/* @__PURE__ */ jsx30(DialogTrigger, { asChild: true, children: trigger ?? /* @__PURE__ */ jsx30(Button, { variant: "outline", size: "icon", "aria-label": "Choose columns", children: /* @__PURE__ */ jsx30(ViewColumnsIcon, { className: "h-4 w-4", "aria-hidden": true }) }) }),
|
|
2907
3012
|
/* @__PURE__ */ jsxs18(DialogContent, { className: "w-fit max-w-[calc(100vw-2rem)] sm:max-w-2xl", children: [
|
|
2908
|
-
/* @__PURE__ */
|
|
2909
|
-
/* @__PURE__ */
|
|
2910
|
-
group && /* @__PURE__ */
|
|
3013
|
+
/* @__PURE__ */ jsx30(DialogHeader, { children: /* @__PURE__ */ jsx30(DialogTitle, { children: "Columns" }) }),
|
|
3014
|
+
/* @__PURE__ */ jsx30("div", { className: "flex flex-wrap gap-x-8 gap-y-5", children: groups.map(({ group, columns: groupCols }) => /* @__PURE__ */ jsxs18("div", { className: "flex min-w-32 flex-col gap-1.5", children: [
|
|
3015
|
+
group && /* @__PURE__ */ jsx30("span", { className: "border-b pb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group }),
|
|
2911
3016
|
groupCols.map((column) => {
|
|
2912
3017
|
const visible = isColumnVisible(visibility, column.id);
|
|
2913
3018
|
return /* @__PURE__ */ jsxs18(
|
|
@@ -2937,14 +3042,14 @@ function ColumnSelector({
|
|
|
2937
3042
|
overId === column.id && draggedId !== null && draggedId !== column.id && "outline -outline-offset-2 outline-2 outline-primary"
|
|
2938
3043
|
),
|
|
2939
3044
|
children: [
|
|
2940
|
-
canReorder && /* @__PURE__ */
|
|
2941
|
-
|
|
3045
|
+
canReorder && /* @__PURE__ */ jsx30(
|
|
3046
|
+
Bars2Icon,
|
|
2942
3047
|
{
|
|
2943
|
-
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/50",
|
|
3048
|
+
className: "h-3.5 w-3.5 shrink-0 rotate-90 text-muted-foreground/50",
|
|
2944
3049
|
"aria-hidden": true
|
|
2945
3050
|
}
|
|
2946
3051
|
),
|
|
2947
|
-
/* @__PURE__ */
|
|
3052
|
+
/* @__PURE__ */ jsx30(
|
|
2948
3053
|
Checkbox,
|
|
2949
3054
|
{
|
|
2950
3055
|
checked: visible,
|
|
@@ -2975,16 +3080,16 @@ function resolveMenuItems(items, ctx) {
|
|
|
2975
3080
|
}
|
|
2976
3081
|
|
|
2977
3082
|
// src/menu/ActionsMenu.tsx
|
|
2978
|
-
import {
|
|
2979
|
-
import { useMemo as
|
|
3083
|
+
import { EllipsisVerticalIcon } from "@heroicons/react/24/outline";
|
|
3084
|
+
import { useMemo as useMemo5 } from "react";
|
|
2980
3085
|
|
|
2981
3086
|
// src/components/ui/dropdown-menu.tsx
|
|
2982
3087
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
2983
3088
|
import { forwardRef as forwardRef8 } from "react";
|
|
2984
|
-
import { jsx as
|
|
3089
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
2985
3090
|
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
2986
3091
|
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
2987
|
-
var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */
|
|
3092
|
+
var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx31(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx31(
|
|
2988
3093
|
DropdownMenuPrimitive.Content,
|
|
2989
3094
|
{
|
|
2990
3095
|
ref,
|
|
@@ -2997,7 +3102,7 @@ var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props },
|
|
|
2997
3102
|
}
|
|
2998
3103
|
) }));
|
|
2999
3104
|
DropdownMenuContent.displayName = "DropdownMenuContent";
|
|
3000
|
-
var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /* @__PURE__ */
|
|
3105
|
+
var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /* @__PURE__ */ jsx31(
|
|
3001
3106
|
DropdownMenuPrimitive.Item,
|
|
3002
3107
|
{
|
|
3003
3108
|
ref,
|
|
@@ -3010,7 +3115,7 @@ var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /*
|
|
|
3010
3115
|
}
|
|
3011
3116
|
));
|
|
3012
3117
|
DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
3013
|
-
var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */
|
|
3118
|
+
var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
|
|
3014
3119
|
DropdownMenuPrimitive.Separator,
|
|
3015
3120
|
{
|
|
3016
3121
|
ref,
|
|
@@ -3019,7 +3124,7 @@ var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__
|
|
|
3019
3124
|
}
|
|
3020
3125
|
));
|
|
3021
3126
|
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
3022
|
-
var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */
|
|
3127
|
+
var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
|
|
3023
3128
|
DropdownMenuPrimitive.Label,
|
|
3024
3129
|
{
|
|
3025
3130
|
ref,
|
|
@@ -3030,16 +3135,16 @@ var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE
|
|
|
3030
3135
|
DropdownMenuLabel.displayName = "DropdownMenuLabel";
|
|
3031
3136
|
|
|
3032
3137
|
// src/menu/ActionsMenu.tsx
|
|
3033
|
-
import { jsx as
|
|
3138
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3034
3139
|
function ActionsMenu({ items, ctx, triggerLabel }) {
|
|
3035
|
-
const resolved =
|
|
3140
|
+
const resolved = useMemo5(
|
|
3036
3141
|
() => resolveMenuItems(items, ctx),
|
|
3037
3142
|
[items, ctx.row, ctx.selectedRows]
|
|
3038
3143
|
);
|
|
3039
3144
|
if (resolved.length === 0) return null;
|
|
3040
3145
|
return /* @__PURE__ */ jsxs19(DropdownMenu, { children: [
|
|
3041
|
-
/* @__PURE__ */
|
|
3042
|
-
/* @__PURE__ */
|
|
3146
|
+
/* @__PURE__ */ jsx32(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(Button, { variant: "ghost", size: "icon", "aria-label": triggerLabel, onClick: stopRowClick, children: /* @__PURE__ */ jsx32(EllipsisVerticalIcon, { className: "h-4 w-4", "aria-hidden": true }) }) }),
|
|
3147
|
+
/* @__PURE__ */ jsx32(DropdownMenuContent, { align: "end", children: resolved.map((item) => /* @__PURE__ */ jsx32(
|
|
3043
3148
|
DropdownMenuItem,
|
|
3044
3149
|
{
|
|
3045
3150
|
danger: item.danger,
|
|
@@ -3053,18 +3158,123 @@ function ActionsMenu({ items, ctx, triggerLabel }) {
|
|
|
3053
3158
|
}
|
|
3054
3159
|
|
|
3055
3160
|
// src/grid/DataGrid.tsx
|
|
3056
|
-
import {
|
|
3161
|
+
import {
|
|
3162
|
+
BarsArrowDownIcon,
|
|
3163
|
+
BarsArrowUpIcon,
|
|
3164
|
+
ChevronRightIcon as ChevronRightIcon2,
|
|
3165
|
+
FunnelIcon as FunnelIcon7
|
|
3166
|
+
} from "@heroicons/react/24/outline";
|
|
3057
3167
|
import { columnResizingFeature, columnSizingFeature, flexRender, tableFeatures, useTable } from "@tanstack/react-table";
|
|
3058
3168
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
3059
|
-
|
|
3060
|
-
|
|
3169
|
+
|
|
3170
|
+
// src/components/status.tsx
|
|
3171
|
+
import { ArrowPathIcon, ExclamationTriangleIcon as ExclamationTriangleIcon2 } from "@heroicons/react/24/outline";
|
|
3172
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3173
|
+
function toErrorInfo(error) {
|
|
3174
|
+
if (error == null || error === false || error === "") return void 0;
|
|
3175
|
+
if (typeof error === "string") return { message: error };
|
|
3176
|
+
if (error instanceof Error) return { message: error.message || void 0, details: error.stack };
|
|
3177
|
+
if (typeof error === "object") {
|
|
3178
|
+
const { title, message, details } = error;
|
|
3179
|
+
if (title !== void 0 || message !== void 0 || details !== void 0) return { title, message, details };
|
|
3180
|
+
}
|
|
3181
|
+
try {
|
|
3182
|
+
return { message: typeof error === "object" ? "Unknown error" : String(error) };
|
|
3183
|
+
} catch {
|
|
3184
|
+
return { message: "Unknown error" };
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
var defaultGridStatusLabels = {
|
|
3188
|
+
loading: "Loading...",
|
|
3189
|
+
noResults: "No results.",
|
|
3190
|
+
errorTitle: "Couldn't load data",
|
|
3191
|
+
retry: "Retry",
|
|
3192
|
+
showDetails: "Show details",
|
|
3193
|
+
nodeLoadFailed: "Failed to load."
|
|
3194
|
+
};
|
|
3195
|
+
function resolveStatusLabels(overrides) {
|
|
3196
|
+
return overrides ? { ...defaultGridStatusLabels, ...overrides } : defaultGridStatusLabels;
|
|
3197
|
+
}
|
|
3198
|
+
function LoadingRows({ label, rows = 4 }) {
|
|
3199
|
+
return /* @__PURE__ */ jsxs20("div", { role: "status", "aria-busy": "true", "data-testid": "grid-loading-rows", className: "flex flex-col gap-2 p-1", children: [
|
|
3200
|
+
/* @__PURE__ */ jsx33("span", { className: "sr-only", children: label }),
|
|
3201
|
+
Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx33("div", { className: "h-4 animate-pulse rounded-md bg-muted", style: { width: i === rows - 1 ? "60%" : "100%" } }, i))
|
|
3202
|
+
] });
|
|
3203
|
+
}
|
|
3204
|
+
function RefreshBar(props) {
|
|
3205
|
+
return /* @__PURE__ */ jsx33(
|
|
3206
|
+
"div",
|
|
3207
|
+
{
|
|
3208
|
+
role: "progressbar",
|
|
3209
|
+
"aria-label": "Refreshing",
|
|
3210
|
+
className: "pointer-events-none absolute inset-x-0 top-0 z-30 h-0.5 overflow-hidden bg-muted",
|
|
3211
|
+
...props,
|
|
3212
|
+
children: /* @__PURE__ */ jsx33("div", { className: "h-full w-1/3 animate-pulse bg-primary motion-reduce:animate-none" })
|
|
3213
|
+
}
|
|
3214
|
+
);
|
|
3215
|
+
}
|
|
3216
|
+
function GridErrorState({
|
|
3217
|
+
error,
|
|
3218
|
+
onRetry,
|
|
3219
|
+
labels
|
|
3220
|
+
}) {
|
|
3221
|
+
const info = toErrorInfo(error);
|
|
3222
|
+
if (!info) return null;
|
|
3223
|
+
return /* @__PURE__ */ jsxs20(
|
|
3224
|
+
"div",
|
|
3225
|
+
{
|
|
3226
|
+
role: "alert",
|
|
3227
|
+
"data-testid": "grid-error-state",
|
|
3228
|
+
className: "flex min-h-24 w-full flex-col items-center justify-center gap-1 p-4 text-center text-sm",
|
|
3229
|
+
children: [
|
|
3230
|
+
/* @__PURE__ */ jsx33(ExclamationTriangleIcon2, { className: "h-8 w-8 text-destructive", "aria-hidden": "true" }),
|
|
3231
|
+
/* @__PURE__ */ jsx33("p", { className: "font-semibold", children: info.title ?? labels.errorTitle }),
|
|
3232
|
+
info.message ? /* @__PURE__ */ jsx33("p", { className: "text-muted-foreground", children: info.message }) : null,
|
|
3233
|
+
info.details ? /* @__PURE__ */ jsxs20("details", { className: "w-full max-w-lg text-left text-xs", children: [
|
|
3234
|
+
/* @__PURE__ */ jsx33("summary", { className: "cursor-pointer select-none underline underline-offset-2", children: labels.showDetails }),
|
|
3235
|
+
/* @__PURE__ */ jsx33("pre", { className: "mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-words rounded bg-muted p-2 text-muted-foreground", children: info.details })
|
|
3236
|
+
] }) : null,
|
|
3237
|
+
onRetry ? /* @__PURE__ */ jsxs20(Button, { type: "button", variant: "outline", size: "sm", className: "mt-2", onClick: onRetry, children: [
|
|
3238
|
+
/* @__PURE__ */ jsx33(ArrowPathIcon, { className: "h-4 w-4", "aria-hidden": "true" }),
|
|
3239
|
+
labels.retry
|
|
3240
|
+
] }) : null
|
|
3241
|
+
]
|
|
3242
|
+
}
|
|
3243
|
+
);
|
|
3244
|
+
}
|
|
3245
|
+
function GridInlineError({
|
|
3246
|
+
error,
|
|
3247
|
+
onRetry,
|
|
3248
|
+
labels,
|
|
3249
|
+
className
|
|
3250
|
+
}) {
|
|
3251
|
+
const info = toErrorInfo(error);
|
|
3252
|
+
if (!info) return null;
|
|
3253
|
+
return /* @__PURE__ */ jsxs20(
|
|
3254
|
+
"span",
|
|
3255
|
+
{
|
|
3256
|
+
role: "alert",
|
|
3257
|
+
"data-testid": "grid-inline-error",
|
|
3258
|
+
title: info.details,
|
|
3259
|
+
className: cn("inline-flex min-w-0 items-center gap-1.5 text-xs text-red-700 dark:text-red-300", className),
|
|
3260
|
+
children: [
|
|
3261
|
+
/* @__PURE__ */ jsx33(ExclamationTriangleIcon2, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }),
|
|
3262
|
+
/* @__PURE__ */ jsx33("span", { className: "truncate", children: info.message ?? info.title ?? labels.errorTitle }),
|
|
3263
|
+
onRetry ? /* @__PURE__ */ jsx33("button", { type: "button", className: "shrink-0 underline underline-offset-2", onClick: onRetry, children: labels.retry }) : null
|
|
3264
|
+
]
|
|
3265
|
+
}
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
// src/grid/DataGrid.tsx
|
|
3270
|
+
import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef13, useState as useState16 } from "react";
|
|
3061
3271
|
|
|
3062
3272
|
// src/cell-editing/renderAlwaysEditCell.tsx
|
|
3063
3273
|
import {
|
|
3064
3274
|
useEffect as useEffect9,
|
|
3065
3275
|
useState as useState12
|
|
3066
3276
|
} from "react";
|
|
3067
|
-
import { jsx as
|
|
3277
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
3068
3278
|
function AlwaysEditCell(props) {
|
|
3069
3279
|
const { column, row, rawValue, ctx, atomicGesture } = props;
|
|
3070
3280
|
const rowId = ctx.getRowId(row);
|
|
@@ -3077,7 +3287,7 @@ function AlwaysEditCell(props) {
|
|
|
3077
3287
|
if (shouldOpenEnumNow) setEnumOpen(true);
|
|
3078
3288
|
}, [shouldOpenEnumNow]);
|
|
3079
3289
|
if (!isEditable(column, row)) {
|
|
3080
|
-
return /* @__PURE__ */
|
|
3290
|
+
return /* @__PURE__ */ jsx34("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: column.cell ? column.cell(resolvedValue, row) : defaultFormat(column, resolvedValue) });
|
|
3081
3291
|
}
|
|
3082
3292
|
const isAtomic = isAtomicEditorType(column.type);
|
|
3083
3293
|
const error = ctx.getError(rowId, column.id);
|
|
@@ -3144,7 +3354,7 @@ function AlwaysEditCell(props) {
|
|
|
3144
3354
|
handleModifierCapture(event);
|
|
3145
3355
|
handleEnumOpenCapture(event);
|
|
3146
3356
|
}
|
|
3147
|
-
return /* @__PURE__ */
|
|
3357
|
+
return /* @__PURE__ */ jsx34(
|
|
3148
3358
|
"fieldset",
|
|
3149
3359
|
{
|
|
3150
3360
|
disabled: ctx.disabled,
|
|
@@ -3153,7 +3363,7 @@ function AlwaysEditCell(props) {
|
|
|
3153
3363
|
onPointerDownCapture: handlePointerDownCapture,
|
|
3154
3364
|
onClickCapture: handleClickCapture,
|
|
3155
3365
|
className: "contents",
|
|
3156
|
-
children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */
|
|
3366
|
+
children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */ jsx34(
|
|
3157
3367
|
EnumEditor,
|
|
3158
3368
|
{
|
|
3159
3369
|
column,
|
|
@@ -3214,9 +3424,9 @@ function useStickyGroupHeaderTop(enabled) {
|
|
|
3214
3424
|
}
|
|
3215
3425
|
|
|
3216
3426
|
// src/hooks/useVisibleColumns.ts
|
|
3217
|
-
import { useMemo as
|
|
3427
|
+
import { useMemo as useMemo6 } from "react";
|
|
3218
3428
|
function useVisibleColumns(columns, columnVisibility) {
|
|
3219
|
-
return
|
|
3429
|
+
return useMemo6(
|
|
3220
3430
|
() => columnVisibility ? columns.filter((column) => isColumnVisible(columnVisibility, column.id)) : columns,
|
|
3221
3431
|
[columns, columnVisibility]
|
|
3222
3432
|
);
|
|
@@ -3263,10 +3473,10 @@ function processClientData(data, state) {
|
|
|
3263
3473
|
}
|
|
3264
3474
|
|
|
3265
3475
|
// src/grid/useGridState.ts
|
|
3266
|
-
import { useCallback as useCallback4, useEffect as useEffect11, useMemo as
|
|
3476
|
+
import { useCallback as useCallback4, useEffect as useEffect11, useMemo as useMemo8, useState as useState15 } from "react";
|
|
3267
3477
|
|
|
3268
3478
|
// src/hooks/useDebouncedCallback.ts
|
|
3269
|
-
import { useEffect as useEffect10, useMemo as
|
|
3479
|
+
import { useEffect as useEffect10, useMemo as useMemo7, useRef as useRef12 } from "react";
|
|
3270
3480
|
function useDebouncedCallback(callback, delayMs) {
|
|
3271
3481
|
const callbackRef = useRef12(callback);
|
|
3272
3482
|
callbackRef.current = callback;
|
|
@@ -3276,7 +3486,7 @@ function useDebouncedCallback(callback, delayMs) {
|
|
|
3276
3486
|
clearTimeout(timeoutRef.current);
|
|
3277
3487
|
};
|
|
3278
3488
|
}, []);
|
|
3279
|
-
return
|
|
3489
|
+
return useMemo7(() => {
|
|
3280
3490
|
return {
|
|
3281
3491
|
run: (...args) => {
|
|
3282
3492
|
clearTimeout(timeoutRef.current);
|
|
@@ -3329,7 +3539,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
|
|
|
3329
3539
|
cancelDebouncedNotify();
|
|
3330
3540
|
setState(externalState);
|
|
3331
3541
|
}, [externalState, cancelDebouncedNotify]);
|
|
3332
|
-
const filtersByColumn =
|
|
3542
|
+
const filtersByColumn = useMemo8(() => {
|
|
3333
3543
|
const map = /* @__PURE__ */ new Map();
|
|
3334
3544
|
for (const child of state.filter?.filters ?? []) {
|
|
3335
3545
|
if ("operator" in child) map.set(fieldKey(child.field), child);
|
|
@@ -3393,7 +3603,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
|
|
|
3393
3603
|
}
|
|
3394
3604
|
|
|
3395
3605
|
// src/grid/DataGrid.tsx
|
|
3396
|
-
import { Fragment as Fragment4, jsx as
|
|
3606
|
+
import { Fragment as Fragment4, jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3397
3607
|
var gridTableFeatures = tableFeatures({ columnSizingFeature, columnResizingFeature });
|
|
3398
3608
|
var DEFAULT_COLUMN_SIZE = 150;
|
|
3399
3609
|
var MIN_COLUMN_SIZE = 40;
|
|
@@ -3444,7 +3654,7 @@ function toTanstackColumns(columns, editingCtxRef, cellEditingCtxRef, atomicGest
|
|
|
3444
3654
|
cell: (info) => {
|
|
3445
3655
|
const cellEditingCtx = cellEditingCtxRef.current;
|
|
3446
3656
|
if (!cellEditingCtx) return renderEditableCell(column, info.row.original, info.getValue(), editingCtxRef.current);
|
|
3447
|
-
return cellEditingCtx.alwaysEdit ? /* @__PURE__ */
|
|
3657
|
+
return cellEditingCtx.alwaysEdit ? /* @__PURE__ */ jsx35(
|
|
3448
3658
|
AlwaysEditCell,
|
|
3449
3659
|
{
|
|
3450
3660
|
column,
|
|
@@ -3481,6 +3691,9 @@ function DataGrid({
|
|
|
3481
3691
|
onSelectedIdsChange,
|
|
3482
3692
|
testId,
|
|
3483
3693
|
loading: loadingProp = false,
|
|
3694
|
+
error,
|
|
3695
|
+
onRetry,
|
|
3696
|
+
statusLabels,
|
|
3484
3697
|
groupBy,
|
|
3485
3698
|
renderGroupHeader,
|
|
3486
3699
|
defaultGroupsExpanded = true,
|
|
@@ -3489,8 +3702,10 @@ function DataGrid({
|
|
|
3489
3702
|
zebra = true,
|
|
3490
3703
|
showTotals = false,
|
|
3491
3704
|
editing,
|
|
3492
|
-
cellEditing
|
|
3705
|
+
cellEditing,
|
|
3706
|
+
filterLabels
|
|
3493
3707
|
}) {
|
|
3708
|
+
const resolvedFilterLabels = useFilterLabels(filterLabels);
|
|
3494
3709
|
const hasCellEditing = Boolean(cellEditing) && !groupBy;
|
|
3495
3710
|
const { state, filtersByColumn, setColumnFilter, toggleSort, setPage } = useGridState(
|
|
3496
3711
|
dataSource,
|
|
@@ -3536,11 +3751,11 @@ function DataGrid({
|
|
|
3536
3751
|
const atomicGestureRef = useRef13(void 0);
|
|
3537
3752
|
const visibleColumns = useVisibleColumns(columns, columnVisibility);
|
|
3538
3753
|
const serverRowCount = dataSource.mode === "server" ? dataSource.rowCount : void 0;
|
|
3539
|
-
const { rows, rowCount } =
|
|
3754
|
+
const { rows, rowCount } = useMemo9(() => {
|
|
3540
3755
|
if (dataSource.mode === "client") return processClientData(dataSource.data, state);
|
|
3541
3756
|
return { rows: dataSource.data, rowCount: serverRowCount ?? 0 };
|
|
3542
3757
|
}, [dataSource.mode, dataSource.data, serverRowCount, state]);
|
|
3543
|
-
const selectedRows =
|
|
3758
|
+
const selectedRows = useMemo9(
|
|
3544
3759
|
() => rows.filter((row) => selectedIds.has(getRowId(row))),
|
|
3545
3760
|
[rows, selectedIds, getRowId]
|
|
3546
3761
|
);
|
|
@@ -3559,11 +3774,11 @@ function DataGrid({
|
|
|
3559
3774
|
}
|
|
3560
3775
|
updateSelectedIds(next);
|
|
3561
3776
|
}
|
|
3562
|
-
const tanstackColumns =
|
|
3777
|
+
const tanstackColumns = useMemo9(
|
|
3563
3778
|
() => toTanstackColumns(visibleColumns, editingCtxRef, cellEditingCtxRef, atomicGestureRef),
|
|
3564
3779
|
[visibleColumns]
|
|
3565
3780
|
);
|
|
3566
|
-
const columnById =
|
|
3781
|
+
const columnById = useMemo9(() => {
|
|
3567
3782
|
const map = /* @__PURE__ */ new Map();
|
|
3568
3783
|
for (const column of visibleColumns) map.set(column.id, column);
|
|
3569
3784
|
return map;
|
|
@@ -3585,13 +3800,15 @@ function DataGrid({
|
|
|
3585
3800
|
return table.getRowModel().rowsById[rowId]?.original;
|
|
3586
3801
|
}
|
|
3587
3802
|
const pageCount = Math.max(1, Math.ceil(rowCount / state.pageSize));
|
|
3803
|
+
const labels = resolveStatusLabels(statusLabels);
|
|
3804
|
+
const hasError = toErrorInfo(error) !== void 0;
|
|
3588
3805
|
const loading = loadingProp || (dataSource.mode === "server" ? Boolean(dataSource.loading) : false);
|
|
3589
3806
|
const showSelectionColumn = Boolean(headerActions?.length) || controlledSelectedIds !== void 0;
|
|
3590
3807
|
const showRowActionsColumn = Boolean(rowActions?.length);
|
|
3591
3808
|
const showDetailColumn = Boolean(renderDetail);
|
|
3592
3809
|
const totalColumnCount = visibleColumns.length + (showDetailColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0) + (showRowActionsColumn ? 1 : 0);
|
|
3593
3810
|
const hasFilterRow = visibleColumns.some((column) => isFilterable(column) && column.filterDisplay === "row");
|
|
3594
|
-
const headerRuns =
|
|
3811
|
+
const headerRuns = useMemo9(() => computeHeaderRuns(visibleColumns), [visibleColumns]);
|
|
3595
3812
|
const hasHeaderGroups = visibleColumns.some((column) => column.headerGroup);
|
|
3596
3813
|
const hasColumnSummary = visibleColumns.some((column) => column.summary);
|
|
3597
3814
|
function renderFilterWidget(column) {
|
|
@@ -3602,11 +3819,11 @@ function DataGrid({
|
|
|
3602
3819
|
const columnSize = (columnId) => table.getColumn(columnId)?.getSize() ?? DEFAULT_COLUMN_SIZE;
|
|
3603
3820
|
const leadingStructuralWidth = (showDetailColumn ? DETAIL_COLUMN_WIDTH : 0) + (showSelectionColumn ? SELECTION_COLUMN_WIDTH : 0);
|
|
3604
3821
|
const trailingStructuralWidth = showRowActionsColumn ? ROW_ACTIONS_COLUMN_WIDTH : 0;
|
|
3605
|
-
const leftPinnedOffsets =
|
|
3822
|
+
const leftPinnedOffsets = useMemo9(
|
|
3606
3823
|
() => pinnedOffsets(visibleColumns, "left", columnSize, leadingStructuralWidth),
|
|
3607
3824
|
[visibleColumns, columnSizing, leadingStructuralWidth]
|
|
3608
3825
|
);
|
|
3609
|
-
const rightPinnedOffsets =
|
|
3826
|
+
const rightPinnedOffsets = useMemo9(
|
|
3610
3827
|
() => pinnedOffsets(visibleColumns, "right", columnSize, trailingStructuralWidth),
|
|
3611
3828
|
[visibleColumns, columnSizing, trailingStructuralWidth]
|
|
3612
3829
|
);
|
|
@@ -3656,7 +3873,7 @@ function DataGrid({
|
|
|
3656
3873
|
style: pinnedProps?.style
|
|
3657
3874
|
};
|
|
3658
3875
|
}
|
|
3659
|
-
const bodyCellPropsByColumn =
|
|
3876
|
+
const bodyCellPropsByColumn = useMemo9(() => {
|
|
3660
3877
|
const map = /* @__PURE__ */ new Map();
|
|
3661
3878
|
for (const column of visibleColumns) map.set(column.id, bodyCellClassAndStyle(column));
|
|
3662
3879
|
return map;
|
|
@@ -3672,7 +3889,7 @@ function DataGrid({
|
|
|
3672
3889
|
);
|
|
3673
3890
|
return { className, style: pinnedProps.style };
|
|
3674
3891
|
}
|
|
3675
|
-
const leafHeaderCellPropsByColumn =
|
|
3892
|
+
const leafHeaderCellPropsByColumn = useMemo9(() => {
|
|
3676
3893
|
const map = /* @__PURE__ */ new Map();
|
|
3677
3894
|
for (const column of visibleColumns) {
|
|
3678
3895
|
map.set(
|
|
@@ -3682,7 +3899,7 @@ function DataGrid({
|
|
|
3682
3899
|
}
|
|
3683
3900
|
return map;
|
|
3684
3901
|
}, [visibleColumns, enableColumnResizing, leftPinnedOffsets, rightPinnedOffsets, columnSizing]);
|
|
3685
|
-
const filterHeaderCellPropsByColumn =
|
|
3902
|
+
const filterHeaderCellPropsByColumn = useMemo9(() => {
|
|
3686
3903
|
const map = /* @__PURE__ */ new Map();
|
|
3687
3904
|
for (const column of visibleColumns) {
|
|
3688
3905
|
map.set(column.id, headerCellClassAndStyle(column, "border-b border-border p-2 align-top font-normal"));
|
|
@@ -3702,13 +3919,13 @@ function DataGrid({
|
|
|
3702
3919
|
`[DataGrid] showPagination={false} but only ${tableRows.length} of ${rowCount} row(s) are rendered, with no pagination UI to reach the rest. Pass an explicit pageSize (via initialState or gridState) that covers every row you want visible, or a dataSource that returns all of them.`
|
|
3703
3920
|
);
|
|
3704
3921
|
}, [showPagination, gridState, initialState?.pageSize, tableRows.length, rowCount]);
|
|
3705
|
-
const groupedBuckets =
|
|
3922
|
+
const groupedBuckets = useMemo9(
|
|
3706
3923
|
() => groupBy ? groupRows(tableRows, (row) => groupBy(row.original)) : void 0,
|
|
3707
3924
|
[tableRows, groupBy]
|
|
3708
3925
|
);
|
|
3709
3926
|
const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
|
|
3710
3927
|
const shouldVirtualize = Boolean(virtualize) && tableRows.length > (virtualize?.threshold ?? 100);
|
|
3711
|
-
const flatItems =
|
|
3928
|
+
const flatItems = useMemo9(() => {
|
|
3712
3929
|
if (!shouldVirtualize) return [];
|
|
3713
3930
|
if (!groupedBuckets) return tableRows.map((row) => ({ kind: "row", row }));
|
|
3714
3931
|
const items = [];
|
|
@@ -3745,15 +3962,15 @@ function DataGrid({
|
|
|
3745
3962
|
notifiedForLengthRef.current = tableRows.length;
|
|
3746
3963
|
virtualize.onEndReached();
|
|
3747
3964
|
}, [lastVisibleIndex, flatItems.length, tableRows.length, virtualize]);
|
|
3748
|
-
const cellEditingRowIds =
|
|
3965
|
+
const cellEditingRowIds = useMemo9(
|
|
3749
3966
|
() => hasCellEditing ? tableRows.map((row) => row.id) : EMPTY_ID_ARRAY,
|
|
3750
3967
|
[hasCellEditing, tableRows]
|
|
3751
3968
|
);
|
|
3752
|
-
const cellEditingColumnIds =
|
|
3969
|
+
const cellEditingColumnIds = useMemo9(
|
|
3753
3970
|
() => hasCellEditing ? visibleColumns.map((column) => column.id) : EMPTY_ID_ARRAY,
|
|
3754
3971
|
[hasCellEditing, visibleColumns]
|
|
3755
3972
|
);
|
|
3756
|
-
const cellEditingRowIndex =
|
|
3973
|
+
const cellEditingRowIndex = useMemo9(() => buildIndexMap(cellEditingRowIds), [cellEditingRowIds]);
|
|
3757
3974
|
const cellSelection = useCellSelection({
|
|
3758
3975
|
rowIds: cellEditingRowIds,
|
|
3759
3976
|
columnIds: cellEditingColumnIds,
|
|
@@ -3992,20 +4209,20 @@ function DataGrid({
|
|
|
3992
4209
|
const rowProps = getRowProps?.(row.original);
|
|
3993
4210
|
const rowTestId = getRowTestId?.(row.original) ?? `row-${row.id}`;
|
|
3994
4211
|
const isOddRow = zebra && row.index % 2 === 1;
|
|
3995
|
-
return /* @__PURE__ */
|
|
3996
|
-
/* @__PURE__ */
|
|
4212
|
+
return /* @__PURE__ */ jsxs21("tbody", { ref: measureRef, "data-index": dataIndex, children: [
|
|
4213
|
+
/* @__PURE__ */ jsxs21(
|
|
3997
4214
|
"tr",
|
|
3998
4215
|
{
|
|
3999
4216
|
...rowProps,
|
|
4000
4217
|
"data-testid": rowTestId,
|
|
4001
4218
|
className: rowProps?.className ? cn("divide-x divide-border", rowProps.className, isOddRow && "bg-foreground/5") : `divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
4002
4219
|
children: [
|
|
4003
|
-
showDetailColumn && /* @__PURE__ */
|
|
4220
|
+
showDetailColumn && /* @__PURE__ */ jsx35(
|
|
4004
4221
|
"td",
|
|
4005
4222
|
{
|
|
4006
4223
|
className: isOddRow ? detailCellProps.classNameOdd : detailCellProps.className,
|
|
4007
4224
|
style: detailCellProps.style,
|
|
4008
|
-
children: /* @__PURE__ */
|
|
4225
|
+
children: /* @__PURE__ */ jsx35(
|
|
4009
4226
|
Button,
|
|
4010
4227
|
{
|
|
4011
4228
|
type: "button",
|
|
@@ -4017,8 +4234,8 @@ function DataGrid({
|
|
|
4017
4234
|
stopRowClick(event);
|
|
4018
4235
|
toggleRowExpanded(row.id);
|
|
4019
4236
|
},
|
|
4020
|
-
children: /* @__PURE__ */
|
|
4021
|
-
|
|
4237
|
+
children: /* @__PURE__ */ jsx35(
|
|
4238
|
+
ChevronRightIcon2,
|
|
4022
4239
|
{
|
|
4023
4240
|
className: `h-4 w-4 transition-transform${isExpanded ? " rotate-90" : ""}`,
|
|
4024
4241
|
"aria-hidden": true
|
|
@@ -4028,12 +4245,12 @@ function DataGrid({
|
|
|
4028
4245
|
)
|
|
4029
4246
|
}
|
|
4030
4247
|
),
|
|
4031
|
-
showSelectionColumn && /* @__PURE__ */
|
|
4248
|
+
showSelectionColumn && /* @__PURE__ */ jsx35(
|
|
4032
4249
|
"td",
|
|
4033
4250
|
{
|
|
4034
4251
|
className: isOddRow ? selectionCellProps.classNameOdd : selectionCellProps.className,
|
|
4035
4252
|
style: selectionCellProps.style,
|
|
4036
|
-
children: /* @__PURE__ */
|
|
4253
|
+
children: /* @__PURE__ */ jsx35(
|
|
4037
4254
|
"input",
|
|
4038
4255
|
{
|
|
4039
4256
|
type: "checkbox",
|
|
@@ -4047,7 +4264,7 @@ function DataGrid({
|
|
|
4047
4264
|
),
|
|
4048
4265
|
row.getAllCells().map((cell) => {
|
|
4049
4266
|
const cellProps = bodyCellPropsByColumn.get(cell.column.id);
|
|
4050
|
-
return /* @__PURE__ */
|
|
4267
|
+
return /* @__PURE__ */ jsx35(
|
|
4051
4268
|
"td",
|
|
4052
4269
|
{
|
|
4053
4270
|
style: cellProps?.style,
|
|
@@ -4059,24 +4276,24 @@ function DataGrid({
|
|
|
4059
4276
|
cell.id
|
|
4060
4277
|
);
|
|
4061
4278
|
}),
|
|
4062
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
4279
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx35(
|
|
4063
4280
|
"td",
|
|
4064
4281
|
{
|
|
4065
4282
|
className: isOddRow ? rowActionsCellProps.classNameOdd : rowActionsCellProps.className,
|
|
4066
4283
|
style: rowActionsCellProps.style,
|
|
4067
|
-
children: /* @__PURE__ */
|
|
4284
|
+
children: /* @__PURE__ */ jsx35(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
|
|
4068
4285
|
}
|
|
4069
4286
|
)
|
|
4070
4287
|
]
|
|
4071
4288
|
}
|
|
4072
4289
|
),
|
|
4073
|
-
showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */
|
|
4290
|
+
showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx35("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
|
|
4074
4291
|
] }, row.id);
|
|
4075
4292
|
}
|
|
4076
4293
|
function renderGroupSummaryCells(rows2, bgClassName) {
|
|
4077
4294
|
return visibleColumns.map((column) => {
|
|
4078
4295
|
const cellProps = bodyCellPropsByColumn.get(column.id);
|
|
4079
|
-
return /* @__PURE__ */
|
|
4296
|
+
return /* @__PURE__ */ jsx35(
|
|
4080
4297
|
"td",
|
|
4081
4298
|
{
|
|
4082
4299
|
className: cn(cellProps?.className, bgClassName, "font-medium", alignClassName(column)),
|
|
@@ -4094,10 +4311,10 @@ function DataGrid({
|
|
|
4094
4311
|
const leadingSpan = summaryLeadingCellSpan();
|
|
4095
4312
|
const bgClassName = zebra ? "bg-muted" : "bg-background";
|
|
4096
4313
|
const fillerClass = cn("border-b border-border p-2", bgClassName);
|
|
4097
|
-
return /* @__PURE__ */
|
|
4098
|
-
leadingSpan > 0 && /* @__PURE__ */
|
|
4314
|
+
return /* @__PURE__ */ jsxs21("tr", { "data-testid": "group-summary-row", className: "divide-x divide-border", children: [
|
|
4315
|
+
leadingSpan > 0 && /* @__PURE__ */ jsx35("td", { colSpan: leadingSpan, className: fillerClass }),
|
|
4099
4316
|
renderGroupSummaryCells(rows2, bgClassName),
|
|
4100
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
4317
|
+
showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: fillerClass, "aria-hidden": true })
|
|
4101
4318
|
] });
|
|
4102
4319
|
}
|
|
4103
4320
|
function renderTotalsFooter() {
|
|
@@ -4105,11 +4322,11 @@ function DataGrid({
|
|
|
4105
4322
|
const summaryRows = tableRows.map((row) => row.original);
|
|
4106
4323
|
const leadingSpan = summaryLeadingCellSpan();
|
|
4107
4324
|
const fillerClass = "sticky bottom-0 z-20 border-t border-border bg-muted p-2";
|
|
4108
|
-
return /* @__PURE__ */
|
|
4109
|
-
leadingSpan > 0 && /* @__PURE__ */
|
|
4325
|
+
return /* @__PURE__ */ jsx35("tfoot", { children: /* @__PURE__ */ jsxs21("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
|
|
4326
|
+
leadingSpan > 0 && /* @__PURE__ */ jsx35("td", { colSpan: leadingSpan, className: fillerClass }),
|
|
4110
4327
|
visibleColumns.map((column) => {
|
|
4111
4328
|
const pinnedProps = pinnedCellProps(column, "header");
|
|
4112
|
-
return /* @__PURE__ */
|
|
4329
|
+
return /* @__PURE__ */ jsx35(
|
|
4113
4330
|
"td",
|
|
4114
4331
|
{
|
|
4115
4332
|
className: cn(
|
|
@@ -4124,19 +4341,19 @@ function DataGrid({
|
|
|
4124
4341
|
column.id
|
|
4125
4342
|
);
|
|
4126
4343
|
}),
|
|
4127
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
4344
|
+
showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: fillerClass, "aria-hidden": true })
|
|
4128
4345
|
] }) });
|
|
4129
4346
|
}
|
|
4130
4347
|
function renderGroupHeaderTbody(key, rows2, measureRef, dataIndex) {
|
|
4131
4348
|
const expanded = isGroupExpanded(key);
|
|
4132
|
-
return /* @__PURE__ */
|
|
4133
|
-
/* @__PURE__ */
|
|
4349
|
+
return /* @__PURE__ */ jsxs21("tbody", { ref: measureRef, "data-index": dataIndex, children: [
|
|
4350
|
+
/* @__PURE__ */ jsx35("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx35(
|
|
4134
4351
|
"td",
|
|
4135
4352
|
{
|
|
4136
4353
|
colSpan: totalColumnCount,
|
|
4137
4354
|
className: cn("sticky z-20 border-b p-2 font-medium", zebra ? "bg-muted" : "bg-background"),
|
|
4138
4355
|
style: { top: groupHeaderTop },
|
|
4139
|
-
children: /* @__PURE__ */
|
|
4356
|
+
children: /* @__PURE__ */ jsxs21(
|
|
4140
4357
|
"button",
|
|
4141
4358
|
{
|
|
4142
4359
|
type: "button",
|
|
@@ -4144,8 +4361,8 @@ function DataGrid({
|
|
|
4144
4361
|
onClick: () => toggleGroupExpanded(key),
|
|
4145
4362
|
"aria-expanded": expanded,
|
|
4146
4363
|
children: [
|
|
4147
|
-
/* @__PURE__ */
|
|
4148
|
-
|
|
4364
|
+
/* @__PURE__ */ jsx35(
|
|
4365
|
+
ChevronRightIcon2,
|
|
4149
4366
|
{
|
|
4150
4367
|
className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
|
|
4151
4368
|
"aria-hidden": true
|
|
@@ -4163,7 +4380,7 @@ function DataGrid({
|
|
|
4163
4380
|
function renderGroupedBucket(bucket) {
|
|
4164
4381
|
const expanded = isGroupExpanded(bucket.key);
|
|
4165
4382
|
const originalRows = bucket.items.map((row) => row.original);
|
|
4166
|
-
return /* @__PURE__ */
|
|
4383
|
+
return /* @__PURE__ */ jsxs21(Fragment3, { children: [
|
|
4167
4384
|
renderGroupHeaderTbody(bucket.key, originalRows),
|
|
4168
4385
|
expanded && bucket.items.map((row) => renderRow(row))
|
|
4169
4386
|
] }, `group-${bucket.key}`);
|
|
@@ -4172,7 +4389,7 @@ function DataGrid({
|
|
|
4172
4389
|
if (item.kind === "header") return renderGroupHeaderTbody(item.key, item.rows, measureRef, index);
|
|
4173
4390
|
return renderRow(item.row, measureRef, index);
|
|
4174
4391
|
}
|
|
4175
|
-
|
|
4392
|
+
const grid = (
|
|
4176
4393
|
// `h-full`/`min-h-0` here and on the two wrappers below are no-ops unless
|
|
4177
4394
|
// a consumer itself gives <DataGrid> a bounded height (e.g. wraps it in
|
|
4178
4395
|
// its own `flex-1 min-h-0` container) -- percentage heights fall back to
|
|
@@ -4185,8 +4402,8 @@ function DataGrid({
|
|
|
4185
4402
|
// containers (that one scrolling vertically, this component's own
|
|
4186
4403
|
// `overflow-x-auto` div scrolling horizontally) fighting over which one
|
|
4187
4404
|
// a sticky header/pinned column is actually stuck relative to.
|
|
4188
|
-
/* @__PURE__ */
|
|
4189
|
-
editing && pendingEdits.size > 0 && /* @__PURE__ */
|
|
4405
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex h-full min-h-0 flex-col gap-2", "data-testid": "datagrid", children: [
|
|
4406
|
+
editing && pendingEdits.size > 0 && /* @__PURE__ */ jsx35(
|
|
4190
4407
|
EditingBar,
|
|
4191
4408
|
{
|
|
4192
4409
|
editing,
|
|
@@ -4196,28 +4413,25 @@ function DataGrid({
|
|
|
4196
4413
|
onDiscard: handleDiscardEdits
|
|
4197
4414
|
}
|
|
4198
4415
|
),
|
|
4199
|
-
showSelectionColumn && headerActions && /* @__PURE__ */
|
|
4200
|
-
/* @__PURE__ */
|
|
4416
|
+
showSelectionColumn && headerActions && /* @__PURE__ */ jsxs21("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
|
|
4417
|
+
/* @__PURE__ */ jsxs21("span", { children: [
|
|
4201
4418
|
selectedRows.length,
|
|
4202
4419
|
" selected"
|
|
4203
4420
|
] }),
|
|
4204
|
-
/* @__PURE__ */
|
|
4421
|
+
/* @__PURE__ */ jsx35(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
|
|
4205
4422
|
] }),
|
|
4206
|
-
/* @__PURE__ */
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
"data-testid": "datagrid-loading-overlay",
|
|
4211
|
-
className: "absolute inset-0 z-30 flex items-center justify-center bg-background/60",
|
|
4212
|
-
children: /* @__PURE__ */ jsx33(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
|
|
4213
|
-
}
|
|
4214
|
-
),
|
|
4215
|
-
/* @__PURE__ */ jsxs20(
|
|
4423
|
+
hasError && rows.length > 0 && /* @__PURE__ */ jsx35("div", { className: "flex shrink-0 items-center rounded-md border border-destructive/40 bg-destructive/10 px-2 py-1", children: /* @__PURE__ */ jsx35(GridInlineError, { error, onRetry, labels }) }),
|
|
4424
|
+
/* @__PURE__ */ jsxs21("div", { className: "relative min-h-0 flex-1", children: [
|
|
4425
|
+
loading && rows.length > 0 && /* @__PURE__ */ jsx35(RefreshBar, { "data-testid": "datagrid-loading-overlay" }),
|
|
4426
|
+
/* @__PURE__ */ jsxs21(
|
|
4216
4427
|
"div",
|
|
4217
4428
|
{
|
|
4218
4429
|
ref: scrollRef,
|
|
4219
4430
|
"data-testid": testId,
|
|
4220
|
-
className: cn(
|
|
4431
|
+
className: cn(
|
|
4432
|
+
"h-full overflow-auto rounded-md border",
|
|
4433
|
+
hasCellEditing && "relative"
|
|
4434
|
+
),
|
|
4221
4435
|
style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
|
|
4222
4436
|
tabIndex: hasCellEditing ? 0 : void 0,
|
|
4223
4437
|
onMouseDown: hasCellEditing ? handleCellMouseDown : void 0,
|
|
@@ -4226,8 +4440,8 @@ function DataGrid({
|
|
|
4226
4440
|
onCopy: hasCellEditing ? handleCopy : void 0,
|
|
4227
4441
|
onPaste: hasCellEditing ? handlePaste : void 0,
|
|
4228
4442
|
children: [
|
|
4229
|
-
/* @__PURE__ */
|
|
4230
|
-
/* @__PURE__ */
|
|
4443
|
+
/* @__PURE__ */ jsxs21("table", { className: cn("w-full border-collapse text-sm", enableColumnResizing && "table-fixed"), children: [
|
|
4444
|
+
/* @__PURE__ */ jsxs21("thead", { ref: theadRef, className: "bg-muted", children: [
|
|
4231
4445
|
table.getHeaderGroups().map((headerGroup) => {
|
|
4232
4446
|
const headerById = new Map(headerGroup.headers.map((header) => [header.id, header]));
|
|
4233
4447
|
function renderLeafHeaderCell(column, rowSpan) {
|
|
@@ -4239,7 +4453,7 @@ function DataGrid({
|
|
|
4239
4453
|
const cellProps = leafHeaderCellPropsByColumn.get(column.id);
|
|
4240
4454
|
const headerContent = column.renderHeader ? column.renderHeader(column) : column.header;
|
|
4241
4455
|
const headerLabelId = `${header.id}-label`;
|
|
4242
|
-
return /* @__PURE__ */
|
|
4456
|
+
return /* @__PURE__ */ jsxs21(
|
|
4243
4457
|
"th",
|
|
4244
4458
|
{
|
|
4245
4459
|
rowSpan,
|
|
@@ -4248,8 +4462,8 @@ function DataGrid({
|
|
|
4248
4462
|
"aria-sort": sortable ? sortDirToAriaSort(sortEntry?.dir) : void 0,
|
|
4249
4463
|
"aria-labelledby": headerLabelId,
|
|
4250
4464
|
children: [
|
|
4251
|
-
/* @__PURE__ */
|
|
4252
|
-
sortable ? /* @__PURE__ */
|
|
4465
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1", children: [
|
|
4466
|
+
sortable ? /* @__PURE__ */ jsxs21(
|
|
4253
4467
|
"button",
|
|
4254
4468
|
{
|
|
4255
4469
|
type: "button",
|
|
@@ -4259,8 +4473,8 @@ function DataGrid({
|
|
|
4259
4473
|
onClick: (event) => toggleSort(column.id, enableMultiSort && event.shiftKey, column.sortDescFirst === true),
|
|
4260
4474
|
children: [
|
|
4261
4475
|
headerContent,
|
|
4262
|
-
sortEntry?.dir === "asc" && /* @__PURE__ */
|
|
4263
|
-
sortEntry?.dir === "desc" && /* @__PURE__ */
|
|
4476
|
+
sortEntry?.dir === "asc" && /* @__PURE__ */ jsx35(BarsArrowUpIcon, { className: "h-3 w-3", "aria-hidden": true }),
|
|
4477
|
+
sortEntry?.dir === "desc" && /* @__PURE__ */ jsx35(BarsArrowDownIcon, { className: "h-3 w-3", "aria-hidden": true })
|
|
4264
4478
|
]
|
|
4265
4479
|
}
|
|
4266
4480
|
) : (
|
|
@@ -4269,17 +4483,17 @@ function DataGrid({
|
|
|
4269
4483
|
// silently breaking any interactive content a column's own `renderHeader`
|
|
4270
4484
|
// embeds directly (bare filter inputs, "select/reject all" buttons) —
|
|
4271
4485
|
// clicks never reach them at all, even though nothing looks wrong visually.
|
|
4272
|
-
/* @__PURE__ */
|
|
4486
|
+
/* @__PURE__ */ jsx35("div", { id: headerLabelId, className: "flex items-center gap-1 px-1", children: headerContent })
|
|
4273
4487
|
),
|
|
4274
|
-
filterable && /* @__PURE__ */
|
|
4275
|
-
/* @__PURE__ */
|
|
4488
|
+
filterable && /* @__PURE__ */ jsxs21(Popover, { children: [
|
|
4489
|
+
/* @__PURE__ */ jsx35(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx35(
|
|
4276
4490
|
Button,
|
|
4277
4491
|
{
|
|
4278
4492
|
variant: "ghost",
|
|
4279
4493
|
size: "icon",
|
|
4280
4494
|
"data-testid": `filter-trigger-${column.id}`,
|
|
4281
|
-
"aria-label":
|
|
4282
|
-
children: /* @__PURE__ */
|
|
4495
|
+
"aria-label": resolvedFilterLabels.filterAriaLabel(column.header),
|
|
4496
|
+
children: /* @__PURE__ */ jsx35(
|
|
4283
4497
|
FunnelIcon7,
|
|
4284
4498
|
{
|
|
4285
4499
|
className: cn(
|
|
@@ -4291,10 +4505,10 @@ function DataGrid({
|
|
|
4291
4505
|
)
|
|
4292
4506
|
}
|
|
4293
4507
|
) }),
|
|
4294
|
-
/* @__PURE__ */
|
|
4508
|
+
/* @__PURE__ */ jsx35(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: renderFilterWidget(column) })
|
|
4295
4509
|
] })
|
|
4296
4510
|
] }),
|
|
4297
|
-
enableColumnResizing && /* @__PURE__ */
|
|
4511
|
+
enableColumnResizing && /* @__PURE__ */ jsx35(
|
|
4298
4512
|
"div",
|
|
4299
4513
|
{
|
|
4300
4514
|
"data-testid": `resize-handle-${column.id}`,
|
|
@@ -4319,9 +4533,9 @@ function DataGrid({
|
|
|
4319
4533
|
header.id
|
|
4320
4534
|
);
|
|
4321
4535
|
}
|
|
4322
|
-
return /* @__PURE__ */
|
|
4323
|
-
hasHeaderGroups && /* @__PURE__ */
|
|
4324
|
-
showDetailColumn && /* @__PURE__ */
|
|
4536
|
+
return /* @__PURE__ */ jsxs21(Fragment3, { children: [
|
|
4537
|
+
hasHeaderGroups && /* @__PURE__ */ jsxs21("tr", { "data-testid": "header-group-row", className: "divide-x divide-border", children: [
|
|
4538
|
+
showDetailColumn && /* @__PURE__ */ jsx35(
|
|
4325
4539
|
"th",
|
|
4326
4540
|
{
|
|
4327
4541
|
rowSpan: 2,
|
|
@@ -4330,13 +4544,13 @@ function DataGrid({
|
|
|
4330
4544
|
"aria-hidden": true
|
|
4331
4545
|
}
|
|
4332
4546
|
),
|
|
4333
|
-
showSelectionColumn && /* @__PURE__ */
|
|
4547
|
+
showSelectionColumn && /* @__PURE__ */ jsx35(
|
|
4334
4548
|
"th",
|
|
4335
4549
|
{
|
|
4336
4550
|
rowSpan: 2,
|
|
4337
4551
|
className: selectionHeaderCellProps.className,
|
|
4338
4552
|
style: selectionHeaderCellProps.style,
|
|
4339
|
-
children: /* @__PURE__ */
|
|
4553
|
+
children: /* @__PURE__ */ jsx35(
|
|
4340
4554
|
"input",
|
|
4341
4555
|
{
|
|
4342
4556
|
type: "checkbox",
|
|
@@ -4348,7 +4562,7 @@ function DataGrid({
|
|
|
4348
4562
|
}
|
|
4349
4563
|
),
|
|
4350
4564
|
headerRuns.map(
|
|
4351
|
-
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */
|
|
4565
|
+
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx35(
|
|
4352
4566
|
"th",
|
|
4353
4567
|
{
|
|
4354
4568
|
colSpan: run.columns.length,
|
|
@@ -4358,7 +4572,7 @@ function DataGrid({
|
|
|
4358
4572
|
`group-${run.label}-${run.columns[0].id}`
|
|
4359
4573
|
)
|
|
4360
4574
|
),
|
|
4361
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
4575
|
+
showRowActionsColumn && /* @__PURE__ */ jsx35(
|
|
4362
4576
|
"th",
|
|
4363
4577
|
{
|
|
4364
4578
|
rowSpan: 2,
|
|
@@ -4368,8 +4582,8 @@ function DataGrid({
|
|
|
4368
4582
|
}
|
|
4369
4583
|
)
|
|
4370
4584
|
] }, `${headerGroup.id}-groups`),
|
|
4371
|
-
/* @__PURE__ */
|
|
4372
|
-
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */
|
|
4585
|
+
/* @__PURE__ */ jsxs21("tr", { className: "divide-x divide-border", children: [
|
|
4586
|
+
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx35(
|
|
4373
4587
|
"th",
|
|
4374
4588
|
{
|
|
4375
4589
|
className: detailHeaderCellProps.className,
|
|
@@ -4377,12 +4591,12 @@ function DataGrid({
|
|
|
4377
4591
|
"aria-hidden": true
|
|
4378
4592
|
}
|
|
4379
4593
|
),
|
|
4380
|
-
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */
|
|
4594
|
+
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx35(
|
|
4381
4595
|
"th",
|
|
4382
4596
|
{
|
|
4383
4597
|
className: selectionHeaderCellProps.className,
|
|
4384
4598
|
style: selectionHeaderCellProps.style,
|
|
4385
|
-
children: /* @__PURE__ */
|
|
4599
|
+
children: /* @__PURE__ */ jsx35(
|
|
4386
4600
|
"input",
|
|
4387
4601
|
{
|
|
4388
4602
|
type: "checkbox",
|
|
@@ -4398,7 +4612,7 @@ function DataGrid({
|
|
|
4398
4612
|
if (!column || hasHeaderGroups && !column.headerGroup) return null;
|
|
4399
4613
|
return renderLeafHeaderCell(column);
|
|
4400
4614
|
}),
|
|
4401
|
-
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */
|
|
4615
|
+
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx35(
|
|
4402
4616
|
"th",
|
|
4403
4617
|
{
|
|
4404
4618
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -4409,9 +4623,9 @@ function DataGrid({
|
|
|
4409
4623
|
] }, headerGroup.id)
|
|
4410
4624
|
] }, headerGroup.id);
|
|
4411
4625
|
}),
|
|
4412
|
-
hasFilterRow && /* @__PURE__ */
|
|
4413
|
-
showDetailColumn && /* @__PURE__ */
|
|
4414
|
-
showSelectionColumn && /* @__PURE__ */
|
|
4626
|
+
hasFilterRow && /* @__PURE__ */ jsxs21("tr", { "data-testid": "filter-row", className: "divide-x divide-border", children: [
|
|
4627
|
+
showDetailColumn && /* @__PURE__ */ jsx35("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
|
|
4628
|
+
showSelectionColumn && /* @__PURE__ */ jsx35(
|
|
4415
4629
|
"th",
|
|
4416
4630
|
{
|
|
4417
4631
|
className: selectionHeaderCellProps.className,
|
|
@@ -4420,9 +4634,9 @@ function DataGrid({
|
|
|
4420
4634
|
),
|
|
4421
4635
|
visibleColumns.map((column) => {
|
|
4422
4636
|
const cellProps = filterHeaderCellPropsByColumn.get(column.id);
|
|
4423
|
-
return /* @__PURE__ */
|
|
4637
|
+
return /* @__PURE__ */ jsx35("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
|
|
4424
4638
|
}),
|
|
4425
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
4639
|
+
showRowActionsColumn && /* @__PURE__ */ jsx35(
|
|
4426
4640
|
"th",
|
|
4427
4641
|
{
|
|
4428
4642
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -4431,8 +4645,8 @@ function DataGrid({
|
|
|
4431
4645
|
)
|
|
4432
4646
|
] })
|
|
4433
4647
|
] }),
|
|
4434
|
-
rows.length === 0 ? /* @__PURE__ */
|
|
4435
|
-
paddingTop > 0 && /* @__PURE__ */
|
|
4648
|
+
rows.length === 0 ? /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsx35(LoadingRows, { label: labels.loading }) : hasError ? /* @__PURE__ */ jsx35(GridErrorState, { error, onRetry, labels }) : labels.noResults }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs21(Fragment4, { children: [
|
|
4649
|
+
paddingTop > 0 && /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
|
|
4436
4650
|
virtualItems.map(
|
|
4437
4651
|
(virtualItem) => renderFlatItem(
|
|
4438
4652
|
flatItems[virtualItem.index],
|
|
@@ -4440,11 +4654,11 @@ function DataGrid({
|
|
|
4440
4654
|
(el) => virtualizer.measureElement(el)
|
|
4441
4655
|
)
|
|
4442
4656
|
),
|
|
4443
|
-
paddingBottom > 0 && /* @__PURE__ */
|
|
4657
|
+
paddingBottom > 0 && /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
|
|
4444
4658
|
] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row)),
|
|
4445
4659
|
renderTotalsFooter()
|
|
4446
4660
|
] }),
|
|
4447
|
-
hasCellEditing && /* @__PURE__ */
|
|
4661
|
+
hasCellEditing && /* @__PURE__ */ jsx35(
|
|
4448
4662
|
SelectionOverlay,
|
|
4449
4663
|
{
|
|
4450
4664
|
containerRef: scrollRef,
|
|
@@ -4457,8 +4671,8 @@ function DataGrid({
|
|
|
4457
4671
|
}
|
|
4458
4672
|
)
|
|
4459
4673
|
] }),
|
|
4460
|
-
showPagination && /* @__PURE__ */
|
|
4461
|
-
/* @__PURE__ */
|
|
4674
|
+
showPagination && /* @__PURE__ */ jsxs21("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
|
|
4675
|
+
/* @__PURE__ */ jsxs21("span", { children: [
|
|
4462
4676
|
"Page ",
|
|
4463
4677
|
state.page + 1,
|
|
4464
4678
|
" of ",
|
|
@@ -4469,8 +4683,8 @@ function DataGrid({
|
|
|
4469
4683
|
rowCount === 1 ? "" : "s",
|
|
4470
4684
|
")"
|
|
4471
4685
|
] }),
|
|
4472
|
-
/* @__PURE__ */
|
|
4473
|
-
/* @__PURE__ */
|
|
4686
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex gap-2", children: [
|
|
4687
|
+
/* @__PURE__ */ jsx35(
|
|
4474
4688
|
Button,
|
|
4475
4689
|
{
|
|
4476
4690
|
variant: "outline",
|
|
@@ -4480,7 +4694,7 @@ function DataGrid({
|
|
|
4480
4694
|
children: "Previous"
|
|
4481
4695
|
}
|
|
4482
4696
|
),
|
|
4483
|
-
/* @__PURE__ */
|
|
4697
|
+
/* @__PURE__ */ jsx35(
|
|
4484
4698
|
Button,
|
|
4485
4699
|
{
|
|
4486
4700
|
variant: "outline",
|
|
@@ -4494,12 +4708,17 @@ function DataGrid({
|
|
|
4494
4708
|
] })
|
|
4495
4709
|
] })
|
|
4496
4710
|
);
|
|
4711
|
+
return /* @__PURE__ */ jsx35(FilterLabelsProvider, { labels: filterLabels, children: grid });
|
|
4497
4712
|
}
|
|
4498
4713
|
|
|
4499
4714
|
// src/tree/TreeDataGrid.tsx
|
|
4500
4715
|
import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
|
|
4501
|
-
import {
|
|
4502
|
-
|
|
4716
|
+
import {
|
|
4717
|
+
ArrowPathIcon as ArrowPathIcon2,
|
|
4718
|
+
ChevronDownIcon as ChevronDownIcon3,
|
|
4719
|
+
ChevronRightIcon as ChevronRightIcon3
|
|
4720
|
+
} from "@heroicons/react/24/outline";
|
|
4721
|
+
import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo11, useRef as useRef14 } from "react";
|
|
4503
4722
|
|
|
4504
4723
|
// src/tree/flattenTree.ts
|
|
4505
4724
|
function flattenTree(roots, accessors, expanded, childrenOverride) {
|
|
@@ -4544,7 +4763,7 @@ function computeSelectionStates(roots, accessors, childrenOverride, selectedIds)
|
|
|
4544
4763
|
}
|
|
4545
4764
|
|
|
4546
4765
|
// src/tree/useTreeState.ts
|
|
4547
|
-
import { useCallback as useCallback5, useMemo as
|
|
4766
|
+
import { useCallback as useCallback5, useMemo as useMemo10, useState as useState17 } from "react";
|
|
4548
4767
|
function useTreeState({
|
|
4549
4768
|
data,
|
|
4550
4769
|
getRowId,
|
|
@@ -4582,7 +4801,7 @@ function useTreeState({
|
|
|
4582
4801
|
);
|
|
4583
4802
|
const [loadingIds, setLoadingIds] = useState17(/* @__PURE__ */ new Set());
|
|
4584
4803
|
const [errorIds, setErrorIds] = useState17(/* @__PURE__ */ new Map());
|
|
4585
|
-
const resolveHasChildren =
|
|
4804
|
+
const resolveHasChildren = useMemo10(
|
|
4586
4805
|
() => hasChildren ?? ((row) => (getChildren(row)?.length ?? 0) > 0),
|
|
4587
4806
|
[hasChildren, getChildren]
|
|
4588
4807
|
);
|
|
@@ -4661,7 +4880,7 @@ function useTreeState({
|
|
|
4661
4880
|
}
|
|
4662
4881
|
|
|
4663
4882
|
// src/tree/TreeDataGrid.tsx
|
|
4664
|
-
import { Fragment as Fragment6, jsx as
|
|
4883
|
+
import { Fragment as Fragment6, jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4665
4884
|
var EMPTY_SELECTED_IDS = /* @__PURE__ */ new Set();
|
|
4666
4885
|
var UNCHECKED_STATE = { checked: false, indeterminate: false };
|
|
4667
4886
|
function renderCell(column, row, editingCtx) {
|
|
@@ -4673,12 +4892,13 @@ function TreeCell({
|
|
|
4673
4892
|
indentSize,
|
|
4674
4893
|
isLoading,
|
|
4675
4894
|
error,
|
|
4895
|
+
labels,
|
|
4676
4896
|
onToggle,
|
|
4677
4897
|
onRetry,
|
|
4678
4898
|
editingCtx
|
|
4679
4899
|
}) {
|
|
4680
|
-
return /* @__PURE__ */
|
|
4681
|
-
flatRow.hasChildren ? /* @__PURE__ */
|
|
4900
|
+
return /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-1", style: { paddingLeft: flatRow.depth * indentSize }, children: [
|
|
4901
|
+
flatRow.hasChildren ? /* @__PURE__ */ jsx36(
|
|
4682
4902
|
"button",
|
|
4683
4903
|
{
|
|
4684
4904
|
type: "button",
|
|
@@ -4690,21 +4910,28 @@ function TreeCell({
|
|
|
4690
4910
|
"aria-label": flatRow.isExpanded ? "Collapse" : "Expand",
|
|
4691
4911
|
"aria-expanded": flatRow.isExpanded,
|
|
4692
4912
|
className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
4693
|
-
children: isLoading ? /* @__PURE__ */
|
|
4913
|
+
children: isLoading ? /* @__PURE__ */ jsx36(ArrowPathIcon2, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }) : flatRow.isExpanded ? /* @__PURE__ */ jsx36(ChevronDownIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx36(ChevronRightIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
|
|
4694
4914
|
}
|
|
4695
|
-
) : /* @__PURE__ */
|
|
4696
|
-
/* @__PURE__ */
|
|
4697
|
-
flatRow.isExpanded && error ? /* @__PURE__ */
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4915
|
+
) : /* @__PURE__ */ jsx36("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
|
|
4916
|
+
/* @__PURE__ */ jsx36("span", { className: "min-w-0 flex-1 truncate", children: renderCell(column, flatRow.row, editingCtx) }),
|
|
4917
|
+
flatRow.isExpanded && error ? /* @__PURE__ */ jsx36(
|
|
4918
|
+
GridInlineError,
|
|
4919
|
+
{
|
|
4920
|
+
error: { message: labels.nodeLoadFailed, details: error },
|
|
4921
|
+
onRetry,
|
|
4922
|
+
labels,
|
|
4923
|
+
className: "ml-1 shrink-0"
|
|
4924
|
+
}
|
|
4925
|
+
) : null
|
|
4702
4926
|
] });
|
|
4703
4927
|
}
|
|
4704
4928
|
function TreeDataGrid({
|
|
4705
4929
|
columns,
|
|
4706
4930
|
data,
|
|
4707
4931
|
loading = false,
|
|
4932
|
+
error,
|
|
4933
|
+
onRetry,
|
|
4934
|
+
statusLabels,
|
|
4708
4935
|
treeColumnId,
|
|
4709
4936
|
columnVisibility,
|
|
4710
4937
|
getRowId,
|
|
@@ -4737,7 +4964,9 @@ function TreeDataGrid({
|
|
|
4737
4964
|
showTotals = false,
|
|
4738
4965
|
editing
|
|
4739
4966
|
}) {
|
|
4740
|
-
const
|
|
4967
|
+
const labels = resolveStatusLabels(statusLabels);
|
|
4968
|
+
const hasError = toErrorInfo(error) !== void 0;
|
|
4969
|
+
const accessors = useMemo11(
|
|
4741
4970
|
() => ({ getRowId, getChildren, hasChildren }),
|
|
4742
4971
|
[getRowId, getChildren, hasChildren]
|
|
4743
4972
|
);
|
|
@@ -4765,11 +4994,11 @@ function TreeDataGrid({
|
|
|
4765
4994
|
controlledExpandedGroups,
|
|
4766
4995
|
onExpandedGroupsChange
|
|
4767
4996
|
);
|
|
4768
|
-
const flatRows =
|
|
4997
|
+
const flatRows = useMemo11(
|
|
4769
4998
|
() => groupBy ? [] : flattenTree(data, accessors, expanded, childrenMap),
|
|
4770
4999
|
[groupBy, data, accessors, expanded, childrenMap]
|
|
4771
5000
|
);
|
|
4772
|
-
const groupedBuckets =
|
|
5001
|
+
const groupedBuckets = useMemo11(
|
|
4773
5002
|
() => groupBy ? groupRows(data, groupBy).map((bucket) => ({
|
|
4774
5003
|
key: bucket.key,
|
|
4775
5004
|
roots: bucket.items,
|
|
@@ -4777,7 +5006,7 @@ function TreeDataGrid({
|
|
|
4777
5006
|
})) : void 0,
|
|
4778
5007
|
[groupBy, data, accessors, expanded, childrenMap]
|
|
4779
5008
|
);
|
|
4780
|
-
const groupedRender =
|
|
5009
|
+
const groupedRender = useMemo11(() => {
|
|
4781
5010
|
if (!groupedBuckets) return void 0;
|
|
4782
5011
|
const startIndexByBucket = /* @__PURE__ */ new Map();
|
|
4783
5012
|
const rows = [];
|
|
@@ -4794,7 +5023,7 @@ function TreeDataGrid({
|
|
|
4794
5023
|
const showSelectionColumn = controlledSelectedIds !== void 0;
|
|
4795
5024
|
const totalColumnCount = visibleColumns.length + (showRowActionsColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0);
|
|
4796
5025
|
const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
|
|
4797
|
-
const selectionStates =
|
|
5026
|
+
const selectionStates = useMemo11(
|
|
4798
5027
|
() => showSelectionColumn ? computeSelectionStates(data, accessors, childrenMap, controlledSelectedIds ?? EMPTY_SELECTED_IDS) : void 0,
|
|
4799
5028
|
[showSelectionColumn, data, accessors, childrenMap, controlledSelectedIds]
|
|
4800
5029
|
);
|
|
@@ -4810,7 +5039,7 @@ function TreeDataGrid({
|
|
|
4810
5039
|
else next.add(id);
|
|
4811
5040
|
onSelectedIdsChange?.(next);
|
|
4812
5041
|
}
|
|
4813
|
-
const selectableFlatRows =
|
|
5042
|
+
const selectableFlatRows = useMemo11(
|
|
4814
5043
|
() => allFlatRows.filter((flatRow) => !(isRowSelectionDisabled?.(flatRow.row) ?? false)),
|
|
4815
5044
|
[allFlatRows, isRowSelectionDisabled]
|
|
4816
5045
|
);
|
|
@@ -4824,14 +5053,14 @@ function TreeDataGrid({
|
|
|
4824
5053
|
}
|
|
4825
5054
|
onSelectedIdsChange?.(next);
|
|
4826
5055
|
}
|
|
4827
|
-
const bodyTdClassByColumn =
|
|
5056
|
+
const bodyTdClassByColumn = useMemo11(() => {
|
|
4828
5057
|
const map = /* @__PURE__ */ new Map();
|
|
4829
5058
|
for (const column of visibleColumns) map.set(column.id, `p-2 ${alignClassName(column)}`);
|
|
4830
5059
|
return map;
|
|
4831
5060
|
}, [visibleColumns]);
|
|
4832
5061
|
const hasColumnSummary = visibleColumns.some((column) => column.summary);
|
|
4833
5062
|
function renderGroupSummaryCells(rows) {
|
|
4834
|
-
return visibleColumns.map((column) => /* @__PURE__ */
|
|
5063
|
+
return visibleColumns.map((column) => /* @__PURE__ */ jsx36("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
|
|
4835
5064
|
}
|
|
4836
5065
|
const scrollRef = useRef14(null);
|
|
4837
5066
|
const shouldVirtualize = !groupBy && flatRows.length > virtualizeThreshold;
|
|
@@ -4846,7 +5075,7 @@ function TreeDataGrid({
|
|
|
4846
5075
|
const rowProps = getRowProps?.(flatRow.row, flatRow.depth, index);
|
|
4847
5076
|
const rowTestId = getRowTestId?.(flatRow.row) ?? `tree-row-${flatRow.id}`;
|
|
4848
5077
|
const isOddRow = zebra && index % 2 === 1;
|
|
4849
|
-
return /* @__PURE__ */
|
|
5078
|
+
return /* @__PURE__ */ jsxs22(
|
|
4850
5079
|
"tr",
|
|
4851
5080
|
{
|
|
4852
5081
|
ref: measureRef,
|
|
@@ -4859,9 +5088,9 @@ function TreeDataGrid({
|
|
|
4859
5088
|
isOddRow && "bg-foreground/5"
|
|
4860
5089
|
) : `border-b border-border divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
4861
5090
|
children: [
|
|
4862
|
-
showSelectionColumn && /* @__PURE__ */
|
|
5091
|
+
showSelectionColumn && /* @__PURE__ */ jsx36("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
|
|
4863
5092
|
const state = resolveSelectionState(flatRow.row, flatRow.id);
|
|
4864
|
-
return /* @__PURE__ */
|
|
5093
|
+
return /* @__PURE__ */ jsx36(
|
|
4865
5094
|
Checkbox,
|
|
4866
5095
|
{
|
|
4867
5096
|
"aria-label": `Select row ${flatRow.id}`,
|
|
@@ -4872,7 +5101,7 @@ function TreeDataGrid({
|
|
|
4872
5101
|
}
|
|
4873
5102
|
);
|
|
4874
5103
|
})() }),
|
|
4875
|
-
visibleColumns.map((column) => /* @__PURE__ */
|
|
5104
|
+
visibleColumns.map((column) => /* @__PURE__ */ jsx36("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx36(
|
|
4876
5105
|
TreeCell,
|
|
4877
5106
|
{
|
|
4878
5107
|
flatRow,
|
|
@@ -4880,12 +5109,13 @@ function TreeDataGrid({
|
|
|
4880
5109
|
indentSize,
|
|
4881
5110
|
isLoading: loadingIds.has(flatRow.id),
|
|
4882
5111
|
error: errorIds.get(flatRow.id),
|
|
5112
|
+
labels,
|
|
4883
5113
|
onToggle: () => toggleExpand(flatRow.row),
|
|
4884
5114
|
onRetry: () => retry(flatRow.row),
|
|
4885
5115
|
editingCtx: editingState.ctx
|
|
4886
5116
|
}
|
|
4887
5117
|
) : renderCell(column, flatRow.row, editingState.ctx) }, column.id)),
|
|
4888
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
5118
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx36("td", { className: "p-2", children: /* @__PURE__ */ jsx36(
|
|
4889
5119
|
ActionsMenu,
|
|
4890
5120
|
{
|
|
4891
5121
|
items: rowActions,
|
|
@@ -4901,8 +5131,9 @@ function TreeDataGrid({
|
|
|
4901
5131
|
const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
|
|
4902
5132
|
const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
|
|
4903
5133
|
const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
|
|
4904
|
-
return /* @__PURE__ */
|
|
4905
|
-
|
|
5134
|
+
return /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: [
|
|
5135
|
+
hasError && data.length > 0 && /* @__PURE__ */ jsx36("div", { className: "flex shrink-0 items-center rounded-md border border-destructive/40 bg-destructive/10 px-2 py-1", children: /* @__PURE__ */ jsx36(GridInlineError, { error, onRetry, labels }) }),
|
|
5136
|
+
editing && editingState.pendingEdits.size > 0 && /* @__PURE__ */ jsx36(
|
|
4906
5137
|
EditingBar,
|
|
4907
5138
|
{
|
|
4908
5139
|
editing,
|
|
@@ -4913,21 +5144,21 @@ function TreeDataGrid({
|
|
|
4913
5144
|
testIdPrefix: "tree-datagrid"
|
|
4914
5145
|
}
|
|
4915
5146
|
),
|
|
4916
|
-
/* @__PURE__ */
|
|
5147
|
+
/* @__PURE__ */ jsx36(
|
|
4917
5148
|
"div",
|
|
4918
5149
|
{
|
|
4919
5150
|
ref: scrollRef,
|
|
4920
5151
|
"data-testid": testId,
|
|
4921
5152
|
className: "overflow-y-auto",
|
|
4922
5153
|
style: { maxHeight: maxBodyHeight },
|
|
4923
|
-
children: /* @__PURE__ */
|
|
4924
|
-
/* @__PURE__ */
|
|
4925
|
-
showSelectionColumn && /* @__PURE__ */
|
|
5154
|
+
children: /* @__PURE__ */ jsxs22("table", { className: "w-full border-collapse text-sm", children: [
|
|
5155
|
+
/* @__PURE__ */ jsx36("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs22("tr", { className: "divide-x divide-border", children: [
|
|
5156
|
+
showSelectionColumn && /* @__PURE__ */ jsx36(
|
|
4926
5157
|
"th",
|
|
4927
5158
|
{
|
|
4928
5159
|
className: "sticky top-0 z-20 border-b border-border bg-muted p-1",
|
|
4929
5160
|
style: { width: SELECTION_COLUMN_WIDTH },
|
|
4930
|
-
children: /* @__PURE__ */
|
|
5161
|
+
children: /* @__PURE__ */ jsx36(
|
|
4931
5162
|
Checkbox,
|
|
4932
5163
|
{
|
|
4933
5164
|
"aria-label": "Select all visible rows",
|
|
@@ -4937,7 +5168,7 @@ function TreeDataGrid({
|
|
|
4937
5168
|
)
|
|
4938
5169
|
}
|
|
4939
5170
|
),
|
|
4940
|
-
visibleColumns.map((column) => /* @__PURE__ */
|
|
5171
|
+
visibleColumns.map((column) => /* @__PURE__ */ jsx36(
|
|
4941
5172
|
"th",
|
|
4942
5173
|
{
|
|
4943
5174
|
style: column.width ? { width: column.width } : void 0,
|
|
@@ -4949,15 +5180,12 @@ function TreeDataGrid({
|
|
|
4949
5180
|
},
|
|
4950
5181
|
column.id
|
|
4951
5182
|
)),
|
|
4952
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
5183
|
+
showRowActionsColumn && /* @__PURE__ */ jsx36("th", { className: "sticky top-0 z-20 border-b border-border bg-muted p-2", "aria-label": "Row actions" })
|
|
4953
5184
|
] }) }),
|
|
4954
|
-
/* @__PURE__ */
|
|
4955
|
-
/* @__PURE__ */ jsx34(Loader22, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }),
|
|
4956
|
-
"Loading..."
|
|
4957
|
-
] }) : "No results." }) }) : groupedBuckets ? groupedBuckets.map((bucket) => {
|
|
5185
|
+
/* @__PURE__ */ jsx36("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx36("tr", { children: /* @__PURE__ */ jsx36("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsx36(LoadingRows, { label: labels.loading }) : hasError ? /* @__PURE__ */ jsx36(GridErrorState, { error, onRetry, labels }) : labels.noResults }) }) : groupedBuckets ? groupedBuckets.map((bucket) => {
|
|
4958
5186
|
const groupExpanded = isGroupExpanded(bucket.key);
|
|
4959
|
-
return /* @__PURE__ */
|
|
4960
|
-
/* @__PURE__ */
|
|
5187
|
+
return /* @__PURE__ */ jsxs22(Fragment5, { children: [
|
|
5188
|
+
/* @__PURE__ */ jsx36("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx36(
|
|
4961
5189
|
"td",
|
|
4962
5190
|
{
|
|
4963
5191
|
colSpan: totalColumnCount,
|
|
@@ -4966,7 +5194,7 @@ function TreeDataGrid({
|
|
|
4966
5194
|
zebra ? "bg-muted" : "bg-background"
|
|
4967
5195
|
),
|
|
4968
5196
|
style: { top: groupHeaderTop },
|
|
4969
|
-
children: /* @__PURE__ */
|
|
5197
|
+
children: /* @__PURE__ */ jsxs22(
|
|
4970
5198
|
"button",
|
|
4971
5199
|
{
|
|
4972
5200
|
type: "button",
|
|
@@ -4974,8 +5202,8 @@ function TreeDataGrid({
|
|
|
4974
5202
|
onClick: () => toggleGroupExpanded(bucket.key),
|
|
4975
5203
|
"aria-expanded": groupExpanded,
|
|
4976
5204
|
children: [
|
|
4977
|
-
/* @__PURE__ */
|
|
4978
|
-
|
|
5205
|
+
/* @__PURE__ */ jsx36(
|
|
5206
|
+
ChevronRightIcon3,
|
|
4979
5207
|
{
|
|
4980
5208
|
className: `h-4 w-4 shrink-0 transition-transform${groupExpanded ? " rotate-90" : ""}`,
|
|
4981
5209
|
"aria-hidden": true
|
|
@@ -4987,13 +5215,13 @@ function TreeDataGrid({
|
|
|
4987
5215
|
)
|
|
4988
5216
|
}
|
|
4989
5217
|
) }),
|
|
4990
|
-
hasColumnSummary && /* @__PURE__ */
|
|
5218
|
+
hasColumnSummary && /* @__PURE__ */ jsxs22(
|
|
4991
5219
|
"tr",
|
|
4992
5220
|
{
|
|
4993
5221
|
"data-testid": `group-summary-${bucket.key}`,
|
|
4994
5222
|
className: "border-b border-border divide-x divide-border",
|
|
4995
5223
|
children: [
|
|
4996
|
-
showSelectionColumn && /* @__PURE__ */
|
|
5224
|
+
showSelectionColumn && /* @__PURE__ */ jsx36(
|
|
4997
5225
|
"td",
|
|
4998
5226
|
{
|
|
4999
5227
|
className: cn("p-2", zebra ? "bg-muted" : "bg-background"),
|
|
@@ -5001,7 +5229,7 @@ function TreeDataGrid({
|
|
|
5001
5229
|
}
|
|
5002
5230
|
),
|
|
5003
5231
|
renderGroupSummaryCells(bucket.roots),
|
|
5004
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
5232
|
+
showRowActionsColumn && /* @__PURE__ */ jsx36("td", { className: cn("p-2", zebra ? "bg-muted" : "bg-background"), "aria-hidden": true })
|
|
5005
5233
|
]
|
|
5006
5234
|
}
|
|
5007
5235
|
),
|
|
@@ -5010,12 +5238,12 @@ function TreeDataGrid({
|
|
|
5010
5238
|
return bucket.flatRows.map((flatRow, i) => renderRow(flatRow, startIndex + i));
|
|
5011
5239
|
})()
|
|
5012
5240
|
] }, `group-${bucket.key}`);
|
|
5013
|
-
}) : shouldVirtualize ? /* @__PURE__ */
|
|
5014
|
-
paddingTop > 0 && /* @__PURE__ */
|
|
5241
|
+
}) : shouldVirtualize ? /* @__PURE__ */ jsxs22(Fragment6, { children: [
|
|
5242
|
+
paddingTop > 0 && /* @__PURE__ */ jsx36("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx36("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
|
|
5015
5243
|
virtualItems.map(
|
|
5016
5244
|
(virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
|
|
5017
5245
|
),
|
|
5018
|
-
paddingBottom > 0 && /* @__PURE__ */
|
|
5246
|
+
paddingBottom > 0 && /* @__PURE__ */ jsx36("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx36(
|
|
5019
5247
|
"td",
|
|
5020
5248
|
{
|
|
5021
5249
|
colSpan: totalColumnCount,
|
|
@@ -5030,15 +5258,15 @@ function TreeDataGrid({
|
|
|
5030
5258
|
// "roots only" scope `groupBy` itself uses, and for the same
|
|
5031
5259
|
// reason (a child's value is usually already folded into its
|
|
5032
5260
|
// parent's).
|
|
5033
|
-
/* @__PURE__ */
|
|
5034
|
-
showSelectionColumn && /* @__PURE__ */
|
|
5261
|
+
/* @__PURE__ */ jsx36("tfoot", { children: /* @__PURE__ */ jsxs22("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
|
|
5262
|
+
showSelectionColumn && /* @__PURE__ */ jsx36(
|
|
5035
5263
|
"td",
|
|
5036
5264
|
{
|
|
5037
5265
|
className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2",
|
|
5038
5266
|
style: { width: SELECTION_COLUMN_WIDTH }
|
|
5039
5267
|
}
|
|
5040
5268
|
),
|
|
5041
|
-
visibleColumns.map((column) => /* @__PURE__ */
|
|
5269
|
+
visibleColumns.map((column) => /* @__PURE__ */ jsx36(
|
|
5042
5270
|
"td",
|
|
5043
5271
|
{
|
|
5044
5272
|
style: column.width ? { width: column.width } : void 0,
|
|
@@ -5050,7 +5278,7 @@ function TreeDataGrid({
|
|
|
5050
5278
|
},
|
|
5051
5279
|
column.id
|
|
5052
5280
|
)),
|
|
5053
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
5281
|
+
showRowActionsColumn && /* @__PURE__ */ jsx36("td", { className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2", "aria-hidden": true })
|
|
5054
5282
|
] }) })
|
|
5055
5283
|
] })
|
|
5056
5284
|
}
|
|
@@ -5069,6 +5297,7 @@ export {
|
|
|
5069
5297
|
EditingBar,
|
|
5070
5298
|
EnumEditor,
|
|
5071
5299
|
EnumFilter,
|
|
5300
|
+
FilterLabelsProvider,
|
|
5072
5301
|
MultilineStringEditor,
|
|
5073
5302
|
NumberComparisonFilter,
|
|
5074
5303
|
NumberEditor,
|
|
@@ -5089,7 +5318,9 @@ export {
|
|
|
5089
5318
|
computeFillChanges,
|
|
5090
5319
|
countVisible,
|
|
5091
5320
|
defaultAlign,
|
|
5321
|
+
defaultFilterLabels,
|
|
5092
5322
|
defaultFormat,
|
|
5323
|
+
defaultGridStatusLabels,
|
|
5093
5324
|
editErrorId,
|
|
5094
5325
|
evaluateFilter,
|
|
5095
5326
|
extendRangeForFill,
|
|
@@ -5105,6 +5336,7 @@ export {
|
|
|
5105
5336
|
isFilterDescriptor,
|
|
5106
5337
|
isFilterable,
|
|
5107
5338
|
isSortable,
|
|
5339
|
+
mergeFilterLabels,
|
|
5108
5340
|
moveColumnBefore,
|
|
5109
5341
|
normalizeRange,
|
|
5110
5342
|
orderStorageKeyFor,
|
|
@@ -5118,10 +5350,12 @@ export {
|
|
|
5118
5350
|
resolveMenuItems,
|
|
5119
5351
|
storageKeyFor,
|
|
5120
5352
|
toDate,
|
|
5353
|
+
toErrorInfo,
|
|
5121
5354
|
useCellEditingState,
|
|
5122
5355
|
useCellSelection,
|
|
5123
5356
|
useDebouncedCallback,
|
|
5124
5357
|
useEditingState,
|
|
5358
|
+
useFilterLabels,
|
|
5125
5359
|
useGridState,
|
|
5126
5360
|
useGroupExpansion,
|
|
5127
5361
|
useStickyGroupHeaderTop,
|