This commit is contained in:
@@ -63,11 +63,16 @@ function diffChars(prev: ReadonlyArray<{ id: number; char: string }>, next: stri
|
||||
return { reusedId, keptPrev };
|
||||
}
|
||||
|
||||
/** Browsers render password glyphs as this bullet; match it in the overlay
|
||||
* so animated fields don't leak the real characters visually. */
|
||||
const PASSWORD_MASK_CHAR = '•';
|
||||
|
||||
function useFieldAnimation(
|
||||
multiline: boolean,
|
||||
externalRef: Ref<FieldElement>,
|
||||
controlledValue: ComponentPropsWithoutRef<'input'>['value'],
|
||||
initial: ComponentPropsWithoutRef<'input'>['defaultValue'],
|
||||
masked = false,
|
||||
) {
|
||||
const innerRef = useRef<FieldElement | null>(null);
|
||||
const overlayRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -144,33 +149,34 @@ function useFieldAnimation(
|
||||
|
||||
const overlay = (
|
||||
<div
|
||||
ref={overlayRef}
|
||||
aria-hidden="true"
|
||||
className={cx('modern-sk-field-overlay', multiline && 'modern-sk-field-overlay--multiline')}
|
||||
>
|
||||
{entries.map((e) =>
|
||||
e.leaving ? (
|
||||
<span
|
||||
key={`${idPrefix}-${e.id}`}
|
||||
className="modern-sk-field-char modern-sk-field-char--leaving"
|
||||
style={{ left: e.x, top: e.y }}
|
||||
onAnimationEnd={() => onLeaveEnd(e.id)}
|
||||
>
|
||||
{e.char}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
key={`${idPrefix}-${e.id}`}
|
||||
ref={(node) => {
|
||||
if (node) spanRefs.current.set(e.id, node);
|
||||
else spanRefs.current.delete(e.id);
|
||||
}}
|
||||
className={cx('modern-sk-field-char', !multiline && 'modern-sk-field-char--composited')}
|
||||
>
|
||||
{e.char}
|
||||
</span>
|
||||
),
|
||||
)}
|
||||
<div ref={overlayRef} className="modern-sk-field-overlay-content">
|
||||
{entries.map((e) =>
|
||||
e.leaving ? (
|
||||
<span
|
||||
key={`${idPrefix}-${e.id}`}
|
||||
className="modern-sk-field-char modern-sk-field-char--leaving"
|
||||
style={{ left: e.x, top: e.y }}
|
||||
onAnimationEnd={() => onLeaveEnd(e.id)}
|
||||
>
|
||||
{masked ? PASSWORD_MASK_CHAR : e.char}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
key={`${idPrefix}-${e.id}`}
|
||||
ref={(node) => {
|
||||
if (node) spanRefs.current.set(e.id, node);
|
||||
else spanRefs.current.delete(e.id);
|
||||
}}
|
||||
className={cx('modern-sk-field-char', !multiline && 'modern-sk-field-char--composited')}
|
||||
>
|
||||
{masked ? PASSWORD_MASK_CHAR : e.char}
|
||||
</span>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -187,6 +193,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
ref,
|
||||
props.value,
|
||||
props.defaultValue,
|
||||
props.type === 'password',
|
||||
);
|
||||
if (!animated) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user