Skip to content

Commit

Permalink
Add onFirstFocus event
Browse files Browse the repository at this point in the history
  • Loading branch information
marshallku committed Dec 15, 2024
1 parent 2f702cf commit a853303
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
23 changes: 22 additions & 1 deletion packages/ui/src/components/Input/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ describe("Input", () => {
it("should be rendered", () => {
render(<Input data-testid="input" />);

expect(screen.getByTestId("input")).toBeDefined();
expect(screen.getByTestId("input").tagName).toBe("INPUT");
});

it("should handle onFirstFocus", () => {
render(
<Input
onFirstFocus={({ currentTarget }) => {
currentTarget.value = "";
}}
data-testid="input"
/>,
);

expect(screen.getByTestId("input").tagName).toBe("INPUT");
screen.getByTestId<HTMLInputElement>("input").value = "Testing";
expect(screen.getByTestId<HTMLInputElement>("input").value).toBe("Testing");
screen.getByTestId<HTMLInputElement>("input").focus();
expect(screen.getByTestId<HTMLInputElement>("input").value).toBe("");
screen.getByTestId<HTMLInputElement>("input").value = "Testing";
expect(screen.getByTestId<HTMLInputElement>("input").value).toBe("Testing");
screen.getByTestId<HTMLInputElement>("input").focus();
expect(screen.getByTestId<HTMLInputElement>("input").value).toBe("Testing");
});
});
20 changes: 17 additions & 3 deletions packages/ui/src/components/Input/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type InputHTMLAttributes, ReactNode, forwardRef } from "react";
import { type InputHTMLAttributes, type FocusEvent, ReactNode, forwardRef, useRef } from "react";
import { classNames } from "@marshallku/utils";
import Typography from "../Typography";
import styles from "./index.module.scss";
Expand All @@ -9,20 +9,34 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
variant?: InputVariant;
label?: string;
children?: ReactNode;
/** Callback when input is focused for the first time */
onFirstFocus?: (event: FocusEvent<HTMLInputElement, Element>) => void;
}

const cx = classNames(styles, "input");

const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, label, variant = "box", children, ...props }, ref) => {
({ className, label, variant = "box", children, onFirstFocus, ...props }, ref) => {
const focused = useRef(false);
return (
<label className={cx("", `--${variant}`, children && "--has-child", { className })}>
{!!label && (
<Typography variant="c1" className={cx("__label")} component="div">
{label}
</Typography>
)}
<input className={cx("__input")} {...props} ref={ref} />
<input
className={cx("__input")}
{...props}
ref={ref}
onFocus={(event) => {
if (!focused.current) {
focused.current = true;
onFirstFocus?.(event);
}
props.onFocus?.(event);
}}
/>
{children && <div className={cx("__children")}>{children}</div>}
</label>
);
Expand Down

0 comments on commit a853303

Please sign in to comment.