@tulipfarm/sprout 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +183 -2
- package/dist/components/accordion.d.ts +28 -0
- package/dist/components/accordion.js +26 -0
- package/dist/components/alert-dialog.d.ts +60 -0
- package/dist/components/alert-dialog.js +69 -0
- package/dist/components/alert.d.ts +30 -0
- package/dist/components/alert.js +35 -0
- package/dist/components/aspect-ratio.d.ts +7 -0
- package/dist/components/aspect-ratio.js +6 -0
- package/dist/components/attachment.d.ts +118 -0
- package/dist/components/attachment.js +285 -0
- package/dist/components/avatar.d.ts +32 -0
- package/dist/components/avatar.js +73 -0
- package/dist/components/badge.d.ts +21 -0
- package/dist/components/badge.js +27 -0
- package/dist/components/brand-icon.d.ts +28 -0
- package/dist/components/brand-icon.js +82 -0
- package/dist/components/breadcrumb.d.ts +29 -0
- package/dist/components/breadcrumb.js +44 -0
- package/dist/components/button-group.d.ts +28 -0
- package/dist/components/button-group.js +36 -0
- package/dist/components/button.d.ts +79 -0
- package/dist/components/button.js +93 -0
- package/dist/components/calendar.d.ts +27 -0
- package/dist/components/calendar.js +107 -0
- package/dist/components/canvas.d.ts +78 -0
- package/dist/components/canvas.js +180 -0
- package/dist/components/card.d.ts +43 -0
- package/dist/components/card.js +42 -0
- package/dist/components/carousel.d.ts +57 -0
- package/dist/components/carousel.js +422 -0
- package/dist/components/chart.d.ts +112 -0
- package/dist/components/chart.js +172 -0
- package/dist/components/chat-confirmation.d.ts +42 -0
- package/dist/components/chat-confirmation.js +62 -0
- package/dist/components/chat-input.d.ts +94 -0
- package/dist/components/chat-input.js +279 -0
- package/dist/components/chat-plan.d.ts +21 -0
- package/dist/components/chat-plan.js +35 -0
- package/dist/components/chat-sources.d.ts +64 -0
- package/dist/components/chat-sources.js +66 -0
- package/dist/components/checkbox.d.ts +16 -0
- package/dist/components/checkbox.js +17 -0
- package/dist/components/choice-list.d.ts +53 -0
- package/dist/components/choice-list.js +36 -0
- package/dist/components/code-block.d.ts +35 -0
- package/dist/components/code-block.js +64 -0
- package/dist/components/collapsible.d.ts +24 -0
- package/dist/components/collapsible.js +27 -0
- package/dist/components/combobox.d.ts +95 -0
- package/dist/components/combobox.js +106 -0
- package/dist/components/command.d.ts +94 -0
- package/dist/components/command.js +414 -0
- package/dist/components/context-menu.d.ts +57 -0
- package/dist/components/context-menu.js +60 -0
- package/dist/components/dialog.d.ts +60 -0
- package/dist/components/dialog.js +79 -0
- package/dist/components/direction.d.ts +6 -0
- package/dist/components/direction.js +6 -0
- package/dist/components/dropdown-menu.d.ts +62 -0
- package/dist/components/dropdown-menu.js +59 -0
- package/dist/components/field.d.ts +117 -0
- package/dist/components/field.js +150 -0
- package/dist/components/file-explorer.d.ts +27 -0
- package/dist/components/file-explorer.js +300 -0
- package/dist/components/file-viewer.d.ts +137 -0
- package/dist/components/file-viewer.js +400 -0
- package/dist/components/form.d.ts +87 -0
- package/dist/components/form.js +55 -0
- package/dist/components/glass-banner.d.ts +27 -0
- package/dist/components/glass-banner.js +116 -0
- package/dist/components/gradient-banner.d.ts +37 -0
- package/dist/components/gradient-banner.js +43 -0
- package/dist/components/hover-card.d.ts +27 -0
- package/dist/components/hover-card.js +26 -0
- package/dist/components/input-group.d.ts +68 -0
- package/dist/components/input-group.js +88 -0
- package/dist/components/input-otp.d.ts +38 -0
- package/dist/components/input-otp.js +43 -0
- package/dist/components/input.d.ts +16 -0
- package/dist/components/input.js +18 -0
- package/dist/components/kbd.d.ts +12 -0
- package/dist/components/kbd.js +11 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.js +10 -0
- package/dist/components/mention-list.d.ts +54 -0
- package/dist/components/mention-list.js +31 -0
- package/dist/components/menubar.d.ts +64 -0
- package/dist/components/menubar.js +68 -0
- package/dist/components/message-actions.d.ts +34 -0
- package/dist/components/message-actions.js +68 -0
- package/dist/components/message-response.d.ts +20 -0
- package/dist/components/message-response.js +46 -0
- package/dist/components/message-scroller.d.ts +71 -0
- package/dist/components/message-scroller.js +217 -0
- package/dist/components/message.d.ts +49 -0
- package/dist/components/message.js +59 -0
- package/dist/components/navigation-menu.d.ts +45 -0
- package/dist/components/navigation-menu.js +54 -0
- package/dist/components/notice-banner.d.ts +14 -0
- package/dist/components/notice-banner.js +11 -0
- package/dist/components/page-content.d.ts +7 -0
- package/dist/components/page-content.js +9 -0
- package/dist/components/page-header.d.ts +37 -0
- package/dist/components/page-header.js +53 -0
- package/dist/components/pagination.d.ts +29 -0
- package/dist/components/pagination.js +29 -0
- package/dist/components/plan-outline.d.ts +60 -0
- package/dist/components/plan-outline.js +108 -0
- package/dist/components/popover.d.ts +34 -0
- package/dist/components/popover.js +35 -0
- package/dist/components/progress.d.ts +27 -0
- package/dist/components/progress.js +35 -0
- package/dist/components/prompt-list.d.ts +23 -0
- package/dist/components/prompt-list.js +11 -0
- package/dist/components/questionnaire.d.ts +148 -0
- package/dist/components/questionnaire.js +1002 -0
- package/dist/components/radio-group.d.ts +16 -0
- package/dist/components/radio-group.js +21 -0
- package/dist/components/reasoning-effort.d.ts +24 -0
- package/dist/components/reasoning-effort.js +269 -0
- package/dist/components/resizable.d.ts +67 -0
- package/dist/components/resizable.js +536 -0
- package/dist/components/result-card.d.ts +58 -0
- package/dist/components/result-card.js +88 -0
- package/dist/components/review-card.d.ts +62 -0
- package/dist/components/review-card.js +49 -0
- package/dist/components/rich-text-editor.d.ts +51 -0
- package/dist/components/rich-text-editor.js +248 -0
- package/dist/components/schema-diagram.d.ts +52 -0
- package/dist/components/schema-diagram.js +226 -0
- package/dist/components/scroll-area.d.ts +22 -0
- package/dist/components/scroll-area.js +19 -0
- package/dist/components/search-dialog.d.ts +103 -0
- package/dist/components/search-dialog.js +65 -0
- package/dist/components/search-field.d.ts +17 -0
- package/dist/components/search-field.js +27 -0
- package/dist/components/select.d.ts +57 -0
- package/dist/components/select.js +57 -0
- package/dist/components/selection-slot.d.ts +18 -0
- package/dist/components/selection-slot.js +53 -0
- package/dist/components/separator.d.ts +48 -0
- package/dist/components/separator.js +54 -0
- package/dist/components/settings-list.d.ts +26 -0
- package/dist/components/settings-list.js +17 -0
- package/dist/components/sheet.d.ts +70 -0
- package/dist/components/sheet.js +77 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.js +187 -0
- package/dist/components/skeleton.d.ts +31 -0
- package/dist/components/skeleton.js +32 -0
- package/dist/components/slider.d.ts +17 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/spinner.d.ts +37 -0
- package/dist/components/spinner.js +43 -0
- package/dist/components/state-panel-samples.d.ts +25 -0
- package/dist/components/state-panel-samples.js +423 -0
- package/dist/components/state-panel.d.ts +35 -0
- package/dist/components/state-panel.js +29 -0
- package/dist/components/state-sample.d.ts +63 -0
- package/dist/components/state-sample.js +42 -0
- package/dist/components/switch.d.ts +12 -0
- package/dist/components/switch.js +14 -0
- package/dist/components/table-nuqs.d.ts +16 -0
- package/dist/components/table-nuqs.js +59 -0
- package/dist/components/table.d.ts +120 -0
- package/dist/components/table.js +663 -0
- package/dist/components/tabs.d.ts +37 -0
- package/dist/components/tabs.js +36 -0
- package/dist/components/textarea.d.ts +18 -0
- package/dist/components/textarea.js +19 -0
- package/dist/components/toast.d.ts +45 -0
- package/dist/components/toast.js +83 -0
- package/dist/components/toggle-group.d.ts +30 -0
- package/dist/components/toggle-group.js +39 -0
- package/dist/components/toggle.d.ts +27 -0
- package/dist/components/toggle.js +21 -0
- package/dist/components/tool-activity.d.ts +79 -0
- package/dist/components/tool-activity.js +226 -0
- package/dist/components/toolbar-status.d.ts +21 -0
- package/dist/components/toolbar-status.js +14 -0
- package/dist/components/tooltip.d.ts +31 -0
- package/dist/components/tooltip.js +99 -0
- package/dist/components/typed-text.d.ts +17 -0
- package/dist/components/typed-text.js +56 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +90 -0
- package/dist/internal/brand-glyphs.d.ts +370 -0
- package/dist/internal/brand-glyphs.js +262 -0
- package/dist/internal/classes.d.ts +3 -0
- package/dist/internal/classes.js +20 -0
- package/dist/internal/code-tokens.d.ts +4 -0
- package/dist/internal/code-tokens.js +34 -0
- package/dist/internal/fieldset.d.ts +6 -0
- package/dist/internal/fieldset.js +38 -0
- package/dist/internal/file-kind.d.ts +4 -0
- package/dist/internal/file-kind.js +62 -0
- package/dist/internal/languages.d.ts +7 -0
- package/dist/internal/languages.js +1010 -0
- package/dist/internal/message-scroller.d.ts +102 -0
- package/dist/internal/message-scroller.js +637 -0
- package/dist/internal/pressable.d.ts +2 -0
- package/dist/internal/pressable.js +29 -0
- package/dist/internal/syntax.d.ts +14 -0
- package/dist/internal/syntax.js +137 -0
- package/dist/styles/accordion.css +102 -0
- package/dist/styles/alert-dialog.css +198 -0
- package/dist/styles/alert.css +149 -0
- package/dist/styles/aspect-ratio.css +8 -0
- package/dist/styles/attachment.css +700 -0
- package/dist/styles/avatar.css +186 -0
- package/dist/styles/badge.css +178 -0
- package/dist/styles/brand-icon.css +104 -0
- package/dist/styles/breadcrumb.css +121 -0
- package/dist/styles/button-group.css +113 -0
- package/dist/styles/button.css +380 -0
- package/dist/styles/calendar.css +295 -0
- package/dist/styles/canvas.css +313 -0
- package/dist/styles/card.css +146 -0
- package/dist/styles/carousel.css +107 -0
- package/dist/styles/chart.css +227 -0
- package/dist/styles/chat-confirmation.css +29 -0
- package/dist/styles/chat-input.css +240 -0
- package/dist/styles/chat-plan.css +109 -0
- package/dist/styles/chat-sources.css +191 -0
- package/dist/styles/checkbox.css +122 -0
- package/dist/styles/choice-list.css +343 -0
- package/dist/styles/code-block.css +211 -0
- package/dist/styles/collapsible.css +72 -0
- package/dist/styles/combobox.css +347 -0
- package/dist/styles/command.css +233 -0
- package/dist/styles/context-menu.css +151 -0
- package/dist/styles/dialog.css +237 -0
- package/dist/styles/dropdown-menu.css +150 -0
- package/dist/styles/field.css +340 -0
- package/dist/styles/file-explorer.css +517 -0
- package/dist/styles/file-viewer.css +375 -0
- package/dist/styles/form.css +155 -0
- package/dist/styles/glass-banner.css +308 -0
- package/dist/styles/gradient-banner.css +256 -0
- package/dist/styles/hover-card.css +95 -0
- package/dist/styles/index.css +268 -0
- package/dist/styles/input-group.css +285 -0
- package/dist/styles/input-otp.css +138 -0
- package/dist/styles/input.css +98 -0
- package/dist/styles/kbd.css +59 -0
- package/dist/styles/label.css +89 -0
- package/dist/styles/mention-list.css +166 -0
- package/dist/styles/menubar.css +226 -0
- package/dist/styles/message-actions.css +83 -0
- package/dist/styles/message-response.css +176 -0
- package/dist/styles/message-scroller.css +136 -0
- package/dist/styles/message.css +310 -0
- package/dist/styles/navigation-menu.css +291 -0
- package/dist/styles/notice-banner.css +68 -0
- package/dist/styles/page-content.css +21 -0
- package/dist/styles/page-header.css +156 -0
- package/dist/styles/pagination.css +72 -0
- package/dist/styles/plan-outline.css +393 -0
- package/dist/styles/popover.css +140 -0
- package/dist/styles/progress.css +93 -0
- package/dist/styles/prompt-list.css +165 -0
- package/dist/styles/questionnaire.css +308 -0
- package/dist/styles/radio-group.css +119 -0
- package/dist/styles/reasoning-effort.css +157 -0
- package/dist/styles/resizable.css +108 -0
- package/dist/styles/result-card.css +215 -0
- package/dist/styles/review-card.css +235 -0
- package/dist/styles/rich-text-editor.css +169 -0
- package/dist/styles/schema-diagram.css +419 -0
- package/dist/styles/scroll-area.css +77 -0
- package/dist/styles/search-dialog.css +280 -0
- package/dist/styles/search-field.css +17 -0
- package/dist/styles/select.css +285 -0
- package/dist/styles/selection-slot.css +31 -0
- package/dist/styles/separator.css +206 -0
- package/dist/styles/settings-list.css +81 -0
- package/dist/styles/sheet.css +361 -0
- package/dist/styles/sidebar.css +363 -0
- package/dist/styles/skeleton.css +80 -0
- package/dist/styles/slider.css +142 -0
- package/dist/styles/spinner.css +39 -0
- package/dist/styles/state-panel-samples.css +41 -0
- package/dist/styles/state-panel.css +173 -0
- package/dist/styles/state-sample.css +285 -0
- package/dist/styles/switch.css +128 -0
- package/dist/styles/table.css +604 -0
- package/dist/styles/tabs.css +223 -0
- package/dist/styles/textarea.css +77 -0
- package/dist/styles/themes/chatgpt.css +125 -0
- package/dist/styles/themes/claude.css +125 -0
- package/dist/styles/themes/cloudflare.css +125 -0
- package/dist/styles/themes/discord.css +125 -0
- package/dist/styles/themes/github.css +125 -0
- package/dist/styles/themes/grok.css +125 -0
- package/dist/styles/themes/linear.css +126 -0
- package/dist/styles/themes/neutral.css +125 -0
- package/dist/styles/themes/notion.css +125 -0
- package/dist/styles/themes/perplexity.css +125 -0
- package/dist/styles/themes/raycast.css +125 -0
- package/dist/styles/themes/spotify.css +125 -0
- package/dist/styles/themes/stripe.css +125 -0
- package/dist/styles/themes/supabase.css +125 -0
- package/dist/styles/themes/tulipfarm.css +115 -0
- package/dist/styles/themes/vercel.css +126 -0
- package/dist/styles/toast.css +197 -0
- package/dist/styles/toggle-group.css +161 -0
- package/dist/styles/toggle.css +119 -0
- package/dist/styles/tool-activity.css +396 -0
- package/dist/styles/toolbar-status.css +52 -0
- package/dist/styles/tooltip.css +122 -0
- package/dist/styles/typed-text.css +17 -0
- package/package.json +452 -4
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
+
import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from "@dnd-kit/core";
|
|
5
|
+
import { SortableContext, arrayMove, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable";
|
|
6
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
7
|
+
import { aggregationFn_count, aggregationFn_max, aggregationFn_mean, aggregationFn_min, aggregationFn_sum, columnFilteringFeature, columnGroupingFeature, columnOrderingFeature, columnPinningFeature, columnResizingFeature, columnSizingFeature, columnVisibilityFeature, constructFilterFn, createExpandedRowModel, createFilteredRowModel, createGroupedRowModel, createPaginatedRowModel, createSortedRowModel, filterFn_equals, filterFn_inDateRange, filterFn_inNumberRange, filterFn_includesString, functionalUpdate, globalFilteringFeature, rowAggregationFeature, rowExpandingFeature, rowPaginationFeature, rowSelectionFeature, rowSortingFeature, sortFn_alphanumeric, sortFn_basic, sortFn_datetime, sortFn_text, tableFeatures, useTable, } from "@tanstack/react-table";
|
|
8
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
9
|
+
import { ArrowDown } from "reicon-react/icons/ArrowDown";
|
|
10
|
+
import { ArrowUp } from "reicon-react/icons/ArrowUp";
|
|
11
|
+
import { ChevronDown } from "reicon-react/icons/ChevronDown";
|
|
12
|
+
import { ChevronRight } from "reicon-react/icons/ChevronRight";
|
|
13
|
+
import { InfoCircle } from "reicon-react/icons/InfoCircle";
|
|
14
|
+
import { Plus } from "reicon-react/icons/Plus";
|
|
15
|
+
import { Reorder } from "reicon-react/icons/Reorder";
|
|
16
|
+
import { SortV } from "reicon-react/icons/SortV";
|
|
17
|
+
import { X } from "reicon-react/icons/X";
|
|
18
|
+
import { cn } from "../internal/classes.js";
|
|
19
|
+
import { Button } from "./button.js";
|
|
20
|
+
import { Checkbox } from "./checkbox.js";
|
|
21
|
+
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./dropdown-menu.js";
|
|
22
|
+
import { Input } from "./input.js";
|
|
23
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
24
|
+
import { ScrollArea } from "./scroll-area.js";
|
|
25
|
+
import { SearchField } from "./search-field.js";
|
|
26
|
+
import { Skeleton } from "./skeleton.js";
|
|
27
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./tooltip.js";
|
|
28
|
+
export const tableVariantNames = ["plain", "grid"];
|
|
29
|
+
export const tableNarrowNames = ["scroll", "stack"];
|
|
30
|
+
export const tableAlignNames = ["left", "right"];
|
|
31
|
+
export const tableFilterNames = [
|
|
32
|
+
"text",
|
|
33
|
+
"number",
|
|
34
|
+
"select",
|
|
35
|
+
"date",
|
|
36
|
+
"boolean",
|
|
37
|
+
];
|
|
38
|
+
export const tableEditNames = [
|
|
39
|
+
"text",
|
|
40
|
+
"number",
|
|
41
|
+
"select",
|
|
42
|
+
"date",
|
|
43
|
+
"checkbox",
|
|
44
|
+
];
|
|
45
|
+
export const tableAggregateNames = [
|
|
46
|
+
"sum",
|
|
47
|
+
"count",
|
|
48
|
+
"min",
|
|
49
|
+
"max",
|
|
50
|
+
"mean",
|
|
51
|
+
];
|
|
52
|
+
export const tableLayoutKeys = [
|
|
53
|
+
"columnSizing",
|
|
54
|
+
"columnOrder",
|
|
55
|
+
"columnPinning",
|
|
56
|
+
"columnVisibility",
|
|
57
|
+
];
|
|
58
|
+
// dnd-kit's live region is a div; inside <table> it breaks the table roles.
|
|
59
|
+
const dndAccessibility = {
|
|
60
|
+
container: typeof document === "undefined" ? undefined : document.body,
|
|
61
|
+
};
|
|
62
|
+
const isAnyOf = constructFilterFn({
|
|
63
|
+
filter: (dataValue, filterValue) => filterValue.includes(String(dataValue)),
|
|
64
|
+
autoRemove: (value) => !value?.length,
|
|
65
|
+
});
|
|
66
|
+
const features = tableFeatures({
|
|
67
|
+
columnFilteringFeature,
|
|
68
|
+
globalFilteringFeature,
|
|
69
|
+
rowSortingFeature,
|
|
70
|
+
columnGroupingFeature,
|
|
71
|
+
rowAggregationFeature,
|
|
72
|
+
rowExpandingFeature,
|
|
73
|
+
rowPaginationFeature,
|
|
74
|
+
rowSelectionFeature,
|
|
75
|
+
columnVisibilityFeature,
|
|
76
|
+
columnOrderingFeature,
|
|
77
|
+
columnPinningFeature,
|
|
78
|
+
columnSizingFeature,
|
|
79
|
+
columnResizingFeature,
|
|
80
|
+
filteredRowModel: createFilteredRowModel(),
|
|
81
|
+
sortedRowModel: createSortedRowModel(),
|
|
82
|
+
groupedRowModel: createGroupedRowModel(),
|
|
83
|
+
expandedRowModel: createExpandedRowModel(),
|
|
84
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
85
|
+
filterFns: {
|
|
86
|
+
includesString: filterFn_includesString,
|
|
87
|
+
inNumberRange: filterFn_inNumberRange,
|
|
88
|
+
inDateRange: filterFn_inDateRange,
|
|
89
|
+
equals: filterFn_equals,
|
|
90
|
+
isAnyOf,
|
|
91
|
+
},
|
|
92
|
+
sortFns: {
|
|
93
|
+
alphanumeric: sortFn_alphanumeric,
|
|
94
|
+
text: sortFn_text,
|
|
95
|
+
datetime: sortFn_datetime,
|
|
96
|
+
basic: sortFn_basic,
|
|
97
|
+
},
|
|
98
|
+
aggregationFns: {
|
|
99
|
+
sum: aggregationFn_sum,
|
|
100
|
+
count: aggregationFn_count,
|
|
101
|
+
min: aggregationFn_min,
|
|
102
|
+
max: aggregationFn_max,
|
|
103
|
+
mean: aggregationFn_mean,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
const filterFnFor = {
|
|
107
|
+
text: "includesString",
|
|
108
|
+
number: "inNumberRange",
|
|
109
|
+
select: "isAnyOf",
|
|
110
|
+
date: "inDateRange",
|
|
111
|
+
boolean: "equals",
|
|
112
|
+
};
|
|
113
|
+
const DEFAULT_PAGE_SIZE = 10;
|
|
114
|
+
const pageResetKeys = new Set([
|
|
115
|
+
"sorting",
|
|
116
|
+
"columnFilters",
|
|
117
|
+
"globalFilter",
|
|
118
|
+
"grouping",
|
|
119
|
+
]);
|
|
120
|
+
function initialState(columns, pageSize) {
|
|
121
|
+
return {
|
|
122
|
+
sorting: [],
|
|
123
|
+
columnFilters: [],
|
|
124
|
+
globalFilter: "",
|
|
125
|
+
grouping: [],
|
|
126
|
+
expanded: true,
|
|
127
|
+
pagination: { pageIndex: 0, pageSize: pageSize ?? DEFAULT_PAGE_SIZE },
|
|
128
|
+
columnSizing: {},
|
|
129
|
+
columnOrder: [],
|
|
130
|
+
columnPinning: {
|
|
131
|
+
start: columns.filter((c) => c.pin === "left").map((c) => c.key),
|
|
132
|
+
end: columns.filter((c) => c.pin === "right").map((c) => c.key),
|
|
133
|
+
},
|
|
134
|
+
columnVisibility: Object.fromEntries(columns.filter((c) => c.hidden).map((c) => [c.key, false])),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const storageKey = (key) => `sprout-table:${key}`;
|
|
138
|
+
function readLayout(key) {
|
|
139
|
+
try {
|
|
140
|
+
const raw = localStorage.getItem(storageKey(key));
|
|
141
|
+
return raw ? JSON.parse(raw) : {};
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function writeLayout(key, state) {
|
|
148
|
+
try {
|
|
149
|
+
localStorage.setItem(storageKey(key), JSON.stringify(Object.fromEntries(tableLayoutKeys.map((k) => [k, state[k]]))));
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Storage can be full or blocked; the Layout then lasts for this visit only.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A data table. Pass rows and column settings; it renders the header, body,
|
|
157
|
+
* Toolbar, and footer, and runs sorting, filtering, grouping, selection,
|
|
158
|
+
* paging, Row edit, and Layout changes for you.
|
|
159
|
+
*/
|
|
160
|
+
export function Table(props) {
|
|
161
|
+
const { data, columns, getRowId, rowLabel = getRowId, variant = "plain", narrow = "scroll", caption, manual = false, rowCount, onStateChange, persistKey, searchable = false, columnMenu = false, resizable = false, reorderable = false, selectable = false, onSelectionChange, pageSize, virtual = false, onRowReorder, getSubRows, onRowSave, getRowHref, onRowClick, onRowDrop, actions, loading = false, empty, className, } = props;
|
|
162
|
+
const label = props["aria-label"];
|
|
163
|
+
const [inner, setInner] = useState(() => initialState(columns, pageSize));
|
|
164
|
+
const state = { ...inner, ...props.state };
|
|
165
|
+
const stateRef = useRef(state);
|
|
166
|
+
stateRef.current = state;
|
|
167
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
168
|
+
const [editing, setEditing] = useState(null);
|
|
169
|
+
const [dropTarget, setDropTarget] = useState(null);
|
|
170
|
+
const [pinOffsets, setPinOffsets] = useState({});
|
|
171
|
+
const headRowRef = useRef(null);
|
|
172
|
+
const anchorRef = useRef(null);
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
if (!persistKey)
|
|
175
|
+
return;
|
|
176
|
+
const saved = readLayout(persistKey);
|
|
177
|
+
if (Object.keys(saved).length)
|
|
178
|
+
setInner((prev) => ({ ...prev, ...saved }));
|
|
179
|
+
}, [persistKey]);
|
|
180
|
+
const setSlice = (key) => (updater) => {
|
|
181
|
+
const next = {
|
|
182
|
+
...stateRef.current,
|
|
183
|
+
[key]: functionalUpdate(updater, stateRef.current[key]),
|
|
184
|
+
};
|
|
185
|
+
if (pageResetKeys.has(key) && next.pagination.pageIndex !== 0) {
|
|
186
|
+
next.pagination = { ...next.pagination, pageIndex: 0 };
|
|
187
|
+
}
|
|
188
|
+
stateRef.current = next;
|
|
189
|
+
setInner(next);
|
|
190
|
+
if (persistKey && tableLayoutKeys.includes(key)) {
|
|
191
|
+
writeLayout(persistKey, next);
|
|
192
|
+
}
|
|
193
|
+
onStateChange?.(next);
|
|
194
|
+
};
|
|
195
|
+
const byKey = useMemo(() => new Map(columns.map((c) => [c.key, c])), [columns]);
|
|
196
|
+
const columnDefs = useMemo(() => columns.map((c) => ({
|
|
197
|
+
id: c.key,
|
|
198
|
+
accessorFn: (row) => row[c.key],
|
|
199
|
+
header: c.header,
|
|
200
|
+
enableSorting: c.sort ?? false,
|
|
201
|
+
sortDescFirst: false,
|
|
202
|
+
enableColumnFilter: !!c.filter,
|
|
203
|
+
enableGrouping: c.group ?? false,
|
|
204
|
+
...(c.filter ? { filterFn: filterFnFor[c.filter] } : {}),
|
|
205
|
+
...(c.aggregate ? { aggregationFn: c.aggregate } : {}),
|
|
206
|
+
...(c.width ? { size: c.width } : {}),
|
|
207
|
+
})), [columns]);
|
|
208
|
+
const table = useTable({
|
|
209
|
+
features,
|
|
210
|
+
columns: columnDefs,
|
|
211
|
+
data,
|
|
212
|
+
getRowId,
|
|
213
|
+
...(getSubRows ? { getSubRows } : {}),
|
|
214
|
+
state: { ...state, rowSelection },
|
|
215
|
+
onSortingChange: setSlice("sorting"),
|
|
216
|
+
onColumnFiltersChange: setSlice("columnFilters"),
|
|
217
|
+
onGlobalFilterChange: setSlice("globalFilter"),
|
|
218
|
+
onGroupingChange: setSlice("grouping"),
|
|
219
|
+
onExpandedChange: setSlice("expanded"),
|
|
220
|
+
onPaginationChange: setSlice("pagination"),
|
|
221
|
+
onColumnSizingChange: setSlice("columnSizing"),
|
|
222
|
+
onColumnOrderChange: setSlice("columnOrder"),
|
|
223
|
+
onColumnPinningChange: setSlice("columnPinning"),
|
|
224
|
+
onColumnVisibilityChange: setSlice("columnVisibility"),
|
|
225
|
+
onRowSelectionChange: (updater) => {
|
|
226
|
+
const next = functionalUpdate(updater, rowSelection);
|
|
227
|
+
setRowSelection(next);
|
|
228
|
+
onSelectionChange?.(Object.keys(next).filter((id) => next[id]));
|
|
229
|
+
},
|
|
230
|
+
globalFilterFn: "includesString",
|
|
231
|
+
groupedColumnMode: "remove",
|
|
232
|
+
// The reset would use TanStack's empty default, closing every group on each search.
|
|
233
|
+
autoResetExpanded: false,
|
|
234
|
+
// TanStack resets on every new state array (inline or URL state) and never in manual mode; setSlice resets instead.
|
|
235
|
+
autoResetPageIndex: false,
|
|
236
|
+
columnResizeMode: "onChange",
|
|
237
|
+
enableMultiSort: true,
|
|
238
|
+
manualSorting: manual,
|
|
239
|
+
manualFiltering: manual,
|
|
240
|
+
manualPagination: manual || !pageSize,
|
|
241
|
+
...(rowCount !== undefined ? { rowCount } : {}),
|
|
242
|
+
});
|
|
243
|
+
const rows = table.getRowModel().rows;
|
|
244
|
+
// getVisibleLeafColumns keeps the column order but ignores pinning; the header follows pinning.
|
|
245
|
+
const leafColumns = [
|
|
246
|
+
...table.getStartVisibleLeafColumns(),
|
|
247
|
+
...table.getCenterVisibleLeafColumns(),
|
|
248
|
+
...table.getEndVisibleLeafColumns(),
|
|
249
|
+
];
|
|
250
|
+
const editable = !!onRowSave && columns.some((c) => c.edit);
|
|
251
|
+
const hasActions = !!actions || editable;
|
|
252
|
+
const draggableRows = !!onRowReorder &&
|
|
253
|
+
state.sorting.length === 0 &&
|
|
254
|
+
state.grouping.length === 0 &&
|
|
255
|
+
state.columnFilters.length === 0 &&
|
|
256
|
+
!state.globalFilter;
|
|
257
|
+
const totals = columns.some((c) => c.aggregate) && !loading && rows.length > 0;
|
|
258
|
+
const colSpan = leafColumns.length +
|
|
259
|
+
(selectable ? 1 : 0) +
|
|
260
|
+
(onRowReorder ? 1 : 0) +
|
|
261
|
+
(hasActions ? 1 : 0);
|
|
262
|
+
const sized = resizable || columns.some((c) => c.width);
|
|
263
|
+
const pinsStart = !!state.columnPinning.start?.length;
|
|
264
|
+
const pinned = pinsStart || !!state.columnPinning.end?.length;
|
|
265
|
+
const pinLayout = `${leafColumns.map((c) => `${c.id}:${c.getIsPinned()}`).join()}|${selectable}|${!!onRowReorder}|${hasActions}`;
|
|
266
|
+
useLayoutEffect(() => {
|
|
267
|
+
const row = headRowRef.current;
|
|
268
|
+
if (!pinned || !row)
|
|
269
|
+
return;
|
|
270
|
+
const observer = new ResizeObserver(() => {
|
|
271
|
+
const next = measurePinOffsets(Array.from(row.children));
|
|
272
|
+
setPinOffsets((prev) => JSON.stringify(prev) === JSON.stringify(next) ? prev : next);
|
|
273
|
+
});
|
|
274
|
+
for (const cell of row.children)
|
|
275
|
+
observer.observe(cell);
|
|
276
|
+
return () => observer.disconnect();
|
|
277
|
+
}, [pinned, pinLayout]);
|
|
278
|
+
const selectRow = (row, checked, range) => {
|
|
279
|
+
const ids = rows
|
|
280
|
+
.filter((r) => !r.getIsGrouped() && r.getCanSelect())
|
|
281
|
+
.map((r) => r.id);
|
|
282
|
+
const from = anchorRef.current ? ids.indexOf(anchorRef.current) : -1;
|
|
283
|
+
const to = ids.indexOf(row.id);
|
|
284
|
+
if (range && from !== -1 && to !== -1) {
|
|
285
|
+
const span = ids.slice(Math.min(from, to), Math.max(from, to) + 1);
|
|
286
|
+
table.setRowSelection((prev) => {
|
|
287
|
+
const next = { ...prev };
|
|
288
|
+
for (const id of span) {
|
|
289
|
+
if (checked)
|
|
290
|
+
next[id] = true;
|
|
291
|
+
else
|
|
292
|
+
delete next[id];
|
|
293
|
+
}
|
|
294
|
+
return next;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
row.toggleSelected(checked);
|
|
299
|
+
}
|
|
300
|
+
anchorRef.current = row.id;
|
|
301
|
+
};
|
|
302
|
+
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, {
|
|
303
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
304
|
+
}));
|
|
305
|
+
const scrollRef = useRef(null);
|
|
306
|
+
const virtualizer = useVirtualizer({
|
|
307
|
+
count: virtual ? rows.length : 0,
|
|
308
|
+
getScrollElement: () => scrollRef.current,
|
|
309
|
+
estimateSize: () => 41,
|
|
310
|
+
overscan: 8,
|
|
311
|
+
initialRect: { width: 0, height: 600 },
|
|
312
|
+
});
|
|
313
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
314
|
+
const visibleRows = virtual
|
|
315
|
+
? virtualItems.flatMap((item) => rows[item.index] ?? [])
|
|
316
|
+
: rows;
|
|
317
|
+
const paddingTop = virtual ? (virtualItems[0]?.start ?? 0) : 0;
|
|
318
|
+
const paddingBottom = virtual
|
|
319
|
+
? virtualizer.getTotalSize() - (virtualItems.at(-1)?.end ?? 0)
|
|
320
|
+
: 0;
|
|
321
|
+
const startEdit = (row) => setEditing({
|
|
322
|
+
id: row.id,
|
|
323
|
+
draft: Object.fromEntries(columns.filter((c) => c.edit).map((c) => [c.key, row.original[c.key]])),
|
|
324
|
+
});
|
|
325
|
+
const saveEdit = async (row) => {
|
|
326
|
+
if (!editing || !onRowSave)
|
|
327
|
+
return;
|
|
328
|
+
const changes = Object.fromEntries(Object.entries(editing.draft).filter(([key, value]) => row.original[key] !== value));
|
|
329
|
+
setEditing({ ...editing, saving: true });
|
|
330
|
+
try {
|
|
331
|
+
await onRowSave(row.original, changes);
|
|
332
|
+
setEditing(null);
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
setEditing({
|
|
336
|
+
...editing,
|
|
337
|
+
saving: false,
|
|
338
|
+
error: error instanceof Error ? error.message : String(error),
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
const onColumnDragEnd = ({ active, over }) => {
|
|
343
|
+
if (!over || active.id === over.id)
|
|
344
|
+
return;
|
|
345
|
+
const order = state.columnOrder.length
|
|
346
|
+
? state.columnOrder
|
|
347
|
+
: table.getAllLeafColumns().map((c) => c.id);
|
|
348
|
+
table.setColumnOrder(arrayMove(order, order.indexOf(String(active.id)), order.indexOf(String(over.id))));
|
|
349
|
+
};
|
|
350
|
+
const onRowDragEnd = ({ active, over }) => {
|
|
351
|
+
if (!over || active.id === over.id || !onRowReorder)
|
|
352
|
+
return;
|
|
353
|
+
const ids = data.map(getRowId);
|
|
354
|
+
onRowReorder(ids.indexOf(String(active.id)), ids.indexOf(String(over.id)));
|
|
355
|
+
};
|
|
356
|
+
const toolbar = searchable || columns.some((c) => c.filter || c.group) || columnMenu;
|
|
357
|
+
const allPageSelected = table.getIsAllPageRowsSelected();
|
|
358
|
+
const somePageSelected = table.getIsSomePageRowsSelected();
|
|
359
|
+
const stack = narrow === "stack";
|
|
360
|
+
const role = (value) => (stack ? value : undefined);
|
|
361
|
+
const header = (_jsx("thead", { "data-slot": "table-header", className: "sprout-table-header", role: role("rowgroup"), children: _jsx(DndContext, { sensors: sensors, accessibility: dndAccessibility, collisionDetection: closestCenter, onDragEnd: onColumnDragEnd, children: _jsx(SortableContext, { items: leafColumns.map((c) => c.id), strategy: horizontalListSortingStrategy, children: _jsxs("tr", { ref: headRowRef, "data-slot": "table-row", className: "sprout-table-row", role: role("row"), children: [onRowReorder && (_jsx("th", { className: "sprout-table-head", "data-selection": "", "data-column-id": "__reorder", role: role("columnheader"), children: _jsx("span", { className: "sprout-table-sr-only", children: "Reorder" }) })), selectable && (_jsx("th", { className: "sprout-table-head", "data-selection": "", "data-column-id": "__select", role: role("columnheader"), children: _jsx(Checkbox, { "aria-label": "Select all rows", checked: allPageSelected, indeterminate: !allPageSelected && somePageSelected, onCheckedChange: (checked) => table.toggleAllPageRowsSelected(checked) }) })), table
|
|
362
|
+
.getFlatHeaders()
|
|
363
|
+
.map((h) => h.column.getIsVisible() ? (_jsx(HeadCell, { header: h, config: byKey.get(h.column.id), resizable: resizable, reorderable: reorderable, sized: sized, role: role("columnheader") }, h.id)) : null), hasActions && (_jsx("th", { className: "sprout-table-head", "data-sticky-end": "", "data-column-id": "__actions", role: role("columnheader"), children: _jsx("span", { className: "sprout-table-sr-only", children: "Actions" }) }))] }) }) }) }));
|
|
364
|
+
const body = (_jsxs("tbody", { "data-slot": "table-body", className: "sprout-table-body", role: role("rowgroup"), children: [paddingTop > 0 && (_jsx("tr", { "aria-hidden": "true", children: _jsx("td", { colSpan: colSpan, style: { height: paddingTop, padding: 0 } }) })), loading ? (Array.from({ length: 3 }, (_, i) => (_jsxs("tr", { className: "sprout-table-row", "data-loading-row": "", role: role("row"), children: [onRowReorder && (_jsx("td", { className: "sprout-table-cell", "data-selection": "" })), selectable && (_jsx("td", { className: "sprout-table-cell", "data-selection": "", children: _jsx(Skeleton, { shape: "checkbox" }) })), leafColumns.map((c) => (_jsx("td", { className: "sprout-table-cell", role: role("cell"), children: _jsx(Skeleton, {}) }, c.id))), hasActions && (_jsx("td", { className: "sprout-table-cell", "data-sticky-end": "", children: _jsx(Skeleton, { shape: "action" }) }))] }, i)))) : rows.length === 0 ? (_jsx("tr", { className: "sprout-table-row", role: role("row"), children: _jsx("td", { className: "sprout-table-cell sprout-table-empty", colSpan: colSpan, role: role("cell"), children: empty ?? "No results." }) })) : (_jsx(DndContext, { sensors: sensors, accessibility: dndAccessibility, collisionDetection: closestCenter, onDragEnd: onRowDragEnd, children: _jsx(SortableContext, { items: rows.map((r) => r.id), strategy: verticalListSortingStrategy, children: visibleRows.map((row) => row.getIsGrouped() ? (_jsx(GroupRow, { row: row, columns: leafColumns, byKey: byKey, selectable: selectable, reorder: !!onRowReorder, hasActions: hasActions, rowIndex: virtual ? row.index + 2 : undefined, role: role }, row.id)) : (_jsx(BodyRow, { row: row, columns: leafColumns, byKey: byKey, label: rowLabel(row.original), selectable: selectable, onSelect: (checked, range) => selectRow(row, checked, range), reorder: onRowReorder ? draggableRows : undefined, editing: editing?.id === row.id ? editing : null, editable: editable, onEditChange: (key, value) => setEditing((prev) => prev && {
|
|
365
|
+
...prev,
|
|
366
|
+
draft: { ...prev.draft, [key]: value },
|
|
367
|
+
}), onEdit: () => startEdit(row), onSave: () => void saveEdit(row), onCancel: () => setEditing(null), actions: actions, hasActions: hasActions, href: getRowHref?.(row.original), onOpen: onRowClick ? () => onRowClick(row.original) : undefined, drop: onRowDrop
|
|
368
|
+
? {
|
|
369
|
+
active: dropTarget === row.id,
|
|
370
|
+
set: (on) => setDropTarget(on ? row.id : null),
|
|
371
|
+
onDrop: (files) => onRowDrop(row.original, files),
|
|
372
|
+
}
|
|
373
|
+
: undefined, colSpan: colSpan, rowIndex: virtual ? row.index + 2 : undefined, role: role }, row.id))) }) })), paddingBottom > 0 && (_jsx("tr", { "aria-hidden": "true", children: _jsx("td", { colSpan: colSpan, style: { height: paddingBottom, padding: 0 } }) }))] }));
|
|
374
|
+
const footer = totals && (_jsx("tfoot", { "data-slot": "table-footer", className: "sprout-table-footer", role: role("rowgroup"), children: _jsxs("tr", { className: "sprout-table-row", role: role("row"), children: [onRowReorder && _jsx("td", { className: "sprout-table-cell", "data-selection": "" }), selectable && _jsx("td", { className: "sprout-table-cell", "data-selection": "" }), leafColumns.map((c, index) => {
|
|
375
|
+
const config = byKey.get(c.id);
|
|
376
|
+
return (_jsx("td", { className: "sprout-table-cell", "data-align": config?.align ?? "left", "data-label": config?.header, role: role("cell"), style: pinStyle(c, sized, pinOffsets), "data-pinned": c.getIsPinned() || undefined, children: config?.aggregate
|
|
377
|
+
? formatAggregate(config, c.getAggregationValue())
|
|
378
|
+
: index === 0
|
|
379
|
+
? "Total"
|
|
380
|
+
: null }, c.id));
|
|
381
|
+
}), hasActions && _jsx("td", { className: "sprout-table-cell", "data-sticky-end": "" })] }) }));
|
|
382
|
+
const tableElement = (_jsxs("table", { "data-slot": "table", "data-variant": variant, "data-narrow": narrow, "data-sized": sized || undefined, "data-pin-start": pinsStart || undefined, className: "sprout-table", "aria-label": label, "aria-rowcount": virtual ? rows.length + 1 : undefined, "aria-busy": loading || undefined, role: role("table"), style: {
|
|
383
|
+
...(sized ? { minWidth: table.getTotalSize() } : {}),
|
|
384
|
+
...(pinOffsets.__select !== undefined
|
|
385
|
+
? { "--sprout-table-select-start": `${pinOffsets.__select}px` }
|
|
386
|
+
: {}),
|
|
387
|
+
}, children: [caption && (_jsx("caption", { "data-slot": "table-caption", className: "sprout-table-caption", children: caption })), _jsxs(PinOffsetsContext, { value: pinOffsets, children: [header, body] }), footer] }));
|
|
388
|
+
const pageCount = table.getPageCount();
|
|
389
|
+
return (_jsx(TooltipProvider, { children: _jsxs("div", { "data-slot": "table-root", className: cn("sprout-table-root", className), children: [toolbar && (_jsx(Toolbar, { table: table, columns: columns, label: label, searchable: searchable, columnMenu: columnMenu, onReset: () => {
|
|
390
|
+
const reset = initialState(columns, pageSize);
|
|
391
|
+
for (const key of tableLayoutKeys)
|
|
392
|
+
setSlice(key)(reset[key]);
|
|
393
|
+
} })), virtual ? (_jsx("div", { ref: scrollRef, "data-slot": "table-container", "data-virtual": "", className: "sprout-table-container", tabIndex: 0, role: "region", "aria-label": label, children: tableElement })) : variant === "grid" ? (_jsx(ScrollArea, { variant: "table", orientation: "both", viewportLabel: label, "data-slot": "table-container", children: tableElement })) : (_jsx(PlainContainer, { label: label, children: tableElement })), pageSize && pageCount > 1 && (_jsxs("nav", { className: "sprout-table-pages", "aria-label": `${label} pages`, children: [_jsxs("span", { "aria-live": "polite", children: ["Page ", state.pagination.pageIndex + 1, " of ", pageCount] }), _jsx(Button, { variant: "outline", size: "sm", disabled: !table.getCanPreviousPage(), onClick: () => table.previousPage(), children: "Previous" }), _jsx(Button, { variant: "outline", size: "sm", disabled: !table.getCanNextPage(), onClick: () => table.nextPage(), children: "Next" })] }))] }) }));
|
|
394
|
+
}
|
|
395
|
+
const PinOffsetsContext = createContext({});
|
|
396
|
+
/** Sticky offsets from the real header cell widths, so columns without a set width pin in the right place. */
|
|
397
|
+
function measurePinOffsets(cells) {
|
|
398
|
+
const offsets = {};
|
|
399
|
+
let start = 0;
|
|
400
|
+
for (const cell of cells) {
|
|
401
|
+
const id = cell.dataset.columnId;
|
|
402
|
+
if (!id ||
|
|
403
|
+
(cell.dataset.selection === undefined && cell.dataset.pinned !== "start"))
|
|
404
|
+
continue;
|
|
405
|
+
offsets[id] = start;
|
|
406
|
+
start += cell.getBoundingClientRect().width;
|
|
407
|
+
}
|
|
408
|
+
let end = 0;
|
|
409
|
+
for (const cell of [...cells].reverse()) {
|
|
410
|
+
const id = cell.dataset.columnId;
|
|
411
|
+
if (!id ||
|
|
412
|
+
(cell.dataset.stickyEnd === undefined && cell.dataset.pinned !== "end"))
|
|
413
|
+
continue;
|
|
414
|
+
offsets[id] = end;
|
|
415
|
+
end += cell.getBoundingClientRect().width;
|
|
416
|
+
}
|
|
417
|
+
return offsets;
|
|
418
|
+
}
|
|
419
|
+
function pinStyle(column, sized, offsets) {
|
|
420
|
+
const pinned = column.getIsPinned();
|
|
421
|
+
const width = sized ? column.getSize() : undefined;
|
|
422
|
+
if (!pinned)
|
|
423
|
+
return width ? { width } : undefined;
|
|
424
|
+
return pinned === "start"
|
|
425
|
+
? {
|
|
426
|
+
width,
|
|
427
|
+
insetInlineStart: offsets[column.id] ?? column.getStart("start"),
|
|
428
|
+
}
|
|
429
|
+
: { width, insetInlineEnd: offsets[column.id] ?? column.getAfter("end") };
|
|
430
|
+
}
|
|
431
|
+
function formatAggregate(config, value) {
|
|
432
|
+
if (typeof value !== "number")
|
|
433
|
+
return null;
|
|
434
|
+
return config.formatAggregate
|
|
435
|
+
? config.formatAggregate(value)
|
|
436
|
+
: value.toLocaleString();
|
|
437
|
+
}
|
|
438
|
+
/** Joins the Tab order only while the table is wider than its container, so keyboard users can scroll it. */
|
|
439
|
+
function PlainContainer({ label, children, }) {
|
|
440
|
+
const ref = useRef(null);
|
|
441
|
+
const [overflowing, setOverflowing] = useState(false);
|
|
442
|
+
useEffect(() => {
|
|
443
|
+
const element = ref.current;
|
|
444
|
+
if (!element || typeof ResizeObserver === "undefined")
|
|
445
|
+
return;
|
|
446
|
+
const measure = () => setOverflowing(element.scrollWidth > element.clientWidth);
|
|
447
|
+
measure();
|
|
448
|
+
const observer = new ResizeObserver(measure);
|
|
449
|
+
observer.observe(element);
|
|
450
|
+
if (element.firstElementChild)
|
|
451
|
+
observer.observe(element.firstElementChild);
|
|
452
|
+
return () => observer.disconnect();
|
|
453
|
+
}, []);
|
|
454
|
+
return (_jsx("div", { ref: ref, "data-slot": "table-container", "data-overflowing": overflowing || undefined, className: "sprout-table-container", tabIndex: overflowing ? 0 : undefined, role: overflowing ? "region" : undefined, "aria-label": overflowing ? label : undefined, children: children }));
|
|
455
|
+
}
|
|
456
|
+
function HeadCell({ header, config, resizable, reorderable, sized, role, }) {
|
|
457
|
+
const column = header.column;
|
|
458
|
+
const title = config?.header ?? column.id;
|
|
459
|
+
const align = config?.align ?? "left";
|
|
460
|
+
const sorted = column.getIsSorted();
|
|
461
|
+
const sortable = column.getCanSort();
|
|
462
|
+
const sortable_ = useSortable({ id: column.id, disabled: !reorderable });
|
|
463
|
+
const pinned = column.getIsPinned();
|
|
464
|
+
const offsets = useContext(PinOffsetsContext);
|
|
465
|
+
const style = {
|
|
466
|
+
...pinStyle(column, sized, offsets),
|
|
467
|
+
...(reorderable && sortable_.transform
|
|
468
|
+
? {
|
|
469
|
+
transform: CSS.Translate.toString(sortable_.transform),
|
|
470
|
+
transition: sortable_.transition,
|
|
471
|
+
}
|
|
472
|
+
: {}),
|
|
473
|
+
};
|
|
474
|
+
const next = column.getNextSortingOrder();
|
|
475
|
+
const hint = sorted === "asc"
|
|
476
|
+
? `, ascending. ${next === "desc" ? "Select for descending" : "Select to clear"}`
|
|
477
|
+
: sorted === "desc"
|
|
478
|
+
? `, descending. ${next === "asc" ? "Select for ascending" : "Select to clear"}`
|
|
479
|
+
: "";
|
|
480
|
+
const Icon = sorted === "asc" ? ArrowUp : sorted === "desc" ? ArrowDown : SortV;
|
|
481
|
+
const onResizeKey = (event) => {
|
|
482
|
+
const step = event.shiftKey ? 40 : 10;
|
|
483
|
+
const delta = event.key === "ArrowRight" ? step : event.key === "ArrowLeft" ? -step : 0;
|
|
484
|
+
if (!delta)
|
|
485
|
+
return;
|
|
486
|
+
event.preventDefault();
|
|
487
|
+
column.table.setColumnSizing((prev) => ({
|
|
488
|
+
...prev,
|
|
489
|
+
[column.id]: Math.max(48, column.getSize() + delta),
|
|
490
|
+
}));
|
|
491
|
+
};
|
|
492
|
+
return (_jsxs("th", { ref: reorderable ? sortable_.setNodeRef : undefined, "data-slot": "table-head", "data-align": align, "data-pinned": pinned || undefined, "data-column-id": column.id, "data-dragging": sortable_.isDragging || undefined, className: "sprout-table-head", "aria-sort": sorted === "asc"
|
|
493
|
+
? "ascending"
|
|
494
|
+
: sorted === "desc"
|
|
495
|
+
? "descending"
|
|
496
|
+
: undefined, role: role, style: style, children: [_jsxs("span", { className: "sprout-table-head-inner", children: [reorderable && (_jsx("button", { type: "button", className: "sprout-table-handle", "aria-label": `Move ${title} column`, ...sortable_.attributes, ...sortable_.listeners, children: _jsx(Reorder, { size: 14, "aria-hidden": "true" }) })), sortable ? (_jsxs(Button, { variant: sorted ? "secondary" : "ghost", size: align === "right" ? "column-header-end" : "column-header", "aria-label": `Sort by ${title}${hint}`, title: sorted ? undefined : "Sort ascending", onClick: column.getToggleSortingHandler(), children: [title, _jsx(Icon, { size: 14, "aria-hidden": "true" })] })) : (title), config?.hint && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx("button", { type: "button", "aria-label": `About ${title}`, className: "sprout-table-hint" }), children: _jsx(InfoCircle, { size: 14, "aria-hidden": "true" }) }), _jsx(TooltipContent, { children: config.hint })] }))] }), resizable && (_jsx("div", { role: "separator", "aria-orientation": "vertical", "aria-label": `Resize ${title} column`, "aria-valuenow": column.getSize(), "aria-valuemin": 48, tabIndex: 0, className: "sprout-table-resizer", "data-resizing": column.getIsResizing() || undefined, onMouseDown: header.getResizeHandler(), onTouchStart: header.getResizeHandler(), onKeyDown: onResizeKey, onDoubleClick: () => column.resetSize() }))] }));
|
|
497
|
+
}
|
|
498
|
+
function GroupRow({ row, columns, byKey, selectable, reorder, hasActions, rowIndex, role, }) {
|
|
499
|
+
const groupColumn = byKey.get(row.groupingColumnId ?? "");
|
|
500
|
+
const value = row.groupingValue;
|
|
501
|
+
const option = groupColumn?.options?.find((o) => o.value === String(value));
|
|
502
|
+
const name = option?.label ?? (value == null || value === "" ? "None" : String(value));
|
|
503
|
+
const expanded = row.getIsExpanded();
|
|
504
|
+
const leafRows = row.getLeafRows().filter((r) => !r.getIsGrouped());
|
|
505
|
+
const offsets = useContext(PinOffsetsContext);
|
|
506
|
+
return (_jsxs("tr", { "data-slot": "table-row", "data-group": "", className: "sprout-table-row", "aria-rowindex": rowIndex, role: role("row"), children: [reorder && _jsx("td", { className: "sprout-table-cell", "data-selection": "" }), selectable && _jsx("td", { className: "sprout-table-cell", "data-selection": "" }), columns.map((column, index) => {
|
|
507
|
+
const config = byKey.get(column.id);
|
|
508
|
+
return (_jsx("td", { className: "sprout-table-cell", "data-align": index === 0 ? "left" : (config?.align ?? "left"), "data-pinned": column.getIsPinned() || undefined, role: role("cell"), style: pinStyle(column, false, offsets), children: index === 0 ? (_jsxs("button", { type: "button", className: "sprout-table-toggle", "aria-expanded": expanded, onClick: row.getToggleExpandedHandler(), style: { paddingInlineStart: row.depth * 16 }, children: [expanded ? (_jsx(ChevronDown, { size: 14, "aria-hidden": "true" })) : (_jsx(ChevronRight, { size: 14, "aria-hidden": "true" })), _jsxs("span", { className: "sprout-table-group-name", children: [groupColumn?.header, ": ", name] }), _jsx("span", { className: "sprout-table-group-count", children: leafRows.length })] })) : config?.aggregate ? (formatAggregate(config, column.getAggregationValue({ rows: leafRows }))) : null }, column.id));
|
|
509
|
+
}), hasActions && _jsx("td", { className: "sprout-table-cell", "data-sticky-end": "" })] }));
|
|
510
|
+
}
|
|
511
|
+
function BodyRow({ row, columns, byKey, label, selectable, onSelect, reorder, editing, editable, onEditChange, onEdit, onSave, onCancel, actions, hasActions, href, onOpen, drop, colSpan, rowIndex, role, }) {
|
|
512
|
+
const sortable = useSortable({ id: row.id, disabled: !reorder });
|
|
513
|
+
const selected = row.getIsSelected();
|
|
514
|
+
const offsets = useContext(PinOffsetsContext);
|
|
515
|
+
const hasFiles = (event) => event.dataTransfer.types.includes("Files");
|
|
516
|
+
const onKeyDown = (event) => {
|
|
517
|
+
if (!editing)
|
|
518
|
+
return;
|
|
519
|
+
if (event.key === "Escape") {
|
|
520
|
+
event.preventDefault();
|
|
521
|
+
onCancel();
|
|
522
|
+
}
|
|
523
|
+
else if (event.key === "Enter" &&
|
|
524
|
+
event.target instanceof HTMLInputElement) {
|
|
525
|
+
event.preventDefault();
|
|
526
|
+
onSave();
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
return (_jsxs(_Fragment, { children: [_jsxs("tr", { ref: reorder !== undefined ? sortable.setNodeRef : undefined, "data-slot": "table-row", "data-state": selected ? "selected" : undefined, "data-editing": editing ? "" : undefined, "data-drop-target": drop?.active || undefined, "data-linked": href || onOpen ? "" : undefined, "data-dragging": sortable.isDragging || undefined, className: "sprout-table-row", "aria-rowindex": rowIndex, "aria-selected": selectable ? selected : undefined, role: role("row"), style: sortable.transform
|
|
530
|
+
? {
|
|
531
|
+
transform: CSS.Translate.toString(sortable.transform),
|
|
532
|
+
transition: sortable.transition,
|
|
533
|
+
}
|
|
534
|
+
: undefined, onKeyDown: onKeyDown, onDragOver: drop
|
|
535
|
+
? (event) => {
|
|
536
|
+
if (!hasFiles(event))
|
|
537
|
+
return;
|
|
538
|
+
event.preventDefault();
|
|
539
|
+
if (!drop.active)
|
|
540
|
+
drop.set(true);
|
|
541
|
+
}
|
|
542
|
+
: undefined, onDragLeave: drop
|
|
543
|
+
? (event) => {
|
|
544
|
+
if (!event.currentTarget.contains(event.relatedTarget))
|
|
545
|
+
drop.set(false);
|
|
546
|
+
}
|
|
547
|
+
: undefined, onDrop: drop
|
|
548
|
+
? (event) => {
|
|
549
|
+
if (!hasFiles(event))
|
|
550
|
+
return;
|
|
551
|
+
event.preventDefault();
|
|
552
|
+
drop.set(false);
|
|
553
|
+
drop.onDrop(Array.from(event.dataTransfer.files));
|
|
554
|
+
}
|
|
555
|
+
: undefined, children: [reorder !== undefined && (_jsx("td", { className: "sprout-table-cell", "data-selection": "", role: role("cell"), children: _jsx("button", { type: "button", className: "sprout-table-handle", "aria-label": `Move ${label}`, disabled: !reorder, title: reorder
|
|
556
|
+
? undefined
|
|
557
|
+
: "Clear sorting, filters, and grouping to reorder", ...sortable.attributes, ...sortable.listeners, children: _jsx(Reorder, { size: 14, "aria-hidden": "true" }) }) })), selectable && (_jsx("td", { className: "sprout-table-cell", "data-selection": "", role: role("cell"), children: _jsx(Checkbox, { "aria-label": `Select ${label}`, checked: selected, disabled: !row.getCanSelect(), onCheckedChange: (checked, details) => onSelect(checked, details.event.shiftKey ===
|
|
558
|
+
true) }) })), columns.map((column, index) => {
|
|
559
|
+
const config = byKey.get(column.id);
|
|
560
|
+
const content = config?.cell
|
|
561
|
+
? config.cell(row.original)
|
|
562
|
+
: row.getValue(column.id);
|
|
563
|
+
const first = index === 0;
|
|
564
|
+
const canExpand = first && row.getCanExpand();
|
|
565
|
+
return (_jsx("td", { "data-slot": "table-cell", "data-align": config?.align ?? "left", "data-pinned": column.getIsPinned() || undefined, "data-label": config?.header, className: "sprout-table-cell", role: role("cell"), style: pinStyle(column, false, offsets), children: editing && config?.edit ? (_jsx(Editor, { config: config, label: `${config.header} for ${label}`, value: editing.draft[column.id], onChange: (value) => onEditChange(column.id, value), autoFocus: first ||
|
|
566
|
+
columns.findIndex((c) => byKey.get(c.id)?.edit) === index })) : first ? (_jsxs("span", { className: "sprout-table-first", style: row.depth
|
|
567
|
+
? { paddingInlineStart: row.depth * 16 }
|
|
568
|
+
: undefined, children: [canExpand && (_jsx("button", { type: "button", className: "sprout-table-toggle", "aria-expanded": row.getIsExpanded(), "aria-label": `${row.getIsExpanded() ? "Collapse" : "Expand"} ${label}`, onClick: row.getToggleExpandedHandler(), children: row.getIsExpanded() ? (_jsx(ChevronDown, { size: 14, "aria-hidden": "true" })) : (_jsx(ChevronRight, { size: 14, "aria-hidden": "true" })) })), href ? (_jsx("a", { className: "sprout-table-link", href: href, children: content })) : onOpen ? (_jsx("button", { type: "button", className: "sprout-table-link", onClick: onOpen, children: content })) : (content)] })) : (content) }, column.id));
|
|
569
|
+
}), hasActions && (_jsx("td", { className: "sprout-table-cell", "data-sticky-end": "", role: role("cell"), children: _jsx("span", { className: "sprout-table-actions", children: editing ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "sm", disabled: editing.saving, onClick: onSave, children: editing.saving ? "Saving" : "Save" }), _jsx(Button, { size: "sm", variant: "ghost", disabled: editing.saving, onClick: onCancel, children: "Cancel" })] })) : (_jsxs(_Fragment, { children: [editable && (_jsx(Button, { size: "sm", variant: "ghost", "aria-label": `Edit ${label}`, onClick: onEdit, children: "Edit" })), actions?.(row.original)] })) }) }))] }), editing?.error && (_jsx("tr", { className: "sprout-table-row", "data-error-row": "", role: role("row"), children: _jsx("td", { colSpan: colSpan, className: "sprout-table-cell sprout-table-error", role: "alert", children: editing.error }) }))] }));
|
|
570
|
+
}
|
|
571
|
+
function Editor({ config, label, value, onChange, autoFocus, }) {
|
|
572
|
+
if (config.edit === "checkbox") {
|
|
573
|
+
return (_jsx(Checkbox, { "aria-label": label, checked: Boolean(value), onCheckedChange: (checked) => onChange(checked), autoFocus: autoFocus }));
|
|
574
|
+
}
|
|
575
|
+
if (config.edit === "select") {
|
|
576
|
+
return (_jsx("select", { "aria-label": label, className: "sprout-table-select", value: String(value ?? ""), onChange: (event) => onChange(event.target.value), autoFocus: autoFocus, children: config.options?.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) }));
|
|
577
|
+
}
|
|
578
|
+
return (_jsx(Input, { "aria-label": label, type: config.edit === "number"
|
|
579
|
+
? "number"
|
|
580
|
+
: config.edit === "date"
|
|
581
|
+
? "date"
|
|
582
|
+
: "text", value: value == null ? "" : String(value), onValueChange: (next) => onChange(config.edit === "number" ? (next === "" ? null : Number(next)) : next), autoFocus: autoFocus, className: "sprout-table-input" }));
|
|
583
|
+
}
|
|
584
|
+
function Toolbar({ table, columns, label, searchable, columnMenu, onReset, }) {
|
|
585
|
+
const [pending, setPending] = useState([]);
|
|
586
|
+
const [open, setOpen] = useState(null);
|
|
587
|
+
const filters = table.state.columnFilters;
|
|
588
|
+
const filterable = columns.filter((c) => c.filter);
|
|
589
|
+
const groupable = columns.filter((c) => c.group);
|
|
590
|
+
const grouping = table.state.grouping;
|
|
591
|
+
const chips = filterable.filter((c) => pending.includes(c.key) || filters.some((f) => f.id === c.key));
|
|
592
|
+
return (_jsxs("div", { className: "sprout-table-toolbar", role: "toolbar", "aria-label": `${label} tools`, children: [searchable && (_jsx(SearchField, { label: `Search ${label}`, value: String(table.state.globalFilter ?? ""), onChange: (value) => table.setGlobalFilter(value) })), chips.map((c) => {
|
|
593
|
+
const column = table.getColumn(c.key);
|
|
594
|
+
if (!column)
|
|
595
|
+
return null;
|
|
596
|
+
return (_jsxs("span", { className: "sprout-table-chip", children: [_jsxs(Popover, { open: open === c.key, onOpenChange: (next) => setOpen(next ? c.key : null), children: [_jsxs(PopoverTrigger, { className: "sprout-table-chip-label", children: [c.header, describeFilter(c, column.getFilterValue())] }), _jsx(PopoverContent, { align: "start", children: _jsx(FilterEditor, { config: c, column: column }) })] }), _jsx("button", { type: "button", className: "sprout-table-chip-remove", "aria-label": `Remove ${c.header} filter`, onClick: () => {
|
|
597
|
+
column.setFilterValue(undefined);
|
|
598
|
+
setPending((p) => p.filter((k) => k !== c.key));
|
|
599
|
+
}, children: _jsx(X, { size: 12, "aria-hidden": "true" }) })] }, c.key));
|
|
600
|
+
}), filterable.length > chips.length && (_jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { render: _jsx(Button, { variant: "ghost", size: "sm" }), children: [_jsx(Plus, { size: 14, "aria-hidden": "true" }), "Filter"] }), _jsx(DropdownMenuContent, { align: "start", size: "menu", children: filterable
|
|
601
|
+
.filter((c) => !chips.includes(c))
|
|
602
|
+
.map((c) => (_jsx(DropdownMenuItem, { onClick: () => {
|
|
603
|
+
setPending((p) => [...p, c.key]);
|
|
604
|
+
setOpen(c.key);
|
|
605
|
+
}, children: c.header }, c.key))) })] })), _jsxs("span", { className: "sprout-table-toolbar-end", children: [groupable.length > 0 && (_jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { render: _jsx(Button, { variant: "ghost", size: "sm" }), children: [grouping.length ? `Group: ${grouping.length}` : "Group", _jsx(ChevronDown, { size: 14, "aria-hidden": "true" })] }), _jsx(DropdownMenuContent, { align: "end", size: "menu", children: groupable.map((c) => (_jsx(DropdownMenuCheckboxItem, { checked: grouping.includes(c.key), onCheckedChange: () => table.getColumn(c.key)?.toggleGrouping(), children: c.header }, c.key))) })] })), columnMenu && (_jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { render: _jsx(Button, { variant: "ghost", size: "sm" }), children: ["Columns", _jsx(ChevronDown, { size: 14, "aria-hidden": "true" })] }), _jsxs(DropdownMenuContent, { align: "end", size: "menu", children: [columns.map((c) => {
|
|
606
|
+
const column = table.getColumn(c.key);
|
|
607
|
+
if (!column)
|
|
608
|
+
return null;
|
|
609
|
+
return (_jsxs(DropdownMenuSub, { children: [_jsx(DropdownMenuSubTrigger, { children: c.header }), _jsxs(DropdownMenuSubContent, { children: [_jsx(DropdownMenuCheckboxItem, { checked: column.getIsVisible(), onCheckedChange: (checked) => column.toggleVisibility(checked), children: "Show" }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuRadioGroup, { value: column.getIsPinned() || "none", onValueChange: (value) => column.pin(value === "none"
|
|
610
|
+
? false
|
|
611
|
+
: value), children: [_jsx(DropdownMenuRadioItem, { value: "none", children: "Not pinned" }), _jsx(DropdownMenuRadioItem, { value: "start", children: "Pin to start" }), _jsx(DropdownMenuRadioItem, { value: "end", children: "Pin to end" })] })] })] }, c.key));
|
|
612
|
+
}), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { onClick: onReset, children: "Reset columns" })] })] }))] })] }));
|
|
613
|
+
}
|
|
614
|
+
function describeFilter(config, value) {
|
|
615
|
+
if (value === undefined)
|
|
616
|
+
return "";
|
|
617
|
+
if (config.filter === "select" && Array.isArray(value)) {
|
|
618
|
+
const labels = value.map((v) => config.options?.find((o) => o.value === v)?.label ?? String(v));
|
|
619
|
+
return `: ${labels.join(", ")}`;
|
|
620
|
+
}
|
|
621
|
+
if ((config.filter === "number" || config.filter === "date") &&
|
|
622
|
+
Array.isArray(value)) {
|
|
623
|
+
const [min, max] = value;
|
|
624
|
+
const has = (v) => v !== undefined && v !== null && v !== "";
|
|
625
|
+
if (has(min) && has(max))
|
|
626
|
+
return `: ${min} – ${max}`;
|
|
627
|
+
if (has(min))
|
|
628
|
+
return `: ≥ ${min}`;
|
|
629
|
+
if (has(max))
|
|
630
|
+
return `: ≤ ${max}`;
|
|
631
|
+
return "";
|
|
632
|
+
}
|
|
633
|
+
if (config.filter === "boolean")
|
|
634
|
+
return `: ${value ? "Yes" : "No"}`;
|
|
635
|
+
return `: ${String(value)}`;
|
|
636
|
+
}
|
|
637
|
+
function FilterEditor({ config, column, }) {
|
|
638
|
+
const value = column.getFilterValue();
|
|
639
|
+
const name = config.header;
|
|
640
|
+
if (config.filter === "select") {
|
|
641
|
+
const selected = value ?? [];
|
|
642
|
+
return (_jsxs("fieldset", { className: "sprout-table-filter", children: [_jsx("legend", { children: name }), config.options?.map((o) => (_jsxs("label", { className: "sprout-table-filter-option", children: [_jsx(Checkbox, { variant: "neutral", checked: selected.includes(o.value), onCheckedChange: (checked) => column.setFilterValue(checked
|
|
643
|
+
? [...selected, o.value]
|
|
644
|
+
: selected.filter((v) => v !== o.value)) }), o.label] }, o.value)))] }));
|
|
645
|
+
}
|
|
646
|
+
if (config.filter === "boolean") {
|
|
647
|
+
return (_jsxs("fieldset", { className: "sprout-table-filter", children: [_jsx("legend", { children: name }), [true, false].map((option) => (_jsxs("label", { className: "sprout-table-filter-option", children: [_jsx("input", { type: "radio", name: `${column.id}-filter`, checked: value === option, onChange: () => column.setFilterValue(option) }), option ? "Yes" : "No"] }, String(option))))] }));
|
|
648
|
+
}
|
|
649
|
+
if (config.filter === "number" || config.filter === "date") {
|
|
650
|
+
const [min, max] = value ?? [
|
|
651
|
+
undefined,
|
|
652
|
+
undefined,
|
|
653
|
+
];
|
|
654
|
+
const type = config.filter === "number" ? "number" : "date";
|
|
655
|
+
const set = (index, next) => {
|
|
656
|
+
const parsed = next === "" ? undefined : type === "number" ? Number(next) : next;
|
|
657
|
+
const range = index === 0 ? [parsed, max] : [min, parsed];
|
|
658
|
+
column.setFilterValue(range[0] === undefined && range[1] === undefined ? undefined : range);
|
|
659
|
+
};
|
|
660
|
+
return (_jsxs("fieldset", { className: "sprout-table-filter", "data-range": "", children: [_jsx("legend", { children: name }), _jsx(Input, { "aria-label": `${name} from`, type: type, value: min == null ? "" : String(min), onValueChange: (next) => set(0, next) }), _jsx(Input, { "aria-label": `${name} to`, type: type, value: max == null ? "" : String(max), onValueChange: (next) => set(1, next) })] }));
|
|
661
|
+
}
|
|
662
|
+
return (_jsx(Input, { "aria-label": `${name} contains`, autoFocus: true, value: String(value ?? ""), onValueChange: (next) => column.setFilterValue(next || undefined) }));
|
|
663
|
+
}
|