@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +661 -0
  3. package/README.md +9 -0
  4. package/components.json +20 -0
  5. package/package.json +74 -0
  6. package/postcss.config.mjs +6 -0
  7. package/src/components/.gitkeep +0 -0
  8. package/src/components/accordion.tsx +66 -0
  9. package/src/components/alert-dialog.tsx +157 -0
  10. package/src/components/alert.tsx +66 -0
  11. package/src/components/aspect-ratio.tsx +11 -0
  12. package/src/components/avatar.tsx +53 -0
  13. package/src/components/badge.tsx +46 -0
  14. package/src/components/breadcrumb.tsx +109 -0
  15. package/src/components/button.tsx +46 -0
  16. package/src/components/calendar.tsx +85 -0
  17. package/src/components/card.tsx +92 -0
  18. package/src/components/carousel.tsx +241 -0
  19. package/src/components/chart.tsx +353 -0
  20. package/src/components/checkbox.tsx +32 -0
  21. package/src/components/collapsible.tsx +33 -0
  22. package/src/components/command.tsx +177 -0
  23. package/src/components/context-menu.tsx +252 -0
  24. package/src/components/dialog.tsx +135 -0
  25. package/src/components/drawer.tsx +132 -0
  26. package/src/components/dropdown-menu.tsx +257 -0
  27. package/src/components/form.tsx +168 -0
  28. package/src/components/hover-card.tsx +44 -0
  29. package/src/components/input-otp.tsx +77 -0
  30. package/src/components/input.tsx +21 -0
  31. package/src/components/label.tsx +24 -0
  32. package/src/components/menubar.tsx +276 -0
  33. package/src/components/navigation-menu.tsx +168 -0
  34. package/src/components/pagination.tsx +126 -0
  35. package/src/components/popover.tsx +48 -0
  36. package/src/components/progress.tsx +31 -0
  37. package/src/components/radio-group.tsx +45 -0
  38. package/src/components/resizable.tsx +56 -0
  39. package/src/components/scroll-area.tsx +58 -0
  40. package/src/components/select.tsx +185 -0
  41. package/src/components/separator.tsx +28 -0
  42. package/src/components/sheet.tsx +139 -0
  43. package/src/components/sidebar.tsx +726 -0
  44. package/src/components/skeleton.tsx +13 -0
  45. package/src/components/slider.tsx +63 -0
  46. package/src/components/sonner.tsx +25 -0
  47. package/src/components/switch.tsx +31 -0
  48. package/src/components/table.tsx +116 -0
  49. package/src/components/tabs.tsx +66 -0
  50. package/src/components/textarea.tsx +18 -0
  51. package/src/components/toggle-group.tsx +73 -0
  52. package/src/components/toggle.tsx +47 -0
  53. package/src/components/tooltip.tsx +61 -0
  54. package/src/hooks/.gitkeep +0 -0
  55. package/src/hooks/use-mobile.ts +21 -0
  56. package/src/lib/utils.ts +6 -0
  57. package/src/styles/globals.css +161 -0
  58. package/tsconfig.json +11 -0
  59. 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
+ };