diff --git a/apps/docs/.storybook/main.ts b/apps/docs/.storybook/main.ts index fa85d0eb..3ecc947d 100644 --- a/apps/docs/.storybook/main.ts +++ b/apps/docs/.storybook/main.ts @@ -12,8 +12,7 @@ const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ getAbsolutePath('@storybook/addon-links'), - getAbsolutePath('@storybook/addon-essentials'), - getAbsolutePath('@storybook/addon-interactions'), + getAbsolutePath("@storybook/addon-docs") ], framework: { name: getAbsolutePath('@storybook/react-vite'), diff --git a/apps/docs/.storybook/preview.ts b/apps/docs/.storybook/preview.ts index e0568f83..ab220a89 100644 --- a/apps/docs/.storybook/preview.ts +++ b/apps/docs/.storybook/preview.ts @@ -1,4 +1,4 @@ -import type { Preview } from '@storybook/react'; +import type { Preview } from '@storybook/react-vite'; import '../src/main.css'; const preview: Preview = { diff --git a/apps/docs/package.json b/apps/docs/package.json index 70ac54fe..528e69b0 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -15,23 +15,17 @@ "@hookform/resolvers": "^3.9.1", "@lambdacurry/forms": "*", "@lambdacurry/medusa-forms": "*", - "@storybook/addon-essentials": "^8.6.7", - "@storybook/addon-interactions": "^8.6.7", - "@storybook/addon-links": "^8.6.7", - "@storybook/blocks": "^8.6.7", - "@storybook/react": "^8.6.7", - "@storybook/react-vite": "^8.6.7", - "@storybook/test": "^8.6.7", + "@storybook/addon-links": "^9.0.1", + "@storybook/react-vite": "^9.0.1", "react": "^19.0.0", "react-hook-form": "^7.51.0", - "react-router": "^7.0.0", - "react-router-dom": "^7.0.0", + "react-router": "^7.6.1", "remix-hook-form": "^7.0.1", - "storybook": "^8.6.7" + "storybook": "^9.0.1" }, "devDependencies": { - "@medusajs/ui-preset": "^2.8.3", "@react-router/dev": "^7.0.0", + "@storybook/addon-docs": "^9.0.1", "@storybook/test-runner": "^0.22.0", "@storybook/testing-library": "^0.2.2", "@tailwindcss/postcss": "^4.1.8", diff --git a/apps/docs/src/examples/root-example.tsx b/apps/docs/src/examples/root-example.tsx index 586a1a50..4f5ac01a 100644 --- a/apps/docs/src/examples/root-example.tsx +++ b/apps/docs/src/examples/root-example.tsx @@ -1,6 +1,6 @@ +import { Outlet } from 'react-router'; // Example of setting up the middleware in root.tsx import { unstable_extractFormDataMiddleware } from 'remix-hook-form/middleware'; -import { Outlet } from 'react-router-dom'; // Export the middleware for React Router 7 export const unstable_middleware = [unstable_extractFormDataMiddleware()]; diff --git a/apps/docs/src/lib/storybook/react-router-stub.tsx b/apps/docs/src/lib/storybook/react-router-stub.tsx index 901b3f02..fd50abbf 100644 --- a/apps/docs/src/lib/storybook/react-router-stub.tsx +++ b/apps/docs/src/lib/storybook/react-router-stub.tsx @@ -1,38 +1,25 @@ -import type { Decorator } from '@storybook/react'; +import type { Decorator } from '@storybook/react-vite'; import type { ComponentType } from 'react'; import { type ActionFunction, - type IndexRouteObject, type LinksFunction, type LoaderFunction, type MetaFunction, - type NonIndexRouteObject, - RouterProvider, - createMemoryRouter, -} from 'react-router-dom'; + createRoutesStub, +} from 'react-router'; -export type StubRouteObject = StubIndexRouteObject | StubNonIndexRouteObject; - -interface StubNonIndexRouteObject - extends Omit { +export interface StubRouteObject { + path?: string; + index?: boolean; loader?: LoaderFunction; action?: ActionFunction; - children?: StubRouteObject[]; meta?: MetaFunction; links?: LinksFunction; - // biome-ignore lint/suspicious/noExplicitAny: allow any here + // biome-ignore lint/suspicious/noExplicitAny: allow any here for Storybook compatibility Component?: ComponentType; -} - -interface StubIndexRouteObject - extends Omit { - loader?: LoaderFunction; - action?: ActionFunction; children?: StubRouteObject[]; - meta?: MetaFunction; - links?: LinksFunction; - // biome-ignore lint/suspicious/noExplicitAny: allow any here - Component?: ComponentType; + // biome-ignore lint/suspicious/noExplicitAny: allow any here for Storybook compatibility + errorElement?: any; } interface RemixStubOptions { @@ -42,10 +29,9 @@ interface RemixStubOptions { export const withReactRouterStubDecorator = (options: RemixStubOptions): Decorator => { const { routes, initialPath = '/' } = options; - // This outer function runs once when Storybook loads the story meta return (Story, context) => { - // This inner function runs when the story component actually renders + // Map routes to include the Story component if no Component is provided const mappedRoutes = routes.map((route) => ({ ...route, Component: route.Component ?? (() => ), @@ -53,23 +39,18 @@ export const withReactRouterStubDecorator = (options: RemixStubOptions): Decorat // Get the base path (without existing query params from options) const basePath = initialPath.split('?')[0]; - + // Get the current search string from the actual browser window, if available // If not available, use a default search string with parameters needed for the data table - const currentWindowSearch = typeof window !== 'undefined' - ? window.location.search - : '?page=0&pageSize=10'; - + const currentWindowSearch = typeof window !== 'undefined' ? window.location.search : '?page=0&pageSize=10'; + // Combine them for the initial entry const actualInitialPath = `${basePath}${currentWindowSearch}`; - // Create a memory router, initializing it with the path derived from the window's search params - // biome-ignore lint/suspicious/noExplicitAny: - const router = createMemoryRouter(mappedRoutes as any, { - initialEntries: [actualInitialPath], // Use the path combined with window.location.search - }); + // Use React Router's official createRoutesStub + const Stub = createRoutesStub(mappedRoutes); - return ; + return ; }; }; diff --git a/apps/docs/src/main.css b/apps/docs/src/main.css index f11714e0..c1325f75 100644 --- a/apps/docs/src/main.css +++ b/apps/docs/src/main.css @@ -8,7 +8,7 @@ --foreground: hsl(222.2 47.4% 11.2%); --muted: hsl(210 40% 96.1%); - --muted-foreground: hsl(215, 83%, 57%); + --muted-foreground: hsl(215.4 16.3% 46.9%); --popover: hsl(0 0% 100%); --popover-foreground: hsl(222.2 47.4% 11.2%); diff --git a/apps/docs/src/medusa-forms/ControlledInput.stories.tsx b/apps/docs/src/medusa-forms/ControlledInput.stories.tsx index 5624c5e1..66d163e1 100644 --- a/apps/docs/src/medusa-forms/ControlledInput.stories.tsx +++ b/apps/docs/src/medusa-forms/ControlledInput.stories.tsx @@ -1,5 +1,5 @@ import { ControlledInput } from '@lambdacurry/medusa-forms/controlled/ControlledInput'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { FormProvider, useForm } from 'react-hook-form'; const meta = { diff --git a/apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx b/apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx index 08da48f5..223b49fa 100644 --- a/apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx +++ b/apps/docs/src/remix-hook-form/checkbox-custom.stories.tsx @@ -3,8 +3,8 @@ import { Checkbox } from '@lambdacurry/forms/remix-hook-form/checkbox'; import type { FormLabel, FormMessage } from '@lambdacurry/forms/remix-hook-form/form'; import { Button } from '@lambdacurry/forms/ui/button'; import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import type * as React from 'react'; import type { ActionFunctionArgs } from 'react-router'; import { useFetcher } from 'react-router'; diff --git a/apps/docs/src/remix-hook-form/checkbox-list.stories.tsx b/apps/docs/src/remix-hook-form/checkbox-list.stories.tsx index 706aef83..d4f9e9b4 100644 --- a/apps/docs/src/remix-hook-form/checkbox-list.stories.tsx +++ b/apps/docs/src/remix-hook-form/checkbox-list.stories.tsx @@ -2,8 +2,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Checkbox } from '@lambdacurry/forms/remix-hook-form/checkbox'; import { Button } from '@lambdacurry/forms/ui/button'; import { FormMessage } from '@lambdacurry/forms/ui/form'; -import type { Meta, StoryContext, StoryObj } from '@storybook/react'; -import { expect, userEvent } from '@storybook/test'; +import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent } from 'storybook/test'; import type {} from '@testing-library/dom'; import { type ActionFunctionArgs, Form, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; diff --git a/apps/docs/src/remix-hook-form/checkbox.stories.tsx b/apps/docs/src/remix-hook-form/checkbox.stories.tsx index 3a4b0b86..01ba8ff2 100644 --- a/apps/docs/src/remix-hook-form/checkbox.stories.tsx +++ b/apps/docs/src/remix-hook-form/checkbox.stories.tsx @@ -1,8 +1,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Checkbox } from '@lambdacurry/forms/remix-hook-form/checkbox'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryContext, StoryObj } from '@storybook/react'; -import { expect, userEvent } from '@storybook/test'; +import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent } from 'storybook/test'; import { type ActionFunctionArgs, useFetcher } from 'react-router'; import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx b/apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx index d24c5b72..31126488 100644 --- a/apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx +++ b/apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx @@ -1,7 +1,7 @@ import { DataTableRouterForm } from '@lambdacurry/forms/remix-hook-form/data-table-router-form'; import { dataTableRouterParsers } from '@lambdacurry/forms/remix-hook-form/data-table-router-parsers'; import { DataTableColumnHeader } from '@lambdacurry/forms/ui/data-table/data-table-column-header'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import type { ColumnDef } from '@tanstack/react-table'; import { type LoaderFunctionArgs, useLoaderData } from 'react-router'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/date-picker.stories.tsx b/apps/docs/src/remix-hook-form/date-picker.stories.tsx index c0293447..e6af25a0 100644 --- a/apps/docs/src/remix-hook-form/date-picker.stories.tsx +++ b/apps/docs/src/remix-hook-form/date-picker.stories.tsx @@ -1,8 +1,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { DatePicker } from '@lambdacurry/forms/remix-hook-form/date-picker'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import { type ActionFunctionArgs, Form, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx b/apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx index 3d6d5b45..904e4c01 100644 --- a/apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx +++ b/apps/docs/src/remix-hook-form/dropdown-menu-select.stories.tsx @@ -2,8 +2,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { DropdownMenuSelect } from '@lambdacurry/forms/remix-hook-form/dropdown-menu-select'; import { Button } from '@lambdacurry/forms/ui/button'; import { DropdownMenuSelectItem } from '@lambdacurry/forms/ui/dropdown-menu-select-field'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, screen, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, screen, userEvent, within } from 'storybook/test'; import { type ActionFunctionArgs, Form, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/otp-input.stories.tsx b/apps/docs/src/remix-hook-form/otp-input.stories.tsx index 644585c8..96035467 100644 --- a/apps/docs/src/remix-hook-form/otp-input.stories.tsx +++ b/apps/docs/src/remix-hook-form/otp-input.stories.tsx @@ -1,8 +1,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { OTPInput } from '@lambdacurry/forms/remix-hook-form/otp-input'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import { type ActionFunctionArgs, Form, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx b/apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx index 31159318..0002f4e5 100644 --- a/apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx +++ b/apps/docs/src/remix-hook-form/radio-group-custom.stories.tsx @@ -5,8 +5,8 @@ import { Button } from '@lambdacurry/forms/ui/button'; import { FormLabel, FormMessage } from '@lambdacurry/forms/ui/form'; import { cn } from '@lambdacurry/forms/ui/utils'; import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import type * as React from 'react'; import type { ActionFunctionArgs } from 'react-router'; import { Form, useFetcher } from 'react-router'; diff --git a/apps/docs/src/remix-hook-form/radio-group.stories.tsx b/apps/docs/src/remix-hook-form/radio-group.stories.tsx index bc784422..5a34cc17 100644 --- a/apps/docs/src/remix-hook-form/radio-group.stories.tsx +++ b/apps/docs/src/remix-hook-form/radio-group.stories.tsx @@ -3,8 +3,8 @@ import { RadioGroup, type RadioOption } from '@lambdacurry/forms/remix-hook-form import { RadioGroupItem } from '@lambdacurry/forms/remix-hook-form/radio-group-item'; import { Button } from '@lambdacurry/forms/ui/button'; import { Label } from '@lambdacurry/forms/ui/label'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import type { ComponentPropsWithoutRef, ComponentType } from 'react'; import { type ActionFunctionArgs, Form, useFetcher } from 'react-router'; import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form'; diff --git a/apps/docs/src/remix-hook-form/switch-custom.stories.tsx b/apps/docs/src/remix-hook-form/switch-custom.stories.tsx index d6fd6d28..1a210894 100644 --- a/apps/docs/src/remix-hook-form/switch-custom.stories.tsx +++ b/apps/docs/src/remix-hook-form/switch-custom.stories.tsx @@ -3,8 +3,8 @@ import { Switch } from '@lambdacurry/forms/remix-hook-form/switch'; import { Button } from '@lambdacurry/forms/ui/button'; import { FormLabel, FormMessage } from '@lambdacurry/forms/ui/form'; import * as SwitchPrimitives from '@radix-ui/react-switch'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import type * as React from 'react'; import type { ActionFunctionArgs } from 'react-router'; import { useFetcher } from 'react-router'; diff --git a/apps/docs/src/remix-hook-form/switch.stories.tsx b/apps/docs/src/remix-hook-form/switch.stories.tsx index 6f410af7..b3f564eb 100644 --- a/apps/docs/src/remix-hook-form/switch.stories.tsx +++ b/apps/docs/src/remix-hook-form/switch.stories.tsx @@ -1,8 +1,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Switch } from '@lambdacurry/forms/remix-hook-form/switch'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import { type ActionFunctionArgs, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; diff --git a/apps/docs/src/remix-hook-form/text-field-custom.stories.tsx b/apps/docs/src/remix-hook-form/text-field-custom.stories.tsx index ccf7f5c3..d0522c75 100644 --- a/apps/docs/src/remix-hook-form/text-field-custom.stories.tsx +++ b/apps/docs/src/remix-hook-form/text-field-custom.stories.tsx @@ -2,8 +2,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { TextField } from '@lambdacurry/forms/remix-hook-form/text-field'; import { Button } from '@lambdacurry/forms/ui/button'; import { FormLabel, FormMessage } from '@lambdacurry/forms/ui/form'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import type * as React from 'react'; import type { ActionFunctionArgs } from 'react-router'; import { useFetcher } from 'react-router'; diff --git a/apps/docs/src/remix-hook-form/text-field.stories.tsx b/apps/docs/src/remix-hook-form/text-field.stories.tsx index b1c63649..f49cd2e1 100644 --- a/apps/docs/src/remix-hook-form/text-field.stories.tsx +++ b/apps/docs/src/remix-hook-form/text-field.stories.tsx @@ -1,10 +1,10 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { TextField } from '@lambdacurry/forms/remix-hook-form/text-field'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryContext, StoryObj } from '@storybook/react'; -import { expect, userEvent } from '@storybook/test'; +import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite'; import { type ActionFunctionArgs, useFetcher } from 'react-router'; import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form'; +import { expect, userEvent } from 'storybook/test'; import { z } from 'zod'; import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; diff --git a/apps/docs/src/remix-hook-form/textarea-custom.stories.tsx b/apps/docs/src/remix-hook-form/textarea-custom.stories.tsx index 22b71af6..ac8d5308 100644 --- a/apps/docs/src/remix-hook-form/textarea-custom.stories.tsx +++ b/apps/docs/src/remix-hook-form/textarea-custom.stories.tsx @@ -2,8 +2,8 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Textarea } from '@lambdacurry/forms/remix-hook-form/textarea'; import { Button } from '@lambdacurry/forms/ui/button'; import { FormControl, FormItem, FormLabel, FormMessage } from '@lambdacurry/forms/ui/form'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, userEvent, within } from 'storybook/test'; import * as React from 'react'; import type { ActionFunctionArgs } from 'react-router'; import { useFetcher } from 'react-router'; diff --git a/apps/docs/src/remix-hook-form/textarea.stories.tsx b/apps/docs/src/remix-hook-form/textarea.stories.tsx index be8fcd58..7cfdfcf4 100644 --- a/apps/docs/src/remix-hook-form/textarea.stories.tsx +++ b/apps/docs/src/remix-hook-form/textarea.stories.tsx @@ -1,10 +1,10 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Textarea } from '@lambdacurry/forms/remix-hook-form/textarea'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { type ActionFunctionArgs, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; +import { expect, userEvent, within } from 'storybook/test'; import { z } from 'zod'; import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; @@ -43,7 +43,7 @@ const ControlledTextareaExample = () => { return ( -
+