diff --git a/package-lock.json b/package-lock.json index 817d94e..ce99332 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "fast-deep-equal": "^3.1.3", "node-polyglot": "^2.4.0", "react-autosize-textarea": "^7.1.0", + "react-draggable": "^4.4.3", "react-select": "^4.3.1", "react-transition-group": "^4.4.2", "timeago-react": "^3.0.2", @@ -1641,6 +1642,11 @@ "fsevents": "~2.1.1" } }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "node_modules/cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -2956,6 +2962,15 @@ "react": "^16.14.0" } }, + "node_modules/react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, "node_modules/react-input-autosize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", @@ -4903,6 +4918,11 @@ "readdirp": "~3.2.0" } }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -5881,6 +5901,15 @@ "scheduler": "^0.19.1" } }, + "react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, "react-input-autosize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", diff --git a/package.json b/package.json index 137bde6..9c80e2d 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "fast-deep-equal": "^3.1.3", "node-polyglot": "^2.4.0", "react-autosize-textarea": "^7.1.0", + "react-draggable": "^4.4.3", "react-select": "^4.3.1", "react-transition-group": "^4.4.2", "timeago-react": "^3.0.2", diff --git a/src/editor/Editor.jsx b/src/editor/Editor.jsx index bfaac0a..1fa4f90 100644 --- a/src/editor/Editor.jsx +++ b/src/editor/Editor.jsx @@ -1,4 +1,5 @@ import React, { useState, useRef, useEffect } from 'react'; +import Draggable from 'react-draggable'; import { getWidget, DEFAULT_WIDGETS } from './widgets'; import { TrashIcon } from '../Icons'; import setPosition from './setPosition'; @@ -22,6 +23,8 @@ const Editor = props => { // The current state of the edited annotation vs. original const [ currentAnnotation, setCurrentAnnotation ] = useState(); + const [ dragged, setDragged ] = useState(false); + // Reference to the DOM element, so we can set position const element = useRef(); @@ -46,14 +49,16 @@ const Editor = props => { const initResizeObserver = () => { if (window?.ResizeObserver) { const resizeObserver = new ResizeObserver(() => { - setPosition(props.wrapperEl, element.current, props.selectedElement); + if (!dragged) + setPosition(props.wrapperEl, element.current, props.selectedElement); }); resizeObserver.observe(props.wrapperEl); return () => resizeObserver.disconnect(); } else { // Fire setPosition *only* for devices that don't support ResizeObserver - setPosition(props.wrapperEl, element.current, props.selectedElement); + if (!dragged) + setPosition(props.wrapperEl, element.current, props.selectedElement); } } @@ -164,51 +169,57 @@ const Editor = props => { !widgets.some(isReadOnlyWidget); // every widget is deletable return ( -
-
-
- {widgets.map(widget => - React.cloneElement(widget, { - annotation : currentAnnotation, - readOnly : props.readOnly, - env: props.env, - onAppendBody, - onUpdateBody, - onRemoveBody, - onUpsertBody, - onSetProperty, - onSaveAndClose: onOk - }) - )} - - { props.readOnly ? ( -
- -
- ) : ( -
- { hasDelete && ( + setDragged(true)}> + +
+
+
+ {widgets.map(widget => + React.cloneElement(widget, { + annotation : currentAnnotation, + readOnly : props.readOnly, + env: props.env, + onAppendBody, + onUpdateBody, + onRemoveBody, + onUpsertBody, + onSetProperty, + onSaveAndClose: onOk + }) + )} + + { props.readOnly ? ( +
+ +
+ ) : ( +
+ { hasDelete && ( + + )} + - )} + className="r6o-btn outline" + onClick={onCancel}>{i18n.t('Cancel')} - - - -
- )} + +
+ )} +
-
+ + ) } diff --git a/src/editor/widgets/comment/Comment.jsx b/src/editor/widgets/comment/Comment.jsx index cc9b9dc..2369e35 100644 --- a/src/editor/widgets/comment/Comment.jsx +++ b/src/editor/widgets/comment/Comment.jsx @@ -66,7 +66,7 @@ const Comment = props => { /> }
setIsMenuVisible(!isMenuVisible)}>
diff --git a/src/editor/widgets/comment/DropdownMenu.jsx b/src/editor/widgets/comment/DropdownMenu.jsx index 43903f5..60b2d82 100644 --- a/src/editor/widgets/comment/DropdownMenu.jsx +++ b/src/editor/widgets/comment/DropdownMenu.jsx @@ -10,7 +10,7 @@ const DropdownMenu = props => { useClickOutside(ref, () => props.onClickOutside()); return ( -
    +
    • {i18n.t('Edit')}
    • {i18n.t('Delete')}
    diff --git a/src/editor/widgets/comment/TextEntryField.jsx b/src/editor/widgets/comment/TextEntryField.jsx index 1585ea0..cbd5e46 100644 --- a/src/editor/widgets/comment/TextEntryField.jsx +++ b/src/editor/widgets/comment/TextEntryField.jsx @@ -22,7 +22,7 @@ export default class TextEntryField extends Component { return ( { } return ( -
    +
    { tags.length > 0 &&
      { tags.map(tag => diff --git a/themes/default/editor/_editor.scss b/themes/default/editor/_editor.scss index 5b62266..89e0540 100644 --- a/themes/default/editor/_editor.scss +++ b/themes/default/editor/_editor.scss @@ -116,6 +116,10 @@ } +.r6o-editor.dragged .r6o-arrow { + display:none; +} + .r6o-purposedropdown { width: 150px; display: inline-block;