@vllnt/ui 0.1.8 → 0.1.11-canary.54f8a77
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/dist/components/activity-heatmap/activity-heatmap.js +168 -0
- package/dist/components/activity-heatmap/index.js +6 -0
- package/dist/components/activity-log/activity-log.js +256 -0
- package/dist/components/activity-log/index.js +6 -0
- package/dist/components/ai-chat-input/ai-chat-input.js +107 -0
- package/dist/components/ai-chat-input/index.js +4 -0
- package/dist/components/ai-message-bubble/ai-message-bubble.js +119 -0
- package/dist/components/ai-message-bubble/index.js +6 -0
- package/dist/components/ai-source-citation/ai-source-citation.js +39 -0
- package/dist/components/ai-source-citation/index.js +6 -0
- package/dist/components/ai-streaming-text/ai-streaming-text.js +41 -0
- package/dist/components/ai-streaming-text/index.js +6 -0
- package/dist/components/ai-tool-call-display/ai-tool-call-display.js +93 -0
- package/dist/components/ai-tool-call-display/index.js +6 -0
- package/dist/components/animated-text/animated-text.js +328 -0
- package/dist/components/animated-text/index.js +4 -0
- package/dist/components/annotation/annotation.js +49 -0
- package/dist/components/annotation/index.js +8 -0
- package/dist/components/avatar-group/avatar-group.js +82 -0
- package/dist/components/avatar-group/index.js +10 -0
- package/dist/components/border-beam/border-beam.js +51 -0
- package/dist/components/border-beam/index.js +4 -0
- package/dist/components/candlestick-chart/candlestick-chart.js +215 -0
- package/dist/components/candlestick-chart/index.js +6 -0
- package/dist/components/combobox/combobox.js +130 -0
- package/dist/components/combobox/index.js +4 -0
- package/dist/components/countdown-timer/countdown-timer.js +184 -0
- package/dist/components/countdown-timer/index.js +4 -0
- package/dist/components/credit-badge/credit-badge.js +59 -0
- package/dist/components/credit-badge/index.js +6 -0
- package/dist/components/data-list/data-list.js +99 -0
- package/dist/components/data-list/index.js +16 -0
- package/dist/components/data-table/data-table.js +242 -0
- package/dist/components/data-table/index.js +6 -0
- package/dist/components/date-picker/date-picker.js +74 -0
- package/dist/components/date-picker/index.js +4 -0
- package/dist/components/file-upload/file-upload.js +227 -0
- package/dist/components/file-upload/index.js +4 -0
- package/dist/components/flashcard/flashcard.js +66 -0
- package/dist/components/flashcard/index.js +4 -0
- package/dist/components/index.js +172 -1
- package/dist/components/live-feed/index.js +4 -0
- package/dist/components/live-feed/live-feed.js +168 -0
- package/dist/components/market-treemap/index.js +6 -0
- package/dist/components/market-treemap/market-treemap.js +100 -0
- package/dist/components/marquee/index.js +4 -0
- package/dist/components/marquee/marquee.js +98 -0
- package/dist/components/metric-gauge/index.js +6 -0
- package/dist/components/metric-gauge/metric-gauge.js +213 -0
- package/dist/components/model-selector/model-selector.js +11 -2
- package/dist/components/number-input/index.js +4 -0
- package/dist/components/number-input/number-input.js +167 -0
- package/dist/components/number-ticker/index.js +4 -0
- package/dist/components/number-ticker/number-ticker.js +63 -0
- package/dist/components/order-book/index.js +6 -0
- package/dist/components/order-book/order-book.js +128 -0
- package/dist/components/password-input/index.js +4 -0
- package/dist/components/password-input/password-input.js +45 -0
- package/dist/components/plan-badge/index.js +6 -0
- package/dist/components/plan-badge/plan-badge.js +67 -0
- package/dist/components/rating/index.js +4 -0
- package/dist/components/rating/rating.js +121 -0
- package/dist/components/role-badge/index.js +6 -0
- package/dist/components/role-badge/role-badge.js +50 -0
- package/dist/components/scope-selector/index.js +6 -0
- package/dist/components/scope-selector/scope-selector.js +336 -0
- package/dist/components/severity-badge/index.js +8 -0
- package/dist/components/severity-badge/severity-badge.js +163 -0
- package/dist/components/sparkline-grid/index.js +6 -0
- package/dist/components/sparkline-grid/sparkline-grid.js +92 -0
- package/dist/components/spinner/index.js +5 -1
- package/dist/components/spinner/unicode-spinner.js +708 -0
- package/dist/components/stat-card/index.js +5 -0
- package/dist/components/stat-card/stat-card.js +102 -0
- package/dist/components/status-board/index.js +6 -0
- package/dist/components/status-board/status-board.js +138 -0
- package/dist/components/status-indicator/index.js +10 -0
- package/dist/components/status-indicator/status-indicator.js +175 -0
- package/dist/components/stepper/index.js +4 -0
- package/dist/components/stepper/stepper.js +117 -0
- package/dist/components/subscription-card/index.js +6 -0
- package/dist/components/subscription-card/subscription-card.js +161 -0
- package/dist/components/ticker-tape/index.js +6 -0
- package/dist/components/ticker-tape/ticker-tape.js +106 -0
- package/dist/components/tour/index.js +4 -0
- package/dist/components/tour/tour.js +157 -0
- package/dist/components/usage-breakdown/index.js +6 -0
- package/dist/components/usage-breakdown/usage-breakdown.js +140 -0
- package/dist/components/wallet-card/index.js +4 -0
- package/dist/components/wallet-card/wallet-card.js +115 -0
- package/dist/components/watchlist/index.js +6 -0
- package/dist/components/watchlist/watchlist.js +110 -0
- package/dist/components/world-clock-bar/index.js +6 -0
- package/dist/components/world-clock-bar/world-clock-bar.js +101 -0
- package/dist/index.d.ts +1173 -7
- package/dist/test-setup.js +19 -0
- package/package.json +45 -41
- package/styles.css +55 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
const dataListVariants = cva(
|
|
6
|
+
"grid rounded-xl border bg-card text-card-foreground",
|
|
7
|
+
{
|
|
8
|
+
defaultVariants: {
|
|
9
|
+
density: "default"
|
|
10
|
+
},
|
|
11
|
+
variants: {
|
|
12
|
+
density: {
|
|
13
|
+
compact: "divide-y",
|
|
14
|
+
default: "divide-y"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
const dataListItemVariants = cva(
|
|
20
|
+
"grid gap-1 px-4 py-4 sm:grid-cols-[minmax(0,12rem)_1fr] sm:gap-4 sm:px-5",
|
|
21
|
+
{
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
density: "default"
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
density: {
|
|
27
|
+
compact: "py-3",
|
|
28
|
+
default: "py-4"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
const DataListContext = React.createContext({
|
|
34
|
+
density: "default"
|
|
35
|
+
});
|
|
36
|
+
const DataList = React.forwardRef(
|
|
37
|
+
({ className, density, ...props }, reference) => {
|
|
38
|
+
const resolvedDensity = density ?? "default";
|
|
39
|
+
const contextValue = React.useMemo(
|
|
40
|
+
() => ({ density: resolvedDensity }),
|
|
41
|
+
[resolvedDensity]
|
|
42
|
+
);
|
|
43
|
+
return /* @__PURE__ */ jsx(DataListContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
44
|
+
"dl",
|
|
45
|
+
{
|
|
46
|
+
className: cn(
|
|
47
|
+
dataListVariants({ density: resolvedDensity }),
|
|
48
|
+
className
|
|
49
|
+
),
|
|
50
|
+
ref: reference,
|
|
51
|
+
...props
|
|
52
|
+
}
|
|
53
|
+
) });
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
DataList.displayName = "DataList";
|
|
57
|
+
const DataListItem = React.forwardRef(
|
|
58
|
+
({ className, density, ...props }, reference) => {
|
|
59
|
+
const context = React.useContext(DataListContext);
|
|
60
|
+
return /* @__PURE__ */ jsx(
|
|
61
|
+
"div",
|
|
62
|
+
{
|
|
63
|
+
className: cn(
|
|
64
|
+
dataListItemVariants({ density: density ?? context.density }),
|
|
65
|
+
className
|
|
66
|
+
),
|
|
67
|
+
ref: reference,
|
|
68
|
+
...props
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
DataListItem.displayName = "DataListItem";
|
|
74
|
+
const DataListLabel = React.forwardRef(({ className, ...props }, reference) => /* @__PURE__ */ jsx(
|
|
75
|
+
"dt",
|
|
76
|
+
{
|
|
77
|
+
className: cn("text-sm font-medium text-muted-foreground", className),
|
|
78
|
+
ref: reference,
|
|
79
|
+
...props
|
|
80
|
+
}
|
|
81
|
+
));
|
|
82
|
+
DataListLabel.displayName = "DataListLabel";
|
|
83
|
+
const DataListValue = React.forwardRef(({ className, ...props }, reference) => /* @__PURE__ */ jsx(
|
|
84
|
+
"dd",
|
|
85
|
+
{
|
|
86
|
+
className: cn("m-0 text-sm leading-6 text-foreground", className),
|
|
87
|
+
ref: reference,
|
|
88
|
+
...props
|
|
89
|
+
}
|
|
90
|
+
));
|
|
91
|
+
DataListValue.displayName = "DataListValue";
|
|
92
|
+
export {
|
|
93
|
+
DataList,
|
|
94
|
+
DataListItem,
|
|
95
|
+
DataListLabel,
|
|
96
|
+
DataListValue,
|
|
97
|
+
dataListItemVariants,
|
|
98
|
+
dataListVariants
|
|
99
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataList,
|
|
3
|
+
DataListItem,
|
|
4
|
+
dataListItemVariants,
|
|
5
|
+
DataListLabel,
|
|
6
|
+
DataListValue,
|
|
7
|
+
dataListVariants
|
|
8
|
+
} from "./data-list";
|
|
9
|
+
export {
|
|
10
|
+
DataList,
|
|
11
|
+
DataListItem,
|
|
12
|
+
DataListLabel,
|
|
13
|
+
DataListValue,
|
|
14
|
+
dataListItemVariants,
|
|
15
|
+
dataListVariants
|
|
16
|
+
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
flexRender,
|
|
6
|
+
getCoreRowModel,
|
|
7
|
+
getFilteredRowModel,
|
|
8
|
+
getPaginationRowModel,
|
|
9
|
+
getSortedRowModel,
|
|
10
|
+
useReactTable
|
|
11
|
+
} from "@tanstack/react-table";
|
|
12
|
+
import { ArrowDown, ArrowUp, ArrowUpDown } from "lucide-react";
|
|
13
|
+
import { cn } from "../../lib/utils";
|
|
14
|
+
import { Button } from "../button";
|
|
15
|
+
import { Checkbox } from "../checkbox";
|
|
16
|
+
import { Input } from "../input";
|
|
17
|
+
import {
|
|
18
|
+
Select,
|
|
19
|
+
SelectContent,
|
|
20
|
+
SelectItem,
|
|
21
|
+
SelectTrigger,
|
|
22
|
+
SelectValue
|
|
23
|
+
} from "../select";
|
|
24
|
+
import {
|
|
25
|
+
Table,
|
|
26
|
+
TableBody,
|
|
27
|
+
TableCell,
|
|
28
|
+
TableHead,
|
|
29
|
+
TableHeader,
|
|
30
|
+
TableRow
|
|
31
|
+
} from "../table";
|
|
32
|
+
function SortIcon({ direction }) {
|
|
33
|
+
if (direction === "asc") {
|
|
34
|
+
return /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" });
|
|
35
|
+
}
|
|
36
|
+
if (direction === "desc") {
|
|
37
|
+
return /* @__PURE__ */ jsx(ArrowDown, { className: "h-4 w-4" });
|
|
38
|
+
}
|
|
39
|
+
return /* @__PURE__ */ jsx(ArrowUpDown, { className: "h-4 w-4" });
|
|
40
|
+
}
|
|
41
|
+
function DataTableComponent({
|
|
42
|
+
caption,
|
|
43
|
+
className,
|
|
44
|
+
columns,
|
|
45
|
+
data,
|
|
46
|
+
emptyMessage = "No results found.",
|
|
47
|
+
enableFiltering = true,
|
|
48
|
+
enablePagination = true,
|
|
49
|
+
enableSelection = false,
|
|
50
|
+
filterableColumns = [],
|
|
51
|
+
getRowId,
|
|
52
|
+
pageSize = 10,
|
|
53
|
+
searchPlaceholder = "Search rows...",
|
|
54
|
+
...props
|
|
55
|
+
}) {
|
|
56
|
+
const [sorting, setSorting] = React.useState([]);
|
|
57
|
+
const [globalFilter, setGlobalFilter] = React.useState("");
|
|
58
|
+
const [columnFilters, setColumnFilters] = React.useState(
|
|
59
|
+
[]
|
|
60
|
+
);
|
|
61
|
+
const [rowSelection, setRowSelection] = React.useState({});
|
|
62
|
+
const selectionColumn = React.useMemo(
|
|
63
|
+
() => ({
|
|
64
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
65
|
+
Checkbox,
|
|
66
|
+
{
|
|
67
|
+
"aria-label": `Select row ${row.index + 1}`,
|
|
68
|
+
checked: row.getIsSelected(),
|
|
69
|
+
onCheckedChange: (checked) => {
|
|
70
|
+
row.toggleSelected(Boolean(checked));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
),
|
|
74
|
+
enableHiding: false,
|
|
75
|
+
enableSorting: false,
|
|
76
|
+
header: ({ table: table2 }) => /* @__PURE__ */ jsx(
|
|
77
|
+
Checkbox,
|
|
78
|
+
{
|
|
79
|
+
"aria-label": "Select all rows",
|
|
80
|
+
checked: table2.getIsAllPageRowsSelected() ? true : table2.getIsSomePageRowsSelected() ? "indeterminate" : false,
|
|
81
|
+
onCheckedChange: (checked) => {
|
|
82
|
+
table2.toggleAllPageRowsSelected(Boolean(checked));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
id: "select",
|
|
87
|
+
size: 40
|
|
88
|
+
}),
|
|
89
|
+
[]
|
|
90
|
+
);
|
|
91
|
+
const resolvedColumns = React.useMemo(
|
|
92
|
+
() => enableSelection ? [selectionColumn, ...columns] : columns,
|
|
93
|
+
[columns, enableSelection, selectionColumn]
|
|
94
|
+
);
|
|
95
|
+
const table = useReactTable({
|
|
96
|
+
columns: resolvedColumns,
|
|
97
|
+
data,
|
|
98
|
+
enableRowSelection: enableSelection,
|
|
99
|
+
getCoreRowModel: getCoreRowModel(),
|
|
100
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
101
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
102
|
+
getRowId,
|
|
103
|
+
getSortedRowModel: getSortedRowModel(),
|
|
104
|
+
initialState: {
|
|
105
|
+
pagination: {
|
|
106
|
+
pageIndex: 0,
|
|
107
|
+
pageSize
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
onColumnFiltersChange: setColumnFilters,
|
|
111
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
112
|
+
onRowSelectionChange: setRowSelection,
|
|
113
|
+
onSortingChange: setSorting,
|
|
114
|
+
state: {
|
|
115
|
+
columnFilters,
|
|
116
|
+
globalFilter,
|
|
117
|
+
rowSelection,
|
|
118
|
+
sorting
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), ...props, children: [
|
|
122
|
+
enableFiltering ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-xl border bg-card p-4 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
Input,
|
|
125
|
+
{
|
|
126
|
+
className: "w-full sm:max-w-sm",
|
|
127
|
+
onChange: (event) => {
|
|
128
|
+
setGlobalFilter(event.target.value);
|
|
129
|
+
},
|
|
130
|
+
placeholder: searchPlaceholder,
|
|
131
|
+
value: globalFilter
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
filterableColumns.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: filterableColumns.map((filter) => {
|
|
135
|
+
const column = table.getColumn(filter.columnId);
|
|
136
|
+
const value = column?.getFilterValue();
|
|
137
|
+
const selectValue = typeof value === "string" && value ? value : "all";
|
|
138
|
+
return column ? /* @__PURE__ */ jsxs(
|
|
139
|
+
Select,
|
|
140
|
+
{
|
|
141
|
+
onValueChange: (nextValue) => {
|
|
142
|
+
column.setFilterValue(
|
|
143
|
+
nextValue === "all" ? void 0 : nextValue
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
value: selectValue,
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "w-[180px]", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: filter.label }) }),
|
|
149
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
150
|
+
/* @__PURE__ */ jsxs(SelectItem, { value: "all", children: [
|
|
151
|
+
"All ",
|
|
152
|
+
filter.label
|
|
153
|
+
] }),
|
|
154
|
+
filter.options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value))
|
|
155
|
+
] })
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
filter.columnId
|
|
159
|
+
) : null;
|
|
160
|
+
}) }) : null
|
|
161
|
+
] }) : null,
|
|
162
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-card", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
163
|
+
caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
|
|
164
|
+
/* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(TableHead, { children: header.isPlaceholder ? null : header.column.getCanSort() ? /* @__PURE__ */ jsxs(
|
|
165
|
+
Button,
|
|
166
|
+
{
|
|
167
|
+
className: "-ml-3 h-8 px-3 text-xs font-medium",
|
|
168
|
+
onClick: header.column.getToggleSortingHandler(),
|
|
169
|
+
type: "button",
|
|
170
|
+
variant: "ghost",
|
|
171
|
+
children: [
|
|
172
|
+
flexRender(
|
|
173
|
+
header.column.columnDef.header,
|
|
174
|
+
header.getContext()
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsx(SortIcon, { direction: header.column.getIsSorted() })
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
) : flexRender(
|
|
180
|
+
header.column.columnDef.header,
|
|
181
|
+
header.getContext()
|
|
182
|
+
) }, header.id)) }, headerGroup.id)) }),
|
|
183
|
+
/* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows.length > 0 ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
|
|
184
|
+
TableRow,
|
|
185
|
+
{
|
|
186
|
+
"data-state": row.getIsSelected() ? "selected" : void 0,
|
|
187
|
+
children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(
|
|
188
|
+
cell.column.columnDef.cell,
|
|
189
|
+
cell.getContext()
|
|
190
|
+
) }, cell.id))
|
|
191
|
+
},
|
|
192
|
+
row.id
|
|
193
|
+
)) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
|
|
194
|
+
TableCell,
|
|
195
|
+
{
|
|
196
|
+
className: "h-24 text-center text-muted-foreground",
|
|
197
|
+
colSpan: resolvedColumns.length,
|
|
198
|
+
children: emptyMessage
|
|
199
|
+
}
|
|
200
|
+
) }) })
|
|
201
|
+
] }) }),
|
|
202
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-xl border bg-card p-4 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between", children: [
|
|
203
|
+
/* @__PURE__ */ jsx("div", { children: enableSelection ? `${table.getSelectedRowModel().rows.length} selected` : `${table.getFilteredRowModel().rows.length} rows` }),
|
|
204
|
+
enablePagination ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 self-end sm:self-auto", children: [
|
|
205
|
+
/* @__PURE__ */ jsx(
|
|
206
|
+
Button,
|
|
207
|
+
{
|
|
208
|
+
disabled: !table.getCanPreviousPage(),
|
|
209
|
+
onClick: () => {
|
|
210
|
+
table.previousPage();
|
|
211
|
+
},
|
|
212
|
+
type: "button",
|
|
213
|
+
variant: "outline",
|
|
214
|
+
children: "Previous"
|
|
215
|
+
}
|
|
216
|
+
),
|
|
217
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-24 text-center text-xs uppercase tracking-wide text-muted-foreground", children: [
|
|
218
|
+
"Page ",
|
|
219
|
+
table.getState().pagination.pageIndex + 1,
|
|
220
|
+
" of",
|
|
221
|
+
" ",
|
|
222
|
+
table.getPageCount()
|
|
223
|
+
] }),
|
|
224
|
+
/* @__PURE__ */ jsx(
|
|
225
|
+
Button,
|
|
226
|
+
{
|
|
227
|
+
disabled: !table.getCanNextPage(),
|
|
228
|
+
onClick: () => {
|
|
229
|
+
table.nextPage();
|
|
230
|
+
},
|
|
231
|
+
type: "button",
|
|
232
|
+
variant: "outline",
|
|
233
|
+
children: "Next"
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
] }) : null
|
|
237
|
+
] })
|
|
238
|
+
] });
|
|
239
|
+
}
|
|
240
|
+
export {
|
|
241
|
+
DataTableComponent as DataTable
|
|
242
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { CalendarIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
import { Button } from "../button";
|
|
7
|
+
import { Calendar } from "../calendar";
|
|
8
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../popover";
|
|
9
|
+
const defaultDateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
10
|
+
day: "numeric",
|
|
11
|
+
month: "long",
|
|
12
|
+
year: "numeric"
|
|
13
|
+
});
|
|
14
|
+
const DatePicker = React.forwardRef(
|
|
15
|
+
({
|
|
16
|
+
buttonClassName,
|
|
17
|
+
calendarProps,
|
|
18
|
+
className,
|
|
19
|
+
onValueChange,
|
|
20
|
+
placeholder = "Pick a date",
|
|
21
|
+
value
|
|
22
|
+
}, reference) => {
|
|
23
|
+
const [open, setOpen] = React.useState(false);
|
|
24
|
+
const [internalValue, setInternalValue] = React.useState(
|
|
25
|
+
value
|
|
26
|
+
);
|
|
27
|
+
const selectedDate = value ?? internalValue;
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
if (value !== void 0) {
|
|
30
|
+
setInternalValue(value);
|
|
31
|
+
}
|
|
32
|
+
}, [value]);
|
|
33
|
+
const handleSelect = (nextDate) => {
|
|
34
|
+
if (value === void 0) {
|
|
35
|
+
setInternalValue(nextDate);
|
|
36
|
+
}
|
|
37
|
+
onValueChange?.(nextDate);
|
|
38
|
+
if (nextDate) {
|
|
39
|
+
setOpen(false);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ jsxs(Popover, { onOpenChange: setOpen, open, children: [
|
|
43
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
44
|
+
Button,
|
|
45
|
+
{
|
|
46
|
+
className: cn(
|
|
47
|
+
"w-full justify-start text-left font-normal",
|
|
48
|
+
!selectedDate && "text-muted-foreground",
|
|
49
|
+
buttonClassName
|
|
50
|
+
),
|
|
51
|
+
ref: reference,
|
|
52
|
+
variant: "outline",
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ jsx(CalendarIcon, { className: "mr-2 h-4 w-4" }),
|
|
55
|
+
selectedDate ? defaultDateFormatter.format(selectedDate) : placeholder
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
) }),
|
|
59
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: cn("w-auto p-0", className), children: /* @__PURE__ */ jsx(
|
|
60
|
+
Calendar,
|
|
61
|
+
{
|
|
62
|
+
mode: "single",
|
|
63
|
+
onSelect: handleSelect,
|
|
64
|
+
selected: selectedDate,
|
|
65
|
+
...calendarProps
|
|
66
|
+
}
|
|
67
|
+
) })
|
|
68
|
+
] });
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
DatePicker.displayName = "DatePicker";
|
|
72
|
+
export {
|
|
73
|
+
DatePicker
|
|
74
|
+
};
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { FileUp, UploadCloud, X } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
import { Button } from "../button";
|
|
7
|
+
function useFileUploadState(controlledFiles, multiple, onFilesChange) {
|
|
8
|
+
const [internalFiles, setInternalFiles] = React.useState(
|
|
9
|
+
controlledFiles ?? []
|
|
10
|
+
);
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
if (controlledFiles !== void 0) {
|
|
13
|
+
setInternalFiles(controlledFiles);
|
|
14
|
+
}
|
|
15
|
+
}, [controlledFiles]);
|
|
16
|
+
const resolvedFiles = controlledFiles ?? internalFiles;
|
|
17
|
+
const updateFiles = React.useCallback(
|
|
18
|
+
(nextFiles) => {
|
|
19
|
+
if (controlledFiles === void 0) {
|
|
20
|
+
setInternalFiles(nextFiles);
|
|
21
|
+
}
|
|
22
|
+
onFilesChange?.(nextFiles);
|
|
23
|
+
},
|
|
24
|
+
[controlledFiles, onFilesChange]
|
|
25
|
+
);
|
|
26
|
+
const addFiles = React.useCallback(
|
|
27
|
+
(incomingFiles) => {
|
|
28
|
+
const nextFiles = [...incomingFiles];
|
|
29
|
+
updateFiles(
|
|
30
|
+
multiple ? [...resolvedFiles, ...nextFiles] : nextFiles.slice(0, 1)
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
[multiple, resolvedFiles, updateFiles]
|
|
34
|
+
);
|
|
35
|
+
const removeFile = React.useCallback(
|
|
36
|
+
(fileToRemove) => {
|
|
37
|
+
updateFiles(
|
|
38
|
+
resolvedFiles.filter(
|
|
39
|
+
(file) => !(file.name === fileToRemove.name && file.size === fileToRemove.size && file.lastModified === fileToRemove.lastModified)
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
[resolvedFiles, updateFiles]
|
|
44
|
+
);
|
|
45
|
+
return { addFiles, removeFile, resolvedFiles };
|
|
46
|
+
}
|
|
47
|
+
function assignInputReference(reference, node) {
|
|
48
|
+
if (typeof reference === "function") {
|
|
49
|
+
reference(node);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (reference) {
|
|
53
|
+
reference.current = node;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function FileListItem({
|
|
57
|
+
file,
|
|
58
|
+
onRemove
|
|
59
|
+
}) {
|
|
60
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between rounded-md border bg-muted/30 px-3 py-2 text-sm", children: [
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("p", { className: "truncate font-medium", children: file.name }),
|
|
63
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
64
|
+
(file.size / 1024).toFixed(1),
|
|
65
|
+
" KB"
|
|
66
|
+
] })
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx(
|
|
69
|
+
Button,
|
|
70
|
+
{
|
|
71
|
+
"aria-label": `Remove ${file.name}`,
|
|
72
|
+
onClick: onRemove,
|
|
73
|
+
size: "icon",
|
|
74
|
+
type: "button",
|
|
75
|
+
variant: "ghost",
|
|
76
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
function FileUploadDropzone({
|
|
82
|
+
browseLabel,
|
|
83
|
+
children,
|
|
84
|
+
disabled,
|
|
85
|
+
dropzoneText,
|
|
86
|
+
helperText,
|
|
87
|
+
isDragging,
|
|
88
|
+
onActivate,
|
|
89
|
+
onDragStateChange,
|
|
90
|
+
onFilesDrop
|
|
91
|
+
}) {
|
|
92
|
+
return /* @__PURE__ */ jsxs(
|
|
93
|
+
"div",
|
|
94
|
+
{
|
|
95
|
+
className: cn(
|
|
96
|
+
"flex min-h-40 cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed border-input bg-background px-6 py-8 text-center transition-colors",
|
|
97
|
+
isDragging && "border-primary bg-accent/40",
|
|
98
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
99
|
+
),
|
|
100
|
+
onClick: onActivate,
|
|
101
|
+
onDragEnter: (event) => {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
if (!disabled) {
|
|
104
|
+
onDragStateChange(true);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
onDragLeave: (event) => {
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
onDragStateChange(false);
|
|
110
|
+
},
|
|
111
|
+
onDragOver: (event) => {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
},
|
|
114
|
+
onDrop: (event) => {
|
|
115
|
+
event.preventDefault();
|
|
116
|
+
onDragStateChange(false);
|
|
117
|
+
if (!disabled && event.dataTransfer.files.length > 0) {
|
|
118
|
+
onFilesDrop(event.dataTransfer.files);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
onKeyDown: (event) => {
|
|
122
|
+
if ((event.key === "Enter" || event.key === " ") && !disabled) {
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
onActivate();
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
role: "button",
|
|
128
|
+
tabIndex: disabled ? -1 : 0,
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx(UploadCloud, { className: "mb-3 h-10 w-10 text-muted-foreground" }),
|
|
131
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
132
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium", children: dropzoneText }),
|
|
133
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: helperText })
|
|
134
|
+
] }),
|
|
135
|
+
/* @__PURE__ */ jsxs("span", { className: "mt-4 inline-flex h-10 items-center justify-center rounded-md border border-input bg-secondary px-4 py-2 text-sm font-medium text-secondary-foreground shadow-sm", children: [
|
|
136
|
+
/* @__PURE__ */ jsx(FileUp, { className: "mr-2 h-4 w-4" }),
|
|
137
|
+
browseLabel
|
|
138
|
+
] }),
|
|
139
|
+
children
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
function FileUploadList({
|
|
145
|
+
files,
|
|
146
|
+
onRemove
|
|
147
|
+
}) {
|
|
148
|
+
if (files.length === 0) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: files.map((file) => /* @__PURE__ */ jsx(
|
|
152
|
+
FileListItem,
|
|
153
|
+
{
|
|
154
|
+
file,
|
|
155
|
+
onRemove: () => {
|
|
156
|
+
onRemove(file);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
`${file.name}-${file.lastModified}-${file.size}`
|
|
160
|
+
)) });
|
|
161
|
+
}
|
|
162
|
+
function FileUploadComponent({
|
|
163
|
+
accept,
|
|
164
|
+
browseLabel = "Choose files",
|
|
165
|
+
className,
|
|
166
|
+
disabled,
|
|
167
|
+
dropzoneText = "Drag and drop files here, or click to browse.",
|
|
168
|
+
files,
|
|
169
|
+
helperText = "Supports one or more files.",
|
|
170
|
+
multiple = true,
|
|
171
|
+
onFilesChange,
|
|
172
|
+
...props
|
|
173
|
+
}, reference) {
|
|
174
|
+
const inputReference = React.useRef(null);
|
|
175
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
176
|
+
const { addFiles, removeFile, resolvedFiles } = useFileUploadState(
|
|
177
|
+
files,
|
|
178
|
+
multiple,
|
|
179
|
+
onFilesChange
|
|
180
|
+
);
|
|
181
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
|
|
182
|
+
/* @__PURE__ */ jsx(
|
|
183
|
+
FileUploadDropzone,
|
|
184
|
+
{
|
|
185
|
+
browseLabel,
|
|
186
|
+
disabled,
|
|
187
|
+
dropzoneText,
|
|
188
|
+
helperText,
|
|
189
|
+
isDragging,
|
|
190
|
+
onActivate: () => {
|
|
191
|
+
if (!disabled) {
|
|
192
|
+
inputReference.current?.click();
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
onDragStateChange: setIsDragging,
|
|
196
|
+
onFilesDrop: addFiles,
|
|
197
|
+
children: /* @__PURE__ */ jsx(
|
|
198
|
+
"input",
|
|
199
|
+
{
|
|
200
|
+
...props,
|
|
201
|
+
accept,
|
|
202
|
+
"aria-label": browseLabel,
|
|
203
|
+
className: "sr-only",
|
|
204
|
+
disabled,
|
|
205
|
+
multiple,
|
|
206
|
+
onChange: (event) => {
|
|
207
|
+
if (event.target.files) {
|
|
208
|
+
addFiles(event.target.files);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
ref: (node) => {
|
|
212
|
+
inputReference.current = node;
|
|
213
|
+
assignInputReference(reference, node);
|
|
214
|
+
},
|
|
215
|
+
type: "file"
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
),
|
|
220
|
+
/* @__PURE__ */ jsx(FileUploadList, { files: resolvedFiles, onRemove: removeFile })
|
|
221
|
+
] });
|
|
222
|
+
}
|
|
223
|
+
const FileUpload = React.forwardRef(FileUploadComponent);
|
|
224
|
+
FileUpload.displayName = "FileUpload";
|
|
225
|
+
export {
|
|
226
|
+
FileUpload
|
|
227
|
+
};
|