diff --git a/docs/src/PropTable.js b/docs/src/PropTable.js
index 250a70a8f6..3c35233e72 100644
--- a/docs/src/PropTable.js
+++ b/docs/src/PropTable.js
@@ -7,21 +7,22 @@ import Table from '../../src/Table';
let cleanDocletValue = str => str.trim().replace(/^\{/, '').replace(/\}$/, '');
-function getPropsData(componentData, metadata){
-
+function getPropsData(component, metadata){
+ let componentData = metadata[component] || {};
let props = componentData.props || {};
if (componentData.composes) {
- componentData.composes.forEach( other => {
- props = merge({}, getPropsData(metadata[other] || {}, metadata), props);
-
+ componentData.composes.forEach(other => {
+ if (other !== component) {
+ props = merge({}, getPropsData(other, metadata), props);
+ }
});
}
if (componentData.mixins) {
componentData.mixins.forEach( other => {
- if ( componentData.composes.indexOf(other) === -1) {
- props = merge({}, getPropsData(metadata[other] || {}, metadata), props);
+ if (other !== component && componentData.composes.indexOf(other) === -1) {
+ props = merge({}, getPropsData(other, metadata), props);
}
});
}
@@ -36,9 +37,7 @@ const PropTable = React.createClass({
},
componentWillMount(){
- let componentData = this.context.metadata[this.props.component] || {};
-
- this.propsData = getPropsData(componentData, this.context.metadata);
+ this.propsData = getPropsData(this.props.component, this.context.metadata);
},
render(){
diff --git a/package.json b/package.json
index 84e2a3b43d..b0b0181636 100644
--- a/package.json
+++ b/package.json
@@ -108,7 +108,8 @@
},
"dependencies": {
"babel-runtime": "^5.8.19",
+ "classnames": "^2.1.3",
"lodash": "^3.10.0",
- "classnames": "^2.1.3"
+ "react-overlays": "^0.4.2"
}
}
diff --git a/src/Collapse.js b/src/Collapse.js
index ab8e4b652f..e38e3fcb0c 100644
--- a/src/Collapse.js
+++ b/src/Collapse.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Transition from './Transition';
+import Transition from 'react-overlays/lib/Transition';
import domUtils from './utils/domUtils';
import createChainedFunction from './utils/createChainedFunction';
@@ -138,7 +138,7 @@ Collapse.propTypes = {
* finishing callbacks are fired even if the original browser transition end
* events are canceled
*/
- duration: React.PropTypes.number,
+ timeout: React.PropTypes.number,
/**
* Callback fired before the component expands
@@ -194,7 +194,7 @@ Collapse.propTypes = {
Collapse.defaultProps = {
in: false,
- duration: 300,
+ timeout: 300,
unmountOnExit: false,
transitionAppear: false,
diff --git a/src/Fade.js b/src/Fade.js
index ce5a9a3370..a707ea386b 100644
--- a/src/Fade.js
+++ b/src/Fade.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Transition from './Transition';
+import Transition from 'react-overlays/lib/Transition';
class Fade extends React.Component {
render() {
@@ -41,7 +41,7 @@ Fade.propTypes = {
* callbacks are fired even if the original browser transition end events are
* canceled
*/
- duration: React.PropTypes.number,
+ timeout: React.PropTypes.number,
/**
* Callback fired before the component fades in
@@ -71,7 +71,7 @@ Fade.propTypes = {
Fade.defaultProps = {
in: false,
- duration: 300,
+ timeout: 300,
unmountOnExit: false,
transitionAppear: false
};
diff --git a/src/Modal.js b/src/Modal.js
index 48de68689f..7bc2677c4a 100644
--- a/src/Modal.js
+++ b/src/Modal.js
@@ -6,7 +6,7 @@ import EventListener from './utils/EventListener';
import createChainedFunction from './utils/createChainedFunction';
import CustomPropTypes from './utils/CustomPropTypes';
-import Portal from './Portal';
+import Portal from 'react-overlays/lib/Portal';
import Fade from './Fade';
import ModalDialog from './ModalDialog';
import Body from './ModalBody';
diff --git a/src/Overlay.js b/src/Overlay.js
index 379aea35f9..c8b3c0f6bf 100644
--- a/src/Overlay.js
+++ b/src/Overlay.js
@@ -2,115 +2,43 @@
/* These properties are validated in 'Portal' and 'Position' components */
import React, { cloneElement } from 'react';
-import Portal from './Portal';
-import Position from './Position';
-import RootCloseWrapper from './RootCloseWrapper';
+import BaseOverlay from 'react-overlays/lib/Overlay';
import CustomPropTypes from './utils/CustomPropTypes';
import Fade from './Fade';
import classNames from 'classnames';
class Overlay extends React.Component {
- constructor(props, context) {
- super(props, context);
-
- this.state = {exited: !props.show};
- this.onHiddenListener = this.handleHidden.bind(this);
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.show) {
- this.setState({exited: false});
- } else if (!nextProps.animation) {
- // Otherwise let handleHidden take care of marking exited.
- this.setState({exited: true});
- }
- }
render() {
let {
- container
- , containerPadding
- , target
- , placement
- , rootClose
- , children
- , animation: Transition
+ children: child
+ , animation: transition
, ...props } = this.props;
- if (Transition === true) {
- Transition = Fade;
+ if (transition === true) {
+ transition = Fade;
}
- // Don't un-render the overlay while it's transitioning out.
- const mountOverlay = props.show || (Transition && !this.state.exited);
- if (!mountOverlay) {
- // Don't bother showing anything if we don't have to.
- return null;
- }
-
- let child = children;
-
- // Position is be inner-most because it adds inline styles into the child,
- // which the other wrappers don't forward correctly.
- child = (
-
- {child}
-
- );
-
- if (Transition) {
- let { onExit, onExiting, onEnter, onEntering, onEntered } = props;
-
- // This animates the child node by injecting props, so it must precede
- // anything that adds a wrapping div.
- child = (
-
- {child}
-
- );
- } else {
+ if (!transition) {
child = cloneElement(child, {
className: classNames('in', child.props.className)
});
}
- // This goes after everything else because it adds a wrapping div.
- if (rootClose) {
- child = (
-
- {child}
-
- );
- }
-
return (
-
+
{child}
-
+
);
}
-
- handleHidden(...args) {
- this.setState({exited: true});
-
- if (this.props.onExited) {
- this.props.onExited(...args);
- }
- }
}
Overlay.propTypes = {
- ...Portal.propTypes,
- ...Position.propTypes,
+ ...BaseOverlay.propTypes,
+
/**
* Set the visibility of the Overlay
*/
diff --git a/src/Portal.js b/src/Portal.js
index 7e87fcf08f..9741a0f1d5 100644
--- a/src/Portal.js
+++ b/src/Portal.js
@@ -1,93 +1,3 @@
-import React from 'react';
-import CustomPropTypes from './utils/CustomPropTypes';
-import domUtils from './utils/domUtils';
-
-let Portal = React.createClass({
-
- displayName: 'Portal',
-
- propTypes: {
- /**
- * The DOM Node that the Component will render it's children into
- */
- container: CustomPropTypes.mountable
- },
-
- componentDidMount() {
- this._renderOverlay();
- },
-
- componentDidUpdate() {
- this._renderOverlay();
- },
-
- componentWillUnmount() {
- this._unrenderOverlay();
- this._unmountOverlayTarget();
- },
-
- _mountOverlayTarget() {
- if (!this._overlayTarget) {
- this._overlayTarget = document.createElement('div');
- this.getContainerDOMNode()
- .appendChild(this._overlayTarget);
- }
- },
-
- _unmountOverlayTarget() {
- if (this._overlayTarget) {
- this.getContainerDOMNode()
- .removeChild(this._overlayTarget);
- this._overlayTarget = null;
- }
- },
-
- _renderOverlay() {
- let overlay = !this.props.children
- ? null
- : React.Children.only(this.props.children);
-
- // Save reference for future access.
- if (overlay !== null) {
- this._mountOverlayTarget();
- this._overlayInstance = React.render(overlay, this._overlayTarget);
- } else {
- // Unrender if the component is null for transitions to null
- this._unrenderOverlay();
- this._unmountOverlayTarget();
- }
- },
-
- _unrenderOverlay() {
- if (this._overlayTarget) {
- React.unmountComponentAtNode(this._overlayTarget);
- this._overlayInstance = null;
- }
- },
-
- render() {
- return null;
- },
-
- getOverlayDOMNode() {
- if (!this.isMounted()) {
- throw new Error('getOverlayDOMNode(): A component must be mounted to have a DOM node.');
- }
-
- if (this._overlayInstance) {
- if (this._overlayInstance.getWrappedDOMNode) {
- return this._overlayInstance.getWrappedDOMNode();
- } else {
- return React.findDOMNode(this._overlayInstance);
- }
- }
-
- return null;
- },
-
- getContainerDOMNode() {
- return React.findDOMNode(this.props.container) || domUtils.ownerDocument(this).body;
- }
-});
+import Portal from 'react-overlays/lib/Portal';
export default Portal;
diff --git a/src/Position.js b/src/Position.js
index 523c7973f7..4c20168ae9 100644
--- a/src/Position.js
+++ b/src/Position.js
@@ -1,136 +1,3 @@
-import React, { cloneElement } from 'react';
-import classNames from 'classnames';
-import domUtils from './utils/domUtils';
-import { calcOverlayPosition } from './utils/overlayPositionUtils';
-import CustomPropTypes from './utils/CustomPropTypes';
-
-class Position extends React.Component {
- constructor(props, context) {
- super(props, context);
-
- this.state = {
- positionLeft: null,
- positionTop: null,
- arrowOffsetLeft: null,
- arrowOffsetTop: null
- };
-
- this._needsFlush = false;
- this._lastTarget = null;
- }
-
- componentDidMount() {
- this.updatePosition();
- }
-
- componentWillReceiveProps() {
- this._needsFlush = true;
- }
-
- componentDidUpdate() {
- if (this._needsFlush) {
- this._needsFlush = false;
- this.updatePosition();
- }
- }
-
- componentWillUnmount() {
- // Probably not necessary, but just in case holding a reference to the
- // target causes problems somewhere.
- this._lastTarget = null;
- }
-
- render() {
- const {children, className, ...props} = this.props;
- const {positionLeft, positionTop, ...arrowPosition} = this.state;
-
- const child = React.Children.only(children);
- return cloneElement(
- child,
- {
- ...props,
- ...arrowPosition,
- positionTop,
- positionLeft,
- className: classNames(className, child.props.className),
- style: {
- ...child.props.style,
- left: positionLeft,
- top: positionTop
- }
- }
- );
- }
-
- getTargetSafe() {
- if (!this.props.target) {
- return null;
- }
-
- const target = this.props.target(this.props);
- if (!target) {
- // This is so we can just use === check below on all falsy targets.
- return null;
- }
-
- return target;
- }
-
- updatePosition() {
- const target = this.getTargetSafe();
- if (target === this._lastTarget) {
- return;
- }
- this._lastTarget = target;
-
- if (!target) {
- this.setState({
- positionLeft: null,
- positionTop: null,
- arrowOffsetLeft: null,
- arrowOffsetTop: null
- });
-
- return;
- }
-
- const overlay = React.findDOMNode(this);
- const container =
- React.findDOMNode(this.props.container) ||
- domUtils.ownerDocument(this).body;
-
- this.setState(calcOverlayPosition(
- this.props.placement,
- overlay,
- target,
- container,
- this.props.containerPadding
- ));
- }
-}
-
-Position.propTypes = {
- /**
- * Function mapping props to DOM node the component is positioned next to
- */
- target: React.PropTypes.func,
- /**
- * "offsetParent" of the component
- */
- container: CustomPropTypes.mountable,
- /**
- * Minimum spacing in pixels between container border and component border
- */
- containerPadding: React.PropTypes.number,
- /**
- * How to position the component relative to the target
- */
- placement: React.PropTypes.oneOf(['top', 'right', 'bottom', 'left'])
-};
-
-Position.defaultProps = {
- containerPadding: 0,
- placement: 'right'
-};
+import Position from 'react-overlays/lib/Position';
export default Position;
diff --git a/src/RootCloseWrapper.js b/src/RootCloseWrapper.js
deleted file mode 100644
index 35fecab769..0000000000
--- a/src/RootCloseWrapper.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react';
-import domUtils from './utils/domUtils';
-import EventListener from './utils/EventListener';
-
-// TODO: Merge this logic with dropdown logic once #526 is done.
-
-// TODO: Consider using an ES6 symbol here, once we use babel-runtime.
-const CLICK_WAS_INSIDE = '__click_was_inside';
-
-function suppressRootClose(event) {
- // Tag the native event to prevent the root close logic on document click.
- // This seems safer than using event.nativeEvent.stopImmediatePropagation(),
- // which is only supported in IE >= 9.
- event.nativeEvent[CLICK_WAS_INSIDE] = true;
-}
-
-export default class RootCloseWrapper extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleDocumentClick = this.handleDocumentClick.bind(this);
- this.handleDocumentKeyUp = this.handleDocumentKeyUp.bind(this);
- }
-
- bindRootCloseHandlers() {
- const doc = domUtils.ownerDocument(this);
-
- this._onDocumentClickListener =
- EventListener.listen(doc, 'click', this.handleDocumentClick);
- this._onDocumentKeyupListener =
- EventListener.listen(doc, 'keyup', this.handleDocumentKeyUp);
- }
-
- handleDocumentClick(e) {
- // This is now the native event.
- if (e[CLICK_WAS_INSIDE]) {
- return;
- }
-
- this.props.onRootClose();
- }
-
- handleDocumentKeyUp(e) {
- if (e.keyCode === 27) {
- this.props.onRootClose();
- }
- }
-
- unbindRootCloseHandlers() {
- if (this._onDocumentClickListener) {
- this._onDocumentClickListener.remove();
- }
-
- if (this._onDocumentKeyupListener) {
- this._onDocumentKeyupListener.remove();
- }
- }
-
- componentDidMount() {
- this.bindRootCloseHandlers();
- }
-
- render() {
- // Wrap the child in a new element, so the child won't have to handle
- // potentially combining multiple onClick listeners.
- return (
-
- {React.Children.only(this.props.children)}
-
- );
- }
-
- getWrappedDOMNode() {
- // We can't use a ref to identify the wrapped child, since we might be
- // stealing the ref from the owner, but we know exactly the DOM structure
- // that will be rendered, so we can just do this to get the child's DOM
- // node for doing size calculations in OverlayMixin.
- return React.findDOMNode(this).children[0];
- }
-
- componentWillUnmount() {
- this.unbindRootCloseHandlers();
- }
-}
-RootCloseWrapper.propTypes = {
- onRootClose: React.PropTypes.func.isRequired
-};
diff --git a/src/Transition.js b/src/Transition.js
index 8235d41f9f..3ba7d50deb 100644
--- a/src/Transition.js
+++ b/src/Transition.js
@@ -1,273 +1,3 @@
-import React from 'react';
-import TransitionEvents from './utils/TransitionEvents';
-import classnames from 'classnames';
-
-export const UNMOUNTED = 0;
-export const EXITED = 1;
-export const ENTERING = 2;
-export const ENTERED = 3;
-export const EXITING = 4;
-
-class Transition extends React.Component {
- constructor(props, context) {
- super(props, context);
-
- let initialStatus;
- if (props.in) {
- // Start enter transition in componentDidMount.
- initialStatus = props.transitionAppear ? EXITED : ENTERED;
- } else {
- initialStatus = props.unmountOnExit ? UNMOUNTED : EXITED;
- }
- this.state = {status: initialStatus};
-
- this.nextCallback = null;
- }
-
- componentDidMount() {
- if (this.props.transitionAppear && this.props.in) {
- this.performEnter(this.props);
- }
- }
-
- componentWillReceiveProps(nextProps) {
- const status = this.state.status;
- if (nextProps.in) {
- if (status === EXITING) {
- this.performEnter(nextProps);
- } else if (this.props.unmountOnExit) {
- if (status === UNMOUNTED) {
- // Start enter transition in componentDidUpdate.
- this.setState({status: EXITED});
- }
- } else if (status === EXITED) {
- this.performEnter(nextProps);
- }
-
- // Otherwise we're already entering or entered.
- } else {
- if (status === ENTERING || status === ENTERED) {
- this.performExit(nextProps);
- }
-
- // Otherwise we're already exited or exiting.
- }
- }
-
- componentDidUpdate() {
- if (this.props.unmountOnExit && this.state.status === EXITED) {
- // EXITED is always a transitional state to either ENTERING or UNMOUNTED
- // when using unmountOnExit.
- if (this.props.in) {
- this.performEnter(this.props);
- } else {
- this.setState({status: UNMOUNTED});
- }
- }
- }
-
- componentWillUnmount() {
- this.cancelNextCallback();
- }
-
- performEnter(props) {
- this.cancelNextCallback();
- const node = React.findDOMNode(this);
-
- // Not this.props, because we might be about to receive new props.
- props.onEnter(node);
-
- this.safeSetState({status: ENTERING}, () => {
- this.props.onEntering(node);
-
- this.onTransitionEnd(node, () => {
- this.safeSetState({status: ENTERED}, () => {
- this.props.onEntered(node);
- });
- });
- });
- }
-
- performExit(props) {
- this.cancelNextCallback();
- const node = React.findDOMNode(this);
-
- // Not this.props, because we might be about to receive new props.
- props.onExit(node);
-
- this.safeSetState({status: EXITING}, () => {
- this.props.onExiting(node);
-
- this.onTransitionEnd(node, () => {
- this.safeSetState({status: EXITED}, () => {
- this.props.onExited(node);
- });
- });
- });
- }
-
- cancelNextCallback() {
- if (this.nextCallback !== null) {
- this.nextCallback.cancel();
- this.nextCallback = null;
- }
- }
-
- safeSetState(nextState, callback) {
- // This shouldn't be necessary, but there are weird race conditions with
- // setState callbacks and unmounting in testing, so always make sure that
- // we can cancel any pending setState callbacks after we unmount.
- this.setState(nextState, this.setNextCallback(callback));
- }
-
- setNextCallback(callback) {
- let active = true;
-
- this.nextCallback = (event) => {
- if (active) {
- active = false;
- this.nextCallback = null;
-
- callback(event);
- }
- };
-
- this.nextCallback.cancel = () => {
- active = false;
- };
-
- return this.nextCallback;
- }
-
- onTransitionEnd(node, handler) {
- this.setNextCallback(handler);
-
- if (node) {
- TransitionEvents.addEndEventListener(node, this.nextCallback);
- setTimeout(this.nextCallback, this.props.duration);
- } else {
- setTimeout(this.nextCallback, 0);
- }
- }
-
- render() {
- const status = this.state.status;
- if (status === UNMOUNTED) {
- return null;
- }
-
- const {children, className, ...childProps} = this.props;
- Object.keys(Transition.propTypes).forEach(key => delete childProps[key]);
-
- let transitionClassName;
- if (status === EXITED) {
- transitionClassName = this.props.exitedClassName;
- } else if (status === ENTERING) {
- transitionClassName = this.props.enteringClassName;
- } else if (status === ENTERED) {
- transitionClassName = this.props.enteredClassName;
- } else if (status === EXITING) {
- transitionClassName = this.props.exitingClassName;
- }
-
- const child = React.Children.only(children);
- return React.cloneElement(
- child,
- {
- ...childProps,
- className: classnames(
- child.props.className,
- className,
- transitionClassName
- )
- }
- );
- }
-}
-
-Transition.propTypes = {
- /**
- * Show the component; triggers the enter or exit animation
- */
- in: React.PropTypes.bool,
-
- /**
- * Unmount the component (remove it from the DOM) when it is not shown
- */
- unmountOnExit: React.PropTypes.bool,
-
- /**
- * Run the enter animation when the component mounts, if it is initially
- * shown
- */
- transitionAppear: React.PropTypes.bool,
-
- /**
- * Duration of the animation in milliseconds, to ensure that finishing
- * callbacks are fired even if the original browser transition end events are
- * canceled
- */
- duration: React.PropTypes.number,
-
- /**
- * CSS class or classes applied when the component is exited
- */
- exitedClassName: React.PropTypes.string,
- /**
- * CSS class or classes applied while the component is exiting
- */
- exitingClassName: React.PropTypes.string,
- /**
- * CSS class or classes applied when the component is entered
- */
- enteredClassName: React.PropTypes.string,
- /**
- * CSS class or classes applied while the component is entering
- */
- enteringClassName: React.PropTypes.string,
-
- /**
- * Callback fired before the "entering" classes are applied
- */
- onEnter: React.PropTypes.func,
- /**
- * Callback fired after the "entering" classes are applied
- */
- onEntering: React.PropTypes.func,
- /**
- * Callback fired after the "enter" classes are applied
- */
- onEntered: React.PropTypes.func,
- /**
- * Callback fired before the "exiting" classes are applied
- */
- onExit: React.PropTypes.func,
- /**
- * Callback fired after the "exiting" classes are applied
- */
- onExiting: React.PropTypes.func,
- /**
- * Callback fired after the "exited" classes are applied
- */
- onExited: React.PropTypes.func
-};
-
-// Name the function so it is clearer in the documentation
-function noop() {}
-
-Transition.defaultProps = {
- in: false,
- duration: 300,
- unmountOnExit: false,
- transitionAppear: false,
-
- onEnter: noop,
- onEntering: noop,
- onEntered: noop,
-
- onExit: noop,
- onExiting: noop,
- onExited: noop
-};
+import Transition from 'react-overlays/lib/Transition';
export default Transition;
diff --git a/src/utils/overlayPositionUtils.js b/src/utils/overlayPositionUtils.js
index d8909ec2ac..de8cfba920 100644
--- a/src/utils/overlayPositionUtils.js
+++ b/src/utils/overlayPositionUtils.js
@@ -1,109 +1,2 @@
-import domUtils from './domUtils';
-const utils = {
-
- getContainerDimensions(containerNode) {
- let size, scroll;
-
- if (containerNode.tagName === 'BODY') {
- size = {
- width: window.innerWidth,
- height: window.innerHeight
- };
- scroll =
- domUtils.ownerDocument(containerNode).documentElement.scrollTop ||
- containerNode.scrollTop;
- } else {
- size = domUtils.getSize(containerNode);
- scroll = containerNode.scrollTop;
- }
-
- return {...size, scroll};
- },
-
- getPosition(target, container) {
- const offset = container.tagName === 'BODY' ?
- domUtils.getOffset(target) : domUtils.getPosition(target, container);
- const size = domUtils.getSize(target);
- return {...offset, ...size};
- },
-
- calcOverlayPosition(placement, overlayNode, target, container, padding) {
- const childOffset = utils.getPosition(target, container);
-
- const {height: overlayHeight, width: overlayWidth} = domUtils.getSize(overlayNode);
-
- let positionLeft, positionTop, arrowOffsetLeft, arrowOffsetTop;
-
- if (placement === 'left' || placement === 'right') {
- positionTop = childOffset.top + (childOffset.height - overlayHeight) / 2;
-
- if (placement === 'left') {
- positionLeft = childOffset.left - overlayWidth;
- } else {
- positionLeft = childOffset.left + childOffset.width;
- }
-
- const topDelta = getTopDelta(positionTop, overlayHeight, container, padding);
-
- positionTop += topDelta;
- arrowOffsetTop = 50 * (1 - 2 * topDelta / overlayHeight) + '%';
- arrowOffsetLeft = null;
-
- } else if (placement === 'top' || placement === 'bottom') {
- positionLeft = childOffset.left + (childOffset.width - overlayWidth) / 2;
-
- if (placement === 'top') {
- positionTop = childOffset.top - overlayHeight;
- } else {
- positionTop = childOffset.top + childOffset.height;
- }
-
- const leftDelta = getLeftDelta(positionLeft, overlayWidth, container, padding);
- positionLeft += leftDelta;
- arrowOffsetLeft = 50 * (1 - 2 * leftDelta / overlayWidth) + '%';
- arrowOffsetTop = null;
- } else {
- throw new Error(
- `calcOverlayPosition(): No such placement of "${placement }" found.`
- );
- }
-
- return { positionLeft, positionTop, arrowOffsetLeft, arrowOffsetTop };
- }
-};
-
-
-function getTopDelta(top, overlayHeight, container, padding) {
- const containerDimensions = utils.getContainerDimensions(container);
- const containerScroll = containerDimensions.scroll;
- const containerHeight = containerDimensions.height;
-
- const topEdgeOffset = top - padding - containerScroll;
- const bottomEdgeOffset = top + padding - containerScroll + overlayHeight;
-
- if (topEdgeOffset < 0) {
- return -topEdgeOffset;
- } else if (bottomEdgeOffset > containerHeight) {
- return containerHeight - bottomEdgeOffset;
- } else {
- return 0;
- }
-}
-
-function getLeftDelta(left, overlayWidth, container, padding) {
- const containerDimensions = utils.getContainerDimensions(container);
- const containerWidth = containerDimensions.width;
-
- const leftEdgeOffset = left - padding;
- const rightEdgeOffset = left + padding + overlayWidth;
-
- if (leftEdgeOffset < 0) {
- return -leftEdgeOffset;
- } else if (rightEdgeOffset > containerWidth) {
- return containerWidth - rightEdgeOffset;
- } else {
- return 0;
- }
-}
-export default utils;
+export * from 'react-overlays/lib/utils/overlayPositionUtils';
diff --git a/test/OverlayTriggerSpec.js b/test/OverlayTriggerSpec.js
index 78b63502b4..cb48067872 100644
--- a/test/OverlayTriggerSpec.js
+++ b/test/OverlayTriggerSpec.js
@@ -82,7 +82,6 @@ describe('OverlayTrigger', function() {
);
overlayTrigger = React.findDOMNode(instance);
-
ReactTestUtils.Simulate.click(overlayTrigger);
});
diff --git a/test/PortalSpec.js b/test/PortalSpec.js
deleted file mode 100644
index 66a1b49fc0..0000000000
--- a/test/PortalSpec.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react';
-import ReactTestUtils from 'react/lib/ReactTestUtils';
-import Portal from '../src/Portal';
-
-describe('Portal', function () {
- let instance;
-
- let Overlay = React.createClass({
- render() {
- return (
-
- );
- },
- getOverlayDOMNode(){
- return this.refs.p.getOverlayDOMNode();
- }
- });
-
- afterEach(function() {
- if (instance && ReactTestUtils.isCompositeComponent(instance) && instance.isMounted()) {
- React.unmountComponentAtNode(React.findDOMNode(instance));
- }
- });
-
- it('Should render overlay into container (DOMNode)', function() {
- let container = document.createElement('div');
-
- instance = ReactTestUtils.renderIntoDocument(
- } />
- );
-
- assert.equal(container.querySelectorAll('#test1').length, 1);
- });
-
- it('Should render overlay into container (ReactComponent)', function() {
- let Container = React.createClass({
- render() {
- return } />;
- }
- });
-
- instance = ReactTestUtils.renderIntoDocument(
-
- );
-
- assert.equal(React.findDOMNode(instance).querySelectorAll('#test1').length, 1);
- });
-
- it('Should not render a null overlay', function() {
- let Container = React.createClass({
- render() {
- return ;
- }
- });
-
- instance = ReactTestUtils.renderIntoDocument(
-
- );
-
- assert.equal(instance.refs.overlay.getOverlayDOMNode(), null);
- });
-
- it('Should render only an overlay', function() {
- let OnlyOverlay = React.createClass({
- render() {
- return {this.props.overlay};
- }
- });
-
- let overlayInstance = ReactTestUtils.renderIntoDocument(
- } />
- );
-
- assert.equal(overlayInstance.refs.p.getOverlayDOMNode().nodeName, 'DIV');
- });
-});
diff --git a/test/PositionSpec.js b/test/PositionSpec.js
deleted file mode 100644
index ea1405fd14..0000000000
--- a/test/PositionSpec.js
+++ /dev/null
@@ -1,218 +0,0 @@
-import pick from 'lodash/object/pick';
-import React from 'react';
-import ReactTestUtils from 'react/lib/ReactTestUtils';
-
-import Position from '../src/Position';
-import overlayPositionUtils from '../src/utils/overlayPositionUtils';
-
-import {render} from './helpers';
-
-describe('Position', function () {
- it('Should output a child', function () {
- let instance = ReactTestUtils.renderIntoDocument(
-
- Text
-
- );
- assert.equal(React.findDOMNode(instance).nodeName, 'SPAN');
- });
-
- it('Should warn about several children', function () {
- expect(() => {
- ReactTestUtils.renderIntoDocument(
-
- Text
- Another Text
-
- );
- }).to.throw(Error, /onlyChild must be passed a children with exactly one child/);
- });
-
- describe('position recalculation', function () {
- beforeEach(function () {
- sinon.spy(overlayPositionUtils, 'calcOverlayPosition');
- sinon.spy(Position.prototype, 'componentWillReceiveProps');
- });
-
- afterEach(function () {
- overlayPositionUtils.calcOverlayPosition.restore();
- Position.prototype.componentWillReceiveProps.restore();
- });
-
- it('Should only recalculate when target changes', function () {
- class TargetChanger extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- target: 'foo',
- fakeProp: 0
- };
- }
-
- render() {
- return (
-
-
-
-
-
this.refs[this.state.target]}
- fakeProp={this.state.fakeProp}
- >
-
-
-
- );
- }
- }
-
- const instance = ReactTestUtils.renderIntoDocument();
-
- // Position calculates initial position.
- expect(Position.prototype.componentWillReceiveProps)
- .to.have.not.been.called;
- expect(overlayPositionUtils.calcOverlayPosition)
- .to.have.been.calledOnce;
-
- instance.setState({target: 'bar'});
-
- // Position receives new props and recalculates position.
- expect(Position.prototype.componentWillReceiveProps)
- .to.have.been.calledOnce;
- expect(overlayPositionUtils.calcOverlayPosition)
- .to.have.been.calledTwice;
-
- instance.setState({fakeProp: 1});
-
- // Position receives new props but should not recalculate position.
- expect(Position.prototype.componentWillReceiveProps)
- .to.have.been.calledTwice;
- expect(overlayPositionUtils.calcOverlayPosition)
- .to.have.been.calledTwice;
- });
- });
-
- describe('position calculation', function () {
- let mountPoint;
-
- beforeEach(function () {
- mountPoint = document.createElement('div');
- document.body.appendChild(mountPoint);
- });
-
- afterEach(function () {
- React.unmountComponentAtNode(mountPoint);
- document.body.removeChild(mountPoint);
- });
-
- function checkPosition(placement, targetPosition, expected) {
- class FakeOverlay extends React.Component {
- render() {
- return (
-
- );
- }
- }
-
- class FakeContainer extends React.Component {
- render() {
- return (
-
-
-
-
React.findDOMNode(this.refs.target)}
- container={this}
- containerPadding={50}
- placement={placement}
- >
-
-
-
- );
- }
- }
-
- const expectedPosition = {
- positionLeft: expected[0],
- positionTop: expected[1],
- arrowOffsetLeft: expected[2],
- arrowOffsetTop: expected[3]
- };
-
- it('Should calculate the correct position', function() {
- const instance = render(, mountPoint);
-
- const calculatedPosition = pick(
- instance.refs.overlay.props, Object.keys(expectedPosition)
- );
- expect(calculatedPosition).to.eql(expectedPosition);
- });
- }
-
- [
- {
- placement: 'left',
- noOffset: [50, 200, null, '50%'],
- offsetBefore: [-200, 50, null, '0%'],
- offsetAfter: [300, 350, null, '100%']
- },
- {
- placement: 'top',
- noOffset: [200, 50, '50%', null],
- offsetBefore: [50, -200, '0%', null],
- offsetAfter: [350, 300, '100%', null]
- },
- {
- placement: 'bottom',
- noOffset: [200, 350, '50%', null],
- offsetBefore: [50, 100, '0%', null],
- offsetAfter: [350, 600, '100%', null]
- },
- {
- placement: 'right',
- noOffset: [350, 200, null, '50%'],
- offsetBefore: [100, 50, null, '0%'],
- offsetAfter: [600, 350, null, '100%']
- }
- ].forEach(function(testCase) {
- const placement = testCase.placement;
-
- describe(`placement = ${placement}`, function() {
- describe('no viewport offset', function() {
- checkPosition(
- placement, {left: 250, top: 250}, testCase.noOffset
- );
- });
-
- describe('viewport offset before', function() {
- checkPosition(
- placement, {left: 0, top: 0}, testCase.offsetBefore
- );
- });
-
- describe('viewport offset after', function() {
- checkPosition(
- placement, {left: 500, top: 500}, testCase.offsetAfter
- );
- });
- });
- });
- });
-
- // ToDo: add remaining tests
-});
diff --git a/test/TransitionSpec.js b/test/TransitionSpec.js
deleted file mode 100644
index 1592e646f7..0000000000
--- a/test/TransitionSpec.js
+++ /dev/null
@@ -1,279 +0,0 @@
-import React from 'react';
-import ReactTestUtils from 'react/lib/ReactTestUtils';
-import { render } from './helpers';
-import Transition, {UNMOUNTED, EXITED, ENTERING, ENTERED, EXITING} from
- '../src/Transition';
-
-describe('Transition', function () {
- it('should not transition on mount', function(){
- let instance = render(
- { throw new Error('should not Enter'); }}>
-
-
- );
-
- expect(instance.state.status).to.equal(ENTERED);
- });
-
- it('should transition on mount with transitionAppear', done =>{
- let instance = ReactTestUtils.renderIntoDocument(
- done()}
- >
-
-
- );
-
- expect(instance.state.status).to.equal(EXITED);
- });
-
- describe('entering', ()=> {
- let instance;
-
- beforeEach(function(){
- instance = render(
-
-
-
- );
- });
-
- it('should fire callbacks', done => {
- let onEnter = sinon.spy();
- let onEntering = sinon.spy();
-
- expect(instance.state.status).to.equal(EXITED);
-
- instance = instance.renderWithProps({
- in: true,
-
- onEnter,
-
- onEntering,
-
- onEntered(){
- expect(onEnter.calledOnce).to.be.ok;
- expect(onEntering.calledOnce).to.be.ok;
- expect(onEnter.calledBefore(onEntering)).to.be.ok;
- done();
- }
- });
- });
-
- it('should move to each transition state', done => {
- let count = 0;
-
- expect(instance.state.status).to.equal(EXITED);
-
- instance = instance.renderWithProps({
- in: true,
-
- onEnter(){
- count++;
- expect(instance.state.status).to.equal(EXITED);
- },
-
- onEntering(){
- count++;
- expect(instance.state.status).to.equal(ENTERING);
- },
-
- onEntered(){
- expect(instance.state.status).to.equal(ENTERED);
- expect(count).to.equal(2);
- done();
- }
- });
- });
-
- it('should apply classes at each transition state', done => {
- let count = 0;
-
- expect(instance.state.status).to.equal(EXITED);
-
- instance = instance.renderWithProps({
- in: true,
-
- onEnter(node){
- count++;
- expect(node.className).to.equal('');
- },
-
- onEntering(node){
- count++;
- expect(node.className).to.equal('test-entering');
- },
-
- onEntered(node){
- expect(node.className).to.equal('test-enter');
- expect(count).to.equal(2);
- done();
- }
- });
- });
- });
-
- describe('exiting', ()=> {
- let instance;
-
- beforeEach(function(){
- instance = render(
-
-
-
- );
- });
-
- it('should fire callbacks', done => {
- let onExit = sinon.spy();
- let onExiting = sinon.spy();
-
- expect(instance.state.status).to.equal(ENTERED);
-
- instance = instance.renderWithProps({
- in: false,
-
- onExit,
-
- onExiting,
-
- onExited(){
- expect(onExit.calledOnce).to.be.ok;
- expect(onExiting.calledOnce).to.be.ok;
- expect(onExit.calledBefore(onExiting)).to.be.ok;
- done();
- }
- });
- });
-
- it('should move to each transition state', done => {
- let count = 0;
-
- expect(instance.state.status).to.equal(ENTERED);
-
- instance = instance.renderWithProps({
- in: false,
-
- onExit(){
- count++;
- expect(instance.state.status).to.equal(ENTERED);
- },
-
- onExiting(){
- count++;
- expect(instance.state.status).to.equal(EXITING);
- },
-
- onExited(){
- expect(instance.state.status).to.equal(EXITED);
- expect(count).to.equal(2);
- done();
- }
- });
- });
-
- it('should apply classes at each transition state', done => {
- let count = 0;
-
- expect(instance.state.status).to.equal(ENTERED);
-
- instance = instance.renderWithProps({
- in: false,
-
- onExit(node){
- count++;
- expect(node.className).to.equal('');
- },
-
- onExiting(node){
- count++;
- expect(node.className).to.equal('test-exiting');
- },
-
- onExited(node){
- expect(node.className).to.equal('test-exit');
- expect(count).to.equal(2);
- done();
- }
- });
- });
- });
-
- describe('unmountOnExit', () => {
- class UnmountTransition extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {in: props.initialIn};
- }
-
- render() {
- return (
-
-
-
- );
- }
-
- getStatus() {
- return this.refs.transition.state.status;
- }
- }
-
- it('should mount when entering', done => {
- const instance = render(
- {
- expect(instance.getStatus()).to.equal(EXITED);
- expect(React.findDOMNode(instance)).to.exist;
-
- done();
- }}
- />
- );
-
- expect(instance.getStatus()).to.equal(UNMOUNTED);
- expect(React.findDOMNode(instance)).to.not.exist;
-
- instance.setState({in: true});
- });
-
- it('should unmount after exiting', done => {
- const instance = render(
- {
- expect(instance.getStatus()).to.equal(UNMOUNTED);
- expect(React.findDOMNode(instance)).to.not.exist;
-
- done();
- }}
- />
- );
-
- expect(instance.getStatus()).to.equal(ENTERED);
- expect(React.findDOMNode(instance)).to.exist;
-
- instance.setState({in: false});
- });
- });
-});