Skip to content

Commit

Permalink
feat: add popover
Browse files Browse the repository at this point in the history
Also made general improvements to the modal.
  • Loading branch information
satazor committed Jul 17, 2018
1 parent cb3664d commit 5fc01d9
Show file tree
Hide file tree
Showing 17 changed files with 846 additions and 73 deletions.
34 changes: 26 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-modal": "^3.5.1",
"react-popper": "^1.0.0",
"react-preload-image": "^1.0.4",
"react-time-ago": "^2.0.3"
"react-time-ago": "^2.0.3",
"react-transition-group": "^2.4.0"
},
"devDependencies": {
"@storybook/addon-knobs": "^3.4.8",
Expand Down
2 changes: 1 addition & 1 deletion src/components/button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default class Button extends Component {
}

render() {
const { variant, fullWidth, children, className, disabled, ...rest } = this.props;
const { variant, fullWidth, disabled, className, children, ...rest } = this.props;
const { feedback, feedbackOutcome } = this.state;
const loading = feedback === 'loading';
const finalDisabled = disabled || loading;
Expand Down
22 changes: 11 additions & 11 deletions src/components/button/ProgressBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default class ProgressBar extends Component {
}

storeRef = (ref) => {
this.progressBar = ref;
this.progressBarNode = ref;
};

maybeHandleRunningChange(prevRunning) {
Expand Down Expand Up @@ -75,24 +75,24 @@ export default class ProgressBar extends Component {
this.clearTimersAndListeners();
this.currentProgress = 1;

this.progressBar.style.transform = 'scaleX(1)';
this.cancelOnTransitionEnd = onTransitionEnd(this.progressBar, () => {
this.progressBarNode.style.transform = 'scaleX(1)';
this.cancelOnTransitionEnd = onTransitionEnd(this.progressBarNode, () => {
this.props.onEnd && this.props.onEnd();

this.progressBar.style.opacity = '0';
this.cancelOnTransitionEnd = onTransitionEnd(this.progressBar, () => this.reset);
this.progressBarNode.style.opacity = '0';
this.cancelOnTransitionEnd = onTransitionEnd(this.progressBarNode, () => this.reset);
});
}

reset = () => {
this.clearTimersAndListeners();
this.currentProgress = 0;

this.progressBar.style.transition = 'none';
this.progressBar.style.transform = '';
this.progressBar.style.opacity = '';
this.progressBar.offsetHeight; // eslint-disable-line no-unused-expressions
this.progressBar.style.transition = '';
this.progressBarNode.style.transition = 'none';
this.progressBarNode.style.transform = '';
this.progressBarNode.style.opacity = '';
this.progressBarNode.offsetHeight; // eslint-disable-line no-unused-expressions
this.progressBarNode.style.transition = '';

this.props.onReset && this.props.onReset();
};
Expand All @@ -113,7 +113,7 @@ export default class ProgressBar extends Component {
}

this.currentProgress += increment;
this.progressBar.style.transform = `scaleX(${this.currentProgress})`;
this.progressBarNode.style.transform = `scaleX(${this.currentProgress})`;
};

determineIncrement() {
Expand Down
12 changes: 9 additions & 3 deletions src/components/modal/Modal.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "colors";
@import "mixins/typography";

:root {
--spacing: 4em;
Expand Down Expand Up @@ -28,10 +29,10 @@
opacity: 0;
transition: opacity 0.1s linear;
}
}

.modal-content {
@mixin typography-body-1 em;
& .content {
@mixin typography-body-1 em;
}
}

.modal-overlay {
Expand All @@ -53,6 +54,11 @@
}
}

.modal-portal {
position: relative;
z-index: 999999;
}

.modal-body-open {
overflow: hidden;
}
6 changes: 3 additions & 3 deletions src/components/modal/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from 'classnames';
import ReactModal from 'react-modal';
import styles from './Modal.css';

const CLOSE_TIMEOUT_MS = 250; // Must be 50ms higher than the close animation
const CLOSE_TRANSITION_DURATION = 250; // Must be 50ms higher than the actual CSS duration

const computeClassName = (className, classNameProp) => {
if (classNameProp) {
Expand Down Expand Up @@ -55,13 +55,13 @@ export default class Modal extends Component {

return (
<ReactModal
closeTimeoutMS={ CLOSE_TIMEOUT_MS }
closeTimeoutMS={ CLOSE_TRANSITION_DURATION }
{ ...rest }
className={ finalClassName }
overlayClassName={ finalOverlayClassName }
portalClassName={ classNames(styles.modalPortal, portalClassName) }
bodyOpenClassName={ classNames(styles.modalBodyOpen, bodyOpenClassName) }>
<div className={ classNames(styles.modalContent, contentClassName) }>
<div className={ classNames(styles.content, contentClassName) }>
{ children }
</div>
</ReactModal>
Expand Down
85 changes: 68 additions & 17 deletions src/components/modal/ModalTrigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,85 @@ import PropTypes from 'prop-types';
export default class ModalTrigger extends Component {
static propTypes = {
modal: PropTypes.element.isRequired,
children: PropTypes.func.isRequired,
children: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired,
};

constructor() {
super();

this.defaultEventProps = {
onClick: this.handleOpen,
};
}

state = { isOpen: false };

render() {
const { children: trigger, modal } = this.props;
const { isOpen } = this.state;
componentWillUnmount() {
clearTimeout(this.openCloseTimeoutId);
}

render() {
return (
<Fragment>
{ trigger({
isOpen,
open: this.handleOpen,
close: this.handleClose,
toggle: this.handleToggle,
}) }
{ cloneElement(modal, {
isOpen,
onRequestClose: this.handleClose,
}) }
{ this.renderTrigger() }
{ this.renderModal() }
</Fragment>
);
}

handleOpen = () => this.setState({ isOpen: true });
renderTrigger() {
const { children: trigger } = this.props;
const { isOpen } = this.state;

return typeof trigger === 'function' ?
trigger({
isOpen,
open: this.handleOpen,
cancelOpen: this.handleCancelOpen,
close: this.handleClose,
toggle: this.handleToggle,
defaultEventProps: this.defaultEventProps,
}) :
cloneElement(trigger, this.defaultEventProps);
}

renderModal() {
const { modal } = this.props;
const { isOpen } = this.state;

handleClose = () => this.setState({ isOpen: false });
return cloneElement(modal, {
isOpen,
onRequestClose: this.handleModalRequestClose,
});
}

handleOpen = (delay) => {
clearTimeout(this.openCloseTimeoutId);

this.openCloseTimeoutId = setTimeout(() => {
this.setState({ isOpen: true });
}, delay);
};

handleCancelOpen = () => {
clearTimeout(this.openCloseTimeoutId);
};

handleClose = (delay) => {
clearTimeout(this.openCloseTimeoutId);

this.openCloseTimeoutId = setTimeout(() => {
this.setState({ isOpen: false });
}, delay);
};

handleToggle = (delay) => {
if (this.state.isOpen) {
this.handleClose(delay);
} else {
this.handleOpen(delay);
}
};

handleToggle = () => this.setState(({ isOpen }) => ({ isOpen: !isOpen }));
handleModalRequestClose = (e, delay) => this.handleClose(e, delay);
}
Loading

0 comments on commit 5fc01d9

Please sign in to comment.