Fix PasswordField: move label into OwnProps, remove FieldLabelProps extension, useDefinition first

- Add label to PasswordFieldOwnProps and propDefs
- Remove Omit<FieldLabelProps, ...> from PasswordFieldProps
- Move useDefinition call to top of component
- Access aria-label/aria-labelledby from restProps instead of props

Signed-off-by: Johan Persson <johanopersson@gmail.com>
This commit is contained in:
Johan Persson
2026-02-25 11:37:28 +01:00
parent 61e4e033f8
commit dbf64fc345
4 changed files with 13 additions and 24 deletions
+2 -4
View File
@@ -1616,6 +1616,7 @@ export const PasswordFieldDefinition: {
readonly className: {};
readonly icon: {};
readonly placeholder: {};
readonly label: {};
readonly description: {};
readonly secondaryLabel: {};
readonly isRequired: {};
@@ -1628,6 +1629,7 @@ export type PasswordFieldOwnProps = {
className?: string;
icon?: ReactNode;
placeholder?: string;
label?: FieldLabelProps['label'];
description?: FieldLabelProps['description'];
secondaryLabel?: FieldLabelProps['secondaryLabel'];
isRequired?: boolean;
@@ -1636,10 +1638,6 @@ export type PasswordFieldOwnProps = {
// @public (undocumented)
export interface PasswordFieldProps
extends Omit<TextFieldProps_2, 'className' | 'isRequired' | 'description'>,
Omit<
FieldLabelProps,
'htmlFor' | 'id' | 'className' | 'description' | 'secondaryLabel'
>,
PasswordFieldOwnProps {}
// @public
@@ -31,26 +31,13 @@ import { RiEyeLine, RiEyeOffLine } from '@remixicon/react';
/** @public */
export const PasswordField = forwardRef<HTMLDivElement, PasswordFieldProps>(
(props, ref) => {
const {
label,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
} = props;
useEffect(() => {
if (!label && !ariaLabel && !ariaLabelledBy) {
console.warn(
'PasswordField requires either a visible label, aria-label, or aria-labelledby for accessibility',
);
}
}, [label, ariaLabel, ariaLabelledBy]);
const { ownProps, restProps, dataAttributes } = useDefinition(
PasswordFieldDefinition,
props,
);
const {
classes,
label,
icon,
isRequired,
secondaryLabel,
@@ -58,6 +45,14 @@ export const PasswordField = forwardRef<HTMLDivElement, PasswordFieldProps>(
description,
} = ownProps;
useEffect(() => {
if (!label && !restProps['aria-label'] && !restProps['aria-labelledby']) {
console.warn(
'PasswordField requires either a visible label, aria-label, or aria-labelledby for accessibility',
);
}
}, [label, restProps['aria-label'], restProps['aria-labelledby']]);
// If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required.
const secondaryLabelText =
secondaryLabel || (isRequired ? 'Required' : null);
@@ -69,8 +64,6 @@ export const PasswordField = forwardRef<HTMLDivElement, PasswordFieldProps>(
<AriaTextField
className={classes.root}
{...dataAttributes}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
type="password"
{...restProps}
ref={ref}
@@ -37,6 +37,7 @@ export const PasswordFieldDefinition = defineComponent<PasswordFieldOwnProps>()(
className: {},
icon: {},
placeholder: {},
label: {},
description: {},
secondaryLabel: {},
isRequired: {},
@@ -39,6 +39,7 @@ export type PasswordFieldOwnProps = {
*/
placeholder?: string;
label?: FieldLabelProps['label'];
description?: FieldLabelProps['description'];
secondaryLabel?: FieldLabelProps['secondaryLabel'];
isRequired?: boolean;
@@ -47,8 +48,4 @@ export type PasswordFieldOwnProps = {
/** @public */
export interface PasswordFieldProps
extends Omit<AriaTextFieldProps, 'className' | 'isRequired' | 'description'>,
Omit<
FieldLabelProps,
'htmlFor' | 'id' | 'className' | 'description' | 'secondaryLabel'
>,
PasswordFieldOwnProps {}