fix(number-input): ignore name prop in getNumberInputProps (#5762)

* fix(number-input): ignore name prop in getNumberInputProps

* fix(number-input): react-hook-form test case

* chore(number-input): assert no duplicate name attribute
This commit is contained in:
WK 2025-10-04 10:16:21 +08:00 committed by GitHub
parent 0d95d7faa0
commit f13c6875db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 80 additions and 46 deletions

View File

@ -0,0 +1,5 @@
---
"@heroui/number-input": patch
---
ignore name prop in getNumberInputProps (#5594)

View File

@ -1,7 +1,7 @@
import type {UserEvent} from "@testing-library/user-event";
import * as React from "react";
import {render, renderHook, fireEvent, act} from "@testing-library/react";
import {render, fireEvent, act} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {useForm} from "react-hook-form";
import {Form} from "@heroui/form";
@ -330,59 +330,85 @@ describe("NumberInput", () => {
});
describe("NumberInput with React Hook Form", () => {
let input1: HTMLInputElement;
let input2: HTMLInputElement;
let input3: HTMLInputElement;
let hiddenInput1: HTMLInputElement;
let hiddenInput2: HTMLInputElement;
let hiddenInput3: HTMLInputElement;
let visibleInput3: HTMLInputElement;
let submitButton: HTMLButtonElement;
let onSubmit: () => void;
beforeEach(() => {
const {result} = renderHook(() =>
useForm({
defaultValues: {
withDefaultValue: 1234,
withoutDefaultValue: undefined,
requiredField: undefined,
},
}),
);
const {
handleSubmit,
register,
formState: {errors},
} = result.current;
onSubmit = jest.fn();
render(
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<NumberInput isClearable label="With default value" {...register("withDefaultValue")} />
<NumberInput
data-testid="input-2"
label="Without default value"
{...register("withoutDefaultValue")}
/>
<NumberInput
data-testid="input-3"
label="Required"
{...register("requiredField", {required: true})}
/>
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button type="submit">Submit</button>
</form>,
);
function TestForm() {
const {
handleSubmit,
setValue,
watch,
register,
formState: {errors},
} = useForm<{
withDefaultValue: number;
withoutDefaultValue?: number;
requiredField?: number;
}>();
input1 = document.querySelector("input[name=withDefaultValue]")!;
input2 = document.querySelector("input[name=withoutDefaultValue]")!;
input3 = document.querySelector("input[name=requiredField]")!;
React.useEffect(() => {
register("withDefaultValue");
register("withoutDefaultValue");
register("requiredField", {required: true});
}, [register]);
const requiredFieldValue = watch("requiredField");
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<NumberInput
isClearable
data-testid="input-1"
defaultValue={1234}
label="With default value"
name="withDefaultValue"
onValueChange={(value) => setValue("withDefaultValue", value)}
/>
<NumberInput
data-testid="input-2"
label="Without default value"
name="withoutDefaultValue"
onValueChange={(value) => setValue("withoutDefaultValue", value)}
/>
<NumberInput
data-testid="input-3"
label="Required"
name="requiredField"
value={requiredFieldValue}
onValueChange={(value) =>
setValue("requiredField", value, {shouldValidate: true, shouldDirty: true})
}
/>
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button type="submit">Submit</button>
</form>
);
}
const {getByTestId} = render(<TestForm />);
hiddenInput1 = document.querySelector("input[name=withDefaultValue][type=hidden]")!;
hiddenInput2 = document.querySelector("input[name=withoutDefaultValue][type=hidden]")!;
hiddenInput3 = document.querySelector("input[name=requiredField][type=hidden]")!;
visibleInput3 = getByTestId("input-3") as HTMLInputElement;
submitButton = document.querySelector('button[type="submit"]')!;
});
it("should work with defaultValues", () => {
expect(input1).toHaveValue("1234");
expect(input2).not.toHaveValue();
expect(input3).not.toHaveValue();
expect(hiddenInput1).toHaveValue("1234");
expect(hiddenInput2).not.toHaveValue();
expect(hiddenInput3).not.toHaveValue();
expect(document.querySelectorAll('input[name="requiredField"]')).toHaveLength(1);
expect(visibleInput3).not.toHaveAttribute("name");
expect(hiddenInput3).toHaveAttribute("name", "requiredField");
});
it("should not submit form when required field is empty", async () => {
@ -394,10 +420,13 @@ describe("NumberInput with React Hook Form", () => {
});
it("should submit form when required field is not empty", async () => {
fireEvent.change(input3, {target: {value: 123}});
const user = userEvent.setup();
await user.click(visibleInput3);
await user.keyboard("123");
expect(hiddenInput3).toHaveValue("123");
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(1);

View File

@ -334,7 +334,7 @@ export function useNumberInput(originalProps: UseNumberInputProps) {
enabled: true,
labelable: true,
omitEventNames: new Set(Object.keys(inputProps)),
omitPropNames: new Set(["value"]),
omitPropNames: new Set(["value", "name"]),
}),
props,
),