From f2ecc1803f3ea294a0c6b7915b61348ed0395b26 Mon Sep 17 00:00:00 2001
From: Marcin Zelent <marcin@zelent.net>
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<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;
-- 
cgit v1.2.3

