box-annotations 4.1.1-beta.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/annotations.css +1 -1
  2. package/dist/annotations.js +2 -1
  3. package/dist/annotations.js.LICENSE.txt +89 -0
  4. package/i18n/en-US.js +1 -0
  5. package/i18n/en-US.properties +2 -0
  6. package/i18n/json/src/components/Popups/messages.json +1 -1
  7. package/package.json +47 -43
  8. package/src/@types/global.ts +1 -4
  9. package/src/common/BaseAnnotator.scss +1 -14
  10. package/src/common/BaseManager.ts +10 -6
  11. package/src/common/DeselectManager.tsx +6 -3
  12. package/src/common/useAutoScroll/useAutoScroll.tsx +1 -1
  13. package/src/components/Popups/Popper.ts +18 -0
  14. package/src/components/Popups/PopupBase.tsx +1 -1
  15. package/src/components/Popups/PopupCursor.tsx +3 -10
  16. package/src/components/Popups/PopupHighlight.tsx +2 -9
  17. package/src/components/Popups/PopupHighlightError.tsx +2 -9
  18. package/src/components/Popups/PopupReply.tsx +7 -10
  19. package/src/components/Popups/messages.ts +5 -0
  20. package/src/components/ReplyField/ReplyField.tsx +5 -1
  21. package/src/components/ReplyForm/ReplyButton.tsx +1 -1
  22. package/src/components/ReplyForm/ReplyForm.tsx +9 -1
  23. package/src/drawing/DrawingAnnotations.tsx +1 -1
  24. package/src/drawing/DrawingCreator.tsx +1 -1
  25. package/src/drawing/DrawingManager.tsx +6 -2
  26. package/src/drawing/actions.ts +0 -2
  27. package/src/drawing/drawingUtil.ts +0 -1
  28. package/src/highlight/HighlightManager.tsx +6 -2
  29. package/src/highlight/actions.ts +0 -1
  30. package/src/popup/PopupLayer.tsx +2 -2
  31. package/src/popup/PopupManager.tsx +6 -2
  32. package/src/region/RegionCreationManager.tsx +6 -2
  33. package/src/region/RegionManager.tsx +6 -2
  34. package/src/region/actions.ts +0 -1
  35. package/src/store/highlight/actions.ts +1 -1
  36. package/src/store/users/actions.ts +3 -3
  37. package/src/common/usePrevious.ts +0 -13
@@ -0,0 +1,89 @@
1
+ /*
2
+ object-assign
3
+ (c) Sindre Sorhus
4
+ @license MIT
5
+ */
6
+
7
+ /*!
8
+ Copyright (c) 2017 Jed Watson.
9
+ Licensed under the MIT License (MIT), see
10
+ http://jedwatson.github.io/classnames
11
+ */
12
+
13
+ /*!
14
+ * Box Annotations
15
+ *
16
+ * Copyright 2016-present Box, Inc. All Rights Reserved.
17
+ *
18
+ * This source code is licensed under the Box Software License Agreement found
19
+ * in the LICENSE file in the root directory of this source tree. Additional
20
+ * third party license disclosures can be found in the THIRD_PARTY_LICENSES
21
+ * file in the same directory.
22
+ */
23
+
24
+ /*!
25
+ * UAParser.js v0.7.21
26
+ * Lightweight JavaScript-based User-Agent string parser
27
+ * https://github.com/faisalman/ua-parser-js
28
+ *
29
+ * Copyright © 2012-2019 Faisal Salman <f@faisalman.com>
30
+ * Licensed under MIT License
31
+ */
32
+
33
+ /**
34
+ * @license React
35
+ * react-dom.production.min.js
36
+ *
37
+ * Copyright (c) Facebook, Inc. and its affiliates.
38
+ *
39
+ * This source code is licensed under the MIT license found in the
40
+ * LICENSE file in the root directory of this source tree.
41
+ */
42
+
43
+ /**
44
+ * @license React
45
+ * react.production.min.js
46
+ *
47
+ * Copyright (c) Facebook, Inc. and its affiliates.
48
+ *
49
+ * This source code is licensed under the MIT license found in the
50
+ * LICENSE file in the root directory of this source tree.
51
+ */
52
+
53
+ /**
54
+ * @license React
55
+ * scheduler.production.min.js
56
+ *
57
+ * Copyright (c) Facebook, Inc. and its affiliates.
58
+ *
59
+ * This source code is licensed under the MIT license found in the
60
+ * LICENSE file in the root directory of this source tree.
61
+ */
62
+
63
+ /**
64
+ * @license React
65
+ * use-sync-external-store-with-selector.production.min.js
66
+ *
67
+ * Copyright (c) Facebook, Inc. and its affiliates.
68
+ *
69
+ * This source code is licensed under the MIT license found in the
70
+ * LICENSE file in the root directory of this source tree.
71
+ */
72
+
73
+ /** @license React v0.18.0
74
+ * scheduler.production.min.js
75
+ *
76
+ * Copyright (c) Facebook, Inc. and its affiliates.
77
+ *
78
+ * This source code is licensed under the MIT license found in the
79
+ * LICENSE file in the root directory of this source tree.
80
+ */
81
+
82
+ /** @license React v16.12.0
83
+ * react-is.production.min.js
84
+ *
85
+ * Copyright (c) Facebook, Inc. and its affiliates.
86
+ *
87
+ * This source code is licensed under the MIT license found in the
88
+ * LICENSE file in the root directory of this source tree.
89
+ */
package/i18n/en-US.js CHANGED
@@ -5,6 +5,7 @@ export default {
5
5
  "ba.annotationsPost": "Post",
6
6
  "ba.annotationsSave": "Save",
7
7
  "ba.popup.reply.comment": "Comment",
8
+ "ba.popup.reply.field": "Type a comment",
8
9
  "ba.popups.cancel": "Cancel",
9
10
  "ba.popups.drawing.addComment": "Add Comment",
10
11
  "ba.popups.drawing.delete": "Delete",
@@ -10,6 +10,8 @@ ba.annotationsPost = Post
10
10
  ba.annotationsSave = Save
11
11
  # Aria label description for reply popup
12
12
  ba.popup.reply.comment = Comment
13
+ # Aria label description for annotation comment field
14
+ ba.popup.reply.field = Type a comment
13
15
  # Button label for cancelling the creation of a description, comment, or reply
14
16
  ba.popups.cancel = Cancel
15
17
  # Button label for adding a comment in the drawing toolbar
@@ -1 +1 @@
1
- [{"id":"ba.popup.reply.comment","description":"Aria label description for reply popup","defaultMessage":"Comment"},{"id":"ba.popups.cancel","description":"Button label for cancelling the creation of a description, comment, or reply","defaultMessage":"Cancel"},{"id":"ba.popups.post","description":"Button label for creating a description, comment, or reply","defaultMessage":"Post"},{"id":"ba.popups.drawing.addComment","description":"Button label for adding a comment in the drawing toolbar","defaultMessage":"Add Comment"},{"id":"ba.popups.drawing.delete","description":"Button title for deleting a staged drawing","defaultMessage":"Delete"},{"id":"ba.popups.drawing.redo","description":"Button title for redoing a staged drawing","defaultMessage":"Redo"},{"id":"ba.popups.drawing.undo","description":"Button title for undoing a staged drawing","defaultMessage":"Undo"},{"id":"ba.popups.replyField.placeholder","description":"Placeholder for reply field editor","defaultMessage":"Type a comment..."},{"id":"ba.popups.popupHighlight.promoter","description":"Popup message for highlight promoter","defaultMessage":"Highlight and Comment"},{"id":"ba.popups.popupHighlight.restrictedPrompt","description":"Prompt message when selection crosses multiple pages","defaultMessage":"Comments restricted to single page"},{"id":"ba.popups.popupList.prompt","description":"Prompt message for empty popup list","defaultMessage":"Mention someone to notify them"},{"id":"ba.popups.popupCursor.regionPrompt","description":"Prompt message following cursor in region annotations mode","defaultMessage":"Draw a box to comment"}]
1
+ [{"id":"ba.popup.reply.comment","description":"Aria label description for reply popup","defaultMessage":"Comment"},{"id":"ba.popup.reply.field","description":"Aria label description for annotation comment field","defaultMessage":"Type a comment"},{"id":"ba.popups.cancel","description":"Button label for cancelling the creation of a description, comment, or reply","defaultMessage":"Cancel"},{"id":"ba.popups.post","description":"Button label for creating a description, comment, or reply","defaultMessage":"Post"},{"id":"ba.popups.drawing.addComment","description":"Button label for adding a comment in the drawing toolbar","defaultMessage":"Add Comment"},{"id":"ba.popups.drawing.delete","description":"Button title for deleting a staged drawing","defaultMessage":"Delete"},{"id":"ba.popups.drawing.redo","description":"Button title for redoing a staged drawing","defaultMessage":"Redo"},{"id":"ba.popups.drawing.undo","description":"Button title for undoing a staged drawing","defaultMessage":"Undo"},{"id":"ba.popups.replyField.placeholder","description":"Placeholder for reply field editor","defaultMessage":"Type a comment..."},{"id":"ba.popups.popupHighlight.promoter","description":"Popup message for highlight promoter","defaultMessage":"Highlight and Comment"},{"id":"ba.popups.popupHighlight.restrictedPrompt","description":"Prompt message when selection crosses multiple pages","defaultMessage":"Comments restricted to single page"},{"id":"ba.popups.popupList.prompt","description":"Prompt message for empty popup list","defaultMessage":"Mention someone to notify them"},{"id":"ba.popups.popupCursor.regionPrompt","description":"Prompt message following cursor in region annotations mode","defaultMessage":"Draw a box to comment"}]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "box-annotations",
3
- "version": "4.1.1-beta.4",
3
+ "version": "5.0.0",
4
4
  "description": "Box Annotations",
5
5
  "author": "Box (https://www.box.com/)",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -12,22 +12,24 @@
12
12
  "registry": "https://registry.npmjs.org/"
13
13
  },
14
14
  "engines": {
15
- "node": ">=10.x",
15
+ "node": ">=18.x",
16
16
  "yarn": ">=1.10.x"
17
17
  },
18
18
  "devDependencies": {
19
- "@babel/cli": "^7.8.4",
20
- "@babel/core": "^7.9.0",
21
- "@babel/plugin-proposal-class-properties": "^7.8.3",
22
- "@babel/plugin-transform-flow-strip-types": "^7.9.0",
23
- "@babel/plugin-transform-object-assign": "^7.8.3",
24
- "@babel/plugin-transform-runtime": "^7.9.0",
25
- "@babel/polyfill": "^7.8.7",
26
- "@babel/preset-env": "^7.9.5",
27
- "@babel/preset-react": "^7.9.4",
28
- "@babel/preset-typescript": "^7.9.0",
29
- "@box/frontend": "^6.4.0",
19
+ "@babel/cli": "^7.25.9",
20
+ "@babel/core": "^7.25.9",
21
+ "@babel/eslint-parser": "^7.24.7",
22
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
23
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
24
+ "@babel/plugin-transform-flow-strip-types": "^7.25.9",
25
+ "@babel/plugin-transform-object-assign": "^7.25.9",
26
+ "@babel/plugin-transform-runtime": "^7.25.9",
27
+ "@babel/preset-env": "^7.25.9",
28
+ "@babel/preset-react": "^7.25.9",
29
+ "@babel/preset-typescript": "^7.25.9",
30
+ "@box/frontend": "^10.0.0",
30
31
  "@box/languages": "^1.1.0",
32
+ "@cfaester/enzyme-adapter-react-18": "^0.8.0",
31
33
  "@commitlint/cli": "^8.3.5",
32
34
  "@commitlint/config-conventional": "^8.2.0",
33
35
  "@formatjs/intl-pluralrules": "^1.5.5",
@@ -39,67 +41,67 @@
39
41
  "@types/enzyme": "^3.10.5",
40
42
  "@types/jest": "^24.9.0",
41
43
  "@types/lodash": "^4.14.150",
42
- "@types/react": "^17.0.2",
43
- "@types/react-dom": "^17.0.1",
44
- "@types/react-redux": "^7.1.16",
44
+ "@types/react": "18.3.12",
45
+ "@types/react-dom": "18.3.1",
46
+ "@types/react-redux": "^7.1.33",
45
47
  "@types/uuid": "^8.3.0",
46
- "@typescript-eslint/eslint-plugin": "^2.29.0",
47
- "@typescript-eslint/parser": "^2.29.0",
48
- "@wojtekmaj/enzyme-adapter-react-17": "^0.4.1",
48
+ "@typescript-eslint/eslint-plugin": "^7.3.1",
49
+ "@typescript-eslint/parser": "^7.3.1",
49
50
  "autoprefixer": "^9.7.6",
50
51
  "axios": "^0.24.0",
51
52
  "babel-eslint": "^10.1.0",
52
53
  "babel-jest": "^24.9.0",
53
- "babel-loader": "^8.1.0",
54
+ "babel-loader": "^8.3.0",
54
55
  "babel-plugin-istanbul": "^6.0.0",
55
56
  "babel-plugin-react-intl": "^7.5.1",
56
57
  "babel-plugin-transform-require-ignore": "^0.1.1",
57
58
  "box-node-sdk": "^1.33.0",
58
- "box-ui-elements": "^15.0.0-beta.6",
59
+ "box-ui-elements": "^20.0.0",
59
60
  "circular-dependency-plugin": "^5.2.0",
60
61
  "classnames": "^2.2.5",
61
62
  "conventional-github-releaser": "^3.1.3",
62
- "core-js": "^3.6.5",
63
+ "core-js": "^3.38.1",
63
64
  "css-loader": "^3.5.2",
64
65
  "cypress": "^4.4.1",
65
66
  "draft-js": "0.10.5",
66
67
  "enzyme": "^3.11.0",
67
68
  "enzyme-to-json": "^3.4.4",
68
- "eslint": "^6.7.2",
69
- "eslint-config-airbnb": "^18.1.0",
70
- "eslint-config-prettier": "^6.11.0",
69
+ "eslint": "^8.57.0",
70
+ "eslint-config-airbnb": "^19.0.4",
71
+ "eslint-config-prettier": "^9.1.0",
71
72
  "eslint-plugin-babel": "^5.3.0",
72
73
  "eslint-plugin-cypress": "^2.10.3",
73
- "eslint-plugin-flowtype": "^4.7.0",
74
- "eslint-plugin-formatjs": "^1.5.4",
75
- "eslint-plugin-import": "^2.20.2",
74
+ "eslint-plugin-flowtype": "^8.0.3",
75
+ "eslint-plugin-formatjs": "^4.13.3",
76
+ "eslint-plugin-import": "^2.26.0",
76
77
  "eslint-plugin-jest": "^23.8.2",
77
78
  "eslint-plugin-jsx-a11y": "^6.2.3",
78
- "eslint-plugin-lodash": "^6.0.0",
79
- "eslint-plugin-prettier": "^3.1.3",
80
- "eslint-plugin-react": "^7.19.0",
81
- "eslint-plugin-react-hooks": "^1.7.0",
79
+ "eslint-plugin-lodash": "^7.4.0",
80
+ "eslint-plugin-prettier": "^5.2.1",
81
+ "eslint-plugin-react": "^7.34.3",
82
+ "eslint-plugin-react-hooks": "^4.6.0",
82
83
  "formik": "^2.1.4",
83
84
  "husky": "^3.1.0",
84
85
  "jest": "^24.9.0",
85
- "jest-canvas-mock": "^2.2.0",
86
+ "jest-canvas-mock": "^2.4.0",
86
87
  "jest-environment-jsdom-sixteen": "^1.0.3",
87
88
  "lint-staged": "^9.5.0",
88
89
  "lodash": "^4.17.15",
89
90
  "mini-css-extract-plugin": "^0.9.0",
90
- "node-sass": "^4.13.1",
91
91
  "npm-run-all": "^4.1.5",
92
92
  "optimize-css-assets-webpack-plugin": "^5.0.3",
93
93
  "postcss-loader": "^3.0.0",
94
94
  "prettier": "^1.19.1",
95
95
  "raw-loader": "^4.0.1",
96
- "react": "^17.0.1",
97
- "react-dom": "^17.0.1",
98
- "react-intl": "^3.12.0",
99
- "react-redux": "^7.2.2",
96
+ "react": "18.3.1",
97
+ "react-dom": "18.3.1",
98
+ "react-intl": "6.4.2",
99
+ "react-redux": "^9.1.2",
100
100
  "react-tether": "1.0.5",
101
101
  "react-textarea-autosize": "^7.1.2",
102
102
  "redux": "^4.0.5",
103
+ "regenerator-runtime": "^0.13.9",
104
+ "sass": "^1.64.1",
103
105
  "sass-loader": "^8.0.2",
104
106
  "scroll-into-view-if-needed": "^2.2.24",
105
107
  "style-loader": "^1.1.4",
@@ -108,11 +110,11 @@
108
110
  "stylelint-config-standard": "^19.0.0",
109
111
  "stylelint-order": "^3.1.1",
110
112
  "tabbable": "^1.1.3",
111
- "typescript": "^3.8.3",
112
- "uglifyjs-webpack-plugin": "^2.2.0",
113
+ "terser-webpack-plugin": "^4.2.3",
114
+ "typescript": "4.9.5",
113
115
  "uuid": "^8.3.1",
114
116
  "wait-on": "^4.0.2",
115
- "webpack": "^4.43.0",
117
+ "webpack": "^4.47.0",
116
118
  "webpack-cli": "^3.3.11",
117
119
  "webpack-dev-server": "^3.10.3",
118
120
  "worker-farm": "^1.7.0"
@@ -121,7 +123,7 @@
121
123
  "build": "yarn setup && yarn build:prod:dist",
122
124
  "build:i18n": "props2es",
123
125
  "build:dev:dist": "LANGUAGE=en-US BABEL_ENV=dev NODE_ENV=dev webpack --config scripts/webpack.config.js --mode development --progress --colors",
124
- "build:prod:dist": "BABEL_ENV=production NODE_ENV=production webpack --config scripts/webpack.config.js --mode production",
126
+ "build:prod:dist": "LANGUAGE=en-US BABEL_ENV=production NODE_ENV=production webpack --config scripts/webpack.config.js --mode production",
125
127
  "clean": "rm -rf dist reports/* i18n/json i18n/*.js",
126
128
  "cy:open": "yarn cy:wait; yarn cypress open",
127
129
  "cy:run": "yarn cy:wait; yarn cypress run --spec test/integration/**/*.test.js",
@@ -153,6 +155,8 @@
153
155
  }
154
156
  },
155
157
  "resolutions": {
156
- "uglify-es": "3.3.4"
158
+ "**/react-intl/**/@types/react": "^18.3.12",
159
+ "**/@types/react": "^18.3.12",
160
+ "**/@types/react-dom": "^18.2.0"
157
161
  }
158
162
  }
@@ -1,8 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-namespace */
2
- declare namespace Intl {
3
- const RelativeTimeFormat: {};
4
- }
5
-
2
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
3
  declare namespace NodeJS {
7
4
  interface Global {
8
5
  window: any;
@@ -1,17 +1,4 @@
1
- @font-face {
2
- font-weight: normal;
3
- font-family: 'Lato';
4
- font-style: normal;
5
- src: local('Lato Regular'), local('Lato-Regular'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Regular.woff2') format('woff2'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Regular.woff') format('woff');
6
- }
7
-
8
- @font-face {
9
- font-weight: bold;
10
- font-family: 'Lato';
11
- font-style: normal;
12
- src: local('Lato Bold'), local('Lato-Bold'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Bold.woff2') format('woff2'), url('https://cdn01.boxcdn.net/fonts/1.0.2/lato/Lato-Bold.woff') format('woff');
13
- }
14
-
1
+ @import '~box-ui-elements/es/elements/common/fonts';
15
2
  @import '~box-ui-elements/es/styles/variables';
16
3
 
17
4
  .ba {
@@ -1,4 +1,4 @@
1
- import * as ReactDOM from 'react-dom';
1
+ import * as ReactDOM from 'react-dom/client';
2
2
  import { IntlShape } from 'react-intl';
3
3
  import { Store } from 'redux';
4
4
  import { applyResinTags } from '../utils/resin';
@@ -28,6 +28,8 @@ export default class BaseManager implements Manager {
28
28
 
29
29
  reactEl: HTMLElement;
30
30
 
31
+ root: ReactDOM.Root | null = null;
32
+
31
33
  constructor({ location = 1, referenceEl, resinTags = {} }: Options) {
32
34
  this.location = location;
33
35
  this.reactEl = this.insert(referenceEl, {
@@ -35,6 +37,8 @@ export default class BaseManager implements Manager {
35
37
  feature: 'annotations',
36
38
  });
37
39
 
40
+ this.root = ReactDOM.createRoot(this.reactEl);
41
+
38
42
  this.decorate();
39
43
  }
40
44
 
@@ -43,11 +47,11 @@ export default class BaseManager implements Manager {
43
47
  }
44
48
 
45
49
  destroy(): void {
46
- ReactDOM.unmountComponentAtNode(this.reactEl);
47
-
48
- const parentEl = this.reactEl.parentNode;
49
- if (parentEl) {
50
- parentEl.removeChild(this.reactEl);
50
+ if (this.root) {
51
+ this.root.unmount();
52
+ }
53
+ if (this.reactEl.parentNode) {
54
+ this.reactEl.parentNode.removeChild(this.reactEl);
51
55
  }
52
56
  }
53
57
 
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import * as ReactDOM from 'react-dom';
2
+ import * as ReactDOM from 'react-dom/client';
3
3
  import { Provider } from 'react-redux';
4
4
  import { Store } from 'redux';
5
5
  import BaseManager from './BaseManager';
@@ -20,11 +20,14 @@ export default class DeselectManager extends BaseManager {
20
20
  }
21
21
 
22
22
  render({ store }: Props): void {
23
- ReactDOM.render(
23
+ if (!this.root) {
24
+ this.root = ReactDOM.createRoot(this.reactEl);
25
+ }
26
+
27
+ this.root.render(
24
28
  <Provider store={store}>
25
29
  <DeselectListener />
26
30
  </Provider>,
27
- this.reactEl,
28
31
  );
29
32
  }
30
33
  }
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import React from 'react';
2
2
  import noop from 'lodash/noop';
3
3
  import { getScrollParent } from './util';
4
4
 
@@ -31,3 +31,21 @@ export default function create(
31
31
  ): Instance {
32
32
  return popper.createPopper(reference, popup, mergeWith({}, defaults, options, merger) as Options);
33
33
  }
34
+
35
+ export function clientBoundingRect(height: number, width: number, x: number, y: number): DOMRect {
36
+ const rect = {
37
+ bottom: y + height,
38
+ height,
39
+ left: x,
40
+ right: x + width,
41
+ top: y,
42
+ width,
43
+ x,
44
+ y,
45
+ };
46
+
47
+ return {
48
+ ...rect,
49
+ toJSON: () => ({ ...rect }),
50
+ };
51
+ }
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import React from 'react';
2
2
  import classNames from 'classnames';
3
3
  import createPopper, { Instance, Options, PopupReference } from './Popper';
4
4
  import './PopupBase.scss';
@@ -1,8 +1,8 @@
1
- import * as React from 'react';
1
+ import React from 'react';
2
2
  import { FormattedMessage } from 'react-intl';
3
3
  import messages from './messages';
4
4
  import PopupBase from './PopupBase';
5
- import { Options, VirtualElement } from './Popper';
5
+ import { clientBoundingRect, Options, VirtualElement } from './Popper';
6
6
  import './PopupCursor.scss';
7
7
 
8
8
  const options: Partial<Options> = {
@@ -18,14 +18,7 @@ const options: Partial<Options> = {
18
18
  };
19
19
 
20
20
  const generateGetBoundingClientRect = (x = 0, y = 0) => {
21
- return () => ({
22
- width: 0,
23
- height: 0,
24
- top: y,
25
- right: x,
26
- bottom: y,
27
- left: x,
28
- });
21
+ return () => clientBoundingRect(0, 0, x, y);
29
22
  };
30
23
 
31
24
  export default function PopupCursor(): JSX.Element {
@@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl';
5
5
  import messages from './messages';
6
6
  import PopupBase from './PopupBase';
7
7
  import useOutsideEvent from '../../common/useOutsideEvent';
8
- import { Options } from './Popper';
8
+ import { clientBoundingRect, Options } from './Popper';
9
9
  import { Shape } from '../../@types/model';
10
10
  import './PopupHighlight.scss';
11
11
 
@@ -50,14 +50,7 @@ export default function PopupHighlight({ onCancel = noop, onSubmit = noop, shape
50
50
  const { height, width, x, y } = shape;
51
51
 
52
52
  const reference = {
53
- getBoundingClientRect: () => ({
54
- bottom: y + height,
55
- height,
56
- left: x,
57
- right: x + width,
58
- top: y,
59
- width,
60
- }),
53
+ getBoundingClientRect: () => clientBoundingRect(height, width, x, y),
61
54
  };
62
55
 
63
56
  const handleKeydownOutside = (event: Event): void => {
@@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl';
4
4
  import messages from './messages';
5
5
  import PopupBase from './PopupBase';
6
6
  import useOutsideEvent from '../../common/useOutsideEvent';
7
- import { Options } from './Popper';
7
+ import { clientBoundingRect, Options } from './Popper';
8
8
  import { Shape } from '../../@types/model';
9
9
  import './PopupHighlightError.scss';
10
10
 
@@ -48,14 +48,7 @@ export default function PopupHighlightError({ onCancel = noop, shape }: Props):
48
48
  const { height, width, x, y } = shape;
49
49
 
50
50
  const reference = {
51
- getBoundingClientRect: () => ({
52
- bottom: y + height,
53
- height,
54
- left: x,
55
- right: x + width,
56
- top: y,
57
- width,
58
- }),
51
+ getBoundingClientRect: () => clientBoundingRect(height, width, x, y),
59
52
  };
60
53
 
61
54
  useOutsideEvent('mousedown', popupRef.current?.popupRef, onCancel);
@@ -1,12 +1,11 @@
1
- import * as React from 'react';
2
- import * as Popper from '@popperjs/core';
3
- import * as ReactRedux from 'react-redux';
1
+ import React from 'react';
2
+ import Popper from '@popperjs/core';
3
+ import { useSelector } from 'react-redux';
4
4
  import { useIntl } from 'react-intl';
5
5
  import FocusTrap from 'box-ui-elements/es/components/focus-trap/FocusTrap';
6
6
  import messages from './messages';
7
7
  import PopupBase from './PopupBase';
8
8
  import ReplyForm from '../ReplyForm';
9
- import usePrevious from '../../common/usePrevious';
10
9
  import { getScale, getRotation } from '../../store/options';
11
10
  import { PopupReference } from './Popper';
12
11
  import './PopupReply.scss';
@@ -89,18 +88,16 @@ export default function PopupReply({
89
88
  const intl = useIntl();
90
89
  const popupRef = React.useRef<PopupBase>(null);
91
90
  const popupOptions = React.useRef<Partial<Popper.Options>>(getOptions()); // Keep the options reference the same between renders
92
- const rotation = ReactRedux.useSelector(getRotation);
93
- const prevRotation = usePrevious(rotation);
94
- const scale = ReactRedux.useSelector(getScale);
95
- const prevScale = usePrevious(scale);
91
+ const rotation = useSelector(getRotation);
92
+ const scale = useSelector(getScale);
96
93
 
97
94
  React.useEffect(() => {
98
95
  const { current: popup } = popupRef;
99
96
 
100
- if (popup?.popper && (rotation !== prevRotation || scale !== prevScale)) {
97
+ if (popup?.popper) {
101
98
  popup.popper.update();
102
99
  }
103
- }, [popupRef, prevRotation, prevScale, rotation, scale]);
100
+ }, [popupRef, rotation, scale]);
104
101
 
105
102
  return (
106
103
  <FocusTrap>
@@ -6,6 +6,11 @@ export default defineMessages({
6
6
  description: 'Aria label description for reply popup',
7
7
  defaultMessage: 'Comment',
8
8
  },
9
+ ariaLabelReplyField: {
10
+ id: 'ba.popup.reply.field',
11
+ description: 'Aria label description for annotation comment field',
12
+ defaultMessage: 'Type a comment',
13
+ },
9
14
  buttonCancel: {
10
15
  id: 'ba.popups.cancel',
11
16
  description: 'Button label for cancelling the creation of a description, comment, or reply',
@@ -6,8 +6,10 @@ import {
6
6
  getActiveMentionForEditorState,
7
7
  } from 'box-ui-elements/es/components/form-elements/draft-js-mention-selector/utils';
8
8
  import { DraftHandleValue, Editor, EditorState } from 'draft-js';
9
+ import { IntlShape } from 'react-intl';
9
10
  import PopupList from '../Popups/PopupList';
10
11
  import { Collaborator } from '../../@types';
12
+ import messages from '../Popups/messages';
11
13
  import { VirtualElement } from '../Popups/Popper';
12
14
  import './ReplyField.scss';
13
15
 
@@ -29,6 +31,7 @@ export type Props = {
29
31
  onChange: (editorState: EditorState) => void;
30
32
  placeholder?: string;
31
33
  setCursorPosition: (cursorPosition: number) => void;
34
+ intl: IntlShape;
32
35
  };
33
36
 
34
37
  export type State = {
@@ -197,13 +200,14 @@ export default class ReplyField extends React.Component<Props, State> {
197
200
  handleMouseDown = (event: React.SyntheticEvent): void => event.preventDefault(); // prevent the blur event so that Editor can remain focus
198
201
 
199
202
  render(): JSX.Element {
200
- const { className, collaborators, editorState, isDisabled, placeholder, ...rest } = this.props;
203
+ const { className, collaborators, intl, editorState, isDisabled, placeholder, ...rest } = this.props;
201
204
  const { activeItemIndex, popupAutoScroll, popupReference } = this.state;
202
205
 
203
206
  return (
204
207
  <div className={classnames(className, 'ba-ReplyField')}>
205
208
  <Editor
206
209
  {...rest}
210
+ ariaLabel={intl.formatMessage(messages.ariaLabelReplyField)}
207
211
  ariaMultiline
208
212
  editorState={editorState}
209
213
  handleReturn={this.handleReturn}
@@ -7,7 +7,7 @@ export type Props = {
7
7
  isDisabled?: boolean;
8
8
  isPrimary?: boolean;
9
9
  onClick?: (event: React.MouseEvent) => void;
10
- type: 'button' | 'submit' | 'reset' | undefined;
10
+ type?: 'button' | 'submit' | 'reset' | undefined;
11
11
  } & HTMLAttributes<HTMLButtonElement>;
12
12
 
13
13
  export default function ReplyButton({ children, isDisabled, isPrimary, onClick = noop, ...rest }: Props): JSX.Element {
@@ -70,12 +70,20 @@ const ReplyForm = (props: Props): JSX.Element => {
70
70
  }, [formRef]); // eslint-disable-line react-hooks/exhaustive-deps
71
71
 
72
72
  return (
73
- <Form ref={formRef} className="ba-ReplyForm" data-testid="ba-ReplyForm">
73
+ <Form
74
+ ref={formRef}
75
+ className="ba-ReplyForm"
76
+ data-testid="ba-ReplyForm"
77
+ onPointerEnterCapture={undefined}
78
+ onPointerLeaveCapture={undefined}
79
+ placeholder={undefined}
80
+ >
74
81
  <div className="ba-Popup-main">
75
82
  <ReplyField
76
83
  className="ba-Popup-field"
77
84
  data-testid="ba-Popup-field"
78
85
  editorState={editorState}
86
+ intl={intl}
79
87
  isDisabled={isPending}
80
88
  onChange={handleChange}
81
89
  placeholder={intl.formatMessage(messages.fieldPlaceholder)}
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import React from 'react';
2
2
  import classNames from 'classnames';
3
3
  import DecoratedDrawingPath from './DecoratedDrawingPath';
4
4
  import DrawingList from './DrawingList';
@@ -35,7 +35,7 @@ export default function DrawingCreator({
35
35
  const drawingPathRef = React.useRef<DrawingPathRef>(null);
36
36
  const drawingSVGRef = React.useRef<DrawingSVGRef>(null);
37
37
  const renderHandleRef = React.useRef<number | null>(null);
38
- const stroke = { color, size };
38
+ const stroke = React.useMemo(() => ({ color, size }), [color, size]);
39
39
 
40
40
  const getPoints = React.useCallback((): Array<Position> => {
41
41
  const { current: creatorEl } = creatorElRef;