chore: fix aria label warnings

This commit is contained in:
Aarnav Tale 2025-02-04 11:27:29 -05:00
parent 771b87ae41
commit 347c6698ee
No known key found for this signature in database
4 changed files with 65 additions and 24 deletions

View File

@ -3,12 +3,14 @@ import { type AriaTextFieldProps, useId, useTextField } from 'react-aria';
import cn from '~/utils/cn';
export interface InputProps extends AriaTextFieldProps<HTMLInputElement> {
label: string;
labelHidden?: boolean;
isRequired?: boolean;
className?: string;
}
export default function Input(props: InputProps) {
const { label, className } = props;
const { label, labelHidden, className } = props;
const ref = useRef<HTMLInputElement | null>(null);
const id = useId(props.id);
@ -19,16 +21,24 @@ export default function Input(props: InputProps) {
errorMessageProps,
isInvalid,
validationErrors,
} = useTextField(props, ref);
} = useTextField(
{
...props,
label,
'aria-label': label,
},
ref,
);
return (
<div className="flex flex-col">
<div className="flex flex-col w-full" aria-label={label}>
<label
{...labelProps}
htmlFor={id}
className={cn(
'text-xs font-medium px-3 mb-0.5',
'text-headplane-700 dark:text-headplane-100',
labelHidden && 'sr-only',
)}
>
{label}
@ -37,7 +47,6 @@ export default function Input(props: InputProps) {
{...inputProps}
required={props.isRequired}
ref={ref}
id={id}
className={cn(
'rounded-xl px-3 py-2',
'focus:outline-none focus:ring',

View File

@ -2,6 +2,7 @@ import { Minus, Plus } from 'lucide-react';
import { useRef } from 'react';
import {
type AriaNumberFieldProps,
useId,
useLocale,
useNumberField,
} from 'react-aria';
@ -19,6 +20,7 @@ export default function NumberInput(props: InputProps) {
const { locale } = useLocale();
const state = useNumberFieldState({ ...props, locale });
const ref = useRef<HTMLInputElement | null>(null);
const id = useId(props.id);
const {
labelProps,
@ -36,8 +38,7 @@ export default function NumberInput(props: InputProps) {
<div className="flex flex-col">
<label
{...labelProps}
// TODO: This is WRONG use useId
htmlFor={name}
htmlFor={id}
className={cn(
'text-xs font-medium px-3 mb-0.5',
'text-headplane-700 dark:text-headplane-100',
@ -56,6 +57,7 @@ export default function NumberInput(props: InputProps) {
>
<input
{...inputProps}
id={id}
required={props.isRequired}
name={name}
ref={ref}

View File

@ -6,6 +6,7 @@ import {
useButton,
useComboBox,
useFilter,
useId,
useListBox,
useOption,
} from 'react-aria';
@ -18,6 +19,7 @@ export interface SelectProps extends AriaComboBoxProps<object> {}
function Select(props: SelectProps) {
const { contains } = useFilter({ sensitivity: 'base' });
const state = useComboBoxState({ ...props, defaultFilter: contains });
const id = useId(props.id);
const buttonRef = useRef<HTMLButtonElement | null>(null);
const inputRef = useRef<HTMLInputElement | null>(null);
@ -46,8 +48,7 @@ function Select(props: SelectProps) {
<div className="flex flex-col">
<label
{...labelProps}
// TODO: THIS IS WRONG, use useId
htmlFor={props['aria-labelledby']}
htmlFor={id}
className={cn(
'text-xs font-medium px-3 mb-0.5',
'text-headplane-700 dark:text-headplane-100',
@ -65,7 +66,9 @@ function Select(props: SelectProps) {
<input
{...inputProps}
ref={inputRef}
id={id}
className="outline-none px-3 py-2 rounded-l-xl w-full bg-transparent"
data-1p-ignore
/>
<button
{...buttonProps}

View File

@ -1,34 +1,61 @@
import { Switch as AriaSwitch } from 'react-aria-components';
import { useRef } from 'react';
import {
AriaSwitchProps,
VisuallyHidden,
useFocusRing,
useSwitch,
} from 'react-aria';
import { useToggleState } from 'react-stately';
import cn from '~/utils/cn';
type SwitchProps = Parameters<typeof AriaSwitch>[0] & {
readonly label: string;
};
export interface SwitchProps extends AriaSwitchProps {
label: string;
className?: string;
}
export default function Switch(props: SwitchProps) {
const state = useToggleState(props);
const ref = useRef<HTMLInputElement | null>(null);
const { focusProps, isFocusVisible } = useFocusRing();
const { inputProps } = useSwitch(
{
...props,
'aria-label': props.label,
},
state,
ref,
);
return (
<AriaSwitch
{...props}
aria-label={props.label}
className="group flex gap-2 items-center"
>
<label className="flex items-center gap-x-2">
<VisuallyHidden elementType="span">
<input
{...inputProps}
{...focusProps}
aria-label={props.label}
ref={ref}
/>
</VisuallyHidden>
<div
aria-hidden
className={cn(
'flex h-[26px] w-[44px] p-[4px] shrink-0',
'rounded-full outline-none group-focus-visible:ring-2',
'bg-main-600/50 dark:bg-main-600/20 group-selected:bg-main-700',
props.isDisabled && 'opacity-50 cursor-not-allowed',
props.className,
'flex h-[28px] w-[46px] p-[4px] shrink-0 rounded-full',
'bg-headplane-300 dark:bg-headplane-700',
'border border-transparent dark:border-headplane-800',
state.isSelected && 'bg-headplane-900 dark:bg-headplane-950',
isFocusVisible && 'ring-2',
props.isDisabled && 'opacity-50',
)}
>
<span
className={cn(
'h-[18px] w-[18px] transform rounded-full',
'bg-white transition duration-100 ease-in-out',
'bg-white transition duration-50 ease-in-out',
'translate-x-0 group-selected:translate-x-[100%]',
state.isSelected && 'translate-x-[100%]',
)}
/>
</div>
</AriaSwitch>
</label>
);
}