Skip to content

Commit

Permalink
refactor(Circle): rewrite with enhanceElement and cleaner interfaces
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Naming convention for event handlers has tweaked to follow React's convention.

Before:

```js
<Circle
  onClick={_.noop}
  onRightclick={_.noop}
  onDragstart={_.noop}
/>
```

After:

```js
<Circle
  onClick={_.noop}
  onRightClick={_.noop}
  onDragStart={_.noop}
/>
```
  • Loading branch information
tomchentw committed Oct 4, 2016
1 parent 1e20d70 commit da0ebc2
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 151 deletions.
178 changes: 119 additions & 59 deletions src/lib/Circle.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,145 @@
/* global google */
import _ from "lodash";

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

import {
default as canUseDOM,
} from "can-use-dom";
MAP,
CIRCLE,
} from "./constants";

import {
default as CircleCreator,
circleDefaultPropTypes,
circleControlledPropTypes,
circleEventPropTypes,
} from "./creators/CircleCreator";

import { default as GoogleMapHolder } from "./creators/GoogleMapHolder";

export default class Circle extends Component {
static propTypes = {
// Uncontrolled default[props] - used only in componentDidMount
...circleDefaultPropTypes,
// Controlled [props] - used in componentDidMount/componentDidUpdate
...circleControlledPropTypes,
// Event [onEventName]
...circleEventPropTypes,
}

static contextTypes = {
mapHolderRef: PropTypes.instanceOf(GoogleMapHolder),
}
addDefaultPrefixToPropTypes,
collectUncontrolledAndControlledProps,
default as enhanceElement,
} from "./enhanceElement";

// Public APIs
const controlledPropTypes = {
// NOTICE!!!!!!
//
// https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
// Only expose those with getters & setters in the table as controlled props.
//
// [].map.call($0.querySelectorAll("tr>td>code", function(it){ return it.textContent; })
// .filter(function(it){ return it.match(/^set/) && !it.match(/^setMap/); })
//
// https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
center: PropTypes.any,
draggable: PropTypes.bool,
editable: PropTypes.bool,
options: PropTypes.object,
radius: PropTypes.number,
visible: PropTypes.bool,
};

const defaultUncontrolledPropTypes = addDefaultPrefixToPropTypes(controlledPropTypes);

const eventMap = {
// https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
// [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; })
// .filter(function(it){ return it.match(/^get/) && !it.match(/^getMap/); })
getBounds() { return this.state.circle.getBounds(); }
onCenterChanged: `center_changed`,

getCenter() { return this.state.circle.getCenter(); }
onClick: `click`,

getDraggable() { return this.state.circle.getDraggable(); }
onDblClick: `dblclick`,

getEditable() { return this.state.circle.getEditable(); }
onDrag: `drag`,

getMap() { return this.state.circle.getMap(); }
onDragEnd: `dragend`,

getRadius() { return this.state.circle.getRadius(); }
onDragStart: `dragstart`,

getVisible() { return this.state.circle.getVisible(); }
// END - Public APIs
onMouseDown: `mousedown`,

onMouseMove: `mousemove`,

onMouseOut: `mouseout`,

onMouseOver: `mouseover`,

onMouseUp: `mouseup`,

onRadiusChanged: `radius_changed`,

onRightClick: `rightclick`,
};

const publicMethodMap = {
// Public APIs
//
// https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
//
// [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; })
// .filter(function(it){ return it.match(/^get/) && !it.match(/Map$/); })
getBounds(circle) { return circle.getBounds(); },

state = {
}
getCenter(circle) { return circle.getCenter(); },

componentWillMount() {
const { mapHolderRef } = this.context;
getDraggable(circle) { return circle.getDraggable(); },

if (!canUseDOM) {
return;
}
const circle = CircleCreator._createCircle({
...this.props,
mapHolderRef,
});
getEditable(circle) { return circle.getEditable(); },

this.setState({ circle });
}
getMap(circle) { return circle.getMap(); },

render() {
if (this.state.circle) {
return (
<CircleCreator circle={this.state.circle} {...this.props}>
{this.props.children}
</CircleCreator>
);
} else {
return (<noscript />);
}
}
getRadius(circle) { return circle.getRadius(); },

getVisible(circle) { return circle.getVisible(); },
// END - Public APIs
};

const controlledPropUpdaterMap = {
center(circle, center) { circle.setCenter(center); },
draggable(circle, draggable) { circle.setDraggable(draggable); },
editable(circle, editable) { circle.setEditable(editable); },
options(circle, options) { circle.setOptions(options); },
radius(circle, radius) { circle.setRadius(radius); },
visible(circle, visible) { circle.setVisible(visible); },
};

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

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

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

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

getInitialState() {
// https://developers.google.com/maps/documentation/javascript/3.exp/reference#Circle
const circle = new google.maps.Circle({
map: this.context[MAP],
...collectUncontrolledAndControlledProps(
defaultUncontrolledPropTypes,
controlledPropTypes,
this.props
),
});
return {
[CIRCLE]: circle,
};
},

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

render() {
return false;
},
});
2 changes: 2 additions & 0 deletions src/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export const RECTANGLE = `__SECRET_RECTANGLE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;
export const POLYLINE = `__SECRET_POLYLINE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;

export const POLYGON = `__SECRET_POLYGON_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;

export const CIRCLE = `__SECRET_CIRCLE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`;
75 changes: 0 additions & 75 deletions src/lib/creators/CircleCreator.js

This file was deleted.

17 changes: 0 additions & 17 deletions src/lib/eventLists/CircleEventList.js

This file was deleted.

4 changes: 4 additions & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export {
export {
default as Polygon,
} from "./Polygon";

export {
default as Circle,
} from "./Circle";

0 comments on commit da0ebc2

Please sign in to comment.