@ddd-ts/event-tree-viewer 0.0.0-eventviz.10
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 +21 -0
- package/dist/cli.mjs +20 -0
- package/index.html +13 -0
- package/package.json +67 -0
- package/src/App.tsx +153 -0
- package/src/application/trpc-client.ts +6 -0
- package/src/application/use-direction.ts +18 -0
- package/src/application/use-domains.ts +9 -0
- package/src/application/use-expansion.ts +42 -0
- package/src/application/use-filters.ts +78 -0
- package/src/application/use-graph.ts +38 -0
- package/src/application/use-reveal.ts +26 -0
- package/src/application/use-selection.ts +15 -0
- package/src/application/use-settings.ts +84 -0
- package/src/application/use-view-mode.ts +14 -0
- package/src/assets/fonts/Monor_Regular.otf +0 -0
- package/src/assets/fonts/Supreme-Variable.woff2 +0 -0
- package/src/assets/fonts/Supreme-VariableItalic.woff2 +0 -0
- package/src/assets/fonts/monor-bold.otf +0 -0
- package/src/assets/react.svg +1 -0
- package/src/cli.ts +29 -0
- package/src/components/direction-toggle.tsx +28 -0
- package/src/components/domain-header.tsx +44 -0
- package/src/components/export-dialog.tsx +164 -0
- package/src/components/filter-bar.tsx +17 -0
- package/src/components/header.tsx +37 -0
- package/src/components/inspector.tsx +183 -0
- package/src/components/kind-filter.tsx +70 -0
- package/src/components/node-badge.tsx +19 -0
- package/src/components/node-name.tsx +66 -0
- package/src/components/settings-menu.tsx +147 -0
- package/src/components/ui/badge.tsx +52 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +103 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/dialog.tsx +108 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/popover.tsx +88 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +88 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +43 -0
- package/src/components/view-switcher.tsx +28 -0
- package/src/components/views/graph-view.tsx +1203 -0
- package/src/components/views/list-view.tsx +109 -0
- package/src/components/views/tree-view.tsx +485 -0
- package/src/domain/cypher-export.ts +66 -0
- package/src/domain/direction.ts +1 -0
- package/src/domain/domain-grouping.ts +217 -0
- package/src/domain/edge.ts +37 -0
- package/src/domain/filter.ts +21 -0
- package/src/domain/flatten-tree.ts +167 -0
- package/src/domain/graph.ts +42 -0
- package/src/domain/node.ts +28 -0
- package/src/domain/roots.ts +18 -0
- package/src/domain/traversal.ts +60 -0
- package/src/index.css +205 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +16 -0
- package/src/server/router.ts +87 -0
- package/src/server/vite-plugin.ts +99 -0
- package/vite.config.ts +36 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
import {
|
|
3
|
+
GearSixIcon,
|
|
4
|
+
MonitorIcon,
|
|
5
|
+
MoonIcon,
|
|
6
|
+
SunIcon,
|
|
7
|
+
} from "@phosphor-icons/react"
|
|
8
|
+
import { Button } from "@/components/ui/button"
|
|
9
|
+
import { Checkbox } from "@/components/ui/checkbox"
|
|
10
|
+
import {
|
|
11
|
+
Popover,
|
|
12
|
+
PopoverContent,
|
|
13
|
+
PopoverTrigger,
|
|
14
|
+
} from "@/components/ui/popover"
|
|
15
|
+
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
|
16
|
+
import type {
|
|
17
|
+
FontSize,
|
|
18
|
+
Settings,
|
|
19
|
+
SettingsApi,
|
|
20
|
+
Theme,
|
|
21
|
+
} from "@/application/use-settings"
|
|
22
|
+
|
|
23
|
+
interface BoolOption {
|
|
24
|
+
key: keyof Settings
|
|
25
|
+
label: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const BOOL_OPTIONS: BoolOption[] = [
|
|
29
|
+
{ key: "hideDomainPrefix", label: "Hide domain prefix in names" },
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const FONT_SIZES: { value: FontSize; preview: string }[] = [
|
|
33
|
+
{ value: "sm", preview: "text-xs" },
|
|
34
|
+
{ value: "md", preview: "text-sm" },
|
|
35
|
+
{ value: "lg", preview: "text-base" },
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const THEMES: { value: Theme; icon: ReactNode; label: string }[] = [
|
|
39
|
+
{ value: "light", icon: <SunIcon />, label: "Light" },
|
|
40
|
+
{ value: "auto", icon: <MonitorIcon />, label: "Auto" },
|
|
41
|
+
{ value: "dark", icon: <MoonIcon />, label: "Dark" },
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
export function SettingsMenu({ settings }: { settings: SettingsApi }) {
|
|
45
|
+
return (
|
|
46
|
+
<Popover>
|
|
47
|
+
<PopoverTrigger
|
|
48
|
+
render={
|
|
49
|
+
<Button variant="ghost" size="icon-sm" aria-label="Settings">
|
|
50
|
+
<GearSixIcon />
|
|
51
|
+
</Button>
|
|
52
|
+
}
|
|
53
|
+
/>
|
|
54
|
+
<PopoverContent align="end" className="w-64 p-1">
|
|
55
|
+
<ul className="flex flex-col">
|
|
56
|
+
{BOOL_OPTIONS.map((opt) => (
|
|
57
|
+
<li key={opt.key}>
|
|
58
|
+
<SettingOption
|
|
59
|
+
label={opt.label}
|
|
60
|
+
checked={settings.settings[opt.key] as boolean}
|
|
61
|
+
onToggle={() => settings.toggle(opt.key as "hideDomainPrefix")}
|
|
62
|
+
/>
|
|
63
|
+
</li>
|
|
64
|
+
))}
|
|
65
|
+
<li>
|
|
66
|
+
<FontSizeOption settings={settings} />
|
|
67
|
+
</li>
|
|
68
|
+
<li>
|
|
69
|
+
<ThemeOption settings={settings} />
|
|
70
|
+
</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</PopoverContent>
|
|
73
|
+
</Popover>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function SettingOption({
|
|
78
|
+
label,
|
|
79
|
+
checked,
|
|
80
|
+
onToggle,
|
|
81
|
+
}: {
|
|
82
|
+
label: string
|
|
83
|
+
checked: boolean
|
|
84
|
+
onToggle: () => void
|
|
85
|
+
}) {
|
|
86
|
+
return (
|
|
87
|
+
<label className="flex cursor-pointer items-center gap-2 px-2 py-1.5 text-sm transition-colors hover:bg-muted hover:text-foreground">
|
|
88
|
+
<Checkbox checked={checked} onCheckedChange={onToggle} />
|
|
89
|
+
<span>{label}</span>
|
|
90
|
+
</label>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function FontSizeOption({ settings }: { settings: SettingsApi }) {
|
|
95
|
+
return (
|
|
96
|
+
<div className="flex items-center justify-between gap-2 px-2 py-1.5 text-sm">
|
|
97
|
+
<span>Row size</span>
|
|
98
|
+
<ToggleGroup
|
|
99
|
+
value={[settings.settings.fontSize]}
|
|
100
|
+
onValueChange={(next) => {
|
|
101
|
+
const picked = next[0] as FontSize | undefined
|
|
102
|
+
if (picked) settings.setFontSize(picked)
|
|
103
|
+
}}
|
|
104
|
+
variant="outline"
|
|
105
|
+
size="sm"
|
|
106
|
+
>
|
|
107
|
+
{FONT_SIZES.map((size) => (
|
|
108
|
+
<ToggleGroupItem
|
|
109
|
+
key={size.value}
|
|
110
|
+
value={size.value}
|
|
111
|
+
className="size-7"
|
|
112
|
+
>
|
|
113
|
+
<span className={size.preview}>A</span>
|
|
114
|
+
</ToggleGroupItem>
|
|
115
|
+
))}
|
|
116
|
+
</ToggleGroup>
|
|
117
|
+
</div>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function ThemeOption({ settings }: { settings: SettingsApi }) {
|
|
122
|
+
return (
|
|
123
|
+
<div className="flex items-center justify-between gap-2 px-2 py-1.5 text-sm">
|
|
124
|
+
<span>Theme</span>
|
|
125
|
+
<ToggleGroup
|
|
126
|
+
value={[settings.settings.theme]}
|
|
127
|
+
onValueChange={(next) => {
|
|
128
|
+
const picked = next[0] as Theme | undefined
|
|
129
|
+
if (picked) settings.setTheme(picked)
|
|
130
|
+
}}
|
|
131
|
+
variant="outline"
|
|
132
|
+
size="sm"
|
|
133
|
+
>
|
|
134
|
+
{THEMES.map((theme) => (
|
|
135
|
+
<ToggleGroupItem
|
|
136
|
+
key={theme.value}
|
|
137
|
+
value={theme.value}
|
|
138
|
+
aria-label={theme.label}
|
|
139
|
+
className="size-7"
|
|
140
|
+
>
|
|
141
|
+
{theme.icon}
|
|
142
|
+
</ToggleGroupItem>
|
|
143
|
+
))}
|
|
144
|
+
</ToggleGroup>
|
|
145
|
+
</div>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-none border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
13
|
+
secondary:
|
|
14
|
+
"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
|
15
|
+
destructive:
|
|
16
|
+
"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
|
|
17
|
+
outline:
|
|
18
|
+
"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
|
|
19
|
+
ghost:
|
|
20
|
+
"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
|
|
21
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: "default",
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function Badge({
|
|
31
|
+
className,
|
|
32
|
+
variant = "default",
|
|
33
|
+
render,
|
|
34
|
+
...props
|
|
35
|
+
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
|
|
36
|
+
return useRender({
|
|
37
|
+
defaultTagName: "span",
|
|
38
|
+
props: mergeProps<"span">(
|
|
39
|
+
{
|
|
40
|
+
className: cn(badgeVariants({ variant }), className),
|
|
41
|
+
},
|
|
42
|
+
props
|
|
43
|
+
),
|
|
44
|
+
render,
|
|
45
|
+
state: {
|
|
46
|
+
slot: "badge",
|
|
47
|
+
variant,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
12
|
+
outline:
|
|
13
|
+
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
14
|
+
secondary:
|
|
15
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
16
|
+
ghost:
|
|
17
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
18
|
+
destructive:
|
|
19
|
+
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
default:
|
|
24
|
+
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
25
|
+
xs: "h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
+
sm: "h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
27
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
28
|
+
icon: "size-8",
|
|
29
|
+
"icon-xs": "size-6 rounded-none [&_svg:not([class*='size-'])]:size-3",
|
|
30
|
+
"icon-sm": "size-7 rounded-none",
|
|
31
|
+
"icon-lg": "size-9",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
variant: "default",
|
|
36
|
+
size: "default",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
function Button({
|
|
42
|
+
className,
|
|
43
|
+
variant = "default",
|
|
44
|
+
size = "default",
|
|
45
|
+
...props
|
|
46
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
47
|
+
return (
|
|
48
|
+
<ButtonPrimitive
|
|
49
|
+
data-slot="button"
|
|
50
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Card({
|
|
6
|
+
className,
|
|
7
|
+
size = "default",
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card"
|
|
13
|
+
data-size={size}
|
|
14
|
+
className={cn(
|
|
15
|
+
"group/card flex flex-col gap-4 overflow-hidden rounded-none bg-card py-4 text-xs/relaxed text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-2 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-none *:[img:last-child]:rounded-none",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
data-slot="card-header"
|
|
27
|
+
className={cn(
|
|
28
|
+
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-none px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
data-slot="card-title"
|
|
40
|
+
className={cn(
|
|
41
|
+
"font-heading text-sm font-medium group-data-[size=sm]/card:text-sm",
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-slot="card-description"
|
|
53
|
+
className={cn("text-xs/relaxed text-muted-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
data-slot="card-action"
|
|
63
|
+
className={cn(
|
|
64
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
65
|
+
className
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="card-content"
|
|
76
|
+
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
data-slot="card-footer"
|
|
86
|
+
className={cn(
|
|
87
|
+
"flex items-center rounded-none border-t p-4 group-data-[size=sm]/card:p-3",
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
Card,
|
|
97
|
+
CardHeader,
|
|
98
|
+
CardFooter,
|
|
99
|
+
CardTitle,
|
|
100
|
+
CardAction,
|
|
101
|
+
CardDescription,
|
|
102
|
+
CardContent,
|
|
103
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
import { CheckIcon } from "@phosphor-icons/react"
|
|
7
|
+
|
|
8
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
9
|
+
return (
|
|
10
|
+
<CheckboxPrimitive.Root
|
|
11
|
+
data-slot="checkbox"
|
|
12
|
+
className={cn(
|
|
13
|
+
"peer relative flex size-4 shrink-0 items-center justify-center rounded-none border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<CheckboxPrimitive.Indicator
|
|
19
|
+
data-slot="checkbox-indicator"
|
|
20
|
+
className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
|
|
21
|
+
>
|
|
22
|
+
<CheckIcon />
|
|
23
|
+
</CheckboxPrimitive.Indicator>
|
|
24
|
+
</CheckboxPrimitive.Root>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { Checkbox }
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
|
|
3
|
+
import { XIcon } from "@phosphor-icons/react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
|
|
8
|
+
return <DialogPrimitive.Root {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
|
|
12
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
|
|
16
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function DialogContent({
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
showCloseButton = true,
|
|
23
|
+
...props
|
|
24
|
+
}: DialogPrimitive.Popup.Props & { showCloseButton?: boolean }) {
|
|
25
|
+
return (
|
|
26
|
+
<DialogPrimitive.Portal>
|
|
27
|
+
<DialogPrimitive.Backdrop
|
|
28
|
+
data-slot="dialog-backdrop"
|
|
29
|
+
className="fixed inset-0 z-50 bg-background/70 backdrop-blur-[2px] data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0"
|
|
30
|
+
/>
|
|
31
|
+
<DialogPrimitive.Popup
|
|
32
|
+
data-slot="dialog-content"
|
|
33
|
+
className={cn(
|
|
34
|
+
"surface-elevated fixed top-1/2 left-1/2 z-50 flex w-full max-w-lg -translate-x-1/2 -translate-y-1/2 flex-col gap-4 rounded-none bg-popover p-5 text-popover-foreground shadow-lg ring-1 ring-foreground/10 outline-hidden duration-150 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
{showCloseButton && (
|
|
41
|
+
<DialogPrimitive.Close
|
|
42
|
+
aria-label="Close"
|
|
43
|
+
className="absolute top-3 right-3 inline-flex size-7 items-center justify-center rounded-none text-muted-foreground transition-colors outline-none hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring"
|
|
44
|
+
>
|
|
45
|
+
<XIcon className="size-4" />
|
|
46
|
+
</DialogPrimitive.Close>
|
|
47
|
+
)}
|
|
48
|
+
</DialogPrimitive.Popup>
|
|
49
|
+
</DialogPrimitive.Portal>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
data-slot="dialog-header"
|
|
57
|
+
className={cn("flex flex-col gap-1.5", className)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
data-slot="dialog-footer"
|
|
67
|
+
className={cn(
|
|
68
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
|
|
77
|
+
return (
|
|
78
|
+
<DialogPrimitive.Title
|
|
79
|
+
data-slot="dialog-title"
|
|
80
|
+
className={cn("text-sm font-medium", className)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function DialogDescription({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: DialogPrimitive.Description.Props) {
|
|
90
|
+
return (
|
|
91
|
+
<DialogPrimitive.Description
|
|
92
|
+
data-slot="dialog-description"
|
|
93
|
+
className={cn("text-xs text-muted-foreground", className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
Dialog,
|
|
101
|
+
DialogClose,
|
|
102
|
+
DialogContent,
|
|
103
|
+
DialogDescription,
|
|
104
|
+
DialogFooter,
|
|
105
|
+
DialogHeader,
|
|
106
|
+
DialogTitle,
|
|
107
|
+
DialogTrigger,
|
|
108
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Input as InputPrimitive } from "@base-ui/react/input"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
7
|
+
return (
|
|
8
|
+
<InputPrimitive
|
|
9
|
+
type={type}
|
|
10
|
+
data-slot="input"
|
|
11
|
+
className={cn(
|
|
12
|
+
"h-8 w-full min-w-0 rounded-none border border-input bg-transparent px-2.5 py-1 text-xs transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 md:text-xs dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Input }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
function Popover({ ...props }: PopoverPrimitive.Root.Props) {
|
|
7
|
+
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
|
|
11
|
+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function PopoverContent({
|
|
15
|
+
className,
|
|
16
|
+
align = "center",
|
|
17
|
+
alignOffset = 0,
|
|
18
|
+
side = "bottom",
|
|
19
|
+
sideOffset = 4,
|
|
20
|
+
...props
|
|
21
|
+
}: PopoverPrimitive.Popup.Props &
|
|
22
|
+
Pick<
|
|
23
|
+
PopoverPrimitive.Positioner.Props,
|
|
24
|
+
"align" | "alignOffset" | "side" | "sideOffset"
|
|
25
|
+
>) {
|
|
26
|
+
return (
|
|
27
|
+
<PopoverPrimitive.Portal>
|
|
28
|
+
<PopoverPrimitive.Positioner
|
|
29
|
+
align={align}
|
|
30
|
+
alignOffset={alignOffset}
|
|
31
|
+
side={side}
|
|
32
|
+
sideOffset={sideOffset}
|
|
33
|
+
className="isolate z-50"
|
|
34
|
+
>
|
|
35
|
+
<PopoverPrimitive.Popup
|
|
36
|
+
data-slot="popover-content"
|
|
37
|
+
className={cn(
|
|
38
|
+
"z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-none bg-popover p-2.5 text-xs text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
</PopoverPrimitive.Positioner>
|
|
44
|
+
</PopoverPrimitive.Portal>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
data-slot="popover-header"
|
|
52
|
+
className={cn("flex flex-col gap-1 text-xs", className)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
|
|
59
|
+
return (
|
|
60
|
+
<PopoverPrimitive.Title
|
|
61
|
+
data-slot="popover-title"
|
|
62
|
+
className={cn("text-sm font-medium", className)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function PopoverDescription({
|
|
69
|
+
className,
|
|
70
|
+
...props
|
|
71
|
+
}: PopoverPrimitive.Description.Props) {
|
|
72
|
+
return (
|
|
73
|
+
<PopoverPrimitive.Description
|
|
74
|
+
data-slot="popover-description"
|
|
75
|
+
className={cn("text-xs/relaxed text-muted-foreground", className)}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
Popover,
|
|
83
|
+
PopoverContent,
|
|
84
|
+
PopoverDescription,
|
|
85
|
+
PopoverHeader,
|
|
86
|
+
PopoverTitle,
|
|
87
|
+
PopoverTrigger,
|
|
88
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
function ScrollArea({
|
|
8
|
+
className,
|
|
9
|
+
children,
|
|
10
|
+
...props
|
|
11
|
+
}: ScrollAreaPrimitive.Root.Props) {
|
|
12
|
+
return (
|
|
13
|
+
<ScrollAreaPrimitive.Root
|
|
14
|
+
data-slot="scroll-area"
|
|
15
|
+
className={cn("relative", className)}
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<ScrollAreaPrimitive.Viewport
|
|
19
|
+
data-slot="scroll-area-viewport"
|
|
20
|
+
className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</ScrollAreaPrimitive.Viewport>
|
|
24
|
+
<ScrollBar />
|
|
25
|
+
<ScrollAreaPrimitive.Corner />
|
|
26
|
+
</ScrollAreaPrimitive.Root>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ScrollBar({
|
|
31
|
+
className,
|
|
32
|
+
orientation = "vertical",
|
|
33
|
+
...props
|
|
34
|
+
}: ScrollAreaPrimitive.Scrollbar.Props) {
|
|
35
|
+
return (
|
|
36
|
+
<ScrollAreaPrimitive.Scrollbar
|
|
37
|
+
data-slot="scroll-area-scrollbar"
|
|
38
|
+
data-orientation={orientation}
|
|
39
|
+
orientation={orientation}
|
|
40
|
+
className={cn(
|
|
41
|
+
"flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
<ScrollAreaPrimitive.Thumb
|
|
47
|
+
data-slot="scroll-area-thumb"
|
|
48
|
+
className="relative flex-1 rounded-none bg-border"
|
|
49
|
+
/>
|
|
50
|
+
</ScrollAreaPrimitive.Scrollbar>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { ScrollArea, ScrollBar }
|