Skip to content

Commit 1c5a4e6

Browse files
authored
Merge pull request #96 from lambda-curry/mohsen/360t-220-add-ref-support-to-textfield-component-in-forms-repo
2 parents 879e7e4 + 0db2c8d commit 1c5a4e6

5 files changed

Lines changed: 28 additions & 9 deletions

File tree

apps/docs/src/remix-hook-form/text-field.stories.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
22
import { TextField } from '@lambdacurry/forms/remix-hook-form/text-field';
33
import { Button } from '@lambdacurry/forms/ui/button';
44
import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite';
5+
import { useRef } from 'react';
56
import { type ActionFunctionArgs, useFetcher } from 'react-router';
67
import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form';
78
import { expect, userEvent } from 'storybook/test';
@@ -38,6 +39,8 @@ const ControlledTextFieldExample = () => {
3839
},
3940
});
4041

42+
const ref = useRef<HTMLInputElement>(null);
43+
4144
return (
4245
<RemixFormProvider {...methods}>
4346
<fetcher.Form onSubmit={methods.handleSubmit}>
@@ -58,6 +61,12 @@ const ControlledTextFieldExample = () => {
5861
suffix="cm"
5962
/>
6063

64+
<div className="flex gap-2 items-end">
65+
<TextField name="refExample" label="Ref Example" placeholder="Enter something, this has a ref" ref={ref} />
66+
67+
<Button onClick={() => ref.current?.focus()}>Focus the input</Button>
68+
</div>
69+
6170
<Button type="submit" className="mt-4">
6271
Submit
6372
</Button>

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lambdacurry/forms",
3-
"version": "0.15.1",
3+
"version": "0.15.2",
44
"type": "module",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import type * as React from 'react';
12
import { TextField as BaseTextField, type TextInputProps as BaseTextFieldProps } from '../ui/text-field';
23
import { FormControl, FormDescription, FormLabel, FormMessage } from './form';
34

45
import { useRemixFormContext } from 'remix-hook-form';
56

67
export type TextFieldProps = Omit<BaseTextFieldProps, 'control'>;
78

8-
export function TextField(props: TextFieldProps) {
9+
export const TextField = function RemixTextField(props: TextFieldProps & { ref?: React.Ref<HTMLInputElement> }) {
910
const { control } = useRemixFormContext();
1011

1112
// Merge the provided components with the default form components
@@ -15,11 +16,13 @@ export function TextField(props: TextFieldProps) {
1516
FormDescription,
1617
FormMessage,
1718
};
18-
19+
1920
const components = {
2021
...defaultComponents,
2122
...props.components,
2223
};
2324

2425
return <BaseTextField control={control} components={components} {...props} />;
25-
}
26+
};
27+
28+
TextField.displayName = 'RemixTextField';

packages/components/src/ui/text-field.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ export interface TextInputProps extends Omit<InputProps, 'prefix' | 'suffix'> {
5757
label?: string;
5858
description?: string;
5959
components?: Partial<FieldComponents> & {
60-
Input?: React.ComponentType<InputProps>;
60+
Input?: React.ComponentType<InputProps & React.RefAttributes<HTMLInputElement>>;
6161
};
6262
prefix?: React.ReactNode;
6363
suffix?: React.ReactNode;
6464
className?: string;
6565
}
6666

67-
export const TextField = ({
67+
export const TextField = function TextField({
6868
control,
6969
name,
7070
label,
@@ -73,8 +73,9 @@ export const TextField = ({
7373
components,
7474
prefix,
7575
suffix,
76+
ref,
7677
...props
77-
}: TextInputProps) => {
78+
}: TextInputProps & { ref?: React.Ref<HTMLInputElement> }) {
7879
// Use the custom Input component if provided, otherwise use the default TextInput
7980
const InputComponent = components?.Input || TextInput;
8081

@@ -98,6 +99,7 @@ export const TextField = ({
9899
<InputComponent
99100
{...field}
100101
{...props}
102+
ref={ref}
101103
className={cn('focus-visible:ring-0 focus-visible:ring-offset-0 border-input', {
102104
'rounded-l-none border-l-0': prefix,
103105
'rounded-r-none border-r-0': suffix,

packages/components/src/ui/text-input.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import type * as React from 'react';
22
import { cn } from './utils';
33

4-
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
4+
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
5+
ref?: React.Ref<HTMLInputElement>;
6+
}
57

6-
function TextInput({ className, type, ...props }: InputProps) {
8+
function TextInput({ className, type, ref, ...props }: InputProps) {
79
return (
810
<input
11+
ref={ref}
912
type={type}
1013
className={cn(
1114
'flex h-10 w-full text-base sm:text-sm rounded-md border border-input bg-background px-3 py-2 ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
@@ -17,4 +20,6 @@ function TextInput({ className, type, ...props }: InputProps) {
1720
);
1821
}
1922

23+
TextInput.displayName = 'TextInput';
24+
2025
export { TextInput };

0 commit comments

Comments
 (0)