77 lines
1.9 KiB
TypeScript
77 lines
1.9 KiB
TypeScript
import { ReactNode, useEffect, useRef } from 'react';
|
|
import * as L from 'leaflet';
|
|
import { useMap } from 'react-leaflet';
|
|
import { createRoot, Root } from 'react-dom/client';
|
|
|
|
export interface ButtonDef {
|
|
title: string;
|
|
active: boolean;
|
|
onClick: () => void;
|
|
icon: ReactNode;
|
|
}
|
|
|
|
interface GroupControlProps {
|
|
position?: L.ControlPosition;
|
|
buttons: ButtonDef[];
|
|
}
|
|
|
|
export function GroupControl({ position = 'bottomright', buttons }: GroupControlProps) {
|
|
const map = useMap();
|
|
// References
|
|
const controlRef = useRef<L.Control>(null);
|
|
const rootRef = useRef<Root>(null);
|
|
|
|
useEffect(() => {
|
|
const ctrl = new L.Control({ position });
|
|
controlRef.current = ctrl;
|
|
|
|
ctrl.onAdd = () => {
|
|
return L.DomUtil.create('div', 'leaflet-bar leaflet-control custom-control');
|
|
};
|
|
|
|
ctrl.addTo(map);
|
|
|
|
// @ts-expect-error ctrl is a L.Control
|
|
const container = (ctrl as unknown)._container as HTMLElement;
|
|
rootRef.current = createRoot(container);
|
|
L.DomEvent.disableClickPropagation(container);
|
|
|
|
return () => {
|
|
ctrl.remove();
|
|
rootRef.current!.unmount();
|
|
};
|
|
}, [map, position]);
|
|
|
|
useEffect(() => {
|
|
if (rootRef.current) {
|
|
rootRef.current.render(
|
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
{buttons.map((b, i) => (
|
|
<a
|
|
key={i}
|
|
href='#'
|
|
title={b.title}
|
|
className={b.active ? 'active' : ''}
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
b.onClick();
|
|
}}
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: '4px'
|
|
}}
|
|
>
|
|
{b.icon}
|
|
</a>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
}, [buttons]);
|
|
|
|
return null;
|
|
}
|