pdyform 1.0.1 → 1.2.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 (71) hide show
  1. package/package.json +13 -1
  2. package/packages/core/node_modules/.bin/jiti +17 -0
  3. package/packages/core/node_modules/.bin/tsup +2 -2
  4. package/packages/core/node_modules/.bin/tsup-node +2 -2
  5. package/packages/core/node_modules/.vite/vitest/results.json +1 -1
  6. package/packages/core/package.json +7 -0
  7. package/packages/core/test/utils.test.ts +93 -0
  8. package/packages/react/dist/index.cjs +375 -111
  9. package/packages/react/dist/index.d.cts +80 -4
  10. package/packages/react/dist/index.d.ts +80 -4
  11. package/packages/react/dist/index.js +347 -111
  12. package/packages/react/node_modules/.bin/jiti +17 -0
  13. package/packages/react/node_modules/.bin/tsup +2 -2
  14. package/packages/react/node_modules/.bin/tsup-node +2 -2
  15. package/packages/react/node_modules/.vite/vitest/results.json +1 -1
  16. package/packages/react/package.json +14 -2
  17. package/packages/react/postcss.config.mjs +6 -0
  18. package/packages/react/src/FormFieldRenderer.tsx +32 -112
  19. package/packages/react/src/components/Checkbox.tsx +28 -0
  20. package/packages/react/src/components/CheckboxRenderer.tsx +37 -0
  21. package/packages/react/src/components/Input.tsx +24 -0
  22. package/packages/react/src/components/InputRenderer.tsx +18 -0
  23. package/packages/react/src/components/Label.tsx +24 -0
  24. package/packages/react/src/components/RadioGroup.tsx +42 -0
  25. package/packages/react/src/components/RadioRenderer.tsx +29 -0
  26. package/packages/react/src/components/Select.tsx +93 -0
  27. package/packages/react/src/components/SelectRenderer.tsx +27 -0
  28. package/packages/react/src/components/Textarea.tsx +23 -0
  29. package/packages/react/src/components/TextareaRenderer.tsx +17 -0
  30. package/packages/react/src/components/index.ts +55 -0
  31. package/packages/react/src/components/types.ts +17 -0
  32. package/packages/react/src/index.tsx +1 -0
  33. package/packages/react/src/utils.ts +7 -0
  34. package/packages/react/tailwind.config.mjs +10 -0
  35. package/packages/react/test/FormFieldRenderer.test.tsx +117 -0
  36. package/packages/vue/dist/index.d.ts +33 -0
  37. package/packages/vue/dist/index.js +28 -1
  38. package/packages/vue/dist/index.mjs +6792 -142
  39. package/packages/vue/node_modules/.bin/tsc +2 -2
  40. package/packages/vue/node_modules/.bin/tsserver +2 -2
  41. package/packages/vue/node_modules/.bin/vite +2 -2
  42. package/packages/vue/node_modules/.bin/vitest +2 -2
  43. package/packages/vue/node_modules/.bin/vue-tsc +2 -2
  44. package/packages/vue/node_modules/.vite/vitest/results.json +1 -1
  45. package/packages/vue/package.json +11 -2
  46. package/packages/vue/postcss.config.mjs +6 -0
  47. package/packages/vue/src/FormFieldRenderer.vue +46 -90
  48. package/packages/vue/src/components/Checkbox.vue +28 -0
  49. package/packages/vue/src/components/CheckboxRenderer.vue +35 -0
  50. package/packages/vue/src/components/Input.vue +21 -0
  51. package/packages/vue/src/components/InputRenderer.vue +19 -0
  52. package/packages/vue/src/components/Label.vue +21 -0
  53. package/packages/vue/src/components/RadioGroup.vue +30 -0
  54. package/packages/vue/src/components/RadioGroupItem.vue +26 -0
  55. package/packages/vue/src/components/RadioRenderer.vue +24 -0
  56. package/packages/vue/src/components/Select.vue +40 -0
  57. package/packages/vue/src/components/SelectContent.vue +38 -0
  58. package/packages/vue/src/components/SelectItem.vue +43 -0
  59. package/packages/vue/src/components/SelectRenderer.vue +30 -0
  60. package/packages/vue/src/components/SelectTrigger.vue +27 -0
  61. package/packages/vue/src/components/Textarea.vue +19 -0
  62. package/packages/vue/src/components/TextareaRenderer.vue +18 -0
  63. package/packages/vue/src/components/index.ts +24 -0
  64. package/packages/vue/src/fieldComponentMap.ts +34 -0
  65. package/packages/vue/src/index.ts +2 -0
  66. package/packages/vue/src/utils.ts +6 -0
  67. package/packages/vue/tailwind.config.mjs +10 -0
  68. package/packages/vue/test/FormFieldRenderer.test.ts +122 -0
  69. package/packages/core/src/index.test.ts +0 -37
  70. /package/packages/react/{src → test}/DynamicForm.test.tsx +0 -0
  71. /package/packages/vue/{src → test}/DynamicForm.test.ts +0 -0
@@ -1,12 +1,77 @@
1
- import React from 'react';
1
+ import * as React from 'react';
2
+ import React__default from 'react';
2
3
  import { FormSchema, FormField } from 'pdyform/core';
4
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
5
+ import * as class_variance_authority_types from 'class-variance-authority/types';
6
+ import * as LabelPrimitive from '@radix-ui/react-label';
7
+ import { VariantProps } from 'class-variance-authority';
8
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
9
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
10
 
4
11
  interface DynamicFormProps {
5
12
  schema: FormSchema;
6
13
  onSubmit: (values: Record<string, any>) => void;
7
14
  className?: string;
8
15
  }
9
- declare const DynamicForm: React.FC<DynamicFormProps>;
16
+ declare const DynamicForm: React__default.FC<DynamicFormProps>;
17
+
18
+ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
19
+ }
20
+ declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
21
+
22
+ interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
23
+ }
24
+ declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
25
+
26
+ declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
27
+
28
+ declare const RadioGroup: React.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
29
+ declare const RadioGroupItem: React.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
30
+
31
+ declare const Select: React.FC<SelectPrimitive.SelectProps>;
32
+ declare const SelectGroup: React.ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & React.RefAttributes<HTMLDivElement>>;
33
+ declare const SelectValue: React.ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
34
+ declare const SelectTrigger: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
35
+ declare const SelectContent: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
36
+ declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
37
+
38
+ declare const Label: React.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React.RefAttributes<HTMLLabelElement>, "ref"> & VariantProps<(props?: class_variance_authority_types.ClassProp | undefined) => string> & React.RefAttributes<HTMLLabelElement>>;
39
+
40
+ /** All props passed into each individual field renderer component */
41
+ interface FieldRenderContext {
42
+ field: FormField;
43
+ value: any;
44
+ onChange: (value: any) => void;
45
+ onBlur?: () => void;
46
+ fieldId: string;
47
+ }
48
+ /** A React component that renders a specific field type */
49
+ type FieldRenderer = React__default.ComponentType<FieldRenderContext>;
50
+ /** Map from field `type` string to its renderer component */
51
+ type FieldComponentMap = Record<string, FieldRenderer>;
52
+
53
+ declare const InputRenderer: React__default.FC<FieldRenderContext>;
54
+
55
+ declare const TextareaRenderer: React__default.FC<FieldRenderContext>;
56
+
57
+ declare const SelectRenderer: React__default.FC<FieldRenderContext>;
58
+
59
+ declare const CheckboxRenderer: React__default.FC<FieldRenderContext>;
60
+
61
+ declare const RadioRenderer: React__default.FC<FieldRenderContext>;
62
+
63
+ /**
64
+ * The default built-in component map.
65
+ * Import and spread this to extend or override individual field types:
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * import { defaultComponentMap } from 'pdyform-react';
70
+ * const myMap = { ...defaultComponentMap, text: MyInput, rating: StarRating };
71
+ * <FormFieldRenderer componentMap={myMap} ... />
72
+ * ```
73
+ */
74
+ declare const defaultComponentMap: FieldComponentMap;
10
75
 
11
76
  interface FormFieldRendererProps {
12
77
  field: FormField;
@@ -14,7 +79,18 @@ interface FormFieldRendererProps {
14
79
  onChange: (value: any) => void;
15
80
  onBlur?: () => void;
16
81
  error?: string;
82
+ /**
83
+ * Custom component map merged with the default map — external entries win.
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * import { defaultComponentMap } from 'pdyform-react';
88
+ * const myMap = { ...defaultComponentMap, text: MyInput, rating: StarRating };
89
+ * <FormFieldRenderer componentMap={myMap} ... />
90
+ * ```
91
+ */
92
+ componentMap?: FieldComponentMap;
17
93
  }
18
- declare const FormFieldRenderer: React.FC<FormFieldRendererProps>;
94
+ declare const FormFieldRenderer: React__default.FC<FormFieldRendererProps>;
19
95
 
20
- export { DynamicForm, FormFieldRenderer };
96
+ export { Checkbox, CheckboxRenderer, DynamicForm, type FieldComponentMap, type FieldRenderContext, type FieldRenderer, FormFieldRenderer, type FormFieldRendererProps, Input, InputRenderer, Label, RadioGroup, RadioGroupItem, RadioRenderer, Select, SelectContent, SelectGroup, SelectItem, SelectRenderer, SelectTrigger, SelectValue, Textarea, TextareaRenderer, defaultComponentMap };
@@ -2,119 +2,337 @@
2
2
  import { useState } from "react";
3
3
  import { validateField, getDefaultValues } from "pdyform/core";
4
4
 
5
- // src/FormFieldRenderer.tsx
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
- var FormFieldRenderer = ({ field, value, onChange, onBlur, error }) => {
8
- const { type, label, placeholder, options, description, disabled, name } = field;
9
- const fieldId = `field-${name}`;
10
- const baseInputClasses = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50";
11
- const renderInput = () => {
12
- switch (type) {
13
- case "textarea":
14
- return /* @__PURE__ */ jsx(
15
- "textarea",
16
- {
17
- id: fieldId,
18
- className: `${baseInputClasses} min-h-[80px]`,
19
- placeholder,
20
- value: value || "",
21
- onChange: (e) => onChange(e.target.value),
22
- onBlur,
23
- disabled,
24
- name
25
- }
26
- );
27
- case "select":
28
- return /* @__PURE__ */ jsxs(
29
- "select",
30
- {
31
- id: fieldId,
32
- className: baseInputClasses,
33
- value: value || "",
34
- onChange: (e) => onChange(e.target.value),
35
- onBlur,
36
- disabled,
37
- name,
38
- children: [
39
- /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder || "Select an option" }),
40
- options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
41
- ]
42
- }
43
- );
44
- case "checkbox":
45
- return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-4", children: options?.map((opt) => /* @__PURE__ */ jsxs("label", { className: "flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", children: [
46
- /* @__PURE__ */ jsx(
47
- "input",
48
- {
49
- type: "checkbox",
50
- className: "h-4 w-4 rounded border-primary text-primary focus:ring-primary",
51
- checked: Array.isArray(value) && value.includes(opt.value),
52
- onChange: (e) => {
53
- const newValue = Array.isArray(value) ? [...value] : [];
54
- if (e.target.checked) {
55
- newValue.push(opt.value);
56
- } else {
57
- const index = newValue.indexOf(opt.value);
58
- if (index > -1) newValue.splice(index, 1);
59
- }
60
- onChange(newValue);
61
- },
62
- onBlur,
63
- disabled
64
- }
65
- ),
66
- /* @__PURE__ */ jsx("span", { children: opt.label })
67
- ] }, opt.value)) });
68
- case "radio":
69
- return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-4", children: options?.map((opt) => /* @__PURE__ */ jsxs("label", { className: "flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", children: [
70
- /* @__PURE__ */ jsx(
71
- "input",
72
- {
73
- type: "radio",
74
- className: "h-4 w-4 border-primary text-primary focus:ring-primary",
75
- name: field.name,
76
- checked: value === opt.value,
77
- onChange: () => onChange(opt.value),
78
- onBlur,
79
- disabled
80
- }
81
- ),
82
- /* @__PURE__ */ jsx("span", { children: opt.label })
83
- ] }, opt.value)) });
84
- default:
85
- return /* @__PURE__ */ jsx(
86
- "input",
87
- {
88
- id: fieldId,
89
- type,
90
- className: baseInputClasses,
91
- placeholder,
92
- value: value || "",
93
- onChange: (e) => onChange(e.target.value),
94
- onBlur,
95
- disabled,
96
- name
97
- }
98
- );
5
+ // src/components/Input.tsx
6
+ import * as React from "react";
7
+
8
+ // src/utils.ts
9
+ import { clsx } from "clsx";
10
+ import { twMerge } from "tailwind-merge";
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+
15
+ // src/components/Input.tsx
16
+ import { jsx } from "react/jsx-runtime";
17
+ var Input = React.forwardRef(
18
+ ({ className, type, ...props }, ref) => {
19
+ return /* @__PURE__ */ jsx(
20
+ "input",
21
+ {
22
+ type,
23
+ className: cn(
24
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
25
+ className
26
+ ),
27
+ ref,
28
+ ...props
29
+ }
30
+ );
31
+ }
32
+ );
33
+ Input.displayName = "Input";
34
+
35
+ // src/components/Textarea.tsx
36
+ import * as React2 from "react";
37
+ import { jsx as jsx2 } from "react/jsx-runtime";
38
+ var Textarea = React2.forwardRef(
39
+ ({ className, ...props }, ref) => {
40
+ return /* @__PURE__ */ jsx2(
41
+ "textarea",
42
+ {
43
+ className: cn(
44
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
45
+ className
46
+ ),
47
+ ref,
48
+ ...props
49
+ }
50
+ );
51
+ }
52
+ );
53
+ Textarea.displayName = "Textarea";
54
+
55
+ // src/components/Checkbox.tsx
56
+ import * as React3 from "react";
57
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
58
+ import { Check } from "lucide-react";
59
+ import { jsx as jsx3 } from "react/jsx-runtime";
60
+ var Checkbox = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
61
+ CheckboxPrimitive.Root,
62
+ {
63
+ ref,
64
+ className: cn(
65
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
66
+ className
67
+ ),
68
+ ...props,
69
+ children: /* @__PURE__ */ jsx3(
70
+ CheckboxPrimitive.Indicator,
71
+ {
72
+ className: cn("flex items-center justify-center text-current"),
73
+ children: /* @__PURE__ */ jsx3(Check, { className: "h-4 w-4" })
74
+ }
75
+ )
76
+ }
77
+ ));
78
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
79
+
80
+ // src/components/RadioGroup.tsx
81
+ import * as React4 from "react";
82
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
83
+ import { Circle } from "lucide-react";
84
+ import { jsx as jsx4 } from "react/jsx-runtime";
85
+ var RadioGroup = React4.forwardRef(({ className, ...props }, ref) => {
86
+ return /* @__PURE__ */ jsx4(
87
+ RadioGroupPrimitive.Root,
88
+ {
89
+ className: cn("grid gap-2", className),
90
+ ...props,
91
+ ref
99
92
  }
100
- };
101
- return /* @__PURE__ */ jsxs("div", { className: `space-y-2 ${field.className || ""}`, children: [
102
- label && /* @__PURE__ */ jsx(
103
- "label",
93
+ );
94
+ });
95
+ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
96
+ var RadioGroupItem = React4.forwardRef(({ className, ...props }, ref) => {
97
+ return /* @__PURE__ */ jsx4(
98
+ RadioGroupPrimitive.Item,
99
+ {
100
+ ref,
101
+ className: cn(
102
+ "aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
103
+ className
104
+ ),
105
+ ...props,
106
+ children: /* @__PURE__ */ jsx4(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx4(Circle, { className: "h-2.5 w-2.5 fill-current text-current" }) })
107
+ }
108
+ );
109
+ });
110
+ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
111
+
112
+ // src/components/Select.tsx
113
+ import * as React5 from "react";
114
+ import * as SelectPrimitive from "@radix-ui/react-select";
115
+ import { Check as Check2, ChevronDown } from "lucide-react";
116
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
117
+ var Select = SelectPrimitive.Root;
118
+ var SelectGroup = SelectPrimitive.Group;
119
+ var SelectValue = SelectPrimitive.Value;
120
+ var SelectTrigger = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
121
+ SelectPrimitive.Trigger,
122
+ {
123
+ ref,
124
+ className: cn(
125
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
126
+ className
127
+ ),
128
+ ...props,
129
+ children: [
130
+ children,
131
+ /* @__PURE__ */ jsx5(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx5(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
132
+ ]
133
+ }
134
+ ));
135
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
136
+ var SelectContent = React5.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx5(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx5(
137
+ SelectPrimitive.Content,
138
+ {
139
+ ref,
140
+ className: cn(
141
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
142
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
143
+ className
144
+ ),
145
+ position,
146
+ ...props,
147
+ children: /* @__PURE__ */ jsx5(
148
+ SelectPrimitive.Viewport,
104
149
  {
105
- htmlFor: fieldId,
106
- className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
107
- children: label
150
+ className: cn(
151
+ "p-1",
152
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
153
+ ),
154
+ children
108
155
  }
156
+ )
157
+ }
158
+ ) }));
159
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
160
+ var SelectItem = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
161
+ SelectPrimitive.Item,
162
+ {
163
+ ref,
164
+ className: cn(
165
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
166
+ className
109
167
  ),
110
- renderInput(),
111
- description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description }),
112
- error && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive", children: error })
168
+ ...props,
169
+ children: [
170
+ /* @__PURE__ */ jsx5("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx5(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx5(Check2, { className: "h-4 w-4" }) }) }),
171
+ /* @__PURE__ */ jsx5(SelectPrimitive.ItemText, { children })
172
+ ]
173
+ }
174
+ ));
175
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
176
+
177
+ // src/components/Label.tsx
178
+ import * as React6 from "react";
179
+ import * as LabelPrimitive from "@radix-ui/react-label";
180
+ import { cva } from "class-variance-authority";
181
+ import { jsx as jsx6 } from "react/jsx-runtime";
182
+ var labelVariants = cva(
183
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
184
+ );
185
+ var Label = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
186
+ LabelPrimitive.Root,
187
+ {
188
+ ref,
189
+ className: cn(labelVariants(), className),
190
+ ...props
191
+ }
192
+ ));
193
+ Label.displayName = LabelPrimitive.Root.displayName;
194
+
195
+ // src/components/InputRenderer.tsx
196
+ import { jsx as jsx7 } from "react/jsx-runtime";
197
+ var InputRenderer = ({ field, value, onChange, onBlur, fieldId }) => /* @__PURE__ */ jsx7(
198
+ Input,
199
+ {
200
+ id: fieldId,
201
+ type: field.type,
202
+ placeholder: field.placeholder,
203
+ value: value ?? "",
204
+ onChange: (e) => onChange(e.target.value),
205
+ onBlur,
206
+ disabled: field.disabled,
207
+ name: field.name
208
+ }
209
+ );
210
+ var InputRenderer_default = InputRenderer;
211
+
212
+ // src/components/TextareaRenderer.tsx
213
+ import { jsx as jsx8 } from "react/jsx-runtime";
214
+ var TextareaRenderer = ({ field, value, onChange, onBlur, fieldId }) => /* @__PURE__ */ jsx8(
215
+ Textarea,
216
+ {
217
+ id: fieldId,
218
+ placeholder: field.placeholder,
219
+ value: value ?? "",
220
+ onChange: (e) => onChange(e.target.value),
221
+ onBlur,
222
+ disabled: field.disabled,
223
+ name: field.name
224
+ }
225
+ );
226
+ var TextareaRenderer_default = TextareaRenderer;
227
+
228
+ // src/components/SelectRenderer.tsx
229
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
230
+ var SelectRenderer = ({ field, value, onChange, onBlur, fieldId }) => /* @__PURE__ */ jsxs2(
231
+ Select,
232
+ {
233
+ value: value != null ? String(value) : "",
234
+ onValueChange: onChange,
235
+ disabled: field.disabled,
236
+ name: field.name,
237
+ children: [
238
+ /* @__PURE__ */ jsx9(SelectTrigger, { id: fieldId, onBlur, children: /* @__PURE__ */ jsx9(SelectValue, { placeholder: field.placeholder || "Select an option" }) }),
239
+ /* @__PURE__ */ jsx9(SelectContent, { children: /* @__PURE__ */ jsx9(SelectGroup, { children: field.options?.map((opt) => /* @__PURE__ */ jsx9(SelectItem, { value: String(opt.value), children: opt.label }, opt.value)) }) })
240
+ ]
241
+ }
242
+ );
243
+ var SelectRenderer_default = SelectRenderer;
244
+
245
+ // src/components/CheckboxRenderer.tsx
246
+ import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
247
+ var CheckboxRenderer = ({ field, value, onChange, onBlur }) => /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-4", children: field.options?.map((opt) => {
248
+ const checked = Array.isArray(value) && value.includes(opt.value);
249
+ return /* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
250
+ /* @__PURE__ */ jsx10(
251
+ Checkbox,
252
+ {
253
+ id: `checkbox-${field.name}-${opt.value}`,
254
+ checked,
255
+ disabled: field.disabled,
256
+ onCheckedChange: (c) => {
257
+ const next = Array.isArray(value) ? [...value] : [];
258
+ if (c) {
259
+ next.push(opt.value);
260
+ } else {
261
+ const idx = next.indexOf(opt.value);
262
+ if (idx > -1) next.splice(idx, 1);
263
+ }
264
+ onChange(next);
265
+ },
266
+ onBlur
267
+ }
268
+ ),
269
+ /* @__PURE__ */ jsx10(Label, { htmlFor: `checkbox-${field.name}-${opt.value}`, className: "font-normal", children: opt.label })
270
+ ] }, opt.value);
271
+ }) });
272
+ var CheckboxRenderer_default = CheckboxRenderer;
273
+
274
+ // src/components/RadioRenderer.tsx
275
+ import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
276
+ var RadioRenderer = ({ field, value, onChange, onBlur }) => /* @__PURE__ */ jsx11(
277
+ RadioGroup,
278
+ {
279
+ value: value != null ? String(value) : "",
280
+ onValueChange: onChange,
281
+ disabled: field.disabled,
282
+ name: field.name,
283
+ className: "flex flex-wrap gap-4",
284
+ children: field.options?.map((opt) => /* @__PURE__ */ jsxs4("div", { className: "flex items-center space-x-2", children: [
285
+ /* @__PURE__ */ jsx11(
286
+ RadioGroupItem,
287
+ {
288
+ value: String(opt.value),
289
+ id: `radio-${field.name}-${opt.value}`,
290
+ onBlur
291
+ }
292
+ ),
293
+ /* @__PURE__ */ jsx11(Label, { htmlFor: `radio-${field.name}-${opt.value}`, className: "font-normal", children: opt.label })
294
+ ] }, opt.value))
295
+ }
296
+ );
297
+ var RadioRenderer_default = RadioRenderer;
298
+
299
+ // src/components/index.ts
300
+ var defaultComponentMap = {
301
+ text: InputRenderer_default,
302
+ number: InputRenderer_default,
303
+ password: InputRenderer_default,
304
+ email: InputRenderer_default,
305
+ date: InputRenderer_default,
306
+ textarea: TextareaRenderer_default,
307
+ select: SelectRenderer_default,
308
+ checkbox: CheckboxRenderer_default,
309
+ radio: RadioRenderer_default
310
+ };
311
+
312
+ // src/FormFieldRenderer.tsx
313
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
314
+ var FormFieldRenderer = ({
315
+ field,
316
+ value,
317
+ onChange,
318
+ onBlur,
319
+ error,
320
+ componentMap
321
+ }) => {
322
+ const { label, description, name, type } = field;
323
+ const fieldId = `field-${name}`;
324
+ const resolvedMap = componentMap ? { ...defaultComponentMap, ...componentMap } : defaultComponentMap;
325
+ const FieldComponent = resolvedMap[type] ?? InputRenderer_default;
326
+ return /* @__PURE__ */ jsxs5("div", { className: `space-y-2 ${field.className || ""}`, children: [
327
+ label && /* @__PURE__ */ jsx12(Label, { htmlFor: fieldId, children: label }),
328
+ /* @__PURE__ */ jsx12(FieldComponent, { field, value, onChange, onBlur, fieldId }),
329
+ description && /* @__PURE__ */ jsx12("p", { className: "text-[0.8rem] text-muted-foreground", children: description }),
330
+ error && /* @__PURE__ */ jsx12("p", { className: "text-[0.8rem] font-medium text-destructive", children: error })
113
331
  ] });
114
332
  };
115
333
 
116
334
  // src/DynamicForm.tsx
117
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
335
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
118
336
  var DynamicForm = ({ schema, onSubmit, className }) => {
119
337
  const [values, setValues] = useState(getDefaultValues(schema.fields));
120
338
  const [errors, setErrors] = useState({});
@@ -158,10 +376,10 @@ var DynamicForm = ({ schema, onSubmit, className }) => {
158
376
  }
159
377
  setIsSubmitting(false);
160
378
  };
161
- return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: `space-y-6 ${className || ""}`, children: [
162
- schema.title && /* @__PURE__ */ jsx2("h2", { className: "text-2xl font-bold tracking-tight", children: schema.title }),
163
- schema.description && /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground", children: schema.description }),
164
- /* @__PURE__ */ jsx2("div", { className: "space-y-4", children: schema.fields.map((field) => !field.hidden && /* @__PURE__ */ jsx2(
379
+ return /* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: `space-y-6 ${className || ""}`, children: [
380
+ schema.title && /* @__PURE__ */ jsx13("h2", { className: "text-2xl font-bold tracking-tight", children: schema.title }),
381
+ schema.description && /* @__PURE__ */ jsx13("p", { className: "text-muted-foreground", children: schema.description }),
382
+ /* @__PURE__ */ jsx13("div", { className: "space-y-4", children: schema.fields.map((field) => !field.hidden && /* @__PURE__ */ jsx13(
165
383
  FormFieldRenderer,
166
384
  {
167
385
  field,
@@ -172,7 +390,7 @@ var DynamicForm = ({ schema, onSubmit, className }) => {
172
390
  },
173
391
  field.name
174
392
  )) }),
175
- /* @__PURE__ */ jsx2(
393
+ /* @__PURE__ */ jsx13(
176
394
  "button",
177
395
  {
178
396
  type: "submit",
@@ -184,6 +402,24 @@ var DynamicForm = ({ schema, onSubmit, className }) => {
184
402
  ] });
185
403
  };
186
404
  export {
405
+ Checkbox,
406
+ CheckboxRenderer_default as CheckboxRenderer,
187
407
  DynamicForm,
188
- FormFieldRenderer
408
+ FormFieldRenderer,
409
+ Input,
410
+ InputRenderer_default as InputRenderer,
411
+ Label,
412
+ RadioGroup,
413
+ RadioGroupItem,
414
+ RadioRenderer_default as RadioRenderer,
415
+ Select,
416
+ SelectContent,
417
+ SelectGroup,
418
+ SelectItem,
419
+ SelectRenderer_default as SelectRenderer,
420
+ SelectTrigger,
421
+ SelectValue,
422
+ Textarea,
423
+ TextareaRenderer_default as TextareaRenderer,
424
+ defaultComponentMap
189
425
  };
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
+ esac
7
+
8
+ if [ -z "$NODE_PATH" ]; then
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
+ else
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/jiti@1.21.7/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
+ fi
13
+ if [ -x "$basedir/node" ]; then
14
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/jiti.js" "$@"
15
+ else
16
+ exec node "$basedir/../../../../node_modules/.pnpm/jiti@1.21.7/node_modules/jiti/bin/jiti.js" "$@"
17
+ fi
@@ -6,9 +6,9 @@ case `uname` in
6
6
  esac
7
7
 
8
8
  if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
10
  else
11
- export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
12
  fi
13
13
  if [ -x "$basedir/node" ]; then
14
14
  exec "$basedir/node" "$basedir/../tsup/dist/cli-default.js" "$@"
@@ -6,9 +6,9 @@ case `uname` in
6
6
  esac
7
7
 
8
8
  if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
9
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules"
10
10
  else
11
- export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
11
+ export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.57.6_@types+node@20.19.35__jiti@1.21.7_postcss@8.5.8_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
12
12
  fi
13
13
  if [ -x "$basedir/node" ]; then
14
14
  exec "$basedir/node" "$basedir/../tsup/dist/cli-node.js" "$@"
@@ -1 +1 @@
1
- {"version":"1.6.1","results":[[":src/DynamicForm.test.tsx",{"duration":26,"failed":false}]]}
1
+ {"version":"1.6.1","results":[[":test/FormFieldRenderer.test.tsx",{"duration":123,"failed":false}],[":test/DynamicForm.test.tsx",{"duration":29,"failed":false}]]}