- TextFieldMD3: add helpTextPrefix prop rendered inline left of helpText - Guard changed to (helpText || helpTextPrefix) so icon renders without helpText - FieldRenderer: move tooltip icon from above field to inline with helpText via helpTextPrefix - FieldRenderer: add hoverTooltip state; tooltip visible on mouseEnter, dismisses on mouseLeave - FieldRenderer: click-to-unpin clears hoverTooltip to prevent sticky tooltip after dismiss - PasswordField: same tooltip fix as FieldRenderer text-branch - Select-branch also gains hover support
65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
import { useState } from 'react';
|
|
import type { FieldError, UseFormRegisterReturn } from 'react-hook-form';
|
|
import { TextFieldMD3 } from './TextFieldMD3';
|
|
|
|
interface PasswordFieldProps {
|
|
id: string;
|
|
label: string;
|
|
error?: FieldError;
|
|
registration: UseFormRegisterReturn;
|
|
helpText?: string;
|
|
tooltipText?: string;
|
|
}
|
|
|
|
export function PasswordField({ id, label, error, registration, helpText, tooltipText }: PasswordFieldProps) {
|
|
const [show, setShow] = useState(false);
|
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
const [hoverTooltip, setHoverTooltip] = useState(false);
|
|
|
|
const toggleButton = (
|
|
<button
|
|
type="button"
|
|
onClick={() => setShow(v => !v)}
|
|
aria-label={show ? 'Hide' : 'Show'}
|
|
className="text-on-surface-container/50 hover:text-on-surface-container text-sm"
|
|
>
|
|
{show ? 'Hide' : 'Show'}
|
|
</button>
|
|
);
|
|
|
|
const tooltipIcon = tooltipText ? (
|
|
<button
|
|
type="button"
|
|
onClick={() => { setShowTooltip(v => { if (v) setHoverTooltip(false); return !v; }); }}
|
|
onMouseEnter={() => setHoverTooltip(true)}
|
|
onMouseLeave={() => setHoverTooltip(false)}
|
|
aria-label={`More info about ${label}`}
|
|
className="text-primary hover:text-primary/80 text-xs leading-none mt-px shrink-0"
|
|
>
|
|
ⓘ
|
|
</button>
|
|
) : undefined;
|
|
|
|
const tooltipVisible = showTooltip || hoverTooltip;
|
|
|
|
return (
|
|
<div className="flex flex-col gap-1">
|
|
<TextFieldMD3
|
|
id={id}
|
|
label={label}
|
|
error={error}
|
|
registration={registration}
|
|
type={show ? 'text' : 'password'}
|
|
helpText={helpText}
|
|
helpTextPrefix={tooltipIcon}
|
|
suffix={toggleButton}
|
|
/>
|
|
{tooltipText && tooltipVisible && (
|
|
<p className="text-xs text-primary bg-primary/10 border border-primary/30 rounded px-2 py-1.5">
|
|
{tooltipText}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|