Merge pull request #29755 from backstage/canon-fix-select-label-click
Canon - Fix - Clicking Select label moves focus to trigger + style TextField label to indicate it's interactive.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
For improved a11y, clicking a Select component label now focuses the Select trigger element, and the TextField component's label is now styled to indicate it's interactive.
|
||||
@@ -543,6 +543,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-TextFieldLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-TextFieldDescription {
|
||||
@@ -836,6 +841,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-SelectLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-SelectDescription {
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-SelectLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-SelectDescription {
|
||||
|
||||
@@ -9767,6 +9767,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-TextFieldLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-TextFieldDescription {
|
||||
@@ -10060,6 +10065,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-SelectLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-SelectDescription {
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.canon-TextFieldLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-TextFieldDescription {
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
.canon-SelectLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-SelectDescription {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { forwardRef, useId } from 'react';
|
||||
import { forwardRef, useCallback, useId, useRef, MouseEvent } from 'react';
|
||||
import { Select as SelectPrimitive } from '@base-ui-components/react/select';
|
||||
import { Icon } from '../Icon';
|
||||
import clsx from 'clsx';
|
||||
@@ -45,10 +45,27 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
const descriptionId = useId();
|
||||
const errorId = useId();
|
||||
|
||||
const triggerRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const handleLabelClick = useCallback(
|
||||
(e: MouseEvent<HTMLLabelElement>) => {
|
||||
if (!props.disabled && triggerRef.current) {
|
||||
e.preventDefault();
|
||||
triggerRef.current.focus();
|
||||
}
|
||||
},
|
||||
[props.disabled],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx('canon-Select', className)} style={style} ref={ref}>
|
||||
{label && (
|
||||
<label className="canon-SelectLabel" htmlFor={selectId}>
|
||||
<label
|
||||
className="canon-SelectLabel"
|
||||
htmlFor={selectId}
|
||||
onClick={handleLabelClick}
|
||||
data-disabled={props.disabled ? true : undefined}
|
||||
>
|
||||
{label}
|
||||
{required && (
|
||||
<span aria-hidden="true" className="canon-SelectRequired">
|
||||
@@ -59,6 +76,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
)}
|
||||
<SelectPrimitive.Root {...rest}>
|
||||
<SelectPrimitive.Trigger
|
||||
ref={triggerRef}
|
||||
id={selectId}
|
||||
className="canon-SelectTrigger"
|
||||
data-size={responsiveSize}
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-fg-primary);
|
||||
margin-bottom: var(--canon-space-1_5);
|
||||
cursor: pointer;
|
||||
}
|
||||
.canon-TextFieldLabel[data-disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.canon-TextFieldDescription {
|
||||
|
||||
@@ -32,6 +32,7 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
error,
|
||||
required,
|
||||
style,
|
||||
disabled,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@@ -50,7 +51,11 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
ref={ref}
|
||||
>
|
||||
{label && (
|
||||
<label className="canon-TextFieldLabel" htmlFor={inputId}>
|
||||
<label
|
||||
className="canon-TextFieldLabel"
|
||||
htmlFor={inputId}
|
||||
data-disabled={disabled}
|
||||
>
|
||||
{label}
|
||||
{required && (
|
||||
<span aria-hidden="true" className="canon-TextFieldRequired">
|
||||
@@ -70,6 +75,7 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
})}
|
||||
data-invalid={error}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
{...rest}
|
||||
/>
|
||||
{description && (
|
||||
|
||||
Reference in New Issue
Block a user