Files
aviation/ui/src/components/GroupControl.tsx

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;
}