mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-15 16:58:14 +00:00
fix: Fix inaccessible "Clear search" button (#35152)
This commit is contained in:
parent
644da36336
commit
8ba1487f30
|
@ -13,14 +13,13 @@ interface Props extends React.SVGProps<SVGSVGElement> {
|
|||
children?: never;
|
||||
id: string;
|
||||
icon: IconProp;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const Icon: React.FC<Props> = ({
|
||||
id,
|
||||
icon: IconComponent,
|
||||
className,
|
||||
title: titleProp,
|
||||
'aria-label': ariaLabel,
|
||||
...other
|
||||
}) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
|
@ -34,18 +33,19 @@ export const Icon: React.FC<Props> = ({
|
|||
IconComponent = CheckBoxOutlineBlankIcon;
|
||||
}
|
||||
|
||||
const ariaHidden = titleProp ? undefined : true;
|
||||
const ariaHidden = ariaLabel ? undefined : true;
|
||||
const role = !ariaHidden ? 'img' : undefined;
|
||||
|
||||
// Set the title to an empty string to remove the built-in SVG one if any
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
const title = titleProp || '';
|
||||
const title = ariaLabel || '';
|
||||
|
||||
return (
|
||||
<IconComponent
|
||||
className={classNames('icon', `icon-${id}`, className)}
|
||||
title={title}
|
||||
aria-hidden={ariaHidden}
|
||||
aria-label={ariaLabel}
|
||||
role={role}
|
||||
{...other}
|
||||
/>
|
||||
|
|
|
@ -318,7 +318,7 @@ const PollOption: React.FC<PollOptionProps> = (props) => {
|
|||
id='check'
|
||||
icon={CheckIcon}
|
||||
className='poll__voted__mark'
|
||||
title={intl.formatMessage(messages.voted)}
|
||||
aria-label={intl.formatMessage(messages.voted)}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
|
|
|
@ -58,7 +58,7 @@ export const VisibilityIcon: React.FC<{ visibility: StatusVisibility }> = ({
|
|||
<Icon
|
||||
id={visibilityIcon.icon}
|
||||
icon={visibilityIcon.iconComponent}
|
||||
title={visibilityIcon.text}
|
||||
aria-label={visibilityIcon.text}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -768,7 +768,7 @@ export const AccountHeader: React.FC<{
|
|||
<Icon
|
||||
id='lock'
|
||||
icon={LockIcon}
|
||||
title={intl.formatMessage(messages.account_locked)}
|
||||
aria-label={intl.formatMessage(messages.account_locked)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
|
|||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
|
||||
clearSearch: { id: 'search.clear', defaultMessage: 'Clear search' },
|
||||
placeholderSignedIn: {
|
||||
id: 'search.search_or_paste',
|
||||
defaultMessage: 'Search or paste URL',
|
||||
|
@ -50,6 +51,34 @@ const unfocus = () => {
|
|||
document.querySelector('.ui')?.parentElement?.focus();
|
||||
};
|
||||
|
||||
const ClearButton: React.FC<{
|
||||
onClick: () => void;
|
||||
hasValue: boolean;
|
||||
}> = ({ onClick, hasValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('search__icon-wrapper', { 'has-value': hasValue })}
|
||||
>
|
||||
<Icon id='search' icon={SearchIcon} className='search__icon' />
|
||||
<button
|
||||
type='button'
|
||||
onClick={onClick}
|
||||
className='search__icon search__icon--clear-button'
|
||||
tabIndex={hasValue ? undefined : -1}
|
||||
aria-hidden={!hasValue}
|
||||
>
|
||||
<Icon
|
||||
id='times-circle'
|
||||
icon={CancelIcon}
|
||||
aria-label={intl.formatMessage(messages.clearSearch)}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface SearchOption {
|
||||
key: string;
|
||||
label: React.ReactNode;
|
||||
|
@ -380,6 +409,7 @@ export const Search: React.FC<{
|
|||
setValue('');
|
||||
setQuickActions([]);
|
||||
setSelectedOption(-1);
|
||||
unfocus();
|
||||
}, [setValue, setQuickActions, setSelectedOption]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
|
@ -474,19 +504,7 @@ export const Search: React.FC<{
|
|||
onBlur={handleBlur}
|
||||
/>
|
||||
|
||||
<button type='button' className='search__icon' onClick={handleClear}>
|
||||
<Icon
|
||||
id='search'
|
||||
icon={SearchIcon}
|
||||
className={hasValue ? '' : 'active'}
|
||||
/>
|
||||
<Icon
|
||||
id='times-circle'
|
||||
icon={CancelIcon}
|
||||
className={hasValue ? 'active' : ''}
|
||||
aria-label={intl.formatMessage(messages.placeholder)}
|
||||
/>
|
||||
</button>
|
||||
<ClearButton hasValue={hasValue} onClick={handleClear} />
|
||||
|
||||
<div className='search__popout'>
|
||||
{!hasValue && (
|
||||
|
|
|
@ -804,6 +804,7 @@
|
|||
"report_notification.categories.violation": "Rule violation",
|
||||
"report_notification.categories.violation_sentence": "rule violation",
|
||||
"report_notification.open": "Open report",
|
||||
"search.clear": "Clear search",
|
||||
"search.no_recent_searches": "No recent searches",
|
||||
"search.placeholder": "Search",
|
||||
"search.quick_action.account_search": "Profiles matching {x}",
|
||||
|
|
|
@ -5670,18 +5670,47 @@ a.status-card {
|
|||
}
|
||||
}
|
||||
|
||||
.search__icon {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
.search__icon-wrapper {
|
||||
position: absolute;
|
||||
top: 12px + 2px;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
top: 14px;
|
||||
display: grid;
|
||||
margin-inline-start: 16px - 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:not(.has-value) {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.search__icon {
|
||||
grid-area: 1 / 1;
|
||||
transition: all 100ms linear;
|
||||
transition-property: transform, opacity;
|
||||
color: $darker-text-color;
|
||||
}
|
||||
|
||||
.search__icon.icon-search {
|
||||
.has-value & {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.search__icon--clear-button {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 100%;
|
||||
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
@ -5691,39 +5720,14 @@ a.status-card {
|
|||
outline: 0 !important;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
opacity: 0;
|
||||
transition: all 100ms linear;
|
||||
transition-property: transform, opacity;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: $darker-text-color;
|
||||
|
||||
&.active {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 2px $ui-button-focus-outline-color;
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
transform: rotate(90deg);
|
||||
|
||||
&.active {
|
||||
&[aria-hidden='true'] {
|
||||
pointer-events: none;
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-times-circle {
|
||||
transform: rotate(0deg);
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
opacity: 0;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user