UNPKG

ldx-widgets

Version:

widgets

209 lines (163 loc) 6.31 kB
### 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 @props.displayProgressBar - OPTIONAL - [Boolean] Defaults to no, whether or not the confirm/save show the progress bar instead of the spinner @props.uploadProgress - OPTIONAL Progress of a file being uploaded 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'}) ### React = require 'react' createClass = require 'create-react-class' Animation = require 'ainojs-animation' easing = require 'ainojs-easing' Spinner = React.createFactory(require './spinner') ProgressBar = React.createFactory(require './progress_bar') {div, span, button} = require 'react-dom-factories' ConfirmSave = createClass displayName: 'ConfirmSave' getDefaultProps: -> dismissBtnText: 'Dismiss' scaleCheckmark: 1 animationDuration: 800 vTranslateCheckmark: 0 saveMessage: '' displayProgressBar: no uploadProgress: '' getInitialState: -> scale: .25 render: -> {dismissBtnText, saveState, scaleCheckmark, vTranslateCheckmark, saveMessage, displayProgressBar, uploadProgress} = @props {scale} = @state confirmSaveClass = 'confirm-save-wrap' confirmSaveClass += ' has-message' if saveMessage if saveState is 'pending' and displayProgressBar and uploadProgress isnt '' confirmSaveClass += ' progress-background' content = ProgressBar { key: 'progress' progress: uploadProgress className: "modal-bar" labelPosition: "top" } else if saveState is 'pending' content = Spinner { lines: 12 length: 10 width: 3 radius: 8 color: 'white' } # Use a separate component for messages else if saveMessage checkClassName = 'confirm-check-message' checkClassName += ' failed' if saveState is 'failed' checkClassName += ' warning' if saveState is 'warning' # Don't do a scale animation when there's a message scaleCheckmark = 1 content = [ div { key: 'icon' className: checkClassName }, span { className: 'confirm-message' }, saveMessage div { key: 'dismiss' className: 'message-dismiss' }, button { onClick: @end }, dismissBtnText ] else checkClassName = 'confirm-check' checkClassName += ' failed' if saveState is 'failed' checkClassName += ' warning' if saveState is 'warning' content = div { className: checkClassName style: transform: "scale(#{scale})" msTransform: "scale(#{scale})" WebkitTransform: "scale(#{scale})" } if saveState is 'pending' and displayProgressBar and uploadProgress isnt '' displayContent = div { className: 'progress-bar-frame' }, content else displayContent = div { className: 'confirm-frame' style: transform: "scale(#{scaleCheckmark}) translateY(#{vTranslateCheckmark}px)" msTransform: "scale(#{scaleCheckmark}) translateY(#{vTranslateCheckmark}px)" WebkitTransform: "scale(#{scaleCheckmark}) translateY(#{vTranslateCheckmark}px)" }, content div { className: confirmSaveClass }, displayContent componentWillMount: -> @endHasBeenCalled = no # Handles the case when the saveState is never pending if @props.saveState is 'complete' or @props.saveState is 'failed' @animateImmediately = yes componentDidMount: -> @animateCheck() if @animateImmediately componentDidUpdate: (prevProps) -> return unless prevProps.saveState is 'pending' and (@props.saveState is 'complete' or @props.saveState is 'warning' or @props.saveState is 'failed') @animateCheck() componentWillUnmount: -> if @animation?.isAnimating() then @animation.end() animateCheck: -> if @animation?.isAnimating() then @animation.end() {scale} = @state {animationDuration, saveMessage} = @props @animation = new Animation duration: animationDuration easing: easing('easeOutElastic') .init {scale} .on 'frame', @onFrame .on 'complete', if saveMessage then -> else @end .animateTo {scale: 1} onFrame: (e) -> @setState e.values end: -> {saveState, done, fail} = @props if not @endHasBeenCalled @endHasBeenCalled = yes if saveState is 'complete' then @props.done?() else @props.fail?() module.exports = ConfirmSave