diff --git a/.changeset/heavy-dragons-drop.md b/.changeset/heavy-dragons-drop.md new file mode 100644 index 00000000..66edcada --- /dev/null +++ b/.changeset/heavy-dragons-drop.md @@ -0,0 +1,6 @@ +--- +"@lambdacurry/forms": minor +"@lambdacurry/forms-docs": minor +--- + +Added remix textarea story and fixes a react error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff5df6cb..5743076d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,3 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Send a Slack notification if a publish happens - if: steps.changesets.outputs.published == 'true' - run: my-slack-bot send-notification --message "A new version of ${GITHUB_REPOSITORY} was published!" diff --git a/.vscode/settings.json b/.vscode/settings.json index 88ffd366..7c6b24e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,14 @@ { - "cSpell.words": ["autodocs", "biomejs", "Filenaming", "hookform", "isbot", "lucide", "shadcn", "sonner"] + "cSpell.words": ["autodocs", "biomejs", "Filenaming", "hookform", "isbot", "lucide", "shadcn", "sonner"], + "editor.defaultFormatter": "biomejs.biome", + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit", + "source.organizeImports.biome": "explicit" + } } diff --git a/README.md b/README.md index f4aee75e..d7e71b87 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Welcome! -Checkout our [Storybook Documentation](https://lambda-curry.github.io/forms/?path=/docs/helloworld-start-here--docs) to see the components in action and get started. +Checkout our [Storybook Documentation](https://lambda-curry.github.io/forms/?path=/docs/0-1-hello-world-start-here--docs) to see the components in action and get started. ## Getting Started @@ -10,7 +10,7 @@ Step 1: Install the dependencies yarn install ``` -Note: You may need to enable corepack for yarn v4 by running `corepack enable` before intstalling the dependencies. +Note: You may need to enable corepack for yarn v4 by running `corepack enable` before installing the dependencies. Step 2: Start Storybook diff --git a/apps/docs/CHANGELOG.md b/apps/docs/CHANGELOG.md deleted file mode 100644 index ca501d40..00000000 --- a/apps/docs/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# @lambdacurry/forms-docs - -## 0.1.1 - -### Patch Changes - -- d3ab83e: Fixed errors and versioning differences -- Updated dependencies [d3ab83e] - - @lambdacurry/forms@0.0.2 diff --git a/apps/docs/src/remix/remix-textarea.stories.tsx b/apps/docs/src/remix/remix-textarea.stories.tsx index 53e4d905..c23f042a 100644 --- a/apps/docs/src/remix/remix-textarea.stories.tsx +++ b/apps/docs/src/remix/remix-textarea.stories.tsx @@ -1,4 +1,6 @@ import { zodResolver } from '@hookform/resolvers/zod'; +import { RemixTextarea } from '@lambdacurry/forms/remix/remix-textarea'; +import { Button } from '@lambdacurry/forms/ui/button'; import type { ActionFunctionArgs } from '@remix-run/node'; import { useFetcher } from '@remix-run/react'; import type { Meta, StoryContext, StoryObj } from '@storybook/react'; @@ -6,8 +8,6 @@ import { expect, userEvent, within } from '@storybook/test'; import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form'; import { z } from 'zod'; import { withRemixStubDecorator } from '../lib/storybook/remix-stub'; -import { RemixTextarea } from '@lambdacurry/forms/remix/remix-textarea'; -import { Button } from '@lambdacurry/forms/ui/button'; const formSchema = z.object({ comment: z.string().min(10, 'Comment must be at least 10 characters'), @@ -37,9 +37,6 @@ const ControlledTextareaExample = () => { Submit {fetcher.data?.message &&

{fetcher.data.message}

} - {methods.formState.errors.comment && ( -

{methods.formState.errors.comment.message}

- )} ); @@ -54,7 +51,7 @@ const handleFormSubmission = async (request: Request) => { } = await getValidatedFormData(request, zodResolver(formSchema)); if (errors) { - return { errors, defaultValues }; + return { defaultValues }; } if (data.comment.includes(BLOCKED_CONTENT)) { @@ -108,6 +105,9 @@ const testInvalidSubmission = async ({ canvasElement }: { canvasElement: HTMLEle await userEvent.type(textarea, 'short'); await userEvent.click(submitButton); + // Wait for any state updates + await new Promise((resolve) => setTimeout(resolve, 100)); + expect(canvas.getByText((content) => content.includes('Comment must be at least 10 characters'))).toBeInTheDocument(); }; @@ -149,6 +149,9 @@ const testValidSubmission = async ({ canvasElement }: { canvasElement: HTMLEleme await userEvent.type(textarea, 'This is a valid comment that is long enough'); await userEvent.click(submitButton); + // Wait for any state updates + await new Promise((resolve) => setTimeout(resolve, 100)); + // Check for success message await expect(canvas.getByText('Comment submitted successfully')).toBeInTheDocument(); }; diff --git a/packages/components/src/remix/remix-checkbox.tsx b/packages/components/src/remix/remix-checkbox.tsx index b486201c..f7424234 100644 --- a/packages/components/src/remix/remix-checkbox.tsx +++ b/packages/components/src/remix/remix-checkbox.tsx @@ -1,15 +1,13 @@ -import { useRemixFormContext } from 'remix-hook-form' -import { Checkbox, type CheckboxProps } from '../ui/checkbox' +import { useRemixFormContext } from 'remix-hook-form'; +import { Checkbox, type CheckboxProps } from '../ui/checkbox'; import { RemixFormControl, RemixFormDescription, RemixFormLabel, RemixFormMessage } from './remix-form'; -import type { FieldComponents } from '../ui/form'; export type RemixCheckboxProps = Omit; export function RemixCheckbox(props: RemixCheckboxProps) { const { control } = useRemixFormContext(); - - const components: Partial = { + const components = { FormDescription: RemixFormDescription, FormControl: RemixFormControl, FormLabel: RemixFormLabel, @@ -17,4 +15,4 @@ export function RemixCheckbox(props: RemixCheckboxProps) { }; return ; -} \ No newline at end of file +} diff --git a/packages/components/src/remix/remix-form.tsx b/packages/components/src/remix/remix-form.tsx index d0a8a5fb..9c8dd438 100644 --- a/packages/components/src/remix/remix-form.tsx +++ b/packages/components/src/remix/remix-form.tsx @@ -1,13 +1,8 @@ -import { type ReactNode, useContext, forwardRef } from 'react'; -import type { - KeepStateOptions, - FieldValues, - UseFormReturn, - UseFormRegister, -} from 'react-hook-form'; +import { type ReactNode, forwardRef, useContext } from 'react'; +import type { BaseSyntheticEvent, ComponentPropsWithoutRef } from 'react'; +import type { FieldValues, KeepStateOptions, UseFormRegister, UseFormReturn } from 'react-hook-form'; import { useRemixFormContext } from 'remix-hook-form'; -import { FormLabel, FormControl, FormDescription, FormMessage, FormFieldContext, FormItemContext } from '../ui/form'; -import type { BaseSyntheticEvent, ComponentPropsWithoutRef, } from 'react'; +import { FormControl, FormDescription, FormFieldContext, FormItemContext, FormLabel, FormMessage } from '../ui/form'; export interface RemixFormProviderProps extends Omit, 'handleSubmit' | 'reset'> { @@ -40,36 +35,40 @@ export const useRemixFormField = () => { }; }; - export const RemixFormLabel = forwardRef>((props, ref) => ( )); RemixFormLabel.displayName = 'RemixFormLabel'; -export const RemixFormControl = forwardRef>((props, ref) => { - const { error, formItemId, formDescriptionId, formMessageId } = useRemixFormField(); - return ( - - ); -}); +export const RemixFormControl = forwardRef>( + (props, ref) => { + const { error, formItemId, formDescriptionId, formMessageId } = useRemixFormField(); + return ( + + ); + }, +); RemixFormControl.displayName = 'RemixFormControl'; -export const RemixFormDescription = forwardRef>((props, ref) => { - const { formDescriptionId } = useRemixFormField(); - return ; -}); +export const RemixFormDescription = forwardRef>( + (props, ref) => { + const { formDescriptionId } = useRemixFormField(); + return ; + }, +); RemixFormDescription.displayName = 'RemixFormDescription'; -export const RemixFormMessage = forwardRef>((props, ref) => { - const { error, formMessageId } = useRemixFormField(); - return ; -}); +export const RemixFormMessage = forwardRef>( + (props, ref) => { + const { error, formMessageId } = useRemixFormField(); + return ; + }, +); RemixFormMessage.displayName = 'RemixFormMessage'; - diff --git a/packages/components/src/remix/remix-switch.tsx b/packages/components/src/remix/remix-switch.tsx index 111a073b..02d0734d 100644 --- a/packages/components/src/remix/remix-switch.tsx +++ b/packages/components/src/remix/remix-switch.tsx @@ -1,8 +1,7 @@ import type { ComponentPropsWithoutRef } from 'react'; -import { useRemixFormContext } from 'remix-hook-form' -import { Switch } from '../ui/switch' +import { useRemixFormContext } from 'remix-hook-form'; +import { Switch } from '../ui/switch'; import { RemixFormControl, RemixFormDescription, RemixFormLabel, RemixFormMessage } from './remix-form'; -import type { FieldComponents } from '../ui/form'; export interface RemixSwitchProps extends Omit, 'control'> { name: string; @@ -13,7 +12,7 @@ export interface RemixSwitchProps extends Omit = { + const components = { FormDescription: RemixFormDescription, FormControl: RemixFormControl, FormLabel: RemixFormLabel, @@ -21,14 +20,6 @@ export function RemixSwitch({ name, label, description, ...props }: RemixSwitchP }; return ( - + ); } - diff --git a/packages/components/src/remix/remix-text-field.tsx b/packages/components/src/remix/remix-text-field.tsx index e68c5fb6..663f2d22 100644 --- a/packages/components/src/remix/remix-text-field.tsx +++ b/packages/components/src/remix/remix-text-field.tsx @@ -1,6 +1,5 @@ import { useRemixFormContext } from 'remix-hook-form'; import { TextField, type TextFieldProps } from '../ui/text-field'; -import type { FieldComponents } from '../ui/form'; import { RemixFormControl, RemixFormDescription, RemixFormLabel, RemixFormMessage } from './remix-form'; export type RemixTextFieldProps = Omit; @@ -8,7 +7,7 @@ export type RemixTextFieldProps = Omit; export function RemixTextField(props: RemixTextFieldProps) { const { control } = useRemixFormContext(); - const components: Partial = { + const components = { FormControl: RemixFormControl, FormLabel: RemixFormLabel, FormDescription: RemixFormDescription, diff --git a/packages/components/src/remix/remix-textarea.tsx b/packages/components/src/remix/remix-textarea.tsx index 19d025a9..c48ea263 100644 --- a/packages/components/src/remix/remix-textarea.tsx +++ b/packages/components/src/remix/remix-textarea.tsx @@ -1,23 +1,18 @@ import { useRemixFormContext } from 'remix-hook-form'; import { Textarea, type TextareaProps } from '../ui/textarea'; -import { FormField, FormItem } from '../ui/form'; -export interface RemixTextareaProps extends Omit { - label?: string; - description?: string; -} +import { RemixFormControl, RemixFormDescription, RemixFormLabel, RemixFormMessage } from './remix-form'; + +export type RemixTextareaProps = Omit; export function RemixTextarea(props: RemixTextareaProps) { const { control } = useRemixFormContext(); - return ( - ( - -