Skip to content

Commit

Permalink
fix(input): use onPress for wrapper click focus (#4483)
Browse files Browse the repository at this point in the history
* fix(input): use onPress for wrapper click focus

* test(input): wrapper click focus test

* chore(changeset): input onPress for wrapper click focus

* chore(changeset): minor wording
  • Loading branch information
Peterl561 authored Jan 15, 2025
1 parent 26fc514 commit 992220a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-hounds-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nextui-org/input": patch
---

fixed input inconsistent focus behaviour on wrapper click (#4287)
27 changes: 27 additions & 0 deletions packages/components/input/__tests__/input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,33 @@ describe("Input", () => {

expect(onClear).toHaveBeenCalledTimes(0);
});

it("should focus input on click", async () => {
const {getByTestId} = render(<Input data-testid="input" />);

const input = getByTestId("input") as HTMLInputElement;
const innerWrapper = document.querySelector("[data-slot='inner-wrapper']") as HTMLDivElement;
const inputWrapper = document.querySelector("[data-slot='input-wrapper']") as HTMLDivElement;

const user = userEvent.setup();

expect(document.activeElement).not.toBe(input);

await user.click(input);
expect(document.activeElement).toBe(input);
input.blur();
expect(document.activeElement).not.toBe(input);

await user.click(innerWrapper);
expect(document.activeElement).toBe(input);
input.blur();
expect(document.activeElement).not.toBe(input);

await user.click(inputWrapper);
expect(document.activeElement).toBe(input);
input.blur();
expect(document.activeElement).not.toBe(input);
});
});

describe("Input with React Hook Form", () => {
Expand Down
23 changes: 12 additions & 11 deletions packages/components/input/src/use-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
domRef.current?.focus();
}, [setInputValue, onClear]);

const handleInputWrapperClick = useCallback(() => {
if (domRef.current) {
domRef.current?.focus();
}
}, [domRef.current]);

// if we use `react-hook-form`, it will set the input value using the ref in register
// i.e. setting ref.current.value to something which is uncontrolled
// hence, sync the state with `ref.current.value`
Expand Down Expand Up @@ -225,6 +231,11 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
onPress: handleClear,
});

const {pressProps: inputWrapperPressProps} = usePress({
isDisabled: !!originalProps?.isDisabled || !!originalProps?.isReadOnly,
onPress: handleInputWrapperClick,
});

const isInvalid = validationState === "invalid" || isAriaInvalid;

const labelPlacement = useMemo<InputVariantProps["labelPlacement"]>(() => {
Expand Down Expand Up @@ -403,12 +414,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
className: slots.inputWrapper({
class: clsx(classNames?.inputWrapper, isFilled ? "is-filled" : ""),
}),
...mergeProps(props, hoverProps),
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
...mergeProps(props, hoverProps, inputWrapperPressProps),
style: {
cursor: "text",
...props.style,
Expand All @@ -432,11 +438,6 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
...props,
ref: innerWrapperRef,
"data-slot": "inner-wrapper",
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
className: slots.innerWrapper({
class: clsx(classNames?.innerWrapper, props?.className),
}),
Expand Down

0 comments on commit 992220a

Please sign in to comment.