Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ You can also check the

## Next Release

- Fixes
- Keyboard focus is now visible on buttons, links, tabs and menu items, the
switch has sufficient contrast, and switches and tabs stay visible in
forced colors (high contrast) mode

## 6.5.7 - 2026-11-10

- Fixes
Expand Down
3 changes: 3 additions & 0 deletions app/browse/ui/navigation-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { NavigationChip } from "@/browse/ui/navigation-chip";
import { MaybeLink } from "@/components/maybe-link";
import { accordionPresenceProps, MotionBox } from "@/components/presence";
import SvgIcClose from "@/icons/components/IcClose";
import { FOCUS_OUTLINE_INSET } from "@/themes/focus";

export const NavigationItem = ({
children,
Expand Down Expand Up @@ -155,6 +156,8 @@ const useStyles = makeStyles<Theme, { level: number }>((theme) => ({
"&:hover": {
backgroundColor: theme.palette.cobalt[50],
},

"&:focus-visible": FOCUS_OUTLINE_INSET,
},
removeFilterButton: ({ level }) => ({
display: "flex",
Expand Down
2 changes: 1 addition & 1 deletion app/browse/ui/search-dataset-sort-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const SearchDatasetSortControl = ({
}, [disableScore]);

return (
<Flex alignItems="center">
<Flex alignItems="center" gap={2}>
<label htmlFor="datasetSort">
<Typography variant="body3">
<Trans id="dataset.sortby">Sort by</Trans>
Expand Down
15 changes: 12 additions & 3 deletions app/browse/ui/select-dataset-step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,11 @@ const SelectDatasetStepInner = ({
<MotionBox
key="navigation"
initial={{ opacity: 0, height: 0, overflow: "hidden" }}
animate={{ opacity: 1, height: "auto" }}
animate={{
opacity: 1,
height: "auto",
transitionEnd: { overflow: "visible" },
}}
exit={{ opacity: 0, height: 0 }}
// To match mode="wait" enter / exit animation duration
transition={{ duration: odsIframe ? 0 : DURATION * 2 }}
Expand Down Expand Up @@ -574,6 +578,8 @@ const useStyles = makeStyles<
},
panelLeft: {
marginBottom: theme.spacing(12),
paddingInline: theme.spacing(1),
marginInline: theme.spacing(-1),
boxShadow: "none",
outline: "none",
transition: "padding-top 0.5s ease",
Expand All @@ -582,8 +588,11 @@ const useStyles = makeStyles<
position: ({ datasetPresent }) => (datasetPresent ? "static" : "sticky"),
top: ({ datasetPresent }) => (datasetPresent ? 0 : theme.spacing(8)),
overflowY: "auto",
minHeight: "100vh",
maxHeight: ({ datasetPresent }) => (datasetPresent ? "none" : "100vh"),
boxSizing: "border-box",
minHeight: ({ datasetPresent }) =>
datasetPresent ? "100vh" : `calc(100vh - ${theme.spacing(8)})`,
maxHeight: ({ datasetPresent }) =>
datasetPresent ? "none" : `calc(100vh - ${theme.spacing(8)})`,
marginBottom: "unset",
paddingBottom: ({ datasetPresent }) =>
datasetPresent ? 0 : theme.spacing(16),
Expand Down
5 changes: 5 additions & 0 deletions app/charts/combo/axis-height-linear-dual.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { useChartState } from "@/charts/shared/chart-state";
import { useChartTheme } from "@/charts/shared/use-chart-theme";
import { DISABLE_SCREENSHOT_COLOR_WIPE_ATTR } from "@/components/chart-shared";
import { OpenMetadataPanelWrapper } from "@/components/metadata-panel";
import {
FOCUS_OUTLINE_ON_FILL_CLASS_NAME,
INSET_FOCUS_OUTLINE_CLASS_NAME,
} from "@/themes/focus";
import { theme } from "@/themes/theme";

type AxisHeightLinearDualProps = {
Expand Down Expand Up @@ -56,6 +60,7 @@ export const AxisHeightLinearDual = (props: AxisHeightLinearDualProps) => {
return (
<>
<foreignObject
className={`${INSET_FOCUS_OUTLINE_CLASS_NAME} ${FOCUS_OUTLINE_ON_FILL_CLASS_NAME}`}
data-testid={`axis-title-${orientation}`}
x={axisTitleX}
width={axisTitleWidth}
Expand Down
2 changes: 2 additions & 0 deletions app/charts/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
import { GeoFeature, GeoPoint } from "@/domain/data";
import { Icon, IconName } from "@/icons";
import { useLocale } from "@/locales/use-locale";
import { FOCUS_OUTLINE_INSET, FOCUS_VISIBLE } from "@/themes/focus";
import { hexToRgba } from "@/utils/color-utils";
import { useEvent } from "@/utils/use-event";
import { DISABLE_SCREENSHOT_ATTR } from "@/utils/use-screenshot";
Expand Down Expand Up @@ -649,6 +650,7 @@ const ControlButton = ({
className={classes.controlButton}
variant="contained"
onClick={onClick}
sx={{ [FOCUS_VISIBLE]: FOCUS_OUTLINE_INSET }}
>
<Icon name={iconName} size={24} />
</Button>
Expand Down
2 changes: 2 additions & 0 deletions app/charts/shared/axis-height-title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AxisHeightLinearChartState } from "@/charts/shared/axis-height-linear";
import { useChartState } from "@/charts/shared/chart-state";
import { useChartTheme } from "@/charts/shared/use-chart-theme";
import { OpenMetadataPanelWrapper } from "@/components/metadata-panel";
import { INSET_FOCUS_OUTLINE_CLASS_NAME } from "@/themes/focus";

// Axis title can be used in both "linear" and pie charts.
type AxisHeightTitleChartState = AxisHeightLinearChartState | PieState;
Expand All @@ -28,6 +29,7 @@ export const AxisHeightTitle = () => {
</text>
) : (
<foreignObject
className={INSET_FOCUS_OUTLINE_CLASS_NAME}
y={leftAxisLabelOffsetTop}
width={leftAxisLabelSize.width}
height={leftAxisLabelSize.height}
Expand Down
5 changes: 5 additions & 0 deletions app/charts/table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import { Flex } from "@/components/flex";
import { Input, Switch } from "@/components/form";
import { Observation } from "@/domain/data";
import { Icon } from "@/icons";
import {
FOCUS_OUTLINE_INSET,
FOCUS_VISIBLE_WITHIN_FIELD,
} from "@/themes/focus";
import { DISABLE_SCREENSHOT_ATTR } from "@/utils/use-screenshot";

const MOBILE_VIEW_THRESHOLD = 384;
Expand Down Expand Up @@ -312,6 +316,7 @@ export const Table = () => {
message: "Search...",
})}
endAdornment={<Icon name="search" />}
sx={{ [FOCUS_VISIBLE_WITHIN_FIELD]: FOCUS_OUTLINE_INSET }}
value={searchTerm}
onChange={(e) => setSearchTerm(e.currentTarget.value)}
/>
Expand Down
2 changes: 2 additions & 0 deletions app/components/chart-footnotes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Component, Measure } from "@/domain/data";
import { useTimeFormatLocale } from "@/formatters";
import { useDataCubesMetadataQuery } from "@/graphql/hooks";
import { useLocale } from "@/locales/use-locale";
import { UNCLIP_FOCUS_OUTLINE } from "@/themes/focus";
import { DISABLE_SCREENSHOT_ATTR } from "@/utils/use-screenshot";

export const useFootnotesStyles = makeStyles<Theme, { useMarginTop: boolean }>(
Expand All @@ -39,6 +40,7 @@ export const useFootnotesStyles = makeStyles<Theme, { useMarginTop: boolean }>(
alignItems: "center",
flexWrap: "wrap",
overflow: "hidden",
...UNCLIP_FOCUS_OUTLINE,
fontSize: theme.typography.caption.fontSize,
"& > button": {
minWidth: "auto",
Expand Down
2 changes: 1 addition & 1 deletion app/components/data-download.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const DataDownloadInnerMenu = ({
width: "fit-content",
minHeight: 0,
p: 0,
ml: "2.5px",
ml: 0,
fontSize: "inherit",
}}
>
Expand Down
80 changes: 31 additions & 49 deletions app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { t } from "@lingui/macro";
import { Link, SxProps } from "@mui/material";
import { SxProps } from "@mui/material";
import NextLink from "next/link";

import contentRoutes from "@/content-routes.json";
Expand Down Expand Up @@ -91,62 +91,44 @@ export const Footer = ({ sx }: { sx?: SxProps }) => {
message: "Further information",
})}
/>
<Link
<FooterSectionButton
href={`https://lindas.admin.ch/?lang=${locale}`}
target="_blank"
underline="none"
>
<FooterSectionButton
iconName="external"
label={t({
id: "footer.button.lindas",
message: "LINDAS Linked Data Services",
})}
/>
</Link>
<Link
iconName="external"
label={t({
id: "footer.button.lindas",
message: "LINDAS Linked Data Services",
})}
/>
<FooterSectionButton
href={`https://cognizone.atlassian.net/servicedesk/customer/portal/1`}
target="_blank"
underline="none"
>
<FooterSectionButton
iconName="external"
label={t({
id: "footer.button.service-desk",
message: "Service Desk",
})}
/>
</Link>
<Link
iconName="external"
label={t({
id: "footer.button.service-desk",
message: "Service Desk",
})}
/>
<FooterSectionButton
href={`https://www.youtube.com/@visualizetutorials`}
target="_blank"
underline="none"
>
<FooterSectionButton
iconName="external"
label={t({
id: "footer.tutorials",
message: "Tutorials",
})}
/>
</Link>
<NextLink href="/statistics" passHref legacyBehavior>
<Link underline="none">
<FooterSectionButton
label={t({ id: "footer.statistics", message: "Statistics" })}
/>
</Link>
</NextLink>
<Link
iconName="external"
label={t({
id: "footer.tutorials",
message: "Tutorials",
})}
/>
<FooterSectionButton
href="/statistics"
LinkComponent={NextLink}
label={t({ id: "footer.statistics", message: "Statistics" })}
/>
<FooterSectionButton
href="https://status.lindas.admin.ch/"
target="_blank"
underline="none"
>
<FooterSectionButton
iconName="external"
label={t({ id: "footer.status", message: "Status" })}
/>
</Link>
iconName="external"
label={t({ id: "footer.status", message: "Status" })}
/>
</FooterSection>
</SwissFederalCiFooter>
);
Expand Down
10 changes: 10 additions & 0 deletions app/components/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ export const VisualizeTab = styled(Tab)<TabProps>(({ theme }) => {
"&.Mui-selected": {
borderBottomColor: theme.palette.background.paper,
},
"@media (forced-colors: active)": {
"&.Mui-selected": {
forcedColorAdjust: "none",
backgroundColor: "Canvas",
color: "CanvasText",
borderColor: "CanvasText",
borderBottomColor: "Canvas",
boxShadow: "inset 0 3px 0 Highlight",
},
},
minWidth: "fit-content",
padding: theme.spacing(0, 2),
};
Expand Down
2 changes: 1 addition & 1 deletion app/configurator/components/annotator-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const AnnotatorOptions = ({
id={`annotator-panel-${activeField}`}
aria-labelledby={`annotator-tab-${activeField}`}
tabIndex={-1}
sx={{ overflowX: "hidden", overflowY: "auto" }}
sx={{ overflowX: "hidden", overflowY: "auto", outline: "none" }}
>
<ControlSection hideTopBorder>
<SectionTitle closable>{getFieldLabel(activeField)}</SectionTitle>
Expand Down
3 changes: 3 additions & 0 deletions app/configurator/components/chart-configurator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import {
import { Icon } from "@/icons";
import { useLocale } from "@/locales/use-locale";
import { InteractiveFiltersChartProvider } from "@/stores/interactive-filters";
import { UNCLIP_FOCUS_OUTLINE } from "@/themes/focus";
import { useEvent } from "@/utils/use-event";

export const DataFilterSelectGeneric = ({
Expand Down Expand Up @@ -574,9 +575,11 @@ const useStyles = makeStyles<Theme, { fetching: boolean }>((theme) => ({
overflow: "hidden",
width: "100%",
marginBottom: theme.spacing(5),
...UNCLIP_FOCUS_OUTLINE,

"& > *": {
overflow: "hidden",
...UNCLIP_FOCUS_OUTLINE,
},

"&:last-child": {
Expand Down
2 changes: 2 additions & 0 deletions app/configurator/components/chart-controls/color-ramp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
getColorInterpolator,
sequentialPalettes,
} from "@/palettes";
import { FOCUS_OUTLINE_INSET, FOCUS_VISIBLE } from "@/themes/focus";
import { getFittingColorInterpolator } from "@/utils/color-palette-utils";
import { useEvent } from "@/utils/use-event";
import { useUserPalettes } from "@/utils/use-user-palettes";
Expand Down Expand Up @@ -297,6 +298,7 @@ const PaletteSection = (props: PaletteSectionProps) => {
width: "100%",
paddingY: 3,
paddingX: 4,
[FOCUS_VISIBLE]: FOCUS_OUTLINE_INSET,
}}
>
<Trans id="login.profile.my-color-palettes.add">
Expand Down
2 changes: 2 additions & 0 deletions app/configurator/components/chart-controls/control-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Component } from "@/domain/data";
import { Icon, IconName } from "@/icons";
import SvgIcPen from "@/icons/components/IcPen";
import SvgIcWarningCircle from "@/icons/components/IcWarningCircle";
import { FOCUS_OUTLINE_INSET, FOCUS_VISIBLE } from "@/themes/focus";
import { useEvent } from "@/utils/use-event";

export const ControlTabFieldInner = ({
Expand Down Expand Up @@ -322,6 +323,7 @@ const ControlTabButton = ({
backgroundColor: checked
? (t) => `${t.palette.cobalt[50]} !important`
: "transparent",
[FOCUS_VISIBLE]: FOCUS_OUTLINE_INSET,
}}
>
{children}
Expand Down
17 changes: 17 additions & 0 deletions app/configurator/components/chart-controls/drag-and-drop-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { getIconName } from "@/configurator/components/ui-helpers";
import { useActiveChartField } from "@/configurator/config-form";
import { Component, Dimension, Measure } from "@/domain/data";
import { FOCUS_OUTLINE_INSET, UNCLIP_FOCUS_OUTLINE } from "@/themes/focus";

const useStyles = makeStyles((theme: Theme) => ({
filterRow: {
Expand All @@ -25,9 +26,25 @@ const useStyles = makeStyles((theme: Theme) => ({
gridColumnGap: theme.spacing(2),
gridTemplateRows: "min-content min-content",
gridTemplateAreas: '"description drag-button" "select drag-button"',
position: "relative",
...UNCLIP_FOCUS_OUTLINE,

"&:focus-visible": {
outline: "none",

"&::after": {
content: '""',
position: "absolute",
inset: 0,
zIndex: 1,
pointerEvents: "none",
...FOCUS_OUTLINE_INSET,
},
},

"& > *": {
overflow: "hidden",
...UNCLIP_FOCUS_OUTLINE,
},
},
dragButtons: {
Expand Down
3 changes: 3 additions & 0 deletions app/configurator/components/chart-controls/section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { useDisclosure } from "@/components/use-disclosure";
import { isConfiguring, isLayouting } from "@/configurator/configurator-state";
import { Icon, IconName } from "@/icons";
import { useConfiguratorState } from "@/src";
import { FOCUS_OUTLINE_INSET } from "@/themes/focus";

const useControlSectionStyles = makeStyles<Theme, { hideTopBorder: boolean }>(
(theme) => ({
Expand Down Expand Up @@ -85,6 +86,8 @@ export const useSectionTitleStyles = makeStyles<
WebkitUserSelect: "none",
transition: "background-color 0.2s ease",

"&:focus-visible": FOCUS_OUTLINE_INSET,

"&:hover": {
cursor: ({ interactive }) => (interactive ? "pointer" : "initial"),
backgroundColor: ({ interactive }) => {
Expand Down
Loading
Loading