Skip to content

Commit c678488

Browse files
feat: complete medusa forms extraction and migration
- Migrated core repository structure from @lambdacurry/forms - Copied packages/medusa-forms with all controlled components - Migrated apps/docs with Storybook documentation for medusa forms - Copied development setup (.cursor, .vscode, configuration files) - Updated package names and references to @lambdacurry/medusa-forms - Removed remix-hook-form dependencies and stories (out of scope) - Added missing zod dependency for form validation - Updated README.md to reflect new repository purpose - Verified Storybook builds and runs successfully Components migrated: - ControlledInput, ControlledTextArea, ControlledSelect - ControlledCheckbox, ControlledDatePicker, ControlledCurrencyInput - Supporting UI components and field wrappers All medusa form components are now functional in the new repository.
0 parents  commit c678488

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+21292
-0
lines changed

.changeset/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changesets
2+
3+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4+
with multi-package repos, or single-package repos to help you version and publish your code. You can
5+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6+
7+
We have a quick list of common questions to get you started engaging with this project in
8+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

.changeset/config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": ["@lambdacurry/forms-docs"]
11+
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
---
2+
type: Always
3+
description: Rules for form component integration patterns in the lambda-curry/forms repository (applies to Remix Hook Form components)
4+
---
5+
6+
You are an expert in React Hook Form, Remix Hook Form, Zod validation, and form component architecture for the lambda-curry/forms monorepo.
7+
8+
# Form Component Integration Patterns (Remix Hook Form)
9+
10+
**Note: These patterns apply to Remix Hook Form components in `packages/components/`. For Medusa Forms components using react-hook-form + @medusajs/ui, see the medusa-forms-patterns.mdc rules.**
11+
12+
## Core Principles
13+
- All form components must integrate seamlessly with Remix Hook Form
14+
- Use Zod schemas for validation with proper TypeScript inference
15+
- Follow the wrapper pattern for consistent component composition
16+
- Maintain separation between UI components and form-aware components
17+
- Ensure proper error handling and validation feedback
18+
19+
## Required Imports for Form Components
20+
```typescript
21+
// Remix Hook Form integration
22+
import { useRemixFormContext } from 'remix-hook-form';
23+
import { zodResolver } from '@hookform/resolvers/zod';
24+
import { z } from 'zod';
25+
26+
// Form components
27+
import { FormControl, FormDescription, FormLabel, FormMessage } from './form';
28+
29+
// Base UI components
30+
import { ComponentName as BaseComponentName } from '../ui/component-name';
31+
```
32+
33+
## Form Schema Pattern
34+
Always define Zod schemas with proper error messages:
35+
```typescript
36+
const formSchema = z.object({
37+
fieldName: z.string().min(1, 'Field is required'),
38+
email: z.string().email('Invalid email address'),
39+
price: z.string().min(1, 'Price is required'),
40+
});
41+
42+
type FormData = z.infer<typeof formSchema>;
43+
```
44+
45+
## Wrapper Component Pattern
46+
Follow this pattern for all form-aware components:
47+
```typescript
48+
export type ComponentNameProps = Omit<BaseComponentNameProps, 'control'>;
49+
50+
export function ComponentName(props: ComponentNameProps) {
51+
const { control } = useRemixFormContext();
52+
53+
// Merge provided components with default form components
54+
const defaultComponents = {
55+
FormControl,
56+
FormLabel,
57+
FormDescription,
58+
FormMessage,
59+
};
60+
61+
const components = {
62+
...defaultComponents,
63+
...props.components,
64+
};
65+
66+
return <BaseComponentName control={control} components={components} {...props} />;
67+
}
68+
```
69+
70+
## Component Composition Pattern
71+
For UI components that accept form integration:
72+
```typescript
73+
export interface ComponentNameProps extends Omit<InputProps, 'prefix' | 'suffix'> {
74+
control?: Control<FieldValues>;
75+
name: FieldPath<FieldValues>;
76+
label?: string;
77+
description?: string;
78+
components?: Partial<FieldComponents> & {
79+
Input?: React.ComponentType<InputProps>;
80+
};
81+
className?: string;
82+
}
83+
84+
export const ComponentName = ({
85+
control,
86+
name,
87+
label,
88+
description,
89+
className,
90+
components,
91+
...props
92+
}: ComponentNameProps) => {
93+
const InputComponent = components?.Input || DefaultInput;
94+
95+
return (
96+
<FormField
97+
control={control}
98+
name={name}
99+
render={({ field, fieldState }) => (
100+
<FormItem className={className}>
101+
{label && <FormLabel Component={components?.FormLabel}>{label}</FormLabel>}
102+
<FormControl Component={components?.FormControl}>
103+
<InputComponent {...field} {...props} />
104+
</FormControl>
105+
{description && <FormDescription Component={components?.FormDescription}>{description}</FormDescription>}
106+
{fieldState.error && (
107+
<FormMessage Component={components?.FormMessage}>{fieldState.error.message}</FormMessage>
108+
)}
109+
</FormItem>
110+
)}
111+
/>
112+
);
113+
};
114+
```
115+
116+
## Form Setup Pattern
117+
Use this pattern for form initialization:
118+
```typescript
119+
const ControlledComponentExample = () => {
120+
const fetcher = useFetcher<{ message: string }>();
121+
const methods = useRemixForm<FormData>({
122+
resolver: zodResolver(formSchema),
123+
defaultValues: {
124+
// Provide sensible defaults
125+
},
126+
fetcher,
127+
submitConfig: { action: '/', method: 'post' },
128+
});
129+
130+
return (
131+
<RemixFormProvider {...methods}>
132+
<fetcher.Form onSubmit={methods.handleSubmit}>
133+
{/* Form components */}
134+
</fetcher.Form>
135+
</RemixFormProvider>
136+
);
137+
};
138+
```
139+
140+
## Validation Patterns
141+
142+
### Client-Side Validation
143+
- Use Zod schemas for all form validation
144+
- Provide clear, user-friendly error messages
145+
- Validate on blur and submit, not on every keystroke
146+
147+
### Server-Side Validation
148+
```typescript
149+
export const action = async ({ request }: ActionFunctionArgs) => {
150+
const { data, errors } = await getValidatedFormData<FormData>(
151+
request,
152+
zodResolver(formSchema)
153+
);
154+
155+
if (errors) return { errors };
156+
157+
// Additional server-side validation
158+
if (data.username === 'taken') {
159+
return {
160+
errors: {
161+
username: { message: 'Username is already taken' }
162+
}
163+
};
164+
}
165+
166+
return { message: 'Success!' };
167+
};
168+
```
169+
170+
## Error Handling Best Practices
171+
- Always display field-level errors using FormMessage
172+
- Handle both client-side and server-side validation errors
173+
- Provide loading states during form submission
174+
- Clear errors appropriately when fields are corrected
175+
176+
## Component Naming Conventions
177+
- Form-aware components: `ComponentName` (e.g., `TextField`, `Checkbox`)
178+
- Base UI components: `ComponentName` in ui/ directory
179+
- Props interfaces: `ComponentNameProps`
180+
- Form schemas: `formSchema` or `componentNameSchema`
181+
182+
## File Organization
183+
```
184+
packages/components/src/
185+
├── remix-hook-form/ # Form-aware wrapper components
186+
│ ├── text-field.tsx
187+
│ ├── checkbox.tsx
188+
│ └── index.ts
189+
└── ui/ # Base UI components
190+
├── text-field.tsx
191+
├── checkbox.tsx
192+
└── index.ts
193+
```
194+
195+
## Required Exports
196+
Always export both the component and its props type:
197+
```typescript
198+
export { ComponentName };
199+
export type { ComponentNameProps };
200+
```
201+
202+
## Performance Considerations
203+
- Use React.memo for expensive form components
204+
- Avoid unnecessary re-renders by properly structuring form state
205+
- Consider field-level subscriptions for large forms
206+
207+
## Accessibility Requirements
208+
- All form fields must have proper labels
209+
- Use ARIA attributes for complex form interactions
210+
- Ensure keyboard navigation works correctly
211+
- Provide clear error announcements for screen readers
212+
213+
## Testing Integration
214+
- Form components should work with the existing Storybook testing patterns
215+
- Test both valid and invalid form states
216+
- Verify server-side validation integration
217+
- Test component composition and customization
218+
219+
Remember: Form components are the core of this library. Every form component should be intuitive, accessible, and integrate seamlessly with the Remix Hook Form + Zod validation pattern.

0 commit comments

Comments
 (0)