Skip to content

feat: Add shadcn/ui registry for medusa-forms components #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
144 changes: 144 additions & 0 deletions packages/medusa-forms/REGISTRY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Medusa Forms Registry

This package provides a custom shadcn/ui registry that allows developers to install medusa-forms components using the native shadcn CLI.

## Installation

You can install components from this registry using the shadcn CLI:

```bash
npx shadcn@latest add --registry https://raw.githubusercontent.com/lambda-curry/medusa-forms/main/packages/medusa-forms/registry.json input
```

## Registry Maintenance

The registry files are automatically generated from source components using a build script. This ensures the registry stays in sync with the actual component code without manual maintenance.

### Regenerating Registry Files

To regenerate the registry files after making changes to components:

```bash
yarn build:registry
```

This script:
- Scans component source files in `src/ui/` and `src/controlled/`
- Generates registry JSON files with file references (not inline content)
- Updates the main `registry.json` with proper metadata
- Validates that all referenced source files exist

### Adding New Components

To add a new component to the registry:

1. Create your component in the appropriate directory (`src/ui/` or `src/controlled/`)
2. Add the component configuration to `scripts/build-registry.js` in the `COMPONENTS` object
3. Run `yarn build:registry` to generate the registry files
4. Commit both the source component and generated registry files

## Available Components

### Base UI Components

- `field-wrapper` - Core wrapper component with error handling and labels
- `field-error` - Error display component
- `label` - Label component with tooltip support
- `input` - Base input component
- `select` - Base select component
- `field-checkbox` - Base checkbox component
- `textarea` - Base textarea component
- `datepicker` - Base datepicker component
- `currency-input` - Base currency input component

### Controlled Components (React Hook Form)

- `controlled-input` - Input with react-hook-form integration
- `controlled-select` - Select with react-hook-form integration
- `controlled-checkbox` - Checkbox with react-hook-form integration
- `controlled-textarea` - Textarea with react-hook-form integration
- `controlled-datepicker` - DatePicker with react-hook-form integration
- `controlled-currency-input` - CurrencyInput with react-hook-form integration

## Usage Examples

### Installing a single component

```bash
npx shadcn@latest add --registry https://raw.githubusercontent.com/lambda-curry/medusa-forms/main/packages/medusa-forms/registry.json controlled-input
```

### Installing multiple components

```bash
npx shadcn@latest add --registry https://raw.githubusercontent.com/lambda-curry/medusa-forms/main/packages/medusa-forms/registry.json controlled-input controlled-select controlled-checkbox
```

### Using the components

```tsx
import { ControlledInput } from '@/components/ui/controlled-input'
import { ControlledSelect } from '@/components/ui/controlled-select'
import { useForm, FormProvider } from 'react-hook-form'

function MyForm() {
const methods = useForm()

return (
<FormProvider {...methods}>
<form>
<ControlledInput
name="email"
label="Email"
placeholder="Enter your email"
/>

<ControlledSelect
name="country"
label="Country"
options={[
{ label: 'United States', value: 'us' },
{ label: 'Canada', value: 'ca' },
]}
/>
</form>
</FormProvider>
)
}
```

## Component Dependencies

The registry properly handles component dependencies:

- Controlled components depend on their base UI components
- UI components depend on `field-wrapper` when needed
- `field-wrapper` depends on `field-error` and `label`
- All components use `@medusajs/ui` for base styling

## Architecture

### Field Wrapper Pattern

All form components use a consistent wrapper pattern:

- `FieldWrapper` provides consistent layout and error handling
- `Label` component handles labels and tooltips
- `FieldError` handles error message display
- UI components wrap `@medusajs/ui` components

### Controlled Component Pattern

Controlled components use react-hook-form:

- Uses `Controller` from react-hook-form
- Integrates with form context
- Handles form validation and errors
- Preserves component props and types

## Types and Interfaces

- `BasicFieldProps` - Common field properties
- `FieldWrapperProps` - Wrapper component props
- Component-specific props (`InputProps`, `SelectProps`, etc.)
- React Hook Form integration types
1 change: 1 addition & 0 deletions packages/medusa-forms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"scripts": {
"prepublishOnly": "yarn run build",
"build": "vite build",
"build:registry": "node scripts/build-registry.js",
"lint": "biome check .",
"lint:fix": "biome check --apply .",
"type-check": "tsc --noEmit"
Expand Down
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"name": "medusa-forms",
"description": "Controlled form fields for Medusa Admin and Medusa UI",
"url": "https://raw.githubusercontent.com/lambda-curry/medusa-forms/main/packages/medusa-forms",
"style": "default",
"tailwind": {
"config": "tailwind.config.js",
"css": "src/styles/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "src/components",
"utils": "src/lib/utils"
}
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-checkbox.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-checkbox",
"type": "registry:ui",
"description": "Checkbox component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"field-checkbox"
],
"files": [
{
"name": "controlled-checkbox.tsx",
"path": "src/controlled/ControlledCheckbox.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-currency-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-currency-input",
"type": "registry:ui",
"description": "CurrencyInput component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"currency-input"
],
"files": [
{
"name": "controlled-currency-input.tsx",
"path": "src/controlled/ControlledCurrencyInput.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-datepicker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-datepicker",
"type": "registry:ui",
"description": "DatePicker component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"datepicker"
],
"files": [
{
"name": "controlled-datepicker.tsx",
"path": "src/controlled/ControlledDatePicker.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-input",
"type": "registry:ui",
"description": "Input component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"input"
],
"files": [
{
"name": "controlled-input.tsx",
"path": "src/controlled/ControlledInput.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-select.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-select",
"type": "registry:ui",
"description": "Select component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"select"
],
"files": [
{
"name": "controlled-select.tsx",
"path": "src/controlled/ControlledSelect.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/controlled-textarea.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "controlled-textarea",
"type": "registry:ui",
"description": "Textarea component with react-hook-form integration",
"dependencies": [
"react-hook-form"
],
"registryDependencies": [
"textarea"
],
"files": [
{
"name": "controlled-textarea.tsx",
"path": "src/controlled/ControlledTextArea.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/currency-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "currency-input",
"type": "registry:ui",
"description": "Base currency input component",
"dependencies": [
"@medusajs/ui"
],
"registryDependencies": [
"field-wrapper"
],
"files": [
{
"name": "currency-input.tsx",
"path": "src/ui/CurrencyInput.tsx"
}
]
}
17 changes: 17 additions & 0 deletions packages/medusa-forms/registry/datepicker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "datepicker",
"type": "registry:ui",
"description": "Base datepicker component",
"dependencies": [
"@medusajs/ui"
],
"registryDependencies": [
"field-wrapper"
],
"files": [
{
"name": "datepicker.tsx",
"path": "src/ui/DatePicker.tsx"
}
]
}
18 changes: 18 additions & 0 deletions packages/medusa-forms/registry/field-checkbox.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "field-checkbox",
"type": "registry:ui",
"description": "Base checkbox component",
"dependencies": [
"@medusajs/ui"
],
"registryDependencies": [
"field-wrapper",
"label"
],
"files": [
{
"name": "fieldcheckbox.tsx",
"path": "src/ui/FieldCheckbox.tsx"
}
]
}
15 changes: 15 additions & 0 deletions packages/medusa-forms/registry/field-error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "field-error",
"type": "registry:ui",
"description": "Error display component",
"dependencies": [
"@medusajs/ui"
],
"registryDependencies": [],
"files": [
{
"name": "error.tsx",
"path": "src/ui/Error.tsx"
}
]
}
22 changes: 22 additions & 0 deletions packages/medusa-forms/registry/field-wrapper.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "field-wrapper",
"type": "registry:ui",
"description": "Core wrapper component with error handling and labels",
"dependencies": [
"@medusajs/ui"
],
"registryDependencies": [
"field-error",
"label"
],
"files": [
{
"name": "fieldwrapper.tsx",
"path": "src/ui/FieldWrapper.tsx"
},
{
"name": "types.d.ts",
"path": "src/ui/types.d.ts"
}
]
}
Loading
Loading