@atlaskit/editor-plugin-block-menu 15.0.11 → 15.0.13
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 +17 -0
- package/dist/cjs/ui/block-menu-provider.js +71 -10
- package/dist/cjs/ui/block-menu.js +22 -1
- package/dist/cjs/ui/move-down.js +7 -5
- package/dist/cjs/ui/move-up.js +7 -5
- package/dist/cjs/ui/utils/fixBlockMenuPositionAndScroll.js +218 -5
- package/dist/es2019/ui/block-menu-provider.js +67 -10
- package/dist/es2019/ui/block-menu.js +20 -1
- package/dist/es2019/ui/move-down.js +8 -6
- package/dist/es2019/ui/move-up.js +8 -6
- package/dist/es2019/ui/utils/fixBlockMenuPositionAndScroll.js +213 -4
- package/dist/esm/ui/block-menu-provider.js +71 -10
- package/dist/esm/ui/block-menu.js +22 -1
- package/dist/esm/ui/move-down.js +8 -6
- package/dist/esm/ui/move-up.js +8 -6
- package/dist/esm/ui/utils/fixBlockMenuPositionAndScroll.js +216 -4
- package/dist/types/ui/block-menu-provider.d.ts +13 -0
- package/dist/types/ui/utils/fixBlockMenuPositionAndScroll.d.ts +55 -1
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-menu
|
|
2
2
|
|
|
3
|
+
## 15.0.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 15.0.12
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`91559dfb45b53`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/91559dfb45b53) -
|
|
14
|
+
Behind platform_editor_blocks_patch_8, make the block menu popup conditionally sticky after Move
|
|
15
|
+
up / Move down: the editor no longer scrolls while the moved block's drag handle stays visible,
|
|
16
|
+
and scrolls by the minimum needed to bring the drag handle, block and popup back into view -
|
|
17
|
+
realigning the popup to it - when the handle crosses a fold. The scroll distance accounts for the
|
|
18
|
+
popup's own height, so a popup taller than the moved block is no longer cut off at the fold.
|
|
19
|
+
|
|
3
20
|
## 15.0.11
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.useBlockMenu = exports.BlockMenuProvider = void 0;
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
10
|
+
var _fixBlockMenuPositionAndScroll = require("./utils/fixBlockMenuPositionAndScroll");
|
|
9
11
|
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); }
|
|
10
12
|
var BlockMenuContext = /*#__PURE__*/(0, _react.createContext)({
|
|
11
13
|
onDropdownOpenChanged: function onDropdownOpenChanged() {},
|
|
@@ -13,6 +15,15 @@ var BlockMenuContext = /*#__PURE__*/(0, _react.createContext)({
|
|
|
13
15
|
moveUpRef: /*#__PURE__*/_react.default.createRef(),
|
|
14
16
|
getFirstSelectedDomNode: function getFirstSelectedDomNode() {
|
|
15
17
|
return undefined;
|
|
18
|
+
},
|
|
19
|
+
getMovedBlockDomNode: function getMovedBlockDomNode() {
|
|
20
|
+
return undefined;
|
|
21
|
+
},
|
|
22
|
+
getSelectedBlockDomNode: function getSelectedBlockDomNode() {
|
|
23
|
+
return undefined;
|
|
24
|
+
},
|
|
25
|
+
anchorMetricsRef: {
|
|
26
|
+
current: undefined
|
|
16
27
|
}
|
|
17
28
|
});
|
|
18
29
|
var useBlockMenu = exports.useBlockMenu = function useBlockMenu() {
|
|
@@ -28,6 +39,7 @@ var BlockMenuProvider = exports.BlockMenuProvider = function BlockMenuProvider(_
|
|
|
28
39
|
editorView = _ref.editorView;
|
|
29
40
|
var moveUpRef = (0, _react.useRef)(null);
|
|
30
41
|
var moveDownRef = (0, _react.useRef)(null);
|
|
42
|
+
var anchorMetricsRef = (0, _react.useRef)(undefined);
|
|
31
43
|
var getFirstSelectedDomNode = (0, _react.useCallback)(function () {
|
|
32
44
|
var _api$selection;
|
|
33
45
|
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;
|
|
@@ -38,25 +50,74 @@ var BlockMenuProvider = exports.BlockMenuProvider = function BlockMenuProvider(_
|
|
|
38
50
|
}
|
|
39
51
|
}
|
|
40
52
|
}, [api, editorView]);
|
|
53
|
+
var getTopLevelBlockDomNodeAt = (0, _react.useCallback)(function (from) {
|
|
54
|
+
if (!editorView) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
var nodeDOM = editorView.nodeDOM(from);
|
|
58
|
+
var domAtPos = nodeDOM instanceof Element ? nodeDOM : editorView.domAtPos(from).node;
|
|
59
|
+
var element = domAtPos instanceof Element ? domAtPos : domAtPos.parentElement;
|
|
60
|
+
if (!element || !editorView.dom.contains(element)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
var block = element;
|
|
64
|
+
while (block.parentElement && block.parentElement !== editorView.dom) {
|
|
65
|
+
block = block.parentElement;
|
|
66
|
+
}
|
|
67
|
+
return block;
|
|
68
|
+
}, [editorView]);
|
|
69
|
+
var getSelectedBlockDomNode = (0, _react.useCallback)(function () {
|
|
70
|
+
var _api$blockControls, _ref2, _blockControlsState$a, _blockControlsState$a2, _blockControlsState$m, _blockControlsState$p;
|
|
71
|
+
var blockControlsState = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState();
|
|
72
|
+
// The editor selection is not necessarily in the block the menu was opened for.
|
|
73
|
+
var from = (_ref2 = (_blockControlsState$a = blockControlsState === null || blockControlsState === void 0 || (_blockControlsState$a2 = blockControlsState.activeNode) === null || _blockControlsState$a2 === void 0 ? void 0 : _blockControlsState$a2.pos) !== null && _blockControlsState$a !== void 0 ? _blockControlsState$a : blockControlsState === null || blockControlsState === void 0 || (_blockControlsState$m = blockControlsState.menuTriggerByNode) === null || _blockControlsState$m === void 0 ? void 0 : _blockControlsState$m.pos) !== null && _ref2 !== void 0 ? _ref2 : blockControlsState === null || blockControlsState === void 0 || (_blockControlsState$p = blockControlsState.preservedSelection) === null || _blockControlsState$p === void 0 ? void 0 : _blockControlsState$p.from;
|
|
74
|
+
return from === undefined ? undefined : getTopLevelBlockDomNodeAt(from);
|
|
75
|
+
}, [api, getTopLevelBlockDomNodeAt]);
|
|
76
|
+
var getMovedBlockDomNode = (0, _react.useCallback)(function () {
|
|
77
|
+
// A move transaction maps its preserved selection onto the node it just moved, so this is
|
|
78
|
+
// where that node ended up - unlike the block menu state, which keeps stale positions.
|
|
79
|
+
var from = editorView === null || editorView === void 0 ? void 0 : editorView.state.selection.from;
|
|
80
|
+
return from === undefined ? undefined : getTopLevelBlockDomNodeAt(from);
|
|
81
|
+
}, [editorView, getTopLevelBlockDomNodeAt]);
|
|
41
82
|
var onDropdownOpenChanged = (0, _react.useCallback)(function (isOpen) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
83
|
+
anchorMetricsRef.current = undefined;
|
|
84
|
+
if (isOpen) {
|
|
85
|
+
if ((0, _fg.fg)('platform_editor_blocks_patch_8')) {
|
|
86
|
+
// The popup lays itself out next to the drag handle over the next frame or two.
|
|
87
|
+
var remainingFrames = 3;
|
|
88
|
+
var _captureAnchorMetrics = function captureAnchorMetrics() {
|
|
89
|
+
requestAnimationFrame(function () {
|
|
90
|
+
anchorMetricsRef.current = (0, _fixBlockMenuPositionAndScroll.getBlockMenuAnchorMetrics)(getSelectedBlockDomNode());
|
|
91
|
+
remainingFrames -= 1;
|
|
92
|
+
if (!anchorMetricsRef.current && remainingFrames > 0) {
|
|
93
|
+
_captureAnchorMetrics();
|
|
94
|
+
}
|
|
48
95
|
});
|
|
49
|
-
}
|
|
50
|
-
|
|
96
|
+
};
|
|
97
|
+
_captureAnchorMetrics();
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
51
100
|
}
|
|
52
|
-
|
|
101
|
+
|
|
102
|
+
// On Dropdown closed, return focus to editor
|
|
103
|
+
setTimeout(function () {
|
|
104
|
+
return requestAnimationFrame(function () {
|
|
105
|
+
api === null || api === void 0 || api.core.actions.focus({
|
|
106
|
+
scrollIntoView: false
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}, 1);
|
|
110
|
+
}, [api, getSelectedBlockDomNode]);
|
|
53
111
|
return /*#__PURE__*/_react.default.createElement(BlockMenuContext.Provider, {
|
|
54
112
|
// eslint-disable-next-line @atlassian/perf-linting/no-inline-context-value, @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
55
113
|
value: {
|
|
56
114
|
onDropdownOpenChanged: onDropdownOpenChanged,
|
|
57
115
|
moveDownRef: moveDownRef,
|
|
58
116
|
moveUpRef: moveUpRef,
|
|
59
|
-
getFirstSelectedDomNode: getFirstSelectedDomNode
|
|
117
|
+
getFirstSelectedDomNode: getFirstSelectedDomNode,
|
|
118
|
+
getMovedBlockDomNode: getMovedBlockDomNode,
|
|
119
|
+
getSelectedBlockDomNode: getSelectedBlockDomNode,
|
|
120
|
+
anchorMetricsRef: anchorMetricsRef
|
|
60
121
|
}
|
|
61
122
|
}, children);
|
|
62
123
|
};
|
|
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
9
9
|
exports.default = void 0;
|
|
10
10
|
require("./block-menu.compiled.css");
|
|
11
11
|
var _runtime = require("@compiled/react/runtime");
|
|
12
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
12
13
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
14
|
var _react = _interopRequireWildcard(require("react"));
|
|
14
15
|
var _reactIntl = require("react-intl");
|
|
@@ -33,6 +34,8 @@ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
|
33
34
|
var _blockMenuProvider = require("./block-menu-provider");
|
|
34
35
|
var _BlockMenuRenderer = require("./block-menu-renderer/BlockMenuRenderer");
|
|
35
36
|
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); }
|
|
37
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
38
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
36
39
|
var styles = {
|
|
37
40
|
base: "_2rko12b0 _bfhk1bhr _16qs130s",
|
|
38
41
|
maxWidthStyles: "_p12fnklw",
|
|
@@ -266,8 +269,9 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
266
269
|
if (!isMenuOpen) {
|
|
267
270
|
return;
|
|
268
271
|
}
|
|
272
|
+
onDropdownOpenChanged(true);
|
|
269
273
|
setMenuHeight(((_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.clientHeight) || FALLBACK_MENU_HEIGHT);
|
|
270
|
-
}, [isMenuOpen]);
|
|
274
|
+
}, [isMenuOpen, onDropdownOpenChanged]);
|
|
271
275
|
var hasFocus = (_ref8 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) ||
|
|
272
276
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
273
277
|
document.activeElement === targetHandleRef || popupRef.current && (
|
|
@@ -356,6 +360,23 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
356
360
|
stick: true
|
|
357
361
|
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
358
362
|
,
|
|
363
|
+
onPositionCalculated: (0, _fg.fg)('platform_editor_blocks_patch_8') ? function (position) {
|
|
364
|
+
if (position.left === undefined) {
|
|
365
|
+
// Already placed on the gutter side (using `right`) - nothing to correct.
|
|
366
|
+
return position;
|
|
367
|
+
}
|
|
368
|
+
// Popup prefers whichever side has more room, which flips the menu onto the
|
|
369
|
+
// content side when the gutter is too narrow to fit it. Force it back onto the
|
|
370
|
+
// gutter side instead - it can still overlap the content once there, but it
|
|
371
|
+
// must not start on top of the node. `position.left` is shifted by the same
|
|
372
|
+
// distance regardless of the offset parent/scroll it was calculated against,
|
|
373
|
+
// since that just moves both by the same amount.
|
|
374
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
375
|
+
left: position.left - DEFAULT_MENU_WIDTH - _styles.DRAG_HANDLE_WIDTH - 2 * DRAG_HANDLE_OFFSET_PADDING
|
|
376
|
+
});
|
|
377
|
+
} : undefined
|
|
378
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
379
|
+
,
|
|
359
380
|
offset: [_styles.DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
360
381
|
focusTrap: openedViaKeyboard ?
|
|
361
382
|
// Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
|
package/dist/cjs/ui/move-down.js
CHANGED
|
@@ -16,6 +16,7 @@ var _messages = require("@atlaskit/editor-common/messages");
|
|
|
16
16
|
var _types = require("@atlaskit/editor-common/types");
|
|
17
17
|
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
18
18
|
var _arrowDown = _interopRequireDefault(require("@atlaskit/icon/core/arrow-down"));
|
|
19
|
+
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
19
20
|
var _blockMenuProvider = require("./block-menu-provider");
|
|
20
21
|
var _consts = require("./consts");
|
|
21
22
|
var _fixBlockMenuPositionAndScroll = require("./utils/fixBlockMenuPositionAndScroll");
|
|
@@ -27,7 +28,10 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
27
28
|
var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
|
|
28
29
|
moveUpRef = _useBlockMenu.moveUpRef,
|
|
29
30
|
moveDownRef = _useBlockMenu.moveDownRef,
|
|
30
|
-
getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode
|
|
31
|
+
getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode,
|
|
32
|
+
getMovedBlockDomNode = _useBlockMenu.getMovedBlockDomNode,
|
|
33
|
+
getSelectedBlockDomNode = _useBlockMenu.getSelectedBlockDomNode,
|
|
34
|
+
anchorMetricsRef = _useBlockMenu.anchorMetricsRef;
|
|
31
35
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
|
|
32
36
|
var _blockControlsState$b;
|
|
33
37
|
var blockControlsState = _ref2.blockControlsState;
|
|
@@ -45,6 +49,7 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
45
49
|
}
|
|
46
50
|
}, [canMoveDown, moveUpRef, moveDownRef]);
|
|
47
51
|
var handleClick = function handleClick() {
|
|
52
|
+
var positionSnapshot = (0, _fg.fg)('platform_editor_blocks_patch_8') ? (0, _fixBlockMenuPositionAndScroll.getBlockMenuPositionSnapshot)(getSelectedBlockDomNode(), anchorMetricsRef.current) : undefined;
|
|
48
53
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
49
54
|
var _api$analytics, _api$blockControls;
|
|
50
55
|
var tr = _ref3.tr;
|
|
@@ -62,10 +67,7 @@ var MoveDownDropdownItemContent = function MoveDownDropdownItemContent(_ref) {
|
|
|
62
67
|
});
|
|
63
68
|
return tr;
|
|
64
69
|
});
|
|
65
|
-
|
|
66
|
-
var newFirstNode = getFirstSelectedDomNode();
|
|
67
|
-
(0, _fixBlockMenuPositionAndScroll.fixBlockMenuPositionAndScroll)(newFirstNode);
|
|
68
|
-
});
|
|
70
|
+
(0, _fixBlockMenuPositionAndScroll.scheduleBlockMenuPositionFix)(positionSnapshot, getMovedBlockDomNode, getFirstSelectedDomNode);
|
|
69
71
|
};
|
|
70
72
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
|
|
71
73
|
triggerRef: moveDownRef,
|
package/dist/cjs/ui/move-up.js
CHANGED
|
@@ -16,6 +16,7 @@ var _messages = require("@atlaskit/editor-common/messages");
|
|
|
16
16
|
var _types = require("@atlaskit/editor-common/types");
|
|
17
17
|
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
18
18
|
var _arrowUp = _interopRequireDefault(require("@atlaskit/icon/core/arrow-up"));
|
|
19
|
+
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
19
20
|
var _blockMenuProvider = require("./block-menu-provider");
|
|
20
21
|
var _consts = require("./consts");
|
|
21
22
|
var _fixBlockMenuPositionAndScroll = require("./utils/fixBlockMenuPositionAndScroll");
|
|
@@ -27,7 +28,10 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
27
28
|
var _useBlockMenu = (0, _blockMenuProvider.useBlockMenu)(),
|
|
28
29
|
moveUpRef = _useBlockMenu.moveUpRef,
|
|
29
30
|
moveDownRef = _useBlockMenu.moveDownRef,
|
|
30
|
-
getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode
|
|
31
|
+
getFirstSelectedDomNode = _useBlockMenu.getFirstSelectedDomNode,
|
|
32
|
+
getMovedBlockDomNode = _useBlockMenu.getMovedBlockDomNode,
|
|
33
|
+
getSelectedBlockDomNode = _useBlockMenu.getSelectedBlockDomNode,
|
|
34
|
+
anchorMetricsRef = _useBlockMenu.anchorMetricsRef;
|
|
31
35
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (_ref2) {
|
|
32
36
|
var _blockControlsState$b;
|
|
33
37
|
var blockControlsState = _ref2.blockControlsState;
|
|
@@ -43,6 +47,7 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
43
47
|
}
|
|
44
48
|
}, [canMoveUp, moveDownRef, moveUpRef]);
|
|
45
49
|
var handleClick = function handleClick() {
|
|
50
|
+
var positionSnapshot = (0, _fg.fg)('platform_editor_blocks_patch_8') ? (0, _fixBlockMenuPositionAndScroll.getBlockMenuPositionSnapshot)(getSelectedBlockDomNode(), anchorMetricsRef.current) : undefined;
|
|
46
51
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
47
52
|
var _api$analytics, _api$blockControls;
|
|
48
53
|
var tr = _ref3.tr;
|
|
@@ -60,10 +65,7 @@ var MoveUpDropdownItemContent = function MoveUpDropdownItemContent(_ref) {
|
|
|
60
65
|
});
|
|
61
66
|
return tr;
|
|
62
67
|
});
|
|
63
|
-
|
|
64
|
-
var newFirstNode = getFirstSelectedDomNode();
|
|
65
|
-
(0, _fixBlockMenuPositionAndScroll.fixBlockMenuPositionAndScroll)(newFirstNode);
|
|
66
|
-
});
|
|
68
|
+
(0, _fixBlockMenuPositionAndScroll.scheduleBlockMenuPositionFix)(positionSnapshot, getMovedBlockDomNode, getFirstSelectedDomNode);
|
|
67
69
|
};
|
|
68
70
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
|
|
69
71
|
triggerRef: moveUpRef,
|
|
@@ -1,12 +1,166 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
|
-
exports.fixBlockMenuPositionAndScroll = void 0;
|
|
7
|
+
exports.scheduleBlockMenuPositionFix = exports.getScrollDistanceToRevealAnchor = exports.getBlockMenuPositionSnapshot = exports.getBlockMenuAnchorMetrics = exports.fixBlockMenuPositionAndScroll = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
7
9
|
var _browserApis = require("@atlaskit/browser-apis");
|
|
8
10
|
var _blockMenu = require("@atlaskit/editor-common/block-menu");
|
|
9
|
-
var
|
|
11
|
+
var _styles = require("@atlaskit/editor-common/styles");
|
|
12
|
+
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
13
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
15
|
+
var POPUP_WRAPPER_TEST_ID = 'popup-wrapper';
|
|
16
|
+
var EDITOR_CONTENT_CONTAINER_SELECTOR = '[data-testid="editor-content-container"]';
|
|
17
|
+
/**
|
|
18
|
+
* Breathing room left between the revealed block and the fold it just crossed, so the block does
|
|
19
|
+
* not end up flush against the edge of the viewport.
|
|
20
|
+
*/
|
|
21
|
+
var REVEAL_MARGIN = 8;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Where the drag handle and the popup sit relative to their block. The drag handle is removed from
|
|
25
|
+
* the DOM as soon as the pointer moves onto the block menu, so this has to be measured while the
|
|
26
|
+
* menu opens rather than when a menu item is clicked.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Minimum scroll needed to bring the drag handle back inside the viewport.
|
|
31
|
+
* Zero means the handle is already fully visible.
|
|
32
|
+
*/
|
|
33
|
+
var getScrollDistanceToRevealAnchor = exports.getScrollDistanceToRevealAnchor = function getScrollDistanceToRevealAnchor(dragHandleTop, dragHandleHeight, viewport) {
|
|
34
|
+
if (dragHandleTop < viewport.top) {
|
|
35
|
+
return dragHandleTop - viewport.top;
|
|
36
|
+
}
|
|
37
|
+
var dragHandleBottom = dragHandleTop + dragHandleHeight;
|
|
38
|
+
if (dragHandleBottom > viewport.bottom) {
|
|
39
|
+
return dragHandleBottom - viewport.bottom;
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The editor content container is not always the element that actually scrolls - depending on the
|
|
46
|
+
* product it can be an ancestor, or the document itself. Pick the closest one that really scrolls.
|
|
47
|
+
*/
|
|
48
|
+
var getScrollContainer = function getScrollContainer(doc, selectedBlock) {
|
|
49
|
+
var editorContentContainer = doc.querySelector(EDITOR_CONTENT_CONTAINER_SELECTOR);
|
|
50
|
+
if (editorContentContainer && editorContentContainer.scrollHeight > editorContentContainer.clientHeight) {
|
|
51
|
+
return editorContentContainer;
|
|
52
|
+
}
|
|
53
|
+
var ancestor = selectedBlock.parentElement;
|
|
54
|
+
while (ancestor) {
|
|
55
|
+
var _doc$defaultView;
|
|
56
|
+
var overflowY = (_doc$defaultView = doc.defaultView) === null || _doc$defaultView === void 0 ? void 0 : _doc$defaultView.getComputedStyle(ancestor).overflowY;
|
|
57
|
+
if ((overflowY === 'auto' || overflowY === 'scroll') && ancestor.scrollHeight > ancestor.clientHeight) {
|
|
58
|
+
return ancestor;
|
|
59
|
+
}
|
|
60
|
+
ancestor = ancestor.parentElement;
|
|
61
|
+
}
|
|
62
|
+
return doc.scrollingElement;
|
|
63
|
+
};
|
|
64
|
+
var getScrollViewport = function getScrollViewport(doc, scrollContainer) {
|
|
65
|
+
if (scrollContainer === doc.scrollingElement) {
|
|
66
|
+
var _doc$defaultView$inne, _doc$defaultView2;
|
|
67
|
+
return {
|
|
68
|
+
bottom: (_doc$defaultView$inne = (_doc$defaultView2 = doc.defaultView) === null || _doc$defaultView2 === void 0 ? void 0 : _doc$defaultView2.innerHeight) !== null && _doc$defaultView$inne !== void 0 ? _doc$defaultView$inne : 0,
|
|
69
|
+
top: 0
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
var _scrollContainer$getB = scrollContainer.getBoundingClientRect(),
|
|
73
|
+
top = _scrollContainer$getB.top,
|
|
74
|
+
bottom = _scrollContainer$getB.bottom;
|
|
75
|
+
return {
|
|
76
|
+
bottom: bottom,
|
|
77
|
+
top: top
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Float based node views - a media group is one - collapse their top level wrapper to zero height,
|
|
83
|
+
* so the visual bottom of the block has to come from its children.
|
|
84
|
+
*/
|
|
85
|
+
var getBlockBottom = function getBlockBottom(block) {
|
|
86
|
+
var rect = block.getBoundingClientRect();
|
|
87
|
+
if (rect.height > 0) {
|
|
88
|
+
return rect.bottom;
|
|
89
|
+
}
|
|
90
|
+
return Array.from(block.children).reduce(function (bottom, child) {
|
|
91
|
+
return Math.max(bottom, child.getBoundingClientRect().bottom);
|
|
92
|
+
}, rect.bottom);
|
|
93
|
+
};
|
|
94
|
+
var setPopupTop = function setPopupTop(blockMenuEl, targetTop) {
|
|
95
|
+
var _blockMenuEl$closest;
|
|
96
|
+
var popupWrapper = (_blockMenuEl$closest = blockMenuEl.closest("[data-testid=\"".concat(POPUP_WRAPPER_TEST_ID, "\"]"))) !== null && _blockMenuEl$closest !== void 0 ? _blockMenuEl$closest : blockMenuEl.parentElement;
|
|
97
|
+
if (!(popupWrapper instanceof HTMLElement)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
var distance = blockMenuEl.getBoundingClientRect().top - targetTop;
|
|
101
|
+
var hasTopProperty = popupWrapper.style.top !== '';
|
|
102
|
+
var hasBottomProperty = popupWrapper.style.bottom !== '';
|
|
103
|
+
if (hasBottomProperty && !hasTopProperty) {
|
|
104
|
+
popupWrapper.style.bottom = "".concat(parseFloat(popupWrapper.style.bottom || '0') + distance, "px");
|
|
105
|
+
} else {
|
|
106
|
+
popupWrapper.style.top = "".concat(parseFloat(popupWrapper.style.top || '0') - distance, "px");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Measured while the menu opens, when the popup is still aligned to the drag handle. Moves that
|
|
112
|
+
* keep the handle visible deliberately leave the popup where it is, so this alignment - not the
|
|
113
|
+
* drifted one - is what the popup is restored to when a fold is crossed.
|
|
114
|
+
*/
|
|
115
|
+
var getBlockMenuAnchorMetrics = exports.getBlockMenuAnchorMetrics = function getBlockMenuAnchorMetrics(selectedBlock) {
|
|
116
|
+
var _doc$querySelector;
|
|
117
|
+
var doc = (0, _browserApis.getDocument)();
|
|
118
|
+
var blockMenuEl = doc === null || doc === void 0 ? void 0 : doc.querySelector("[data-testid=\"".concat(_blockMenu.BLOCK_MENU_TEST_ID, "\"]"));
|
|
119
|
+
if (!doc || !selectedBlock || !blockMenuEl) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
var blockMenuRect = blockMenuEl.getBoundingClientRect();
|
|
123
|
+
var dragHandleRect = (_doc$querySelector = doc.querySelector(_styles.DRAG_HANDLE_SELECTOR)) === null || _doc$querySelector === void 0 ? void 0 : _doc$querySelector.getBoundingClientRect();
|
|
124
|
+
if (blockMenuRect.height === 0 || !(dragHandleRect !== null && dragHandleRect !== void 0 && dragHandleRect.height)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
var blockTop = selectedBlock.getBoundingClientRect().top;
|
|
128
|
+
return {
|
|
129
|
+
blockHeight: getBlockBottom(selectedBlock) - blockTop,
|
|
130
|
+
dragHandleHeight: dragHandleRect.height,
|
|
131
|
+
dragHandleOffsetFromBlock: dragHandleRect.top - blockTop,
|
|
132
|
+
popupOffsetFromBlock: blockMenuRect.top - blockTop,
|
|
133
|
+
popupHeight: blockMenuRect.height
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Captured before the move transaction, so the popup can be realigned to the block after it.
|
|
139
|
+
*/
|
|
140
|
+
var getBlockMenuPositionSnapshot = exports.getBlockMenuPositionSnapshot = function getBlockMenuPositionSnapshot(selectedBlock, anchorMetrics) {
|
|
141
|
+
var doc = (0, _browserApis.getDocument)();
|
|
142
|
+
if (!doc || !selectedBlock) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
var scrollContainer = getScrollContainer(doc, selectedBlock);
|
|
146
|
+
var metrics = anchorMetrics !== null && anchorMetrics !== void 0 ? anchorMetrics : getBlockMenuAnchorMetrics(selectedBlock);
|
|
147
|
+
if (!scrollContainer || !metrics) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
return _objectSpread(_objectSpread({}, metrics), {}, {
|
|
151
|
+
scrollContainer: scrollContainer,
|
|
152
|
+
scrollTop: scrollContainer.scrollTop
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Called after a move up/down transaction.
|
|
158
|
+
*
|
|
159
|
+
* With a `positionSnapshot` the popup is only sticky when it has to be: the editor stays put while
|
|
160
|
+
* the moved node's drag handle is still visible, and scrolls the minimum needed to reveal the
|
|
161
|
+
* handle otherwise - realigning the popup to the revealed handle.
|
|
162
|
+
*/
|
|
163
|
+
var fixBlockMenuPositionAndScroll = exports.fixBlockMenuPositionAndScroll = function fixBlockMenuPositionAndScroll(selectedNode, positionSnapshot) {
|
|
10
164
|
var doc = (0, _browserApis.getDocument)();
|
|
11
165
|
if (!doc) {
|
|
12
166
|
return;
|
|
@@ -15,13 +169,54 @@ var fixBlockMenuPositionAndScroll = exports.fixBlockMenuPositionAndScroll = func
|
|
|
15
169
|
if (!(blockMenuEl !== null && blockMenuEl !== void 0 && blockMenuEl.parentElement)) {
|
|
16
170
|
return;
|
|
17
171
|
}
|
|
18
|
-
|
|
19
|
-
|
|
172
|
+
if (positionSnapshot) {
|
|
173
|
+
if (!selectedNode) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Reuse the container resolved when the snapshot was taken - re-resolving it independently
|
|
177
|
+
// here could pick a different element (e.g. for a node near an overflow boundary), applying
|
|
178
|
+
// positionSnapshot.scrollTop to the wrong container.
|
|
179
|
+
var scrollContainer = positionSnapshot.scrollContainer;
|
|
180
|
+
|
|
181
|
+
// The move transaction scrolls the new selection into view - undo that, only a drag handle
|
|
182
|
+
// leaving the viewport is allowed to move the editor.
|
|
183
|
+
scrollContainer.scrollTo({
|
|
184
|
+
behavior: 'instant',
|
|
185
|
+
top: positionSnapshot.scrollTop
|
|
186
|
+
});
|
|
187
|
+
var viewport = getScrollViewport(doc, scrollContainer);
|
|
188
|
+
var anchorTop = selectedNode.getBoundingClientRect().top + positionSnapshot.dragHandleOffsetFromBlock;
|
|
189
|
+
|
|
190
|
+
// Whether to scroll at all is decided by the drag handle alone - a block taller than the
|
|
191
|
+
// viewport is expected to be cut off while its handle stays usable.
|
|
192
|
+
if (getScrollDistanceToRevealAnchor(anchorTop, positionSnapshot.dragHandleHeight, viewport) === 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Once we do scroll, reveal the block and the popup, not just the handle sized sliver of it.
|
|
197
|
+
// popupOffsetFromBlock is relative to the block - re-express it relative to the handle (the
|
|
198
|
+
// anchor everything else here is measured from) to build one span covering all three. The
|
|
199
|
+
// handle itself (0 to dragHandleHeight) always stays inside that span, so its visibility is
|
|
200
|
+
// never sacrificed to make room for the block or the popup.
|
|
201
|
+
var popupTopFromHandle = positionSnapshot.popupOffsetFromBlock - positionSnapshot.dragHandleOffsetFromBlock;
|
|
202
|
+
var revealTop = Math.min(0, popupTopFromHandle);
|
|
203
|
+
var revealBottom = Math.max(positionSnapshot.dragHandleHeight, positionSnapshot.blockHeight - positionSnapshot.dragHandleOffsetFromBlock, popupTopFromHandle + positionSnapshot.popupHeight);
|
|
204
|
+
var revealHeight = Math.min(revealBottom - revealTop, Math.max(viewport.bottom - viewport.top - 2 * REVEAL_MARGIN, 0));
|
|
205
|
+
var scrollDistance = getScrollDistanceToRevealAnchor(anchorTop + revealTop - REVEAL_MARGIN, revealHeight + 2 * REVEAL_MARGIN, viewport);
|
|
206
|
+
scrollContainer.scrollBy({
|
|
207
|
+
behavior: 'instant',
|
|
208
|
+
top: scrollDistance
|
|
209
|
+
});
|
|
210
|
+
setPopupTop(blockMenuEl, selectedNode.getBoundingClientRect().top + positionSnapshot.popupOffsetFromBlock);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
var scrollableContainer = doc.querySelector(EDITOR_CONTENT_CONTAINER_SELECTOR);
|
|
214
|
+
if (!selectedNode || !scrollableContainer) {
|
|
20
215
|
return;
|
|
21
216
|
}
|
|
22
217
|
var parentElement = blockMenuEl.parentElement;
|
|
23
218
|
var currentTop = parentElement.getBoundingClientRect().top;
|
|
24
|
-
var distance =
|
|
219
|
+
var distance = selectedNode.getBoundingClientRect().top - blockMenuEl.getBoundingClientRect().top;
|
|
25
220
|
scrollableContainer.scrollBy({
|
|
26
221
|
behavior: 'instant',
|
|
27
222
|
top: distance
|
|
@@ -37,4 +232,22 @@ var fixBlockMenuPositionAndScroll = exports.fixBlockMenuPositionAndScroll = func
|
|
|
37
232
|
var currentTopValue = parseFloat(parentElement.style.top || '0');
|
|
38
233
|
parentElement.style.top = "".concat(currentTopValue + topDifference, "px");
|
|
39
234
|
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Shared by move-up.tsx and move-down.tsx: schedules the post-move fix for the frame after
|
|
239
|
+
* ProseMirror has re-rendered.
|
|
240
|
+
*
|
|
241
|
+
* Falls back to the pre-PR always-scroll path (matching gate-off, via `getFirstSelectedDomNode`)
|
|
242
|
+
* whenever a `positionSnapshot` wasn't captured - e.g. a media/file thumbnail reporting zero height
|
|
243
|
+
* for a frame when the menu opened - rather than silently doing nothing.
|
|
244
|
+
*/
|
|
245
|
+
var scheduleBlockMenuPositionFix = exports.scheduleBlockMenuPositionFix = function scheduleBlockMenuPositionFix(positionSnapshot, getMovedBlockDomNode, getFirstSelectedDomNode) {
|
|
246
|
+
requestAnimationFrame(function () {
|
|
247
|
+
if ((0, _fg.fg)('platform_editor_blocks_patch_8') && positionSnapshot) {
|
|
248
|
+
fixBlockMenuPositionAndScroll(getMovedBlockDomNode(), positionSnapshot);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
fixBlockMenuPositionAndScroll(getFirstSelectedDomNode());
|
|
252
|
+
});
|
|
40
253
|
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import React, { useCallback, createContext, useContext, useRef } from 'react';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
3
|
+
import { getBlockMenuAnchorMetrics } from './utils/fixBlockMenuPositionAndScroll';
|
|
2
4
|
const BlockMenuContext = /*#__PURE__*/createContext({
|
|
3
5
|
onDropdownOpenChanged: () => {},
|
|
4
6
|
moveDownRef: /*#__PURE__*/React.createRef(),
|
|
5
7
|
moveUpRef: /*#__PURE__*/React.createRef(),
|
|
6
|
-
getFirstSelectedDomNode: () => undefined
|
|
8
|
+
getFirstSelectedDomNode: () => undefined,
|
|
9
|
+
getMovedBlockDomNode: () => undefined,
|
|
10
|
+
getSelectedBlockDomNode: () => undefined,
|
|
11
|
+
anchorMetricsRef: {
|
|
12
|
+
current: undefined
|
|
13
|
+
}
|
|
7
14
|
});
|
|
8
15
|
export const useBlockMenu = () => {
|
|
9
16
|
const context = useContext(BlockMenuContext);
|
|
@@ -19,6 +26,7 @@ export const BlockMenuProvider = ({
|
|
|
19
26
|
}) => {
|
|
20
27
|
const moveUpRef = useRef(null);
|
|
21
28
|
const moveDownRef = useRef(null);
|
|
29
|
+
const anchorMetricsRef = useRef(undefined);
|
|
22
30
|
const getFirstSelectedDomNode = useCallback(() => {
|
|
23
31
|
var _api$selection, _api$selection$shared, _api$selection$shared2;
|
|
24
32
|
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;
|
|
@@ -29,23 +37,72 @@ export const BlockMenuProvider = ({
|
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
}, [api, editorView]);
|
|
40
|
+
const getTopLevelBlockDomNodeAt = useCallback(from => {
|
|
41
|
+
if (!editorView) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const nodeDOM = editorView.nodeDOM(from);
|
|
45
|
+
const domAtPos = nodeDOM instanceof Element ? nodeDOM : editorView.domAtPos(from).node;
|
|
46
|
+
const element = domAtPos instanceof Element ? domAtPos : domAtPos.parentElement;
|
|
47
|
+
if (!element || !editorView.dom.contains(element)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let block = element;
|
|
51
|
+
while (block.parentElement && block.parentElement !== editorView.dom) {
|
|
52
|
+
block = block.parentElement;
|
|
53
|
+
}
|
|
54
|
+
return block;
|
|
55
|
+
}, [editorView]);
|
|
56
|
+
const getSelectedBlockDomNode = useCallback(() => {
|
|
57
|
+
var _api$blockControls, _ref, _blockControlsState$a, _blockControlsState$a2, _blockControlsState$m, _blockControlsState$p;
|
|
58
|
+
const blockControlsState = api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState();
|
|
59
|
+
// The editor selection is not necessarily in the block the menu was opened for.
|
|
60
|
+
const from = (_ref = (_blockControlsState$a = blockControlsState === null || blockControlsState === void 0 ? void 0 : (_blockControlsState$a2 = blockControlsState.activeNode) === null || _blockControlsState$a2 === void 0 ? void 0 : _blockControlsState$a2.pos) !== null && _blockControlsState$a !== void 0 ? _blockControlsState$a : blockControlsState === null || blockControlsState === void 0 ? void 0 : (_blockControlsState$m = blockControlsState.menuTriggerByNode) === null || _blockControlsState$m === void 0 ? void 0 : _blockControlsState$m.pos) !== null && _ref !== void 0 ? _ref : blockControlsState === null || blockControlsState === void 0 ? void 0 : (_blockControlsState$p = blockControlsState.preservedSelection) === null || _blockControlsState$p === void 0 ? void 0 : _blockControlsState$p.from;
|
|
61
|
+
return from === undefined ? undefined : getTopLevelBlockDomNodeAt(from);
|
|
62
|
+
}, [api, getTopLevelBlockDomNodeAt]);
|
|
63
|
+
const getMovedBlockDomNode = useCallback(() => {
|
|
64
|
+
// A move transaction maps its preserved selection onto the node it just moved, so this is
|
|
65
|
+
// where that node ended up - unlike the block menu state, which keeps stale positions.
|
|
66
|
+
const from = editorView === null || editorView === void 0 ? void 0 : editorView.state.selection.from;
|
|
67
|
+
return from === undefined ? undefined : getTopLevelBlockDomNodeAt(from);
|
|
68
|
+
}, [editorView, getTopLevelBlockDomNodeAt]);
|
|
32
69
|
const onDropdownOpenChanged = useCallback(isOpen => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
anchorMetricsRef.current = undefined;
|
|
71
|
+
if (isOpen) {
|
|
72
|
+
if (fg('platform_editor_blocks_patch_8')) {
|
|
73
|
+
// The popup lays itself out next to the drag handle over the next frame or two.
|
|
74
|
+
let remainingFrames = 3;
|
|
75
|
+
const captureAnchorMetrics = () => {
|
|
76
|
+
requestAnimationFrame(() => {
|
|
77
|
+
anchorMetricsRef.current = getBlockMenuAnchorMetrics(getSelectedBlockDomNode());
|
|
78
|
+
remainingFrames -= 1;
|
|
79
|
+
if (!anchorMetricsRef.current && remainingFrames > 0) {
|
|
80
|
+
captureAnchorMetrics();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
captureAnchorMetrics();
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
40
87
|
}
|
|
41
|
-
|
|
88
|
+
|
|
89
|
+
// On Dropdown closed, return focus to editor
|
|
90
|
+
setTimeout(() => requestAnimationFrame(() => {
|
|
91
|
+
api === null || api === void 0 ? void 0 : api.core.actions.focus({
|
|
92
|
+
scrollIntoView: false
|
|
93
|
+
});
|
|
94
|
+
}), 1);
|
|
95
|
+
}, [api, getSelectedBlockDomNode]);
|
|
42
96
|
return /*#__PURE__*/React.createElement(BlockMenuContext.Provider, {
|
|
43
97
|
// eslint-disable-next-line @atlassian/perf-linting/no-inline-context-value, @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
44
98
|
value: {
|
|
45
99
|
onDropdownOpenChanged,
|
|
46
100
|
moveDownRef,
|
|
47
101
|
moveUpRef,
|
|
48
|
-
getFirstSelectedDomNode
|
|
102
|
+
getFirstSelectedDomNode,
|
|
103
|
+
getMovedBlockDomNode,
|
|
104
|
+
getSelectedBlockDomNode,
|
|
105
|
+
anchorMetricsRef
|
|
49
106
|
}
|
|
50
107
|
}, children);
|
|
51
108
|
};
|