chore: textfield visuals fixed
Publish npm package / publish (push) Successful in 18s

This commit is contained in:
Senko-san
2026-07-11 16:18:26 +03:00
parent a7e2a1887d
commit 03a70d27a3
3 changed files with 44 additions and 26 deletions
+31 -24
View File
@@ -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 (