mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
Chore/remove badges from tab order (#9643)
Makes badges not tabbable by default instead of tabbable by default. Turns out, badges aren't tabbable by default and they never were until I made them as much (for some reason that I don't quite understand now). Anyway, I've gone through the list of uses for the Badge element and made any element that should be reachable by tab either have an explicit tab index (if it's within a tooltip, for instance), or be wrapped in a Link (instead of having an on-click handler). The two places I've wrapped it in a link, I've also gone and changed the item group to be a list (for HTML semantics). I've also updated some spacing for the profile tab. Application list (one is before, one is after. don't remember which is which; it's now a list):   Profile page (now a list + improved spacing) Before:   After:  
This commit is contained in:
parent
fc0383620b
commit
398246c3ec
@ -88,7 +88,6 @@ export const RequestSummary: FC<Props> = ({
|
|||||||
: 'error'
|
: 'error'
|
||||||
: 'neutral'
|
: 'neutral'
|
||||||
}
|
}
|
||||||
tabIndex={-1}
|
|
||||||
>
|
>
|
||||||
{usageTotal.toLocaleString(
|
{usageTotal.toLocaleString(
|
||||||
locationSettings.locale ?? 'en-US',
|
locationSettings.locale ?? 'en-US',
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { ApplicationIssues } from './ApplicationIssues/ApplicationIssues';
|
|||||||
import { ApplicationChart } from './ApplicationChart';
|
import { ApplicationChart } from './ApplicationChart';
|
||||||
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
||||||
import { Badge } from '../common/Badge/Badge';
|
import { Badge } from '../common/Badge/Badge';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useFeedback } from '../feedbackNew/useFeedback';
|
import { useFeedback } from '../feedbackNew/useFeedback';
|
||||||
@ -35,11 +35,22 @@ const ApplicationContainer = styled(Box)(({ theme }) => ({
|
|||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ProjectContainer = styled(Box)(({ theme }) => ({
|
const ProjectContainer = styled('ul')(({ theme }) => ({
|
||||||
|
padding: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
|
listStyle: 'none',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledBadgeLink = styled(Link)(({ theme }) => ({
|
||||||
|
':hover,:focus-visible': {
|
||||||
|
outline: 'none',
|
||||||
|
'> *': {
|
||||||
|
outline: `1px solid ${theme.palette.primary.main}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ApplicationHeader = styled('div')(({ theme }) => ({
|
const ApplicationHeader = styled('div')(({ theme }) => ({
|
||||||
@ -97,18 +108,18 @@ const ApplicationOverview = () => {
|
|||||||
<ProjectContainer>
|
<ProjectContainer>
|
||||||
Application is connected to these projects:
|
Application is connected to these projects:
|
||||||
{data.projects.map((project) => (
|
{data.projects.map((project) => (
|
||||||
<Badge
|
<li key={project}>
|
||||||
sx={{ cursor: 'pointer' }}
|
<StyledBadgeLink
|
||||||
key={project}
|
to={`/projects/${project}`}
|
||||||
onClick={(e) => {
|
>
|
||||||
e.preventDefault();
|
<Badge
|
||||||
navigate(`/projects/${project}`);
|
color='secondary'
|
||||||
}}
|
icon={<TopicOutlinedIcon />}
|
||||||
color='secondary'
|
>
|
||||||
icon={<TopicOutlinedIcon />}
|
{project}
|
||||||
>
|
</Badge>
|
||||||
{project}
|
</StyledBadgeLink>
|
||||||
</Badge>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ProjectContainer>
|
</ProjectContainer>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -97,14 +97,12 @@ export const Badge: FC<IBadgeProps> = forwardRef(
|
|||||||
className,
|
className,
|
||||||
sx,
|
sx,
|
||||||
children,
|
children,
|
||||||
tabIndex = 0,
|
|
||||||
...props
|
...props
|
||||||
}: IBadgeProps,
|
}: IBadgeProps,
|
||||||
ref: ForwardedRef<HTMLDivElement>,
|
ref: ForwardedRef<HTMLDivElement>,
|
||||||
) => (
|
) => (
|
||||||
<StyledBadge
|
<StyledBadge
|
||||||
as={as}
|
as={as}
|
||||||
tabIndex={tabIndex}
|
|
||||||
color={color}
|
color={color}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
className={className}
|
className={className}
|
||||||
|
|||||||
@ -27,7 +27,12 @@ export const RoleBadge = ({ roleId, hideIcon, children }: IRoleBadgeProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HtmlTooltip title={<RoleDescription roleId={roleId} tooltip />} arrow>
|
<HtmlTooltip title={<RoleDescription roleId={roleId} tooltip />} arrow>
|
||||||
<Badge color='success' icon={icon} sx={{ cursor: 'pointer' }}>
|
<Badge
|
||||||
|
tabIndex={0}
|
||||||
|
color='success'
|
||||||
|
icon={icon}
|
||||||
|
sx={{ cursor: 'pointer' }}
|
||||||
|
>
|
||||||
{role.name}
|
{role.name}
|
||||||
</Badge>
|
</Badge>
|
||||||
</HtmlTooltip>
|
</HtmlTooltip>
|
||||||
|
|||||||
@ -342,7 +342,9 @@ export const PrimaryFeatureInfo: FC<{
|
|||||||
/>
|
/>
|
||||||
{archivedAt && (
|
{archivedAt && (
|
||||||
<HtmlTooltip arrow title={archivedDate} describeChild>
|
<HtmlTooltip arrow title={archivedDate} describeChild>
|
||||||
<Badge color='neutral'>Archived</Badge>
|
<Badge tabIndex={0} color='neutral'>
|
||||||
|
Archived
|
||||||
|
</Badge>
|
||||||
</HtmlTooltip>
|
</HtmlTooltip>
|
||||||
)}
|
)}
|
||||||
</FeatureNameAndType>
|
</FeatureNameAndType>
|
||||||
|
|||||||
@ -117,13 +117,11 @@ export const FeatureDetails = ({
|
|||||||
<p>
|
<p>
|
||||||
{feature?.strategies?.result !== 'unknown' ? (
|
{feature?.strategies?.result !== 'unknown' ? (
|
||||||
<PlaygroundResultChip
|
<PlaygroundResultChip
|
||||||
tabindex={-1}
|
|
||||||
enabled={feature.isEnabled}
|
enabled={feature.isEnabled}
|
||||||
label={feature.isEnabled ? 'True' : 'False'}
|
label={feature.isEnabled ? 'True' : 'False'}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PlaygroundResultChip
|
<PlaygroundResultChip
|
||||||
tabindex={-1}
|
|
||||||
enabled='unknown'
|
enabled='unknown'
|
||||||
label={'Unknown'}
|
label={'Unknown'}
|
||||||
showIcon={false}
|
showIcon={false}
|
||||||
|
|||||||
@ -14,14 +14,12 @@ interface IResultChipProps {
|
|||||||
label: string;
|
label: string;
|
||||||
// Result icon - defaults to true
|
// Result icon - defaults to true
|
||||||
showIcon?: boolean;
|
showIcon?: boolean;
|
||||||
tabindex?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PlaygroundResultChip: VFC<IResultChipProps> = ({
|
export const PlaygroundResultChip: VFC<IResultChipProps> = ({
|
||||||
enabled,
|
enabled,
|
||||||
label,
|
label,
|
||||||
showIcon = true,
|
showIcon = true,
|
||||||
tabindex,
|
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
|
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
|
||||||
@ -73,7 +71,6 @@ export const PlaygroundResultChip: VFC<IResultChipProps> = ({
|
|||||||
condition={typeof enabled === 'boolean' && Boolean(enabled)}
|
condition={typeof enabled === 'boolean' && Boolean(enabled)}
|
||||||
show={
|
show={
|
||||||
<Badge
|
<Badge
|
||||||
tabIndex={tabindex}
|
|
||||||
color='success'
|
color='success'
|
||||||
icon={showIcon ? icon : undefined}
|
icon={showIcon ? icon : undefined}
|
||||||
>
|
>
|
||||||
@ -81,11 +78,7 @@ export const PlaygroundResultChip: VFC<IResultChipProps> = ({
|
|||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Badge
|
<Badge color='error' icon={showIcon ? icon : undefined}>
|
||||||
color='error'
|
|
||||||
icon={showIcon ? icon : undefined}
|
|
||||||
tabIndex={tabindex}
|
|
||||||
>
|
|
||||||
{label}
|
{label}
|
||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,6 @@ export const PlaygroundResultChip: FC<ResultChipProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge
|
<Badge
|
||||||
tabIndex={-1}
|
|
||||||
color={color}
|
color={color}
|
||||||
icon={
|
icon={
|
||||||
showIcon ? (
|
showIcon ? (
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
|
|||||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||||
import type { IUser } from 'interfaces/user';
|
import type { IUser } from 'interfaces/user';
|
||||||
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { RoleBadge } from 'component/common/RoleBadge/RoleBadge';
|
import { RoleBadge } from 'component/common/RoleBadge/RoleBadge';
|
||||||
@ -56,14 +56,19 @@ const StyledSectionLabel = styled(Typography)(({ theme }) => ({
|
|||||||
const StyledAccess = styled('div')(({ theme }) => ({
|
const StyledAccess = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
gap: theme.spacing(2),
|
||||||
'& > div > p': {
|
'& > div > p': {
|
||||||
marginBottom: theme.spacing(1.5),
|
marginBottom: theme.spacing(1.5),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledBadge = styled(Badge)(({ theme }) => ({
|
const StyledBadgeLink = styled(Link)(({ theme }) => ({
|
||||||
cursor: 'pointer',
|
':hover,:focus-visible': {
|
||||||
marginRight: theme.spacing(1),
|
outline: 'none',
|
||||||
|
'> *': {
|
||||||
|
outline: `2px solid ${theme.palette.primary.main}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledDivider = styled('div')(({ theme }) => ({
|
const StyledDivider = styled('div')(({ theme }) => ({
|
||||||
@ -86,6 +91,14 @@ interface IProfileTabProps {
|
|||||||
user: IUser;
|
user: IUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProjectList = styled('ul')(({ theme }) => ({
|
||||||
|
listStyle: 'none',
|
||||||
|
padding: 0,
|
||||||
|
display: 'flex',
|
||||||
|
flexFlow: 'row wrap',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
export const ProfileTab = ({ user }: IProfileTabProps) => {
|
export const ProfileTab = ({ user }: IProfileTabProps) => {
|
||||||
const { profile, refetchProfile } = useProfile();
|
const { profile, refetchProfile } = useProfile();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -158,33 +171,40 @@ export const ProfileTab = ({ user }: IProfileTabProps) => {
|
|||||||
<Typography variant='body2'>Projects</Typography>
|
<Typography variant='body2'>Projects</Typography>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(profile?.projects.length)}
|
condition={Boolean(profile?.projects.length)}
|
||||||
show={profile?.projects.map((project) => (
|
show={
|
||||||
<Tooltip
|
<ProjectList>
|
||||||
key={project}
|
{profile?.projects.map((project) => (
|
||||||
title='View project'
|
<li key={project}>
|
||||||
arrow
|
<Tooltip
|
||||||
placement='bottom-end'
|
title='View project'
|
||||||
describeChild
|
arrow
|
||||||
>
|
placement='bottom-end'
|
||||||
<StyledBadge
|
describeChild
|
||||||
onClick={(e) => {
|
>
|
||||||
e.preventDefault();
|
<StyledBadgeLink
|
||||||
navigate(`/projects/${project}`);
|
to={`/projects/${project}`}
|
||||||
}}
|
>
|
||||||
color='secondary'
|
<Badge
|
||||||
icon={<TopicOutlinedIcon />}
|
color='secondary'
|
||||||
>
|
icon={
|
||||||
{project}
|
<TopicOutlinedIcon />
|
||||||
</StyledBadge>
|
}
|
||||||
</Tooltip>
|
>
|
||||||
))}
|
{project}
|
||||||
|
</Badge>
|
||||||
|
</StyledBadgeLink>
|
||||||
|
</Tooltip>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ProjectList>
|
||||||
|
}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title='You are not assigned to any projects'
|
title='You are not assigned to any projects'
|
||||||
arrow
|
arrow
|
||||||
describeChild
|
describeChild
|
||||||
>
|
>
|
||||||
<Badge>No projects</Badge>
|
<Badge tabIndex={0}>No projects</Badge>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user