diff --git a/src/lib/GoogleMapLoader.js b/src/lib/GoogleMapLoader.js deleted file mode 100644 index 1c19e3ab..00000000 --- a/src/lib/GoogleMapLoader.js +++ /dev/null @@ -1,73 +0,0 @@ -import _ from "lodash"; - -import { - default as React, - PropTypes, - Component, -} from "react"; - -import { - default as propTypesElementOfType, -} from "react-prop-types-element-of-type"; - -import { - default as GoogleMap, -} from "./GoogleMap"; - -import { - default as GoogleMapHolder, -} from "./creators/GoogleMapHolder"; - -export default class GoogleMapLoader extends Component { - static propTypes = { - containerElement: PropTypes.node.isRequired, - googleMapElement: propTypesElementOfType(GoogleMap).isRequired, - }; - - static defaultProps = { - containerElement: (
), - }; - - state = { - map: null, - }; - - mountGoogleMap = this.mountGoogleMap.bind(this); - - mountGoogleMap(domEl) { - if (this.state.map || domEl === null) { - return; - } - const restProps = _.omit(this.props.googleMapElement.props, [`children`]); - // - // Create google.maps.Map instance so that dom is initialized before - // React's children creators. - // - const map = GoogleMapHolder._createMap(domEl, restProps); - this.setState({ map }); - } - - renderChild() { - if (this.state.map) { - // Notice: implementation details - // - // In this state, the DOM of google.maps.Map is already initialized in - // my innerHTML. Adding extra React components will not clean it - // in current version*. It will use prepend to add DOM of - // GoogleMapHolder and become a sibling of the DOM of google.maps.Map - // Not sure this is subject to change - // - // *current version: 0.13.3, 0.14.2 - // - return React.cloneElement(this.props.googleMapElement, { - map: this.state.map, - }); - } - } - - render() { - return React.cloneElement(this.props.containerElement, { - ref: this.mountGoogleMap, - }, this.renderChild()); - } -} diff --git a/src/lib/constants.js b/src/lib/constants.js new file mode 100644 index 00000000..4f133b08 --- /dev/null +++ b/src/lib/constants.js @@ -0,0 +1 @@ +export const MAP = `__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`; diff --git a/src/lib/index.js b/src/lib/index.js index 392dfd7e..43264e61 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1,15 +1,3 @@ -export { default as GoogleMapLoader } from "./GoogleMapLoader"; - -export { default as GoogleMap } from "./GoogleMap"; -export { default as Circle } from "./Circle"; -export { default as DirectionsRenderer } from "./DirectionsRenderer"; -export { default as DrawingManager } from "./DrawingManager"; -export { default as InfoWindow } from "./InfoWindow"; -export { default as KmlLayer } from "./KmlLayer"; -export { default as Marker } from "./Marker"; -export { default as OverlayView } from "./OverlayView"; -export { default as Polygon } from "./Polygon"; -export { default as Polyline } from "./Polyline"; -export { default as Rectangle } from "./Rectangle"; -export { default as SearchBox } from "./SearchBox"; -export { default as HeatmapLayer } from "./HeatmapLayer"; +export { + default as withGoogleMap, +} from "./withGoogleMap"; diff --git a/src/lib/withGoogleMap.js b/src/lib/withGoogleMap.js new file mode 100644 index 00000000..0564e712 --- /dev/null +++ b/src/lib/withGoogleMap.js @@ -0,0 +1,106 @@ +/* global google */ +import warning from "warning"; + +import invariant from "invariant"; + +import getDisplayName from "react-display-name"; + +import { + default as React, + PropTypes, + Component, +} from "react"; + +import { + MAP, +} from "./constants"; + +export default function withGoogleMap(WrappedComponent) { + return class Container extends Component { + static displayName = `withGoogleMap(${getDisplayName(WrappedComponent)})`; + + static propTypes = { + containerElement: PropTypes.node.isRequired, + mapElement: PropTypes.node.isRequired, + }; + + static childContextTypes = { + [MAP]: PropTypes.object, + }; + + state = { + map: null, + }; + + handleComponentMount = this.handleComponentMount.bind(this); + + getChildContext() { + return { + [MAP]: this.state.map, + }; + } + + componentWillMount() { + const { + containerElement, + mapElement, + } = this.props; + invariant(!!containerElement && !!mapElement, +`Required props containerElement or mapElement is missing. You need to provide both of them. + The \`google.maps.Map\` instance will be initialized on mapElement and it's wrapped by\ + containerElement.\nYou need to provide both of them since Google Map requires the DOM to\ + have height when initialized.` + ); + } + + handleComponentMount(node) { + if (this.state.map || node === null) { + return; + } + warning(`undefined` !== typeof google, +`Make sure you've put a