From 871b81de2fadcb317398e9bafd627e121d61ca7e Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 03:43:26 +0000 Subject: [PATCH 1/2] feat: Add comprehensive ControlledSelect Storybook stories - 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 --- .../medusa-forms/ControlledSelect.stories.tsx | 475 ++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 apps/docs/src/medusa-forms/ControlledSelect.stories.tsx diff --git a/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx b/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx new file mode 100644 index 00000000..a5f7daeb --- /dev/null +++ b/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx @@ -0,0 +1,475 @@ +import { ControlledSelect } from '@lambdacurry/medusa-forms/controlled/ControlledSelect'; +import { Select } from '@lambdacurry/medusa-forms/ui/Select'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useState } from 'react'; + +const meta = { + title: 'Medusa Forms/Controlled Select', + component: ControlledSelect, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Sample options for stories +const countryOptions = [ + { label: 'United States', value: 'us' }, + { label: 'Canada', value: 'ca' }, + { label: 'United Kingdom', value: 'uk' }, + { label: 'Germany', value: 'de' }, + { label: 'France', value: 'fr' }, + { label: 'Japan', value: 'jp' }, + { label: 'Australia', value: 'au' }, +]; + +const categoryOptions = [ + { label: 'Electronics', value: 'electronics' }, + { label: 'Clothing', value: 'clothing' }, + { label: 'Books', value: 'books' }, + { label: 'Home & Garden', value: 'home-garden' }, + { label: 'Sports', value: 'sports' }, +]; + +// 1. Basic Single Select +const BasicSingleSelectForm = () => { + const form = useForm({ + defaultValues: { + country: '', + }, + }); + + return ( + +
+ +
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const BasicSingleSelect: Story = { + render: () => , +}; + +// 2. Single Select with Default Value +const DefaultValueSelectForm = () => { + const form = useForm({ + defaultValues: { + country: 'us', + }, + }); + + return ( + +
+ +
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const WithDefaultValue: Story = { + render: () => , +}; + +// 3. Required Field Validation +const RequiredValidationForm = () => { + const form = useForm({ + defaultValues: { + requiredCountry: '', + }, + }); + + const onSubmit = (data: any) => { + alert(`Form submitted with: ${JSON.stringify(data)}`); + }; + + return ( + +
+ +
+ + {form.formState.errors.requiredCountry && ( +
+ {form.formState.errors.requiredCountry.message} +
+ )} +
+
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+ +
+ ); +}; + +export const RequiredValidation: Story = { + render: () => , +}; + +// 4. Loading States +const LoadingStateForm = () => { + const [isLoading, setIsLoading] = useState(false); + const form = useForm({ + defaultValues: { + country: '', + }, + }); + + const toggleLoading = () => { + setIsLoading(!isLoading); + }; + + return ( + +
+ +
+ +
+
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+ Loading: {isLoading.toString()} +
+
+
+ ); +}; + +export const LoadingState: Story = { + render: () => , +}; + +// 5. Custom Option Rendering (using children) +const CustomOptionRenderingForm = () => { + const form = useForm({ + defaultValues: { + customSelect: '', + }, + }); + + return ( + +
+ + + + + +
+ + Premium Plan + ($29/mo) +
+
+ +
+ 💎 + Standard Plan + ($19/mo) +
+
+ +
+ 🌱 + Basic Plan + ($9/mo) +
+
+
+
+
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const CustomOptionRendering: Story = { + render: () => , +}; + +// 6. Disabled State +const DisabledStateForm = () => { + const form = useForm({ + defaultValues: { + disabledSelect: 'us', + }, + }); + + return ( + +
+ +
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const DisabledState: Story = { + render: () => , +}; + +// 7. Error State +const ErrorStateForm = () => { + const form = useForm({ + defaultValues: { + errorSelect: '', + }, + }); + + // Manually set an error for demonstration + form.setError('errorSelect', { + type: 'manual', + message: 'This field has an error', + }); + + return ( + +
+ + {form.formState.errors.errorSelect && ( +
+ {form.formState.errors.errorSelect.message} +
+ )} +
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const ErrorState: Story = { + render: () => , +}; + +// 8. Small Size Variant +const SmallSizeForm = () => { + const form = useForm({ + defaultValues: { + smallSelect: '', + }, + }); + + return ( + +
+ +
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const SmallSize: Story = { + render: () => , +}; + +// 9. Complex Form Integration +const ComplexFormIntegration = () => { + const form = useForm({ + defaultValues: { + country: '', + category: '', + plan: '', + priority: '', + }, + }); + + const onSubmit = (data: any) => { + alert(`Complete form submitted: ${JSON.stringify(data, null, 2)}`); + }; + + return ( + +
+ + + + + + + + +
+ + + +
+ +
+ Form Values: +
{JSON.stringify(form.watch(), null, 2)}
+
+ +
+ Form Errors: +
+            {JSON.stringify(form.formState.errors, null, 2)}
+          
+
+ +
+ ); +}; + +export const ComplexFormIntegration: Story = { + render: () => , +}; + +// 10. Interactive Demo with onChange Handler +const InteractiveDemoForm = () => { + const [selectedValue, setSelectedValue] = useState(''); + const form = useForm({ + defaultValues: { + interactiveSelect: '', + }, + }); + + const handleSelectChange = (value: unknown) => { + setSelectedValue(value as string); + console.log('Select value changed:', value); + }; + + return ( + +
+ +
+ External State Value: {selectedValue || 'None'} +
+
+ Form Value: {JSON.stringify(form.watch(), null, 2)} +
+
+
+ ); +}; + +export const InteractiveDemo: Story = { + render: () => , +}; + From eb24bde0b419a317c1d5ccb423f43cd74474d9a2 Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 03:52:13 +0000 Subject: [PATCH 2/2] fix: Resolve identifier conflicts and import issues in Storybook stories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- .../src/medusa-forms/ControlledCheckbox.stories.tsx | 6 +++--- .../docs/src/medusa-forms/ControlledSelect.stories.tsx | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx b/apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx index 2c22b898..e75df06c 100644 --- a/apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx +++ b/apps/docs/src/medusa-forms/ControlledCheckbox.stories.tsx @@ -1,4 +1,4 @@ -import { ControlledCheckbox } from '@lambdacurry/medusa-forms/controlled'; +import { ControlledCheckbox } from '@lambdacurry/medusa-forms/controlled/ControlledCheckbox'; import type { Meta, StoryObj } from '@storybook/react-vite'; import React from 'react'; import { FormProvider, useForm } from 'react-hook-form'; @@ -306,7 +306,7 @@ export const MultipleCheckboxes: Story = { }; // Form Integration Example Story -const CompleteFormExample = () => { +const CompleteFormExampleComponent = () => { const form = useForm({ defaultValues: { username: '', @@ -392,5 +392,5 @@ const CompleteFormExample = () => { }; export const CompleteFormExample: Story = { - render: () => , + render: () => , }; diff --git a/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx b/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx index a5f7daeb..00893d50 100644 --- a/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx +++ b/apps/docs/src/medusa-forms/ControlledSelect.stories.tsx @@ -136,7 +136,7 @@ const RequiredValidationForm = () => { ); }; -export const RequiredValidation: Story = { +export const SelectRequiredValidation: Story = { render: () => , }; @@ -266,7 +266,7 @@ const DisabledStateForm = () => { ); }; -export const DisabledState: Story = { +export const SelectDisabledState: Story = { render: () => , }; @@ -306,7 +306,7 @@ const ErrorStateForm = () => { ); }; -export const ErrorState: Story = { +export const SelectErrorState: Story = { render: () => , }; @@ -341,7 +341,7 @@ export const SmallSize: Story = { }; // 9. Complex Form Integration -const ComplexFormIntegration = () => { +const ComplexFormIntegrationComponent = () => { const form = useForm({ defaultValues: { country: '', @@ -431,7 +431,7 @@ const ComplexFormIntegration = () => { }; export const ComplexFormIntegration: Story = { - render: () => , + render: () => , }; // 10. Interactive Demo with onChange Handler