diff --git a/i18n/en-US.properties b/i18n/en-US.properties index d5ff763a6..1400fa7cf 100644 --- a/i18n/en-US.properties +++ b/i18n/en-US.properties @@ -1,5 +1,7 @@ # Placeholder when the current annotation's user information is unknown ba.anonymousUserName = Some User +# Description for popover close hotkey record +ba.closePopover = Close Popover # Label for who left the annotation ba.whoAnnotated = {name} annotated # Label for who drew the drawing annotation diff --git a/package.json b/package.json index c762e89be..168bd8826 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "lint-staged": "^7.2.2", "mini-css-extract-plugin": "^0.4.2", "mocha": "^5.2.0", + "mousetrap": "^1.6.2", "node-sass": "^4.9.3", "optimize-css-assets-webpack-plugin": "^4.0.2", "pikaday": "^1.8.0", diff --git a/src/AnnotationThread.js b/src/AnnotationThread.js index 6e884c639..51156ef16 100644 --- a/src/AnnotationThread.js +++ b/src/AnnotationThread.js @@ -669,25 +669,6 @@ class AnnotationThread extends EventEmitter { super.emit('threadevent', { event, data: threadData, eventData }); } - /** - * Keydown handler for dialog. - * - * @param {Event} event DOM event - * @return {void} - */ - keydownHandler(event: Event) { - event.stopPropagation(); - - const key = util.decodeKeydown(event); - if (key === 'Escape') { - if (this.hasAnnotations()) { - this.hide(); - } else { - this.cancelAnnotation(); - } - } - } - /** * Show/hide the top portion of the annotations icon based on if the * entire dialog is flipped diff --git a/src/components/AnnotationPopover/AnnotationPopover.js b/src/components/AnnotationPopover/AnnotationPopover.js index 0ab916f35..a262d188b 100644 --- a/src/components/AnnotationPopover/AnnotationPopover.js +++ b/src/components/AnnotationPopover/AnnotationPopover.js @@ -2,9 +2,12 @@ import React from 'react'; import classNames from 'classnames'; import noop from 'lodash/noop'; +import { FormattedMessage } from 'react-intl'; import PlainButton from 'box-react-ui/lib/components/plain-button'; import IconClose from 'box-react-ui/lib/icons/general/IconClose'; +import { HotkeyRecord, HotkeyLayer } from 'box-react-ui/lib/components/hotkeys'; +import messages from './messages'; import Internationalize from '../Internationalize'; import CommentList from '../CommentList'; import { TYPES, CLASS_ANNOTATION_POPOVER, CLASS_ANNOTATION_CARET } from '../../constants'; @@ -43,7 +46,6 @@ class AnnotationPopover extends React.PureComponent { canDelete: false, onCommentClick: noop, onDelete: noop, - onCancel: noop, onCreate: noop, comments: [] }; @@ -80,49 +82,59 @@ class AnnotationPopover extends React.PureComponent { } = this.props; const hasComments = comments.length > 0; const isInline = !hasComments && (type === TYPES.highlight || type === TYPES.draw); + const configs = [ + new HotkeyRecord({ + description: , + key: 'esc', + handler: onCancel, + type: 'Close' + }) + ]; return ( -
- {isMobile ? ( - - - - - - ) : ( - - )} -
- {hasComments ? ( - + +
+ {isMobile ? ( + + + + + ) : ( - - )} - {canAnnotate && ( - + )} +
+ {hasComments ? ( + + ) : ( + + )} + {canAnnotate && ( + + )} +
-
+ ); } diff --git a/src/components/AnnotationPopover/__tests__/__snapshots__/AnnotationPopover-test.js.snap b/src/components/AnnotationPopover/__tests__/__snapshots__/AnnotationPopover-test.js.snap index ee816424b..d2d255d99 100644 --- a/src/components/AnnotationPopover/__tests__/__snapshots__/AnnotationPopover-test.js.snap +++ b/src/components/AnnotationPopover/__tests__/__snapshots__/AnnotationPopover-test.js.snap @@ -2,21 +2,15 @@ exports[`components/AnnotationPopover should correctly render a div without a Focus Trap 1`] = ` -
- - , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -26,133 +20,157 @@ exports[`components/AnnotationPopover should correctly render a div without a Fo "value": undefined, }, ], - } - } - > - - - + }, + "key": "esc", + "type": "Close", + }, + ] + } + enableHelpModal={false} + helpModalShortcut="?" + >
- - + + + + +
+ + onDelete={ + [MockFunction] { + "calls": Array [ + Array [], + ], + "results": Array [ + Object { + "isThrow": false, + "value": undefined, + }, + ], + } + } + /> + +
-
+
`; exports[`components/AnnotationPopover should correctly render a pending annotation 1`] = ` -
- -
- - , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -162,83 +180,90 @@ exports[`components/AnnotationPopover should correctly render a pending annotati "value": undefined, }, ], + }, + "key": "esc", + "type": "Close", + }, + ] + } + enableHelpModal={false} + helpModalShortcut="?" + > +
+ +
+ + + /> +
-
+ `; exports[`components/AnnotationPopover should correctly render a popover with comments and reply textarea 1`] = ` -
- -
- , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -248,102 +273,130 @@ exports[`components/AnnotationPopover should correctly render a popover with com "value": undefined, }, ], - } - } + }, + "key": "esc", + "type": "Close", + }, + ] + } + enableHelpModal={false} + helpModalShortcut="?" + > +
+ - + + /> + +
-
+
`; exports[`components/AnnotationPopover should correctly render a view-only popover with comments 1`] = ` -
- -
- , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -353,36 +406,84 @@ exports[`components/AnnotationPopover should correctly render a view-only popove "value": undefined, }, ], - } - } + }, + "key": "esc", + "type": "Close", + }, + ] + } + enableHelpModal={false} + helpModalShortcut="?" + > +
+ +
+ +
-
+ `; exports[`components/AnnotationPopover should correctly render an annotation with a annotator label and no comments 1`] = ` -
- -
- - , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -392,24 +493,92 @@ exports[`components/AnnotationPopover should correctly render an annotation with "value": undefined, }, ], + }, + "key": "esc", + "type": "Close", + }, + ] + } + enableHelpModal={false} + helpModalShortcut="?" + > +
+ +
+ + +
+
+ + +`; + +exports[`components/AnnotationPopover should render a view-only annotation with a annotator label and no comments 1`] = ` + + , + "handler": [MockFunction] { "calls": Array [ Array [], ], @@ -419,31 +588,30 @@ exports[`components/AnnotationPopover should correctly render an annotation with "value": undefined, }, ], - } - } - type="highlight" - /> -
-
-
-`; - -exports[`components/AnnotationPopover should render a view-only annotation with a annotator label and no comments 1`] = ` - -
-
- +
+ +
-
+
`; diff --git a/src/components/AnnotationPopover/messages.js b/src/components/AnnotationPopover/messages.js index 24dd65293..71a71da80 100644 --- a/src/components/AnnotationPopover/messages.js +++ b/src/components/AnnotationPopover/messages.js @@ -28,6 +28,11 @@ const messages: { [string]: MessageDescriptor } = defineMessages({ id: 'ba.whoAnnotated', description: 'Label for who left the annotation', defaultMessage: '{name} annotated' + }, + close: { + id: 'ba.closePopover', + description: 'Description for popover close hotkey record', + defaultMessage: 'Close Popover' } }); diff --git a/src/doc/DocHighlightThread.js b/src/doc/DocHighlightThread.js index c01d56b35..77b98de64 100644 --- a/src/doc/DocHighlightThread.js +++ b/src/doc/DocHighlightThread.js @@ -498,21 +498,6 @@ class DocHighlightThread extends AnnotationThread { popoverEl.style.top = `${dialogY + INLINE_POPOVER_HEIGHT / 2 - BORDER_OFFSET}px`; }; - /** - * Keydown handler on dialog. Needed since we are binding to 'mousedown' - * instead of 'click'. - * - * @param {Event} event - Mouse event - * @return {void} - */ - keydownHandler(event: Event) { - event.stopPropagation(); - if (util.decodeKeydown(event) === 'Enter') { - this.mousedownHandler(event); - } - super.keydownHandler(event); - } - /** @inheritdoc */ cleanupAnnotationOnDelete(annotationIDToRemove: string) { // Delete matching comment from annotation diff --git a/yarn.lock b/yarn.lock index 88b53e57c..f991579a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8668,6 +8668,11 @@ moo@^0.4.3: resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e" integrity sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw== +mousetrap@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.2.tgz#caadd9cf886db0986fb2fee59a82f6bd37527587" + integrity sha512-jDjhi7wlHwdO6q6DS7YRmSHcuI+RVxadBkLt3KHrhd3C2b+w5pKefg3oj5beTcHZyVFA9Aksf+yEE1y5jxUjVA== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"