UNPKG

@alyzenpublic/react-keyed-file-browser

Version:

Folder based file browser given a flat keyed list of objects, powered by React.

213 lines (189 loc) 5.77 kB
import PropTypes from 'prop-types' import React from 'react' class BaseFolder extends React.Component { static propTypes = { name: PropTypes.string, fileKey: PropTypes.string, newName: PropTypes.string, keyDerived: PropTypes.bool, isDraft: PropTypes.bool, isRenaming: PropTypes.bool, isDeleting: PropTypes.bool, connectDragSource: PropTypes.func, connectDropTarget: PropTypes.func, isDragging: PropTypes.bool, action: PropTypes.string, browserProps: PropTypes.shape({ select: PropTypes.func, toggleFolder: PropTypes.func, beginAction: PropTypes.func, endAction: PropTypes.func, preview: PropTypes.func, createFiles: PropTypes.func, createFolder: PropTypes.func, moveFile: PropTypes.func, moveFolder: PropTypes.func, renameFolder: PropTypes.func, deleteFolder: PropTypes.func, }), } state = { newName: this.props.isDraft ? 'New folder' : this.getName(), } componentDidMount() { if (this.props.isDraft) { this.selectAllNewName() } } componentDidUpdate(oldProps, oldState) { if (!oldProps.isRenaming && this.props.isRenaming) { this.selectAllNewName() } } selectAllNewName = () => { window.requestAnimationFrame(() => { const currentName = this.newNameRef.value this.newNameRef.setSelectionRange(0, currentName.length) this.newNameRef.focus() }) } getName() { if (this.props.name) { return this.props.name } const folders = this.props.fileKey.split('/') return this.props.newName || folders[folders.length - 2] } handleFolderClick = (event) => { event.stopPropagation() this.props.browserProps.select(this.props.fileKey, 'folder') } handleFolderDoubleClick = (event) => { event.stopPropagation() this.toggleFolder() } handleRenameClick = (event) => { if (!this.props.browserProps.renameFolder) { return } this.props.browserProps.beginAction('rename', this.props.fileKey) } handleNewNameChange = (event) => { const newName = this.newNameRef.value this.setState({newName: newName}) } handleRenameSubmit = (event) => { event.preventDefault() if (!this.props.browserProps.renameFolder) { return } const newName = this.state.newName.trim() if (newName.length === 0) { // todo: move to props handler // window.notify({ // style: 'error', // title: 'Invalid new folder name', // body: 'Folder name cannot be blank', // }) return } if (newName.indexOf('/') !== -1) { // todo: move to props handler // window.notify({ // style: 'error', // title: 'Invalid new folder name', // body: 'Folder names cannot contain forward slashes.', // }) return } let newKey = this.props.fileKey.substr(0, this.props.fileKey.substr(0, this.props.fileKey.length - 1).lastIndexOf('/')) if (newKey.length) { newKey += '/' } newKey += newName newKey += '/' if (this.props.isDraft) { this.props.browserProps.createFolder(newKey) } else { this.props.browserProps.renameFolder(this.props.fileKey, newKey) } } handleDeleteClick = (event) => { if (!this.props.browserProps.deleteFolder) { return } this.props.browserProps.beginAction('delete', this.props.fileKey) } handleDeleteSubmit = (event) => { event.preventDefault() if (!this.props.browserProps.deleteFolder) { return } this.props.browserProps.deleteFolder(this.props.fileKey) } handleCancelEdit = (event) => { this.props.browserProps.endAction() } toggleFolder = () => { this.props.browserProps.toggleFolder(this.props.fileKey) } connectDND(render) { const inAction = (this.props.isDragging || this.props.action) if (this.props.keyDerived) { if ( typeof this.props.browserProps.moveFolder === 'function' && !inAction && !this.props.isRenaming && !this.props.isDeleting ) { render = this.props.connectDragSource(render) } if ( typeof this.props.browserProps.createFiles === 'function' || typeof this.props.browserProps.moveFolder === 'function' || typeof this.props.browserProps.moveFile === 'function' ) { render = this.props.connectDropTarget(render) } } return render } } const dragSource = { beginDrag(props) { props.browserProps.select(props.fileKey, 'folder') return { key: props.fileKey, } }, endDrag(props, monitor, component) { if (!monitor.didDrop()) { return } const dropResult = monitor.getDropResult() const fileNameParts = props.fileKey.split('/') const folderName = fileNameParts[fileNameParts.length - 2] const newKey = `${dropResult.path}${folderName}/` // abort if the new folder name contains itself if (newKey.substr(0, props.fileKey.length) === props.fileKey) return if (newKey !== props.fileKey && props.browserProps.renameFolder) { props.browserProps.openFolder(dropResult.path) props.browserProps.renameFolder(props.fileKey, newKey) } }, } function dragCollect(connect, monitor) { return { connectDragPreview: connect.dragPreview(), connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), } } const BaseFolderConnectors = { dragSource, dragCollect, } export default BaseFolder export { BaseFolderConnectors, }