ldx-widgets
Version:
widgets
201 lines (177 loc) • 6.79 kB
JavaScript
/*
This component is intended to be used inside of a modal or popover,
but could be used other places to confirm a save event was successful
Confirm Save Props
@props.saveState - string
This can be either 'pending' or 'complete' or 'failed'
- When 'pending', a spinner shows
- When 'complete', a green check mark flashes before calling the done callback
- When 'warning', a yellow exclamation mark flashes before calling the done callback
- When 'failed', a red x flashes before calling the fail callback
@props.saveMessage - string
A message that will be displayed alongside the saveState imagery
@props.dismissBtnText - string
Text that will be displayed as the dismiss button
@props.done - method
This method will be called animationDuration ms after the saveState hits complete
It will usually be a method that closes the popover or modal
@props.fail - method
This method will be called animationDuration ms after the saveState hits failed
It will usually be a method that sets the parent's saveState back to null, which will remove this widget from the DOM
@props.scaleCheckmark - default 1
percent to scale the confirm check and spinner
@props.vTranslateCheckmark - default 0
number of pixels to move the checkmark up above the middle of the container
@props.animationDuration - default 800
ms over which the check scalling takes place
Tips for using this..
- It is absolutely positioned w/ all zeroes, to add to the top level of the render tree
- Create a local 'saveState' state on your component, and default it to null
- render like this:
ConfirmSave {
key: 'confirm'
done: @close
saveState: @state.saveState
} if @state.saveState?
This way, when you trigger the save, also call @setState({saveState: 'pending'})
Then pass a call back to the save action, which just calls @setState({saveState: 'complete'})
*/
(function() {
var Animation, ConfirmSave, React, Spinner, button, createClass, div, easing, ref, span;
React = require('react');
createClass = require('create-react-class');
Animation = require('ainojs-animation');
easing = require('ainojs-easing');
Spinner = React.createFactory(require('./spinner'));
ref = React.DOM, div = ref.div, span = ref.span, button = ref.button;
ConfirmSave = createClass({
displayName: 'ConfirmSave',
getDefaultProps: function() {
return {
dismissBtnText: 'Dismiss',
scaleCheckmark: 1,
animationDuration: 800,
vTranslateCheckmark: 0,
saveMessage: ''
};
},
getInitialState: function() {
return {
scale: .25
};
},
render: function() {
var checkClassName, content, dismissBtnText, ref1, saveMessage, saveState, scale, scaleCheckmark, vTranslateCheckmark;
ref1 = this.props, dismissBtnText = ref1.dismissBtnText, saveState = ref1.saveState, scaleCheckmark = ref1.scaleCheckmark, vTranslateCheckmark = ref1.vTranslateCheckmark, saveMessage = ref1.saveMessage;
scale = this.state.scale;
if (saveState === 'pending') {
content = Spinner({
lines: 12,
length: 10,
width: 3,
radius: 8,
color: 'white'
});
} else if (saveMessage) {
checkClassName = 'confirm-check-message';
if (saveState === 'failed') {
checkClassName += ' failed';
}
if (saveState === 'warning') {
checkClassName += ' warning';
}
scaleCheckmark = 1;
content = [
div({
key: 'icon',
className: checkClassName
}, span({
className: 'confirm-message'
}, saveMessage)), div({
key: 'dismiss',
className: 'message-dismiss'
}, button({
onClick: this.end
}, dismissBtnText))
];
} else {
checkClassName = 'confirm-check';
if (saveState === 'failed') {
checkClassName += ' failed';
}
if (saveState === 'warning') {
checkClassName += ' warning';
}
content = div({
className: checkClassName,
style: {
transform: "scale(" + scale + ")",
msTransform: "scale(" + scale + ")",
WebkitTransform: "scale(" + scale + ")"
}
});
}
return div({
className: 'confirm-save-wrap' + (saveMessage ? ' has-message' : '')
}, div({
className: 'confirm-frame',
style: {
transform: "scale(" + scaleCheckmark + ") translateY(" + vTranslateCheckmark + "px)",
msTransform: "scale(" + scaleCheckmark + ") translateY(" + vTranslateCheckmark + "px)",
WebkitTransform: "scale(" + scaleCheckmark + ") translateY(" + vTranslateCheckmark + "px)"
}
}, content));
},
componentWillMount: function() {
if (this.props.saveState === 'complete' || this.props.saveState === 'failed') {
return this.animateImmediately = true;
}
},
componentDidMount: function() {
if (this.animateImmediately) {
return this.animateCheck();
}
},
componentDidUpdate: function(prevProps) {
if (!(prevProps.saveState === 'pending' && (this.props.saveState === 'complete' || this.props.saveState === 'warning' || this.props.saveState === 'failed'))) {
return;
}
return this.animateCheck();
},
componentWillUnmount: function() {
var ref1;
if ((ref1 = this.animation) != null ? ref1.isAnimating() : void 0) {
return this.animation.end();
}
},
animateCheck: function() {
var animationDuration, ref1, ref2, saveMessage, scale;
if ((ref1 = this.animation) != null ? ref1.isAnimating() : void 0) {
this.animation.end();
}
scale = this.state.scale;
ref2 = this.props, animationDuration = ref2.animationDuration, saveMessage = ref2.saveMessage;
return this.animation = new Animation({
duration: animationDuration,
easing: easing('easeOutElastic')
}).init({
scale: scale
}).on('frame', this.onFrame).on('complete', saveMessage ? function() {} : this.end).animateTo({
scale: 1
});
},
onFrame: function(e) {
return this.setState(e.values);
},
end: function() {
var base, base1, done, fail, ref1, saveState;
ref1 = this.props, saveState = ref1.saveState, done = ref1.done, fail = ref1.fail;
if (saveState === 'complete') {
return typeof (base = this.props).done === "function" ? base.done() : void 0;
} else {
return typeof (base1 = this.props).fail === "function" ? base1.fail() : void 0;
}
}
});
module.exports = ConfirmSave;
}).call(this);