Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d6819ba
Add form input components with field wrapper for Medusa UI
cursoragent May 31, 2025
2f4a280
Resolve merge conflicts: keep React 19 patterns without forwardRef
codegen-sh[bot] May 31, 2025
9d8b33c
Merge pull request #80 from lambda-curry/cursor/update-components-to-…
jaruesink May 31, 2025
c2e0790
refactor: update imports to use type-only imports for React in form c…
jaruesink May 31, 2025
b446142
Initial scaffolding for controlled components stories
codegen-sh[bot] May 31, 2025
4cb0966
feat: Add comprehensive ControlledTextArea Storybook stories
codegen-sh[bot] May 31, 2025
bd9ecb9
feat: add comprehensive form integration examples
codegen-sh[bot] May 31, 2025
d23ebab
feat: Add ControlledTextArea stories (merged from LC-245)
codegen-sh[bot] May 31, 2025
25359e0
feat: Add ControlledCurrencyInput and ControlledDatePicker stories
codegen-sh[bot] May 31, 2025
248f6ae
feat: Add ControlledCheckbox stories (merged from LC-243)
codegen-sh[bot] May 31, 2025
871b81d
feat: Add comprehensive ControlledSelect Storybook stories
codegen-sh[bot] May 31, 2025
eb24bde
fix: Resolve identifier conflicts and import issues in Storybook stories
codegen-sh[bot] May 31, 2025
7f02d10
Merge pull request #83 from lambda-curry/codegen/lc-246-create-comple…
jaruesink May 31, 2025
a00c074
Merge pull request #82 from lambda-curry/codegen/lc-245-create-contro…
jaruesink May 31, 2025
a790cdc
Merge pull request #86 from lambda-curry/codegen/lc-241-create-contro…
jaruesink May 31, 2025
67fe131
Merge pull request #85 from lambda-curry/codegen/lc-240-medusa-forms-…
jaruesink May 31, 2025
0d48c37
feat: Enhance ControlledCurrencyInput and FormIntegrationExamples sto…
jaruesink May 31, 2025
bf5c98b
feat: Refactor form components in FormIntegrationExamples to use Butt…
jaruesink May 31, 2025
cb26e17
Add cursor rules for Medusa Forms components and stories
codegen-sh[bot] May 31, 2025
8fa205b
Update existing cursor rules for Medusa Forms compatibility
codegen-sh[bot] May 31, 2025
2bc8ec3
Merge pull request #87 from lambda-curry/codegen-bot/medusa-cursor-ru…
jaruesink May 31, 2025
47379bc
refactor: Update form stories to enhance usability and consistency
jaruesink Jun 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .cursor/rules/form-component-patterns.mdc
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
---
type: Always
description: Rules for form component integration patterns in the lambda-curry/forms repository
description: Rules for form component integration patterns in the lambda-curry/forms repository (applies to Remix Hook Form components)
---

You are an expert in React Hook Form, Remix Hook Form, Zod validation, and form component architecture for the lambda-curry/forms monorepo.

# Form Component Integration Patterns
# Form Component Integration Patterns (Remix Hook Form)

**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.**

## Core Principles
- All form components must integrate seamlessly with Remix Hook Form
Expand Down Expand Up @@ -215,4 +217,3 @@ export type { ComponentNameProps };
- Test component composition and customization

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.

252 changes: 252 additions & 0 deletions .cursor/rules/medusa-forms-patterns.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
---
type: Auto Attached
description: Rules for Medusa Forms component development patterns using @medusajs/ui and react-hook-form
globs: ["packages/medusa-forms/**/*.{ts,tsx}", "apps/docs/src/medusa-forms/**/*.{ts,tsx}"]
---

You are an expert in React Hook Form, @medusajs/ui components, and Medusa design system integration for the lambda-curry/forms repository.

# Medusa Forms Component Patterns

## Core Architecture Principles
- Medusa Forms use **react-hook-form** directly (not remix-hook-form)
- All UI components are built on **@medusajs/ui** as the base design system
- Follow the **controlled/** and **ui/** directory separation pattern
- Use the **Controller** pattern for form integration
- Maintain **FieldWrapper** consistency for all form fields

## Required Imports for Medusa Forms

### For Controlled Components
```typescript
import {
Controller,
type ControllerProps,
type FieldValues,
type Path,
type RegisterOptions,
useFormContext,
} from 'react-hook-form';
import { ComponentName, type Props as ComponentNameProps } from '../ui/ComponentName';
```

### For UI Components
```typescript
import { ComponentName as MedusaComponentName } from '@medusajs/ui';
import type * as React from 'react';
import { FieldWrapper } from './FieldWrapper';
import type { BasicFieldProps, MedusaComponentNameProps } from './types';
```

## Directory Structure Convention
```
packages/medusa-forms/src/
├── controlled/ # Form-aware wrapper components using Controller
│ ├── ControlledInput.tsx
│ ├── ControlledCheckbox.tsx
│ ├── ControlledSelect.tsx
│ └── index.ts
└── ui/ # Base UI components using @medusajs/ui
├── Input.tsx
├── FieldCheckbox.tsx
├── Select.tsx
├── FieldWrapper.tsx
└── types.d.ts
```

## Controlled Component Pattern
All controlled components must follow this exact pattern:

```typescript
type Props<T extends FieldValues> = ComponentNameProps &
Omit<ControllerProps, 'render'> & {
name: Path<T>;
rules?: Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>;
};

export const ControlledComponentName = <T extends FieldValues>({
name,
rules,
onChange,
...props
}: Props<T>) => {
const {
control,
formState: { errors },
} = useFormContext<T>();

return (
<Controller
control={control}
name={name}
rules={rules as Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>}
render={({ field }) => (
<ComponentName
{...field}
{...props}
formErrors={errors}
onChange={(value) => {
if (onChange) onChange(value);
field.onChange(value);
}}
/>
)}
/>
);
};
```

## UI Component Pattern
All UI components must use FieldWrapper and @medusajs/ui:

```typescript
export type Props = MedusaComponentNameProps &
BasicFieldProps & {
ref?: React.Ref<HTMLInputElement>; // Adjust ref type based on component
};

const Wrapper = FieldWrapper<Props>;

export const ComponentName: React.FC<Props> = ({ ref, ...props }) => (
<Wrapper {...props}>
{(inputProps) => <MedusaComponentName {...inputProps} ref={ref} />}
</Wrapper>
);
```

## FieldWrapper Integration
- **Always** use FieldWrapper for consistent label, error, and styling patterns
- Pass `formErrors` prop to enable automatic error display
- Use `labelClassName`, `wrapperClassName`, `errorClassName` for styling customization

```typescript
<FieldWrapper<ComponentProps>
wrapperClassName={wrapperClassName}
errorClassName={errorClassName}
formErrors={formErrors}
{...props}
>
{(fieldProps) => (
<MedusaComponent {...fieldProps} ref={ref} />
)}
</FieldWrapper>
```

## @medusajs/ui Component Integration

### Input Components
```typescript
import { Input as MedusaInput } from '@medusajs/ui';
// Use with FieldWrapper pattern
```

### Checkbox Components
```typescript
import { Checkbox as MedusaCheckbox } from '@medusajs/ui';
// Special handling for checked state and onCheckedChange
```

### Select Components
```typescript
import { Select as MedusaSelect } from '@medusajs/ui';
// Compound component pattern with Trigger, Content, Item
```

### Currency Input Components
```typescript
import { CurrencyInput as MedusaCurrencyInput } from '@medusajs/ui';
// Special props: symbol, code, currency
```

### Date Picker Components
```typescript
import { DatePicker } from '@medusajs/ui';
// Special props: dateFormat, minDate, maxDate, filterDate
```

## Type Safety Requirements
- Use generic types `<T extends FieldValues>` for all controlled components
- Properly type `Path<T>` for name props
- Extend `BasicFieldProps` for all UI components
- Use proper ref types based on underlying HTML element

## Error Handling Pattern
```typescript
// In controlled components
const {
control,
formState: { errors },
} = useFormContext<T>();

// Pass errors to UI component
<ComponentName
{...field}
{...props}
formErrors={errors}
/>
```

## Validation Integration
- Use `rules` prop for react-hook-form validation
- Support both built-in and custom validation rules
- Ensure error messages are user-friendly and specific

```typescript
<ControlledInput
name="email"
label="Email Address"
rules={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
}}
/>
```

## Accessibility Requirements
- All form fields must have proper labels via FieldWrapper
- Use ARIA attributes provided by @medusajs/ui components
- Ensure keyboard navigation works correctly
- Provide clear error announcements for screen readers

## Component Naming Conventions
- Controlled components: `ControlledComponentName` (e.g., `ControlledInput`, `ControlledCheckbox`)
- UI components: `ComponentName` (e.g., `Input`, `FieldCheckbox`)
- Props interfaces: `ComponentNameProps`
- File names: PascalCase matching component name

## Export Requirements
Always export both the component and its props type:
```typescript
export { ControlledComponentName };
export type { Props as ControlledComponentNameProps };
```

## Performance Considerations
- Use React.memo for expensive form components when needed
- Avoid unnecessary re-renders by properly structuring form state
- Consider field-level subscriptions for large forms

## Testing Integration
- Components should work with existing Storybook patterns
- Test both valid and invalid form states
- Verify @medusajs/ui component integration
- Test component composition and customization

## Common Patterns to Avoid
- **Don't** use remix-hook-form patterns (use react-hook-form directly)
- **Don't** create custom UI components when @medusajs/ui equivalents exist
- **Don't** bypass FieldWrapper for form fields
- **Don't** mix controlled and uncontrolled patterns
- **Don't** forget to handle both onChange and field.onChange in controlled components

## Medusa Design System Compliance
- Follow Medusa UI spacing and sizing conventions
- Use Medusa color tokens and design patterns
- Ensure components work with Medusa themes
- Maintain consistency with Medusa component APIs

Remember: Medusa Forms are specifically designed to integrate with the Medusa ecosystem. Always prioritize @medusajs/ui component usage and follow Medusa design system principles while maintaining the react-hook-form integration patterns.

Loading
Loading