From f2ecc1803f3ea294a0c6b7915b61348ed0395b26 Mon Sep 17 00:00:00 2001 From: Marcin Zelent Date: Wed, 16 Nov 2022 15:16:38 +0100 Subject: Remade and extended the app using React --- .../ReactLeafletControl/ReactLeafletControl.tsx | 104 +++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/components/ReactLeafletControl/ReactLeafletControl.tsx (limited to 'src/components/ReactLeafletControl/ReactLeafletControl.tsx') diff --git a/src/components/ReactLeafletControl/ReactLeafletControl.tsx b/src/components/ReactLeafletControl/ReactLeafletControl.tsx new file mode 100644 index 0000000..2592b25 --- /dev/null +++ b/src/components/ReactLeafletControl/ReactLeafletControl.tsx @@ -0,0 +1,104 @@ +import React, { + useState, + useEffect, + forwardRef, + useImperativeHandle, + Ref, + ReactNode, + ReactPortal, +} from 'react'; +import { createPortal } from 'react-dom'; +import { Control, ControlOptions, DomUtil, DomEvent, Map } from 'leaflet'; +import { + ElementHook, + LeafletProvider, + LeafletElement, + createElementHook, + LeafletContextInterface, + createControlHook, +} from '@react-leaflet/core'; +import { useMap } from 'react-leaflet'; + +interface IDumbControl extends Control {} +interface PropsWithChildren { + children?: ReactNode; +} +interface ControlOptionsWithChildren extends ControlOptions { + children?: ReactNode; +} + +const DumbControl = Control.extend({ + options: { + className: '', + onOff: '', + handleOff: function noop() {}, + }, + + onAdd(/* map */) { + const _controlDiv = DomUtil.create('div', this.options.className); + + DomEvent.on(_controlDiv, 'click', (event) => { + DomEvent.stopPropagation(event); + }); + DomEvent.disableScrollPropagation(_controlDiv); + DomEvent.disableClickPropagation(_controlDiv); + + return _controlDiv; + }, + + onRemove(map: Map) { + if (this.options.onOff !== '') { + map.off(this.options.onOff, this.options.handleOff, this); + } + + return this; + }, +}); + +const useForceUpdate: () => () => void = () => { + const [, setValue] = useState(0); // integer state + return () => setValue((value) => value + 1); // update the state to force render +}; + +export function createContainerComponent( + useElement: ElementHook, +): React.ForwardRefExoticComponent & React.RefAttributes> { + function ContainerComponent(props: P, ref: Ref): ReactPortal | null { + const forceUpdate = useForceUpdate(); + const map = useMap(); + const ctx = { __version: 0, map }; + const { instance, context } = useElement(props, ctx).current; + const children = props.children; + const contentNode = (instance as any).getContainer(); + + useImperativeHandle(ref, () => instance); + useEffect(() => { + forceUpdate(); + }, [contentNode]); + + if (children === undefined || contentNode === undefined) return null; + + return createPortal({children}, contentNode); + } + + return forwardRef(ContainerComponent); +} + +export function createControlComponent( + createInstance: (props: P) => E, +): React.ForwardRefExoticComponent & React.RefAttributes> { + function createElement(props: P, context: LeafletContextInterface): LeafletElement { + return { instance: createInstance(props), context }; + } + const useElement = createElementHook(createElement); + const useControl = createControlHook(useElement); + return createContainerComponent(useControl); +} + +const ReactLeafletControl = createControlComponent( + function createControlWithChildren(props) { + return new DumbControl(props); + }, +); + +export default ReactLeafletControl; -- cgit v1.2.3