文件
mynode/packages/app-desktop/gui/PasswordInput/LabelledPasswordInput.tsx
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

59 行
1.5 KiB
TypeScript

import * as React from 'react';
import PasswordInput from './PasswordInput';
import { useId } from 'react';
import { ChangeEventHandler } from './types';
import { _ } from '@joplin/lib/locale';
interface Props {
labelText: string;
value: string;
onChange: ChangeEventHandler;
valid?: boolean;
reserveIconGutter?: boolean;
}
const LabelledPasswordInput: React.FC<Props> = props => {
const inputId = useId();
const statusIconId = useId();
const canRenderStatusIcon = (props.valid ?? null) !== null && props.value;
const renderStatusIcon = () => {
if (!canRenderStatusIcon) return null;
let title, classNames;
if (props.valid) {
title = _('Valid');
classNames = 'fas fa-check -valid';
} else {
title = _('Invalid');
classNames = 'fas fa-times -invalid';
}
return <i
className={`password-status-icon ${classNames}`}
id={statusIconId}
role='img'
aria-label={title}
title={title}
aria-live='polite'
></i>;
};
const rootClassName = `labelled-password-input form-input-group${props.reserveIconGutter ? ' -reserve-icon-gutter' : ''}`;
return <div className={rootClassName}>
<label htmlFor={inputId}>{props.labelText}</label>
<div className='password'>
<PasswordInput
inputId={inputId}
aria-invalid={canRenderStatusIcon ? !props.valid : undefined}
aria-errormessage={canRenderStatusIcon ? statusIconId : undefined}
value={props.value}
onChange={props.onChange}
/>
{renderStatusIcon()}
</div>
</div>;
};
export default LabelledPasswordInput;