pxengine 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 (127) hide show
  1. package/README.md +175 -0
  2. package/config/tailwind-preset.js +106 -0
  3. package/dist/index.d.mts +1259 -0
  4. package/dist/index.d.ts +1259 -0
  5. package/dist/index.js +5175 -0
  6. package/dist/index.mjs +4929 -0
  7. package/package.json +94 -0
  8. package/src/atoms/AccordionAtom.tsx +44 -0
  9. package/src/atoms/AlertAtom.tsx +46 -0
  10. package/src/atoms/AlertDialogAtom.tsx +66 -0
  11. package/src/atoms/AspectRatioAtom.tsx +27 -0
  12. package/src/atoms/AvatarAtom.tsx +20 -0
  13. package/src/atoms/BadgeAtom.tsx +25 -0
  14. package/src/atoms/BreadcrumbAtom.tsx +36 -0
  15. package/src/atoms/ButtonAtom.tsx +63 -0
  16. package/src/atoms/CalendarAtom.tsx +24 -0
  17. package/src/atoms/CardAtom.tsx +64 -0
  18. package/src/atoms/CarouselAtom.tsx +40 -0
  19. package/src/atoms/CollapsibleAtom.tsx +44 -0
  20. package/src/atoms/CommandAtom.tsx +46 -0
  21. package/src/atoms/DialogAtom.tsx +68 -0
  22. package/src/atoms/InputAtom.tsx +162 -0
  23. package/src/atoms/LayoutAtom.tsx +43 -0
  24. package/src/atoms/PaginationAtom.tsx +49 -0
  25. package/src/atoms/PopoverAtom.tsx +40 -0
  26. package/src/atoms/ProgressAtom.tsx +15 -0
  27. package/src/atoms/ScrollAreaAtom.tsx +31 -0
  28. package/src/atoms/SeparatorAtom.tsx +16 -0
  29. package/src/atoms/SheetAtom.tsx +72 -0
  30. package/src/atoms/SkeletonAtom.tsx +22 -0
  31. package/src/atoms/SpinnerAtom.tsx +26 -0
  32. package/src/atoms/TableAtom.tsx +58 -0
  33. package/src/atoms/TabsAtom.tsx +40 -0
  34. package/src/atoms/TextAtom.tsx +35 -0
  35. package/src/atoms/TooltipAtom.tsx +39 -0
  36. package/src/atoms/index.ts +28 -0
  37. package/src/components/index.ts +178 -0
  38. package/src/components/ui/accordion.tsx +56 -0
  39. package/src/components/ui/alert-dialog.tsx +139 -0
  40. package/src/components/ui/alert.tsx +59 -0
  41. package/src/components/ui/aspect-ratio.tsx +5 -0
  42. package/src/components/ui/avatar.tsx +50 -0
  43. package/src/components/ui/badge.tsx +36 -0
  44. package/src/components/ui/breadcrumb.tsx +115 -0
  45. package/src/components/ui/button-group.tsx +83 -0
  46. package/src/components/ui/button.tsx +56 -0
  47. package/src/components/ui/calendar.tsx +213 -0
  48. package/src/components/ui/card.tsx +79 -0
  49. package/src/components/ui/carousel.tsx +260 -0
  50. package/src/components/ui/chart.tsx +367 -0
  51. package/src/components/ui/checkbox.tsx +28 -0
  52. package/src/components/ui/collapsible.tsx +11 -0
  53. package/src/components/ui/command.tsx +153 -0
  54. package/src/components/ui/context-menu.tsx +198 -0
  55. package/src/components/ui/dialog.tsx +122 -0
  56. package/src/components/ui/drawer.tsx +116 -0
  57. package/src/components/ui/dropdown-menu.tsx +200 -0
  58. package/src/components/ui/empty.tsx +104 -0
  59. package/src/components/ui/field.tsx +244 -0
  60. package/src/components/ui/form.tsx +176 -0
  61. package/src/components/ui/hover-card.tsx +27 -0
  62. package/src/components/ui/input-group.tsx +168 -0
  63. package/src/components/ui/input-otp.tsx +69 -0
  64. package/src/components/ui/input.tsx +22 -0
  65. package/src/components/ui/item.tsx +193 -0
  66. package/src/components/ui/kbd.tsx +28 -0
  67. package/src/components/ui/label.tsx +26 -0
  68. package/src/components/ui/menubar.tsx +254 -0
  69. package/src/components/ui/navigation-menu.tsx +128 -0
  70. package/src/components/ui/pagination.tsx +117 -0
  71. package/src/components/ui/popover.tsx +29 -0
  72. package/src/components/ui/progress.tsx +28 -0
  73. package/src/components/ui/radio-group.tsx +42 -0
  74. package/src/components/ui/resizable.tsx +45 -0
  75. package/src/components/ui/scroll-area.tsx +46 -0
  76. package/src/components/ui/select.tsx +160 -0
  77. package/src/components/ui/separator.tsx +29 -0
  78. package/src/components/ui/sheet.tsx +140 -0
  79. package/src/components/ui/sidebar.tsx +771 -0
  80. package/src/components/ui/skeleton.tsx +15 -0
  81. package/src/components/ui/slider.tsx +26 -0
  82. package/src/components/ui/sonner.tsx +45 -0
  83. package/src/components/ui/spinner.tsx +16 -0
  84. package/src/components/ui/switch.tsx +27 -0
  85. package/src/components/ui/table.tsx +117 -0
  86. package/src/components/ui/tabs.tsx +53 -0
  87. package/src/components/ui/textarea.tsx +22 -0
  88. package/src/components/ui/toggle-group.tsx +61 -0
  89. package/src/components/ui/toggle.tsx +43 -0
  90. package/src/components/ui/tooltip.tsx +30 -0
  91. package/src/hooks/use-mobile.tsx +19 -0
  92. package/src/index.ts +24 -0
  93. package/src/lib/countries.ts +203 -0
  94. package/src/lib/index.ts +2 -0
  95. package/src/lib/utils.ts +15 -0
  96. package/src/lib/validators/index.ts +1 -0
  97. package/src/lib/validators/theme.ts +148 -0
  98. package/src/molecules/creator-discovery/CampaignSeedCard/CampaignSeedCard.tsx +123 -0
  99. package/src/molecules/creator-discovery/CampaignSeedCard/CampaignSeedCard.types.ts +13 -0
  100. package/src/molecules/creator-discovery/CampaignSeedCard/index.ts +2 -0
  101. package/src/molecules/creator-discovery/MCQCard/MCQCard.tsx +165 -0
  102. package/src/molecules/creator-discovery/MCQCard/MCQCard.types.ts +71 -0
  103. package/src/molecules/creator-discovery/MCQCard/index.ts +2 -0
  104. package/src/molecules/creator-discovery/SearchSpecCard/CustomFieldRenderers.tsx +334 -0
  105. package/src/molecules/creator-discovery/SearchSpecCard/SearchSpecCard.tsx +111 -0
  106. package/src/molecules/creator-discovery/SearchSpecCard/SearchSpecCard.types.ts +18 -0
  107. package/src/molecules/creator-discovery/SearchSpecCard/index.ts +3 -0
  108. package/src/molecules/creator-discovery/index.ts +3 -0
  109. package/src/molecules/generic/ActionButton/ActionButton.tsx +137 -0
  110. package/src/molecules/generic/ActionButton/ActionButton.types.ts +68 -0
  111. package/src/molecules/generic/ActionButton/index.ts +2 -0
  112. package/src/molecules/generic/EditableField/EditableField.tsx +229 -0
  113. package/src/molecules/generic/EditableField/EditableField.types.ts +73 -0
  114. package/src/molecules/generic/EditableField/index.ts +2 -0
  115. package/src/molecules/generic/FormCard/FormCard.tsx +136 -0
  116. package/src/molecules/generic/FormCard/FormCard.types.ts +93 -0
  117. package/src/molecules/generic/FormCard/index.ts +2 -0
  118. package/src/molecules/generic/index.ts +3 -0
  119. package/src/molecules/index.ts +2 -0
  120. package/src/render/PXEngineRenderer.tsx +272 -0
  121. package/src/render/index.ts +1 -0
  122. package/src/styles/globals.css +146 -0
  123. package/src/types/atoms.ts +294 -0
  124. package/src/types/common.ts +116 -0
  125. package/src/types/index.ts +3 -0
  126. package/src/types/molecules.ts +54 -0
  127. package/src/types/schema.ts +12 -0
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import {
3
+ Dialog,
4
+ DialogContent,
5
+ DialogDescription,
6
+ DialogHeader,
7
+ DialogTitle,
8
+ DialogTrigger,
9
+ DialogFooter,
10
+ } from "@/components/ui/dialog";
11
+ import { DialogAtomType, UIComponent } from "../types/schema";
12
+ import { cn } from "@/lib/utils";
13
+
14
+ interface Props extends DialogAtomType {
15
+ renderComponent: (component: UIComponent) => React.ReactNode;
16
+ }
17
+
18
+ export const DialogAtom: React.FC<Props> = ({
19
+ title,
20
+ description,
21
+ trigger,
22
+ children,
23
+ footer,
24
+ className,
25
+ renderComponent,
26
+ }) => {
27
+ return (
28
+ <Dialog>
29
+ <DialogTrigger asChild>
30
+ <div className={cn("inline-block cursor-pointer", className)}>
31
+ {trigger.map((child) => (
32
+ <React.Fragment key={child.id}>
33
+ {renderComponent(child)}
34
+ </React.Fragment>
35
+ ))}
36
+ </div>
37
+ </DialogTrigger>
38
+ <DialogContent className="sm:max-w-[425px] rounded-3xl p-6 bg-white/95 backdrop-blur-md shadow-3xl border-gray-100">
39
+ <DialogHeader>
40
+ <DialogTitle className="text-xl font-bold bg-gradient-to-r from-purple600 to-indigo-600 bg-clip-text text-transparent">
41
+ {title}
42
+ </DialogTitle>
43
+ {description && (
44
+ <DialogDescription className="text-gray-500 font-medium pt-1">
45
+ {description}
46
+ </DialogDescription>
47
+ )}
48
+ </DialogHeader>
49
+ <div className="py-4">
50
+ {children.map((child) => (
51
+ <React.Fragment key={child.id}>
52
+ {renderComponent(child)}
53
+ </React.Fragment>
54
+ ))}
55
+ </div>
56
+ {footer && (
57
+ <DialogFooter className="pt-2">
58
+ {footer.map((child) => (
59
+ <React.Fragment key={child.id}>
60
+ {renderComponent(child)}
61
+ </React.Fragment>
62
+ ))}
63
+ </DialogFooter>
64
+ )}
65
+ </DialogContent>
66
+ </Dialog>
67
+ );
68
+ };
@@ -0,0 +1,162 @@
1
+ import React from "react";
2
+ import { Input } from "@/components/ui/input";
3
+ import { Textarea } from "@/components/ui/textarea";
4
+ import { Label } from "@/components/ui/label";
5
+ import { Checkbox } from "@/components/ui/checkbox";
6
+ import { Switch } from "@/components/ui/switch";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue,
13
+ } from "@/components/ui/select";
14
+ import { Slider } from "@/components/ui/slider";
15
+ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
16
+ import {
17
+ InputOTP,
18
+ InputOTPGroup,
19
+ InputOTPSlot,
20
+ } from "@/components/ui/input-otp";
21
+ import { InputAtomType } from "../types/schema";
22
+ import { cn } from "@/lib/utils";
23
+
24
+ /**
25
+ * InputAtom
26
+ * A multi-purpose input wrapper that switches based on inputType in schema
27
+ */
28
+ export const InputAtom: React.FC<InputAtomType> = ({
29
+ inputType,
30
+ label,
31
+ placeholder,
32
+ defaultValue,
33
+ required,
34
+ disabled,
35
+ options,
36
+ config,
37
+ className,
38
+ }) => {
39
+ const containerClass = cn("flex flex-col gap-1.5 w-full", className);
40
+
41
+ const renderLabel = () => {
42
+ if (!label) return null;
43
+ return (
44
+ <Label className="text-xs font-bold text-gray-400 uppercase tracking-widest pl-1">
45
+ {label} {required && <span className="text-destructive">*</span>}
46
+ </Label>
47
+ );
48
+ };
49
+
50
+ const renderInput = () => {
51
+ switch (inputType) {
52
+ case "textarea":
53
+ return (
54
+ <Textarea
55
+ placeholder={placeholder}
56
+ defaultValue={defaultValue}
57
+ disabled={disabled}
58
+ rows={config?.rows || 3}
59
+ />
60
+ );
61
+ case "select":
62
+ return (
63
+ <Select defaultValue={defaultValue} disabled={disabled}>
64
+ <SelectTrigger>
65
+ <SelectValue placeholder={placeholder || "Select option"} />
66
+ </SelectTrigger>
67
+ <SelectContent>
68
+ {options?.map((opt) => (
69
+ <SelectItem key={opt.value} value={opt.value}>
70
+ {opt.label}
71
+ </SelectItem>
72
+ ))}
73
+ </SelectContent>
74
+ </Select>
75
+ );
76
+ case "slider":
77
+ return (
78
+ <div className="pt-4 pb-2">
79
+ <Slider
80
+ defaultValue={[defaultValue || config?.min || 0]}
81
+ max={config?.max || 100}
82
+ min={config?.min || 0}
83
+ step={config?.step || 1}
84
+ disabled={disabled}
85
+ />
86
+ </div>
87
+ );
88
+ case "checkbox":
89
+ return (
90
+ <div className="flex items-center space-x-2 py-2">
91
+ <Checkbox
92
+ id={label}
93
+ defaultChecked={defaultValue}
94
+ disabled={disabled}
95
+ />
96
+ <label
97
+ htmlFor={label}
98
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
99
+ >
100
+ {label}
101
+ </label>
102
+ </div>
103
+ );
104
+ case "switch":
105
+ return (
106
+ <div className="flex items-center space-x-2 py-2">
107
+ <Switch
108
+ id={label}
109
+ defaultChecked={defaultValue}
110
+ disabled={disabled}
111
+ />
112
+ <Label htmlFor={label}>{label}</Label>
113
+ </div>
114
+ );
115
+ case "radio":
116
+ return (
117
+ <RadioGroup defaultValue={defaultValue} disabled={disabled}>
118
+ {options?.map((opt) => (
119
+ <div key={opt.value} className="flex items-center space-x-2">
120
+ <RadioGroupItem
121
+ value={opt.value}
122
+ id={`${label}-${opt.value}`}
123
+ />
124
+ <Label htmlFor={`${label}-${opt.value}`}>{opt.label}</Label>
125
+ </div>
126
+ ))}
127
+ </RadioGroup>
128
+ );
129
+ case "otp":
130
+ return (
131
+ <InputOTP
132
+ maxLength={config?.maxLength || 6}
133
+ disabled={disabled}
134
+ defaultValue={defaultValue}
135
+ >
136
+ <InputOTPGroup>
137
+ {Array.from({ length: config?.maxLength || 6 }).map((_, i) => (
138
+ <InputOTPSlot key={i} index={i} />
139
+ ))}
140
+ </InputOTPGroup>
141
+ </InputOTP>
142
+ );
143
+ default:
144
+ return (
145
+ <Input
146
+ type={inputType}
147
+ placeholder={placeholder}
148
+ defaultValue={defaultValue}
149
+ disabled={disabled}
150
+ required={required}
151
+ />
152
+ );
153
+ }
154
+ };
155
+
156
+ return (
157
+ <div className={containerClass}>
158
+ {inputType !== "checkbox" && inputType !== "switch" && renderLabel()}
159
+ {renderInput()}
160
+ </div>
161
+ );
162
+ };
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { LayoutAtomType, UIComponent } from "../types/schema";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ interface Props extends LayoutAtomType {
6
+ renderComponent: (component: UIComponent) => React.ReactNode;
7
+ }
8
+
9
+ /**
10
+ * LayoutAtom
11
+ * Standardized container with flex/grid support from schema
12
+ */
13
+ export const LayoutAtom: React.FC<Props> = ({
14
+ direction,
15
+ gap = "md",
16
+ children,
17
+ className,
18
+ renderComponent,
19
+ }) => {
20
+ const gapMap: Record<string, string> = {
21
+ none: "gap-0",
22
+ sm: "gap-2",
23
+ md: "gap-4",
24
+ lg: "gap-8",
25
+ xl: "gap-12",
26
+ };
27
+
28
+ const classes = cn(
29
+ "flex",
30
+ direction === "vertical" ? "flex-col" : "flex-row flex-wrap",
31
+ direction === "grid" && "grid grid-cols-1 md:grid-cols-2",
32
+ gapMap[gap],
33
+ className,
34
+ );
35
+
36
+ return (
37
+ <div className={classes}>
38
+ {children.map((child) => (
39
+ <React.Fragment key={child.id}>{renderComponent(child)}</React.Fragment>
40
+ ))}
41
+ </div>
42
+ );
43
+ };
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import {
3
+ Pagination,
4
+ PaginationContent,
5
+ PaginationEllipsis,
6
+ PaginationItem,
7
+ PaginationLink,
8
+ PaginationNext,
9
+ PaginationPrevious,
10
+ } from "@/components/ui/pagination";
11
+ import { PaginationAtomType } from "../types/schema";
12
+
13
+ export const PaginationAtom: React.FC<PaginationAtomType> = ({
14
+ currentPage,
15
+ totalPages,
16
+ hasNext = true,
17
+ hasPrev = true,
18
+ className,
19
+ }) => {
20
+ return (
21
+ <Pagination className={className}>
22
+ <PaginationContent>
23
+ {hasPrev && (
24
+ <PaginationItem>
25
+ <PaginationPrevious href="#" />
26
+ </PaginationItem>
27
+ )}
28
+
29
+ <PaginationItem>
30
+ <PaginationLink href="#" isActive>
31
+ {currentPage}
32
+ </PaginationLink>
33
+ </PaginationItem>
34
+
35
+ {totalPages > currentPage && (
36
+ <PaginationItem>
37
+ <PaginationEllipsis />
38
+ </PaginationItem>
39
+ )}
40
+
41
+ {hasNext && (
42
+ <PaginationItem>
43
+ <PaginationNext href="#" />
44
+ </PaginationItem>
45
+ )}
46
+ </PaginationContent>
47
+ </Pagination>
48
+ );
49
+ };
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import {
3
+ Popover,
4
+ PopoverContent,
5
+ PopoverTrigger,
6
+ } from "@/components/ui/popover";
7
+ import { PopoverAtomType, UIComponent } from "../types/schema";
8
+ import { cn } from "@/lib/utils";
9
+
10
+ interface Props extends PopoverAtomType {
11
+ renderComponent: (component: UIComponent) => React.ReactNode;
12
+ }
13
+
14
+ export const PopoverAtom: React.FC<Props> = ({
15
+ trigger,
16
+ content,
17
+ className,
18
+ renderComponent,
19
+ }) => {
20
+ return (
21
+ <Popover>
22
+ <PopoverTrigger asChild>
23
+ <div className={cn("inline-block cursor-pointer", className)}>
24
+ {trigger.map((child) => (
25
+ <React.Fragment key={child.id}>
26
+ {renderComponent(child)}
27
+ </React.Fragment>
28
+ ))}
29
+ </div>
30
+ </PopoverTrigger>
31
+ <PopoverContent className="w-80 rounded-2xl shadow-2xl border-gray-100 p-4 bg-white/95 backdrop-blur-sm">
32
+ {content.map((child) => (
33
+ <React.Fragment key={child.id}>
34
+ {renderComponent(child)}
35
+ </React.Fragment>
36
+ ))}
37
+ </PopoverContent>
38
+ </Popover>
39
+ );
40
+ };
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import { Progress } from "@/components/ui/progress";
3
+ import { ProgressAtomType } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ export const ProgressAtom: React.FC<ProgressAtomType> = ({
7
+ value,
8
+ className,
9
+ }) => {
10
+ return (
11
+ <div className={cn("w-full py-2", className)}>
12
+ <Progress value={value} className="h-2 bg-gray-100" />
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
3
+ import { ScrollAreaAtomType, UIComponent } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ interface Props extends ScrollAreaAtomType {
7
+ renderComponent: (component: UIComponent) => React.ReactNode;
8
+ }
9
+
10
+ export const ScrollAreaAtom: React.FC<Props> = ({
11
+ maxHeight = "300px",
12
+ children,
13
+ className,
14
+ renderComponent,
15
+ }) => {
16
+ return (
17
+ <ScrollArea
18
+ className={cn("rounded-xl border", className)}
19
+ style={{ height: maxHeight }}
20
+ >
21
+ <div className="p-4">
22
+ {children.map((child) => (
23
+ <React.Fragment key={child.id}>
24
+ {renderComponent(child)}
25
+ </React.Fragment>
26
+ ))}
27
+ </div>
28
+ <ScrollBar orientation="vertical" />
29
+ </ScrollArea>
30
+ );
31
+ };
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { Separator } from "@/components/ui/separator";
3
+ import { SeparatorAtomType } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ export const SeparatorAtom: React.FC<SeparatorAtomType> = ({
7
+ orientation = "horizontal",
8
+ className,
9
+ }) => {
10
+ return (
11
+ <Separator
12
+ orientation={orientation}
13
+ className={cn("bg-gray-100", className)}
14
+ />
15
+ );
16
+ };
@@ -0,0 +1,72 @@
1
+ import React from "react";
2
+ import {
3
+ Sheet,
4
+ SheetContent,
5
+ SheetDescription,
6
+ SheetHeader,
7
+ SheetTitle,
8
+ SheetTrigger,
9
+ SheetFooter,
10
+ } from "@/components/ui/sheet";
11
+ import { SheetAtomType, UIComponent } from "../types/schema";
12
+ import { cn } from "@/lib/utils";
13
+
14
+ interface Props extends SheetAtomType {
15
+ renderComponent: (component: UIComponent) => React.ReactNode;
16
+ }
17
+
18
+ export const SheetAtom: React.FC<Props> = ({
19
+ side = "right",
20
+ title,
21
+ description,
22
+ trigger,
23
+ children,
24
+ footer,
25
+ className,
26
+ renderComponent,
27
+ }) => {
28
+ return (
29
+ <Sheet>
30
+ <SheetTrigger asChild>
31
+ <div className={cn("inline-block cursor-pointer", className)}>
32
+ {trigger.map((child) => (
33
+ <React.Fragment key={child.id}>
34
+ {renderComponent(child)}
35
+ </React.Fragment>
36
+ ))}
37
+ </div>
38
+ </SheetTrigger>
39
+ <SheetContent
40
+ side={side}
41
+ className="bg-white/95 backdrop-blur-md border-l-gray-100 shadow-2xl p-6"
42
+ >
43
+ <SheetHeader>
44
+ <SheetTitle className="text-xl font-bold text-gray-900">
45
+ {title}
46
+ </SheetTitle>
47
+ {description && (
48
+ <SheetDescription className="text-gray-500 font-medium">
49
+ {description}
50
+ </SheetDescription>
51
+ )}
52
+ </SheetHeader>
53
+ <div className="py-8">
54
+ {children.map((child) => (
55
+ <React.Fragment key={child.id}>
56
+ {renderComponent(child)}
57
+ </React.Fragment>
58
+ ))}
59
+ </div>
60
+ {footer && (
61
+ <SheetFooter className="absolute bottom-6 left-6 right-6">
62
+ {footer.map((child) => (
63
+ <React.Fragment key={child.id}>
64
+ {renderComponent(child)}
65
+ </React.Fragment>
66
+ ))}
67
+ </SheetFooter>
68
+ )}
69
+ </SheetContent>
70
+ </Sheet>
71
+ );
72
+ };
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import { Skeleton } from "@/components/ui/skeleton";
3
+ import { SkeletonAtomType } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ export const SkeletonAtom: React.FC<SkeletonAtomType> = ({
7
+ shape = "rect",
8
+ width,
9
+ height,
10
+ className,
11
+ }) => {
12
+ return (
13
+ <Skeleton
14
+ className={cn(
15
+ shape === "circle" ? "rounded-full" : "rounded-md",
16
+ "bg-gray-100",
17
+ className,
18
+ )}
19
+ style={{ width, height }}
20
+ />
21
+ );
22
+ };
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { Loader2 } from "lucide-react";
3
+ import { SpinnerAtomType } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ export const SpinnerAtom: React.FC<SpinnerAtomType> = ({
7
+ size = "md",
8
+ className,
9
+ }) => {
10
+ const sizeMap = {
11
+ sm: "h-4 w-4",
12
+ md: "h-6 w-6",
13
+ lg: "h-8 w-8",
14
+ xl: "h-12 w-12",
15
+ };
16
+
17
+ return (
18
+ <Loader2
19
+ className={cn(
20
+ "animate-spin text-purple500",
21
+ sizeMap[size] || sizeMap.md,
22
+ className,
23
+ )}
24
+ />
25
+ );
26
+ };
@@ -0,0 +1,58 @@
1
+ import React from "react";
2
+ import {
3
+ Table,
4
+ TableBody,
5
+ TableCell,
6
+ TableHead,
7
+ TableHeader,
8
+ TableRow,
9
+ } from "@/components/ui/table";
10
+ import { TableAtomType } from "../types/schema";
11
+ import { cn } from "@/lib/utils";
12
+
13
+ export const TableAtom: React.FC<TableAtomType> = ({
14
+ headers,
15
+ rows,
16
+ className,
17
+ }) => {
18
+ return (
19
+ <div
20
+ className={cn(
21
+ "rounded-2xl border border-gray-100 overflow-hidden bg-white",
22
+ className,
23
+ )}
24
+ >
25
+ <Table>
26
+ <TableHeader className="bg-gray-50/50">
27
+ <TableRow>
28
+ {headers.map((header, i) => (
29
+ <TableHead
30
+ key={i}
31
+ className="text-xs font-bold text-gray-400 uppercase tracking-widest px-6 py-4"
32
+ >
33
+ {header}
34
+ </TableHead>
35
+ ))}
36
+ </TableRow>
37
+ </TableHeader>
38
+ <TableBody>
39
+ {rows.map((row, i) => (
40
+ <TableRow
41
+ key={i}
42
+ className="hover:bg-purple-50/30 transition-colors border-gray-50"
43
+ >
44
+ {row.map((cell, j) => (
45
+ <TableCell
46
+ key={j}
47
+ className="text-sm text-gray-700 px-6 py-4 font-medium"
48
+ >
49
+ {cell}
50
+ </TableCell>
51
+ ))}
52
+ </TableRow>
53
+ ))}
54
+ </TableBody>
55
+ </Table>
56
+ </div>
57
+ );
58
+ };
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
3
+ import { TabsAtomType, UIComponent } from "../types/schema";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ interface Props extends TabsAtomType {
7
+ renderComponent: (component: UIComponent) => React.ReactNode;
8
+ }
9
+
10
+ export const TabsAtom: React.FC<Props> = ({
11
+ defaultValue,
12
+ tabs,
13
+ className,
14
+ renderComponent,
15
+ }) => {
16
+ return (
17
+ <Tabs defaultValue={defaultValue} className={cn("w-full", className)}>
18
+ <TabsList className="bg-gray-100/50 p-1 rounded-xl">
19
+ {tabs.map((tab) => (
20
+ <TabsTrigger
21
+ key={tab.value}
22
+ value={tab.value}
23
+ className="rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-sm"
24
+ >
25
+ {tab.label}
26
+ </TabsTrigger>
27
+ ))}
28
+ </TabsList>
29
+ {tabs.map((tab) => (
30
+ <TabsContent key={tab.value} value={tab.value} className="mt-4">
31
+ {tab.content.map((child) => (
32
+ <React.Fragment key={child.id}>
33
+ {renderComponent(child)}
34
+ </React.Fragment>
35
+ ))}
36
+ </TabsContent>
37
+ ))}
38
+ </Tabs>
39
+ );
40
+ };
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+ import { TextAtomType } from "../types/schema";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ /**
6
+ * TextAtom
7
+ * Renders standardized text styles from UISchema
8
+ */
9
+ export const TextAtom: React.FC<TextAtomType> = ({
10
+ content,
11
+ variant = "p",
12
+ className,
13
+ }) => {
14
+ const baseStyles: Record<string, string> = {
15
+ h1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-gray-900",
16
+ h2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0 text-gray-900",
17
+ h3: "scroll-m-20 text-2xl font-semibold tracking-tight text-gray-900",
18
+ h4: "scroll-m-20 text-xl font-semibold tracking-tight text-gray-900",
19
+ p: "leading-7 [&:not(:first-child)]:mt-6 text-gray-700",
20
+ small: "text-sm font-medium leading-none text-gray-600",
21
+ muted: "text-sm text-muted-foreground",
22
+ label: "text-[10px] font-bold text-gray-400 uppercase tracking-widest pl-1",
23
+ };
24
+
25
+ const Component =
26
+ variant === "small" || variant === "muted" || variant === "label"
27
+ ? "p"
28
+ : variant;
29
+
30
+ return (
31
+ <Component className={cn(baseStyles[variant], className)}>
32
+ {content}
33
+ </Component>
34
+ );
35
+ };