@deftui/react 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +4 -2
- package/dist/styles.shadcn.css +1 -1
- package/dist/vendor/README.md +3 -2
- package/dist/vendor/tailored/file-tree.d.mts +20 -0
- package/dist/vendor/tailored/file-tree.mjs +145 -0
- package/dist/vendor/tailored/json-viewer.d.mts +10 -0
- package/dist/vendor/tailored/json-viewer.mjs +230 -0
- package/dist/widgets/index.d.mts +4 -2
- package/dist/widgets/index.mjs +4 -2
- package/package.json +11 -10
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @deftui/react
|
|
2
|
+
|
|
3
|
+
A React component library built on Base UI, shadcn/ui, and their open-source registry ecosystem, offering easy-to-use compound component APIs.
|
|
4
|
+
|
|
5
|
+
[Upstream documentation](./dist/vendor/README.md): To look up component usage, check the local exports first, then consult the upstream.
|
|
6
|
+
|
|
7
|
+
> Most basic components expose exactly the same APIs as their shadcn/ui counterparts backed by Base UI.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
bun add @deftui/react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Install Tailwind CSS 4 in your project first, then import the styles in your application's global CSS:
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
@import "tailwindcss";
|
|
21
|
+
@import "@deftui/react/styles";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Component Example:
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { Button, Card } from "@deftui/react";
|
|
28
|
+
|
|
29
|
+
export function Example() {
|
|
30
|
+
return (
|
|
31
|
+
<Card>
|
|
32
|
+
<Card.Header>
|
|
33
|
+
<Card.Title>Welcome to Deft UI</Card.Title>
|
|
34
|
+
<Card.Description>Compose your UI using Compound Component API</Card.Description>
|
|
35
|
+
</Card.Header>
|
|
36
|
+
|
|
37
|
+
<Card.Content>
|
|
38
|
+
<Button>Get started</Button>
|
|
39
|
+
</Card.Content>
|
|
40
|
+
</Card>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,7 @@ import { Dropzone, formatSize } from "./widgets/dropzone.mjs";
|
|
|
16
16
|
import { LightboxActions, LightboxBackdrop, LightboxCaptions, LightboxChangeReason, LightboxClose, LightboxContent, LightboxControl, LightboxControlContext, LightboxCounter, LightboxDownload, LightboxImageChangeEventDetails, LightboxImageItem, LightboxItem, LightboxMore, LightboxNext, LightboxOpenEventDetails, LightboxPrevious, LightboxProps, LightboxSlide, LightboxSlides, LightboxThumbnail, LightboxThumbnails, LightboxToolbar, LightboxTrigger, LightboxTriggerProps, LightboxVideoItem, LightboxViewport, LightboxZoom, LightboxZoomButton, useLightbox } from "./vendor/tailored/lightbox.mjs";
|
|
17
17
|
import { Carousel, Image, ImageProps, Lightbox } from "./widgets/multimedia.mjs";
|
|
18
18
|
import { Pagination } from "./widgets/pagination.mjs";
|
|
19
|
+
import { Form } from "./vendor/coss/form.mjs";
|
|
19
20
|
import { Badge } from "./vendor/shadcn/badge.mjs";
|
|
20
21
|
import { Switch } from "./vendor/shadcn/switch.mjs";
|
|
21
22
|
import { Spinner } from "./vendor/shadcn/spinner.mjs";
|
|
@@ -23,12 +24,13 @@ import { Skeleton } from "./vendor/shadcn/skeleton.mjs";
|
|
|
23
24
|
import { Checkbox } from "./vendor/shadcn/checkbox.mjs";
|
|
24
25
|
import { Textarea } from "./vendor/shadcn/textarea.mjs";
|
|
25
26
|
import { ScrollArea } from "./vendor/coss/scroll-area.mjs";
|
|
26
|
-
import { Form } from "./vendor/coss/form.mjs";
|
|
27
27
|
import { IconSwap } from "./vendor/tailored/icon-swap.mjs";
|
|
28
|
+
import { JsonViewer } from "./vendor/tailored/json-viewer.mjs";
|
|
29
|
+
import { FileTree, FileTreeNode } from "./vendor/tailored/file-tree.mjs";
|
|
28
30
|
import { AlertDialog, Breadcrumb, ButtonGroup, Calendar, Card, Combobox, Dialog, Drawer, Dropdown, Empty, Field, InputGroup, Kbd, Popover, Progress, Radio, Select, Table, Tabs, Tooltip } from "./widgets/index.mjs";
|
|
29
31
|
import { cn } from "cn";
|
|
30
32
|
import { cva } from "class-variance-authority";
|
|
31
33
|
import { mergeProps } from "@base-ui/react/merge-props";
|
|
32
34
|
import { useDropzone } from "react-dropzone";
|
|
33
35
|
export type * from "react-dropzone";
|
|
34
|
-
export { AlertDialog, type AlertDialogHandle, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, type ComboboxItemCollection, type ComboboxPrimitiveValue, type CreateComboboxItemsOptions, DatePicker, type DateRange, DateRangePicker, Dialog, type DialogHandle, Drawer, type DrawerHandle, Dropdown, Dropzone, Empty, Field, Form, IconSwap, Image, ImageProps, Input, InputGroup, Kbd, Label, Lightbox, type LightboxActions, type LightboxBackdrop, type LightboxCaptions, type LightboxChangeReason, type LightboxClose, type LightboxContent, type LightboxControl, type LightboxControlContext, type LightboxCounter, type LightboxDownload, type LightboxImageChangeEventDetails, type LightboxImageItem, type LightboxItem, type LightboxMore, type LightboxNext, type LightboxOpenEventDetails, type LightboxPrevious, type LightboxProps, type LightboxSlide, type LightboxSlides, type LightboxThumbnail, type LightboxThumbnails, type LightboxToolbar, type LightboxTrigger, type LightboxTriggerProps, type LightboxVideoItem, type LightboxViewport, type LightboxZoom, type LightboxZoomButton, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, cn, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, cva, formatSize, mergeProps, toast, useCopyToClipboard, useDropzone, useIsMobile, type useLightbox, useMediaQuery, useSidebar };
|
|
36
|
+
export { AlertDialog, type AlertDialogHandle, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, type ComboboxItemCollection, type ComboboxPrimitiveValue, type CreateComboboxItemsOptions, DatePicker, type DateRange, DateRangePicker, Dialog, type DialogHandle, Drawer, type DrawerHandle, Dropdown, Dropzone, Empty, Field, FileTree, type FileTreeNode, Form, IconSwap, Image, ImageProps, Input, InputGroup, JsonViewer, Kbd, Label, Lightbox, type LightboxActions, type LightboxBackdrop, type LightboxCaptions, type LightboxChangeReason, type LightboxClose, type LightboxContent, type LightboxControl, type LightboxControlContext, type LightboxCounter, type LightboxDownload, type LightboxImageChangeEventDetails, type LightboxImageItem, type LightboxItem, type LightboxMore, type LightboxNext, type LightboxOpenEventDetails, type LightboxPrevious, type LightboxProps, type LightboxSlide, type LightboxSlides, type LightboxThumbnail, type LightboxThumbnails, type LightboxToolbar, type LightboxTrigger, type LightboxTriggerProps, type LightboxVideoItem, type LightboxViewport, type LightboxZoom, type LightboxZoomButton, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, cn, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, cva, formatSize, mergeProps, toast, useCopyToClipboard, useDropzone, useIsMobile, type useLightbox, useMediaQuery, useSidebar };
|
package/dist/index.mjs
CHANGED
|
@@ -18,15 +18,17 @@ import { DatePicker, DateRangePicker, TimePicker } from "./widgets/datetime.mjs"
|
|
|
18
18
|
import { Dropzone, formatSize } from "./widgets/dropzone.mjs";
|
|
19
19
|
import { Carousel, Image, Lightbox } from "./widgets/multimedia.mjs";
|
|
20
20
|
import { Pagination } from "./widgets/pagination.mjs";
|
|
21
|
+
import { Form } from "./vendor/coss/form.mjs";
|
|
21
22
|
import { Badge } from "./vendor/shadcn/badge.mjs";
|
|
22
23
|
import { Switch } from "./vendor/shadcn/switch.mjs";
|
|
23
24
|
import { Checkbox } from "./vendor/shadcn/checkbox.mjs";
|
|
24
25
|
import { ScrollArea } from "./vendor/coss/scroll-area.mjs";
|
|
25
|
-
import { Form } from "./vendor/coss/form.mjs";
|
|
26
26
|
import { IconSwap } from "./vendor/tailored/icon-swap.mjs";
|
|
27
|
+
import { JsonViewer } from "./vendor/tailored/json-viewer.mjs";
|
|
28
|
+
import { FileTree } from "./vendor/tailored/file-tree.mjs";
|
|
27
29
|
import { AlertDialog, Breadcrumb, ButtonGroup, Calendar, Card, Combobox, Dialog, Drawer, Dropdown, Empty, Field, InputGroup, Kbd, Popover, Progress, Radio, Select, Table, Tabs, Tooltip } from "./widgets/index.mjs";
|
|
28
30
|
import { cn } from "cn";
|
|
29
31
|
import { cva } from "class-variance-authority";
|
|
30
32
|
import { mergeProps } from "@base-ui/react/merge-props";
|
|
31
33
|
import { useDropzone } from "react-dropzone";
|
|
32
|
-
export { AlertDialog, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, DatePicker, DateRangePicker, Dialog, Drawer, Dropdown, Dropzone, Empty, Field, Form, IconSwap, Image, Input, InputGroup, Kbd, Label, Lightbox, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, cn, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, cva, formatSize, mergeProps, toast, useCopyToClipboard, useDropzone, useIsMobile, useMediaQuery, useSidebar };
|
|
34
|
+
export { AlertDialog, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, DatePicker, DateRangePicker, Dialog, Drawer, Dropdown, Dropzone, Empty, Field, FileTree, Form, IconSwap, Image, Input, InputGroup, JsonViewer, Kbd, Label, Lightbox, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, cn, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, cva, formatSize, mergeProps, toast, useCopyToClipboard, useDropzone, useIsMobile, useMediaQuery, useSidebar };
|
package/dist/styles.shadcn.css
CHANGED
package/dist/vendor/README.md
CHANGED
|
@@ -54,14 +54,15 @@ shadcn 组件使用 `components.json` 中的 `base-vega` 风格和 Lucide 图标
|
|
|
54
54
|
|
|
55
55
|
## Tailored
|
|
56
56
|
|
|
57
|
-
`tailored/`
|
|
57
|
+
`tailored/` 存放:仅少量引入的上游组件 或 需要较大调整的单体组件
|
|
58
58
|
|
|
59
59
|
- 按本地需求维护,对比后选择性吸收上游修复,避免直接覆盖本地实现。
|
|
60
60
|
- 优先复用已有基础组件;仅供该组件使用的依赖可内联,分别记录其来源。
|
|
61
|
-
- 下表记录主组件及内联依赖的 registry ID、文档和主要修改;对外的组合封装放在 `widgets/`。
|
|
62
61
|
|
|
63
62
|
| ID | File | Docs | Modifications |
|
|
64
63
|
| --- | --- | --- | --- |
|
|
65
64
|
| `https://ui.iandefined.com/r/icon-swap.json` | [tailored/icon-swap.tsx](tailored/icon-swap.tsx) | [Icon Swap](https://ui.iandefined.com/docs/utilities/icon-swap/) | 进出场动画减弱模糊为 2px,缩短为 0.2s 时长 |
|
|
66
65
|
| `https://ui.iandefined.com/r/lightbox.json` | [tailored/lightbox.tsx](tailored/lightbox.tsx) | [Lightbox](https://ui.iandefined.com/docs/components/lightbox/) | 适配本地组件和尺寸;修正嵌套弹层层级与点击隔离;补充加载失败反馈 |
|
|
67
66
|
| `https://ui.iandefined.com/r/scroll-area.json` | [tailored/lightbox.tsx](tailored/lightbox.tsx) | [Scroll Area](https://ui.iandefined.com/docs/components/scroll-area/) | 作为 Lightbox 的私有依赖内联 |
|
|
67
|
+
| `Tinkerers-Labs/mischief-ui/file-tree` | [tailored/file-tree.tsx](tailored/file-tree.tsx) | [File Tree](https://ui.tinkererslabs.com/docs/components/file-tree/) | — |
|
|
68
|
+
| `Tinkerers-Labs/mischief-ui/json-viewer` | [tailored/json-viewer.tsx](tailored/json-viewer.tsx) | [JSON Viewer](https://ui.tinkererslabs.com/docs/components/json-viewer/) | — |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
export type FileTreeNode = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
kind?: "file" | "folder";
|
|
6
|
+
children?: FileTreeNode[];
|
|
7
|
+
meta?: React$1.ReactNode;
|
|
8
|
+
icon?: React$1.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export type FileTreeProps = Omit<React$1.HTMLAttributes<HTMLDivElement>, "children" | "onSelect"> & {
|
|
11
|
+
nodes: FileTreeNode[];
|
|
12
|
+
expandedIds?: string[];
|
|
13
|
+
defaultExpandedIds?: string[];
|
|
14
|
+
onExpandedChange?: (ids: string[]) => void;
|
|
15
|
+
selectedId?: string | null;
|
|
16
|
+
defaultSelectedId?: string | null;
|
|
17
|
+
onSelect?: (node: FileTreeNode) => void;
|
|
18
|
+
label?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function FileTree({ nodes, expandedIds, defaultExpandedIds, onExpandedChange, selectedId, defaultSelectedId, onSelect, label, className, ...rootProps }: FileTreeProps): React$1.JSX.Element;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../shadcn/lib/utils.mjs";
|
|
3
|
+
import * as React$1 from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { ChevronRight, File, Folder, FolderOpen } from "lucide-react";
|
|
6
|
+
// src/vendor/tailored/file-tree.tsx
|
|
7
|
+
function isFolder(node) {
|
|
8
|
+
return node.kind === "folder" || Array.isArray(node.children);
|
|
9
|
+
}
|
|
10
|
+
function flatten(nodes, expanded, level = 1) {
|
|
11
|
+
return nodes.flatMap((node) => {
|
|
12
|
+
const folder = isFolder(node);
|
|
13
|
+
const open = folder && expanded.has(node.id);
|
|
14
|
+
const self = {
|
|
15
|
+
node,
|
|
16
|
+
level,
|
|
17
|
+
isFolder: folder,
|
|
18
|
+
isExpanded: open
|
|
19
|
+
};
|
|
20
|
+
if (!open || !node.children) return [self];
|
|
21
|
+
return [self, ...flatten(node.children, expanded, level + 1)];
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function FileTree({ nodes, expandedIds, defaultExpandedIds = [], onExpandedChange, selectedId, defaultSelectedId = null, onSelect, label = "Files", className, ...rootProps }) {
|
|
25
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = React$1.useState(defaultExpandedIds);
|
|
26
|
+
const [uncontrolledSelected, setUncontrolledSelected] = React$1.useState(defaultSelectedId);
|
|
27
|
+
const expandedList = expandedIds ?? uncontrolledExpanded;
|
|
28
|
+
const expanded = React$1.useMemo(() => new Set(expandedList), [expandedList]);
|
|
29
|
+
const selected = selectedId === void 0 ? uncontrolledSelected : selectedId;
|
|
30
|
+
const rows = React$1.useMemo(() => flatten(nodes, expanded), [nodes, expanded]);
|
|
31
|
+
const containerRef = React$1.useRef(null);
|
|
32
|
+
const setExpanded = (ids) => {
|
|
33
|
+
if (expandedIds === void 0) setUncontrolledExpanded(ids);
|
|
34
|
+
onExpandedChange?.(ids);
|
|
35
|
+
};
|
|
36
|
+
const toggle = (id, open) => {
|
|
37
|
+
const shouldOpen = open ?? !expanded.has(id);
|
|
38
|
+
if (shouldOpen === expanded.has(id)) return;
|
|
39
|
+
setExpanded(shouldOpen ? [...expandedList, id] : expandedList.filter((entry) => entry !== id));
|
|
40
|
+
};
|
|
41
|
+
const select = (node) => {
|
|
42
|
+
if (selectedId === void 0) setUncontrolledSelected(node.id);
|
|
43
|
+
onSelect?.(node);
|
|
44
|
+
};
|
|
45
|
+
const focusRow = (index) => {
|
|
46
|
+
const target = rows[index];
|
|
47
|
+
if (!target) return;
|
|
48
|
+
containerRef.current?.querySelector(`[data-node="${CSS.escape(target.node.id)}"]`)?.focus();
|
|
49
|
+
};
|
|
50
|
+
const onKeyDown = (event, row, index) => {
|
|
51
|
+
switch (event.key) {
|
|
52
|
+
case "ArrowDown":
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
focusRow(Math.min(index + 1, rows.length - 1));
|
|
55
|
+
break;
|
|
56
|
+
case "ArrowUp":
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
focusRow(Math.max(index - 1, 0));
|
|
59
|
+
break;
|
|
60
|
+
case "ArrowRight":
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
if (row.isFolder && !row.isExpanded) toggle(row.node.id, true);
|
|
63
|
+
else if (row.isFolder) focusRow(index + 1);
|
|
64
|
+
break;
|
|
65
|
+
case "ArrowLeft": {
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
if (row.isFolder && row.isExpanded) {
|
|
68
|
+
toggle(row.node.id, false);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
const parent = rows.slice(0, index).reverse().findIndex((entry) => entry.level < row.level);
|
|
72
|
+
if (parent >= 0) focusRow(index - 1 - parent);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "Home":
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
focusRow(0);
|
|
78
|
+
break;
|
|
79
|
+
case "End":
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
focusRow(rows.length - 1);
|
|
82
|
+
break;
|
|
83
|
+
case "Enter":
|
|
84
|
+
case " ":
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
if (row.isFolder) toggle(row.node.id);
|
|
87
|
+
select(row.node);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const activeIndex = Math.max(rows.findIndex((row) => row.node.id === selected), 0);
|
|
91
|
+
return /* @__PURE__ */ jsx("div", {
|
|
92
|
+
ref: containerRef,
|
|
93
|
+
"data-slot": "file-tree",
|
|
94
|
+
className: cn("border-border bg-card text-card-foreground rounded-[var(--radius)] border p-1.5", className),
|
|
95
|
+
...rootProps,
|
|
96
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
97
|
+
role: "tree",
|
|
98
|
+
"aria-label": label,
|
|
99
|
+
children: rows.map((row, index) => {
|
|
100
|
+
const isSelected = row.node.id === selected;
|
|
101
|
+
const Icon = row.isFolder ? row.isExpanded ? FolderOpen : Folder : File;
|
|
102
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
103
|
+
role: "treeitem",
|
|
104
|
+
"data-node": row.node.id,
|
|
105
|
+
"data-slot": "file-tree-item",
|
|
106
|
+
"aria-level": row.level,
|
|
107
|
+
"aria-selected": isSelected,
|
|
108
|
+
"aria-expanded": row.isFolder ? row.isExpanded : void 0,
|
|
109
|
+
tabIndex: index === activeIndex ? 0 : -1,
|
|
110
|
+
className: cn("focus-visible:ring-ring flex min-h-9 cursor-default items-center gap-1.5 rounded-[calc(var(--radius)-0.35rem)] pr-2 text-sm focus-visible:ring-2 focus-visible:outline-none", isSelected ? "bg-muted font-semibold" : "hover:bg-muted/60 transition-colors duration-150 motion-reduce:transition-none"),
|
|
111
|
+
style: { paddingLeft: `${(row.level - 1) * .85 + .35}rem` },
|
|
112
|
+
onClick: () => {
|
|
113
|
+
if (row.isFolder) toggle(row.node.id);
|
|
114
|
+
select(row.node);
|
|
115
|
+
},
|
|
116
|
+
onKeyDown: (event) => onKeyDown(event, row, index),
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsx("span", {
|
|
119
|
+
className: "flex size-4 shrink-0 items-center justify-center",
|
|
120
|
+
children: row.isFolder ? /* @__PURE__ */ jsx(ChevronRight, {
|
|
121
|
+
"aria-hidden": "true",
|
|
122
|
+
size: 13,
|
|
123
|
+
className: cn("text-muted-foreground transition-transform duration-150 motion-reduce:transition-none", row.isExpanded && "rotate-90")
|
|
124
|
+
}) : null
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ jsx("span", {
|
|
127
|
+
"aria-hidden": "true",
|
|
128
|
+
className: "text-muted-foreground shrink-0",
|
|
129
|
+
children: row.node.icon ?? /* @__PURE__ */ jsx(Icon, { size: 15 })
|
|
130
|
+
}),
|
|
131
|
+
/* @__PURE__ */ jsx("span", {
|
|
132
|
+
className: "min-w-0 flex-1 truncate",
|
|
133
|
+
children: row.node.name
|
|
134
|
+
}),
|
|
135
|
+
row.node.meta ? /* @__PURE__ */ jsx("span", {
|
|
136
|
+
className: "text-muted-foreground shrink-0 text-xs",
|
|
137
|
+
children: row.node.meta
|
|
138
|
+
}) : null
|
|
139
|
+
]
|
|
140
|
+
}, row.node.id);
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
export { FileTree };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
export type JsonViewerProps = Omit<React$1.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
3
|
+
value: unknown;
|
|
4
|
+
rootName?: string;
|
|
5
|
+
defaultExpandedDepth?: number;
|
|
6
|
+
maxStringLength?: number;
|
|
7
|
+
copyable?: boolean;
|
|
8
|
+
label?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function JsonViewer({ value, rootName, defaultExpandedDepth, maxStringLength, copyable, label, className, ...rootProps }: JsonViewerProps): React$1.JSX.Element;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../shadcn/lib/utils.mjs";
|
|
3
|
+
import * as React$1 from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Check, ChevronRight, Clipboard } from "lucide-react";
|
|
6
|
+
// src/vendor/tailored/json-viewer.tsx
|
|
7
|
+
function kindOf(value) {
|
|
8
|
+
if (value === null) return "null";
|
|
9
|
+
if (Array.isArray(value)) return "array";
|
|
10
|
+
switch (typeof value) {
|
|
11
|
+
case "object": return "object";
|
|
12
|
+
case "string": return "string";
|
|
13
|
+
case "number": return "number";
|
|
14
|
+
case "boolean": return "boolean";
|
|
15
|
+
default: return "other";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function entriesOf(value) {
|
|
19
|
+
if (Array.isArray(value)) return value.map((entry, index) => [String(index), entry]);
|
|
20
|
+
return Object.entries(value);
|
|
21
|
+
}
|
|
22
|
+
function size(value) {
|
|
23
|
+
return Array.isArray(value) ? value.length : Object.keys(value).length;
|
|
24
|
+
}
|
|
25
|
+
/** What a collapsed branch says about itself, without unfolding it. */
|
|
26
|
+
function summarise(value, kind) {
|
|
27
|
+
const count = size(value);
|
|
28
|
+
const noun = count === 1 ? "item" : "items";
|
|
29
|
+
return kind === "array" ? `[ ${count} ${noun} ]` : `{ ${count} ${noun} }`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A JSON path in the notation somebody would paste back into code, so the copy
|
|
33
|
+
* is worth taking: `data.rows[0].name` rather than a list of segments.
|
|
34
|
+
*/
|
|
35
|
+
function joinPath(parent, key, inArray) {
|
|
36
|
+
if (inArray) return `${parent}[${key}]`;
|
|
37
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? `${parent}.${key}` : `${parent}[${JSON.stringify(key)}]`;
|
|
38
|
+
}
|
|
39
|
+
function flatten(value, expanded, rootName) {
|
|
40
|
+
const walk = (node, key, path, level, index) => {
|
|
41
|
+
const kind = kindOf(node);
|
|
42
|
+
const branch = (kind === "object" || kind === "array") && size(node) > 0;
|
|
43
|
+
const open = branch && expanded.has(path);
|
|
44
|
+
const self = {
|
|
45
|
+
path,
|
|
46
|
+
key,
|
|
47
|
+
value: node,
|
|
48
|
+
kind,
|
|
49
|
+
level,
|
|
50
|
+
branch,
|
|
51
|
+
expanded: open,
|
|
52
|
+
index
|
|
53
|
+
};
|
|
54
|
+
if (!open) return [self];
|
|
55
|
+
const inArray = kind === "array";
|
|
56
|
+
return [self, ...entriesOf(node).flatMap(([childKey, child], at) => walk(child, childKey, joinPath(path, childKey, inArray), level + 1, inArray ? at : null))];
|
|
57
|
+
};
|
|
58
|
+
return walk(value, null, rootName, 1, null);
|
|
59
|
+
}
|
|
60
|
+
/** Every path down to the requested depth, so the first view is not one line. */
|
|
61
|
+
function pathsToDepth(value, rootName, depth) {
|
|
62
|
+
const open = /* @__PURE__ */ new Set();
|
|
63
|
+
const walk = (node, path, level) => {
|
|
64
|
+
const kind = kindOf(node);
|
|
65
|
+
if (kind !== "object" && kind !== "array") return;
|
|
66
|
+
if (size(node) === 0 || level > depth) return;
|
|
67
|
+
open.add(path);
|
|
68
|
+
const inArray = kind === "array";
|
|
69
|
+
for (const [key, child] of entriesOf(node)) walk(child, joinPath(path, key, inArray), level + 1);
|
|
70
|
+
};
|
|
71
|
+
walk(value, rootName, 1);
|
|
72
|
+
return open;
|
|
73
|
+
}
|
|
74
|
+
const VALUE_CLASS = {
|
|
75
|
+
string: "text-emerald-600 dark:text-emerald-400",
|
|
76
|
+
number: "text-sky-600 dark:text-sky-400",
|
|
77
|
+
boolean: "text-violet-600 dark:text-violet-400",
|
|
78
|
+
null: "text-muted-foreground",
|
|
79
|
+
other: "text-muted-foreground",
|
|
80
|
+
object: "text-muted-foreground",
|
|
81
|
+
array: "text-muted-foreground"
|
|
82
|
+
};
|
|
83
|
+
function JsonViewer({ value, rootName = "root", defaultExpandedDepth = 1, maxStringLength = 120, copyable = true, label = "JSON", className, ...rootProps }) {
|
|
84
|
+
const [expanded, setExpanded] = React$1.useState(() => pathsToDepth(value, rootName, defaultExpandedDepth));
|
|
85
|
+
const [copied, setCopied] = React$1.useState(null);
|
|
86
|
+
const [activePath, setActivePath] = React$1.useState(null);
|
|
87
|
+
const containerRef = React$1.useRef(null);
|
|
88
|
+
const timer = React$1.useRef(null);
|
|
89
|
+
React$1.useEffect(() => () => {
|
|
90
|
+
if (timer.current) clearTimeout(timer.current);
|
|
91
|
+
}, []);
|
|
92
|
+
const rows = React$1.useMemo(() => flatten(value, expanded, rootName), [
|
|
93
|
+
value,
|
|
94
|
+
expanded,
|
|
95
|
+
rootName
|
|
96
|
+
]);
|
|
97
|
+
const active = activePath && rows.some((row) => row.path === activePath) ? activePath : rows[0]?.path;
|
|
98
|
+
const toggle = (path, open) => {
|
|
99
|
+
setExpanded((current) => {
|
|
100
|
+
const shouldOpen = open ?? !current.has(path);
|
|
101
|
+
if (shouldOpen === current.has(path)) return current;
|
|
102
|
+
const next = new Set(current);
|
|
103
|
+
if (shouldOpen) next.add(path);
|
|
104
|
+
else next.delete(path);
|
|
105
|
+
return next;
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
const focusRow = (index) => {
|
|
109
|
+
const target = rows[index];
|
|
110
|
+
if (!target) return;
|
|
111
|
+
setActivePath(target.path);
|
|
112
|
+
containerRef.current?.querySelector(`[data-path="${CSS.escape(target.path)}"]`)?.focus();
|
|
113
|
+
};
|
|
114
|
+
async function copyValue(row) {
|
|
115
|
+
try {
|
|
116
|
+
await navigator.clipboard.writeText(typeof row.value === "string" ? row.value : JSON.stringify(row.value, null, 2));
|
|
117
|
+
setCopied(row.path);
|
|
118
|
+
} catch {
|
|
119
|
+
setCopied(null);
|
|
120
|
+
}
|
|
121
|
+
if (timer.current) clearTimeout(timer.current);
|
|
122
|
+
timer.current = setTimeout(() => setCopied(null), 1400);
|
|
123
|
+
}
|
|
124
|
+
const onKeyDown = (event, row, index) => {
|
|
125
|
+
switch (event.key) {
|
|
126
|
+
case "ArrowDown":
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
focusRow(Math.min(index + 1, rows.length - 1));
|
|
129
|
+
break;
|
|
130
|
+
case "ArrowUp":
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
focusRow(Math.max(index - 1, 0));
|
|
133
|
+
break;
|
|
134
|
+
case "ArrowRight":
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
if (row.branch && !row.expanded) toggle(row.path, true);
|
|
137
|
+
else if (row.branch) focusRow(index + 1);
|
|
138
|
+
break;
|
|
139
|
+
case "ArrowLeft": {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
if (row.branch && row.expanded) {
|
|
142
|
+
toggle(row.path, false);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const back = rows.slice(0, index).reverse().findIndex((entry) => entry.level < row.level);
|
|
146
|
+
if (back >= 0) focusRow(index - 1 - back);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case "Home":
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
focusRow(0);
|
|
152
|
+
break;
|
|
153
|
+
case "End":
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
focusRow(rows.length - 1);
|
|
156
|
+
break;
|
|
157
|
+
case "Enter":
|
|
158
|
+
case " ":
|
|
159
|
+
if (!row.branch) break;
|
|
160
|
+
event.preventDefault();
|
|
161
|
+
toggle(row.path);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
165
|
+
"data-slot": "json-viewer",
|
|
166
|
+
ref: containerRef,
|
|
167
|
+
className: cn("border-border bg-muted/40 min-w-0 overflow-hidden rounded-[calc(var(--radius)+0.15rem)] border font-mono text-xs", className),
|
|
168
|
+
...rootProps,
|
|
169
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
170
|
+
role: "tree",
|
|
171
|
+
"aria-label": label,
|
|
172
|
+
className: "max-h-96 overflow-auto py-1",
|
|
173
|
+
children: rows.map((row, index) => {
|
|
174
|
+
const preview = row.kind === "string" ? JSON.stringify(row.value).length > maxStringLength ? `${JSON.stringify(row.value).slice(0, maxStringLength)}…"` : JSON.stringify(row.value) : row.branch || row.kind === "object" || row.kind === "array" ? summarise(row.value, row.kind) : String(row.value);
|
|
175
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
176
|
+
"data-path": row.path,
|
|
177
|
+
role: "treeitem",
|
|
178
|
+
"aria-level": row.level,
|
|
179
|
+
"aria-expanded": row.branch ? row.expanded : void 0,
|
|
180
|
+
"aria-selected": row.path === active,
|
|
181
|
+
tabIndex: row.path === active ? 0 : -1,
|
|
182
|
+
onFocus: () => setActivePath(row.path),
|
|
183
|
+
onKeyDown: (event) => onKeyDown(event, row, index),
|
|
184
|
+
onClick: () => row.branch && toggle(row.path),
|
|
185
|
+
style: { paddingInlineStart: `${row.level * .85}rem` },
|
|
186
|
+
className: cn("group hover:bg-muted/70 focus-visible:ring-ring flex min-h-7 items-center gap-1.5 pr-2 focus-visible:ring-2 focus-visible:outline-none", row.branch && "cursor-pointer"),
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ jsx(ChevronRight, {
|
|
189
|
+
"aria-hidden": "true",
|
|
190
|
+
size: 13,
|
|
191
|
+
className: cn("text-muted-foreground shrink-0 transition-transform motion-reduce:transition-none", !row.branch && "invisible", row.expanded && "rotate-90")
|
|
192
|
+
}),
|
|
193
|
+
row.key !== null ? /* @__PURE__ */ jsx("span", {
|
|
194
|
+
className: "text-foreground shrink-0",
|
|
195
|
+
children: row.index === null ? `${row.key}:` : `${row.index}:`
|
|
196
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
197
|
+
className: "text-muted-foreground shrink-0",
|
|
198
|
+
children: rootName
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ jsx("span", {
|
|
201
|
+
className: cn("truncate", VALUE_CLASS[row.kind]),
|
|
202
|
+
children: preview
|
|
203
|
+
}),
|
|
204
|
+
copyable ? /* @__PURE__ */ jsx("button", {
|
|
205
|
+
type: "button",
|
|
206
|
+
"aria-label": copied === row.path ? "Copied" : `Copy ${row.path}`,
|
|
207
|
+
onClick: (event) => {
|
|
208
|
+
event.stopPropagation();
|
|
209
|
+
copyValue(row);
|
|
210
|
+
},
|
|
211
|
+
className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring ml-auto hidden size-6 shrink-0 items-center justify-center rounded group-focus-within:flex group-hover:flex focus-visible:ring-2 focus-visible:outline-none",
|
|
212
|
+
children: copied === row.path ? /* @__PURE__ */ jsx(Check, {
|
|
213
|
+
"aria-hidden": "true",
|
|
214
|
+
size: 12
|
|
215
|
+
}) : /* @__PURE__ */ jsx(Clipboard, {
|
|
216
|
+
"aria-hidden": "true",
|
|
217
|
+
size: 12
|
|
218
|
+
})
|
|
219
|
+
}) : null
|
|
220
|
+
]
|
|
221
|
+
}, row.path);
|
|
222
|
+
})
|
|
223
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
224
|
+
"aria-live": "polite",
|
|
225
|
+
className: "sr-only",
|
|
226
|
+
children: copied ? `${copied} copied to clipboard.` : ""
|
|
227
|
+
})]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
export { JsonViewer };
|
package/dist/widgets/index.d.mts
CHANGED
|
@@ -32,6 +32,7 @@ import { Dropzone, formatSize } from "./dropzone.mjs";
|
|
|
32
32
|
import { LightboxActions, LightboxBackdrop, LightboxCaptions, LightboxChangeReason, LightboxClose, LightboxContent, LightboxControl, LightboxControlContext, LightboxCounter, LightboxDownload, LightboxImageChangeEventDetails, LightboxImageItem, LightboxItem, LightboxMore, LightboxNext, LightboxOpenEventDetails, LightboxPrevious, LightboxProps, LightboxSlide, LightboxSlides, LightboxThumbnail, LightboxThumbnails, LightboxToolbar, LightboxTrigger, LightboxTriggerProps, LightboxVideoItem, LightboxViewport, LightboxZoom, LightboxZoomButton, useLightbox } from "../vendor/tailored/lightbox.mjs";
|
|
33
33
|
import { Carousel, Image, ImageProps, Lightbox } from "./multimedia.mjs";
|
|
34
34
|
import { Pagination } from "./pagination.mjs";
|
|
35
|
+
import { Form } from "../vendor/coss/form.mjs";
|
|
35
36
|
import { Badge } from "../vendor/shadcn/badge.mjs";
|
|
36
37
|
import { Switch } from "../vendor/shadcn/switch.mjs";
|
|
37
38
|
import { Spinner } from "../vendor/shadcn/spinner.mjs";
|
|
@@ -39,8 +40,9 @@ import { Skeleton } from "../vendor/shadcn/skeleton.mjs";
|
|
|
39
40
|
import { Checkbox } from "../vendor/shadcn/checkbox.mjs";
|
|
40
41
|
import { Textarea } from "../vendor/shadcn/textarea.mjs";
|
|
41
42
|
import { ScrollArea } from "../vendor/coss/scroll-area.mjs";
|
|
42
|
-
import { Form } from "../vendor/coss/form.mjs";
|
|
43
43
|
import { IconSwap } from "../vendor/tailored/icon-swap.mjs";
|
|
44
|
+
import { JsonViewer } from "../vendor/tailored/json-viewer.mjs";
|
|
45
|
+
import { FileTree, FileTreeNode } from "../vendor/tailored/file-tree.mjs";
|
|
44
46
|
export declare const Kbd: typeof Kbd$1 & {
|
|
45
47
|
Group: typeof KbdGroup;
|
|
46
48
|
};
|
|
@@ -185,4 +187,4 @@ export declare const InputGroup: typeof InputGroup$1 & {
|
|
|
185
187
|
Textarea: typeof InputGroupTextarea;
|
|
186
188
|
Button: typeof InputGroupButton;
|
|
187
189
|
};
|
|
188
|
-
export { type AlertDialogHandle, Badge, Button, Carousel, Checkbox, type ComboboxItemCollection, type ComboboxPrimitiveValue, type CreateComboboxItemsOptions, DatePicker, type DateRange, DateRangePicker, type DialogHandle, type DrawerHandle, Dropzone, Form, IconSwap, Image, ImageProps, Input, Label, Lightbox, type LightboxActions, type LightboxBackdrop, type LightboxCaptions, type LightboxChangeReason, type LightboxClose, type LightboxContent, type LightboxControl, type LightboxControlContext, type LightboxCounter, type LightboxDownload, type LightboxImageChangeEventDetails, type LightboxImageItem, type LightboxItem, type LightboxMore, type LightboxNext, type LightboxOpenEventDetails, type LightboxPrevious, type LightboxProps, type LightboxSlide, type LightboxSlides, type LightboxThumbnail, type LightboxThumbnails, type LightboxToolbar, type LightboxTrigger, type LightboxTriggerProps, type LightboxVideoItem, type LightboxViewport, type LightboxZoom, type LightboxZoomButton, Pagination, ScrollArea, Separator, Sidebar, Skeleton, Spinner, Switch, Textarea, TimePicker, Toaster as ToastProvider, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, formatSize, toast, type useLightbox, useSidebar };
|
|
190
|
+
export { type AlertDialogHandle, Badge, Button, Carousel, Checkbox, type ComboboxItemCollection, type ComboboxPrimitiveValue, type CreateComboboxItemsOptions, DatePicker, type DateRange, DateRangePicker, type DialogHandle, type DrawerHandle, Dropzone, FileTree, type FileTreeNode, Form, IconSwap, Image, ImageProps, Input, JsonViewer, Label, Lightbox, type LightboxActions, type LightboxBackdrop, type LightboxCaptions, type LightboxChangeReason, type LightboxClose, type LightboxContent, type LightboxControl, type LightboxControlContext, type LightboxCounter, type LightboxDownload, type LightboxImageChangeEventDetails, type LightboxImageItem, type LightboxItem, type LightboxMore, type LightboxNext, type LightboxOpenEventDetails, type LightboxPrevious, type LightboxProps, type LightboxSlide, type LightboxSlides, type LightboxThumbnail, type LightboxThumbnails, type LightboxToolbar, type LightboxTrigger, type LightboxTriggerProps, type LightboxVideoItem, type LightboxViewport, type LightboxZoom, type LightboxZoomButton, Pagination, ScrollArea, Separator, Sidebar, Skeleton, Spinner, Switch, Textarea, TimePicker, Toaster as ToastProvider, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, formatSize, toast, type useLightbox, useSidebar };
|
package/dist/widgets/index.mjs
CHANGED
|
@@ -32,12 +32,14 @@ import { DatePicker, DateRangePicker, TimePicker } from "./datetime.mjs";
|
|
|
32
32
|
import { Dropzone, formatSize } from "./dropzone.mjs";
|
|
33
33
|
import { Carousel, Image, Lightbox } from "./multimedia.mjs";
|
|
34
34
|
import { Pagination } from "./pagination.mjs";
|
|
35
|
+
import { Form } from "../vendor/coss/form.mjs";
|
|
35
36
|
import { Badge } from "../vendor/shadcn/badge.mjs";
|
|
36
37
|
import { Switch } from "../vendor/shadcn/switch.mjs";
|
|
37
38
|
import { Checkbox } from "../vendor/shadcn/checkbox.mjs";
|
|
38
39
|
import { ScrollArea } from "../vendor/coss/scroll-area.mjs";
|
|
39
|
-
import { Form } from "../vendor/coss/form.mjs";
|
|
40
40
|
import { IconSwap } from "../vendor/tailored/icon-swap.mjs";
|
|
41
|
+
import { JsonViewer } from "../vendor/tailored/json-viewer.mjs";
|
|
42
|
+
import { FileTree } from "../vendor/tailored/file-tree.mjs";
|
|
41
43
|
// src/widgets/index.ts
|
|
42
44
|
const Kbd = /* @__PURE__ */ Object.assign(Kbd$1, { Group: KbdGroup });
|
|
43
45
|
const Tabs = /* @__PURE__ */ Object.assign(Tabs$1, {
|
|
@@ -177,4 +179,4 @@ const InputGroup = /* @__PURE__ */ Object.assign(InputGroup$1, {
|
|
|
177
179
|
Textarea: InputGroupTextarea,
|
|
178
180
|
Button: InputGroupButton
|
|
179
181
|
});
|
|
180
|
-
export { AlertDialog, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, DatePicker, DateRangePicker, Dialog, Drawer, Dropdown, Dropzone, Empty, Field, Form, IconSwap, Image, Input, InputGroup, Kbd, Label, Lightbox, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, formatSize, toast, useSidebar };
|
|
182
|
+
export { AlertDialog, Badge, Breadcrumb, Button, ButtonGroup, Calendar, Card, Carousel, Checkbox, Combobox, DatePicker, DateRangePicker, Dialog, Drawer, Dropdown, Dropzone, Empty, Field, FileTree, Form, IconSwap, Image, Input, InputGroup, JsonViewer, Kbd, Label, Lightbox, Pagination, Popover, Progress, Radio, ScrollArea, Select, Separator, Sidebar, Skeleton, Spinner, Switch, Table, Tabs, Textarea, TimePicker, Toaster as ToastProvider, Tooltip, createAlertDialogHandle, createComboboxItems, createDialogHandle, createDrawerHandle, formatSize, toast, useSidebar };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftui/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/KiriRainCat/deftui.git",
|
|
@@ -33,28 +33,29 @@
|
|
|
33
33
|
"fix": "vp check --fix"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@base-ui/react": "^1.9.0",
|
|
37
36
|
"@daypicker/react": "^10.0.2",
|
|
38
37
|
"@fontsource-variable/inter": "^5.3.0",
|
|
39
38
|
"class-variance-authority": "^0.7.1",
|
|
40
|
-
"cn": "^0.5.
|
|
39
|
+
"cn": "^0.5.1",
|
|
41
40
|
"date-fns": "^4.4.0",
|
|
42
41
|
"embla-carousel-react": "^8.6.0",
|
|
43
|
-
"lucide-react": "^1.
|
|
44
|
-
"motion": "^14.
|
|
45
|
-
"radashi": "^
|
|
42
|
+
"lucide-react": "^1.66.0",
|
|
43
|
+
"motion": "^14.9.0",
|
|
44
|
+
"radashi": "^13.0.1",
|
|
46
45
|
"react-dropzone": "^20.1.4",
|
|
47
46
|
"tw-animate-css": "^1.4.0"
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
49
|
+
"@base-ui/react": "^1.9.0",
|
|
50
50
|
"@types/react": "^19.3.0",
|
|
51
51
|
"@types/react-dom": "^19.3.0",
|
|
52
|
-
"shadcn": "^4.
|
|
52
|
+
"shadcn": "^4.23.0",
|
|
53
53
|
"vite-plus": "catalog:"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"react": "^
|
|
57
|
-
"react
|
|
58
|
-
"
|
|
56
|
+
"@base-ui/react": "^1.9.0",
|
|
57
|
+
"react": "^19.0.0",
|
|
58
|
+
"react-dom": "^19.0.0",
|
|
59
|
+
"tailwindcss": "^4.3.0"
|
|
59
60
|
}
|
|
60
61
|
}
|