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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ You can also check the
- 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
- Keyboard access to shared widgets: menus (chart and dashboard actions,
"Download data", user menu, profile rows) open on their first item and
work with the arrow keys; confirmation dialogs open outside the menu; the
"Add chart" popover, color palette select and color picker (saturation,
hue, swatches) are operable by keyboard; time sliders and time range
brushes move with arrow keys, Home and End and announce their value; Tab
no longer gets trapped in the rich text editor, whose toolbar uses arrow
keys and shows the active format, also in forced colors mode; Escape
closes the editor drawers, the link dialog and the date picker without
closing the options panel
- Accessible names for icon-only buttons, selects, radio groups, editors
and color controls, linked error messages, and a "Skip to main content"
link on every page

## 6.5.7 - 2026-11-10

Expand Down
3 changes: 2 additions & 1 deletion app/browse/ui/search-dataset-sort-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ export const SearchDatasetSortControl = ({

return (
<Flex alignItems="center" gap={2}>
<label htmlFor="datasetSort">
<label id="datasetSort-label" htmlFor="datasetSort">
<Typography variant="body3">
<Trans id="dataset.sortby">Sort by</Trans>
</Typography>
</label>
<Select
id="datasetSort"
labelId="datasetSort-label"
data-testId="datasetSort"
variant="standard"
size="sm"
Expand Down
22 changes: 19 additions & 3 deletions app/charts/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ScatterplotLayer,
ScatterplotLayerProps,
} from "@deck.gl/layers";
import { t } from "@lingui/macro";
import { supported } from "@mapbox/mapbox-gl-supported";
import { Button, Theme } from "@mui/material";
import { makeStyles } from "@mui/styles";
Expand Down Expand Up @@ -566,9 +567,21 @@ export const MapComponent = ({
<>
{locked ? null : (
<div className={classes.controlButtons} {...DISABLE_SCREENSHOT_ATTR}>
<ControlButton iconName="refresh" onClick={reset} />
<ControlButton iconName="plus" onClick={zoomIn} />
<ControlButton iconName="minus" onClick={zoomOut} />
<ControlButton
iconName="refresh"
label={t({ id: "chart.map.reset", message: "Reset map view" })}
onClick={reset}
/>
<ControlButton
iconName="plus"
label={t({ id: "chart.map.zoom-in", message: "Zoom in" })}
onClick={zoomIn}
/>
<ControlButton
iconName="minus"
label={t({ id: "chart.map.zoom-out", message: "Zoom out" })}
onClick={zoomOut}
/>
</div>
)}

Expand Down Expand Up @@ -638,9 +651,11 @@ export const MapComponent = ({

const ControlButton = ({
iconName,
label,
onClick,
}: {
iconName: IconName;
label: string;
onClick: () => void;
}) => {
const classes = useStyles();
Expand All @@ -649,6 +664,7 @@ const ControlButton = ({
<Button
className={classes.controlButton}
variant="contained"
aria-label={label}
onClick={onClick}
// The stacked buttons would cover an outside ring.
sx={{ [FOCUS_VISIBLE]: FOCUS_OUTLINE_INSET }}
Expand Down
54 changes: 51 additions & 3 deletions app/charts/map/wms-wmts-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro";
import { plural, t, Trans } from "@lingui/macro";
import { TreeItem, TreeView } from "@mui/lab";
import {
Box,
Expand All @@ -14,7 +14,7 @@ import {
import { makeStyles } from "@mui/styles";
import sortBy from "lodash/sortBy";
import uniqBy from "lodash/uniqBy";
import { useCallback, useMemo, useState } from "react";
import { useCallback, useMemo, useRef, useState } from "react";
import createStore from "zustand";

import { RemoteLayer } from "@/charts/map/types";
Expand All @@ -28,6 +28,7 @@ import { ProviderAutocomplete } from "@/charts/map/wms-wmts-providers-autocomple
import { RemoteWMTSLayer } from "@/charts/map/wmts-utils";
import { Flex } from "@/components/flex";
import { HintError, Spinner } from "@/components/hint";
import { LiveRegion } from "@/components/live-region";
import { Tree, useSelectTree } from "@/components/select-tree";
import { Icon } from "@/icons";
import SvgIcChevronRight from "@/icons/components/IcChevronRight";
Expand Down Expand Up @@ -103,6 +104,7 @@ const LegendButton = ({
}: {
layer: RemoteWMTSLayer | RemoteWMSLayer;
}) => {
const { title } = layer;
const [showLegend, setShowLegend] = useState<
| {
value: string;
Expand All @@ -115,6 +117,10 @@ const LegendButton = ({
<IconButton
data-value={layer.path}
size="small"
aria-label={t({
id: "wmts.legend-for",
message: `Legend: ${title}`,
})}
onClick={(ev) => {
return setShowLegend({
value: layer.path,
Expand All @@ -137,6 +143,7 @@ const LegendButton = ({
<IconButton
sx={{ position: "absolute", top: "0.25rem", right: "0.25rem" }}
size="small"
aria-label={t({ id: "button.close", message: "Close" })}
onClick={() => setShowLegend(undefined)}
>
<SvgIcClose />
Expand Down Expand Up @@ -297,6 +304,16 @@ export const WMTSSelector = ({
onChangeInputValue: setInputValue,
});

const searchInputRef = useRef<HTMLInputElement>(null);
const resultsCount = useMemo(() => {
let count = 0;
visitHierarchy(unsortedFilteredOptions, () => {
count++;
});

return count;
}, [unsortedFilteredOptions]);

const filteredOptions = useMemo(() => {
return mapTree(
sortBy(unsortedFilteredOptions, (x) => x.label),
Expand Down Expand Up @@ -382,15 +399,32 @@ export const WMTSSelector = ({
<Input
size="sm"
value={inputValue}
inputRef={searchInputRef}
autoFocus
startAdornment={<Icon name="search" size={18} />}
placeholder={t({
id: "wmts.search-placeholder",
message: "Search in imported maps...",
})}
inputProps={{
"aria-label": t({
id: "wmts.search-label",
message: "Search in imported maps",
}),
}}
endAdornment={
inputValue.length > 0 ? (
<IconButton size="small" onClick={handleClickResetInput}>
<IconButton
size="small"
aria-label={t({
id: "controls.search.clear",
message: "Clear search field",
})}
onClick={() => {
handleClickResetInput();
searchInputRef.current?.focus();
}}
>
<Icon name="close" size={16} />
</IconButton>
) : null
Expand Down Expand Up @@ -418,6 +452,20 @@ export const WMTSSelector = ({
>
{renderTreeContent(filteredOptions)}
</TreeView>
<LiveRegion
message={
inputValue && status !== "fetching"
? t({
id: "wmts.search-results",
message: plural(resultsCount, {
0: "No results",
one: "# result",
other: "# results",
}),
})
: ""
}
/>
</Flex>
);
};
Loading