Skip to content

Commit 22037e0

Browse files
committed
1 parent 78c7b9a commit 22037e0

File tree

1 file changed

+38
-3
lines changed

1 file changed

+38
-3
lines changed

src/blocks/PasswordInput.tsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import React, {
66
type InputHTMLAttributes,
77
memo,
88
type ReactNode,
9-
useId
9+
useId,
10+
useState,
11+
useEffect
1012
} from "react";
1113
import { assert, type Equals } from "tsafe/assert";
1214
import { symToStr } from "tsafe/symToStr";
@@ -84,6 +86,39 @@ export const PasswordInput = memo(
8486
messages.length !== 0 &&
8587
messages.find(({ severity }) => severity !== "valid") === undefined;
8688

89+
const [inputWrapperElement, setInputWrapperElement] = useState<HTMLDivElement | null>(null);
90+
91+
const [isPasswordReveled, setIsPasswordReveled] = useState(false);
92+
93+
useEffect(() => {
94+
if (inputWrapperElement === null) {
95+
return;
96+
}
97+
98+
const inputElement = inputWrapperElement.querySelector<HTMLInputElement>("input");
99+
100+
assert(inputElement !== null);
101+
102+
const observer = new MutationObserver(mutations => {
103+
mutations.forEach(mutation => {
104+
if (mutation.type === "attributes" && mutation.attributeName === "type") {
105+
const input = mutation.target as HTMLInputElement;
106+
const type = input.getAttribute("type");
107+
if (type === "password") {
108+
setIsPasswordReveled(false);
109+
} else {
110+
setIsPasswordReveled(true);
111+
}
112+
}
113+
});
114+
});
115+
116+
observer.observe(inputElement, {
117+
attributes: true,
118+
attributeFilter: ["type"]
119+
});
120+
}, [inputWrapperElement]);
121+
87122
return (
88123
<div
89124
className={cx(
@@ -110,12 +145,12 @@ export const PasswordInput = memo(
110145
{hintText !== undefined && <span className="fr-hint-text">{hintText}</span>}
111146
</label>
112147
)}
113-
<div className={fr.cx("fr-input-wrap")}>
148+
<div className={fr.cx("fr-input-wrap")} ref={setInputWrapperElement}>
114149
<input
115150
{...nativeInputProps}
116151
className={cx(fr.cx("fr-password__input", "fr-input"), classes.input)}
117152
id={inputId}
118-
type="password"
153+
type={isPasswordReveled ? "text" : "password"}
119154
disabled={disabled}
120155
{...(messages.length !== 0 && { "aria-describedby": messagesGroupId })}
121156
/>

0 commit comments

Comments
 (0)