diff options
author | Marcin Zelent <marcin@zelent.net> | 2022-11-16 15:16:38 +0100 |
---|---|---|
committer | Marcin Zelent <marcin@zelent.net> | 2022-11-16 15:16:38 +0100 |
commit | f2ecc1803f3ea294a0c6b7915b61348ed0395b26 (patch) | |
tree | e8c6fb1350ae4f659b3f9ef8d17157158b974b16 /src/components/ReactLeafletControl/ReactLeafletControl.tsx | |
parent | efb64f24d6200a39870c0e8966ab4f87e07c93a9 (diff) |
Remade and extended the app using React
Diffstat (limited to 'src/components/ReactLeafletControl/ReactLeafletControl.tsx')
-rw-r--r-- | src/components/ReactLeafletControl/ReactLeafletControl.tsx | 104 |
1 files changed, 104 insertions, 0 deletions
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<E, P extends PropsWithChildren>(
+ useElement: ElementHook<E, P>,
+): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<E>> {
+ function ContainerComponent(props: P, ref: Ref<E>): 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(<LeafletProvider value={context}>{children}</LeafletProvider>, contentNode);
+ }
+
+ return forwardRef(ContainerComponent);
+}
+
+export function createControlComponent<E extends Control, P extends ControlOptionsWithChildren>(
+ createInstance: (props: P) => E,
+): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<E>> {
+ function createElement(props: P, context: LeafletContextInterface): LeafletElement<E> {
+ return { instance: createInstance(props), context };
+ }
+ const useElement = createElementHook(createElement);
+ const useControl = createControlHook(useElement);
+ return createContainerComponent(useControl);
+}
+
+const ReactLeafletControl = createControlComponent<IDumbControl, ControlOptionsWithChildren>(
+ function createControlWithChildren(props) {
+ return new DumbControl(props);
+ },
+);
+
+export default ReactLeafletControl;
|