@openui-xio/ui 0.0.2
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/CHANGELOG.md +13 -0
- package/LICENSE +661 -0
- package/README.md +9 -0
- package/components.json +20 -0
- package/package.json +74 -0
- package/postcss.config.mjs +6 -0
- package/src/components/.gitkeep +0 -0
- package/src/components/accordion.tsx +66 -0
- package/src/components/alert-dialog.tsx +157 -0
- package/src/components/alert.tsx +66 -0
- package/src/components/aspect-ratio.tsx +11 -0
- package/src/components/avatar.tsx +53 -0
- package/src/components/badge.tsx +46 -0
- package/src/components/breadcrumb.tsx +109 -0
- package/src/components/button.tsx +46 -0
- package/src/components/calendar.tsx +85 -0
- package/src/components/card.tsx +92 -0
- package/src/components/carousel.tsx +241 -0
- package/src/components/chart.tsx +353 -0
- package/src/components/checkbox.tsx +32 -0
- package/src/components/collapsible.tsx +33 -0
- package/src/components/command.tsx +177 -0
- package/src/components/context-menu.tsx +252 -0
- package/src/components/dialog.tsx +135 -0
- package/src/components/drawer.tsx +132 -0
- package/src/components/dropdown-menu.tsx +257 -0
- package/src/components/form.tsx +168 -0
- package/src/components/hover-card.tsx +44 -0
- package/src/components/input-otp.tsx +77 -0
- package/src/components/input.tsx +21 -0
- package/src/components/label.tsx +24 -0
- package/src/components/menubar.tsx +276 -0
- package/src/components/navigation-menu.tsx +168 -0
- package/src/components/pagination.tsx +126 -0
- package/src/components/popover.tsx +48 -0
- package/src/components/progress.tsx +31 -0
- package/src/components/radio-group.tsx +45 -0
- package/src/components/resizable.tsx +56 -0
- package/src/components/scroll-area.tsx +58 -0
- package/src/components/select.tsx +185 -0
- package/src/components/separator.tsx +28 -0
- package/src/components/sheet.tsx +139 -0
- package/src/components/sidebar.tsx +726 -0
- package/src/components/skeleton.tsx +13 -0
- package/src/components/slider.tsx +63 -0
- package/src/components/sonner.tsx +25 -0
- package/src/components/switch.tsx +31 -0
- package/src/components/table.tsx +116 -0
- package/src/components/tabs.tsx +66 -0
- package/src/components/textarea.tsx +18 -0
- package/src/components/toggle-group.tsx +73 -0
- package/src/components/toggle.tsx +47 -0
- package/src/components/tooltip.tsx +61 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/globals.css +161 -0
- package/tsconfig.json +11 -0
- package/tsconfig.lint.json +8 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
5
|
+
import { DayPicker } from 'react-day-picker';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@openui-xio/ui/lib/utils';
|
|
8
|
+
import { buttonVariants } from '@openui-xio/ui/components/button';
|
|
9
|
+
|
|
10
|
+
const IconLeft = ({
|
|
11
|
+
className,
|
|
12
|
+
...props
|
|
13
|
+
}: React.ComponentProps<typeof ChevronLeft>) => (
|
|
14
|
+
<ChevronLeft className={cn('size-4', className)} {...props} />
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const IconRight = ({
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<typeof ChevronRight>) => (
|
|
21
|
+
<ChevronRight className={cn('size-4', className)} {...props} />
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
function Calendar({
|
|
25
|
+
className,
|
|
26
|
+
classNames,
|
|
27
|
+
showOutsideDays = true,
|
|
28
|
+
...props
|
|
29
|
+
}: React.ComponentProps<typeof DayPicker>) {
|
|
30
|
+
return (
|
|
31
|
+
<DayPicker
|
|
32
|
+
showOutsideDays={showOutsideDays}
|
|
33
|
+
className={cn('p-3', className)}
|
|
34
|
+
classNames={{
|
|
35
|
+
months: 'flex flex-col sm:flex-row gap-2',
|
|
36
|
+
month: 'flex flex-col gap-4',
|
|
37
|
+
caption: 'flex justify-center pt-1 relative items-center w-full',
|
|
38
|
+
caption_label: 'text-sm font-medium',
|
|
39
|
+
nav: 'flex items-center gap-1',
|
|
40
|
+
nav_button: cn(
|
|
41
|
+
buttonVariants({ variant: 'outline' }),
|
|
42
|
+
'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
|
43
|
+
),
|
|
44
|
+
nav_button_previous: 'absolute left-1',
|
|
45
|
+
nav_button_next: 'absolute right-1',
|
|
46
|
+
table: 'w-full border-collapse space-x-1',
|
|
47
|
+
head_row: 'flex',
|
|
48
|
+
head_cell:
|
|
49
|
+
'text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]',
|
|
50
|
+
row: 'flex w-full mt-2',
|
|
51
|
+
cell: cn(
|
|
52
|
+
'relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md',
|
|
53
|
+
props.mode === 'range'
|
|
54
|
+
? '[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md'
|
|
55
|
+
: '[&:has([aria-selected])]:rounded-md',
|
|
56
|
+
),
|
|
57
|
+
day: cn(
|
|
58
|
+
buttonVariants({ variant: 'ghost' }),
|
|
59
|
+
'size-8 p-0 font-normal aria-selected:opacity-100',
|
|
60
|
+
),
|
|
61
|
+
day_range_start:
|
|
62
|
+
'day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground',
|
|
63
|
+
day_range_end:
|
|
64
|
+
'day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground',
|
|
65
|
+
day_selected:
|
|
66
|
+
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
|
|
67
|
+
day_today: 'bg-accent text-accent-foreground',
|
|
68
|
+
day_outside:
|
|
69
|
+
'day-outside text-muted-foreground aria-selected:text-muted-foreground',
|
|
70
|
+
day_disabled: 'text-muted-foreground opacity-50',
|
|
71
|
+
day_range_middle:
|
|
72
|
+
'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
|
73
|
+
day_hidden: 'invisible',
|
|
74
|
+
...classNames,
|
|
75
|
+
}}
|
|
76
|
+
components={{
|
|
77
|
+
IconLeft,
|
|
78
|
+
IconRight,
|
|
79
|
+
}}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { Calendar };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '@openui-xio/ui/lib/utils';
|
|
4
|
+
|
|
5
|
+
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="card"
|
|
9
|
+
className={cn(
|
|
10
|
+
'flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm',
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
data-slot="card-header"
|
|
22
|
+
className={cn(
|
|
23
|
+
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
data-slot="card-title"
|
|
35
|
+
className={cn('font-semibold leading-none', className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
data-slot="card-description"
|
|
45
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
data-slot="card-action"
|
|
55
|
+
className={cn(
|
|
56
|
+
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
65
|
+
return (
|
|
66
|
+
<div
|
|
67
|
+
data-slot="card-content"
|
|
68
|
+
className={cn('px-6', className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
data-slot="card-footer"
|
|
78
|
+
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
Card,
|
|
86
|
+
CardHeader,
|
|
87
|
+
CardFooter,
|
|
88
|
+
CardTitle,
|
|
89
|
+
CardAction,
|
|
90
|
+
CardDescription,
|
|
91
|
+
CardContent,
|
|
92
|
+
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import useEmblaCarousel, {
|
|
5
|
+
type UseEmblaCarouselType,
|
|
6
|
+
} from 'embla-carousel-react';
|
|
7
|
+
import { ArrowLeft, ArrowRight } from 'lucide-react';
|
|
8
|
+
|
|
9
|
+
import { cn } from '@openui-xio/ui/lib/utils';
|
|
10
|
+
import { Button } from '@openui-xio/ui/components/button';
|
|
11
|
+
|
|
12
|
+
type CarouselApi = UseEmblaCarouselType[1];
|
|
13
|
+
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
|
14
|
+
type CarouselOptions = UseCarouselParameters[0];
|
|
15
|
+
type CarouselPlugin = UseCarouselParameters[1];
|
|
16
|
+
|
|
17
|
+
type CarouselProps = {
|
|
18
|
+
opts?: CarouselOptions;
|
|
19
|
+
plugins?: CarouselPlugin;
|
|
20
|
+
orientation?: 'horizontal' | 'vertical';
|
|
21
|
+
setApi?: (api: CarouselApi) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type CarouselContextProps = {
|
|
25
|
+
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
|
26
|
+
api: ReturnType<typeof useEmblaCarousel>[1];
|
|
27
|
+
scrollPrev: () => void;
|
|
28
|
+
scrollNext: () => void;
|
|
29
|
+
canScrollPrev: boolean;
|
|
30
|
+
canScrollNext: boolean;
|
|
31
|
+
} & CarouselProps;
|
|
32
|
+
|
|
33
|
+
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
|
|
34
|
+
|
|
35
|
+
function useCarousel() {
|
|
36
|
+
const context = React.useContext(CarouselContext);
|
|
37
|
+
|
|
38
|
+
if (!context) {
|
|
39
|
+
throw new Error('useCarousel must be used within a <Carousel />');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return context;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function Carousel({
|
|
46
|
+
orientation = 'horizontal',
|
|
47
|
+
opts,
|
|
48
|
+
setApi,
|
|
49
|
+
plugins,
|
|
50
|
+
className,
|
|
51
|
+
children,
|
|
52
|
+
...props
|
|
53
|
+
}: React.ComponentProps<'div'> & CarouselProps) {
|
|
54
|
+
const [carouselRef, api] = useEmblaCarousel(
|
|
55
|
+
{
|
|
56
|
+
...opts,
|
|
57
|
+
axis: orientation === 'horizontal' ? 'x' : 'y',
|
|
58
|
+
},
|
|
59
|
+
plugins,
|
|
60
|
+
);
|
|
61
|
+
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
|
62
|
+
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
|
63
|
+
|
|
64
|
+
const onSelect = React.useCallback((api: CarouselApi) => {
|
|
65
|
+
if (!api) return;
|
|
66
|
+
setCanScrollPrev(api.canScrollPrev());
|
|
67
|
+
setCanScrollNext(api.canScrollNext());
|
|
68
|
+
}, []);
|
|
69
|
+
|
|
70
|
+
const scrollPrev = React.useCallback(() => {
|
|
71
|
+
api?.scrollPrev();
|
|
72
|
+
}, [api]);
|
|
73
|
+
|
|
74
|
+
const scrollNext = React.useCallback(() => {
|
|
75
|
+
api?.scrollNext();
|
|
76
|
+
}, [api]);
|
|
77
|
+
|
|
78
|
+
const handleKeyDown = React.useCallback(
|
|
79
|
+
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
80
|
+
if (event.key === 'ArrowLeft') {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
scrollPrev();
|
|
83
|
+
} else if (event.key === 'ArrowRight') {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
scrollNext();
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
[scrollPrev, scrollNext],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
React.useEffect(() => {
|
|
92
|
+
if (!api || !setApi) return;
|
|
93
|
+
setApi(api);
|
|
94
|
+
}, [api, setApi]);
|
|
95
|
+
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
if (!api) return;
|
|
98
|
+
onSelect(api);
|
|
99
|
+
api.on('reInit', onSelect);
|
|
100
|
+
api.on('select', onSelect);
|
|
101
|
+
|
|
102
|
+
return () => {
|
|
103
|
+
api?.off('select', onSelect);
|
|
104
|
+
};
|
|
105
|
+
}, [api, onSelect]);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<CarouselContext.Provider
|
|
109
|
+
value={{
|
|
110
|
+
carouselRef,
|
|
111
|
+
api: api,
|
|
112
|
+
opts,
|
|
113
|
+
orientation:
|
|
114
|
+
orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
|
|
115
|
+
scrollPrev,
|
|
116
|
+
scrollNext,
|
|
117
|
+
canScrollPrev,
|
|
118
|
+
canScrollNext,
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
<div
|
|
122
|
+
onKeyDownCapture={handleKeyDown}
|
|
123
|
+
className={cn('relative', className)}
|
|
124
|
+
role="region"
|
|
125
|
+
aria-roledescription="carousel"
|
|
126
|
+
data-slot="carousel"
|
|
127
|
+
{...props}
|
|
128
|
+
>
|
|
129
|
+
{children}
|
|
130
|
+
</div>
|
|
131
|
+
</CarouselContext.Provider>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
136
|
+
const { carouselRef, orientation } = useCarousel();
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
ref={carouselRef}
|
|
141
|
+
className="overflow-hidden"
|
|
142
|
+
data-slot="carousel-content"
|
|
143
|
+
>
|
|
144
|
+
<div
|
|
145
|
+
className={cn(
|
|
146
|
+
'flex',
|
|
147
|
+
orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
|
|
148
|
+
className,
|
|
149
|
+
)}
|
|
150
|
+
{...props}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
|
|
157
|
+
const { orientation } = useCarousel();
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div
|
|
161
|
+
role="group"
|
|
162
|
+
aria-roledescription="slide"
|
|
163
|
+
data-slot="carousel-item"
|
|
164
|
+
className={cn(
|
|
165
|
+
'min-w-0 shrink-0 grow-0 basis-full',
|
|
166
|
+
orientation === 'horizontal' ? 'pl-4' : 'pt-4',
|
|
167
|
+
className,
|
|
168
|
+
)}
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function CarouselPrevious({
|
|
175
|
+
className,
|
|
176
|
+
variant = 'outline',
|
|
177
|
+
size = 'icon',
|
|
178
|
+
...props
|
|
179
|
+
}: React.ComponentProps<typeof Button>) {
|
|
180
|
+
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<Button
|
|
184
|
+
data-slot="carousel-previous"
|
|
185
|
+
variant={variant}
|
|
186
|
+
size={size}
|
|
187
|
+
className={cn(
|
|
188
|
+
'absolute size-8 rounded-full',
|
|
189
|
+
orientation === 'horizontal'
|
|
190
|
+
? '-left-12 -translate-y-1/2 top-1/2'
|
|
191
|
+
: '-top-12 -translate-x-1/2 left-1/2 rotate-90',
|
|
192
|
+
className,
|
|
193
|
+
)}
|
|
194
|
+
disabled={!canScrollPrev}
|
|
195
|
+
onClick={scrollPrev}
|
|
196
|
+
{...props}
|
|
197
|
+
>
|
|
198
|
+
<ArrowLeft />
|
|
199
|
+
<span className="sr-only">Previous slide</span>
|
|
200
|
+
</Button>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function CarouselNext({
|
|
205
|
+
className,
|
|
206
|
+
variant = 'outline',
|
|
207
|
+
size = 'icon',
|
|
208
|
+
...props
|
|
209
|
+
}: React.ComponentProps<typeof Button>) {
|
|
210
|
+
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<Button
|
|
214
|
+
data-slot="carousel-next"
|
|
215
|
+
variant={variant}
|
|
216
|
+
size={size}
|
|
217
|
+
className={cn(
|
|
218
|
+
'absolute size-8 rounded-full',
|
|
219
|
+
orientation === 'horizontal'
|
|
220
|
+
? '-right-12 -translate-y-1/2 top-1/2'
|
|
221
|
+
: '-bottom-12 -translate-x-1/2 left-1/2 rotate-90',
|
|
222
|
+
className,
|
|
223
|
+
)}
|
|
224
|
+
disabled={!canScrollNext}
|
|
225
|
+
onClick={scrollNext}
|
|
226
|
+
{...props}
|
|
227
|
+
>
|
|
228
|
+
<ArrowRight />
|
|
229
|
+
<span className="sr-only">Next slide</span>
|
|
230
|
+
</Button>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export {
|
|
235
|
+
type CarouselApi,
|
|
236
|
+
Carousel,
|
|
237
|
+
CarouselContent,
|
|
238
|
+
CarouselItem,
|
|
239
|
+
CarouselPrevious,
|
|
240
|
+
CarouselNext,
|
|
241
|
+
};
|