UNPKG

ldx-widgets

Version:

widgets

302 lines (246 loc) 7.7 kB
React = require 'react' createClass = require 'create-react-class' PropTypes = require 'prop-types' {StyleSheet, css} = require 'aphrodite/no-important' assign = require 'lodash/assign' dialogueMixin = require '../mixins/dialogue_mixin' {ESCAPE, KEY_S} = require '../constants/keyboard' ConfirmSave = React.createFactory(require('./confirm_save')) Spinner = React.createFactory(require('./spinner')) {div, span, button} = require 'react-dom-factories' ###& @props.title - OPTIONAL - [String] title for the modal header @props.buttons - OPTIONAL - [Array] Array of button objects with name, handler to be called on click, and disabled boolean, eg... ``` [ { name: 'Create' handler: @create disabled: no } ] ``` @props.children - REQUIRED - [Element] React element (or array of elements) to inserted as the form body @props.styleOverride - OPTIONAL - [Object] aphrodite style object, optionally can contain .form, .title, .bar, .btn, .class defs, eg... ``` { formBase: {} form: {} title: {} bar: {} btn: {} } ``` @props.canUpdate - OPTIONAL - [Boolean] Defaults to no, whether or not the user can update and save the form @props.save - OPTIONAL - [Function] Function that save the form @props.close - OPTIONAL - [Function] Function that closes the form @props.onClose - OPTIONAL - [Function] Function that is called right before the modal closes @props.showClose - OPTIONAL - [Boolean] Defaults to yes, set it to no to not show the close button @props.closeAfterSave - OPTIONAL - [Boolean] Defaults to yes, set it to no to prevent the modal from calling @props.close after a save is complete Note: in this case you MUST pass an onSaveComplete handler that sets the saveState to null after a save @props.onSaveComplete - OPTIONAL - [Function] Function that is called right after the saveState is set to complete and the success indicator finishes animating @props.closeBtnText - OPTIONAL - [String] Defaults to 'Cancel', text to display in the close button @props.loading - OPTIONAL - [Boolean] Defaults to no, whether or not to show the spinner instead of the children @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 @props.unSavedMessage - OPTIONAL Message to be displayed in dialog if you have unsaved changes &### Form = createClass displayName: 'Form' mixins: [dialogueMixin] propTypes: styleOverride: PropTypes.shape form: PropTypes.object bar: PropTypes.object title: PropTypes.object btn: PropTypes.object title: PropTypes.string buttons: PropTypes.array canUpdate: PropTypes.bool save: PropTypes.func.isRequired close: PropTypes.func.isRequired onClose: PropTypes.func onSaveComplete: PropTypes.func showClose: PropTypes.bool closeAfterSave: PropTypes.bool closeBtnText: PropTypes.string unSavedMessage: PropTypes.string unSavedDialogueHeight: PropTypes.number unSavedChanges: PropTypes.bool onSaveFail: PropTypes.func inLineStyle: PropTypes.object loading: PropTypes.bool spinnerProps: PropTypes.object displayProgressBar: PropTypes.bool uploadProgress: PropTypes.oneOfType [ PropTypes.string PropTypes.number ] getDefaultProps: -> styleOverride: {} inLineStyle: {} buttons: [] canUpdate: true showClose: yes closeAfterSave: yes unSavedDialogueHeight: 100 saveState: null saveMessage: null unSavedChanges: no loading: no spinnerProps: length: 7 radius: 7 lines: 12 width: 2 displayProgressBar: no uploadProgress: '' componentWillMount: -> # This is necessary becasue translation is not available on app load # So this cannot live in default props @closeBtnText = t 'Cancel' document.addEventListener 'keydown', @handleKeyPress componentWillUnmount: -> document.removeEventListener 'keydown', @handleKeyPress render: -> {styleOverride, title, buttons, closeBtnText, showClose, children, save, saveState, saveMessage, canUpdate, unSavedChanges, onSaveFail, inLineStyle, loading, spinnerProps, displayProgressBar, uploadProgress} = @props closeBtnText = closeBtnText or @closeBtnText # buttons btns = [] # save button btns.push button { key: 'save' className: if unSavedChanges then css(styles.btn) else css(styles.btn, styles.disabled) onClick: save disabled: not unSavedChanges tabIndex: -1 }, t 'Save' if canUpdate # close/cancel button btns.push button { key: 'cancel' className: css(styles.btn) onClick: @closeWithCheck tabIndex: -1 }, closeBtnText if showClose # other buttons btns.push button { key: b.name className: css(styles.btn) onClick: b.handler disabled: b.disabled }, b.name for b in buttons by -1 assign styles, styleOverride inLineStyle = assign {}, inLineStyle assign spinnerProps, key: 'spinner' div { className: css(styles.formBase, styles.form) style: inLineStyle }, [ div { key: 'bar' className: css(styles.bar) }, [ div { key: 'name' className: css(styles.title) }, title btns ] unless loading @dialogueBox() ConfirmSave { key: 'confirm' done: @saveComplete fail: -> onSaveFail?() saveMessage: saveMessage saveState: saveState displayProgressBar: displayProgressBar uploadProgress: uploadProgress } if saveState? if loading then Spinner(spinnerProps) else children ] closeWithCheck: -> {unSavedMessage, unSavedDialogueHeight, unSavedChanges} = @props if unSavedChanges @showDialogue message: unSavedMessage or t 'There are unsaved changes. How do you want to proceed?' confirmText: t 'Discard Changes' height: unSavedDialogueHeight confirmCallback: @close else do @close close: -> {close, onClose} = @props onClose?() do close saveComplete: -> {close, onSaveComplete, closeAfterSave} = @props # if a onSaveComplete method has been passed then call it onSaveComplete?() do close if closeAfterSave handleKeyPress: (e) -> {keyCode, metaKey} = e if keyCode is ESCAPE then do @closeWithCheck if keyCode is KEY_S and metaKey do e.preventDefault {buttons} = @props if buttons[0]?.name is t 'Save' then do buttons[0].handler styles = StyleSheet.create formBase: position: 'absolute' backgroundColor: 'white' overflow: 'hidden' width: '100%' height: '100%' form: top: '0px' left: '0px' bar: position: 'absolute' height: '40px' backgroundColor: '#fafaf6' borderBottom: '1px solid #e5e4dc' overflow: 'hidden' zIndex: '8' width: '100%' title: overflow: 'hidden' whiteSpace: 'nowrap' textOverflow: 'ellipsis' fontSize: '18px' height: '100%' lineHeight: '40px' color: '#666666' display: 'inline-block' marginTop: '0px' marginLeft: '20px' paddingRight: '20px' btn: float: 'right' marginRight: '15px' color: '#007fff' height: '28px' textAlign: 'center' lineHeight: '26px' marginTop: '6px' fontSize: '13px' disabled: color: '#cccccc' module.exports = Form