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 (
- (
-
-
-
- )}
- />
- );
+ const components = {
+ FormControl: RemixFormControl,
+ FormLabel: RemixFormLabel,
+ FormDescription: RemixFormDescription,
+ FormMessage: RemixFormMessage,
+ };
+
+ return ;
}
diff --git a/packages/components/src/ui/calendar.tsx b/packages/components/src/ui/calendar.tsx
index fd4dbb0e..77141b67 100644
--- a/packages/components/src/ui/calendar.tsx
+++ b/packages/components/src/ui/calendar.tsx
@@ -1,6 +1,6 @@
import type * as React from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
-import { DayPicker } from 'react-day-picker';
+import { type CustomComponents, DayPicker } from 'react-day-picker';
import { cn } from '../../lib/utils';
import { buttonVariants } from './button';
@@ -42,9 +42,9 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
...classNames,
}}
components={{
- IconLeft: ({ ...props }) => ,
- IconRight: ({ ...props }) => ,
- }}
+ IconLeft: ({ ...props }) => ,
+ IconRight: ({ ...props }) => ,
+ } as Partial}
{...props}
/>
);
diff --git a/packages/components/src/ui/checkbox.tsx b/packages/components/src/ui/checkbox.tsx
index f4041db7..4286ae42 100644
--- a/packages/components/src/ui/checkbox.tsx
+++ b/packages/components/src/ui/checkbox.tsx
@@ -1,4 +1,4 @@
-import { type ComponentPropsWithoutRef, type ReactNode, forwardRef, type ElementRef } from 'react';
+import { type ComponentPropsWithoutRef, type ReactNode, forwardRef, } from 'react';
// biome-ignore lint/style/noNamespaceImport: from Radix
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { Check } from 'lucide-react';
@@ -26,16 +26,16 @@ export interface CheckboxProps<
components?: Partial;
}
-const Checkbox = forwardRef, CheckboxProps>(
+const Checkbox = forwardRef(
({ control, name, className, label, description, components, ...props }, ref) => (
(
-
+
;
}
-export const DatePicker = forwardRef(
+export const DatePicker = forwardRef(
({ control, name, label, description, className, labelClassName, buttonClassName, components }, ref) => {
return (
(
-
+
{label && (
{label}
@@ -47,7 +47,7 @@ export const DatePicker = forwardRef(