Skip to content

Commit

Permalink
refactor(addons/InfoBox): rewrite with enhanceElement and cleaner int…
Browse files Browse the repository at this point in the history
…erfaces

BREAKING CHANGE: Naming convention for event handlers has tweaked to follow React's convention.

Before:

```js
<InfoBox
  onCloseclick={_.noop}
  onDomready={_.noop}
  onZindexChanged={_.noop}
/>
```

After:

```js
<InfoBox
  onCloseClick={_.noop}
  onDomReady={_.noop}
  onZIndexChanged={_.noop}
/>
```
  • Loading branch information
tomchentw committed Oct 4, 2016
1 parent f1032f4 commit 06f2e9b
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 141 deletions.
190 changes: 144 additions & 46 deletions src/lib/addons/InfoBox.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,166 @@
import _ from "lodash";

import invariant from "invariant";

import {
default as React,
Component,
PropTypes,
Children,
} from "react";

import {
default as canUseDOM,
} from "can-use-dom";
render,
} from "react-dom";

import {
default as InfoBoxCreator,
infoBoxDefaultPropTypes,
infoBoxControlledPropTypes,
infoBoxEventPropTypes,
} from "./addonsCreators/InfoBoxCreator";

/*
* Original author: @wuct
* Original PR: https://github.com/tomchentw/react-google-maps/pull/54
*/
export default class InfoBox extends Component {
static propTypes = {
// Uncontrolled default[props] - used only in componentDidMount
...infoBoxDefaultPropTypes,
// Controlled [props] - used in componentDidMount/componentDidUpdate
...infoBoxControlledPropTypes,
// Event [onEventName]
...infoBoxEventPropTypes,
}
MAP,
ANCHOR,
INFO_BOX,
} from "../constants";

// Public APIs
import {
addDefaultPrefixToPropTypes,
collectUncontrolledAndControlledProps,
default as enhanceElement,
} from "../enhanceElement";

const controlledPropTypes = {
// NOTICE!!!!!!
//
// Only expose those with getters & setters in the table as controlled props.
//
// http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/reference.html
content: PropTypes.any,
options: PropTypes.object,
position: PropTypes.any,
visible: PropTypes.bool,
zIndex: PropTypes.number,
};

const defaultUncontrolledPropTypes = addDefaultPrefixToPropTypes(controlledPropTypes);

const eventMap = {
// http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/reference.html
getContent() { /* TODO: children */ }
onCloseClick: `closeclick`,

getPosition() { return this.state.infoBox.getPosition(); }
onContentChanged: `content_changed`,

getVisible() { return this.state.infoBox.getVisible(); }
onDomReady: `domready`,

getZIndex() { return this.state.infoBox.getZIndex(); }
// END - Public APIs
onPositionChanged: `position_changed`,

onZIndexChanged: `zindex_changed`,
};

const publicMethodMap = {
// Public APIs
//
// http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/reference.html
getPosition(infoBox) { return infoBox.getPosition(); },

getVisible(infoBox) { return infoBox.getVisible(); },

getZIndex(infoBox) { return infoBox.getZIndex(); },
// END - Public APIs
};

const controlledPropUpdaterMap = {
children(infoWindow, children) {
render(Children.only(children), infoWindow.getContent());
},
options(infoBox, options) { infoBox.setOptions(options); },
position(infoBox, position) { infoBox.setPosition(position); },
visible(infoBox, visible) { infoBox.setVisible(visible); },
zIndex(infoBox, zIndex) { infoBox.setZIndex(zIndex); },
};

function getInstanceFromComponent(component) {
return component.state[INFO_BOX];
}

state = {
function openInfoBox(context, infoBox) {
const map = context[MAP];
const anchor = context[ANCHOR];
if (anchor) {
infoBox.open(map, anchor);
} else if (infoBox.getPosition()) {
infoBox.open(map);
} else {
invariant(false,
`You must provide either an anchor (typically a <Marker>) or a position for <InfoBox>.`
);
}
}

export default _.flowRight(
React.createClass,
enhanceElement(getInstanceFromComponent, publicMethodMap, eventMap, controlledPropUpdaterMap),
)({
displayName: `InfoBox`,

propTypes: {
...controlledPropTypes,
...defaultUncontrolledPropTypes,
},

contextTypes: {
[MAP]: PropTypes.object,
[ANCHOR]: PropTypes.object,
},

componentWillMount() {
if (!canUseDOM) {
return;
getInitialState() {
const GoogleMapsInfobox = require(
// "google-maps-infobox" uses "google" as a global variable. Since we don't
// have "google" on the server, we can not use it in server-side rendering.
// As a result, we import "google-maps-infobox" here to prevent an error on
// a isomorphic server.
`google-maps-infobox`
);
const map = this.context[MAP];
const infoBoxProps = collectUncontrolledAndControlledProps(
defaultUncontrolledPropTypes,
controlledPropTypes,
this.props
);
// http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/reference.html
const infoBox = new GoogleMapsInfobox({
map,
...infoBoxProps,
// Override props of ReactElement type
content: document.createElement(`div`),
children: undefined,
});
// BUG: the `GoogleMapsInfobox` does not take infoBoxProps.options
// into account in its constructor. Need to manually set
infoBox.setOptions(infoBoxProps.options || {});

openInfoBox(this.context, infoBox);
return {
[INFO_BOX]: infoBox,
};
},

componentDidMount() {
const infoBox = getInstanceFromComponent(this);
controlledPropUpdaterMap.children(infoBox, this.props.children);
},

componentWillReceiveProps(nextProps, nextContext) {
const anchorChanged = this.context[ANCHOR] !== nextContext[ANCHOR];
if (anchorChanged) {
const infoBox = getInstanceFromComponent(this);
openInfoBox(nextContext, infoBox);
}
const infoBox = InfoBoxCreator._createInfoBox(this.props);
},

this.setState({ infoBox });
}
componentWillUnmount() {
const infoBox = getInstanceFromComponent(this);
if (infoBox) {
infoBox.setMap(null);
}
},

render() {
if (this.state.infoBox) {
return (
<InfoBoxCreator infoBox={this.state.infoBox} {...this.props}>
{this.props.children}
</InfoBoxCreator>
);
} else {
return (<noscript />);
}
}
}
return false;
},
});
87 changes: 0 additions & 87 deletions src/lib/addons/addonsCreators/InfoBoxCreator.js

This file was deleted.

8 changes: 0 additions & 8 deletions src/lib/addons/addonsEventLists/InfoBoxEventList.js

This file was deleted.

2 changes: 2 additions & 0 deletions src/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ export const DRAWING_MANAGER = `__SECRET_DRAWING_MANAGER_DO_NOT_USE_OR_YOU_WILL_
export const SEARCH_BOX = `__SECRET_SEARCH_BOX_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;

export const MARKER_CLUSTERER = `__SECRET_MARKER_CLUSTERER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;

export const INFO_BOX = `__SECRET_INFO_BOX_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;

0 comments on commit 06f2e9b

Please sign in to comment.