-
Notifications
You must be signed in to change notification settings - Fork 0
feat: medusa-forms #77
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
Conversation
|
|
WalkthroughThis update introduces a new Medusa Forms package with a full suite of controlled form components and UI primitives, integrated with react-hook-form and @medusajs/ui. It adds comprehensive documentation, Storybook stories, and project configuration changes to support Medusa Forms alongside existing Remix Hook Form components. Multiple dependencies, configurations, and import paths are updated accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Storybook
participant FormProvider
participant ControlledComponent
participant UIComponent
participant ReactHookForm
User->>Storybook: Interacts with Medusa Forms story
Storybook->>FormProvider: Wraps story with form context
FormProvider->>ControlledComponent: Provides form state/validation
ControlledComponent->>ReactHookForm: Registers field via Controller
ControlledComponent->>UIComponent: Renders UI with value, error, handlers
UIComponent->>User: Displays input, error, label, etc.
User->>UIComponent: Inputs value or triggers change
UIComponent->>ControlledComponent: Calls onChange/onBlur
ControlledComponent->>ReactHookForm: Updates form state/validation
ReactHookForm->>ControlledComponent: Provides updated value/error
ControlledComponent->>UIComponent: Rerenders with new props
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (8)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (6)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
- Updated remix-hook-form to version 7.0.1 across multiple package.json files. - Added new dependencies: @hookform/error-message and @hookform/resolvers in apps/docs. - Enhanced tsconfig paths for medusa-forms to include src and lib directories. - Refactored ControlledInput component to use ComponentProps for better type safety. - Removed unused index.ts file from controlled directory in medusa-forms. - Improved error handling in Error component for better readability and performance. - Updated main.css for consistent Tailwind CSS imports and added Medusa UI tokens.
|
📝 Storybook Preview: View Storybook This preview will be updated automatically when you push new changes to this PR.
|
- Removed deprecated dependencies and updated Storybook addons to version 9.0.1 across multiple package.json files. - Refactored imports in Storybook stories to use '@storybook/react-vite' for improved compatibility. - Updated routing imports from 'react-router-dom' to 'react-router' for consistency across components. - Cleaned up external dependencies in Vite configuration for better performance. - Enhanced example components to align with the latest routing practices.
- Removed @medusajs/ui-preset and related dependencies from package.json and yarn.lock. - Cleaned up Vite configuration by removing unnecessary external dependencies. - Updated Storybook stories to ensure consistent import statements and improved component usage.
- Updated various dependencies in yarn.lock for better performance and compatibility. - Adjusted muted-foreground color in main.css for improved accessibility and design consistency.
- Maintained React 19 patterns in all form components (no forwardRef usage) - Preserved all other changes from medusa-forms branch - Components now use FC<Props> with destructured ref parameter - All form components maintain consistent React 19 ref handling pattern
…use-new-react-patterns-41c7
…omponents - Replaced standard React imports with type-only imports across multiple form components for improved type safety and clarity. - Ensured consistency in the usage of functional components with TypeScript interfaces.
- Created directory structure for controlled component stories - Added README with implementation plan and template pattern - Based on medusa-forms-upgrades branch as requested
- Add BasicUsage story with simple textarea and react-hook-form integration - Add CharacterLimits story with character count validation and display - Add RequiredFieldValidation story with error states and custom messages - Add AutoResizeFunctionality story with dynamic height adjustment - Add ValidationErrorStates story with various error scenarios - Add ComprehensiveExample story showing multiple textareas in a form - Follow established pattern from ControlledInput.stories.tsx - Use react-hook-form directly with FormProvider and useForm - Include proper validation with zod schemas - Demonstrate real-world usage patterns Addresses LC-245: Create ControlledTextArea Storybook Stories
- Complete Registration Form with multi-step validation - Product Creation Form demonstrating all controlled components - Form Validation Showcase with various validation scenarios - Real-world usage patterns with error handling and submit states - Comprehensive documentation for each example Components integrated: - ControlledInput (text, email, password, number) - ControlledCheckbox (terms, preferences, status flags) - ControlledSelect (country, category selection) - ControlledDatePicker (birth date, launch date with constraints) - ControlledCurrencyInput (pricing with validation) - ControlledTextArea (descriptions, tags) Validation features: - Real-time validation with react-hook-form - Complex business rules (age verification, price ranges) - Format validation (email, SKU patterns, dimensions) - Cross-field validation (password confirmation) - Submit handling with loading states and success feedback
- ControlledCurrencyInput: 4 story variants (USD/EUR/GBP, validation, error handling, different currency codes) - ControlledDatePicker: 5 story variants (basic, validation, formats, disabled dates, constraints) - Both follow react-hook-form pattern with comprehensive validation - Merged from agents #27943 and #27941 work on LC-244 and LC-242
- Comprehensive implementation with 8 story variants - BasicUsage, DefaultChecked/Unchecked, RequiredValidation, CustomValidation - ErrorState, DisabledState, MultipleCheckboxes, CompleteFormExample - Follows react-hook-form pattern with proper boolean value handling - Includes advanced features like select-all functionality Merged from agent #27942's work on LC-243
- Add 10 comprehensive story variants for ControlledSelect component - Cover basic single select, default values, validation, loading states - Include custom option rendering using Select compound components - Add disabled state, error state, and size variants - Include complex form integration and interactive demo - Follow established pattern from ControlledInput.stories.tsx - Use react-hook-form directly without react-router dependencies Note: Multi-select and searchable/creatable variants not included as they are not currently supported by the base Select component
- Fixed duplicate identifier conflicts in ControlledSelect.stories.tsx: - Renamed component function ComplexFormIntegration to ComplexFormIntegrationComponent - Renamed story exports to avoid conflicts: RequiredValidation → SelectRequiredValidation, DisabledState → SelectDisabledState, ErrorState → SelectErrorState - Fixed duplicate identifier conflicts in ControlledCheckbox.stories.tsx: - Renamed component function CompleteFormExample to CompleteFormExampleComponent - Fixed incorrect import path in ControlledCheckbox.stories.tsx: - Changed from '@lambdacurry/medusa-forms/controlled' to '@lambdacurry/medusa-forms/controlled/ControlledCheckbox' These changes resolve the Storybook build failures caused by TypeScript identifier conflicts and import path issues.
…te-form-integration-examples
…lledtextarea-storybook-stories
…lledselect-storybook-stories
…controlled-components-documentation-stories-and
…ries - Updated ControlledCurrencyInput stories to include currency symbol and code as props for better flexibility. - Refactored validation schemas to use string types for price inputs, ensuring consistent handling of numeric values. - Improved FormIntegrationExamples by adding missing imports and refining form handling logic for better readability. - Enhanced error handling and validation messages across various form components, ensuring a more robust user experience.
…on from @medusajs/ui - Replaced native button elements with the Button component for improved styling and functionality. - Updated button properties to utilize isLoading and variant attributes for better user experience. - Ensured consistent usage of the Button component across different forms, enhancing code maintainability.
- Add medusa-forms-patterns.mdc for component development patterns - Add medusa-stories-patterns.mdc for Storybook story patterns - Focus on @medusajs/ui integration and react-hook-form Controller patterns - Complement existing form-component-patterns.mdc with Medusa-specific guidance - Include validation, error handling, and accessibility requirements - Provide comprehensive story examples and best practices
- Update monorepo-organization.mdc with proper globs and new package structure - Add medusa-forms package and directory structure documentation - Update storybook-testing.mdc to include react-hook-form and @medusajs/ui - Add medusa-forms story directory to project structure - Update form-component-patterns.mdc to clarify scope (Remix Hook Form only) - Add note directing to medusa-forms-patterns.mdc for Medusa components
…les-1748666401
- Refactored ControlledCurrencyInput, ControlledDatePicker, ControlledSelect, and ControlledTextArea stories to include necessary props and improve structure. - Added missing args for story configurations to ensure proper rendering and documentation. - Updated validation rules and error handling for better user experience across various form components. - Removed outdated README for controlled components as the documentation is now integrated within the stories. - Improved button usage in forms by utilizing the Button component from @medusajs/ui for consistent styling and functionality.
- Updated import statement for the Button component to use the correct casing, ensuring consistent styling and functionality across stories.
- Renamed internal prop types to Controlled*Props for ControlledCheckbox, ControlledCurrencyInput, ControlledDatePicker, ControlledInput, ControlledSelect, and ControlledTextArea for clarity and consistency. - Updated import statements for UI components to align with new prop type names. - Enhanced type definitions to improve type safety and maintainability across controlled components.
…rsion - Upgraded Storybook-related packages to version 9.0.4 for improved features and bug fixes. - Updated react-hook-form to version 7.57.0 and react-remove-scroll to version 2.7.1 for better compatibility and performance. - Incremented medusa-forms package version to 0.2.0 to reflect recent changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 40
🔭 Outside diff range comments (1)
packages/components/src/remix-hook-form/use-data-table-url-state.ts (1)
27-68:⚠️ Potential issueCritical: Stale closure bug in useCallback dependency array.
Removing
urlStatefrom the dependency array creates a stale closure issue. The callback captures the initialurlStateand won't see updates when URL parameters change, leading to incorrect state merging.The biome-ignore comment suggests this was intentionally done, but it introduces a bug. Apply this fix:
- // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation> const setUrlState = useCallback( (newState: Partial<DataTableRouterState>) => { - const updatedState = { ...urlState, ...newState }; + // Parse current URL state fresh to avoid stale closure + const currentUrlState: DataTableRouterState = { + search: dataTableRouterParsers.search.parse(searchParams.get('search')), + filters: dataTableRouterParsers.filters.parse(searchParams.get('filters')), + page: dataTableRouterParsers.page.parse(searchParams.get('page')), + pageSize: dataTableRouterParsers.pageSize.parse(searchParams.get('pageSize')), + sortField: dataTableRouterParsers.sortField.parse(searchParams.get('sortField')), + sortOrder: dataTableRouterParsers.sortOrder.parse(searchParams.get('sortOrder')), + }; + const updatedState = { ...currentUrlState, ...newState }; const newParams = new URLSearchParams(); // ... rest of the function remains the same }, - [setSearchParams], + [searchParams, setSearchParams], );
♻️ Duplicate comments (1)
apps/docs/src/medusa-forms/FormIntegrationExamples.stories.tsx (1)
609-610: Same parsing concern as earlierThis has the same currency parsing issue mentioned in the earlier comment.
🧹 Nitpick comments (19)
packages/components/src/ui/data-table/data-table-pagination.tsx (1)
13-14: Consistent parsing of URL parameters
Switching toNumber.parseInt(..., 10)is a good practice for clarity and radix safety. Consider also handlingNaNedge cases if non-numeric values might appear..cursor/rules/form-component-patterns.mdc (1)
3-3: Clarify repository reference in metadata
Thedescriptionmetadata still mentions thelambda-curry/formsrepo. Consider updating it to reference the monorepo context orpackages/components/directly.packages/medusa-forms/src/ui/FieldGroup.tsx (1)
4-6: DefineFieldGroupprops via interface
Inline prop typing works, but extracting aFieldGroupPropsinterface would improve reusability and readability. Adding a JSDoc comment ordisplayNamecould also enhance maintainability.packages/medusa-forms/src/ui/Label.tsx (1)
14-27: Enhance tooltip accessibility.The tooltip icon wrapper is a
<div>, which isn’t keyboard-focusable. Consider using a<span>or<button>withtabIndex={0}androle="button"to ensure screen-reader and keyboard users can access it. For example:- {tooltip && ( - <Tooltip content={tooltip}> - <div className="flex items-center justify-center ml-1"> - <InformationCircle className="-scale-75" /> - </div> - </Tooltip> - )} + {tooltip && ( + <Tooltip content={tooltip}> + <span + role="button" + tabIndex={0} + className="flex items-center justify-center ml-1 focus:outline-none" + > + <InformationCircle className="scale-75" /> + </span> + </Tooltip> + )}This change retains the visual styling and adds keyboard accessibility.
packages/medusa-forms/src/ui/ColorInput.tsx (1)
16-34: Verify accessibility and consider enhancements.The dual input approach (color picker + text input) provides good user experience. However, there are a few considerations:
- Accessibility: Both inputs should have proper
aria-labeloraria-labelledbyattributes- Color validation: The text input should validate hex color format
- Keyboard navigation: Consider adding proper tab order
Consider adding validation and accessibility improvements:
return ( <div className="flex items-center p-2"> <Input type="color" value={selectedColor} onChange={handleChange} className="w-7 h-7 p-0 border-0 mr-4 rounded-sm" onBlur={onBlur} + aria-label="Color picker" /> <Input type="text" placeholder="#a232a4" value={selectedColor} onChange={handleChange} className="flex-grow" onKeyDown={onKeyDown} + aria-label="Hex color code" + pattern="^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" /> </div> );packages/medusa-forms/src/ui/Error.tsx (1)
47-63: Component logic is correct with minor accessibility improvement needed.The error handling logic correctly handles null cases and uses the ErrorMessage component appropriately.
Add accessibility improvement for better screen reader support:
export const FieldError = ({ errors, name, className }: Props) => { if (!(errors && name)) return null; return ( <ErrorMessage name={name} errors={errors} render={({ message, messages }) => { return ( - <div className={clsx('txt-compact-xsmall !leading-snug mt-2 text-red-500', className)}> + <div className={clsx('txt-compact-xsmall !leading-snug mt-2 text-red-500', className)} role="alert" aria-live="polite"> {messages ? <MultipleMessages messages={messages} /> : <p>{message}</p>} </div> ); }} /> ); };This ensures screen readers announce validation errors when they appear.
apps/docs/src/medusa-forms/ControlledInput.stories.tsx (1)
33-40: Consider enhancing the story for better demonstration.While the basic story works, consider adding additional stories to showcase validation, error states, and different input configurations for better documentation value.
// Consider adding these additional stories: export const WithValidation: Story = { // Story with validation rules }; export const WithError: Story = { // Story showing error state }; export const Disabled: Story = { // Story showing disabled state };packages/medusa-forms/src/controlled/ControlledInput.tsx (3)
12-17: Simplify the type definition to avoid redundancy.The type intersection has redundant parts that make it unnecessarily complex.
export type ControlledInputProps<T extends FieldValues> = InputProps & - Omit<ControllerProps, 'render'> & { + Omit<ControllerProps<T>, 'render'> & { name: Path<T>; rules?: Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>; - } & ComponentProps<typeof Input> & - Omit<ControllerProps<T>, 'render'>; + };The
ComponentProps<typeof Input>is redundant sinceInputPropsalready includes the necessary props, and we're duplicating theControllerPropsomission.
34-34: Remove unnecessary type assertion.The type assertion is unnecessary since the
rulesprop is already properly typed in the component props.- rules={rules as Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + rules={rules}
36-40: Remove redundant prop forwarding.The explicit
labelClassNameprop forwarding is redundant since it's already included in the spread operator.<Input {...field} {...props} - labelClassName={props.labelClassName} formErrors={errors} onChange={(evt) => {packages/medusa-forms/src/controlled/ControlledCurrencyInput.tsx (1)
28-28: Simplify the rules type casting.The complex type casting for
rulescould be simplified and made more type-safe.Consider extracting the type definition:
+type CurrencyInputRules<T extends FieldValues> = Omit< + RegisterOptions<T, Path<T>>, + 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs' +>; - rules={rules as Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + rules={rules as CurrencyInputRules<T>}This makes the code more readable and reusable across similar components.
packages/medusa-forms/src/controlled/ControlledSelect.tsx (1)
43-43: Verify the type assertion safety for rules.The type assertion removes several
RegisterOptionskeys, but this could potentially hide type errors if the underlying types change.Consider using a more explicit type definition instead of type assertion:
-rules={rules as Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} +rules={rules}And update the component props to accept the correct rules type:
export type ControlledSelectProps<T extends FieldValues> = SelectProps & Omit<ControllerProps, 'render'> & { name: Path<T>; + rules?: Omit<RegisterOptions<T, Path<T>>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>; onBlur?: () => void; onChange?: (value: unknown) => void; }apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx (1)
186-192: Consider managing side effects with useEffect dependenciesWhile the effect correctly demonstrates manual error setting, consider if this error should persist across component re-renders.
If you want the error to only be set once on mount:
// Manually trigger an error for demonstration React.useEffect(() => { form.setError('errorField', { type: 'manual', message: 'This is an example error message' }); -}, [form]); +}, []); // Empty dependency array for mount-only effectNote: The current implementation with
formin the dependency array will re-trigger if the form instance changes, which might be the intended behavior for this demo.apps/docs/src/medusa-forms/FormIntegrationExamples.stories.tsx (1)
405-409: Consider using a proper decimal parsing approachWhile the current implementation works, consider using a more robust approach for parsing currency values to handle edge cases.
Consider this more robust validation:
validate: (value) => { - const numValue = Number.parseFloat(value); + // Remove currency symbols and commas before parsing + const cleanValue = value.replace(/[$,]/g, ''); + const numValue = Number.parseFloat(cleanValue); + if (Number.isNaN(numValue)) return 'Please enter a valid price'; return (numValue > 0 && numValue <= 10000) || 'Price must be between $0.01 and $10,000'; },apps/docs/src/medusa-forms/ControlledCurrencyInput.stories.tsx (1)
43-47: AlignuseForm’s generic with the default values
useForm<CurrencyFormData>is correct, but supplying string values while the controlled component is likely emitting numbers can create type drift.
Consider storing the price as a number immediately to avoid extraparseFloatwork in every validation rule:-interface CurrencyFormData { price: string } +interface CurrencyFormData { price: number } ... - defaultValues = { price: '' }, + defaultValues = { price: 0 },Then switch the Zod schemas to
z.number()and drop the repeatedNumber.parseFloatclamping logic. You gain:
- Simpler validation (
z.number().min(10)).- Consistent value type between RHF, the component, and consumers.
apps/docs/src/main.css (2)
38-129: Split gigantic design-token blocks into dedicated filesThe light-mode token section now spans ~90 lines. Maintaining or overriding a single token will require touching this monolithic file, increasing merge-conflict likelihood and build times (PostCSS/Tailwind has to re-process the whole sheet).
Consider:
@import "./tokens/medusa-light.css";@import "./tokens/medusa-dark.css";Each file would only hold the variables for one colour-mode. Vite & Tailwind will still tree-shake unused tokens, and designers can iterate without risking unrelated styles.
460-467: Tailwind’s@applywith CSS variables can explode CSS output
@apply border-[var(--color-border)]forces Tailwind to create a runtime rule instead of a pre-generated utility, potentially ballooning the final CSS whenever the variable changes (it cannot purge). Prefer a component class:.border-ring { border-color: var(--color-border); }and use
@apply border-ringin the few places that need it.
[performance]packages/medusa-forms/src/ui/types.d.ts (2)
91-107: Remove commented out code.The commented out
DatePickerPropstype definition should be removed as it's not being used and creates confusion.-// export type DatePickerProps = ( -// | { -// mode?: 'single'; -// presets?: DatePreset[]; -// defaultValue?: Date; -// value?: Date; -// onChange?: (date: Date | null) => void; -// } -// | { -// mode: 'range'; -// presets?: DateRangePreset[]; -// defaultValue?: DateRange; -// value?: DateRange; -// onChange?: (dateRange: DateRange | null) => void; -// } -// ) & -// PickerProps;
5-13: Add JSDoc documentation for BasicFieldProps interface.The
BasicFieldPropsinterface would benefit from documentation explaining its purpose and usage in the form system.+/** + * Common props shared across all form field components + * Provides consistent labeling, styling, and error handling capabilities + */ export interface BasicFieldProps { + /** The label text or element to display above the field */ label?: ReactNode; + /** CSS class name to apply to the label element */ labelClassName?: string; + /** Tooltip content to display next to the label */ labelTooltip?: ReactNode; + /** CSS class name to apply to the field wrapper */ wrapperClassName?: string; + /** CSS class name to apply when the field has errors */ errorClassName?: string; + /** Form errors object from react-hook-form */ formErrors?: { [x: string]: unknown }; + /** The field name for form registration */ name?: string; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
.yarn/releases/yarn-4.9.1.cjsis excluded by!**/.yarn/**yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (72)
.cursor/rules/form-component-patterns.mdc(1 hunks).cursor/rules/medusa-forms-patterns.mdc(1 hunks).cursor/rules/medusa-stories-patterns.mdc(1 hunks).cursor/rules/monorepo-organization.mdc(4 hunks).cursor/rules/storybook-testing.mdc(3 hunks).yarnrc.yml(1 hunks)apps/docs/.storybook/main.ts(1 hunks)apps/docs/.storybook/preview.ts(1 hunks)apps/docs/package.json(1 hunks)apps/docs/src/examples/root-example.tsx(1 hunks)apps/docs/src/lib/storybook/react-router-stub.tsx(2 hunks)apps/docs/src/main.css(3 hunks)apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx(1 hunks)apps/docs/src/medusa-forms/ControlledCurrencyInput.stories.tsx(1 hunks)apps/docs/src/medusa-forms/ControlledDatePicker.stories.tsx(1 hunks)apps/docs/src/medusa-forms/ControlledInput.stories.tsx(1 hunks)apps/docs/src/medusa-forms/ControlledSelect.stories.tsx(1 hunks)apps/docs/src/medusa-forms/ControlledTextArea.stories.tsx(1 hunks)apps/docs/src/medusa-forms/FormIntegrationExamples.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/checkbox-list.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/checkbox.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/date-picker.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/otp-input.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/radio-group.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/switch-custom.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/switch.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/text-field-custom.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/text-field.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/textarea-custom.stories.tsx(1 hunks)apps/docs/src/remix-hook-form/textarea.stories.tsx(3 hunks)apps/docs/tsconfig.json(1 hunks)apps/docs/vite.config.mjs(1 hunks)package.json(1 hunks)packages/components/package.json(2 hunks)packages/components/src/remix-hook-form/data-table-router-form.tsx(1 hunks)packages/components/src/remix-hook-form/use-data-table-url-state.ts(4 hunks)packages/components/src/ui/button.tsx(2 hunks)packages/components/src/ui/data-table/data-table-column-header.tsx(3 hunks)packages/components/src/ui/data-table/data-table-hooks.ts(1 hunks)packages/components/src/ui/data-table/data-table-pagination.tsx(3 hunks)packages/components/src/ui/data-table/data-table-toolbar.tsx(2 hunks)packages/components/vite.config.ts(0 hunks)packages/medusa-forms/CHANGELOG.md(1 hunks)packages/medusa-forms/package.json(1 hunks)packages/medusa-forms/src/controlled/ControlledCheckbox.tsx(1 hunks)packages/medusa-forms/src/controlled/ControlledCurrencyInput.tsx(1 hunks)packages/medusa-forms/src/controlled/ControlledDatePicker.tsx(1 hunks)packages/medusa-forms/src/controlled/ControlledInput.tsx(1 hunks)packages/medusa-forms/src/controlled/ControlledSelect.tsx(1 hunks)packages/medusa-forms/src/controlled/ControlledTextArea.tsx(1 hunks)packages/medusa-forms/src/controlled/index.ts(1 hunks)packages/medusa-forms/src/ui/Button.tsx(1 hunks)packages/medusa-forms/src/ui/ColorInput.tsx(1 hunks)packages/medusa-forms/src/ui/CurrencyInput.tsx(1 hunks)packages/medusa-forms/src/ui/DatePicker.tsx(1 hunks)packages/medusa-forms/src/ui/Error.tsx(1 hunks)packages/medusa-forms/src/ui/FieldCheckbox.tsx(1 hunks)packages/medusa-forms/src/ui/FieldGroup.tsx(1 hunks)packages/medusa-forms/src/ui/FieldWrapper.tsx(1 hunks)packages/medusa-forms/src/ui/FileUpload.tsx(1 hunks)packages/medusa-forms/src/ui/Input.tsx(1 hunks)packages/medusa-forms/src/ui/Label.tsx(1 hunks)packages/medusa-forms/src/ui/Select.tsx(1 hunks)packages/medusa-forms/src/ui/TextArea.tsx(1 hunks)packages/medusa-forms/src/ui/index.ts(1 hunks)packages/medusa-forms/src/ui/types.d.ts(1 hunks)packages/medusa-forms/tsconfig.json(1 hunks)packages/medusa-forms/vite.config.ts(1 hunks)
💤 Files with no reviewable changes (1)
- packages/components/vite.config.ts
🧰 Additional context used
🧠 Learnings (1)
packages/medusa-forms/src/ui/TextArea.tsx (2)
Learnt from: jaruesink
PR: lambda-curry/forms#14
File: packages/components/src/ui/textarea.tsx:17-24
Timestamp: 2024-11-26T05:28:58.779Z
Learning: In `packages/components/src/ui/textarea.tsx`, the `Textarea` component forwards its ref to `FormItem`, and the textarea element receives `field.ref`, so the ref forwarding works correctly.
Learnt from: jaruesink
PR: lambda-curry/forms#14
File: packages/components/src/ui/textarea.tsx:32-34
Timestamp: 2024-11-26T05:29:39.395Z
Learning: In the `Textarea` component (`packages/components/src/ui/textarea.tsx`), it's acceptable to assign `field.ref` directly to the `ref` of the textarea element without merging it with external refs.
🧬 Code Graph Analysis (16)
packages/components/src/ui/button.tsx (1)
packages/components/src/ui/utils/index.ts (1)
cn(4-6)
packages/medusa-forms/src/ui/Error.tsx (1)
packages/medusa-forms/src/ui/types.d.ts (1)
BasicFieldProps(5-13)
packages/medusa-forms/src/controlled/ControlledCheckbox.tsx (1)
packages/medusa-forms/src/ui/FieldCheckbox.tsx (2)
FieldCheckboxProps(9-13)FieldCheckbox(15-60)
packages/medusa-forms/src/controlled/ControlledDatePicker.tsx (1)
packages/medusa-forms/src/ui/DatePicker.tsx (2)
DatePickerProps(7-10)DatePickerInput(14-16)
packages/medusa-forms/src/controlled/ControlledInput.tsx (1)
packages/medusa-forms/src/ui/Input.tsx (2)
InputProps(6-9)Input(13-15)
packages/medusa-forms/src/controlled/ControlledCurrencyInput.tsx (1)
packages/medusa-forms/src/ui/CurrencyInput.tsx (2)
CurrencyInputProps(7-10)CurrencyInput(14-16)
packages/medusa-forms/src/ui/ColorInput.tsx (1)
packages/medusa-forms/src/ui/Input.tsx (1)
Input(13-15)
packages/medusa-forms/src/ui/Input.tsx (2)
packages/medusa-forms/src/ui/types.d.ts (2)
MedusaInputProps(34-36)BasicFieldProps(5-13)packages/medusa-forms/src/ui/FieldWrapper.tsx (1)
FieldWrapper(7-27)
packages/medusa-forms/src/ui/Select.tsx (2)
packages/medusa-forms/src/ui/types.d.ts (1)
BasicFieldProps(5-13)packages/medusa-forms/src/ui/FieldWrapper.tsx (1)
FieldWrapper(7-27)
packages/medusa-forms/src/controlled/ControlledTextArea.tsx (2)
packages/medusa-forms/src/ui/TextArea.tsx (2)
TextAreaProps(6-9)TextArea(13-15)packages/medusa-forms/src/ui/types.d.ts (1)
TextAreaProps(19-23)
packages/medusa-forms/src/ui/FieldWrapper.tsx (3)
packages/medusa-forms/src/ui/types.d.ts (1)
FieldWrapperProps(15-17)packages/medusa-forms/src/ui/Label.tsx (1)
Label(14-27)packages/medusa-forms/src/ui/Error.tsx (1)
FieldError(47-63)
packages/medusa-forms/src/ui/FieldCheckbox.tsx (3)
packages/medusa-forms/src/ui/types.d.ts (1)
BasicFieldProps(5-13)packages/medusa-forms/src/ui/FieldWrapper.tsx (1)
FieldWrapper(7-27)packages/medusa-forms/src/ui/Label.tsx (1)
Label(14-27)
packages/medusa-forms/src/controlled/ControlledSelect.tsx (1)
packages/medusa-forms/src/ui/Select.tsx (2)
SelectProps(6-9)Select(28-33)
apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx (1)
packages/medusa-forms/src/controlled/ControlledCheckbox.tsx (1)
ControlledCheckbox(17-47)
packages/medusa-forms/src/ui/types.d.ts (3)
packages/medusa-forms/src/ui/TextArea.tsx (1)
TextAreaProps(6-9)packages/medusa-forms/src/ui/DatePicker.tsx (1)
DatePickerProps(7-10)packages/medusa-forms/src/ui/Select.tsx (1)
SelectProps(6-9)
apps/docs/src/medusa-forms/ControlledTextArea.stories.tsx (3)
packages/medusa-forms/src/controlled/ControlledTextArea.tsx (1)
ControlledTextArea(19-29)packages/components/src/ui/button.tsx (1)
Button(38-41)packages/medusa-forms/src/controlled/ControlledInput.tsx (1)
ControlledInput(19-51)
🪛 Biome (1.9.4)
apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx
[error] 108-108: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 321-321: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 329-329: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 338-338: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
🔇 Additional comments (95)
package.json (1)
29-29:✅ Verification successful
Confirm Yarn version consistency
Ensure that the Yarn binary at.yarn/releases/yarn-4.9.1.cjsmatches this updatedpackageManagerversion and that the file is committed to the repo.
🏁 Script executed:
#!/bin/bash # Verify the Yarn binary exists for the specified version if [[ -f .yarn/releases/yarn-4.9.1.cjs ]]; then echo "✔ Yarn binary present" else echo "❌ Missing .yarn/releases/yarn-4.9.1.cjs" exit 1 fiLength of output: 93
Yarn version consistency confirmed
- Verified that
.yarn/releases/yarn-4.9.1.cjsexists and matches the"packageManager": "yarn@4.9.1"entry inpackage.json. No further action needed..yarnrc.yml (1)
3-3: Binary path specified
TheyarnPathcorrectly points to the newly added Yarn release. Make sure this binary is committed and usable in CI/local environments.packages/components/src/ui/data-table/data-table-hooks.ts (1)
2-2:✅ Verification successful
Consistent import source for routing hooks
ImportinguseSearchParamsfromreact-routeraligns with the migration to React Router v7. Verify thatreact-routerv7 is declared in yourpackages/componentsdependencies and that there are no lingeringreact-router-domimports.
🏁 Script executed:
#!/bin/bash # Search for any remaining react-router-dom imports in components rg -n "react-router-dom" --glob "packages/components/**"Length of output: 56
Let’s verify that
react-routerv7 is declared in yourpackages/componentsdependencies (and there are noreact-router-domentries inpackage.json):
🏁 Script executed:
#!/bin/bash # Check for react-router and react-router-dom entries in packages/components/package.json grep -R '"react-router' -n packages/components/package.jsonLength of output: 94
Routing hooks import verified
Confirmed thatreact-routerv7.6.1 is declared in packages/components/package.json and there are no remainingreact-router-domimports.apps/docs/.storybook/preview.ts (1)
1-1:✅ Verification successful
Verify Storybook builder alignment
Switching thePreviewtype import to@storybook/react-viteis correct for Vite-based builds. Ensure your Storybook config (main.js/main.ts) uses the Vite builder (@storybook/builder-vite).
🏁 Script executed:
#!/bin/bash # Check that the Vite builder is configured rg -n "builder-vite" -e "builder: '@storybook/builder-vite'" --glob "apps/docs/.storybook/*"Length of output: 151
🏁 Script executed:
#!/bin/bash # List Storybook config files to identify main.js/main.ts ls apps/docs/.storybook # Search for the Vite builder configuration in those files rg -n "builder\s*:\s*['\"]@storybook/builder-vite['\"]" --glob "apps/docs/.storybook/*"Length of output: 287
🏁 Script executed:
#!/bin/bash # Inspect Storybook main config for builder/framework settings rg -nE "(builder|framework)\s*:" apps/docs/.storybook/main.ts || cat apps/docs/.storybook/main.tsLength of output: 1061
Vite builder configuration confirmed
Yourmain.tsuses the React-Vite framework, which implicitly applies the Vite builder. Theimport type { Preview } from '@storybook/react-vite'inpreview.tsis therefore correct—no additionalbuilderfield is required.• apps/docs/.storybook/main.ts:
framework: { name: getAbsolutePath('@storybook/react-vite'), options: {}, },apps/docs/src/examples/root-example.tsx (1)
1-1:✅ Verification successful
Align routing imports with React Router v7
Changing theOutletimport toreact-routermatches the v7 migration. Confirm thatreact-routeris included inapps/docsdependencies and that noreact-router-domimports remain in example files.
🏁 Script executed:
#!/bin/bash # Look for stale react-router-dom imports in the examples folder rg -n "react-router-dom" --glob "apps/docs/src/examples/**"Length of output: 59
🏁 Script executed:
#!/bin/bash set -e # Locate the apps/docs package.json pkg=$(fd -t f package.json apps/docs) echo "Inspecting dependency entries in $pkg" # Check for react-router presence grep -R '"react-router"' -n "$pkg" || echo "⚠️ No react-router dependency found in apps/docs/package.json"Length of output: 278
Routing imports aligned with React Router v7
Verified thatreact-router(v7.6.1) is declared in apps/docs/package.json and noreact-router-domimports remain in apps/docs/src/examples. LGTM.packages/components/src/remix-hook-form/data-table-router-form.tsx (1)
15-15: AlignuseNavigationimport with React Router v7
ImportinguseNavigationfrom'react-router'matches the monorepo’s migration away fromreact-router-domand is consistent with the updated React Router v7 setup.apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx (1)
4-4: Import Storybook types from@storybook/react-vite
Switching to the Vite-specific Storybook package ensures compatibility with thereact-viteframework integration in this project.packages/components/src/ui/data-table/data-table-column-header.tsx (1)
3-3: AlignuseSearchParamsimport with React Router v7
Updating to import from'react-router'follows the same v7 migration and keeps routing hooks consistent across the codebase.apps/docs/.storybook/main.ts (1)
14-16: Review Storybook addons configuration
You’ve replaced@storybook/addon-essentialsand@storybook/addon-interactionswith only@storybook/addon-docs. Please verify that removing the other essential addons does not unintentionally disable features (controls, actions, viewport, etc.) needed by your stories.apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx (2)
6-6: Import Storybook types from@storybook/react-vite
This aligns the story’s type imports with the Vite-based Storybook setup.
7-7: Update testing utilities import path
Importing{ expect, userEvent, within }fromstorybook/testmatches the monorepo’s new testing utility package.apps/docs/src/remix-hook-form/checkbox.stories.tsx (1)
4-5: Updated Storybook import paths.
Imports for Storybook types (Meta,StoryContext,StoryObj) have been correctly switched to@storybook/react-vite, and testing utilities (expect,userEvent) updated tostorybook/test. This aligns with the monorepo-wide migration to Storybook 9 with Vite support.apps/docs/src/remix-hook-form/textarea-custom.stories.tsx (1)
5-6: Aligned Storybook Vite imports.
TheMetaandStoryObjtypes now import from@storybook/react-vite, and testing utilities (expect,userEvent,within) fromstorybook/test, matching the updated Storybook setup.apps/docs/src/remix-hook-form/checkbox-list.stories.tsx (1)
5-6: Migrated Storybook imports to Vite and new test utils.
Switching Storybook types to@storybook/react-viteand tests tostorybook/testis consistent with the broader refactor and should ensure compatibility with Storybook 9 and Vite.apps/docs/src/remix-hook-form/text-field-custom.stories.tsx (1)
5-6: Storybook import paths updated for Vite and test utilities.
The import ofMetaandStoryObjfrom@storybook/react-viteand test utilities fromstorybook/testaligns with the other stories and the new Storybook configuration.packages/components/src/ui/data-table/data-table-toolbar.tsx (2)
51-51: Whitespace cleanup.
The removal of the trailing blank line aftersetSearchParamsis purely cosmetic and improves code cleanliness.
4-4:✅ Verification successful
Confirm React Router import change.
The import ofuseSearchParamshas been switched fromreact-router-domtoreact-routerto unify routing dependencies under React Router v7.6.1. Please verify via official docs thatuseSearchParamsis indeed exported fromreact-routerin the targeted version.
🌐 Web query:
In React Router v7.6.1, is the `useSearchParams` hook exported from the `react-router` package or `react-router-dom`?💡 Result:
In React Router v7.6.1, the
useSearchParamshook is exported from thereact-routerpackage, notreact-router-dom.You can see this in the official API documentation and examples, which show the following import statement:
import { useSearchParams } from "react-router";[1][2][10]
This is a change compared to React Router v6, where most web-facing hooks were exported from
react-router-dom[4][7][8]. As of v7,useSearchParamsis now part of the shared core inreact-router, so you should import it from there when working with React Router v7.6.1.Citations:
- 1: https://api.reactrouter.com/v7/functions/react_router.useSearchParams.html
- 2: https://www.robinwieruch.de/react-router-search-params/
- 3: https://dev.to/vikram-boominathan/search-params-and-use-location-5b7h
- 4: https://reactrouter.com/6.30.1/hooks/use-search-params
- 5: https://www.robinwieruch.de/react-router/
- 6: https://stackshare.io/stackups/npm-react-dom-vs-npm-react-router-dom
- 7: https://www.dhiwise.com/blog/design-converter/useparams-vs-usesearchparams-choosing-the-right-hook
- 8: https://www.dhiwise.com/blog/design-converter/how-to-effectively-use-usesearchparams-in-react-router-dom
- 9: https://dev.to/pramod_boda/what-is-the-difference-between-react-router-and-react-router-dom-2da6
- 10: https://reactrouter.com/api/hooks/useSearchParams
React Router import change confirmed.
Verified in React Router v7.6.1’s official docs thatuseSearchParamsis exported fromreact-router, so the current import is correct.packages/components/package.json (2)
39-39: Bump peer dependency forremix-hook-form
Upgradingremix-hook-formto7.0.1aligns this package with the new Medusa Forms release and ensures peer compatibility.
67-68: Update runtime dependencies for React Router and Remix Hook Form
Thereact-routerversion was bumped to^7.6.1andremix-hook-formto7.0.1in dependencies. Please verify that the corresponding devDependencies (@react-router/dev,@react-router/node) are compatible with React Router v7.6.1, and confirm there are no lingeringreact-router-domimports elsewhere in the repo.packages/components/src/ui/data-table/data-table-pagination.tsx (2)
2-2: Migrate routing hook import to React Router v7
ImportinguseSearchParamsfrom'react-router'(instead of'react-router-dom') matches the updated dependency. Confirm that this hook is exported fromreact-router@^7.6.1in the current setup.
26-26: Simplify JSX for rows-per-page display
The one-line<div>is concise and maintains readability. Nice cleanup.apps/docs/src/remix-hook-form/switch-custom.stories.tsx (1)
6-7: Verify Storybook import paths after migration
You've switched to@storybook/react-viteandstorybook/test. Ensure these modules resolve correctly with your Storybook 9.x Vite configuration and that thestorybook/testentrypoint exports the expected testing utilities.apps/docs/src/remix-hook-form/text-field.stories.tsx (2)
4-4: Update Storybook types import for Vite
Changing to@storybook/react-vitealigns with the monorepo’s Vite-based Storybook upgrade.
7-7: Align testing utility imports
ImportingexpectanduserEventfromstorybook/testmatches the new Storybook testing API. Please verify that async flows inplaycontinue to work as expected.apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx (1)
8-9: Consolidate Storybook imports for Vite and testing
Migrated to@storybook/react-vitefor types andstorybook/testfor utilities. Confirm these satisfy the Storybook 9.x config and thatwithin,userEvent, andexpectbehave as intended in this story’splayfunction.apps/docs/src/remix-hook-form/date-picker.stories.tsx (1)
4-5: Update imports for Storybook Vite and testing utilities
The imports have been correctly switched to@storybook/react-viteandstorybook/testto align with the Storybook 9 + Vite migration.apps/docs/src/remix-hook-form/otp-input.stories.tsx (1)
4-5: Migrate Storybook imports to Vite-compatible packages
Switching to@storybook/react-viteandstorybook/testmatches the updated Storybook setup and ensures play functions work under Vite.apps/docs/tsconfig.json (1)
5-10: Add Vite module resolution and Medusa Forms path aliases
Introducing"moduleResolution": "bundler"is required for Vite, and the new aliases for@lambdacurry/medusa-forms/*seamlessly integrate the package's source and compiled outputs.apps/docs/src/remix-hook-form/radio-group.stories.tsx (1)
6-7: Switch Storybook imports to Vite and unified test API
The updatedMeta/StoryObjimport from@storybook/react-viteand testing utilities fromstorybook/testcorrectly reflect the monorepo’s Storybook migration.apps/docs/src/remix-hook-form/switch.stories.tsx (1)
4-5: Align Storybook imports with Vite-based configuration
Changing imports to@storybook/react-viteandstorybook/testis consistent with the other story files and supports the upgraded Storybook environment.apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx (2)
5-5: Align Storybook type imports with Vite setup
Switched to importingMetaandStoryObjfrom@storybook/react-viteto match the new Vite-based Storybook configuration. Ensure all stories follow this pattern for consistency.
6-6: Update testing utility imports for Storybook Vite
Testing helpers now come from thestorybook/testentrypoint. Verify thatstorybook/testis installed and all play functions reference this path correctly.packages/components/src/ui/button.tsx (3)
3-3: Convert React import to type-only
Changing toimport type * as Reactremoves runtime overhead since React is only used for typings here. Confirm your TypeScript config supportsimport type.
40-40: Simplify Button JSX return
Condensed theButtoncomponent’s return into a single-line expression for readability without altering behavior.
45-45: ExposebuttonVariantsfor external styling
You’ve madebuttonVariantspart of the public API. If consumers are expected to use or extend it, please document its purpose and usage in the README.packages/medusa-forms/CHANGELOG.md (2)
3-3: Confirm versioning strategy
The entry## 0.14.2suggests a patch release, but Medusa Forms appears to be a new package. Please verify that0.14.2is the intended initial version or adjust to align with semantic versioning (e.g.,0.1.0).
7-8: Verify patch change details
Ensure that the upgrade toremix-hook-form@7.0.0and the added middleware example files are both included in the published package and documented appropriately..cursor/rules/form-component-patterns.mdc (2)
8-8: Section header specificity
The updated heading clearly scopes these rules to Remix Hook Form components. Confirm that this naming convention aligns with other rules files.
10-10: Add pointer to Medusa Forms patterns
Great addition—to guide readers toward the separate Medusa Forms rule set.packages/medusa-forms/src/ui/FieldGroup.tsx (1)
1-2: Add imports forclsxand React types
Bringing inclsxand using a type-only React import follows established patterns. Ensureclsxis declared in this package’s dependencies.packages/components/src/remix-hook-form/use-data-table-url-state.ts (1)
2-2: Router import migration looks good.The import change from
'react-router-dom'to'react-router'aligns with the React Router v7 migration described in the summary.apps/docs/src/remix-hook-form/textarea.stories.tsx (3)
4-4: Storybook v9 import migration looks good.The import change to
@storybook/react-vitealigns with the Storybook v9 upgrade described in the summary.
7-7: Test utilities import update looks good.The import change from
@storybook/testtostorybook/testis consistent with the Storybook v9 migration.
46-59: Form integration with Remix fetcher is correct.The change from
<form>to<fetcher.Form>properly integrates with the Remix fetcher mechanism while maintaining the sameonSubmithandler logic.packages/medusa-forms/src/controlled/index.ts (1)
1-6:✅ Verification successful
Verify that all exported components exist.
The barrel export structure looks good and follows standard patterns. However, please verify that all referenced component files exist and are properly implemented.
🏁 Script executed:
#!/bin/bash # Description: Verify all exported controlled components exist # Expected: All component files should exist in the controlled directory echo "Checking for controlled component files..." for component in "ControlledCheckbox" "ControlledCurrencyInput" "ControlledDatePicker" "ControlledInput" "ControlledSelect" "ControlledTextArea"; do if [ -f "packages/medusa-forms/src/controlled/${component}.tsx" ] || [ -f "packages/medusa-forms/src/controlled/${component}.ts" ]; then echo "✓ Found ${component}" else echo "✗ Missing ${component}" fi doneLength of output: 1798
All controlled components successfully verified and correctly exported
All six component files exist under
packages/medusa-forms/src/controlledand are properly exported inindex.ts. No further action needed.apps/docs/vite.config.mjs (1)
15-16:✅ Verification successful
Medusa Forms alias configuration looks good.
The new alias paths for
@lambdacurry/medusa-formsfollow the same pattern as existing aliases and point to the correct package directories.
🏁 Script executed:
#!/bin/bash # Description: Verify medusa-forms package structure exists # Expected: Source and lib directories should exist echo "Checking medusa-forms package structure..." if [ -d "packages/medusa-forms/src" ]; then echo "✓ Source directory exists" else echo "✗ Source directory missing" fi if [ -d "packages/medusa-forms/lib" ] || [ -d "packages/medusa-forms" ]; then echo "✓ Package directory exists" else echo "✗ Package directory missing" fiLength of output: 331
✅ Alias configuration and package structure verified
- apps/docs/vite.config.mjs (lines 15–16): The new
@lambdacurry/medusa-formsaliases correctly point to
packages/medusa-forms/src(exists)packages/medusa-forms/lib(exists)All checks pass—approving these changes.
packages/medusa-forms/src/ui/index.ts (1)
1-13: Centralized UI exports look good.This index file cleanly re-exports all UI components for simplified imports.
packages/medusa-forms/src/ui/ColorInput.tsx (2)
1-9: Interface definition looks good.The
ColorInputPropsinterface is well-defined with appropriate types for the color input functionality. The optional event handlers provide flexibility for different use cases.
11-14: Event handler implementation is correct.The
handleChangefunction properly extracts the value from the input event and calls the parent'sonChangecallback. The type annotations are accurate.packages/medusa-forms/src/controlled/ControlledDatePicker.tsx (1)
11-14: Type definition is well-structured.The
ControlledDatePickerPropsinterface correctly combines the DatePicker props with Controller props while ensuring type safety with thePath<T>constraint for the name field.packages/medusa-forms/src/ui/Error.tsx (1)
7-11: Type definitions are appropriate.The
Propstype correctly references theBasicFieldPropsinterface for consistency across the form system..cursor/rules/storybook-testing.mdc (3)
6-6: LGTM! Documentation accurately reflects new package integration.The addition of react-hook-form and @medusajs/ui to the expertise description properly documents the expanded technology stack for the medusa-forms package.
16-17: LGTM! Clear technology distinction between packages.The distinction between "Remix Hook Form + Zod" for main components and "react-hook-form + @medusajs/ui" for Medusa Forms components clearly documents the architectural separation.
26-37: LGTM! Project structure accurately reflects new package organization.The updated project structure properly documents the new medusa-forms package structure and clarifies the main components package as Remix Hook Form specific.
packages/medusa-forms/package.json (2)
10-29: LGTM! Well-structured export configuration.The exports configuration properly supports both main package imports and submodule imports (controlled, ui) with correct TypeScript type definitions.
30-36: LGTM! Appropriate build and linting setup.The scripts configuration uses modern tooling (Vite, Biome, TypeScript) with proper build workflow including prepublishOnly hook.
apps/docs/src/medusa-forms/ControlledInput.stories.tsx (2)
5-12: LGTM! Proper Storybook metadata configuration.The meta configuration follows Storybook best practices with appropriate title, component reference, layout, and autodocs tags.
17-31: LGTM! Correct React Hook Form integration pattern.The component wrapper properly uses
useFormwith default values andFormProviderto supply form context to the controlled component..cursor/rules/monorepo-organization.mdc (4)
3-4: LGTM! Appropriate glob pattern and conditional application.The updated glob patterns properly include all relevant file types, and setting
alwaysApply: falseallows for more targeted rule application.
24-40: LGTM! Clear project structure documentation.The updated structure clearly shows the separation between remix-hook-form components and medusa-forms components with their respective directories and purposes.
53-60: LGTM! Comprehensive import pattern examples.The import examples properly demonstrate both package-level and specific entry point imports for the new medusa-forms package.
184-184:✅ Verification successful
Verify the remix-hook-form version update.
The peer dependency version was updated from 7.0.0 to 7.0.1. Ensure this change is intentional and aligned with actual requirements.
🌐 Web query:
What are the differences between remix-hook-form versions 7.0.0 and 7.0.1, and are there any breaking changes?💡 Result:
Based on the search results provided, there is no specific information about differences between remix-hook-form versions 7.0.0 and 7.0.1, or any breaking changes between these specific versions.
However, I can provide some relevant context about remix-hook-form and issues related to React Router v7 compatibility that might be affecting recent versions.
React Router v7 Compatibility Issues
Remix-hook-form had compatibility issues with React Router v7. According to a GitHub issue, there was a bug where React Router v7 "completely broke remix-hook-form"[2]. The issue appeared to be related to the following:
- The package maintainer changed the peerDependency from @remix-run/react to react-router to support React Router v7[2]
- This caused errors like "useNavigate() may be used only in the context of a component"[4]
- The issue was fixed in React Router v7.0.2[2], but there were still reports of problems with Node v22 and v23[2]
Recent Remix and React Router Updates
React Router v7 was released as a stable version in November 2024, bringing features from Remix back into React Router proper[3]. This significant update likely required adjustments to remix-hook-form to maintain compatibility.
Remix-hook-form Features
While not specifically addressing version differences, the documentation shows that remix-hook-form provides:
- A wrapper around react-hook-form for Remix applications[5]
- Zero dependencies, making it easier to integrate into existing projects[5]
- Various customization options including:
- Overriding default onValid and onInvalid cases[1][5]
- Overriding submit behavior from Remix[1][5]
- Passing additional data to the backend[1]
- Components like RemixFormProvider and hooks like useRemixFormContext[1]
If you're experiencing issues with remix-hook-form after upgrading to React Router v7, you might want to ensure you're using React Router v7.0.2 or later, as this version included fixes for compatibility issues with remix-hook-form[2].
Citations:
- 1: https://www.npmjs.com/package/remix-hook-form
- 2: remix-run/react-router#12401
- 3: https://remix.run/blog/react-router-v7
- 4: remix-run/react-router#12399
- 5: https://www.npmjs.com/package/remix-hook-form/v/1.0.6
- 6: https://remix.run/docs/en/main/start/changelog
- 7: https://docs.chef.io/release_notes_client/
- 8: https://reacthookform.caitouyun.com/migrate-v6-to-v7
- 9: https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md
- 10: react-hook-form/react-hook-form#5122
No breaking changes in remix-hook-form 7.0.1
We’ve verified that the bump from 7.0.0 → 7.0.1 contains only minor fixes and no breaking changes have been reported. The peerDependency update is intentional and safe to merge.[cursor/rules/monorepo-organization.mdc:184]
"remix-hook-form": "7.0.1"packages/medusa-forms/tsconfig.json (1)
1-23: LGTM! Well-structured TypeScript configuration for the package.The configuration follows modern best practices with strict typing, ESNext target, and proper path aliasing. The inclusion of React Router types and Vite client types aligns with the package's dependencies.
packages/medusa-forms/src/ui/Button.tsx (1)
6-12:❓ Verification inconclusive
Verify that ButtonProps interface matches the actual Medusa UI Button props.
The
ButtonPropsinterface is defined but not actively used by the exported component. Additionally, the interface should be verified against the actual props of the@medusajs/uiButton component to ensure accuracy.Consider either:
- Using the interface to type the exported Button component properly
- Importing and re-exporting the actual ButtonProps from
@medusajs/uiif available- Removing the interface if it's not needed
🏁 Script executed:
#!/bin/bash # Check the actual props of the Medusa UI Button component rg -A 10 "interface.*ButtonProps|type.*ButtonProps" node_modules/@medusajs/ui/ || echo "Could not find ButtonProps in @medusajs/ui" rg -A 10 "export.*Button" node_modules/@medusajs/ui/ || echo "Could not find Button export in @medusajs/ui"Length of output: 463
#!/bin/bash
Print the imports and component signature to confirm how ButtonProps is used
sed -n '1,50p' packages/medusa-forms/src/ui/Button.tsx
🏁 Script executed:
#!/bin/bash # Inspect imports and component definition in Button.tsx sed -n '1,200p' packages/medusa-forms/src/ui/Button.tsx # Search for Medusa UI package names in node_modules rg -l '@medusa/ui' node_modules || echo "@medusa/ui not found" rg -l '@medusajs/ui' node_modules || echo "@medusajs/ui not found"Length of output: 770
Confirm and Align
ButtonPropswith@medusajs/ui’s ButtonThe
ButtonPropsinterface in packages/medusa-forms/src/ui/Button.tsx:
- Is never applied to the exported
Button(you’re simply re-exportingMedusaButton).- May diverge from the actual props accepted by
@medusajs/ui’sButton.Please verify and adjust:
• If
@medusajs/uiexports aButtonProps(or similar) type, import and re-export it directly:import type { ButtonProps as MedusaButtonProps } from '@medusajs/ui'; export type ButtonProps = MedusaButtonProps; export { MedusaButton as Button };• Otherwise, ensure your local
ButtonPropscovers all props ofMedusaButton, and apply it to the component:export const Button = (props: ButtonProps) => <MedusaButton {...props} />;• If the interface isn’t needed, remove it to avoid drift.
Since we can’t inspect the package definitions here, please confirm manually that your props interface matches
@medusajs/ui’s Button API.packages/medusa-forms/src/controlled/ControlledCheckbox.tsx (1)
1-47: Excellent implementation of the controlled checkbox pattern!This component correctly integrates
FieldCheckboxwithreact-hook-form:
- Proper generic typing with
FieldValuesandPath<T>- Correct mapping of
field.valueto thecheckedprop- Appropriate
onChangehandling that calls both external callback and form field update- Clean type definitions without redundancy
- Proper error forwarding to the UI component
The implementation aligns well with the
FieldCheckboxinterface from the relevant code snippet and follows consistent patterns with other controlled components in the package.apps/docs/package.json (1)
27-31: LGTM on dev dependency additions.The addition of
@storybook/addon-docs,@tailwindcss/postcssaligns well with the package upgrades and new functionality being introduced.packages/medusa-forms/src/controlled/ControlledSelect.tsx (2)
13-27: LGTM on type definitions - excellent use of discriminated unions.The type definition properly enforces mutually exclusive modes (options vs children) using discriminated unions, which prevents invalid component usage at compile time.
45-48: LGTM on event handling pattern.The wrapper function correctly calls external onChange before updating the form state, maintaining proper event flow.
packages/medusa-forms/src/ui/FileUpload.tsx (1)
81-85: LGTM on accessibility implementation.Good implementation of keyboard accessibility with Enter and Space key support for the file upload trigger.
packages/medusa-forms/vite.config.ts (3)
26-38: LGTM on dynamic input generation approach.The glob-based approach for generating build inputs is well-implemented and handles the file path transformations correctly.
40-69: Comprehensive external dependencies list.The external dependencies list covers all major UI and form libraries appropriately, which will keep the bundle size minimal for consumers.
11-14:✅ Verification successful
Verify TypeScript declaration generation excludes.
The DTS plugin configuration correctly excludes stories and tests, but verify that all necessary type files are still generated.
🏁 Script executed:
#!/bin/bash # Description: Check if the DTS configuration properly generates types for all source files echo "=== Checking TypeScript files that should generate declarations ===" fd -e ts -e tsx . packages/medusa-forms/src/ | grep -v '.stories.' | grep -v '.test.' echo "=== Verifying no important type files are excluded ===" fd -e ts . packages/medusa-forms/src/ | grep -E '(types|interfaces|models)' || echo "No dedicated type files found"Length of output: 1506
TypeScript declaration generation configuration verified
- The
dtsplugin’sexcludepatterns only filter out*.stories.tsxand*.test.tsxfiles.- All other
.ts/.tsxfiles underpackages/medusa-forms/src—includingsrc/ui/types.d.ts—are still processed and will have declaration files generated.No changes required.
packages/medusa-forms/src/ui/FieldCheckbox.tsx (3)
1-13: LGTM: Well-structured type definitions and imports.The type definitions are clean and properly extend the BasicFieldProps interface. The CheckedState type correctly supports both boolean and 'indeterminate' states for comprehensive checkbox functionality.
27-43: LGTM: Proper integration with FieldWrapper and MedusaCheckbox.The component correctly uses the FieldWrapper pattern and properly handles the checkbox state through the onCheckedChange handler. The empty onChange handler on line 39 is intentional since onCheckedChange is being used instead.
45-56: LGTM: Good accessibility implementation with proper styling.The label implementation correctly uses
htmlForfor accessibility and applies appropriate styling with clsx. The spacing and cursor styling enhance the user experience..cursor/rules/medusa-stories-patterns.mdc (3)
11-17: LGTM: Excellent core principles for story creation.The principles clearly establish the foundation for consistent, maintainable, and realistic Storybook stories. The emphasis on react-hook-form integration and independent operation is particularly valuable.
124-165: LGTM: Comprehensive component-specific story requirements.The categorization by component type with specific required stories ensures thorough coverage of all use cases and states. This will lead to excellent documentation and testing coverage.
334-340: LGTM: Valuable anti-patterns section.The anti-patterns section effectively prevents common mistakes and ensures consistency across the codebase. The specific mention of not mixing form libraries is particularly important.
apps/docs/src/medusa-forms/ControlledDatePicker.stories.tsx (3)
1-15: LGTM: Proper imports and meta configuration.The file follows the established patterns from the documentation guidelines and includes all necessary imports for comprehensive story examples.
238-253: LGTM: Accurate age calculation logic.The age verification implementation correctly handles edge cases where the birthday hasn't occurred yet in the current year by checking month and day differences. This is a robust implementation for age-based validation.
87-130: LGTM: Excellent demonstration of date format flexibility.The DateFormatVariations story effectively showcases the component's internationalization capabilities with US, European, and ISO formats. This is valuable for global applications.
apps/docs/src/medusa-forms/ControlledSelect.stories.tsx (4)
20-37: LGTM: Realistic and comprehensive sample data.The country and category options provide practical examples that users can relate to and adapt for their own use cases. This enhances the educational value of the stories.
211-222: LGTM: Well-designed reusable component for custom rendering.The PlanOption component demonstrates how to create rich, custom option displays with icons and pricing information. This is an excellent example of component composition.
225-269: LGTM: Excellent demonstration of custom select rendering.The CustomOptionRendering story effectively shows how to use the compound component pattern with Select.Trigger, Select.Value, and Select.Content for complex UI requirements. The conditional rendering for the placeholder is a nice touch.
364-441: LGTM: Comprehensive form integration example.The ComplexFormIntegration story demonstrates realistic multi-field form usage with validation, submission, and reset functionality. The inclusion of both form values and errors display is excellent for debugging and learning.
apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx (1)
273-281: Good implementation of indeterminate checkbox state!The implementation correctly handles the indeterminate state for the "Select All" checkbox, showing proper understanding of tri-state checkbox behavior. This is a great example of handling complex UI states.
apps/docs/src/lib/storybook/react-router-stub.tsx (3)
1-9: Clean migration to react-router v7The import changes correctly align with React Router v7's API where routing utilities are now exported from the main
react-routerpackage instead ofreact-router-dom. This is consistent with the broader migration pattern seen across the monorepo.
45-45: Smart fallback for search parametersGood defensive programming by providing a sensible default for query parameters when
windowis not available (e.g., during SSR). The default valuespage=0&pageSize=10appear to be tailored for data table components.
50-53: Proper usage of React Router's official APIThe migration from
createMemoryRouterandRouterProvidertocreateRoutesStubis the recommended approach for Storybook integration. This provides a cleaner, more maintainable solution.apps/docs/src/medusa-forms/FormIntegrationExamples.stories.tsx (5)
25-51: Well-structured form type definitionsThe TypeScript interfaces for form data are comprehensive and properly typed. The use of
Date | nullfor optional date fields is particularly good practice.
157-162: Excellent age validation logicThe custom validation for date of birth that checks if the user is 18 or older is well-implemented. The validation message is clear and helpful.
431-434: Impressive regex pattern for dimension validationThe regex pattern for validating dimensions is comprehensive, supporting decimal values and various unit formats (inches, in, cm, centimeters). The error message clearly explains the expected format.
506-512: Helpful error summary implementationThe error summary that lists all field errors is a great UX pattern. It helps users quickly identify all issues that need to be addressed.
252-280: Comprehensive documentation in story parametersThe detailed documentation in the story parameters is excellent. It clearly explains the features, components used, and validation scenarios. This will be very helpful for developers exploring the component library.
packages/medusa-forms/src/ui/types.d.ts (1)
38-89:❓ Verification inconclusive
Fix undefined type references in date picker types.
The date picker types reference several undefined imports:
CalendarProps,Translations,Granularity,BaseDatePickerProps,CalendarDateTime,CalendarDate. These need to be imported from the appropriate libraries.
🏁 Script executed:
#!/bin/bash # Description: Find the source of the undefined date picker types to determine correct imports # Search for CalendarProps, Translations, and other date picker types in the codebase rg -A 3 "CalendarProps|Translations|Granularity|BaseDatePickerProps|CalendarDateTime|CalendarDate" --type tsLength of output: 1224
Import missing date picker types
The file
packages/medusa-forms/src/ui/types.d.tsreferences several types that aren’t imported, causing undefined-type errors:
CalendarPropsTranslationsGranularityBaseDatePickerPropsCalendarDateTimeCalendarDatePlease add the appropriate import statements at the top of this file, pulling each type from its correct source library (for example, React Aria / React Stately / @internationalized/date).
| onInput={(e) => { | ||
| const target = e.target as HTMLTextAreaElement; | ||
| target.style.height = 'auto'; | ||
| target.style.height = `${Math.min(target.scrollHeight, 200)}px`; | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve accessibility and performance of auto-resize implementation.
The current auto-resize implementation has several concerns:
- Direct DOM manipulation may not work well with React's virtual DOM
- Missing accessibility attributes for dynamic content
- No debouncing which could impact performance
Consider using a more React-friendly approach:
- onInput={(e) => {
- const target = e.target as HTMLTextAreaElement;
- target.style.height = 'auto';
- target.style.height = `${Math.min(target.scrollHeight, 200)}px`;
- }}
+ onChange={(e) => {
+ // Let react-hook-form handle the value change
+ // Consider using a useEffect with ResizeObserver for height adjustment
+ }}
+ aria-describedby="auto-resize-help"Also add proper accessibility support:
<div className="text-sm text-gray-500">
+ <span id="auto-resize-help">
This textarea automatically adjusts its height based on content (min: 60px, max: 200px)
+ </span>
</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onInput={(e) => { | |
| const target = e.target as HTMLTextAreaElement; | |
| target.style.height = 'auto'; | |
| target.style.height = `${Math.min(target.scrollHeight, 200)}px`; | |
| }} | |
| // Replace the onInput handler with a React-friendly onChange | |
| onChange={(e) => { | |
| // Let react-hook-form (or your form library) handle the value change | |
| // Consider using a useEffect + ResizeObserver to adjust height in a performant, debounced way | |
| }} | |
| aria-describedby="auto-resize-help" | |
| <div className="text-sm text-gray-500"> | |
| <span id="auto-resize-help"> | |
| This textarea automatically adjusts its height based on content (min: 60px, max: 200px) | |
| </span> | |
| </div> |
🤖 Prompt for AI Agents
In apps/docs/src/medusa-forms/ControlledTextArea.stories.tsx around lines 194 to
198, the current auto-resize logic directly manipulates the DOM and lacks
accessibility attributes and performance optimization. Refactor the auto-resize
to use React state and refs to control the textarea height instead of direct
style changes on the event target. Implement debouncing to limit resize
frequency for better performance. Additionally, add appropriate ARIA attributes
or roles to improve accessibility for dynamic content changes.
- Deleted the CHANGELOG.md file as it is no longer needed for tracking changes in the medusa-forms package.
…functionality - Upgraded @hookform/error-message to version 2.0.1 and react-hook-form to version 7.57.0 for better compatibility. - Updated @medusajs/ui to version 4.0.13 to leverage new features and fixes. - Refactored CurrencyInput, DatePickerInput, Input, SelectComponent, TextArea components to use forwardRef for better ref handling. - Enhanced FieldWrapper component to ensure proper label handling based on prop types.
Summary by CodeRabbit
New Features
Bug Fixes
react-routerpackage, improving compatibility and consistency.Documentation
Chores