@atlaskit/editor-plugin-block-menu 20.0.2 → 20.0.4
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-renderer/fallbacks.js +3 -0
- package/dist/cjs/ui/block-menu-target-visibility-context.js +12 -0
- package/dist/cjs/ui/block-menu.js +79 -12
- package/dist/cjs/ui/format-menu-nested.js +3 -0
- package/dist/es2019/ui/block-menu-renderer/fallbacks.js +3 -0
- package/dist/es2019/ui/block-menu-target-visibility-context.js +4 -0
- package/dist/es2019/ui/block-menu.js +73 -12
- package/dist/es2019/ui/format-menu-nested.js +3 -0
- package/dist/esm/ui/block-menu-renderer/fallbacks.js +3 -0
- package/dist/esm/ui/block-menu-target-visibility-context.js +6 -0
- package/dist/esm/ui/block-menu.js +79 -12
- package/dist/esm/ui/format-menu-nested.js +3 -0
- package/dist/types/ui/block-menu-target-visibility-context.d.ts +3 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-menu
|
|
2
2
|
|
|
3
|
+
## 20.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`981dd11bb4ed2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/981dd11bb4ed2) -
|
|
8
|
+
Add opt-in target visibility handling to editor popups, and use it to hide the Jira description
|
|
9
|
+
block menu while its originating node is outside the visible viewport. The popup reappears when
|
|
10
|
+
its target returns, preserving an open nested menu, behind the
|
|
11
|
+
`platform_editor_popup_target_visibility` experiment.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
14
|
+
## 20.0.3
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
|
|
3
20
|
## 20.0.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -10,11 +10,14 @@ var _reactIntl = require("react-intl");
|
|
|
10
10
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
11
11
|
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
12
12
|
var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
|
|
13
|
+
var _blockMenuTargetVisibilityContext = require("../block-menu-target-visibility-context");
|
|
13
14
|
var FallbackNestedMenu = function FallbackNestedMenu(_ref) {
|
|
14
15
|
var children = _ref.children;
|
|
15
16
|
var _useIntl = (0, _reactIntl.useIntl)(),
|
|
16
17
|
formatMessage = _useIntl.formatMessage;
|
|
18
|
+
var targetVisible = (0, _blockMenuTargetVisibilityContext.useBlockMenuTargetVisibility)();
|
|
17
19
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
|
|
20
|
+
isPopupVisible: targetVisible,
|
|
18
21
|
elemBefore: undefined,
|
|
19
22
|
elemAfter: /*#__PURE__*/_react.default.createElement(_chevronRight.default, {
|
|
20
23
|
label: "",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useBlockMenuTargetVisibility = exports.BlockMenuTargetVisibilityProvider = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var BlockMenuTargetVisibilityContext = /*#__PURE__*/(0, _react.createContext)(undefined);
|
|
9
|
+
var BlockMenuTargetVisibilityProvider = exports.BlockMenuTargetVisibilityProvider = BlockMenuTargetVisibilityContext.Provider;
|
|
10
|
+
var useBlockMenuTargetVisibility = exports.useBlockMenuTargetVisibility = function useBlockMenuTargetVisibility() {
|
|
11
|
+
return (0, _react.useContext)(BlockMenuTargetVisibilityContext);
|
|
12
|
+
};
|
|
@@ -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");
|
|
@@ -30,7 +31,10 @@ var _redo = require("@atlaskit/prosemirror-history/redo");
|
|
|
30
31
|
var _undo = require("@atlaskit/prosemirror-history/undo");
|
|
31
32
|
var _blockMenuProvider = require("./block-menu-provider");
|
|
32
33
|
var _BlockMenuRenderer = require("./block-menu-renderer/BlockMenuRenderer");
|
|
34
|
+
var _blockMenuTargetVisibilityContext = require("./block-menu-target-visibility-context");
|
|
33
35
|
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); }
|
|
36
|
+
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; }
|
|
37
|
+
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; }
|
|
34
38
|
var styles = {
|
|
35
39
|
base: "_2rko12b0 _bfhk1bhr _16qs130s",
|
|
36
40
|
maxWidthStyles: "_p12fnklw",
|
|
@@ -180,17 +184,20 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
180
184
|
mountTo = _ref5.mountTo,
|
|
181
185
|
boundariesElement = _ref5.boundariesElement,
|
|
182
186
|
scrollableElement = _ref5.scrollableElement;
|
|
187
|
+
var isPopupTargetVisibilityEnabled = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_popup_target_visibility');
|
|
183
188
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls', 'userIntent'], function (states) {
|
|
184
|
-
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$userIntentSta, _states$
|
|
189
|
+
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$blockControls4, _states$userIntentSta, _states$blockControls5;
|
|
185
190
|
return {
|
|
186
191
|
menuTriggerBy: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.menuTriggerBy,
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
menuTriggerByNode: isPopupTargetVisibilityEnabled ? (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.menuTriggerByNode : undefined,
|
|
193
|
+
isSelectedViaDragHandle: (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : _states$blockControls3.isSelectedViaDragHandle,
|
|
194
|
+
isMenuOpen: (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.isMenuOpen,
|
|
189
195
|
currentUserIntent: (_states$userIntentSta = states.userIntentState) === null || _states$userIntentSta === void 0 ? void 0 : _states$userIntentSta.currentUserIntent,
|
|
190
|
-
openedViaKeyboard: (_states$
|
|
196
|
+
openedViaKeyboard: (_states$blockControls5 = states.blockControlsState) === null || _states$blockControls5 === void 0 || (_states$blockControls5 = _states$blockControls5.blockMenuOptions) === null || _states$blockControls5 === void 0 ? void 0 : _states$blockControls5.openedViaKeyboard
|
|
191
197
|
};
|
|
192
198
|
}),
|
|
193
199
|
menuTriggerBy = _useSharedPluginState.menuTriggerBy,
|
|
200
|
+
menuTriggerByNode = _useSharedPluginState.menuTriggerByNode,
|
|
194
201
|
isSelectedViaDragHandle = _useSharedPluginState.isSelectedViaDragHandle,
|
|
195
202
|
isMenuOpen = _useSharedPluginState.isMenuOpen,
|
|
196
203
|
currentUserIntent = _useSharedPluginState.currentUserIntent,
|
|
@@ -228,6 +235,8 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
228
235
|
anchoredToRef.current = menuTriggerBy;
|
|
229
236
|
}
|
|
230
237
|
var targetHandleRef = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_control_migration') ? (_openMenuHandleRef$cu = openMenuHandleRef.current) !== null && _openMenuHandleRef$cu !== void 0 ? _openMenuHandleRef$cu : surfaceDragHandle : editorView === null || editorView === void 0 || (_editorView$dom = editorView.dom) === null || _editorView$dom === void 0 ? void 0 : _editorView$dom.querySelector(_styles.DRAG_HANDLE_SELECTOR);
|
|
238
|
+
var menuTargetNode = menuTriggerByNode && (editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(menuTriggerByNode.pos));
|
|
239
|
+
var visibilityTarget = menuTargetNode instanceof HTMLElement ? menuTargetNode : undefined;
|
|
231
240
|
var closeMenu = _react.default.useCallback(function () {
|
|
232
241
|
api === null || api === void 0 || api.core.actions.execute(function (_ref7) {
|
|
233
242
|
var _api$blockControls, _api$userIntent2;
|
|
@@ -257,19 +266,71 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
257
266
|
_React$useState4 = (0, _slicedToArray2.default)(_React$useState3, 2),
|
|
258
267
|
menuHeight = _React$useState4[0],
|
|
259
268
|
setMenuHeight = _React$useState4[1];
|
|
269
|
+
var _React$useState5 = _react.default.useState({
|
|
270
|
+
isVisible: undefined,
|
|
271
|
+
restoreFocusTo: null
|
|
272
|
+
}),
|
|
273
|
+
_React$useState6 = (0, _slicedToArray2.default)(_React$useState5, 2),
|
|
274
|
+
targetVisibility = _React$useState6[0],
|
|
275
|
+
setTargetVisibility = _React$useState6[1];
|
|
276
|
+
var targetVisible = targetVisibility.isVisible,
|
|
277
|
+
restoreFocusTo = targetVisibility.restoreFocusTo;
|
|
278
|
+
// CSS visibility can move focus to the document body. Preserve the active menu item so the
|
|
279
|
+
// existing focus-loss guard does not close the menus during a temporary scroll transition.
|
|
280
|
+
var handleTargetVisibilityChanged = _react.default.useCallback(function (isVisible) {
|
|
281
|
+
var _popupRef$current;
|
|
282
|
+
if (isVisible) {
|
|
283
|
+
setTargetVisibility(function (current) {
|
|
284
|
+
return {
|
|
285
|
+
isVisible: true,
|
|
286
|
+
restoreFocusTo: current.isVisible === false ? current.restoreFocusTo : null
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Capture focus before scheduling the state update so the updater stays pure.
|
|
293
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
294
|
+
var activeElement = document.activeElement;
|
|
295
|
+
var isFocusInMenu = activeElement instanceof HTMLElement && (((_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.contains(activeElement)) || activeElement.closest(_styles.NESTED_DROPDOWN_MENU) !== null);
|
|
296
|
+
setTargetVisibility({
|
|
297
|
+
isVisible: false,
|
|
298
|
+
restoreFocusTo: isFocusInMenu ? activeElement : null
|
|
299
|
+
});
|
|
300
|
+
}, []);
|
|
301
|
+
_react.default.useLayoutEffect(function () {
|
|
302
|
+
if (!isPopupTargetVisibilityEnabled || !targetVisible || !restoreFocusTo) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
var _restoreFocusTo$owner = restoreFocusTo.ownerDocument,
|
|
306
|
+
activeElement = _restoreFocusTo$owner.activeElement,
|
|
307
|
+
body = _restoreFocusTo$owner.body,
|
|
308
|
+
documentElement = _restoreFocusTo$owner.documentElement;
|
|
309
|
+
var focusWasLost = activeElement === null || activeElement === body || activeElement === documentElement;
|
|
310
|
+
if (restoreFocusTo.isConnected && focusWasLost) {
|
|
311
|
+
restoreFocusTo.focus({
|
|
312
|
+
preventScroll: true
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
setTargetVisibility(function (current) {
|
|
316
|
+
return _objectSpread(_objectSpread({}, current), {}, {
|
|
317
|
+
restoreFocusTo: null
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
}, [isPopupTargetVisibilityEnabled, restoreFocusTo, targetVisible]);
|
|
260
321
|
var targetHandleHeightOffset = -((targetHandleRef === null || targetHandleRef === void 0 ? void 0 : targetHandleRef.clientHeight) || 0);
|
|
261
322
|
_react.default.useLayoutEffect(function () {
|
|
262
|
-
var _popupRef$
|
|
323
|
+
var _popupRef$current2;
|
|
263
324
|
if (!isMenuOpen) {
|
|
264
325
|
return;
|
|
265
326
|
}
|
|
266
327
|
onDropdownOpenChanged(true);
|
|
267
|
-
setMenuHeight(((_popupRef$
|
|
328
|
+
setMenuHeight(((_popupRef$current2 = popupRef.current) === null || _popupRef$current2 === void 0 ? void 0 : _popupRef$current2.clientHeight) || FALLBACK_MENU_HEIGHT);
|
|
268
329
|
}, [isMenuOpen, onDropdownOpenChanged]);
|
|
269
330
|
|
|
270
331
|
// Nested dropdowns are portaled outside the block-menu popup. Sparse surface reconciliation
|
|
271
332
|
// dispatches after the menu opens, so a re-render can occur while focus is inside that portal.
|
|
272
|
-
var hasFocus = (_ref8 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) ||
|
|
333
|
+
var hasFocus = (_ref8 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || isPopupTargetVisibilityEnabled && (targetVisible === false || restoreFocusTo !== null) ||
|
|
273
334
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
274
335
|
document.activeElement === targetHandleRef || popupRef.current && (
|
|
275
336
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
@@ -340,6 +401,10 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
340
401
|
if (!(targetHandleRef instanceof HTMLElement)) {
|
|
341
402
|
return null;
|
|
342
403
|
}
|
|
404
|
+
var blockMenuContent = /*#__PURE__*/_react.default.createElement(BlockMenuContent, {
|
|
405
|
+
api: api,
|
|
406
|
+
setRef: setRef
|
|
407
|
+
});
|
|
343
408
|
return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
|
|
344
409
|
component: _analytics.ACTION_SUBJECT.BLOCK_MENU,
|
|
345
410
|
dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
|
|
@@ -354,11 +419,14 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
354
419
|
boundariesElement: boundariesElement,
|
|
355
420
|
scrollableElement: scrollableElement,
|
|
356
421
|
target: targetHandleRef,
|
|
422
|
+
visibilityTarget: visibilityTarget,
|
|
357
423
|
zIndex: _editorSharedStyles.akEditorFloatingOverlapPanelZIndex,
|
|
358
424
|
fitWidth: DEFAULT_MENU_WIDTH,
|
|
359
425
|
fitHeight: menuHeight,
|
|
360
426
|
preventOverflow: true,
|
|
361
|
-
stick: true
|
|
427
|
+
stick: true,
|
|
428
|
+
hideWhenTargetOutOfView: isPopupTargetVisibilityEnabled,
|
|
429
|
+
onTargetVisibilityChanged: isPopupTargetVisibilityEnabled ? handleTargetVisibilityChanged : undefined
|
|
362
430
|
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
363
431
|
,
|
|
364
432
|
offset: [_styles.DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
@@ -367,10 +435,9 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
367
435
|
{
|
|
368
436
|
initialFocus: undefined
|
|
369
437
|
} : undefined
|
|
370
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
})));
|
|
438
|
+
}, isPopupTargetVisibilityEnabled ? /*#__PURE__*/_react.default.createElement(_blockMenuTargetVisibilityContext.BlockMenuTargetVisibilityProvider, {
|
|
439
|
+
value: targetVisible
|
|
440
|
+
}, blockMenuContent) : blockMenuContent));
|
|
374
441
|
};
|
|
375
442
|
|
|
376
443
|
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
@@ -14,6 +14,7 @@ var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
|
14
14
|
var _changes = _interopRequireDefault(require("@atlaskit/icon/core/changes"));
|
|
15
15
|
var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
|
|
16
16
|
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
17
|
+
var _blockMenuTargetVisibilityContext = require("./block-menu-target-visibility-context");
|
|
17
18
|
var _consts = require("./consts");
|
|
18
19
|
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); }
|
|
19
20
|
var BLOCK_MENU_TRANSFORM_SPOTLIGHT_PORTAL_SELECTOR = '[data-test-id="block-menu-transform-spotlight-portal-container"]';
|
|
@@ -25,6 +26,7 @@ var FormatMenuComponent = exports.FormatMenuComponent = function FormatMenuCompo
|
|
|
25
26
|
children = _ref.children;
|
|
26
27
|
var _useIntl = (0, _reactIntl.useIntl)(),
|
|
27
28
|
formatMessage = _useIntl.formatMessage;
|
|
29
|
+
var targetVisible = (0, _blockMenuTargetVisibilityContext.useBlockMenuTargetVisibility)();
|
|
28
30
|
var formatMenuLabel = _messages.blockMenuMessages.changeFormat;
|
|
29
31
|
var handleClick = (0, _react.useCallback)(function () {
|
|
30
32
|
api === null || api === void 0 || api.core.actions.execute(function (_ref2) {
|
|
@@ -43,6 +45,7 @@ var FormatMenuComponent = exports.FormatMenuComponent = function FormatMenuCompo
|
|
|
43
45
|
});
|
|
44
46
|
}, [api]);
|
|
45
47
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
|
|
48
|
+
isPopupVisible: targetVisible,
|
|
46
49
|
text: formatMessage(formatMenuLabel),
|
|
47
50
|
elemBefore: /*#__PURE__*/_react.default.createElement(_changes.default, {
|
|
48
51
|
label: "",
|
|
@@ -3,13 +3,16 @@ import { useIntl } from 'react-intl';
|
|
|
3
3
|
import { blockMenuMessages } from '@atlaskit/editor-common/messages';
|
|
4
4
|
import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
5
5
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
6
|
+
import { useBlockMenuTargetVisibility } from '../block-menu-target-visibility-context';
|
|
6
7
|
const FallbackNestedMenu = ({
|
|
7
8
|
children
|
|
8
9
|
}) => {
|
|
9
10
|
const {
|
|
10
11
|
formatMessage
|
|
11
12
|
} = useIntl();
|
|
13
|
+
const targetVisible = useBlockMenuTargetVisibility();
|
|
12
14
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
15
|
+
isPopupVisible: targetVisible,
|
|
13
16
|
elemBefore: undefined,
|
|
14
17
|
elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
|
|
15
18
|
label: "",
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
const BlockMenuTargetVisibilityContext = /*#__PURE__*/createContext(undefined);
|
|
3
|
+
export const BlockMenuTargetVisibilityProvider = BlockMenuTargetVisibilityContext.Provider;
|
|
4
|
+
export const useBlockMenuTargetVisibility = () => useContext(BlockMenuTargetVisibilityContext);
|
|
@@ -21,6 +21,7 @@ import { redo } from '@atlaskit/prosemirror-history/redo';
|
|
|
21
21
|
import { undo } from '@atlaskit/prosemirror-history/undo';
|
|
22
22
|
import { useBlockMenu } from './block-menu-provider';
|
|
23
23
|
import { BlockMenuRenderer } from './block-menu-renderer/BlockMenuRenderer';
|
|
24
|
+
import { BlockMenuTargetVisibilityProvider } from './block-menu-target-visibility-context';
|
|
24
25
|
const styles = {
|
|
25
26
|
base: "_2rko12b0 _bfhk1bhr _16qs130s",
|
|
26
27
|
maxWidthStyles: "_p12fnklw",
|
|
@@ -168,20 +169,23 @@ const BlockMenu = ({
|
|
|
168
169
|
scrollableElement
|
|
169
170
|
}) => {
|
|
170
171
|
var _openMenuHandleRef$cu, _editorView$dom, _ref2, _api$analytics2;
|
|
172
|
+
const isPopupTargetVisibilityEnabled = isExperimentEnabled('platform_editor_popup_target_visibility');
|
|
171
173
|
const {
|
|
172
174
|
menuTriggerBy,
|
|
175
|
+
menuTriggerByNode,
|
|
173
176
|
isSelectedViaDragHandle,
|
|
174
177
|
isMenuOpen,
|
|
175
178
|
currentUserIntent,
|
|
176
179
|
openedViaKeyboard
|
|
177
180
|
} = useSharedPluginStateWithSelector(api, ['blockControls', 'userIntent'], states => {
|
|
178
|
-
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$userIntentSta, _states$
|
|
181
|
+
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$blockControls4, _states$userIntentSta, _states$blockControls5, _states$blockControls6;
|
|
179
182
|
return {
|
|
180
183
|
menuTriggerBy: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.menuTriggerBy,
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
menuTriggerByNode: isPopupTargetVisibilityEnabled ? (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.menuTriggerByNode : undefined,
|
|
185
|
+
isSelectedViaDragHandle: (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : _states$blockControls3.isSelectedViaDragHandle,
|
|
186
|
+
isMenuOpen: (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.isMenuOpen,
|
|
183
187
|
currentUserIntent: (_states$userIntentSta = states.userIntentState) === null || _states$userIntentSta === void 0 ? void 0 : _states$userIntentSta.currentUserIntent,
|
|
184
|
-
openedViaKeyboard: (_states$
|
|
188
|
+
openedViaKeyboard: (_states$blockControls5 = states.blockControlsState) === null || _states$blockControls5 === void 0 ? void 0 : (_states$blockControls6 = _states$blockControls5.blockMenuOptions) === null || _states$blockControls6 === void 0 ? void 0 : _states$blockControls6.openedViaKeyboard
|
|
185
189
|
};
|
|
186
190
|
});
|
|
187
191
|
const {
|
|
@@ -213,6 +217,8 @@ const BlockMenu = ({
|
|
|
213
217
|
anchoredToRef.current = menuTriggerBy;
|
|
214
218
|
}
|
|
215
219
|
const targetHandleRef = isExperimentEnabled('platform_editor_block_control_migration') ? (_openMenuHandleRef$cu = openMenuHandleRef.current) !== null && _openMenuHandleRef$cu !== void 0 ? _openMenuHandleRef$cu : surfaceDragHandle : editorView === null || editorView === void 0 ? void 0 : (_editorView$dom = editorView.dom) === null || _editorView$dom === void 0 ? void 0 : _editorView$dom.querySelector(DRAG_HANDLE_SELECTOR);
|
|
220
|
+
const menuTargetNode = menuTriggerByNode && (editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(menuTriggerByNode.pos));
|
|
221
|
+
const visibilityTarget = menuTargetNode instanceof HTMLElement ? menuTargetNode : undefined;
|
|
216
222
|
const closeMenu = React.useCallback(() => {
|
|
217
223
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
218
224
|
tr
|
|
@@ -240,19 +246,68 @@ const BlockMenu = ({
|
|
|
240
246
|
const prevIsMenuOpenRef = useRef(false);
|
|
241
247
|
const popupRef = useRef(undefined);
|
|
242
248
|
const [menuHeight, setMenuHeight] = React.useState(0);
|
|
249
|
+
const [targetVisibility, setTargetVisibility] = React.useState({
|
|
250
|
+
isVisible: undefined,
|
|
251
|
+
restoreFocusTo: null
|
|
252
|
+
});
|
|
253
|
+
const {
|
|
254
|
+
isVisible: targetVisible,
|
|
255
|
+
restoreFocusTo
|
|
256
|
+
} = targetVisibility;
|
|
257
|
+
// CSS visibility can move focus to the document body. Preserve the active menu item so the
|
|
258
|
+
// existing focus-loss guard does not close the menus during a temporary scroll transition.
|
|
259
|
+
const handleTargetVisibilityChanged = React.useCallback(isVisible => {
|
|
260
|
+
var _popupRef$current;
|
|
261
|
+
if (isVisible) {
|
|
262
|
+
setTargetVisibility(current => ({
|
|
263
|
+
isVisible: true,
|
|
264
|
+
restoreFocusTo: current.isVisible === false ? current.restoreFocusTo : null
|
|
265
|
+
}));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Capture focus before scheduling the state update so the updater stays pure.
|
|
270
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
271
|
+
const activeElement = document.activeElement;
|
|
272
|
+
const isFocusInMenu = activeElement instanceof HTMLElement && (((_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.contains(activeElement)) || activeElement.closest(NESTED_DROPDOWN_MENU) !== null);
|
|
273
|
+
setTargetVisibility({
|
|
274
|
+
isVisible: false,
|
|
275
|
+
restoreFocusTo: isFocusInMenu ? activeElement : null
|
|
276
|
+
});
|
|
277
|
+
}, []);
|
|
278
|
+
React.useLayoutEffect(() => {
|
|
279
|
+
if (!isPopupTargetVisibilityEnabled || !targetVisible || !restoreFocusTo) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const {
|
|
283
|
+
activeElement,
|
|
284
|
+
body,
|
|
285
|
+
documentElement
|
|
286
|
+
} = restoreFocusTo.ownerDocument;
|
|
287
|
+
const focusWasLost = activeElement === null || activeElement === body || activeElement === documentElement;
|
|
288
|
+
if (restoreFocusTo.isConnected && focusWasLost) {
|
|
289
|
+
restoreFocusTo.focus({
|
|
290
|
+
preventScroll: true
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
setTargetVisibility(current => ({
|
|
294
|
+
...current,
|
|
295
|
+
restoreFocusTo: null
|
|
296
|
+
}));
|
|
297
|
+
}, [isPopupTargetVisibilityEnabled, restoreFocusTo, targetVisible]);
|
|
243
298
|
const targetHandleHeightOffset = -((targetHandleRef === null || targetHandleRef === void 0 ? void 0 : targetHandleRef.clientHeight) || 0);
|
|
244
299
|
React.useLayoutEffect(() => {
|
|
245
|
-
var _popupRef$
|
|
300
|
+
var _popupRef$current2;
|
|
246
301
|
if (!isMenuOpen) {
|
|
247
302
|
return;
|
|
248
303
|
}
|
|
249
304
|
onDropdownOpenChanged(true);
|
|
250
|
-
setMenuHeight(((_popupRef$
|
|
305
|
+
setMenuHeight(((_popupRef$current2 = popupRef.current) === null || _popupRef$current2 === void 0 ? void 0 : _popupRef$current2.clientHeight) || FALLBACK_MENU_HEIGHT);
|
|
251
306
|
}, [isMenuOpen, onDropdownOpenChanged]);
|
|
252
307
|
|
|
253
308
|
// Nested dropdowns are portaled outside the block-menu popup. Sparse surface reconciliation
|
|
254
309
|
// dispatches after the menu opens, so a re-render can occur while focus is inside that portal.
|
|
255
|
-
const hasFocus = (_ref2 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) ||
|
|
310
|
+
const hasFocus = (_ref2 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || isPopupTargetVisibilityEnabled && (targetVisible === false || restoreFocusTo !== null) ||
|
|
256
311
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
257
312
|
document.activeElement === targetHandleRef || popupRef.current && (
|
|
258
313
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
@@ -323,6 +378,10 @@ const BlockMenu = ({
|
|
|
323
378
|
if (!(targetHandleRef instanceof HTMLElement)) {
|
|
324
379
|
return null;
|
|
325
380
|
}
|
|
381
|
+
const blockMenuContent = /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
382
|
+
api: api,
|
|
383
|
+
setRef: setRef
|
|
384
|
+
});
|
|
326
385
|
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
327
386
|
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
328
387
|
dispatchAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
|
|
@@ -337,11 +396,14 @@ const BlockMenu = ({
|
|
|
337
396
|
boundariesElement: boundariesElement,
|
|
338
397
|
scrollableElement: scrollableElement,
|
|
339
398
|
target: targetHandleRef,
|
|
399
|
+
visibilityTarget: visibilityTarget,
|
|
340
400
|
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
341
401
|
fitWidth: DEFAULT_MENU_WIDTH,
|
|
342
402
|
fitHeight: menuHeight,
|
|
343
403
|
preventOverflow: true,
|
|
344
|
-
stick: true
|
|
404
|
+
stick: true,
|
|
405
|
+
hideWhenTargetOutOfView: isPopupTargetVisibilityEnabled,
|
|
406
|
+
onTargetVisibilityChanged: isPopupTargetVisibilityEnabled ? handleTargetVisibilityChanged : undefined
|
|
345
407
|
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
346
408
|
,
|
|
347
409
|
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
@@ -350,10 +412,9 @@ const BlockMenu = ({
|
|
|
350
412
|
{
|
|
351
413
|
initialFocus: undefined
|
|
352
414
|
} : undefined
|
|
353
|
-
}, /*#__PURE__*/React.createElement(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
})));
|
|
415
|
+
}, isPopupTargetVisibilityEnabled ? /*#__PURE__*/React.createElement(BlockMenuTargetVisibilityProvider, {
|
|
416
|
+
value: targetVisible
|
|
417
|
+
}, blockMenuContent) : blockMenuContent));
|
|
357
418
|
};
|
|
358
419
|
|
|
359
420
|
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
@@ -6,6 +6,7 @@ import { ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
|
6
6
|
import ChangesIcon from '@atlaskit/icon/core/changes';
|
|
7
7
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
9
|
+
import { useBlockMenuTargetVisibility } from './block-menu-target-visibility-context';
|
|
9
10
|
import { BLOCK_MENU_ITEM_NAME } from './consts';
|
|
10
11
|
const BLOCK_MENU_TRANSFORM_SPOTLIGHT_PORTAL_SELECTOR = '[data-test-id="block-menu-transform-spotlight-portal-container"]';
|
|
11
12
|
const shouldIgnoreBlockMenuTransformSpotlightCloseEvent = event => event.target instanceof Element && event.target.closest(BLOCK_MENU_TRANSFORM_SPOTLIGHT_PORTAL_SELECTOR) !== null;
|
|
@@ -16,6 +17,7 @@ export const FormatMenuComponent = ({
|
|
|
16
17
|
const {
|
|
17
18
|
formatMessage
|
|
18
19
|
} = useIntl();
|
|
20
|
+
const targetVisible = useBlockMenuTargetVisibility();
|
|
19
21
|
const formatMenuLabel = blockMenuMessages.changeFormat;
|
|
20
22
|
const handleClick = useCallback(() => {
|
|
21
23
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
@@ -35,6 +37,7 @@ export const FormatMenuComponent = ({
|
|
|
35
37
|
});
|
|
36
38
|
}, [api]);
|
|
37
39
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
40
|
+
isPopupVisible: targetVisible,
|
|
38
41
|
text: formatMessage(formatMenuLabel),
|
|
39
42
|
elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
|
|
40
43
|
label: "",
|
|
@@ -3,11 +3,14 @@ import { useIntl } from 'react-intl';
|
|
|
3
3
|
import { blockMenuMessages } from '@atlaskit/editor-common/messages';
|
|
4
4
|
import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
5
5
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
6
|
+
import { useBlockMenuTargetVisibility } from '../block-menu-target-visibility-context';
|
|
6
7
|
var FallbackNestedMenu = function FallbackNestedMenu(_ref) {
|
|
7
8
|
var children = _ref.children;
|
|
8
9
|
var _useIntl = useIntl(),
|
|
9
10
|
formatMessage = _useIntl.formatMessage;
|
|
11
|
+
var targetVisible = useBlockMenuTargetVisibility();
|
|
10
12
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
13
|
+
isPopupVisible: targetVisible,
|
|
11
14
|
elemBefore: undefined,
|
|
12
15
|
elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
|
|
13
16
|
label: "",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
var BlockMenuTargetVisibilityContext = /*#__PURE__*/createContext(undefined);
|
|
3
|
+
export var BlockMenuTargetVisibilityProvider = BlockMenuTargetVisibilityContext.Provider;
|
|
4
|
+
export var useBlockMenuTargetVisibility = function useBlockMenuTargetVisibility() {
|
|
5
|
+
return useContext(BlockMenuTargetVisibilityContext);
|
|
6
|
+
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/* block-menu.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
3
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
4
|
import "./block-menu.compiled.css";
|
|
4
5
|
import { ax, ix } from "@compiled/react/runtime";
|
|
6
|
+
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; }
|
|
7
|
+
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) { _defineProperty(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; }
|
|
5
8
|
import React, { useContext, useEffect, useRef } from 'react';
|
|
6
9
|
import { injectIntl } from 'react-intl';
|
|
7
10
|
import { cx } from '@atlaskit/css';
|
|
@@ -22,6 +25,7 @@ import { redo } from '@atlaskit/prosemirror-history/redo';
|
|
|
22
25
|
import { undo } from '@atlaskit/prosemirror-history/undo';
|
|
23
26
|
import { useBlockMenu } from './block-menu-provider';
|
|
24
27
|
import { BlockMenuRenderer } from './block-menu-renderer/BlockMenuRenderer';
|
|
28
|
+
import { BlockMenuTargetVisibilityProvider } from './block-menu-target-visibility-context';
|
|
25
29
|
var styles = {
|
|
26
30
|
base: "_2rko12b0 _bfhk1bhr _16qs130s",
|
|
27
31
|
maxWidthStyles: "_p12fnklw",
|
|
@@ -171,17 +175,20 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
171
175
|
mountTo = _ref5.mountTo,
|
|
172
176
|
boundariesElement = _ref5.boundariesElement,
|
|
173
177
|
scrollableElement = _ref5.scrollableElement;
|
|
178
|
+
var isPopupTargetVisibilityEnabled = isExperimentEnabled('platform_editor_popup_target_visibility');
|
|
174
179
|
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls', 'userIntent'], function (states) {
|
|
175
|
-
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$userIntentSta, _states$
|
|
180
|
+
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$blockControls4, _states$userIntentSta, _states$blockControls5;
|
|
176
181
|
return {
|
|
177
182
|
menuTriggerBy: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.menuTriggerBy,
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
menuTriggerByNode: isPopupTargetVisibilityEnabled ? (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.menuTriggerByNode : undefined,
|
|
184
|
+
isSelectedViaDragHandle: (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : _states$blockControls3.isSelectedViaDragHandle,
|
|
185
|
+
isMenuOpen: (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.isMenuOpen,
|
|
180
186
|
currentUserIntent: (_states$userIntentSta = states.userIntentState) === null || _states$userIntentSta === void 0 ? void 0 : _states$userIntentSta.currentUserIntent,
|
|
181
|
-
openedViaKeyboard: (_states$
|
|
187
|
+
openedViaKeyboard: (_states$blockControls5 = states.blockControlsState) === null || _states$blockControls5 === void 0 || (_states$blockControls5 = _states$blockControls5.blockMenuOptions) === null || _states$blockControls5 === void 0 ? void 0 : _states$blockControls5.openedViaKeyboard
|
|
182
188
|
};
|
|
183
189
|
}),
|
|
184
190
|
menuTriggerBy = _useSharedPluginState.menuTriggerBy,
|
|
191
|
+
menuTriggerByNode = _useSharedPluginState.menuTriggerByNode,
|
|
185
192
|
isSelectedViaDragHandle = _useSharedPluginState.isSelectedViaDragHandle,
|
|
186
193
|
isMenuOpen = _useSharedPluginState.isMenuOpen,
|
|
187
194
|
currentUserIntent = _useSharedPluginState.currentUserIntent,
|
|
@@ -219,6 +226,8 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
219
226
|
anchoredToRef.current = menuTriggerBy;
|
|
220
227
|
}
|
|
221
228
|
var targetHandleRef = isExperimentEnabled('platform_editor_block_control_migration') ? (_openMenuHandleRef$cu = openMenuHandleRef.current) !== null && _openMenuHandleRef$cu !== void 0 ? _openMenuHandleRef$cu : surfaceDragHandle : editorView === null || editorView === void 0 || (_editorView$dom = editorView.dom) === null || _editorView$dom === void 0 ? void 0 : _editorView$dom.querySelector(DRAG_HANDLE_SELECTOR);
|
|
229
|
+
var menuTargetNode = menuTriggerByNode && (editorView === null || editorView === void 0 ? void 0 : editorView.nodeDOM(menuTriggerByNode.pos));
|
|
230
|
+
var visibilityTarget = menuTargetNode instanceof HTMLElement ? menuTargetNode : undefined;
|
|
222
231
|
var closeMenu = React.useCallback(function () {
|
|
223
232
|
api === null || api === void 0 || api.core.actions.execute(function (_ref7) {
|
|
224
233
|
var _api$blockControls, _api$userIntent2;
|
|
@@ -248,19 +257,71 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
248
257
|
_React$useState4 = _slicedToArray(_React$useState3, 2),
|
|
249
258
|
menuHeight = _React$useState4[0],
|
|
250
259
|
setMenuHeight = _React$useState4[1];
|
|
260
|
+
var _React$useState5 = React.useState({
|
|
261
|
+
isVisible: undefined,
|
|
262
|
+
restoreFocusTo: null
|
|
263
|
+
}),
|
|
264
|
+
_React$useState6 = _slicedToArray(_React$useState5, 2),
|
|
265
|
+
targetVisibility = _React$useState6[0],
|
|
266
|
+
setTargetVisibility = _React$useState6[1];
|
|
267
|
+
var targetVisible = targetVisibility.isVisible,
|
|
268
|
+
restoreFocusTo = targetVisibility.restoreFocusTo;
|
|
269
|
+
// CSS visibility can move focus to the document body. Preserve the active menu item so the
|
|
270
|
+
// existing focus-loss guard does not close the menus during a temporary scroll transition.
|
|
271
|
+
var handleTargetVisibilityChanged = React.useCallback(function (isVisible) {
|
|
272
|
+
var _popupRef$current;
|
|
273
|
+
if (isVisible) {
|
|
274
|
+
setTargetVisibility(function (current) {
|
|
275
|
+
return {
|
|
276
|
+
isVisible: true,
|
|
277
|
+
restoreFocusTo: current.isVisible === false ? current.restoreFocusTo : null
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Capture focus before scheduling the state update so the updater stays pure.
|
|
284
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
285
|
+
var activeElement = document.activeElement;
|
|
286
|
+
var isFocusInMenu = activeElement instanceof HTMLElement && (((_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.contains(activeElement)) || activeElement.closest(NESTED_DROPDOWN_MENU) !== null);
|
|
287
|
+
setTargetVisibility({
|
|
288
|
+
isVisible: false,
|
|
289
|
+
restoreFocusTo: isFocusInMenu ? activeElement : null
|
|
290
|
+
});
|
|
291
|
+
}, []);
|
|
292
|
+
React.useLayoutEffect(function () {
|
|
293
|
+
if (!isPopupTargetVisibilityEnabled || !targetVisible || !restoreFocusTo) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
var _restoreFocusTo$owner = restoreFocusTo.ownerDocument,
|
|
297
|
+
activeElement = _restoreFocusTo$owner.activeElement,
|
|
298
|
+
body = _restoreFocusTo$owner.body,
|
|
299
|
+
documentElement = _restoreFocusTo$owner.documentElement;
|
|
300
|
+
var focusWasLost = activeElement === null || activeElement === body || activeElement === documentElement;
|
|
301
|
+
if (restoreFocusTo.isConnected && focusWasLost) {
|
|
302
|
+
restoreFocusTo.focus({
|
|
303
|
+
preventScroll: true
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
setTargetVisibility(function (current) {
|
|
307
|
+
return _objectSpread(_objectSpread({}, current), {}, {
|
|
308
|
+
restoreFocusTo: null
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}, [isPopupTargetVisibilityEnabled, restoreFocusTo, targetVisible]);
|
|
251
312
|
var targetHandleHeightOffset = -((targetHandleRef === null || targetHandleRef === void 0 ? void 0 : targetHandleRef.clientHeight) || 0);
|
|
252
313
|
React.useLayoutEffect(function () {
|
|
253
|
-
var _popupRef$
|
|
314
|
+
var _popupRef$current2;
|
|
254
315
|
if (!isMenuOpen) {
|
|
255
316
|
return;
|
|
256
317
|
}
|
|
257
318
|
onDropdownOpenChanged(true);
|
|
258
|
-
setMenuHeight(((_popupRef$
|
|
319
|
+
setMenuHeight(((_popupRef$current2 = popupRef.current) === null || _popupRef$current2 === void 0 ? void 0 : _popupRef$current2.clientHeight) || FALLBACK_MENU_HEIGHT);
|
|
259
320
|
}, [isMenuOpen, onDropdownOpenChanged]);
|
|
260
321
|
|
|
261
322
|
// Nested dropdowns are portaled outside the block-menu popup. Sparse surface reconciliation
|
|
262
323
|
// dispatches after the menu opens, so a re-render can occur while focus is inside that portal.
|
|
263
|
-
var hasFocus = (_ref8 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) ||
|
|
324
|
+
var hasFocus = (_ref8 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || isPopupTargetVisibilityEnabled && (targetVisible === false || restoreFocusTo !== null) ||
|
|
264
325
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
265
326
|
document.activeElement === targetHandleRef || popupRef.current && (
|
|
266
327
|
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage
|
|
@@ -331,6 +392,10 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
331
392
|
if (!(targetHandleRef instanceof HTMLElement)) {
|
|
332
393
|
return null;
|
|
333
394
|
}
|
|
395
|
+
var blockMenuContent = /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
396
|
+
api: api,
|
|
397
|
+
setRef: setRef
|
|
398
|
+
});
|
|
334
399
|
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
335
400
|
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
336
401
|
dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
|
|
@@ -345,11 +410,14 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
345
410
|
boundariesElement: boundariesElement,
|
|
346
411
|
scrollableElement: scrollableElement,
|
|
347
412
|
target: targetHandleRef,
|
|
413
|
+
visibilityTarget: visibilityTarget,
|
|
348
414
|
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
349
415
|
fitWidth: DEFAULT_MENU_WIDTH,
|
|
350
416
|
fitHeight: menuHeight,
|
|
351
417
|
preventOverflow: true,
|
|
352
|
-
stick: true
|
|
418
|
+
stick: true,
|
|
419
|
+
hideWhenTargetOutOfView: isPopupTargetVisibilityEnabled,
|
|
420
|
+
onTargetVisibilityChanged: isPopupTargetVisibilityEnabled ? handleTargetVisibilityChanged : undefined
|
|
353
421
|
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
354
422
|
,
|
|
355
423
|
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
@@ -358,10 +426,9 @@ var BlockMenu = function BlockMenu(_ref5) {
|
|
|
358
426
|
{
|
|
359
427
|
initialFocus: undefined
|
|
360
428
|
} : undefined
|
|
361
|
-
}, /*#__PURE__*/React.createElement(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
})));
|
|
429
|
+
}, isPopupTargetVisibilityEnabled ? /*#__PURE__*/React.createElement(BlockMenuTargetVisibilityProvider, {
|
|
430
|
+
value: targetVisible
|
|
431
|
+
}, blockMenuContent) : blockMenuContent));
|
|
365
432
|
};
|
|
366
433
|
|
|
367
434
|
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
|
@@ -6,6 +6,7 @@ import { ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
|
6
6
|
import ChangesIcon from '@atlaskit/icon/core/changes';
|
|
7
7
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
9
|
+
import { useBlockMenuTargetVisibility } from './block-menu-target-visibility-context';
|
|
9
10
|
import { BLOCK_MENU_ITEM_NAME } from './consts';
|
|
10
11
|
var BLOCK_MENU_TRANSFORM_SPOTLIGHT_PORTAL_SELECTOR = '[data-test-id="block-menu-transform-spotlight-portal-container"]';
|
|
11
12
|
var shouldIgnoreBlockMenuTransformSpotlightCloseEvent = function shouldIgnoreBlockMenuTransformSpotlightCloseEvent(event) {
|
|
@@ -16,6 +17,7 @@ export var FormatMenuComponent = function FormatMenuComponent(_ref) {
|
|
|
16
17
|
children = _ref.children;
|
|
17
18
|
var _useIntl = useIntl(),
|
|
18
19
|
formatMessage = _useIntl.formatMessage;
|
|
20
|
+
var targetVisible = useBlockMenuTargetVisibility();
|
|
19
21
|
var formatMenuLabel = blockMenuMessages.changeFormat;
|
|
20
22
|
var handleClick = useCallback(function () {
|
|
21
23
|
api === null || api === void 0 || api.core.actions.execute(function (_ref2) {
|
|
@@ -34,6 +36,7 @@ export var FormatMenuComponent = function FormatMenuComponent(_ref) {
|
|
|
34
36
|
});
|
|
35
37
|
}, [api]);
|
|
36
38
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
39
|
+
isPopupVisible: targetVisible,
|
|
37
40
|
text: formatMessage(formatMenuLabel),
|
|
38
41
|
elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
|
|
39
42
|
label: "",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-block-menu",
|
|
3
|
-
"version": "20.0.
|
|
3
|
+
"version": "20.0.4",
|
|
4
4
|
"description": "BlockMenu plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,21 +35,21 @@
|
|
|
35
35
|
"@atlaskit/editor-prosemirror": "^9.0.0",
|
|
36
36
|
"@atlaskit/editor-shared-styles": "^4.3.0",
|
|
37
37
|
"@atlaskit/editor-tables": "^3.2.0",
|
|
38
|
-
"@atlaskit/editor-toolbar": "^2.
|
|
38
|
+
"@atlaskit/editor-toolbar": "^2.8.0",
|
|
39
39
|
"@atlaskit/flag": "^19.0.0",
|
|
40
40
|
"@atlaskit/icon": "^38.0.0",
|
|
41
41
|
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
42
42
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
43
43
|
"@atlaskit/primitives": "^22.5.0",
|
|
44
44
|
"@atlaskit/prosemirror-history": "^1.2.0",
|
|
45
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
45
|
+
"@atlaskit/tmp-editor-statsig": "^208.0.0",
|
|
46
46
|
"@atlaskit/tokens": "^20.0.0",
|
|
47
47
|
"@babel/runtime": "^7.0.0",
|
|
48
48
|
"bind-event-listener": "^3.0.0",
|
|
49
49
|
"memoize-one": "^6.0.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@atlaskit/editor-common": "^125.
|
|
52
|
+
"@atlaskit/editor-common": "^125.3.0",
|
|
53
53
|
"react": "^18.2.0 || ^19.2.0",
|
|
54
54
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|
|
55
55
|
},
|