Skip to content

Commit b71b825

Browse files
Fix build error by removing @remix-run dependencies in docs app
1 parent 2c82715 commit b71b825

10 files changed

Lines changed: 483 additions & 521 deletions

apps/docs/src/lib/storybook/remix-mock.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import React from 'react';
2+
import { Form as RouterForm } from 'react-router-dom';
23

3-
// Mock types from @remix-run/node
4+
// Mock types that were previously from @remix-run/node
45
export type ActionFunction = (args: any) => Promise<any>;
56
export type ActionFunctionArgs = any;
67
export type LoaderFunction = (args: any) => Promise<any>;
78
export type LinksFunction = () => Array<{ rel: string; href: string }>;
89
export type MetaFunction = () => Record<string, string>;
910

10-
// Mock components from @remix-run/react
11+
// Mock components that were previously from @remix-run/react
1112
export const Form: React.FC<React.FormHTMLAttributes<HTMLFormElement>> = ({ children, ...props }) => (
12-
<form {...props}>{children}</form>
13+
<RouterForm {...props}>{children}</RouterForm>
1314
);
1415

1516
export const useFetcher = () => {
@@ -33,9 +34,9 @@ export const useFetcher = () => {
3334
};
3435
};
3536

36-
// Mock createRemixStub from @remix-run/testing
37+
// Mock createRemixStub that was previously from @remix-run/testing
3738
export const createRemixStub = (options: any) => {
38-
const { Component } = options;
39+
const { Component } = options[0] || {};
3940
return {
4041
Component: () => <Component />,
4142
};

apps/docs/src/remix-hook-form/checkbox-list.stories.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { zodResolver } from '@hookform/resolvers/zod';
22
import { Checkbox } from '@lambdacurry/forms/remix-hook-form/checkbox';
33
import { Button } from '@lambdacurry/forms/ui/button';
44
import { FormMessage } from '@lambdacurry/forms/ui/form';
5-
import type { ActionFunctionArgs } from '@remix-run/node';
6-
import { useFetcher } from '@remix-run/react';
7-
import { Form } from '@remix-run/react';
5+
import type { ActionFunctionArgs } from '../lib/storybook/remix-mock';
6+
import { useFetcher, Form } from '../lib/storybook/remix-mock';
87
import type { Meta, StoryContext, StoryObj } from '@storybook/react';
98
import { expect, userEvent } from '@storybook/test';
109
import type {} from '@testing-library/dom';
Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,79 @@
11
import { zodResolver } from '@hookform/resolvers/zod';
22
import { DatePicker } from '@lambdacurry/forms/remix-hook-form/date-picker';
33
import { Button } from '@lambdacurry/forms/ui/button';
4-
import type { ActionFunctionArgs } from '@remix-run/node';
5-
import { Form, useFetcher } from '@remix-run/react';
6-
import type { Meta, StoryContext, StoryObj } from '@storybook/react';
7-
import { expect, userEvent, waitFor, within } from '@storybook/test';
8-
import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form';
4+
import type { ActionFunctionArgs } from '../lib/storybook/remix-mock';
5+
import { Form, useFetcher } from '../lib/storybook/remix-mock';
6+
import type { Meta, StoryObj } from '@storybook/react';
7+
import { expect, userEvent, within } from '@storybook/test';
8+
import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form';
99
import { z } from 'zod';
1010
import { withRemixStubDecorator } from '../lib/storybook/remix-stub';
1111

1212
const formSchema = z.object({
13-
eventDate: z.coerce.date(),
13+
date: z.date({
14+
required_error: 'Please select a date',
15+
}),
1416
});
1517

1618
type FormData = z.infer<typeof formSchema>;
1719

18-
const DatePickerExample = () => {
19-
const fetcher = useFetcher<{ message?: string }>();
20+
const ControlledDatePickerExample = () => {
21+
const fetcher = useFetcher<{ message: string; date: string }>();
2022
const methods = useRemixForm<FormData>({
2123
resolver: zodResolver(formSchema),
2224
defaultValues: {
23-
eventDate: undefined,
25+
date: undefined,
2426
},
2527
fetcher,
2628
submitConfig: {
2729
action: '/',
2830
method: 'post',
2931
},
32+
submitHandlers: {
33+
onValid: (data) => {
34+
fetcher.submit(
35+
createFormData({
36+
date: data.date.toISOString(),
37+
}),
38+
{
39+
method: 'post',
40+
action: '/',
41+
},
42+
);
43+
},
44+
},
3045
});
3146

3247
return (
3348
<RemixFormProvider {...methods}>
3449
<Form onSubmit={methods.handleSubmit}>
35-
<DatePicker name="eventDate" label="Event Date" description="Choose the date for your event." />
36-
<Button type="submit" className="mt-4">
37-
Submit
38-
</Button>
39-
{fetcher.data?.message && <p className="mt-2 text-green-600">{fetcher.data.message}</p>}
50+
<div className="space-y-4">
51+
<DatePicker name="date" label="Select a date" />
52+
<Button type="submit" className="mt-4">
53+
Submit
54+
</Button>
55+
{fetcher.data?.date && (
56+
<div className="mt-4">
57+
<p className="text-sm font-medium">Submitted with date:</p>
58+
<p className="text-sm text-gray-500">{new Date(fetcher.data.date).toLocaleDateString()}</p>
59+
</div>
60+
)}
61+
</div>
4062
</Form>
4163
</RemixFormProvider>
4264
);
4365
};
4466

45-
// Action function for form submission
4667
const handleFormSubmission = async (request: Request) => {
47-
const { errors, receivedValues: defaultValues } = await getValidatedFormData<FormData>(
48-
request,
49-
zodResolver(formSchema),
50-
);
68+
const { data, errors } = await getValidatedFormData<FormData>(request, zodResolver(formSchema));
5169

5270
if (errors) {
53-
return { errors, defaultValues };
71+
return { errors };
5472
}
5573

56-
return { message: 'Form submitted successfully' };
74+
return { message: 'Date selected successfully', date: data.date.toISOString() };
5775
};
5876

59-
// Storybook configuration
6077
const meta: Meta<typeof DatePicker> = {
6178
title: 'RemixHookForm/DatePicker',
6279
component: DatePicker,
@@ -65,7 +82,7 @@ const meta: Meta<typeof DatePicker> = {
6582
decorators: [
6683
withRemixStubDecorator({
6784
root: {
68-
Component: DatePickerExample,
85+
Component: ControlledDatePickerExample,
6986
action: async ({ request }: ActionFunctionArgs) => handleFormSubmission(request),
7087
},
7188
}),
@@ -75,48 +92,33 @@ const meta: Meta<typeof DatePicker> = {
7592
export default meta;
7693
type Story = StoryObj<typeof meta>;
7794

78-
const testDefaultValues = ({ canvas }: StoryContext) => {
79-
const datePickerButton = canvas.getByRole('button', { name: 'Event Date' });
80-
expect(datePickerButton).toHaveTextContent('Event Date');
81-
};
82-
83-
const testDateSelection = async ({ canvas }: StoryContext) => {
84-
const datePickerButton = canvas.getByRole('button', { name: 'Event Date' });
85-
await userEvent.click(datePickerButton);
86-
87-
await waitFor(async () => {
88-
const popover = document.querySelector('[role="dialog"]');
89-
expect(popover).not.toBeNull();
90-
91-
if (popover) {
92-
const calendar = within(popover as HTMLElement).getByRole('grid');
93-
expect(calendar).toBeInTheDocument();
94-
95-
const dateCell = within(calendar).getByText('15');
96-
expect(dateCell).toBeInTheDocument();
97-
await userEvent.click(dateCell);
98-
}
99-
});
100-
101-
const dateToSelect = '15';
102-
await waitFor(() => {
103-
const updatedDatePickerButton = canvas.getByRole('button', { name: new RegExp(dateToSelect, 'i') });
104-
expect(updatedDatePickerButton).toBeInTheDocument();
105-
});
106-
};
107-
108-
const testSubmission = async ({ canvas }: StoryContext) => {
109-
const submitButton = canvas.getByRole('button', { name: 'Submit' });
110-
await userEvent.click(submitButton);
111-
112-
await expect(canvas.findByText('Form submitted successfully')).resolves.toBeInTheDocument();
113-
};
114-
115-
// Stories
116-
export const Tests: Story = {
117-
play: async (storyContext) => {
118-
testDefaultValues(storyContext);
119-
await testDateSelection(storyContext);
120-
await testSubmission(storyContext);
95+
export const Default: Story = {
96+
parameters: {
97+
docs: {
98+
description: {
99+
story: 'A date picker component for selecting a date.',
100+
},
101+
},
102+
},
103+
play: async ({ canvasElement }) => {
104+
const canvas = within(canvasElement);
105+
106+
// Open the date picker
107+
const datePickerButton = canvas.getByRole('button', { name: /select a date/i });
108+
await userEvent.click(datePickerButton);
109+
110+
// Select a date (today)
111+
const today = new Date();
112+
const formattedDate = today.getDate().toString();
113+
const dateButton = canvas.getByRole('button', { name: new RegExp(`^${formattedDate}$`) });
114+
await userEvent.click(dateButton);
115+
116+
// Submit the form
117+
const submitButton = canvas.getByRole('button', { name: 'Submit' });
118+
await userEvent.click(submitButton);
119+
120+
// Check if the selected date is displayed
121+
const selectedDate = new Date(today).toLocaleDateString();
122+
await expect(await canvas.findByText(selectedDate)).toBeInTheDocument();
121123
},
122124
};

0 commit comments

Comments
 (0)