@atlaskit/editor-plugin-block-menu 6.0.15 → 6.0.17

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 6.0.17
4
+
5
+ ### Patch Changes
6
+
7
+ - [`2d587fc62431a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2d587fc62431a) -
8
+ [ux] Fix block menu position on move / scroll moved selection back to same position if possible
9
+ - Updated dependencies
10
+
11
+ ## 6.0.16
12
+
13
+ ### Patch Changes
14
+
15
+ - [`0caee373bff2d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0caee373bff2d) -
16
+ Exported additional types to fix typescript portable annotation errors
17
+ - Updated dependencies
18
+
3
19
  ## 6.0.15
4
20
 
5
21
  ### Patch Changes
@@ -18,6 +18,9 @@
18
18
  "../src/**/examples.*"
19
19
  ],
20
20
  "references": [
21
+ {
22
+ "path": "../../../helpers/browser-apis/afm-cc/tsconfig.json"
23
+ },
21
24
  {
22
25
  "path": "../../../design-system/css/afm-cc/tsconfig.json"
23
26
  },
@@ -18,6 +18,9 @@
18
18
  "../src/**/examples.*"
19
19
  ],
20
20
  "references": [
21
+ {
22
+ "path": "../../../helpers/browser-apis/afm-jira/tsconfig.json"
23
+ },
21
24
  {
22
25
  "path": "../../../design-system/css/afm-jira/tsconfig.json"
23
26
  },
@@ -18,6 +18,9 @@
18
18
  "../src/**/examples.*"
19
19
  ],
20
20
  "references": [
21
+ {
22
+ "path": "../../../helpers/browser-apis/afm-products/tsconfig.json"
23
+ },
21
24
  {
22
25
  "path": "../../../design-system/css/afm-products/tsconfig.json"
23
26
  },
@@ -89,7 +89,8 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
89
89
  popupsBoundariesElement = _ref2.popupsBoundariesElement,
90
90
  popupsScrollableElement = _ref2.popupsScrollableElement;
91
91
  return /*#__PURE__*/_react.default.createElement(_blockMenuProvider.BlockMenuProvider, {
92
- api: api
92
+ api: api,
93
+ editorView: editorView
93
94
  }, /*#__PURE__*/_react.default.createElement(_blockMenu.default, {
94
95
  editorView: editorView,
95
96
  api: api,
@@ -10,7 +10,10 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
10
10
  var BlockMenuContext = /*#__PURE__*/(0, _react.createContext)({
11
11
  onDropdownOpenChanged: function onDropdownOpenChanged() {},
12
12
  moveDownRef: /*#__PURE__*/_react.default.createRef(),
13
- moveUpRef: /*#__PURE__*/_react.default.createRef()
13
+ moveUpRef: /*#__PURE__*/_react.default.createRef(),
14
+ getFirstSelectedDomNode: function getFirstSelectedDomNode() {
15
+ return undefined;
16
+ }
14
17
  });
15
18
  var useBlockMenu = exports.useBlockMenu = function useBlockMenu() {
16
19
  var context = (0, _react.useContext)(BlockMenuContext);
@@ -21,9 +24,20 @@ var useBlockMenu = exports.useBlockMenu = function useBlockMenu() {
21
24
  };
22
25
  var BlockMenuProvider = exports.BlockMenuProvider = function BlockMenuProvider(_ref) {
23
26
  var children = _ref.children,
24
- api = _ref.api;
27
+ api = _ref.api,
28
+ editorView = _ref.editorView;
25
29
  var moveUpRef = (0, _react.useRef)(null);
26
30
  var moveDownRef = (0, _react.useRef)(null);
31
+ var getFirstSelectedDomNode = (0, _react.useCallback)(function () {
32
+ var _api$selection;
33
+ var from = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 || (_api$selection = _api$selection.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.from;
34
+ if (from !== undefined) {
35
+ var nodeDOM = editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(from);
36
+ if (nodeDOM instanceof Element) {
37
+ return nodeDOM;
38
+ }
39
+ }
40
+ }, [api, editorView]);
27
41
  var onDropdownOpenChanged = (0, _react.useCallback)(function (isOpen) {
28
42
  if (!isOpen) {
29
43
  // On Dropdown closed, return focus to editor
@@ -40,7 +54,8 @@ var BlockMenuProvider = exports.BlockMenuProvider = function BlockMenuProvider(_
40
54
  value: {
41
55
  onDropdownOpenChanged: onDropdownOpenChanged,
42
56
  moveDownRef: moveDownRef,
43
- moveUpRef: moveUpRef
57
+ moveUpRef: moveUpRef,
58
+ getFirstSelectedDomNode: getFirstSelectedDomNode
44
59
  }
45
60
  }, children);
46
61
  };
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.MoveDownDropdownItem = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
10
  var _reactIntlNext = require("react-intl-next");
11
+ var _browserApis = require("@atlaskit/browser-apis");
11
12
  var _analytics = require("@atlaskit/editor-common/analytics");
12
13
  var _hooks = require("@atlaskit/editor-common/hooks");
13
14
  var _messages = require("@atlaskit/editor-common/messages");
@@ -16,6 +17,7 @@ var _editorToolbar = require("@atlaskit/editor-toolbar");
16
17
  var _arrowDown = _interopRequireDefault(require("@atlaskit/icon/core/arrow-down"));
17
18
  var _blockMenuProvider = require("./block-menu-provider");
18
19
  var _consts = require("./consts");
20
+ var _fixBlockMenuPositionAndScroll = require("./utils/fixBlockMenuPositionAndScroll");
19
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
20
22
  var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
21
23
  var api = _ref.api;
@@ -23,7 +25,8 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
23
25
  formatMessage = _useIntl.formatMessage;
24
26
  var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
25
27
  moveUpRef = _useBlockMenu.moveUpRef,
26
- moveDownRef = _useBlockMenu.moveDownRef;
28
+ moveDownRef = _useBlockMenu.moveDownRef,
29
+ getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode;
27
30
  var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
28
31
  var _blockControlsState$b;
29
32
  var blockControlsState = _ref2.blockControlsState;
@@ -32,8 +35,11 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
32
35
  };
33
36
  }),
34
37
  canMoveDown = _useSharedPluginState.canMoveDown;
38
+
39
+ // Maybe don't need this
35
40
  (0, _react.useEffect)(function () {
36
- if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
41
+ var doc = (0, _browserApis.getDocument)();
42
+ if (!canMoveDown && moveDownRef.current && doc && moveDownRef.current === doc.activeElement && moveUpRef.current) {
37
43
  moveUpRef.current.focus();
38
44
  }
39
45
  }, [canMoveDown, moveUpRef, moveDownRef]);
@@ -55,6 +61,10 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
55
61
  });
56
62
  return tr;
57
63
  });
64
+ requestAnimationFrame(function () {
65
+ var newFirstNode = getFirstSelectedDomNode();
66
+ (0, _fixBlockMenuPositionAndScroll.fixBlockMenuPositionAndScroll)(newFirstNode);
67
+ });
58
68
  };
59
69
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
60
70
  triggerRef: moveDownRef,
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.MoveUpDropdownItem = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
10
  var _reactIntlNext = require("react-intl-next");
11
+ var _browserApis = require("@atlaskit/browser-apis");
11
12
  var _analytics = require("@atlaskit/editor-common/analytics");
12
13
  var _hooks = require("@atlaskit/editor-common/hooks");
13
14
  var _messages = require("@atlaskit/editor-common/messages");
@@ -16,6 +17,7 @@ var _editorToolbar = require("@atlaskit/editor-toolbar");
16
17
  var _arrowUp = _interopRequireDefault(require("@atlaskit/icon/core/arrow-up"));
17
18
  var _blockMenuProvider = require("./block-menu-provider");
18
19
  var _consts = require("./consts");
20
+ var _fixBlockMenuPositionAndScroll = require("./utils/fixBlockMenuPositionAndScroll");
19
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
20
22
  var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
21
23
  var api = _ref.api;
@@ -23,7 +25,8 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
23
25
  formatMessage = _useIntl.formatMessage;
24
26
  var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
25
27
  moveUpRef = _useBlockMenu.moveUpRef,
26
- moveDownRef = _useBlockMenu.moveDownRef;
28
+ moveDownRef = _useBlockMenu.moveDownRef,
29
+ getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode;
27
30
  var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
28
31
  var _blockControlsState$b;
29
32
  var blockControlsState = _ref2.blockControlsState;
@@ -33,7 +36,8 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
33
36
  }),
34
37
  canMoveUp = _useSharedPluginState.canMoveUp;
35
38
  (0, _react.useEffect)(function () {
36
- if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
39
+ var doc = (0, _browserApis.getDocument)();
40
+ if (!canMoveUp && moveUpRef.current && doc && moveUpRef.current === doc.activeElement && moveDownRef.current) {
37
41
  moveDownRef.current.focus();
38
42
  }
39
43
  }, [canMoveUp, moveDownRef, moveUpRef]);
@@ -55,6 +59,10 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
55
59
  });
56
60
  return tr;
57
61
  });
62
+ requestAnimationFrame(function () {
63
+ var newFirstNode = getFirstSelectedDomNode();
64
+ (0, _fixBlockMenuPositionAndScroll.fixBlockMenuPositionAndScroll)(newFirstNode);
65
+ });
58
66
  };
59
67
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
60
68
  triggerRef: moveUpRef,
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.fixBlockMenuPositionAndScroll = void 0;
7
+ var _browserApis = require("@atlaskit/browser-apis");
8
+ var fixBlockMenuPositionAndScroll = exports.fixBlockMenuPositionAndScroll = function fixBlockMenuPositionAndScroll(firstSelectedNode) {
9
+ var doc = (0, _browserApis.getDocument)();
10
+ if (!doc) {
11
+ return;
12
+ }
13
+ var blockMenuEl = doc.querySelector('[data-testid="editor-block-menu"]');
14
+ if (!(blockMenuEl !== null && blockMenuEl !== void 0 && blockMenuEl.parentElement)) {
15
+ return;
16
+ }
17
+ var scrollableContainer = doc.querySelector('[data-testid="editor-content-container"]');
18
+ if (!firstSelectedNode || !scrollableContainer) {
19
+ return;
20
+ }
21
+ var parentElement = blockMenuEl.parentElement;
22
+ var currentTop = parentElement.getBoundingClientRect().top;
23
+ var distance = firstSelectedNode.getBoundingClientRect().top - blockMenuEl.getBoundingClientRect().top;
24
+ scrollableContainer.scrollBy({
25
+ behavior: 'instant',
26
+ top: distance
27
+ });
28
+ var newTop = parentElement.getBoundingClientRect().top;
29
+ var topDifference = currentTop - newTop;
30
+ var hasTopProperty = parentElement.style.top !== '';
31
+ var hasBottomProperty = parentElement.style.bottom !== '';
32
+ if (hasBottomProperty && !hasTopProperty) {
33
+ var currentBottomValue = parseFloat(parentElement.style.bottom || '0');
34
+ parentElement.style.bottom = "".concat(currentBottomValue - topDifference, "px");
35
+ } else {
36
+ var currentTopValue = parseFloat(parentElement.style.top || '0');
37
+ parentElement.style.top = "".concat(currentTopValue + topDifference, "px");
38
+ }
39
+ };
@@ -82,7 +82,8 @@ export const blockMenuPlugin = ({
82
82
  popupsScrollableElement
83
83
  }) {
84
84
  return /*#__PURE__*/React.createElement(BlockMenuProvider, {
85
- api: api
85
+ api: api,
86
+ editorView: editorView
86
87
  }, /*#__PURE__*/React.createElement(BlockMenu, {
87
88
  editorView: editorView,
88
89
  api: api,
@@ -2,7 +2,8 @@ import React, { useCallback, createContext, useContext, useRef } from 'react';
2
2
  const BlockMenuContext = /*#__PURE__*/createContext({
3
3
  onDropdownOpenChanged: () => {},
4
4
  moveDownRef: /*#__PURE__*/React.createRef(),
5
- moveUpRef: /*#__PURE__*/React.createRef()
5
+ moveUpRef: /*#__PURE__*/React.createRef(),
6
+ getFirstSelectedDomNode: () => undefined
6
7
  });
7
8
  export const useBlockMenu = () => {
8
9
  const context = useContext(BlockMenuContext);
@@ -13,10 +14,21 @@ export const useBlockMenu = () => {
13
14
  };
14
15
  export const BlockMenuProvider = ({
15
16
  children,
16
- api
17
+ api,
18
+ editorView
17
19
  }) => {
18
20
  const moveUpRef = useRef(null);
19
21
  const moveDownRef = useRef(null);
22
+ const getFirstSelectedDomNode = useCallback(() => {
23
+ var _api$selection, _api$selection$shared, _api$selection$shared2;
24
+ const from = api === null || api === void 0 ? void 0 : (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : (_api$selection$shared = _api$selection.sharedState.currentState()) === null || _api$selection$shared === void 0 ? void 0 : (_api$selection$shared2 = _api$selection$shared.selection) === null || _api$selection$shared2 === void 0 ? void 0 : _api$selection$shared2.from;
25
+ if (from !== undefined) {
26
+ const nodeDOM = editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(from);
27
+ if (nodeDOM instanceof Element) {
28
+ return nodeDOM;
29
+ }
30
+ }
31
+ }, [api, editorView]);
20
32
  const onDropdownOpenChanged = useCallback(isOpen => {
21
33
  if (!isOpen) {
22
34
  // On Dropdown closed, return focus to editor
@@ -31,7 +43,8 @@ export const BlockMenuProvider = ({
31
43
  value: {
32
44
  onDropdownOpenChanged,
33
45
  moveDownRef,
34
- moveUpRef
46
+ moveUpRef,
47
+ getFirstSelectedDomNode
35
48
  }
36
49
  }, children);
37
50
  };
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import { useIntl, injectIntl } from 'react-intl-next';
3
+ import { getDocument } from '@atlaskit/browser-apis';
3
4
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
5
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
@@ -8,6 +9,7 @@ import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
8
9
  import ArrowDownIcon from '@atlaskit/icon/core/arrow-down';
9
10
  import { useBlockMenu } from './block-menu-provider';
10
11
  import { BLOCK_MENU_ITEM_NAME } from './consts';
12
+ import { fixBlockMenuPositionAndScroll } from './utils/fixBlockMenuPositionAndScroll';
11
13
  const MoveDownDropdownItemContent = ({
12
14
  api
13
15
  }) => {
@@ -16,7 +18,8 @@ const MoveDownDropdownItemContent = ({
16
18
  } = useIntl();
17
19
  const {
18
20
  moveUpRef,
19
- moveDownRef
21
+ moveDownRef,
22
+ getFirstSelectedDomNode
20
23
  } = useBlockMenu();
21
24
  const {
22
25
  canMoveDown
@@ -28,8 +31,11 @@ const MoveDownDropdownItemContent = ({
28
31
  canMoveDown: blockControlsState === null || blockControlsState === void 0 ? void 0 : (_blockControlsState$b = blockControlsState.blockMenuOptions) === null || _blockControlsState$b === void 0 ? void 0 : _blockControlsState$b.canMoveDown
29
32
  };
30
33
  });
34
+
35
+ // Maybe don't need this
31
36
  useEffect(() => {
32
- if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
37
+ const doc = getDocument();
38
+ if (!canMoveDown && moveDownRef.current && doc && moveDownRef.current === doc.activeElement && moveUpRef.current) {
33
39
  moveUpRef.current.focus();
34
40
  }
35
41
  }, [canMoveDown, moveUpRef, moveDownRef]);
@@ -52,6 +58,10 @@ const MoveDownDropdownItemContent = ({
52
58
  });
53
59
  return tr;
54
60
  });
61
+ requestAnimationFrame(() => {
62
+ const newFirstNode = getFirstSelectedDomNode();
63
+ fixBlockMenuPositionAndScroll(newFirstNode);
64
+ });
55
65
  };
56
66
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
57
67
  triggerRef: moveDownRef,
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import { useIntl, injectIntl } from 'react-intl-next';
3
+ import { getDocument } from '@atlaskit/browser-apis';
3
4
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
5
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
@@ -8,6 +9,7 @@ import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
8
9
  import ArrowUpIcon from '@atlaskit/icon/core/arrow-up';
9
10
  import { useBlockMenu } from './block-menu-provider';
10
11
  import { BLOCK_MENU_ITEM_NAME } from './consts';
12
+ import { fixBlockMenuPositionAndScroll } from './utils/fixBlockMenuPositionAndScroll';
11
13
  const MoveUpDropdownItemContent = ({
12
14
  api
13
15
  }) => {
@@ -16,7 +18,8 @@ const MoveUpDropdownItemContent = ({
16
18
  } = useIntl();
17
19
  const {
18
20
  moveUpRef,
19
- moveDownRef
21
+ moveDownRef,
22
+ getFirstSelectedDomNode
20
23
  } = useBlockMenu();
21
24
  const {
22
25
  canMoveUp
@@ -29,7 +32,8 @@ const MoveUpDropdownItemContent = ({
29
32
  };
30
33
  });
31
34
  useEffect(() => {
32
- if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
35
+ const doc = getDocument();
36
+ if (!canMoveUp && moveUpRef.current && doc && moveUpRef.current === doc.activeElement && moveDownRef.current) {
33
37
  moveDownRef.current.focus();
34
38
  }
35
39
  }, [canMoveUp, moveDownRef, moveUpRef]);
@@ -52,6 +56,10 @@ const MoveUpDropdownItemContent = ({
52
56
  });
53
57
  return tr;
54
58
  });
59
+ requestAnimationFrame(() => {
60
+ const newFirstNode = getFirstSelectedDomNode();
61
+ fixBlockMenuPositionAndScroll(newFirstNode);
62
+ });
55
63
  };
56
64
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
57
65
  triggerRef: moveUpRef,
@@ -0,0 +1,33 @@
1
+ import { getDocument } from '@atlaskit/browser-apis';
2
+ export const fixBlockMenuPositionAndScroll = firstSelectedNode => {
3
+ const doc = getDocument();
4
+ if (!doc) {
5
+ return;
6
+ }
7
+ const blockMenuEl = doc.querySelector('[data-testid="editor-block-menu"]');
8
+ if (!(blockMenuEl !== null && blockMenuEl !== void 0 && blockMenuEl.parentElement)) {
9
+ return;
10
+ }
11
+ const scrollableContainer = doc.querySelector('[data-testid="editor-content-container"]');
12
+ if (!firstSelectedNode || !scrollableContainer) {
13
+ return;
14
+ }
15
+ const parentElement = blockMenuEl.parentElement;
16
+ const currentTop = parentElement.getBoundingClientRect().top;
17
+ const distance = firstSelectedNode.getBoundingClientRect().top - blockMenuEl.getBoundingClientRect().top;
18
+ scrollableContainer.scrollBy({
19
+ behavior: 'instant',
20
+ top: distance
21
+ });
22
+ const newTop = parentElement.getBoundingClientRect().top;
23
+ const topDifference = currentTop - newTop;
24
+ const hasTopProperty = parentElement.style.top !== '';
25
+ const hasBottomProperty = parentElement.style.bottom !== '';
26
+ if (hasBottomProperty && !hasTopProperty) {
27
+ const currentBottomValue = parseFloat(parentElement.style.bottom || '0');
28
+ parentElement.style.bottom = `${currentBottomValue - topDifference}px`;
29
+ } else {
30
+ const currentTopValue = parseFloat(parentElement.style.top || '0');
31
+ parentElement.style.top = `${currentTopValue + topDifference}px`;
32
+ }
33
+ };
@@ -82,7 +82,8 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
82
82
  popupsBoundariesElement = _ref2.popupsBoundariesElement,
83
83
  popupsScrollableElement = _ref2.popupsScrollableElement;
84
84
  return /*#__PURE__*/React.createElement(BlockMenuProvider, {
85
- api: api
85
+ api: api,
86
+ editorView: editorView
86
87
  }, /*#__PURE__*/React.createElement(BlockMenu, {
87
88
  editorView: editorView,
88
89
  api: api,
@@ -2,7 +2,10 @@ import React, { useCallback, createContext, useContext, useRef } from 'react';
2
2
  var BlockMenuContext = /*#__PURE__*/createContext({
3
3
  onDropdownOpenChanged: function onDropdownOpenChanged() {},
4
4
  moveDownRef: /*#__PURE__*/React.createRef(),
5
- moveUpRef: /*#__PURE__*/React.createRef()
5
+ moveUpRef: /*#__PURE__*/React.createRef(),
6
+ getFirstSelectedDomNode: function getFirstSelectedDomNode() {
7
+ return undefined;
8
+ }
6
9
  });
7
10
  export var useBlockMenu = function useBlockMenu() {
8
11
  var context = useContext(BlockMenuContext);
@@ -13,9 +16,20 @@ export var useBlockMenu = function useBlockMenu() {
13
16
  };
14
17
  export var BlockMenuProvider = function BlockMenuProvider(_ref) {
15
18
  var children = _ref.children,
16
- api = _ref.api;
19
+ api = _ref.api,
20
+ editorView = _ref.editorView;
17
21
  var moveUpRef = useRef(null);
18
22
  var moveDownRef = useRef(null);
23
+ var getFirstSelectedDomNode = useCallback(function () {
24
+ var _api$selection;
25
+ var from = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 || (_api$selection = _api$selection.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.from;
26
+ if (from !== undefined) {
27
+ var nodeDOM = editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(from);
28
+ if (nodeDOM instanceof Element) {
29
+ return nodeDOM;
30
+ }
31
+ }
32
+ }, [api, editorView]);
19
33
  var onDropdownOpenChanged = useCallback(function (isOpen) {
20
34
  if (!isOpen) {
21
35
  // On Dropdown closed, return focus to editor
@@ -32,7 +46,8 @@ export var BlockMenuProvider = function BlockMenuProvider(_ref) {
32
46
  value: {
33
47
  onDropdownOpenChanged: onDropdownOpenChanged,
34
48
  moveDownRef: moveDownRef,
35
- moveUpRef: moveUpRef
49
+ moveUpRef: moveUpRef,
50
+ getFirstSelectedDomNode: getFirstSelectedDomNode
36
51
  }
37
52
  }, children);
38
53
  };
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import { useIntl, injectIntl } from 'react-intl-next';
3
+ import { getDocument } from '@atlaskit/browser-apis';
3
4
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
5
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
@@ -8,13 +9,15 @@ import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
8
9
  import ArrowDownIcon from '@atlaskit/icon/core/arrow-down';
9
10
  import { useBlockMenu } from './block-menu-provider';
10
11
  import { BLOCK_MENU_ITEM_NAME } from './consts';
12
+ import { fixBlockMenuPositionAndScroll } from './utils/fixBlockMenuPositionAndScroll';
11
13
  var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
12
14
  var api = _ref.api;
13
15
  var _useIntl = useIntl(),
14
16
  formatMessage = _useIntl.formatMessage;
15
17
  var _useBlockMenu = useBlockMenu(),
16
18
  moveUpRef = _useBlockMenu.moveUpRef,
17
- moveDownRef = _useBlockMenu.moveDownRef;
19
+ moveDownRef = _useBlockMenu.moveDownRef,
20
+ getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode;
18
21
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls'], function (_ref2) {
19
22
  var _blockControlsState$b;
20
23
  var blockControlsState = _ref2.blockControlsState;
@@ -23,8 +26,11 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
23
26
  };
24
27
  }),
25
28
  canMoveDown = _useSharedPluginState.canMoveDown;
29
+
30
+ // Maybe don't need this
26
31
  useEffect(function () {
27
- if (!canMoveDown && moveDownRef.current && moveDownRef.current === document.activeElement && moveUpRef.current) {
32
+ var doc = getDocument();
33
+ if (!canMoveDown && moveDownRef.current && doc && moveDownRef.current === doc.activeElement && moveUpRef.current) {
28
34
  moveUpRef.current.focus();
29
35
  }
30
36
  }, [canMoveDown, moveUpRef, moveDownRef]);
@@ -46,6 +52,10 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
46
52
  });
47
53
  return tr;
48
54
  });
55
+ requestAnimationFrame(function () {
56
+ var newFirstNode = getFirstSelectedDomNode();
57
+ fixBlockMenuPositionAndScroll(newFirstNode);
58
+ });
49
59
  };
50
60
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
51
61
  triggerRef: moveDownRef,
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import { useIntl, injectIntl } from 'react-intl-next';
3
+ import { getDocument } from '@atlaskit/browser-apis';
3
4
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
5
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
@@ -8,13 +9,15 @@ import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
8
9
  import ArrowUpIcon from '@atlaskit/icon/core/arrow-up';
9
10
  import { useBlockMenu } from './block-menu-provider';
10
11
  import { BLOCK_MENU_ITEM_NAME } from './consts';
12
+ import { fixBlockMenuPositionAndScroll } from './utils/fixBlockMenuPositionAndScroll';
11
13
  var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
12
14
  var api = _ref.api;
13
15
  var _useIntl = useIntl(),
14
16
  formatMessage = _useIntl.formatMessage;
15
17
  var _useBlockMenu = useBlockMenu(),
16
18
  moveUpRef = _useBlockMenu.moveUpRef,
17
- moveDownRef = _useBlockMenu.moveDownRef;
19
+ moveDownRef = _useBlockMenu.moveDownRef,
20
+ getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode;
18
21
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls'], function (_ref2) {
19
22
  var _blockControlsState$b;
20
23
  var blockControlsState = _ref2.blockControlsState;
@@ -24,7 +27,8 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
24
27
  }),
25
28
  canMoveUp = _useSharedPluginState.canMoveUp;
26
29
  useEffect(function () {
27
- if (!canMoveUp && moveUpRef.current && moveUpRef.current === document.activeElement && moveDownRef.current) {
30
+ var doc = getDocument();
31
+ if (!canMoveUp && moveUpRef.current && doc && moveUpRef.current === doc.activeElement && moveDownRef.current) {
28
32
  moveDownRef.current.focus();
29
33
  }
30
34
  }, [canMoveUp, moveDownRef, moveUpRef]);
@@ -46,6 +50,10 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
46
50
  });
47
51
  return tr;
48
52
  });
53
+ requestAnimationFrame(function () {
54
+ var newFirstNode = getFirstSelectedDomNode();
55
+ fixBlockMenuPositionAndScroll(newFirstNode);
56
+ });
49
57
  };
50
58
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
51
59
  triggerRef: moveUpRef,
@@ -0,0 +1,33 @@
1
+ import { getDocument } from '@atlaskit/browser-apis';
2
+ export var fixBlockMenuPositionAndScroll = function fixBlockMenuPositionAndScroll(firstSelectedNode) {
3
+ var doc = getDocument();
4
+ if (!doc) {
5
+ return;
6
+ }
7
+ var blockMenuEl = doc.querySelector('[data-testid="editor-block-menu"]');
8
+ if (!(blockMenuEl !== null && blockMenuEl !== void 0 && blockMenuEl.parentElement)) {
9
+ return;
10
+ }
11
+ var scrollableContainer = doc.querySelector('[data-testid="editor-content-container"]');
12
+ if (!firstSelectedNode || !scrollableContainer) {
13
+ return;
14
+ }
15
+ var parentElement = blockMenuEl.parentElement;
16
+ var currentTop = parentElement.getBoundingClientRect().top;
17
+ var distance = firstSelectedNode.getBoundingClientRect().top - blockMenuEl.getBoundingClientRect().top;
18
+ scrollableContainer.scrollBy({
19
+ behavior: 'instant',
20
+ top: distance
21
+ });
22
+ var newTop = parentElement.getBoundingClientRect().top;
23
+ var topDifference = currentTop - newTop;
24
+ var hasTopProperty = parentElement.style.top !== '';
25
+ var hasBottomProperty = parentElement.style.bottom !== '';
26
+ if (hasBottomProperty && !hasTopProperty) {
27
+ var currentBottomValue = parseFloat(parentElement.style.bottom || '0');
28
+ parentElement.style.bottom = "".concat(currentBottomValue - topDifference, "px");
29
+ } else {
30
+ var currentTopValue = parseFloat(parentElement.style.top || '0');
31
+ parentElement.style.top = "".concat(currentTopValue + topDifference, "px");
32
+ }
33
+ };
@@ -1,3 +1,3 @@
1
1
  export { blockMenuPlugin } from './blockMenuPlugin';
2
2
  export type { BlockMenuPlugin, RegisterBlockMenuComponent, Parent, BlockMenuPluginOptions, BlockMenuSharedState, } from './blockMenuPluginType';
3
- export type { TransformNodeMetadata } from './editor-commands/transforms/types';
3
+ export type { TransformNodeMetadata, FormatNodeAnalyticsAttrs, TransfromNodeTargetType, FormatNodeTargetType, } from './editor-commands/transforms/types';
@@ -1,12 +1,15 @@
1
1
  import React from 'react';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
3
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
4
5
  export type Direction = 'moveUp' | 'moveDown';
5
6
  type BlockMenuProviderProps = {
6
7
  api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
8
  children: React.ReactNode;
9
+ editorView: EditorView | undefined;
8
10
  };
9
11
  export type BlockMenuContextType = {
12
+ getFirstSelectedDomNode: () => Element | undefined;
10
13
  moveDownRef: React.MutableRefObject<HTMLButtonElement | null>;
11
14
  moveUpRef: React.MutableRefObject<HTMLButtonElement | null>;
12
15
  /**
@@ -17,5 +20,5 @@ export type BlockMenuContextType = {
17
20
  onDropdownOpenChanged: (isOpen: boolean) => void;
18
21
  };
19
22
  export declare const useBlockMenu: () => BlockMenuContextType;
20
- export declare const BlockMenuProvider: ({ children, api }: BlockMenuProviderProps) => React.JSX.Element;
23
+ export declare const BlockMenuProvider: ({ children, api, editorView, }: BlockMenuProviderProps) => React.JSX.Element;
21
24
  export {};
@@ -0,0 +1 @@
1
+ export declare const fixBlockMenuPositionAndScroll: (firstSelectedNode: Element | undefined) => void;
@@ -1,3 +1,3 @@
1
1
  export { blockMenuPlugin } from './blockMenuPlugin';
2
2
  export type { BlockMenuPlugin, RegisterBlockMenuComponent, Parent, BlockMenuPluginOptions, BlockMenuSharedState, } from './blockMenuPluginType';
3
- export type { TransformNodeMetadata } from './editor-commands/transforms/types';
3
+ export type { TransformNodeMetadata, FormatNodeAnalyticsAttrs, TransfromNodeTargetType, FormatNodeTargetType, } from './editor-commands/transforms/types';
@@ -1,12 +1,15 @@
1
1
  import React from 'react';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
3
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
4
5
  export type Direction = 'moveUp' | 'moveDown';
5
6
  type BlockMenuProviderProps = {
6
7
  api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
8
  children: React.ReactNode;
9
+ editorView: EditorView | undefined;
8
10
  };
9
11
  export type BlockMenuContextType = {
12
+ getFirstSelectedDomNode: () => Element | undefined;
10
13
  moveDownRef: React.MutableRefObject<HTMLButtonElement | null>;
11
14
  moveUpRef: React.MutableRefObject<HTMLButtonElement | null>;
12
15
  /**
@@ -17,5 +20,5 @@ export type BlockMenuContextType = {
17
20
  onDropdownOpenChanged: (isOpen: boolean) => void;
18
21
  };
19
22
  export declare const useBlockMenu: () => BlockMenuContextType;
20
- export declare const BlockMenuProvider: ({ children, api }: BlockMenuProviderProps) => React.JSX.Element;
23
+ export declare const BlockMenuProvider: ({ children, api, editorView, }: BlockMenuProviderProps) => React.JSX.Element;
21
24
  export {};
@@ -0,0 +1 @@
1
+ export declare const fixBlockMenuPositionAndScroll: (firstSelectedNode: Element | undefined) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "6.0.15",
3
+ "version": "6.0.17",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,6 +28,7 @@
28
28
  "sideEffects": false,
29
29
  "atlaskit:src": "src/index.ts",
30
30
  "dependencies": {
31
+ "@atlaskit/browser-apis": "^0.0.1",
31
32
  "@atlaskit/css": "^0.19.0",
32
33
  "@atlaskit/dropdown-menu": "^16.4.0",
33
34
  "@atlaskit/editor-plugin-analytics": "^7.0.0",
@@ -43,13 +44,13 @@
43
44
  "@atlaskit/icon": "^29.4.0",
44
45
  "@atlaskit/platform-feature-flags": "^1.1.0",
45
46
  "@atlaskit/platform-feature-flags-react": "^0.4.0",
46
- "@atlaskit/primitives": "^17.0.0",
47
- "@atlaskit/tmp-editor-statsig": "^16.15.0",
47
+ "@atlaskit/primitives": "^17.1.0",
48
+ "@atlaskit/tmp-editor-statsig": "^16.23.0",
48
49
  "@atlaskit/tokens": "^9.1.0",
49
50
  "@babel/runtime": "^7.0.0"
50
51
  },
51
52
  "peerDependencies": {
52
- "@atlaskit/editor-common": "^111.7.0",
53
+ "@atlaskit/editor-common": "^111.8.0",
53
54
  "react": "^18.2.0",
54
55
  "react-intl-next": "npm:react-intl@^5.18.1"
55
56
  },