mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(input): esc key to clear input value (#4892)
* chore: theme generator credits * fix: blog date and spinner default variant * fix: #4850 Solve Pressing ESC doesn't clear input value * fix: #4850 code review change * fix: undo changes in apps/docs/content/blog/v2.7.0.mdx and add a test case for my changes * fix: run through the test cases successfully * fix: change md content * fix: using isClearable not clear the value * fix: add number-input clearable esc clear * fix: edit review problem * fix: delete unless file * chore(changeset): update changeset * fix: add inputProps.onKeyDown * fix: pressing ESC key in a read-only input not clear --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> Co-authored-by: աӄա <wingkwong.code@gmail.com>
This commit is contained in:
parent
ff8c9b3fec
commit
6453149543
6
.changeset/grumpy-pandas-rescue.md
Normal file
6
.changeset/grumpy-pandas-rescue.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@heroui/input": patch
|
||||
"@heroui/number-input": patch
|
||||
---
|
||||
|
||||
add missing logic to handle esc key to clear input / number-input value (#4850)
|
||||
@ -300,6 +300,66 @@ describe("Input", () => {
|
||||
|
||||
expect(onClear).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it("should clear value when isClearable and pressing ESC key", async () => {
|
||||
const onClear = jest.fn();
|
||||
const defaultValue = "test value";
|
||||
|
||||
const {getByRole} = render(<Input isClearable defaultValue={defaultValue} onClear={onClear} />);
|
||||
|
||||
const input = getByRole("textbox") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe(defaultValue);
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
|
||||
expect(input.value).toBe("");
|
||||
|
||||
expect(onClear).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key if input is empty", () => {
|
||||
const onClear = jest.fn();
|
||||
|
||||
const {getByRole} = render(<Input isClearable defaultValue="" onClear={onClear} />);
|
||||
|
||||
const input = getByRole("textbox");
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
|
||||
expect(onClear).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key if input is isClearable", () => {
|
||||
const defaultValue = "test value";
|
||||
|
||||
const {getByRole} = render(<Input defaultValue={defaultValue} />);
|
||||
|
||||
const input = getByRole("textbox") as HTMLInputElement;
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
|
||||
expect(input.value).toBe("test value");
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key if input is readonly", () => {
|
||||
const onClear = jest.fn();
|
||||
const defaultValue = "test value";
|
||||
|
||||
const {getByRole} = render(
|
||||
<Input isClearable isReadOnly defaultValue={defaultValue} onClear={onClear} />,
|
||||
);
|
||||
|
||||
const input = getByRole("textbox") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe(defaultValue);
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
|
||||
expect(input.value).toBe(defaultValue);
|
||||
|
||||
expect(onClear).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Input with React Hook Form", () => {
|
||||
|
||||
@ -352,6 +352,21 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
|
||||
[slots, isLabelHovered, labelProps, classNames?.label],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
e.key === "Escape" &&
|
||||
inputValue &&
|
||||
(isClearable || onClear) &&
|
||||
!originalProps.isReadOnly
|
||||
) {
|
||||
setInputValue("");
|
||||
onClear?.();
|
||||
}
|
||||
},
|
||||
[inputValue, setInputValue, onClear, isClearable, originalProps.isReadOnly],
|
||||
);
|
||||
|
||||
const getInputProps: PropGetter = useCallback(
|
||||
(props = {}) => {
|
||||
return {
|
||||
@ -375,6 +390,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
|
||||
),
|
||||
"aria-readonly": dataAttr(originalProps.isReadOnly),
|
||||
onChange: chain(inputProps.onChange, onChange),
|
||||
onKeyDown: chain(inputProps.onKeyDown, props.onKeyDown, handleKeyDown),
|
||||
ref: domRef,
|
||||
};
|
||||
},
|
||||
@ -392,6 +408,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
|
||||
originalProps.isReadOnly,
|
||||
originalProps.isRequired,
|
||||
onChange,
|
||||
handleKeyDown,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -241,6 +241,63 @@ describe("NumberInput", () => {
|
||||
expect(stepperButton).toBeNull();
|
||||
});
|
||||
|
||||
it("should clear value when isClearable and pressing ESC key", async () => {
|
||||
const onClear = jest.fn();
|
||||
const defaultValue = 12;
|
||||
|
||||
const {container} = render(
|
||||
<NumberInput isClearable defaultValue={defaultValue} onClear={onClear} />,
|
||||
);
|
||||
|
||||
const input = container.querySelector("input") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe(defaultValue.toString());
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
expect(input.value).toBe("");
|
||||
expect(onClear).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key if input is empty", () => {
|
||||
const onClear = jest.fn();
|
||||
|
||||
const {container} = render(<NumberInput isClearable onClear={onClear} />);
|
||||
|
||||
const input = container.querySelector("input") as HTMLInputElement;
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
expect(onClear).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key without isClearable", () => {
|
||||
const defaultValue = 12;
|
||||
|
||||
const {container} = render(<NumberInput defaultValue={defaultValue} />);
|
||||
|
||||
const input = container.querySelector("input") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe(defaultValue.toString());
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
expect(input.value).toBe(defaultValue.toString());
|
||||
});
|
||||
|
||||
it("should not clear value when pressing ESC key if input is readonly", () => {
|
||||
const onClear = jest.fn();
|
||||
const defaultValue = 42;
|
||||
|
||||
const {container} = render(<NumberInput isReadOnly defaultValue={defaultValue} />);
|
||||
|
||||
const input = container.querySelector("input") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe(defaultValue.toString());
|
||||
|
||||
fireEvent.keyDown(input, {key: "Escape"});
|
||||
|
||||
expect(input.value).toBe(defaultValue.toString());
|
||||
expect(onClear).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should emit onChange", async () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
|
||||
@ -239,6 +239,21 @@ export function useNumberInput(originalProps: UseNumberInputProps) {
|
||||
[objectToDeps(variantProps), isInvalid, isClearable, hasStartContent, disableAnimation],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
e.key === "Escape" &&
|
||||
inputValue &&
|
||||
(isClearable || onClear) &&
|
||||
!originalProps.isReadOnly
|
||||
) {
|
||||
state.setInputValue("");
|
||||
onClear?.();
|
||||
}
|
||||
},
|
||||
[inputValue, state.setInputValue, onClear, isClearable, originalProps.isReadOnly],
|
||||
);
|
||||
|
||||
const getBaseProps: PropGetter = useCallback(
|
||||
(props = {}) => {
|
||||
return {
|
||||
@ -324,6 +339,7 @@ export function useNumberInput(originalProps: UseNumberInputProps) {
|
||||
),
|
||||
"aria-readonly": dataAttr(originalProps.isReadOnly),
|
||||
onChange: chain(inputProps.onChange, onChange),
|
||||
onKeyDown: chain(inputProps.onKeyDown, props.onKeyDown, handleKeyDown),
|
||||
ref: domRef,
|
||||
};
|
||||
},
|
||||
@ -339,6 +355,7 @@ export function useNumberInput(originalProps: UseNumberInputProps) {
|
||||
originalProps.isReadOnly,
|
||||
originalProps.isRequired,
|
||||
onChange,
|
||||
handleKeyDown,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user