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 { ButtonVariant, ButtonSize } from "@/types/common";
2
+
3
+ export interface ActionButtonProps {
4
+ /**
5
+ * Unique identifier
6
+ */
7
+ id?: string;
8
+
9
+ /**
10
+ * Main button label
11
+ */
12
+ label: string;
13
+
14
+ /**
15
+ * Secondary label (e.g. for sub-actions or state changes)
16
+ */
17
+ secondaryLabel?: string;
18
+
19
+ /**
20
+ * Countdown in seconds. If provided, the button will show a timer.
21
+ */
22
+ countdown?: number;
23
+
24
+ /**
25
+ * Whether the auto-proceed is paused
26
+ */
27
+ isPaused?: boolean;
28
+
29
+ /**
30
+ * Triggered when the user pauses/resumes the timer
31
+ */
32
+ onPause?: () => void;
33
+
34
+ /**
35
+ * Triggered when the user clicks the button or timer expires
36
+ */
37
+ onProceed: () => void;
38
+
39
+ /**
40
+ * Button variant (from shadcn)
41
+ */
42
+ variant?: ButtonVariant;
43
+
44
+ /**
45
+ * Button size (from shadcn)
46
+ */
47
+ size?: ButtonSize;
48
+
49
+ /**
50
+ * Whether the button is disabled
51
+ */
52
+ disabled?: boolean;
53
+
54
+ /**
55
+ * Loading state
56
+ */
57
+ isLoading?: boolean;
58
+
59
+ /**
60
+ * Custom className
61
+ */
62
+ className?: string;
63
+
64
+ /**
65
+ * Whether to show the countdown visually
66
+ */
67
+ showCountdown?: boolean;
68
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./ActionButton";
2
+ export * from "./ActionButton.types";
@@ -0,0 +1,229 @@
1
+ import React, { useState, useEffect, useRef } from "react";
2
+ import { EditableFieldProps } from "./EditableField.types";
3
+ import { cn } from "@/lib/utils";
4
+ import {
5
+ Button,
6
+ Input,
7
+ Label,
8
+ Textarea,
9
+ Select,
10
+ SelectContent,
11
+ SelectItem,
12
+ SelectTrigger,
13
+ SelectValue,
14
+ Slider,
15
+ } from "@/components";
16
+ import { Check, X, Pencil, Loader2 } from "lucide-react";
17
+
18
+ /**
19
+ * EditableField
20
+ *
21
+ * A generic field that toggles between display and edit modes.
22
+ * Supports various input types and custom rendering.
23
+ */
24
+ export const EditableField = React.memo<EditableFieldProps>(
25
+ ({
26
+ label,
27
+ value,
28
+ type,
29
+ isEditing: isEditingProp,
30
+ onEdit,
31
+ onSave,
32
+ onCancel,
33
+ isSaving = false,
34
+ isChanged = false,
35
+ config = {},
36
+ className,
37
+ renderDisplay,
38
+ renderEdit,
39
+ }) => {
40
+ const [localValue, setLocalValue] = useState(value);
41
+ const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
42
+
43
+ // Sync local value when external value changes or editing starts
44
+ useEffect(() => {
45
+ setLocalValue(value);
46
+ }, [value, isEditingProp]);
47
+
48
+ // Focus input when editing starts
49
+ useEffect(() => {
50
+ if (isEditingProp) {
51
+ setTimeout(() => inputRef.current?.focus(), 0);
52
+ }
53
+ }, [isEditingProp]);
54
+
55
+ const handleSave = () => {
56
+ onSave?.(localValue);
57
+ };
58
+
59
+ const handleKeyDown = (e: React.KeyboardEvent) => {
60
+ if (e.key === "Enter" && !e.shiftKey && type !== "textarea") {
61
+ e.preventDefault();
62
+ handleSave();
63
+ } else if (e.key === "Escape") {
64
+ onCancel?.();
65
+ }
66
+ };
67
+
68
+ const renderInput = () => {
69
+ if (renderEdit) {
70
+ return renderEdit(localValue, setLocalValue);
71
+ }
72
+
73
+ switch (type) {
74
+ case "textarea":
75
+ return (
76
+ <Textarea
77
+ ref={inputRef as React.RefObject<HTMLTextAreaElement>}
78
+ value={localValue || ""}
79
+ onChange={(e) => setLocalValue(e.target.value)}
80
+ onKeyDown={handleKeyDown}
81
+ placeholder={config.placeholder}
82
+ rows={config.rows || 3}
83
+ className="min-h-[80px] resize-none"
84
+ />
85
+ );
86
+ case "select":
87
+ return (
88
+ <Select
89
+ value={localValue?.toString()}
90
+ onValueChange={(val) => setLocalValue(val)}
91
+ >
92
+ <SelectTrigger className="w-full">
93
+ <SelectValue
94
+ placeholder={config.placeholder || "Select an option"}
95
+ />
96
+ </SelectTrigger>
97
+ <SelectContent>
98
+ {config.options?.map((opt: any) => {
99
+ const label = typeof opt === "string" ? opt : opt.label;
100
+ const val = typeof opt === "string" ? opt : opt.value;
101
+ return (
102
+ <SelectItem key={val} value={val}>
103
+ {label}
104
+ </SelectItem>
105
+ );
106
+ })}
107
+ </SelectContent>
108
+ </Select>
109
+ );
110
+ case "slider":
111
+ return (
112
+ <div className="pt-6 pb-2 px-2">
113
+ <Slider
114
+ defaultValue={[localValue?.min || 0, localValue?.max || 100]}
115
+ max={config.sliderConfig?.max || 100}
116
+ min={config.sliderConfig?.min || 0}
117
+ step={config.sliderConfig?.step || 1}
118
+ onValueChange={([min, max]) => setLocalValue({ min, max })}
119
+ />
120
+ {config.sliderConfig?.formatValue && (
121
+ <div className="mt-2 text-xs text-muted-foreground text-center">
122
+ {config.sliderConfig.formatValue(localValue)}
123
+ </div>
124
+ )}
125
+ </div>
126
+ );
127
+ case "number":
128
+ return (
129
+ <Input
130
+ ref={inputRef as React.RefObject<HTMLInputElement>}
131
+ type="number"
132
+ value={localValue || ""}
133
+ onChange={(e) => setLocalValue(e.target.value)}
134
+ onKeyDown={handleKeyDown}
135
+ min={config.numberConfig?.min}
136
+ max={config.numberConfig?.max}
137
+ step={config.numberConfig?.step}
138
+ />
139
+ );
140
+ default:
141
+ return (
142
+ <Input
143
+ ref={inputRef as React.RefObject<HTMLInputElement>}
144
+ type="text"
145
+ value={localValue || ""}
146
+ onChange={(e) => setLocalValue(e.target.value)}
147
+ onKeyDown={handleKeyDown}
148
+ placeholder={config.placeholder}
149
+ />
150
+ );
151
+ }
152
+ };
153
+
154
+ const formattedValue = () => {
155
+ if (renderDisplay) return renderDisplay(value);
156
+
157
+ if (type === "slider") {
158
+ return config.sliderConfig?.formatValue
159
+ ? config.sliderConfig.formatValue(value)
160
+ : `${value?.min} - ${value?.max}`;
161
+ }
162
+
163
+ if (!value)
164
+ return <span className="text-muted-foreground italic">Not set</span>;
165
+
166
+ return value.toString();
167
+ };
168
+
169
+ return (
170
+ <div className={cn("group flex flex-col gap-1.5 py-2", className)}>
171
+ <div className="flex items-center justify-between">
172
+ <Label className="text-xs font-medium text-gray500 uppercase tracking-tight">
173
+ {label}
174
+ </Label>
175
+ {isChanged && !isEditingProp && (
176
+ <div
177
+ className="w-1.5 h-1.5 rounded-full bg-amber-500"
178
+ title="Unsaved changes"
179
+ />
180
+ )}
181
+ </div>
182
+
183
+ {isEditingProp ? (
184
+ <div className="flex flex-col gap-2">
185
+ {renderInput()}
186
+ <div className="flex items-center justify-end gap-2">
187
+ <Button
188
+ size="icon"
189
+ variant="outline"
190
+ className="h-8 w-8 text-destructive border-destructive/20 hover:bg-destructive/10"
191
+ onClick={onCancel}
192
+ disabled={isSaving}
193
+ >
194
+ <X className="h-4 w-4" />
195
+ </Button>
196
+ <Button
197
+ size="icon"
198
+ className="h-8 w-8 bg-purple500 hover:bg-purple600 text-white"
199
+ onClick={handleSave}
200
+ disabled={isSaving}
201
+ >
202
+ {isSaving ? (
203
+ <Loader2 className="h-4 w-4 animate-spin" />
204
+ ) : (
205
+ <Check className="h-4 w-4" />
206
+ )}
207
+ </Button>
208
+ </div>
209
+ </div>
210
+ ) : (
211
+ <div
212
+ className={cn(
213
+ "relative flex items-center justify-between rounded-md px-2 py-1.5 transition-all",
214
+ "hover:bg-gray-100/50 cursor-pointer border border-transparent hover:border-gray-200",
215
+ )}
216
+ onClick={onEdit}
217
+ >
218
+ <div className="text-sm text-gray-900 font-medium truncate flex-1 leading-relaxed">
219
+ {formattedValue()}
220
+ </div>
221
+ <Pencil className="h-3.5 w-3.5 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity" />
222
+ </div>
223
+ )}
224
+ </div>
225
+ );
226
+ },
227
+ );
228
+
229
+ EditableField.displayName = "EditableField";
@@ -0,0 +1,73 @@
1
+ import { FieldType, FieldConfig } from "@/types/common";
2
+
3
+ export interface EditableFieldProps {
4
+ /**
5
+ * Unique identifier
6
+ */
7
+ id?: string;
8
+
9
+ /**
10
+ * Field label
11
+ */
12
+ label: string;
13
+
14
+ /**
15
+ * Field value
16
+ */
17
+ value: any;
18
+
19
+ /**
20
+ * Input type (text, textarea, number, slider, etc.)
21
+ */
22
+ type: FieldType;
23
+
24
+ /**
25
+ * Current editing state
26
+ */
27
+ isEditing?: boolean;
28
+
29
+ /**
30
+ * Triggered when the user wants to start editing
31
+ */
32
+ onEdit?: () => void;
33
+
34
+ /**
35
+ * Triggered when the user saves the new value
36
+ */
37
+ onSave?: (newValue: any) => void;
38
+
39
+ /**
40
+ * Triggered when the user cancels editing
41
+ */
42
+ onCancel?: () => void;
43
+
44
+ /**
45
+ * Loading state during save
46
+ */
47
+ isSaving?: boolean;
48
+
49
+ /**
50
+ * Indicates if the value has been changed but not saved
51
+ */
52
+ isChanged?: boolean;
53
+
54
+ /**
55
+ * Configuration for the specific field type
56
+ */
57
+ config?: Partial<FieldConfig>;
58
+
59
+ /**
60
+ * Custom className for the container
61
+ */
62
+ className?: string;
63
+
64
+ /**
65
+ * Custom renderer for the display state
66
+ */
67
+ renderDisplay?: (value: any) => React.ReactNode;
68
+
69
+ /**
70
+ * Custom renderer for the edit state
71
+ */
72
+ renderEdit?: (value: any, onChange: (v: any) => void) => React.ReactNode;
73
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./EditableField";
2
+ export * from "./EditableField.types";
@@ -0,0 +1,136 @@
1
+ import React from "react";
2
+ import { FormCardProps } from "./FormCard.types";
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardHeader,
7
+ CardTitle,
8
+ CardFooter,
9
+ } from "@/components";
10
+ import { EditableField } from "../EditableField";
11
+ import { ActionButton } from "../ActionButton";
12
+ import { cn } from "@/lib/utils";
13
+ import { Copy } from "lucide-react";
14
+
15
+ /**
16
+ * FormCard
17
+ *
18
+ * A high-level molecule that assembles EditableFields into a cohesive card unit.
19
+ * Features:
20
+ * - Dotted vertical timeline visual
21
+ * - Copy to clipboard functionality
22
+ * - Integrated ActionButton with countdown
23
+ * - Responsive layout
24
+ */
25
+ export const FormCard = React.memo<FormCardProps>(
26
+ ({
27
+ title,
28
+ fields,
29
+ data,
30
+ editingFields = {},
31
+ changedFields = {},
32
+ savingFields = {},
33
+ onFieldEdit,
34
+ onFieldSave,
35
+ onFieldCancel,
36
+ showTimeline = true,
37
+ proceedLabel,
38
+ countdown,
39
+ isPaused = false,
40
+ onPause,
41
+ onProceed,
42
+ className,
43
+ footer,
44
+ }) => {
45
+ const handleCopyAll = () => {
46
+ const text = fields
47
+ .map(
48
+ (f) =>
49
+ `${f.label}: ${typeof data[f.key] === "object" ? JSON.stringify(data[f.key]) : data[f.key]}`,
50
+ )
51
+ .join("\n");
52
+ navigator.clipboard.writeText(text);
53
+ };
54
+
55
+ return (
56
+ <Card
57
+ className={cn(
58
+ "w-full rounded-[24px] border border-gray200 bg-white shadow-sm overflow-hidden",
59
+ className,
60
+ )}
61
+ >
62
+ <CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
63
+ <CardTitle className="text-lg font-bold text-gray-900 tracking-tight">
64
+ {title}
65
+ </CardTitle>
66
+ <button
67
+ onClick={handleCopyAll}
68
+ className="p-1.5 rounded-md hover:bg-gray-100 text-gray-400 hover:text-gray-600 transition-colors"
69
+ title="Copy all details"
70
+ >
71
+ <Copy className="h-4 w-4" />
72
+ </button>
73
+ </CardHeader>
74
+
75
+ <CardContent className="pt-2 pb-6">
76
+ <div className="relative">
77
+ {/* Vertical Timeline Line */}
78
+ {showTimeline && (
79
+ <div className="absolute left-[7px] top-2 bottom-6 w-0.5 border-l-2 border-dotted border-gray200 pointer-events-none" />
80
+ )}
81
+
82
+ <div className="space-y-4">
83
+ {fields.map((field) => (
84
+ <div key={field.key} className="relative pl-6">
85
+ {/* Timeline Dot */}
86
+ {showTimeline && (
87
+ <div
88
+ className={cn(
89
+ "absolute left-0 top-[18px] w-[14px] h-[14px] -translate-x-1/2 rounded-full border-2 bg-white z-10",
90
+ changedFields[field.key]
91
+ ? "border-amber-500"
92
+ : "border-gray-200",
93
+ )}
94
+ />
95
+ )}
96
+
97
+ <EditableField
98
+ label={field.label}
99
+ value={data[field.key]}
100
+ type={field.type}
101
+ config={field}
102
+ isEditing={editingFields[field.key]}
103
+ isChanged={changedFields[field.key]}
104
+ isSaving={savingFields[field.key]}
105
+ onEdit={() => onFieldEdit?.(field.key)}
106
+ onSave={(val) => onFieldSave?.(field.key, val)}
107
+ onCancel={() => onFieldCancel?.(field.key)}
108
+ />
109
+ </div>
110
+ ))}
111
+ </div>
112
+ </div>
113
+ </CardContent>
114
+
115
+ {(onProceed || footer) && (
116
+ <CardFooter className="flex flex-col gap-4 pt-0 border-t border-gray-100/50 bg-gray-50/30 p-6">
117
+ {onProceed && proceedLabel && (
118
+ <div className="w-full flex justify-center">
119
+ <ActionButton
120
+ label={proceedLabel}
121
+ countdown={countdown}
122
+ isPaused={isPaused}
123
+ onPause={onPause}
124
+ onProceed={onProceed}
125
+ />
126
+ </div>
127
+ )}
128
+ {footer}
129
+ </CardFooter>
130
+ )}
131
+ </Card>
132
+ );
133
+ },
134
+ );
135
+
136
+ FormCard.displayName = "FormCard";
@@ -0,0 +1,93 @@
1
+ import { FieldConfig } from "@/types/common";
2
+
3
+ export interface FormCardProps {
4
+ /**
5
+ * Unique identifier
6
+ */
7
+ id?: string;
8
+
9
+ /**
10
+ * Title of the form card
11
+ */
12
+ title: string;
13
+
14
+ /**
15
+ * Map of fields to render
16
+ */
17
+ fields: FieldConfig[];
18
+
19
+ /**
20
+ * Initial data for the form
21
+ */
22
+ data: Record<string, any>;
23
+
24
+ /**
25
+ * Current editing states for each field
26
+ */
27
+ editingFields?: Record<string, boolean>;
28
+
29
+ /**
30
+ * Fields that have been modified
31
+ */
32
+ changedFields?: Record<string, boolean>;
33
+
34
+ /**
35
+ * Fields currently being saved
36
+ */
37
+ savingFields?: Record<string, boolean>;
38
+
39
+ /**
40
+ * Triggered when a field starts editing
41
+ */
42
+ onFieldEdit?: (key: string) => void;
43
+
44
+ /**
45
+ * Triggered when a field value is saved
46
+ */
47
+ onFieldSave?: (key: string, newValue: any) => void;
48
+
49
+ /**
50
+ * Triggered when a field edit is cancelled
51
+ */
52
+ onFieldCancel?: (key: string) => void;
53
+
54
+ /**
55
+ * Show a dotted timeline visual on the left
56
+ */
57
+ showTimeline?: boolean;
58
+
59
+ /**
60
+ * Label for the "Proceed" button
61
+ */
62
+ proceedLabel?: string;
63
+
64
+ /**
65
+ * Countdown for auto-proceed
66
+ */
67
+ countdown?: number;
68
+
69
+ /**
70
+ * Whether the timer is paused
71
+ */
72
+ isPaused?: boolean;
73
+
74
+ /**
75
+ * Pause/Resume handler
76
+ */
77
+ onPause?: () => void;
78
+
79
+ /**
80
+ * Proceed handler
81
+ */
82
+ onProceed?: () => void;
83
+
84
+ /**
85
+ * Custom className
86
+ */
87
+ className?: string;
88
+
89
+ /**
90
+ * Footer content (optional)
91
+ */
92
+ footer?: React.ReactNode;
93
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./FormCard";
2
+ export * from "./FormCard.types";
@@ -0,0 +1,3 @@
1
+ export * from "./EditableField";
2
+ export * from "./ActionButton";
3
+ export * from "./FormCard";
@@ -0,0 +1,2 @@
1
+ export * from "./generic/index";
2
+ export * from "./creator-discovery/index";