@moloodev/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +139 -3
- package/registry/components.ts +135 -0
- package/registry/fonts.css +81 -0
- package/registry/suit-OFL.txt +94 -0
- package/registry/wanted-sans-OFL.txt +93 -0
- package/src/components/ui/accordion.tsx +74 -0
- package/src/components/ui/alert-dialog.tsx +187 -0
- package/src/components/ui/alert.tsx +83 -0
- package/src/components/ui/aspect-ratio.tsx +22 -0
- package/src/components/ui/attachment.tsx +207 -0
- package/src/components/ui/avatar.tsx +109 -0
- package/src/components/ui/badge.tsx +54 -0
- package/src/components/ui/breadcrumb.tsx +126 -0
- package/src/components/ui/bubble.tsx +128 -0
- package/src/components/ui/button-group.tsx +103 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/calendar.tsx +222 -0
- package/src/components/ui/card.tsx +103 -0
- package/src/components/ui/carousel.tsx +242 -0
- package/src/components/ui/chart.tsx +398 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/collapsible.tsx +40 -0
- package/src/components/ui/combobox.tsx +299 -0
- package/src/components/ui/command.tsx +218 -0
- package/src/components/ui/context-menu.tsx +271 -0
- package/src/components/ui/data-table.tsx +919 -0
- package/src/components/ui/date-picker.tsx +65 -0
- package/src/components/ui/dialog.tsx +224 -0
- package/src/components/ui/drawer.tsx +231 -0
- package/src/components/ui/dropdown-menu.tsx +268 -0
- package/src/components/ui/dropzone.tsx +186 -0
- package/src/components/ui/empty.tsx +101 -0
- package/src/components/ui/field.tsx +238 -0
- package/src/components/ui/form.tsx +83 -0
- package/src/components/ui/highlighted-source.tsx +200 -0
- package/src/components/ui/hover-card.tsx +51 -0
- package/src/components/ui/image-field.tsx +796 -0
- package/src/components/ui/input-group.tsx +149 -0
- package/src/components/ui/input-otp.tsx +86 -0
- package/src/components/ui/input-step.ts +19 -0
- package/src/components/ui/input.tsx +100 -0
- package/src/components/ui/item.tsx +201 -0
- package/src/components/ui/kbd.tsx +91 -0
- package/src/components/ui/kind-icon-glob.ts +24 -0
- package/src/components/ui/kind-icon-load.ts +52 -0
- package/src/components/ui/kind-icon-static.ts +46 -0
- package/src/components/ui/kind-icon.tsx +84 -0
- package/src/components/ui/kind-mark.tsx +65 -0
- package/src/components/ui/label.tsx +29 -0
- package/src/components/ui/marker.tsx +71 -0
- package/src/components/ui/menubar.tsx +277 -0
- package/src/components/ui/message-scroller.tsx +137 -0
- package/src/components/ui/message.tsx +92 -0
- package/src/components/ui/moloo-logo.tsx +45 -0
- package/src/components/ui/native-select.tsx +61 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/outline-list.tsx +73 -0
- package/src/components/ui/pagination.tsx +130 -0
- package/src/components/ui/panel.tsx +108 -0
- package/src/components/ui/popover.tsx +90 -0
- package/src/components/ui/progress.tsx +117 -0
- package/src/components/ui/radio-group.tsx +38 -0
- package/src/components/ui/resizable.tsx +52 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +205 -0
- package/src/components/ui/separator.tsx +25 -0
- package/src/components/ui/sheet.tsx +140 -0
- package/src/components/ui/sidebar.tsx +746 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +52 -0
- package/src/components/ui/spinner.tsx +18 -0
- package/src/components/ui/switch.tsx +32 -0
- package/src/components/ui/table.tsx +116 -0
- package/src/components/ui/tabs.tsx +83 -0
- package/src/components/ui/tag-list-input.tsx +194 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/timeline.tsx +265 -0
- package/src/components/ui/toast.tsx +237 -0
- package/src/components/ui/toggle-group.tsx +90 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/tooltip.tsx +66 -0
- package/src/css.d.ts +1 -0
- package/src/hooks/use-clipboard.ts +82 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/index.ts +106 -0
- package/src/kind-icon.ts +4 -0
- package/src/lib/format-relative-time.ts +41 -0
- package/src/lib/list-selection.ts +61 -0
- package/src/lib/utils.ts +6 -0
- package/src/moloo.css +360 -0
- package/src/styles.css +36 -0
- package/src/typeset.css +518 -0
- package/README.md +0 -3
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
import { IconDots } from "@tabler/icons-react"
|
|
7
|
+
|
|
8
|
+
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
|
|
9
|
+
return (
|
|
10
|
+
<nav
|
|
11
|
+
aria-label="breadcrumb"
|
|
12
|
+
data-slot="breadcrumb"
|
|
13
|
+
className={cn(className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
|
20
|
+
return (
|
|
21
|
+
<ol
|
|
22
|
+
data-slot="breadcrumb-list"
|
|
23
|
+
className={cn(
|
|
24
|
+
"flex flex-wrap items-center gap-1.5 text-sm font-semibold wrap-break-word text-muted-foreground",
|
|
25
|
+
className
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
33
|
+
return (
|
|
34
|
+
<li
|
|
35
|
+
data-slot="breadcrumb-item"
|
|
36
|
+
className={cn("inline-flex items-center gap-1", className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function BreadcrumbLink({
|
|
43
|
+
className,
|
|
44
|
+
render,
|
|
45
|
+
...props
|
|
46
|
+
}: useRender.ComponentProps<"a">) {
|
|
47
|
+
return useRender({
|
|
48
|
+
defaultTagName: "a",
|
|
49
|
+
props: mergeProps<"a">(
|
|
50
|
+
{
|
|
51
|
+
className: cn(
|
|
52
|
+
"moloo-focus transition-colors outline-none hover:text-foreground",
|
|
53
|
+
className
|
|
54
|
+
),
|
|
55
|
+
},
|
|
56
|
+
props
|
|
57
|
+
),
|
|
58
|
+
render,
|
|
59
|
+
state: {
|
|
60
|
+
slot: "breadcrumb-link",
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|
66
|
+
return (
|
|
67
|
+
<span
|
|
68
|
+
data-slot="breadcrumb-page"
|
|
69
|
+
role="link"
|
|
70
|
+
aria-disabled="true"
|
|
71
|
+
aria-current="page"
|
|
72
|
+
className={cn("font-semibold text-foreground", className)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function BreadcrumbSeparator({
|
|
79
|
+
children,
|
|
80
|
+
className,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<"li">) {
|
|
83
|
+
return (
|
|
84
|
+
<li
|
|
85
|
+
data-slot="breadcrumb-separator"
|
|
86
|
+
role="presentation"
|
|
87
|
+
aria-hidden="true"
|
|
88
|
+
className={cn("px-0.5 [&>svg]:size-3.5", className)}
|
|
89
|
+
{...props}
|
|
90
|
+
>
|
|
91
|
+
{children ?? "/"}
|
|
92
|
+
</li>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function BreadcrumbEllipsis({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<"span">) {
|
|
100
|
+
return (
|
|
101
|
+
<span
|
|
102
|
+
data-slot="breadcrumb-ellipsis"
|
|
103
|
+
role="presentation"
|
|
104
|
+
aria-hidden="true"
|
|
105
|
+
className={cn(
|
|
106
|
+
"flex size-5 items-center justify-center [&>svg]:size-4",
|
|
107
|
+
className
|
|
108
|
+
)}
|
|
109
|
+
{...props}
|
|
110
|
+
>
|
|
111
|
+
<IconDots
|
|
112
|
+
/>
|
|
113
|
+
<span className="sr-only">More</span>
|
|
114
|
+
</span>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
Breadcrumb,
|
|
120
|
+
BreadcrumbList,
|
|
121
|
+
BreadcrumbItem,
|
|
122
|
+
BreadcrumbLink,
|
|
123
|
+
BreadcrumbPage,
|
|
124
|
+
BreadcrumbSeparator,
|
|
125
|
+
BreadcrumbEllipsis,
|
|
126
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
|
|
8
|
+
function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
data-slot="bubble-group"
|
|
12
|
+
className={cn("flex min-w-0 flex-col gap-2", className)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const bubbleVariants = cva(
|
|
19
|
+
"group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
variant: {
|
|
23
|
+
default:
|
|
24
|
+
"*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
|
|
25
|
+
secondary:
|
|
26
|
+
"*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
|
|
27
|
+
muted:
|
|
28
|
+
"*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
|
|
29
|
+
tinted:
|
|
30
|
+
"*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
|
|
31
|
+
outline:
|
|
32
|
+
"*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
|
|
33
|
+
ghost:
|
|
34
|
+
"border-none *:data-[slot=bubble-content]:rounded-md *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
|
|
35
|
+
destructive:
|
|
36
|
+
"*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
defaultVariants: {
|
|
40
|
+
variant: "default",
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
function Bubble({
|
|
46
|
+
variant = "default",
|
|
47
|
+
align = "start",
|
|
48
|
+
className,
|
|
49
|
+
...props
|
|
50
|
+
}: React.ComponentProps<"div"> &
|
|
51
|
+
VariantProps<typeof bubbleVariants> & {
|
|
52
|
+
align?: "start" | "end"
|
|
53
|
+
}) {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
data-slot="bubble"
|
|
57
|
+
data-variant={variant}
|
|
58
|
+
data-align={align}
|
|
59
|
+
className={cn(bubbleVariants({ variant }), className)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function BubbleContent({
|
|
66
|
+
className,
|
|
67
|
+
render,
|
|
68
|
+
...props
|
|
69
|
+
}: useRender.ComponentProps<"div">) {
|
|
70
|
+
return useRender({
|
|
71
|
+
defaultTagName: "div",
|
|
72
|
+
props: mergeProps<"div">(
|
|
73
|
+
{
|
|
74
|
+
className: cn(
|
|
75
|
+
"moloo-focus w-fit max-w-full min-w-0 overflow-hidden rounded-md border-2 border-transparent px-2.5 py-2 text-sm font-semibold leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none",
|
|
76
|
+
className
|
|
77
|
+
),
|
|
78
|
+
},
|
|
79
|
+
props
|
|
80
|
+
),
|
|
81
|
+
render,
|
|
82
|
+
state: {
|
|
83
|
+
slot: "bubble-content",
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const bubbleReactionsVariants = cva(
|
|
89
|
+
"absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-md bg-muted px-1.5 py-0.5 text-sm font-semibold ring-2 ring-card has-[button]:p-0",
|
|
90
|
+
{
|
|
91
|
+
variants: {
|
|
92
|
+
side: {
|
|
93
|
+
top: "top-0 -translate-y-3/4",
|
|
94
|
+
bottom: "bottom-0 translate-y-3/4",
|
|
95
|
+
},
|
|
96
|
+
align: {
|
|
97
|
+
start: "left-3",
|
|
98
|
+
end: "right-3",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
defaultVariants: {
|
|
102
|
+
side: "bottom",
|
|
103
|
+
align: "end",
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
function BubbleReactions({
|
|
109
|
+
side = "bottom",
|
|
110
|
+
align = "end",
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}: React.ComponentProps<"div"> & {
|
|
114
|
+
align?: "start" | "end"
|
|
115
|
+
side?: "top" | "bottom"
|
|
116
|
+
}) {
|
|
117
|
+
return (
|
|
118
|
+
<div
|
|
119
|
+
data-slot="bubble-reactions"
|
|
120
|
+
data-align={align}
|
|
121
|
+
data-side={side}
|
|
122
|
+
className={cn(bubbleReactionsVariants({ side, align }), className)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { BubbleGroup, Bubble, BubbleContent, BubbleReactions }
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
import { Separator } from "./separator"
|
|
7
|
+
|
|
8
|
+
const buttonGroupVariants = cva(
|
|
9
|
+
[
|
|
10
|
+
"flex w-fit items-stretch isolate rounded-md",
|
|
11
|
+
"has-[>[data-slot=button-group]]:gap-2",
|
|
12
|
+
"[&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
|
13
|
+
/* Hover/focus chrome must paint above neighbors */
|
|
14
|
+
"*:hover:relative *:hover:z-10 *:focus-visible:relative *:focus-visible:z-10 *:focus-within:relative *:focus-within:z-10",
|
|
15
|
+
].join(" "),
|
|
16
|
+
{
|
|
17
|
+
variants: {
|
|
18
|
+
orientation: {
|
|
19
|
+
horizontal: [
|
|
20
|
+
"[&>[data-slot]:not(:first-child)]:-ml-0.5",
|
|
21
|
+
"[&>[data-slot]]:rounded-none!",
|
|
22
|
+
"[&>[data-slot]:first-child]:rounded-l-md!",
|
|
23
|
+
"[&>[data-slot]:last-child]:rounded-r-md!",
|
|
24
|
+
"has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md!",
|
|
25
|
+
].join(" "),
|
|
26
|
+
vertical: [
|
|
27
|
+
"flex-col",
|
|
28
|
+
"[&>[data-slot]:not(:first-child)]:-mt-0.5",
|
|
29
|
+
"[&>[data-slot]]:rounded-none!",
|
|
30
|
+
"[&>[data-slot]:first-child]:rounded-t-md!",
|
|
31
|
+
"[&>[data-slot]:last-child]:rounded-b-md!",
|
|
32
|
+
].join(" "),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
orientation: "horizontal",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
function ButtonGroup({
|
|
42
|
+
className,
|
|
43
|
+
orientation,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
role="group"
|
|
49
|
+
data-slot="button-group"
|
|
50
|
+
data-orientation={orientation}
|
|
51
|
+
className={cn(buttonGroupVariants({ orientation }), className)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ButtonGroupText({
|
|
58
|
+
className,
|
|
59
|
+
render,
|
|
60
|
+
...props
|
|
61
|
+
}: useRender.ComponentProps<"div">) {
|
|
62
|
+
return useRender({
|
|
63
|
+
defaultTagName: "div",
|
|
64
|
+
props: mergeProps<"div">(
|
|
65
|
+
{
|
|
66
|
+
className: cn(
|
|
67
|
+
"flex items-center gap-2 border-2 border-border bg-muted px-2.5 text-sm font-semibold [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
68
|
+
className
|
|
69
|
+
),
|
|
70
|
+
},
|
|
71
|
+
props
|
|
72
|
+
),
|
|
73
|
+
render,
|
|
74
|
+
state: {
|
|
75
|
+
slot: "button-group-text",
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function ButtonGroupSeparator({
|
|
81
|
+
className,
|
|
82
|
+
orientation = "vertical",
|
|
83
|
+
...props
|
|
84
|
+
}: React.ComponentProps<typeof Separator>) {
|
|
85
|
+
return (
|
|
86
|
+
<Separator
|
|
87
|
+
data-slot="button-group-separator"
|
|
88
|
+
orientation={orientation}
|
|
89
|
+
className={cn(
|
|
90
|
+
"relative z-0 self-stretch bg-input data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto",
|
|
91
|
+
className
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
ButtonGroup,
|
|
100
|
+
ButtonGroupSeparator,
|
|
101
|
+
ButtonGroupText,
|
|
102
|
+
buttonGroupVariants,
|
|
103
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { isValidElement } from "react"
|
|
2
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"group/button moloo-press moloo-focus inline-flex shrink-0 items-center justify-center rounded-md bg-clip-padding font-display text-sm font-bold tracking-[-0.02em] whitespace-nowrap outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground shadow-moloo hover:bg-primary-hover",
|
|
14
|
+
outline:
|
|
15
|
+
"border-2 border-border bg-card text-foreground shadow-moloo hover:border-primary hover:text-primary aria-invalid:border-destructive",
|
|
16
|
+
secondary:
|
|
17
|
+
"bg-secondary text-secondary-foreground shadow-moloo-sm hover:brightness-95 dark:hover:brightness-110",
|
|
18
|
+
ghost:
|
|
19
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
|
|
20
|
+
accent:
|
|
21
|
+
"bg-accent text-accent-foreground shadow-moloo hover:brightness-105",
|
|
22
|
+
destructive:
|
|
23
|
+
"bg-destructive-fill text-destructive-foreground shadow-moloo hover:brightness-110",
|
|
24
|
+
link: "font-sans text-sm font-medium tracking-normal text-primary underline-offset-4 hover:underline shadow-none",
|
|
25
|
+
},
|
|
26
|
+
size: {
|
|
27
|
+
default:
|
|
28
|
+
"h-9 gap-1.5 px-3.5 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
|
|
29
|
+
xs: "h-6 gap-1 rounded-md 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",
|
|
30
|
+
sm: "h-8 gap-1 rounded-md px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
31
|
+
lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
|
32
|
+
icon: "size-9",
|
|
33
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
34
|
+
"icon-sm": "size-8 rounded-md",
|
|
35
|
+
"icon-lg": "size-10",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
variant: "default",
|
|
40
|
+
size: "default",
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
function rendersNativeButton(render: ButtonPrimitive.Props["render"]): boolean {
|
|
46
|
+
return !(isValidElement(render) && render.type !== "button")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function Button({
|
|
50
|
+
className,
|
|
51
|
+
variant = "default",
|
|
52
|
+
size = "default",
|
|
53
|
+
nativeButton,
|
|
54
|
+
...props
|
|
55
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
56
|
+
return (
|
|
57
|
+
<ButtonPrimitive
|
|
58
|
+
data-slot="button"
|
|
59
|
+
data-variant={variant}
|
|
60
|
+
data-size={size}
|
|
61
|
+
nativeButton={nativeButton ?? rendersNativeButton(props.render)}
|
|
62
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import {
|
|
5
|
+
DayPicker,
|
|
6
|
+
getDefaultClassNames,
|
|
7
|
+
type DayButton,
|
|
8
|
+
type Locale,
|
|
9
|
+
} from "react-day-picker"
|
|
10
|
+
|
|
11
|
+
import { cn } from "../../lib/utils"
|
|
12
|
+
import { Button, buttonVariants } from "./button"
|
|
13
|
+
import { IconChevronLeft, IconChevronRight, IconChevronDown } from "@tabler/icons-react"
|
|
14
|
+
|
|
15
|
+
function Calendar({
|
|
16
|
+
className,
|
|
17
|
+
classNames,
|
|
18
|
+
showOutsideDays = true,
|
|
19
|
+
captionLayout = "label",
|
|
20
|
+
buttonVariant = "ghost",
|
|
21
|
+
locale,
|
|
22
|
+
formatters,
|
|
23
|
+
components,
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof DayPicker> & {
|
|
26
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
|
27
|
+
}) {
|
|
28
|
+
const defaultClassNames = getDefaultClassNames()
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<DayPicker
|
|
32
|
+
showOutsideDays={showOutsideDays}
|
|
33
|
+
className={cn(
|
|
34
|
+
"group/calendar bg-background p-2 [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
|
|
35
|
+
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
36
|
+
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
37
|
+
className
|
|
38
|
+
)}
|
|
39
|
+
captionLayout={captionLayout}
|
|
40
|
+
locale={locale}
|
|
41
|
+
formatters={{
|
|
42
|
+
formatMonthDropdown: (date) =>
|
|
43
|
+
date.toLocaleString(locale?.code, { month: "short" }),
|
|
44
|
+
...formatters,
|
|
45
|
+
}}
|
|
46
|
+
classNames={{
|
|
47
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
48
|
+
months: cn(
|
|
49
|
+
"relative flex flex-col gap-4 md:flex-row",
|
|
50
|
+
defaultClassNames.months
|
|
51
|
+
),
|
|
52
|
+
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
53
|
+
nav: cn(
|
|
54
|
+
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
55
|
+
defaultClassNames.nav
|
|
56
|
+
),
|
|
57
|
+
button_previous: cn(
|
|
58
|
+
buttonVariants({ variant: buttonVariant }),
|
|
59
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
60
|
+
defaultClassNames.button_previous
|
|
61
|
+
),
|
|
62
|
+
button_next: cn(
|
|
63
|
+
buttonVariants({ variant: buttonVariant }),
|
|
64
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
65
|
+
defaultClassNames.button_next
|
|
66
|
+
),
|
|
67
|
+
month_caption: cn(
|
|
68
|
+
"flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
|
|
69
|
+
defaultClassNames.month_caption
|
|
70
|
+
),
|
|
71
|
+
dropdowns: cn(
|
|
72
|
+
"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-semibold",
|
|
73
|
+
defaultClassNames.dropdowns
|
|
74
|
+
),
|
|
75
|
+
dropdown_root: cn(
|
|
76
|
+
"relative rounded-md border-2 border-border bg-background px-1.5 py-0.5",
|
|
77
|
+
defaultClassNames.dropdown_root
|
|
78
|
+
),
|
|
79
|
+
dropdown: cn(
|
|
80
|
+
"absolute inset-0 bg-popover opacity-0",
|
|
81
|
+
defaultClassNames.dropdown
|
|
82
|
+
),
|
|
83
|
+
caption_label: cn(
|
|
84
|
+
"font-semibold select-none",
|
|
85
|
+
captionLayout === "label"
|
|
86
|
+
? "text-sm"
|
|
87
|
+
: "flex items-center gap-1 rounded-md text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
|
|
88
|
+
defaultClassNames.caption_label
|
|
89
|
+
),
|
|
90
|
+
month_grid: cn("w-full border-collapse", defaultClassNames.month_grid),
|
|
91
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
92
|
+
weekday: cn(
|
|
93
|
+
"label flex-1 rounded-md text-[0.8rem] text-muted-foreground select-none",
|
|
94
|
+
defaultClassNames.weekday
|
|
95
|
+
),
|
|
96
|
+
week: cn("mt-2 flex w-full", defaultClassNames.week),
|
|
97
|
+
week_number_header: cn(
|
|
98
|
+
"w-(--cell-size) select-none",
|
|
99
|
+
defaultClassNames.week_number_header
|
|
100
|
+
),
|
|
101
|
+
week_number: cn(
|
|
102
|
+
"text-[0.8rem] text-muted-foreground select-none",
|
|
103
|
+
defaultClassNames.week_number
|
|
104
|
+
),
|
|
105
|
+
day: cn(
|
|
106
|
+
"group/day relative aspect-square h-full w-full rounded-md p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
|
|
107
|
+
props.showWeekNumber
|
|
108
|
+
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
|
|
109
|
+
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
|
|
110
|
+
defaultClassNames.day
|
|
111
|
+
),
|
|
112
|
+
range_start: cn(
|
|
113
|
+
"relative isolate z-0 rounded-l-md bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted",
|
|
114
|
+
defaultClassNames.range_start
|
|
115
|
+
),
|
|
116
|
+
range_middle: cn("rounded-md", defaultClassNames.range_middle),
|
|
117
|
+
range_end: cn(
|
|
118
|
+
"relative isolate z-0 rounded-r-md bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted",
|
|
119
|
+
defaultClassNames.range_end
|
|
120
|
+
),
|
|
121
|
+
today: cn(
|
|
122
|
+
"rounded-md bg-muted text-foreground data-[selected=true]:rounded-md",
|
|
123
|
+
defaultClassNames.today
|
|
124
|
+
),
|
|
125
|
+
outside: cn(
|
|
126
|
+
"text-muted-foreground aria-selected:text-muted-foreground",
|
|
127
|
+
defaultClassNames.outside
|
|
128
|
+
),
|
|
129
|
+
disabled: cn(
|
|
130
|
+
"text-muted-foreground opacity-50",
|
|
131
|
+
defaultClassNames.disabled
|
|
132
|
+
),
|
|
133
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
134
|
+
...classNames,
|
|
135
|
+
}}
|
|
136
|
+
components={{
|
|
137
|
+
Root: ({ className, rootRef, ...props }) => {
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
data-slot="calendar"
|
|
141
|
+
ref={rootRef}
|
|
142
|
+
className={cn(className)}
|
|
143
|
+
{...props}
|
|
144
|
+
/>
|
|
145
|
+
)
|
|
146
|
+
},
|
|
147
|
+
Chevron: ({ className, orientation, ...props }) => {
|
|
148
|
+
if (orientation === "left") {
|
|
149
|
+
return (
|
|
150
|
+
<IconChevronLeft className={cn("size-4", className)} {...props} />
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (orientation === "right") {
|
|
155
|
+
return (
|
|
156
|
+
<IconChevronRight className={cn("size-4", className)} {...props} />
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<IconChevronDown className={cn("size-4", className)} {...props} />
|
|
162
|
+
)
|
|
163
|
+
},
|
|
164
|
+
DayButton: ({ ...props }) => (
|
|
165
|
+
<CalendarDayButton locale={locale} {...props} />
|
|
166
|
+
),
|
|
167
|
+
WeekNumber: ({ children, ...props }) => {
|
|
168
|
+
return (
|
|
169
|
+
<td {...props}>
|
|
170
|
+
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
|
171
|
+
{children}
|
|
172
|
+
</div>
|
|
173
|
+
</td>
|
|
174
|
+
)
|
|
175
|
+
},
|
|
176
|
+
...components,
|
|
177
|
+
}}
|
|
178
|
+
{...props}
|
|
179
|
+
/>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function CalendarDayButton({
|
|
184
|
+
className,
|
|
185
|
+
day,
|
|
186
|
+
modifiers,
|
|
187
|
+
locale,
|
|
188
|
+
...props
|
|
189
|
+
}: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
|
|
190
|
+
const defaultClassNames = getDefaultClassNames()
|
|
191
|
+
|
|
192
|
+
const ref = React.useRef<HTMLButtonElement>(null)
|
|
193
|
+
React.useEffect(() => {
|
|
194
|
+
if (modifiers.focused) ref.current?.focus()
|
|
195
|
+
}, [modifiers.focused])
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<Button
|
|
199
|
+
ref={ref}
|
|
200
|
+
variant="ghost"
|
|
201
|
+
size="icon"
|
|
202
|
+
data-day={day.date.toLocaleDateString(locale?.code)}
|
|
203
|
+
data-selected-single={
|
|
204
|
+
modifiers.selected &&
|
|
205
|
+
!modifiers.range_start &&
|
|
206
|
+
!modifiers.range_end &&
|
|
207
|
+
!modifiers.range_middle
|
|
208
|
+
}
|
|
209
|
+
data-range-start={modifiers.range_start}
|
|
210
|
+
data-range-end={modifiers.range_end}
|
|
211
|
+
data-range-middle={modifiers.range_middle}
|
|
212
|
+
className={cn(
|
|
213
|
+
"relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-semibold group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:outline group-data-[focused=true]/day:outline-2 group-data-[focused=true]/day:outline-offset-2 group-data-[focused=true]/day:outline-destructive data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-md data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70",
|
|
214
|
+
defaultClassNames.day,
|
|
215
|
+
className
|
|
216
|
+
)}
|
|
217
|
+
{...props}
|
|
218
|
+
/>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export { Calendar, CalendarDayButton }
|