diff options
Diffstat (limited to 'app/javascript/flavours/glitch/features/composer/options/dropdown')
3 files changed, 0 insertions, 504 deletions
diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js deleted file mode 100644 index b76410561..000000000 --- a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/index.js +++ /dev/null @@ -1,146 +0,0 @@ -// Package imports. -import PropTypes from 'prop-types'; -import React from 'react'; -import spring from 'react-motion/lib/spring'; - -// Components. -import ComposerOptionsDropdownContentItem from './item'; - -// Utils. -import { withPassive } from 'flavours/glitch/util/dom_helpers'; -import Motion from 'flavours/glitch/util/optional_motion'; -import { assignHandlers } from 'flavours/glitch/util/react_helpers'; - -// Handlers. -const handlers = { - // When the document is clicked elsewhere, we close the dropdown. - handleDocumentClick ({ target }) { - const { node } = this; - const { onClose } = this.props; - if (onClose && node && !node.contains(target)) { - onClose(); - } - }, - - // Stores our node in `this.node`. - handleRef (node) { - this.node = node; - }, -}; - -// The spring to use with our motion. -const springMotion = spring(1, { - damping: 35, - stiffness: 400, -}); - -// The component. -export default class ComposerOptionsDropdownContent extends React.PureComponent { - - // Constructor. - constructor (props) { - super(props); - assignHandlers(this, handlers); - - // Instance variables. - this.node = null; - - this.state = { - mounted: false, - }; - } - - // On mounting, we add our listeners. - componentDidMount () { - const { handleDocumentClick } = this.handlers; - document.addEventListener('click', handleDocumentClick, false); - document.addEventListener('touchend', handleDocumentClick, withPassive); - this.setState({ mounted: true }); - } - - // On unmounting, we remove our listeners. - componentWillUnmount () { - const { handleDocumentClick } = this.handlers; - document.removeEventListener('click', handleDocumentClick, false); - document.removeEventListener('touchend', handleDocumentClick, withPassive); - } - - // Rendering. - render () { - const { mounted } = this.state; - const { handleRef } = this.handlers; - const { - items, - onChange, - onClose, - style, - value, - } = this.props; - - // The result. - return ( - <Motion - defaultStyle={{ - opacity: 0, - scaleX: 0.85, - scaleY: 0.75, - }} - style={{ - opacity: springMotion, - scaleX: springMotion, - scaleY: springMotion, - }} - > - {({ opacity, scaleX, scaleY }) => ( - // It should not be transformed when mounting because the resulting - // size will be used to determine the coordinate of the menu by - // react-overlays - <div - className='composer--options--dropdown--content' - ref={handleRef} - style={{ - ...style, - opacity: opacity, - transform: mounted ? `scale(${scaleX}, ${scaleY})` : null, - }} - > - {items ? items.map( - ({ - name, - ...rest - }) => ( - <ComposerOptionsDropdownContentItem - active={name === value} - key={name} - name={name} - onChange={onChange} - onClose={onClose} - options={rest} - /> - ) - ) : null} - </div> - )} - </Motion> - ); - } - -} - -// Props. -ComposerOptionsDropdownContent.propTypes = { - items: PropTypes.arrayOf(PropTypes.shape({ - icon: PropTypes.string, - meta: PropTypes.node, - name: PropTypes.string.isRequired, - on: PropTypes.bool, - text: PropTypes.node, - })), - onChange: PropTypes.func, - onClose: PropTypes.func, - style: PropTypes.object, - value: PropTypes.string, -}; - -// Default props. -ComposerOptionsDropdownContent.defaultProps = { style: {} }; diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js deleted file mode 100644 index 68a52083f..000000000 --- a/app/javascript/flavours/glitch/features/composer/options/dropdown/content/item/index.js +++ /dev/null @@ -1,129 +0,0 @@ -// Package imports. -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import Toggle from 'react-toggle'; - -// Components. -import Icon from 'flavours/glitch/components/icon'; - -// Utils. -import { assignHandlers } from 'flavours/glitch/util/react_helpers'; - -// Handlers. -const handlers = { - - // This function activates the dropdown item. - handleActivate (e) { - const { - name, - onChange, - onClose, - options: { on }, - } = this.props; - - // If the escape key was pressed, we close the dropdown. - if (e.key === 'Escape' && onClose) { - onClose(); - - // Otherwise, we both close the dropdown and change the value. - } else if (onChange && (!e.key || e.key === 'Enter')) { - e.preventDefault(); // Prevents change in focus on click - if ((on === null || typeof on === 'undefined') && onClose) { - onClose(); - } - onChange(name); - } - }, -}; - -// The component. -export default class ComposerOptionsDropdownContentItem extends React.PureComponent { - - // Constructor. - constructor (props) { - super(props); - assignHandlers(this, handlers); - } - - // Rendering. - render () { - const { handleActivate } = this.handlers; - const { - active, - options: { - icon, - meta, - on, - text, - }, - } = this.props; - const computedClass = classNames('composer--options--dropdown--content--item', { - active, - lengthy: meta, - 'toggled-off': !on && on !== null && typeof on !== 'undefined', - 'toggled-on': on, - 'with-icon': icon, - }); - - // The result. - return ( - <div - className={computedClass} - onClick={handleActivate} - onKeyDown={handleActivate} - role='button' - tabIndex='0' - > - {function () { - - // We render a `<Toggle>` if we were provided an `on` - // property, and otherwise show an `<Icon>` if available. - switch (true) { - case on !== null && typeof on !== 'undefined': - return ( - <Toggle - checked={on} - onChange={handleActivate} - /> - ); - case !!icon: - return ( - <Icon - className='icon' - fullwidth - icon={icon} - /> - ); - default: - return null; - } - }()} - {meta ? ( - <div className='content'> - <strong>{text}</strong> - {meta} - </div> - ) : - <div className='content'> - <strong>{text}</strong> - </div>} - </div> - ); - } - -}; - -// Props. -ComposerOptionsDropdownContentItem.propTypes = { - active: PropTypes.bool, - name: PropTypes.string, - onChange: PropTypes.func, - onClose: PropTypes.func, - options: PropTypes.shape({ - icon: PropTypes.string, - meta: PropTypes.node, - on: PropTypes.bool, - text: PropTypes.node, - }), -}; diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js deleted file mode 100644 index 7817cc964..000000000 --- a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js +++ /dev/null @@ -1,229 +0,0 @@ -// Package imports. -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import Overlay from 'react-overlays/lib/Overlay'; - -// Components. -import IconButton from 'flavours/glitch/components/icon_button'; -import ComposerOptionsDropdownContent from './content'; - -// Utils. -import { isUserTouching } from 'flavours/glitch/util/is_mobile'; -import { assignHandlers } from 'flavours/glitch/util/react_helpers'; - -// Handlers. -const handlers = { - - // Closes the dropdown. - handleClose () { - this.setState({ open: false }); - }, - - // The enter key toggles the dropdown's open state, and the escape - // key closes it. - handleKeyDown ({ key }) { - const { - handleClose, - handleToggle, - } = this.handlers; - switch (key) { - case 'Enter': - handleToggle(key); - break; - case 'Escape': - handleClose(); - break; - } - }, - - // Creates an action modal object. - handleMakeModal () { - const component = this; - const { - items, - onChange, - onModalOpen, - onModalClose, - value, - } = this.props; - - // Required props. - if (!(onChange && onModalOpen && onModalClose && items)) { - return null; - } - - // The object. - return { - actions: items.map( - ({ - name, - ...rest - }) => ({ - ...rest, - active: value && name === value, - name, - onClick (e) { - e.preventDefault(); // Prevents focus from changing - onModalClose(); - onChange(name); - }, - onPassiveClick (e) { - e.preventDefault(); // Prevents focus from changing - onChange(name); - component.setState({ needsModalUpdate: true }); - }, - }) - ), - }; - }, - - // Toggles opening and closing the dropdown. - handleToggle ({ target }) { - const { handleMakeModal } = this.handlers; - const { onModalOpen } = this.props; - const { open } = this.state; - - // If this is a touch device, we open a modal instead of the - // dropdown. - if (isUserTouching()) { - - // This gets the modal to open. - const modal = handleMakeModal(); - - // If we can, we then open the modal. - if (modal && onModalOpen) { - onModalOpen(modal); - return; - } - } - - const { top } = target.getBoundingClientRect(); - this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); - // Otherwise, we just set our state to open. - this.setState({ open: !open }); - }, - - // If our modal is open and our props update, we need to also update - // the modal. - handleUpdate () { - const { handleMakeModal } = this.handlers; - const { onModalOpen } = this.props; - const { needsModalUpdate } = this.state; - - // Gets our modal object. - const modal = handleMakeModal(); - - // Reopens the modal with the new object. - if (needsModalUpdate && modal && onModalOpen) { - onModalOpen(modal); - } - }, -}; - -// The component. -export default class ComposerOptionsDropdown extends React.PureComponent { - - // Constructor. - constructor (props) { - super(props); - assignHandlers(this, handlers); - this.state = { - needsModalUpdate: false, - open: false, - placement: 'bottom', - }; - } - - // Updates our modal as necessary. - componentDidUpdate (prevProps) { - const { handleUpdate } = this.handlers; - const { items } = this.props; - const { needsModalUpdate } = this.state; - if (needsModalUpdate && items.find( - (item, i) => item.on !== prevProps.items[i].on - )) { - handleUpdate(); - this.setState({ needsModalUpdate: false }); - } - } - - // Rendering. - render () { - const { - handleClose, - handleKeyDown, - handleToggle, - } = this.handlers; - const { - active, - disabled, - title, - icon, - items, - onChange, - value, - } = this.props; - const { open, placement } = this.state; - const computedClass = classNames('composer--options--dropdown', { - active, - open, - top: placement === 'top', - }); - - // The result. - return ( - <div - className={computedClass} - onKeyDown={handleKeyDown} - > - <IconButton - active={open || active} - className='value' - disabled={disabled} - icon={icon} - onClick={handleToggle} - size={18} - style={{ - height: null, - lineHeight: '27px', - }} - title={title} - /> - <Overlay - containerPadding={20} - placement={placement} - show={open} - target={this} - > - <ComposerOptionsDropdownContent - items={items} - onChange={onChange} - onClose={handleClose} - value={value} - /> - </Overlay> - </div> - ); - } - -} - -// Props. -ComposerOptionsDropdown.propTypes = { - active: PropTypes.bool, - disabled: PropTypes.bool, - icon: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.shape({ - icon: PropTypes.string, - meta: PropTypes.node, - name: PropTypes.string.isRequired, - on: PropTypes.bool, - text: PropTypes.node, - })).isRequired, - onChange: PropTypes.func, - onModalClose: PropTypes.func, - onModalOpen: PropTypes.func, - title: PropTypes.string, - value: PropTypes.string, -}; |