Skip to content

Commit dc95b65

Browse files
feat: preserve field wrapper structure with registry dependencies
- Revert controlled components to use internal UI wrappers - Add all UI wrapper components to registry as dependencies - Implement proper dependency chain: controlled → ui → field-wrapper → [error, label] - Generate registry files for all UI components (field-wrapper, input, select, etc.) - Update registry.json with registryDependencies for automatic component copying - Preserve valuable field wrapper architecture with labels and error handling - Components now maintain superior UX while being shadcn-compatible - Update documentation to explain dependency management and architecture
1 parent 63a0ed6 commit dc95b65

23 files changed

Lines changed: 662 additions & 640 deletions

packages/medusa-forms/REGISTRY.md

Lines changed: 175 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,73 @@
11
# Medusa Forms shadcn/ui Registry
22

3-
This package provides a custom shadcn/ui registry for medusa-forms components, allowing developers to install them using the native shadcn CLI.
3+
This package provides a custom shadcn/ui registry for medusa-forms components, allowing developers to install them using the native shadcn CLI while preserving the valuable field wrapper structure with built-in labels and error handling.
44

55
## Installation
66

7-
You can install individual medusa-forms components using the shadcn CLI:
7+
You can install individual medusa-forms components using the shadcn CLI. The registry automatically handles dependencies, so installing a controlled component will also install the necessary UI wrapper components:
88

99
```bash
10-
# Install individual components
10+
# Install controlled components (automatically includes UI dependencies)
1111
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-input.json
1212
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-select.json
1313
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-checkbox.json
1414
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-textarea.json
1515
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-datepicker.json
1616
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/controlled-currency-input.json
17+
18+
# Or install UI components individually if needed
19+
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/input.json
20+
npx shadcn@latest add https://raw.githubusercontent.com/lambda-curry/forms/main/packages/medusa-forms/registry/field-wrapper.json
1721
```
1822

23+
## Architecture
24+
25+
### 🏗️ **Preserved Field Wrapper Structure**
26+
27+
The registry maintains the valuable field wrapper architecture that provides superior UX:
28+
29+
- **FieldWrapper**: Handles labels, tooltips, and error display
30+
- **UI Components**: Input, Select, Checkbox, etc. with built-in wrapper integration
31+
- **Controlled Components**: react-hook-form integration with wrapper components
32+
33+
### 📦 **Dependency Management**
34+
35+
The registry automatically handles the dependency chain:
36+
37+
```
38+
ControlledInput
39+
└── Input
40+
└── FieldWrapper
41+
├── FieldError
42+
└── Label
43+
```
44+
45+
When you install `controlled-input`, shadcn automatically copies:
46+
- `ControlledInput.tsx` (main component)
47+
- `Input.tsx` (UI wrapper)
48+
- `FieldWrapper.tsx` (field wrapper logic)
49+
- `Error.tsx` (error display)
50+
- `Label.tsx` (label with tooltip support)
51+
- `types.d.ts` (TypeScript definitions)
52+
1953
## Available Components
2054

21-
### ControlledInput
22-
A controlled input component with react-hook-form integration.
55+
### Controlled Components (with react-hook-form)
2356

57+
#### ControlledInput
2458
```tsx
2559
import { ControlledInput } from '@/components/ui/controlled-input'
2660

2761
<ControlledInput
2862
name="email"
29-
label="Email"
63+
label="Email Address"
3064
placeholder="Enter your email"
65+
labelTooltip="We'll never share your email"
3166
rules={{ required: 'Email is required' }}
3267
/>
3368
```
3469

35-
### ControlledSelect
36-
A controlled select component with react-hook-form integration.
37-
70+
#### ControlledSelect
3871
```tsx
3972
import { ControlledSelect } from '@/components/ui/controlled-select'
4073

@@ -52,22 +85,19 @@ const options = [
5285
/>
5386
```
5487

55-
### ControlledCheckbox
56-
A controlled checkbox component with react-hook-form integration.
57-
88+
#### ControlledCheckbox
5889
```tsx
5990
import { ControlledCheckbox } from '@/components/ui/controlled-checkbox'
6091

6192
<ControlledCheckbox
6293
name="terms"
6394
label="I agree to the terms and conditions"
95+
description="You must agree to continue"
6496
rules={{ required: 'You must agree to the terms' }}
6597
/>
6698
```
6799

68-
### ControlledTextarea
69-
A controlled textarea component with react-hook-form integration.
70-
100+
#### ControlledTextarea
71101
```tsx
72102
import { ControlledTextarea } from '@/components/ui/controlled-textarea'
73103

@@ -80,9 +110,7 @@ import { ControlledTextarea } from '@/components/ui/controlled-textarea'
80110
/>
81111
```
82112

83-
### ControlledDatePicker
84-
A controlled date picker component with react-hook-form integration.
85-
113+
#### ControlledDatePicker
86114
```tsx
87115
import { ControlledDatePicker } from '@/components/ui/controlled-datepicker'
88116

@@ -94,21 +122,48 @@ import { ControlledDatePicker } from '@/components/ui/controlled-datepicker'
94122
/>
95123
```
96124

97-
### ControlledCurrencyInput
98-
A controlled currency input component with react-hook-form integration.
99-
125+
#### ControlledCurrencyInput
100126
```tsx
101127
import { ControlledCurrencyInput } from '@/components/ui/controlled-currency-input'
102128

103129
<ControlledCurrencyInput
104130
name="price"
105131
label="Price"
106-
placeholder="Enter price"
107-
currency="USD"
132+
symbol="$"
133+
code="USD"
108134
rules={{ required: 'Price is required' }}
109135
/>
110136
```
111137

138+
### UI Components (standalone)
139+
140+
#### Input
141+
```tsx
142+
import { Input } from '@/components/ui/input'
143+
144+
<Input
145+
label="Email"
146+
placeholder="Enter email"
147+
labelTooltip="Your email address"
148+
formErrors={errors}
149+
name="email"
150+
/>
151+
```
152+
153+
#### FieldWrapper
154+
```tsx
155+
import { FieldWrapper } from '@/components/ui/field-wrapper'
156+
157+
<FieldWrapper
158+
label="Custom Field"
159+
labelTooltip="Additional information"
160+
formErrors={errors}
161+
name="custom"
162+
>
163+
{(props) => <CustomInput {...props} />}
164+
</FieldWrapper>
165+
```
166+
112167
## Prerequisites
113168

114169
Before using these components, make sure you have:
@@ -120,10 +175,10 @@ Before using these components, make sure you have:
120175

121176
2. **Required dependencies** installed:
122177
```bash
123-
npm install @medusajs/ui react-hook-form @hookform/error-message
178+
npm install @medusajs/ui react-hook-form
124179
```
125180

126-
3. **FormProvider setup** in your application:
181+
3. **FormProvider setup** for controlled components:
127182
```tsx
128183
import { useForm, FormProvider } from 'react-hook-form'
129184

@@ -142,12 +197,12 @@ Before using these components, make sure you have:
142197

143198
## Benefits
144199

200+
**Preserved Architecture**: Maintains valuable field wrapper structure
201+
**Built-in Labels & Errors**: Superior UX with integrated label and error handling
202+
**Automatic Dependencies**: shadcn handles all component dependencies
145203
**No Custom CLI**: Leverage existing shadcn infrastructure
204+
**TypeScript Support**: Full TypeScript compatibility
146205
**Familiar UX**: Developers already know `npx shadcn@latest add`
147-
**Auto Dependencies**: shadcn handles npm package installation
148-
**TypeScript Support**: Built-in TypeScript compatibility
149-
**Zero Maintenance**: No CLI package to maintain
150-
**Instant Adoption**: Works with existing shadcn projects
151206
**v0 Compatible**: Components work with v0.dev
152207
**Single Source of Truth**: Components serve both shadcn and npm package usage
153208

@@ -157,42 +212,102 @@ Before using these components, make sure you have:
157212
packages/medusa-forms/
158213
├── registry.json # Main registry configuration
159214
├── registry/ # Component registry files
160-
│ ├── controlled-input.json
161-
│ ├── controlled-select.json
162-
│ ├── controlled-checkbox.json
163-
│ ├── controlled-textarea.json
164-
│ ├── controlled-datepicker.json
165-
│ └── controlled-currency-input.json
166-
└── src/controlled/ # Unified component source files (shadcn-compatible)
167-
├── ControlledInput.tsx
168-
├── ControlledSelect.tsx
169-
├── ControlledCheckbox.tsx
170-
├── ControlledTextArea.tsx
171-
├── ControlledDatePicker.tsx
172-
└── ControlledCurrencyInput.tsx
173-
```
174-
175-
## Unified Approach
176-
177-
The components in `src/controlled/` are now **shadcn-compatible** and serve dual purposes:
178-
179-
- **For shadcn CLI users**: Install via `npx shadcn@latest add [URL]`
180-
- **For npm package users**: Import directly from `@lambdacurry/medusa-forms`
181-
182-
### Key Features:
183-
- **Direct @medusajs/ui usage**: Components use `@medusajs/ui` directly instead of internal wrappers
184-
- **Built-in labels and error handling**: Includes proper labeling and error display with `@hookform/error-message`
185-
- **shadcn patterns**: Follows shadcn/ui conventions for styling and structure
186-
- **Backward compatibility**: Maintains the same API for existing medusa-forms users
215+
│ ├── controlled-*.json # Controlled components
216+
│ ├── field-wrapper.json # Core wrapper component
217+
│ ├── input.json # UI components
218+
│ └── ...
219+
├── src/controlled/ # Controlled component source files
220+
│ ├── ControlledInput.tsx
221+
│ └── ...
222+
└── src/ui/ # UI wrapper components
223+
├── FieldWrapper.tsx # Core field wrapper
224+
├── Input.tsx # Input with wrapper
225+
├── Error.tsx # Error display
226+
├── Label.tsx # Label with tooltip
227+
├── types.d.ts # TypeScript definitions
228+
└── ...
229+
```
230+
231+
## Dependency Chain
232+
233+
The registry manages a complete dependency chain:
234+
235+
```
236+
Controlled Components
237+
├── ControlledInput → Input → FieldWrapper → [FieldError, Label]
238+
├── ControlledSelect → Select → FieldWrapper → [FieldError, Label]
239+
├── ControlledCheckbox → FieldCheckbox → [FieldWrapper, Label] → [FieldError]
240+
├── ControlledTextarea → TextArea → FieldWrapper → [FieldError, Label]
241+
├── ControlledDatePicker → DatePicker → FieldWrapper → [FieldError, Label]
242+
└── ControlledCurrencyInput → CurrencyInput → FieldWrapper → [FieldError, Label]
243+
244+
Core Components
245+
├── FieldWrapper (requires FieldError, Label, types.d.ts)
246+
├── FieldError (standalone)
247+
└── Label (standalone)
248+
```
249+
250+
## Usage Patterns
251+
252+
### 1. **Form with Validation**
253+
```tsx
254+
import { useForm, FormProvider } from 'react-hook-form'
255+
import { ControlledInput, ControlledSelect } from '@/components/ui'
256+
257+
function ContactForm() {
258+
const methods = useForm()
259+
260+
return (
261+
<FormProvider {...methods}>
262+
<form onSubmit={methods.handleSubmit(onSubmit)}>
263+
<ControlledInput
264+
name="name"
265+
label="Full Name"
266+
rules={{ required: 'Name is required' }}
267+
/>
268+
<ControlledSelect
269+
name="country"
270+
label="Country"
271+
options={countries}
272+
rules={{ required: 'Please select a country' }}
273+
/>
274+
</form>
275+
</FormProvider>
276+
)
277+
}
278+
```
279+
280+
### 2. **Custom Field with Wrapper**
281+
```tsx
282+
import { FieldWrapper } from '@/components/ui/field-wrapper'
283+
284+
function CustomField({ name, label, formErrors }) {
285+
return (
286+
<FieldWrapper
287+
name={name}
288+
label={label}
289+
formErrors={formErrors}
290+
labelTooltip="Custom field tooltip"
291+
>
292+
{(props) => (
293+
<div className="custom-input">
294+
<input {...props} />
295+
</div>
296+
)}
297+
</FieldWrapper>
298+
)
299+
}
300+
```
187301

188302
## Contributing
189303

190304
To add new components to the registry:
191305

192-
1. Create the component in `src/controlled/` following shadcn patterns
193-
2. Add it to the main `registry.json`
194-
3. Generate the individual JSON file in `registry/`
195-
4. Update this documentation
306+
1. Create the UI component in `src/ui/` following the wrapper pattern
307+
2. Create the controlled component in `src/controlled/`
308+
3. Add both to the main `registry.json` with proper dependencies
309+
4. Generate the individual JSON files
310+
5. Update this documentation
196311

197312
## License
198313

0 commit comments

Comments
 (0)