fix: a11y (#2275)
This commit is contained in:
@@ -91,7 +91,9 @@ export default function GroupMembersList() {
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
c="gray"
|
||||
aria-label={t("Member actions")}
|
||||
aria-label={t("Member actions for {{name}}", {
|
||||
name: user.name,
|
||||
})}
|
||||
>
|
||||
<IconDots size={20} stroke={2} />
|
||||
</ActionIcon>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useId, useState } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
Group,
|
||||
@@ -31,6 +31,7 @@ import classes from "../notification.module.css";
|
||||
|
||||
export function NotificationPopover() {
|
||||
const { t } = useTranslation();
|
||||
const titleId = useId();
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [tab, setTab] = useState<NotificationTab>("direct");
|
||||
const [filter, setFilter] = useState<NotificationFilter>("all");
|
||||
@@ -83,10 +84,11 @@ export function NotificationPopover() {
|
||||
|
||||
<Popover.Dropdown
|
||||
p={0}
|
||||
aria-labelledby={titleId}
|
||||
style={{ width: "min(420px, calc(100vw - 24px))" }}
|
||||
>
|
||||
<Group justify="space-between" px="md" py="sm">
|
||||
<Title order={2} fz="sm" fw={600}>
|
||||
<Title id={titleId} order={2} fz="sm" fw={600}>
|
||||
{t("Notifications")}
|
||||
</Title>
|
||||
<Group gap={4}>
|
||||
|
||||
@@ -34,6 +34,7 @@ import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
|
||||
import { treeModel } from "@/features/page/tree/model/tree-model";
|
||||
import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts";
|
||||
import type { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
||||
import classes from "@/features/page/tree/styles/tree.module.css";
|
||||
|
||||
export interface NodeMenuProps {
|
||||
node: SpaceTreeNode;
|
||||
@@ -123,8 +124,9 @@ export function NodeMenu({ node, canEdit }: NodeMenuProps) {
|
||||
<Menu shadow="md" width={200}>
|
||||
<Menu.Target>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
c="gray"
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
className={classes.actionIcon}
|
||||
aria-label={t("Page menu for {{name}}", { name: node.name || t("untitled") })}
|
||||
tabIndex={-1}
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -201,13 +201,13 @@ function PageArrow({ isOpen, hasChildren, onToggle }: PageArrowProps) {
|
||||
return (
|
||||
<span
|
||||
aria-hidden
|
||||
className={classes.actionIcon}
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "var(--mantine-color-gray-6)",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
@@ -220,7 +220,8 @@ function PageArrow({ isOpen, hasChildren, onToggle }: PageArrowProps) {
|
||||
<ActionIcon
|
||||
size={20}
|
||||
variant="subtle"
|
||||
c="gray"
|
||||
color="gray"
|
||||
className={classes.actionIcon}
|
||||
aria-label={isOpen ? t("Collapse") : t("Expand")}
|
||||
aria-expanded={isOpen}
|
||||
tabIndex={-1}
|
||||
@@ -272,8 +273,9 @@ function CreateNode({
|
||||
|
||||
return (
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
c="gray"
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
className={classes.actionIcon}
|
||||
aria-label={t("Create subpage of {{name}}", { name: node.name || t("untitled") })}
|
||||
tabIndex={-1}
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -57,6 +57,10 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actionIcon {
|
||||
color: light-dark(var(--mantine-color-dark-3), var(--mantine-color-gray-4));
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: 1;
|
||||
/* min-width: 0 lets a flex child shrink below its content size — required
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useGetSpacesQuery } from "@/features/space/queries/space-query";
|
||||
import { SpaceFilterMenu } from "@/features/space/components/space-filter-menu";
|
||||
import { RadioMenuItem } from "@/components/ui/radio-menu-item";
|
||||
import { useHasFeature } from "@/ee/hooks/use-feature";
|
||||
import { Feature } from "@/ee/features";
|
||||
import classes from "./search-spotlight-filters.module.css";
|
||||
@@ -175,7 +176,7 @@ export function SearchSpotlightFilters({
|
||||
{contentTypeOptions.map((option) => (
|
||||
<Menu.Item
|
||||
key={option.value}
|
||||
role="menuitemradio"
|
||||
component={RadioMenuItem}
|
||||
aria-checked={contentType === option.value}
|
||||
onClick={() =>
|
||||
!option.disabled &&
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useDebouncedValue } from "@mantine/hooks";
|
||||
import { IconCheck, IconSearch } from "@tabler/icons-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useGetSpacesQuery } from "@/features/space/queries/space-query";
|
||||
import { RadioMenuItem } from "@/components/ui/radio-menu-item";
|
||||
|
||||
type SpaceFilterMenuProps = {
|
||||
value: string | null;
|
||||
@@ -75,7 +76,7 @@ export function SpaceFilterMenu({
|
||||
|
||||
<ScrollArea.Autosize mah={280}>
|
||||
<Menu.Item
|
||||
role="menuitemradio"
|
||||
component={RadioMenuItem}
|
||||
aria-checked={!value}
|
||||
onClick={() => onChange(null)}
|
||||
>
|
||||
@@ -103,7 +104,7 @@ export function SpaceFilterMenu({
|
||||
{orderedSpaces.map((space) => (
|
||||
<Menu.Item
|
||||
key={space.id}
|
||||
role="menuitemradio"
|
||||
component={RadioMenuItem}
|
||||
aria-checked={value === space.id}
|
||||
onClick={() => onChange(space.id)}
|
||||
>
|
||||
|
||||
@@ -210,7 +210,9 @@ export default function SpaceMembersList({
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
c="gray"
|
||||
aria-label={t("Member actions")}
|
||||
aria-label={t("Member actions for {{name}}", {
|
||||
name: member.name,
|
||||
})}
|
||||
>
|
||||
<IconDots size={20} stroke={2} />
|
||||
</ActionIcon>
|
||||
|
||||
+7
-2
@@ -12,9 +12,14 @@ import useUserRole from "@/hooks/use-user-role.tsx";
|
||||
|
||||
interface Props {
|
||||
userId: string;
|
||||
name: string;
|
||||
deactivatedAt: Date | null;
|
||||
}
|
||||
export default function MemberActionMenu({ userId, deactivatedAt }: Props) {
|
||||
export default function MemberActionMenu({
|
||||
userId,
|
||||
name,
|
||||
deactivatedAt,
|
||||
}: Props) {
|
||||
const { t } = useTranslation();
|
||||
const deleteWorkspaceMemberMutation = useDeleteWorkspaceMemberMutation();
|
||||
const deactivateMutation = useDeactivateWorkspaceMemberMutation();
|
||||
@@ -86,7 +91,7 @@ export default function MemberActionMenu({ userId, deactivatedAt }: Props) {
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
c="gray"
|
||||
aria-label={t("Member actions")}
|
||||
aria-label={t("Member actions for {{name}}", { name })}
|
||||
>
|
||||
<IconDots size={20} stroke={2} />
|
||||
</ActionIcon>
|
||||
|
||||
+1
@@ -111,6 +111,7 @@ export default function WorkspaceMembersTable() {
|
||||
{isAdmin && (
|
||||
<MemberActionMenu
|
||||
userId={user.id}
|
||||
name={user.name}
|
||||
deactivatedAt={user.deactivatedAt}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user