Skip to content

Commit acef950

Browse files
author
wgj
committed
feature: DivIcon support single jsx element.
Signed-off-by: wgj <wgj>
1 parent 5ec1119 commit acef950

File tree

7 files changed

+76
-54
lines changed

7 files changed

+76
-54
lines changed

README.md

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -685,12 +685,12 @@ import { RCMap, DivIcon, Point } from 'rc-leaflet'
685685
686686
(
687687
<RCMap>
688-
<DivIcon>
688+
<DivIcon content={<div>must be single jsx element content.</div>}>
689689
<Point />
690690
</DivIcon>
691691
692692
<Point>
693-
<DivIcon />
693+
<DivIcon content={<div>must be single jsx element content.</div>} />
694694
</Point>
695695
</RCMap>
696696
)
@@ -708,15 +708,15 @@ import { RCMap, DivIcon, Point } from 'rc-leaflet'
708708
709709
- the className of DivIcon container.
710710
711-
- html
711+
- content
712712
713-
- type: `string | HTMLElement`
713+
- type: `React.ReactElement`
714714
715-
- default: `''`
715+
- default: `null`
716716
717717
- required: `false`
718718
719-
- custom HTML code to put inside the div element, empty by default. Alternatively, an instance of HTMLElement.
719+
- custom `JSX` code to put inside the div element, empty by default. Alternatively, an instance of `React.ReactElement`.
720720
721721
- bgPos
722722
@@ -788,16 +788,6 @@ import { RCMap, Popup, Point, CircleMarker, Circle, Polyline } from 'rc-leaflet'
788788
789789
- position is needed only when popup is set directly under the map component.
790790
791-
- content
792-
793-
- type: `string | HTMLElement | Function`
794-
795-
- default: `undefined`
796-
797-
- required: `false`
798-
799-
- sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a String or HTMLElement to be used in the popup.
800-
801791
- maxWidth
802792
803793
- type: `number`
@@ -1010,16 +1000,6 @@ import { RCMap, Tooltip, Point, CircleMarker, Circle, Polyline } from 'rc-leafle
10101000

10111001
- position is needed only when Tooltip is set directly under the map component.
10121002

1013-
- content
1014-
1015-
- type: `string | HTMLElement | Function`
1016-
1017-
- default: `undefined`
1018-
1019-
- required: `false`
1020-
1021-
- sets the HTML content of the tooltip. If a function is passed the source layer will be passed to the function. The function should return a String or HTMLElement to be used in the tooltip.
1022-
10231003
- pane
10241004

10251005
- type: `string`

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rc-leaflet",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "React components of Leaflet",
55
"keywords": [
66
"leaflet",

src/components/BaseIcon/index.tsx

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,33 @@ export default abstract class BaseIcon<T extends L.Icon | L.DivIcon, P extends L
3838

3939
protected constructor (props: Props & P) {
4040
super(props)
41-
4241
const { layer, children, ...options } = props
4342

4443
this.state = {
4544
instance: this.createInstance(options as P)
4645
}
47-
if (layer) {
48-
layer.setIcon(this.state.instance)
49-
}
5046
}
5147

52-
public componentDidUpdate (prevProps: Props & P, prevState: { instance: T }): void {
53-
const { layer: prevLayer } = prevProps
54-
const { layer, children, ...options } = this.props
55-
const { instance: prevIcon } = prevState
56-
const { instance: icon } = this.state
48+
public static getDerivedStateFromProps (nextProps, prevState): null {
49+
const { layer, children, ...options } = nextProps
50+
const { instance: icon } = prevState
5751

58-
if (icon === prevIcon) {
59-
const instance = this.createInstance(options as P)
60-
61-
if (layer !== prevLayer && prevLayer) {
62-
prevLayer.setIcon(defaultIcon)
63-
}
64-
if (layer) {
65-
layer.setIcon(instance)
66-
}
67-
this.setState({ instance })
52+
for (const [key, value] of Object.entries(options)) {
53+
icon.options[key] = value
54+
}
55+
if (layer) {
56+
layer.setIcon(icon)
6857
}
58+
return null
6959
}
7060

7161
public componentWillUnmount (): void {
7262
const { layer } = this.props
7363

7464
if (layer) {
75-
layer.setIcon(defaultIcon)
65+
setTimeout(() => {
66+
layer.setIcon(defaultIcon)
67+
}, 0)
7668
}
7769
}
7870

src/components/DivIcon/index.tsx

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1+
import React, { createContext } from 'react'
2+
import { createPortal } from 'react-dom'
13
import PropTypes from 'prop-types'
24
import L from 'leaflet'
35
import { Types } from '../../config'
46
import creator, { defaultOptions } from './creator'
57
import BaseIcon, { Props as BaseIconProps } from '../BaseIcon'
68

7-
type Props = Readonly<BaseIconProps & L.DivIconOptions>
9+
interface PartialProps {
10+
content: React.ReactElement
11+
}
12+
13+
type Props = Readonly<Partial<PartialProps> & BaseIconProps & L.DivIconOptions>
14+
15+
const Context = createContext<React.ReactElement>(null)
16+
17+
export const Consumer = Context.Consumer
818

919
export default class DivIcon extends BaseIcon<L.DivIcon, Props> {
1020
protected static propTypes = {
@@ -14,15 +24,40 @@ export default class DivIcon extends BaseIcon<L.DivIcon, Props> {
1424
iconSize: Types.Pixel,
1525
iconAnchor: Types.Pixel,
1626
popupAnchor: Types.Pixel,
17-
className: PropTypes.string
27+
className: PropTypes.string,
28+
content: PropTypes.element
1829
}
1930

20-
protected static defaultProps = {
31+
protected static defaultProps: typeof BaseIcon.defaultProps & typeof defaultOptions & PartialProps = {
2132
...BaseIcon.defaultProps,
22-
...defaultOptions
33+
...defaultOptions,
34+
content: null
35+
}
36+
37+
public static getDerivedStateFromProps (nextProps, prevState): null {
38+
const { layer, children, html, ...options } = nextProps
39+
const { instance: icon } = prevState
40+
41+
if (layer) {
42+
icon.options.html = layer.getElement() ? layer.getElement().firstElementChild : null
43+
}
44+
return BaseIcon.getDerivedStateFromProps({ layer, ...options }, prevState)
2345
}
2446

25-
protected createInstance (options: L.DivIconOptions): L.DivIcon {
47+
protected createInstance ({ html, ...options }: L.DivIconOptions): L.DivIcon {
2648
return creator(options)
2749
}
50+
51+
public render (): React.ReactNode {
52+
const { layer, content } = this.props
53+
54+
return (
55+
<>
56+
<Context.Provider value={content}>
57+
{ super.render() }
58+
</Context.Provider>
59+
{ layer && layer.getElement() ? createPortal(content, layer.getElement()) : null }
60+
</>
61+
)
62+
}
2863
}

src/components/Layer/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export default abstract class Layer<T extends L.Layer, P extends L.LayerOptions>
2929

3030
protected constructor (props: Props & P, context: ContextType) {
3131
super(props)
32-
3332
const { children, ...restProps } = props
3433

3534
this.instance = this.createInstance({ ...this.getOptions(), ...restProps } as P)

src/components/Point/index.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import React from 'react'
2+
import { createPortal } from 'react-dom'
13
import PropTypes from 'prop-types'
24
import L from 'leaflet'
35
import { Types } from '../../config'
46
import InteractiveLayer from '../InteractiveLayer'
7+
import { Consumer as DivIconConsumer } from '../DivIcon'
58
import { defaultIcon } from '../DivIcon/creator'
69

710
interface RequiredProps {
@@ -50,4 +53,17 @@ export default class Point extends InteractiveLayer<L.Marker, Props> {
5053
}
5154
super.bindEvents(prevProps)
5255
}
56+
57+
public render (): React.ReactNode {
58+
const { icon } = this.props
59+
60+
return (
61+
<>
62+
{ super.render() }
63+
<DivIconConsumer>
64+
{ content => (icon instanceof L.DivIcon ? createPortal(content, this.instance.getElement()) : null) }
65+
</DivIconConsumer>
66+
</>
67+
)
68+
}
5369
}

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"allowSyntheticDefaultImports": true,
77
"jsx": "react",
88
"esModuleInterop": true,
9-
"lib": ["ES2017", "DOM"],
9+
"lib": ["es2017", "dom"],
1010
"declaration": true,
1111
"moduleResolution": "Node"
1212
}

0 commit comments

Comments
 (0)