UNPKG

@lyra/form-builder

Version:
447 lines (361 loc) 14.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _slateBase64Serializer = require('slate-base64-serializer'); var _slateBase64Serializer2 = _interopRequireDefault(_slateBase64Serializer); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _slate = require('slate'); var _slateReact = require('slate-react'); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _router = require('part:@lyra/base/router'); var _blockExtras = require('part:@lyra/form-builder/input/block-editor/block-extras'); var _blockExtras2 = _interopRequireDefault(_blockExtras); var _linkIcon = require('part:@lyra/base/link-icon'); var _linkIcon2 = _interopRequireDefault(_linkIcon); var _buttonCollection = require('part:@lyra/components/buttons/button-collection'); var _buttonCollection2 = _interopRequireDefault(_buttonCollection); var _PatchEvent = require('../../../PatchEvent'); var _pathUtils = require('../../../utils/pathUtils'); var _resolveTypeName = require('../../../utils/resolveTypeName'); var _createRange = require('../utils/createRange'); var _createRange2 = _interopRequireDefault(_createRange); var _InvalidValueInput = require('../../InvalidValueInput'); var _InvalidValueInput2 = _interopRequireDefault(_InvalidValueInput); var _Preview = require('../../../Preview'); var _Preview2 = _interopRequireDefault(_Preview); var _DeleteButton = require('../DeleteButton'); var _DeleteButton2 = _interopRequireDefault(_DeleteButton); var _EditButton = require('../EditButton'); var _EditButton2 = _interopRequireDefault(_EditButton); var _ViewButton = require('../ViewButton'); var _ViewButton2 = _interopRequireDefault(_ViewButton); var _BlockObject = require('./styles/BlockObject.css'); var _BlockObject2 = _interopRequireDefault(_BlockObject); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /*:: import type {Node} from 'react'*/ /*:: import type { BlockContentFeatures, SlateValue, Type, SlateChange, Marker } from '../typeDefs'*/ /*:: type Props = { attributes: {}, blockContentFeatures: BlockContentFeatures, children: Node, editor: Editor, editorValue: SlateValue, hasFormBuilderFocus: boolean, isSelected: boolean, markers: Marker[], node: Block, onChange: (change: SlateChange) => void, onFocus: (nextPath: []) => void, onHideBlockDragMarker: void => void, onPatch: (event: PatchEvent) => void, onShowBlockDragMarker: (pos: string, node: HTMLDivElement) => void, readOnly: ?boolean, blockActions?: React.Node, renderCustomMarkers?: (Marker[]) => React.Node, type: ?Type }*/ /*:: type State = { isDragging: boolean, isEditing: boolean, isSelected: boolean }*/ class BlockObject extends _react2.default.Component /*:: <Props, State>*/ { constructor(...args) { var _temp; return _temp = super(...args), this.rootElement = null, this.state = { isDragging: false }, this.handleDragStart = event => { const node = this.props.node; this.setState({ isDragging: true }); this.addDragHandlers(); // const element = ReactDOM.findDOMNode(this.previewContainer) const encoded = _slateBase64Serializer2.default.serializeNode(node, { preserveKeys: true }); event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.dropEffect = 'none'; (0, _slateReact.setEventTransfer)(event, 'node', encoded); // event.dataTransfer.setDragImage(element, element.clientWidth / 2, element.clientHeight) }, this.handleDragLeave = event => { event.dataTransfer.dropEffect = 'none'; this.props.onHideBlockDragMarker(); if (event.target === this._editorNode) { this.resetDropTarget(); } }, this.handleDragOverOtherNode = event => { const node = this.props.node; if (!this.state.isDragging) { return; } const targetDOMNode = event.target; // As the event is registered on the editor parent node // ignore the event if it is coming from from the editor node itself if (targetDOMNode === this._editorNode) { return; } const editorValue = this.props.editorValue; const targetNode = (0, _slateReact.findNode)(targetDOMNode, editorValue); if (!targetNode) { return; } const block = targetNode.object === 'block' ? targetNode : editorValue.document.getClosestBlock(targetNode.key); // If no or same block reset and return if (!block || block.key === node.key) { event.dataTransfer.dropEffect = 'none'; this.resetDropTarget(); return; } const range = (0, _createRange2.default)(event); if (range === null) { return; } const rangeIsAtStart = range.rangeIsAtStart, rangeOffset = range.rangeOffset; // If the block in the nearest vincinity (same position target), reset and return let nearestNeighbour = false; if (rangeIsAtStart) { const nextBlock = editorValue.document.getNextBlock(node.key); nearestNeighbour = nextBlock && nextBlock.key === block.key; } else { const previousBlock = editorValue.document.getPreviousBlock(node.key); nearestNeighbour = previousBlock && previousBlock.key === block.key; } if (nearestNeighbour) { event.dataTransfer.dropEffect = 'none'; this.resetDropTarget(); return; } const domNode = (0, _slateReact.findDOMNode)(block); // eslint-disable-line react/no-find-dom-node if (rangeIsAtStart) { this.props.onShowBlockDragMarker('before', domNode); } else { this.props.onShowBlockDragMarker('after', domNode); } event.dataTransfer.dropEffect = 'move'; this._dropTarget = { node: block, isAtStart: rangeIsAtStart, offset: rangeOffset }; }, this.handleDragEnd = event => { event.preventDefault(); this.setState({ isDragging: false }); this.removeDragHandlers(); var _props = this.props; const onChange = _props.onChange, node = _props.node, editorValue = _props.editorValue; const target = this._dropTarget; // Return if this is our node if (!target || target.node.key === node.key) { this.resetDropTarget(); return; } let nextChange = editorValue.change().removeNodeByKey(node.key); nextChange = nextChange[target.isAtStart ? 'collapseToStartOf' : 'collapseToEndOf'](target.node).insertBlock(node).collapseToEndOf(node).focus(); onChange(nextChange); this.resetDropTarget(); }, this.handleCancelEvent = event => { event.preventDefault(); event.stopPropagation(); }, this.handleFocus = event => { event.stopPropagation(); var _props2 = this.props; const node = _props2.node, onFocus = _props2.onFocus; onFocus([{ _key: node.key }, _pathUtils.FOCUS_TERMINATOR]); }, this.handleEditStart = event => { event.stopPropagation(); var _props3 = this.props; const node = _props3.node, onFocus = _props3.onFocus, onChange = _props3.onChange, editorValue = _props3.editorValue; const change = editorValue.change().collapseToEndOf(node).focus().blur(); onChange(change, () => onFocus([{ _key: node.key }, _pathUtils.FOCUS_TERMINATOR])); }, this.handleClose = () => { var _props4 = this.props; const node = _props4.node, onFocus = _props4.onFocus; onFocus([{ _key: node.key }]); }, this.refFormBuilderBlock = formBuilderBlock => { this.formBuilderBlock = formBuilderBlock; }, this.refPreview = previewContainer => { this.previewContainer = previewContainer; }, this.handleInvalidValue = (event /*: PatchEvent*/) => { const onPatch = this.props.onPatch; const value = this.getValue(); onPatch(event.prefixAll({ _key: value._key }), value); }, this.handleRemoveValue = event => { event.preventDefault(); event.stopPropagation(); var _props5 = this.props; const editorValue = _props5.editorValue, node = _props5.node, onChange = _props5.onChange; const change = editorValue.change(); onChange(change.removeNodeByKey(node.key).focus()); }, _temp; } componentDidMount() { const editor = this.props.editor; this._editorNode = _reactDom2.default.findDOMNode(editor); } componentWillUnmount() { this.removeDragHandlers(); } addDragHandlers() { const readOnly = this.props.readOnly; if (readOnly) { return; } this._editorNode.addEventListener('dragover', this.handleDragOverOtherNode); this._editorNode.addEventListener('dragleave', this.handleDragLeave); } removeDragHandlers() { this._editorNode.removeEventListener('dragover', this.handleDragOverOtherNode); this._editorNode.removeEventListener('dragleave', this.handleDragLeave); } // Remove the drop target if we leave the editors nodes resetDropTarget() { this._dropTarget = null; this.props.onHideBlockDragMarker(); } // eslint-disable-next-line complexity getValue() { return this.props.node.data.get('value'); } renderPreview(value) { var _props6 = this.props; const type = _props6.type, readOnly = _props6.readOnly; return _react2.default.createElement( 'div', null, _react2.default.createElement( 'div', { className: _BlockObject2.default.header }, _react2.default.createElement( 'div', { className: _BlockObject2.default.type }, type.title || type.name || 'Unknown' ), _react2.default.createElement( _buttonCollection2.default, { align: 'end', className: _BlockObject2.default.functions }, value._ref && _react2.default.createElement( _router.IntentLink, { className: _BlockObject2.default.linkToReference, intent: 'edit', params: { id: value._ref } }, _react2.default.createElement(_linkIcon2.default, null) ), readOnly ? _react2.default.createElement( 'div', null, _react2.default.createElement(_ViewButton2.default, { title: 'View this block', onClick: this.handleFocus }) ) : _react2.default.createElement( 'div', null, _react2.default.createElement(_EditButton2.default, { title: 'Edit this block', onClick: this.handleEditStart }) ), !readOnly && _react2.default.createElement( 'div', null, _react2.default.createElement(_DeleteButton2.default, { title: 'Remove this block', onClick: this.handleRemoveValue }) ) ) ), _react2.default.createElement(_Preview2.default, { type: type, value: value, layout: 'block' }) ); } render() { var _props7 = this.props; const attributes = _props7.attributes, blockContentFeatures = _props7.blockContentFeatures, editorValue = _props7.editorValue, isSelected = _props7.isSelected, markers = _props7.markers, node = _props7.node, onChange = _props7.onChange, onFocus = _props7.onFocus, readOnly = _props7.readOnly, blockActions = _props7.blockActions, renderCustomMarkers = _props7.renderCustomMarkers; const value = this.getValue(); const valueType = (0, _resolveTypeName.resolveTypeName)(value); const validTypes = blockContentFeatures.types.blockObjects.map(objType => objType.name).concat('block'); if (!validTypes.includes(valueType)) { return _react2.default.createElement( 'div', { onClick: this.handleCancelEvent }, _react2.default.createElement(_InvalidValueInput2.default, { validTypes: validTypes, actualType: valueType, value: value, onChange: this.handleInvalidValue }) ); } const validation = markers.filter(marker => marker.type === 'validation'); const errors = validation.filter(marker => marker.level === 'error'); const highlightedMarker = markers.find(mrk => mrk.highlighted); const highlightedId = highlightedMarker ? highlightedMarker.highlighted : null; const classname = (0, _classnames2.default)([_BlockObject2.default.root, editorValue.selection.hasFocusIn(node) && _BlockObject2.default.focused, isSelected && _BlockObject2.default.selected, errors.length > 0 && _BlockObject2.default.hasErrors]); return _react2.default.createElement( 'div', null, _react2.default.createElement( 'div', _extends({}, attributes, { onDragStart: this.handleDragStart, onDragEnd: this.handleDragEnd, onDragEnter: this.handleCancelEvent, onDragLeave: this.handleCancelEvent, onDrop: this.handleCancelEvent, onDoubleClick: this.handleEditStart, draggable: !readOnly, ref: this.refFormBuilderBlock, className: classname }), _react2.default.createElement( 'div', { ref: this.refPreview, className: _BlockObject2.default.previewContainer }, this.renderPreview(value) ) ), (markers.length > 0 || blockActions) && _react2.default.createElement(_blockExtras2.default, { highlightedMarkerId: highlightedId, markers: markers, onFocus: onFocus, onChange: onChange, editorValue: editorValue, block: value, blockActions: blockActions, renderCustomMarkers: renderCustomMarkers }) ); } } exports.default = BlockObject;