Skip to content

Commit

Permalink
fix(input): sync ref value to internal value (#3533)
Browse files Browse the repository at this point in the history
* fix: sync ref value to internal value #3024 #3436

* feat: changeset - added changeset

* chore: remove comment

* chore(changeset): add issue numbers

* refactor(input): revise typing

---------

Co-authored-by: Anthony Ortiz <[email protected]>
Co-authored-by: WK Wong <[email protected]>
  • Loading branch information
3 people committed Aug 29, 2024
1 parent 2a34880 commit a254abf
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/long-ducks-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nextui-org/input": patch
---

syncs changes to ref value to internal (state) value (#3024, #3436)
20 changes: 20 additions & 0 deletions packages/components/input/__tests__/input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,26 @@ describe("Input", () => {
expect(ref.current?.value)?.toBe(value);
});

it("setting ref should sync the internal value", () => {
const ref = React.createRef<HTMLInputElement>();

const {container} = render(<Input ref={ref} type="text" />);

if (!ref.current) {
throw new Error("ref is null");
}

ref.current!.value = "value";

const input = container.querySelector("input")!;

input.focus();

const internalValue = input.value;

expect(ref.current?.value)?.toBe(internalValue);
});

it("should clear the value and onClear is triggered", async () => {
const onClear = jest.fn();

Expand Down
38 changes: 36 additions & 2 deletions packages/components/input/src/use-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
import {useFocusWithin, useHover, usePress} from "@react-aria/interactions";
import {clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel, warn} from "@nextui-org/shared-utils";
import {useControlledState} from "@react-stately/utils";
import {useMemo, Ref, useCallback, useState} from "react";
import {useMemo, Ref, useCallback, useState, useImperativeHandle, useRef} from "react";
import {chain, mergeProps} from "@react-aria/utils";
import {useTextField} from "@react-aria/textfield";

Expand Down Expand Up @@ -131,7 +131,41 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;

const domRef = useDOMRef<T>(ref);
const domRef = useRef<T>(null);

let proxy: T | undefined = undefined;

useImperativeHandle(
ref,
() => {
if (proxy === undefined) {
proxy = new Proxy(domRef.current!, {
get(target, prop) {
const value = target[prop];

if (value instanceof Function) {
return value.bind(target);
}

return value;
},
set(target, prop, value) {
target[prop] = value;

if (prop === "value") {
setInputValue(value);
}

return true;
},
});
}

return proxy;
},
[domRef.current],
);

const baseDomRef = useDOMRef<HTMLDivElement>(baseRef);
const inputWrapperRef = useDOMRef<HTMLDivElement>(wrapperRef);
const innerWrapperRef = useDOMRef<HTMLDivElement>(innerWrapperRefProp);
Expand Down

0 comments on commit a254abf

Please sign in to comment.