1
- /* eslint-disable jsdoc/require-returns */
2
- /* eslint-disable jsdoc/require-jsdoc */
3
1
import L from 'leaflet' ;
4
2
import React , { useState , createRef , useEffect } from 'react' ;
5
3
import { useMap } from 'react-leaflet' ;
6
4
7
5
interface ControlProps {
8
- position : L . ControlPosition ;
6
+ position : 'bottomleft' | 'bottomright' | 'topleft' | 'topright' ;
9
7
children ?: React . ReactNode ;
10
8
container ?: React . HTMLAttributes < HTMLDivElement > ;
11
9
prepend ?: boolean ;
@@ -18,14 +16,22 @@ const POSITION_CLASSES = {
18
16
topright : 'leaflet-top leaflet-right' ,
19
17
} ;
20
18
19
+ /**
20
+ * Custom control component for Leaflet maps using React.
21
+ * @param props - The properties object.
22
+ * @param props.position - The position of the control on the map.
23
+ * @param [props.children] - The child elements to be rendered inside the control.
24
+ * @param [props.container] - Additional HTML attributes for the control container.
25
+ * @param [props.prepend] - Whether to prepend the control to the container.
26
+ * @returns The custom control component.
27
+ */
21
28
function Control ( {
22
29
position,
23
30
children,
24
31
container,
25
32
prepend,
26
33
} : ControlProps ) : JSX . Element {
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
- const [ portalRoot , setPortalRoot ] = useState < any > (
34
+ const [ portalRoot , setPortalRoot ] = useState < HTMLElement > (
29
35
document . createElement ( 'div' ) ,
30
36
) ;
31
37
const positionClass =
@@ -35,8 +41,8 @@ function Control({
35
41
36
42
/**
37
43
* Whenever the control container ref is created,
38
- * Ensure the click / scroll propagation is removed
39
- * This way click/scroll events do not bubble down to the map
44
+ * ensure the click/ scroll propagation is removed.
45
+ * This way click/scroll events do not bubble down to the map.
40
46
*/
41
47
useEffect ( ( ) => {
42
48
if ( controlContainerRef . current !== null ) {
@@ -46,21 +52,23 @@ function Control({
46
52
} , [ controlContainerRef ] ) ;
47
53
48
54
/**
49
- * Whenever the position is changed, go ahead and get the container of the map and the first
50
- * instance of the position class in that map container
55
+ * Whenever the position is changed, go ahead and get the container of the map
56
+ * and the first instance of the position class in that map container.
51
57
*/
52
58
useEffect ( ( ) => {
53
59
const mapContainer = map . getContainer ( ) ;
54
- const targetDiv = mapContainer . getElementsByClassName ( positionClass ) ;
55
- setPortalRoot ( targetDiv [ 0 ] ) ;
60
+ const targetDiv = mapContainer . getElementsByClassName ( positionClass ) [ 0 ] ;
61
+ if ( targetDiv ) {
62
+ setPortalRoot ( targetDiv as HTMLElement ) ;
63
+ }
56
64
} , [ positionClass , map ] ) ;
57
65
58
66
/**
59
67
* Whenever the portal root is complete,
60
- * append or prepend the control container to the portal root
68
+ * append or prepend the control container to the portal root.
61
69
*/
62
70
useEffect ( ( ) => {
63
- if ( portalRoot !== null ) {
71
+ if ( portalRoot && controlContainerRef . current ) {
64
72
if ( prepend !== undefined && prepend === true ) {
65
73
portalRoot . prepend ( controlContainerRef . current ) ;
66
74
} else {
@@ -70,8 +78,9 @@ function Control({
70
78
} , [ portalRoot , prepend , controlContainerRef ] ) ;
71
79
72
80
/**
73
- * Concatenate the props.container className to the class of the control div, per leaflet's built in styles.
74
- * Will need to change styling of component itself based on screen breakpoints
81
+ * Concatenate the props.container className to the class of the control div,
82
+ * per Leaflet's built-in styles.
83
+ * Will need to change styling of the component itself based on screen breakpoints.
75
84
*/
76
85
const className = `${ container ?. className ?. concat ( ' ' ) || '' } leaflet-control` ;
77
86
0 commit comments