atlasui-lib 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.
Files changed (41) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/LICENSE +21 -0
  3. package/README.md +253 -0
  4. package/dist/cli/index.js +364 -0
  5. package/dist/index.d.mts +1027 -0
  6. package/dist/index.d.ts +1027 -0
  7. package/dist/index.js +3954 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/index.mjs +3733 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/provider.d.mts +15 -0
  12. package/dist/provider.d.ts +15 -0
  13. package/dist/provider.js +816 -0
  14. package/dist/provider.js.map +1 -0
  15. package/dist/provider.mjs +780 -0
  16. package/dist/provider.mjs.map +1 -0
  17. package/dist/tailwind.d.ts +25 -0
  18. package/dist/tailwind.js +129 -0
  19. package/package.json +138 -0
  20. package/src/cli/index.ts +301 -0
  21. package/src/cli/registry.ts +139 -0
  22. package/src/components/advanced-forms/index.tsx +567 -0
  23. package/src/components/basic/Button.tsx +135 -0
  24. package/src/components/basic/IconButton.tsx +69 -0
  25. package/src/components/basic/index.tsx +446 -0
  26. package/src/components/data-display/index.tsx +608 -0
  27. package/src/components/feedback/index.tsx +554 -0
  28. package/src/components/forms/index.tsx +476 -0
  29. package/src/components/layout/index.tsx +296 -0
  30. package/src/components/media/index.tsx +437 -0
  31. package/src/components/navigation/index.tsx +484 -0
  32. package/src/components/overlay/index.tsx +473 -0
  33. package/src/components/utility/index.tsx +411 -0
  34. package/src/hooks/index.ts +271 -0
  35. package/src/hooks/use-toast.tsx +74 -0
  36. package/src/index.ts +353 -0
  37. package/src/provider.tsx +54 -0
  38. package/src/styles/atlas.css +252 -0
  39. package/src/tailwind.ts +124 -0
  40. package/src/types/index.ts +95 -0
  41. package/src/utils/cn.ts +66 -0
@@ -0,0 +1,476 @@
1
+ import * as React from "react";
2
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
4
+ import * as SwitchPrimitive from "@radix-ui/react-switch";
5
+ import * as SliderPrimitive from "@radix-ui/react-slider";
6
+ import * as SelectPrimitive from "@radix-ui/react-select";
7
+ import { cva, type VariantProps } from "class-variance-authority";
8
+ import { cn } from "../../utils/cn";
9
+
10
+ // ─── Input ─────────────────────────────────────────────────────────────────
11
+
12
+ const inputVariants = cva(
13
+ [
14
+ "atlas-input flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
15
+ "ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium",
16
+ "placeholder:text-muted-foreground",
17
+ "transition-shadow duration-150",
18
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
19
+ "disabled:cursor-not-allowed disabled:opacity-50",
20
+ ],
21
+ {
22
+ variants: {
23
+ size: {
24
+ sm: "h-8 px-2.5 text-xs",
25
+ md: "h-9 px-3 text-sm",
26
+ lg: "h-10 px-4 text-base",
27
+ },
28
+ invalid: {
29
+ true: "border-destructive focus-visible:ring-destructive",
30
+ },
31
+ },
32
+ defaultVariants: { size: "md" },
33
+ }
34
+ );
35
+
36
+ export interface InputProps
37
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">,
38
+ VariantProps<typeof inputVariants> {
39
+ leftElement?: React.ReactNode;
40
+ rightElement?: React.ReactNode;
41
+ invalid?: boolean;
42
+ }
43
+
44
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
45
+ ({ className, type, size, invalid, leftElement, rightElement, ...props }, ref) => {
46
+ if (leftElement || rightElement) {
47
+ return (
48
+ <div className="relative flex items-center w-full">
49
+ {leftElement && (
50
+ <span className="absolute left-3 text-muted-foreground [&>svg]:h-4 [&>svg]:w-4 pointer-events-none">
51
+ {leftElement}
52
+ </span>
53
+ )}
54
+ <input
55
+ type={type}
56
+ className={cn(
57
+ inputVariants({ size, invalid: invalid ?? false }),
58
+ leftElement && "pl-9",
59
+ rightElement && "pr-9",
60
+ className
61
+ )}
62
+ ref={ref}
63
+ aria-invalid={invalid}
64
+ {...props}
65
+ />
66
+ {rightElement && (
67
+ <span className="absolute right-3 text-muted-foreground [&>svg]:h-4 [&>svg]:w-4">
68
+ {rightElement}
69
+ </span>
70
+ )}
71
+ </div>
72
+ );
73
+ }
74
+
75
+ return (
76
+ <input
77
+ type={type}
78
+ className={cn(inputVariants({ size, invalid: invalid ?? false }), className)}
79
+ ref={ref}
80
+ aria-invalid={invalid}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+ );
86
+ Input.displayName = "Input";
87
+
88
+ // ─── TextArea ─────────────────────────────────────────────────────────────
89
+
90
+ export interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
91
+ invalid?: boolean;
92
+ resize?: "none" | "both" | "horizontal" | "vertical";
93
+ }
94
+
95
+ const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
96
+ ({ className, invalid, resize = "vertical", ...props }, ref) => (
97
+ <textarea
98
+ className={cn(
99
+ "atlas-textarea flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
100
+ "ring-offset-background placeholder:text-muted-foreground",
101
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
102
+ "disabled:cursor-not-allowed disabled:opacity-50 transition-shadow",
103
+ resize === "none" && "resize-none",
104
+ resize === "both" && "resize",
105
+ resize === "horizontal" && "resize-x",
106
+ resize === "vertical" && "resize-y",
107
+ invalid && "border-destructive focus-visible:ring-destructive",
108
+ className
109
+ )}
110
+ ref={ref}
111
+ aria-invalid={invalid}
112
+ {...props}
113
+ />
114
+ )
115
+ );
116
+ TextArea.displayName = "TextArea";
117
+
118
+ // ─── Select ───────────────────────────────────────────────────────────────
119
+
120
+ const Select = SelectPrimitive.Root;
121
+ const SelectGroup = SelectPrimitive.Group;
122
+ const SelectValue = SelectPrimitive.Value;
123
+
124
+ const SelectTrigger = React.forwardRef<
125
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
126
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & { invalid?: boolean }
127
+ >(({ className, children, invalid, ...props }, ref) => (
128
+ <SelectPrimitive.Trigger
129
+ ref={ref}
130
+ className={cn(
131
+ "atlas-select-trigger flex h-9 w-full items-center justify-between rounded-md",
132
+ "border border-input bg-background px-3 py-2 text-sm",
133
+ "ring-offset-background placeholder:text-muted-foreground",
134
+ "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
135
+ "disabled:cursor-not-allowed disabled:opacity-50",
136
+ invalid && "border-destructive focus:ring-destructive",
137
+ "[&>span]:line-clamp-1",
138
+ className
139
+ )}
140
+ {...props}
141
+ >
142
+ {children}
143
+ <SelectPrimitive.Icon asChild>
144
+ <svg className="h-4 w-4 opacity-50 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
145
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
146
+ </svg>
147
+ </SelectPrimitive.Icon>
148
+ </SelectPrimitive.Trigger>
149
+ ));
150
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
151
+
152
+ const SelectContent = React.forwardRef<
153
+ React.ElementRef<typeof SelectPrimitive.Content>,
154
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
155
+ >(({ className, children, position = "popper", ...props }, ref) => (
156
+ <SelectPrimitive.Portal>
157
+ <SelectPrimitive.Content
158
+ ref={ref}
159
+ className={cn(
160
+ "atlas-select-content relative z-50 min-w-[8rem] overflow-hidden rounded-md",
161
+ "border border-border bg-popover text-popover-foreground shadow-md",
162
+ "animate-in fade-in-0 zoom-in-95",
163
+ position === "popper" && "translate-y-1",
164
+ className
165
+ )}
166
+ position={position}
167
+ {...props}
168
+ >
169
+ <SelectPrimitive.Viewport className={cn("p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]")}>
170
+ {children}
171
+ </SelectPrimitive.Viewport>
172
+ </SelectPrimitive.Content>
173
+ </SelectPrimitive.Portal>
174
+ ));
175
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
176
+
177
+ const SelectItem = React.forwardRef<
178
+ React.ElementRef<typeof SelectPrimitive.Item>,
179
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
180
+ >(({ className, children, ...props }, ref) => (
181
+ <SelectPrimitive.Item
182
+ ref={ref}
183
+ className={cn(
184
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm",
185
+ "outline-none focus:bg-accent focus:text-accent-foreground",
186
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
187
+ className
188
+ )}
189
+ {...props}
190
+ >
191
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
192
+ <SelectPrimitive.ItemIndicator>
193
+ <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
194
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
195
+ </svg>
196
+ </SelectPrimitive.ItemIndicator>
197
+ </span>
198
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
199
+ </SelectPrimitive.Item>
200
+ ));
201
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
202
+
203
+ const SelectLabel = React.forwardRef<
204
+ React.ElementRef<typeof SelectPrimitive.Label>,
205
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
206
+ >(({ className, ...props }, ref) => (
207
+ <SelectPrimitive.Label ref={ref} className={cn("py-1.5 pl-8 pr-2 text-xs font-semibold text-muted-foreground", className)} {...props} />
208
+ ));
209
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
210
+
211
+ const SelectSeparator = React.forwardRef<
212
+ React.ElementRef<typeof SelectPrimitive.Separator>,
213
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
214
+ >(({ className, ...props }, ref) => (
215
+ <SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} />
216
+ ));
217
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
218
+
219
+ // ─── Checkbox ─────────────────────────────────────────────────────────────
220
+
221
+ export interface CheckboxProps extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> {
222
+ label?: React.ReactNode;
223
+ description?: string;
224
+ invalid?: boolean;
225
+ }
226
+
227
+ const Checkbox = React.forwardRef<React.ElementRef<typeof CheckboxPrimitive.Root>, CheckboxProps>(
228
+ ({ className, label, description, invalid, id, ...props }, ref) => {
229
+ const checkboxId = id ?? React.useId();
230
+
231
+ return (
232
+ <div className="atlas-checkbox flex items-start gap-2.5">
233
+ <CheckboxPrimitive.Root
234
+ ref={ref}
235
+ id={checkboxId}
236
+ className={cn(
237
+ "peer h-4 w-4 shrink-0 rounded border border-primary ring-offset-background",
238
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
239
+ "disabled:cursor-not-allowed disabled:opacity-50",
240
+ "data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
241
+ invalid && "border-destructive",
242
+ className
243
+ )}
244
+ {...props}
245
+ >
246
+ <CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
247
+ <svg className="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
248
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
249
+ </svg>
250
+ </CheckboxPrimitive.Indicator>
251
+ </CheckboxPrimitive.Root>
252
+ {(label || description) && (
253
+ <div className="grid gap-0.5">
254
+ {label && (
255
+ <label htmlFor={checkboxId} className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer">
256
+ {label}
257
+ </label>
258
+ )}
259
+ {description && <p className="text-xs text-muted-foreground">{description}</p>}
260
+ </div>
261
+ )}
262
+ </div>
263
+ );
264
+ }
265
+ );
266
+ Checkbox.displayName = "Checkbox";
267
+
268
+ // ─── RadioGroup ───────────────────────────────────────────────────────────
269
+
270
+ export interface RadioOption {
271
+ value: string;
272
+ label: React.ReactNode;
273
+ description?: string;
274
+ disabled?: boolean;
275
+ }
276
+
277
+ export interface RadioGroupProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
278
+ options?: RadioOption[];
279
+ orientation?: "horizontal" | "vertical";
280
+ }
281
+
282
+ const RadioGroup = React.forwardRef<React.ElementRef<typeof RadioGroupPrimitive.Root>, RadioGroupProps>(
283
+ ({ className, options, orientation = "vertical", children, ...props }, ref) => (
284
+ <RadioGroupPrimitive.Root
285
+ ref={ref}
286
+ className={cn(
287
+ "atlas-radio-group",
288
+ orientation === "vertical" ? "flex flex-col gap-2" : "flex flex-row flex-wrap gap-4",
289
+ className
290
+ )}
291
+ {...props}
292
+ >
293
+ {options
294
+ ? options.map((option) => (
295
+ <div key={option.value} className="flex items-start gap-2.5">
296
+ <RadioGroupPrimitive.Item
297
+ value={option.value}
298
+ disabled={option.disabled}
299
+ className={cn(
300
+ "mt-0.5 h-4 w-4 rounded-full border border-primary shrink-0",
301
+ "ring-offset-background transition-colors",
302
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
303
+ "disabled:cursor-not-allowed disabled:opacity-50",
304
+ "data-[state=checked]:border-primary"
305
+ )}
306
+ >
307
+ <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
308
+ <span className="h-2 w-2 rounded-full bg-primary" />
309
+ </RadioGroupPrimitive.Indicator>
310
+ </RadioGroupPrimitive.Item>
311
+ <div>
312
+ <label className="text-sm font-medium cursor-pointer">{option.label}</label>
313
+ {option.description && <p className="text-xs text-muted-foreground">{option.description}</p>}
314
+ </div>
315
+ </div>
316
+ ))
317
+ : children}
318
+ </RadioGroupPrimitive.Root>
319
+ )
320
+ );
321
+ RadioGroup.displayName = "RadioGroup";
322
+
323
+ // ─── Switch ───────────────────────────────────────────────────────────────
324
+
325
+ export interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {
326
+ label?: React.ReactNode;
327
+ description?: string;
328
+ size?: "sm" | "md" | "lg";
329
+ }
330
+
331
+ const switchSizes = {
332
+ sm: { root: "h-4 w-7", thumb: "h-3 w-3 data-[state=checked]:translate-x-3" },
333
+ md: { root: "h-5 w-9", thumb: "h-4 w-4 data-[state=checked]:translate-x-4" },
334
+ lg: { root: "h-6 w-11", thumb: "h-5 w-5 data-[state=checked]:translate-x-5" },
335
+ };
336
+
337
+ const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(
338
+ ({ className, label, description, size = "md", id, ...props }, ref) => {
339
+ const switchId = id ?? React.useId();
340
+ const sz = switchSizes[size];
341
+
342
+ return (
343
+ <div className="atlas-switch flex items-center gap-2.5">
344
+ <SwitchPrimitive.Root
345
+ id={switchId}
346
+ ref={ref}
347
+ className={cn(
348
+ "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent",
349
+ "transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
350
+ "disabled:cursor-not-allowed disabled:opacity-50",
351
+ "bg-input data-[state=checked]:bg-primary",
352
+ sz.root,
353
+ className
354
+ )}
355
+ {...props}
356
+ >
357
+ <SwitchPrimitive.Thumb
358
+ className={cn(
359
+ "pointer-events-none block rounded-full bg-background shadow-lg ring-0",
360
+ "transition-transform translate-x-0",
361
+ sz.thumb
362
+ )}
363
+ />
364
+ </SwitchPrimitive.Root>
365
+ {(label || description) && (
366
+ <div>
367
+ {label && <label htmlFor={switchId} className="text-sm font-medium cursor-pointer">{label}</label>}
368
+ {description && <p className="text-xs text-muted-foreground">{description}</p>}
369
+ </div>
370
+ )}
371
+ </div>
372
+ );
373
+ }
374
+ );
375
+ Switch.displayName = "Switch";
376
+
377
+ // ─── Slider ───────────────────────────────────────────────────────────────
378
+
379
+ const Slider = React.forwardRef<
380
+ React.ElementRef<typeof SliderPrimitive.Root>,
381
+ React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
382
+ >(({ className, ...props }, ref) => (
383
+ <SliderPrimitive.Root
384
+ ref={ref}
385
+ className={cn("atlas-slider relative flex w-full touch-none select-none items-center", className)}
386
+ {...props}
387
+ >
388
+ <SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-secondary">
389
+ <SliderPrimitive.Range className="absolute h-full bg-primary" />
390
+ </SliderPrimitive.Track>
391
+ {(Array.isArray(props.value) ? props.value : props.defaultValue ?? [0]).map((_, i) => (
392
+ <SliderPrimitive.Thumb
393
+ key={i}
394
+ className={cn(
395
+ "block h-4 w-4 rounded-full border-2 border-primary bg-background shadow",
396
+ "ring-offset-background transition-colors",
397
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
398
+ "disabled:pointer-events-none disabled:opacity-50"
399
+ )}
400
+ />
401
+ ))}
402
+ </SliderPrimitive.Root>
403
+ ));
404
+ Slider.displayName = "Slider";
405
+
406
+ // ─── RangeSlider ──────────────────────────────────────────────────────────
407
+
408
+ export type RangeSliderProps = React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>;
409
+
410
+ const RangeSlider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, RangeSliderProps>(
411
+ ({ className, defaultValue = [20, 80], ...props }, ref) => (
412
+ <Slider ref={ref} defaultValue={defaultValue} className={cn("atlas-range-slider", className)} {...props} />
413
+ )
414
+ );
415
+ RangeSlider.displayName = "RangeSlider";
416
+
417
+ // ─── DatePicker ───────────────────────────────────────────────────────────
418
+
419
+ export interface DatePickerProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "size"> {
420
+ label?: string;
421
+ invalid?: boolean;
422
+ }
423
+
424
+ const DatePicker = React.forwardRef<HTMLInputElement, DatePickerProps>(
425
+ ({ className, label, invalid, id, ...props }, ref) => {
426
+ const inputId = id ?? React.useId();
427
+ return (
428
+ <div className="atlas-date-picker grid gap-1.5 w-full">
429
+ {label && <label htmlFor={inputId} className="text-sm font-medium">{label}</label>}
430
+ <Input
431
+ ref={ref}
432
+ id={inputId}
433
+ type="date"
434
+ invalid={invalid}
435
+ className={className}
436
+ {...props}
437
+ />
438
+ </div>
439
+ );
440
+ }
441
+ );
442
+ DatePicker.displayName = "DatePicker";
443
+
444
+ // ─── TimePicker ───────────────────────────────────────────────────────────
445
+
446
+ export interface TimePickerProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "size"> {
447
+ label?: string;
448
+ invalid?: boolean;
449
+ }
450
+
451
+ const TimePicker = React.forwardRef<HTMLInputElement, TimePickerProps>(
452
+ ({ className, label, invalid, id, ...props }, ref) => {
453
+ const inputId = id ?? React.useId();
454
+ return (
455
+ <div className="atlas-time-picker grid gap-1.5 w-full">
456
+ {label && <label htmlFor={inputId} className="text-sm font-medium">{label}</label>}
457
+ <Input ref={ref} id={inputId} type="time" invalid={invalid} className={className} {...props} />
458
+ </div>
459
+ );
460
+ }
461
+ );
462
+ TimePicker.displayName = "TimePicker";
463
+
464
+ export {
465
+ Input, inputVariants,
466
+ TextArea,
467
+ Select, SelectGroup, SelectValue, SelectTrigger, SelectContent,
468
+ SelectItem, SelectLabel, SelectSeparator,
469
+ Checkbox,
470
+ RadioGroup,
471
+ Switch,
472
+ Slider,
473
+ RangeSlider,
474
+ DatePicker,
475
+ TimePicker,
476
+ };