Skip to content

Commit c64960e

Browse files
committed
disable max zoom control
1 parent 6a1d620 commit c64960e

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

src/features/map/components/MapControls.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ type MapControlClusterProps = {
1818
onZoomIn: () => void;
1919
onZoomOut: () => void;
2020
searchLabel?: string;
21+
zoomInDisabled?: boolean;
2122
zoomInLabel: string;
2223
zoomOutLabel: string;
2324
};
2425

2526
type MapZoomControlsProps = {
2627
onZoomIn: () => void;
2728
onZoomOut: () => void;
29+
zoomInDisabled?: boolean;
2830
zoomInLabel: string;
2931
zoomOutLabel: string;
3032
};
@@ -71,6 +73,20 @@ const controlButtonStyles = css`
7173
outline: 3px solid ${theme.colors.focus.outline};
7274
}
7375
76+
&:disabled {
77+
cursor: default;
78+
}
79+
80+
&:disabled svg {
81+
opacity: 0.35;
82+
transform: none;
83+
}
84+
85+
&:disabled:hover,
86+
&:disabled:active {
87+
background: ${theme.colors.background.top};
88+
}
89+
7490
svg {
7591
width: 1rem;
7692
height: 1rem;
@@ -125,6 +141,7 @@ const ZoomButton = styled.button`
125141
export function MapZoomControls({
126142
onZoomIn,
127143
onZoomOut,
144+
zoomInDisabled = false,
128145
zoomInLabel,
129146
zoomOutLabel,
130147
}: MapZoomControlsProps) {
@@ -133,6 +150,7 @@ export function MapZoomControls({
133150
<ZoomControlGroup
134151
onZoomIn={onZoomIn}
135152
onZoomOut={onZoomOut}
153+
zoomInDisabled={zoomInDisabled}
136154
zoomInLabel={zoomInLabel}
137155
zoomOutLabel={zoomOutLabel}
138156
/>
@@ -143,6 +161,7 @@ export function MapZoomControls({
143161
function ZoomControlGroup({
144162
onZoomIn,
145163
onZoomOut,
164+
zoomInDisabled = false,
146165
zoomInLabel,
147166
zoomOutLabel,
148167
}: MapZoomControlsProps) {
@@ -153,6 +172,7 @@ function ZoomControlGroup({
153172
aria-label={zoomInLabel}
154173
title={zoomInLabel}
155174
data-testid="map-control-zoom-in"
175+
disabled={zoomInDisabled}
156176
onClick={onZoomIn}
157177
>
158178
<MapControlPlusIcon aria-hidden="true" />
@@ -178,6 +198,7 @@ export default function MapControls({
178198
onZoomIn,
179199
onZoomOut,
180200
searchLabel,
201+
zoomInDisabled = false,
181202
zoomInLabel,
182203
zoomOutLabel,
183204
}: MapControlClusterProps) {
@@ -209,6 +230,7 @@ export default function MapControls({
209230
<ZoomControlGroup
210231
onZoomIn={onZoomIn}
211232
onZoomOut={onZoomOut}
233+
zoomInDisabled={zoomInDisabled}
212234
zoomInLabel={zoomInLabel}
213235
zoomOutLabel={zoomOutLabel}
214236
/>

src/features/map/components/MapView.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ const PIN_HALO_MIN_ZOOM = 8;
113113
const PIN_HALO_MIN_SCALE = 0.18;
114114
const PIN_HALO_FULL_ZOOM = MAP_MAX_ZOOM;
115115
const PIN_HALO_GROWTH_EXPONENT = 2.2;
116+
const MAP_ZOOM_DISABLED_EPSILON = 0.001;
116117

117118
type MapPinZoomStyle = CSSProperties & {
118119
"--map-pin-compact-scale": string;
@@ -167,6 +168,10 @@ function resolveMapPinZoomVariables(zoom: number): MapPinZoomStyle {
167168
};
168169
}
169170

171+
function isMapZoomAtMax(zoom: number) {
172+
return zoom >= MAP_MAX_ZOOM - MAP_ZOOM_DISABLED_EPSILON;
173+
}
174+
170175
function resolveInitialViewState(
171176
selectedListing: SelectedListing | null,
172177
initialCoordinates: InitialMapCoordinates | null
@@ -229,6 +234,9 @@ export default function MapView({
229234
() => resolveInitialViewState(selectedListing, initialCoordinates),
230235
[initialCoordinates, selectedListing]
231236
);
237+
const [isZoomInDisabled, setIsZoomInDisabled] = useState(() =>
238+
isMapZoomAtMax(initialViewState.zoom)
239+
);
232240
const hasInitialPosition =
233241
hasValidCoordinates(selectedListing) || initialCoordinates !== null;
234242

@@ -258,6 +266,16 @@ export default function MapView({
258266
[requestBounds]
259267
);
260268

269+
const syncZoomControlState = useCallback((zoom: number) => {
270+
const nextIsZoomInDisabled = isMapZoomAtMax(zoom);
271+
272+
setIsZoomInDisabled((currentIsZoomInDisabled) =>
273+
currentIsZoomInDisabled === nextIsZoomInDisabled
274+
? currentIsZoomInDisabled
275+
: nextIsZoomInDisabled
276+
);
277+
}, []);
278+
261279
const applyMapPinZoomVariables = useCallback((zoom: number) => {
262280
const container = mapContainerRef.current;
263281
if (!container) return;
@@ -324,10 +342,11 @@ export default function MapView({
324342
if (!map) return null;
325343

326344
applyMapPinZoomVariables(map.getZoom());
345+
syncZoomControlState(map.getZoom());
327346
emitBoundsChange(map.getBounds());
328347

329348
return map;
330-
}, [applyMapPinZoomVariables, emitBoundsChange]);
349+
}, [applyMapPinZoomVariables, emitBoundsChange, syncZoomControlState]);
331350

332351
const handleLoad = useCallback(() => {
333352
handleMapLoad();
@@ -389,8 +408,9 @@ export default function MapView({
389408
const handleMove = useCallback(
390409
(event: ViewStateChangeEvent) => {
391410
scheduleMapPinZoomUpdate(event.viewState.zoom);
411+
syncZoomControlState(event.viewState.zoom);
392412
},
393-
[scheduleMapPinZoomUpdate]
413+
[scheduleMapPinZoomUpdate, syncZoomControlState]
394414
);
395415

396416
const handleMoveEnd = useCallback(
@@ -517,6 +537,7 @@ export default function MapView({
517537
onZoomIn={zoomIn}
518538
onZoomOut={zoomOut}
519539
searchLabel={t("searchLabel")}
540+
zoomInDisabled={isZoomInDisabled}
520541
zoomInLabel={t("zoomInControl")}
521542
zoomOutLabel={t("zoomOutControl")}
522543
/>

0 commit comments

Comments
 (0)