Files
cinny/src/app/components/password-input/PasswordInput.tsx
T
Lotus Bot 4e80c0a0f5 feat(a11y,perf): comprehensive icon button labels, toolbar a11y, timeline binary search
A11y C-1: aria-label on 30+ remaining icon-only buttons across:
  - settings panels (close, reset, info, expand, remove, undo)
  - editor toolbar (bold, italic, underline, strike, code, spoiler,
    blockquote, code block, ordered/unordered list, headings 1-3)
  - auth stages (cancel buttons in SSO, Password stages)
  - device verification (cancel buttons)
  - password input (show/hide toggle with dynamic label)
  - event readers, account data editor close buttons
  - global emoji packs (add/remove buttons)
Perf-5: Replace O(N×T) getTimelineAndBaseIndex scan with precomputed binary
  search (timelineSegments useMemo) — O(log T) per visible message render

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 21:54:33 -04:00

47 lines
1.5 KiB
TypeScript

import React, { ComponentProps, forwardRef } from 'react';
import { Icon, IconButton, Input, config, Icons } from 'folds';
import { UseStateProvider } from '../UseStateProvider';
type PasswordInputProps = Omit<ComponentProps<typeof Input>, 'type' | 'size'> & {
size: '400' | '500';
};
export const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(
({ variant = 'Background', size, style, after, ...props }, ref) => {
const paddingRight: string = size === '500' ? config.space.S300 : config.space.S200;
return (
<UseStateProvider initial={false}>
{(visible, setVisible) => (
<Input
{...props}
ref={ref}
style={{ paddingRight, ...style }}
type={visible ? 'text' : 'password'}
size={size}
variant={variant}
after={
<>
{after}
<IconButton
onClick={() => setVisible(!visible)}
type="button"
variant={visible ? 'Warning' : variant}
size="300"
radii="300"
aria-label={visible ? 'Hide password' : 'Show password'}
>
<Icon
style={{ opacity: config.opacity.P300 }}
size="100"
src={visible ? Icons.Eye : Icons.EyeBlind}
/>
</IconButton>
</>
}
/>
)}
</UseStateProvider>
);
}
);