@atlaskit/editor-plugin-block-menu 6.0.22 → 6.0.24

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,19 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 6.0.24
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 6.0.23
10
+
11
+ ### Patch Changes
12
+
13
+ - [`0d8216e610e34`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0d8216e610e34) -
14
+ [ux] Add cmd-option-a shortcut for copylink to block from block menu
15
+ - Updated dependencies
16
+
3
17
  ## 6.0.22
4
18
 
5
19
  ### Patch Changes
@@ -10,6 +10,7 @@ var _editorActions = require("./editor-actions");
10
10
  var _isTransformToTargetDisabled = require("./editor-actions/isTransformToTargetDisabled");
11
11
  var _formatNode2 = require("./editor-commands/formatNode");
12
12
  var _transformNode2 = require("./editor-commands/transformNode");
13
+ var _keymap = require("./pm-plugins/keymap");
13
14
  var _main = require("./pm-plugins/main");
14
15
  var _blockMenu = _interopRequireDefault(require("./ui/block-menu"));
15
16
  var _blockMenuComponents = require("./ui/block-menu-components");
@@ -31,6 +32,11 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
31
32
  plugin: function plugin() {
32
33
  return (0, _main.createPlugin)(api);
33
34
  }
35
+ }, {
36
+ name: 'blockMenuKeymap',
37
+ plugin: function plugin() {
38
+ return (0, _keymap.keymapPlugin)(api, config);
39
+ }
34
40
  }];
35
41
  },
36
42
  actions: {
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.keymapPlugin = keymapPlugin;
7
+ var _keymaps = require("@atlaskit/editor-common/keymaps");
8
+ var _selection = require("@atlaskit/editor-common/selection");
9
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
+ var _blockMenuPluginType = require("../blockMenuPluginType");
11
+ var _main = require("../pm-plugins/main");
12
+ var _copyLink = require("../ui/utils/copyLink");
13
+ function keymapPlugin(api, config) {
14
+ var list = {};
15
+ var copyLinkToBlockCommand = function copyLinkToBlockCommand(state, dispatch) {
16
+ var _api$blockControls, _node$attrs;
17
+ // Check if feature flag is enabled
18
+ if (!(0, _platformFeatureFlags.fg)('platform_editor_adf_with_localid')) {
19
+ return false;
20
+ }
21
+
22
+ // Get the preserved selection (only works when block menu is open and selection is preserved)
23
+ var selection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
24
+ if (!selection) {
25
+ return false;
26
+ }
27
+
28
+ // Check if the selection has a valid block range with localId
29
+ var blockRange = (0, _selection.expandSelectionToBlockRange)(selection);
30
+ if (!blockRange) {
31
+ return false;
32
+ }
33
+ var node = blockRange.$from.nodeAfter;
34
+ if (!(node !== null && node !== void 0 && (_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.localId)) {
35
+ return false;
36
+ }
37
+
38
+ // Execute the copy link action
39
+ var _ref = config || {},
40
+ getLinkPath = _ref.getLinkPath,
41
+ blockLinkHashPrefix = _ref.blockLinkHashPrefix;
42
+ (0, _copyLink.copyLink)({
43
+ getLinkPath: getLinkPath,
44
+ blockLinkHashPrefix: blockLinkHashPrefix,
45
+ selection: selection
46
+ }).then(function (success) {
47
+ if (success && dispatch) {
48
+ dispatch(state.tr.setMeta(_main.blockMenuPluginKey, {
49
+ showFlag: _blockMenuPluginType.FLAG_ID.LINK_COPIED_TO_CLIPBOARD
50
+ }));
51
+ }
52
+ });
53
+ return true;
54
+ };
55
+
56
+ // Ignored via go/ees005
57
+ (0, _keymaps.bindKeymapWithCommand)(
58
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
59
+ _keymaps.copyLinkToBlock.common, copyLinkToBlockCommand, list);
60
+ return (0, _keymaps.keymap)(list);
61
+ }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.createPlugin = exports.blockMenuPluginKey = void 0;
7
7
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
8
8
  var _state = require("@atlaskit/editor-prosemirror/state");
9
+ var _shouldSuppressKeyboardEvent = require("./utils/shouldSuppressKeyboardEvent");
9
10
  var blockMenuPluginKey = exports.blockMenuPluginKey = new _state.PluginKey('blockMenuPlugin');
10
11
  var createPlugin = exports.createPlugin = function createPlugin(api) {
11
12
  return new _safePlugin.SafePlugin({
@@ -35,14 +36,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
35
36
  }
36
37
 
37
38
  // Block further handling of key events when block menu is open
38
- // Except for backspace/delete/copy/cut/paste/undo/redo which should be handled by the selection preservation plugin
39
- var key = event.key.toLowerCase();
40
- var isMetaCtrl = event.metaKey || event.ctrlKey;
41
- var isBackspaceDelete = ['backspace', 'delete'].includes(key);
42
- var isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
43
- var isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
44
- var suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo;
45
- return suppressNativeHandling;
39
+ // Except for backspace/delete/copy/cut/paste/undo/redo/copy-link-to-block which should be handled by the selection preservation plugin
40
+ return (0, _shouldSuppressKeyboardEvent.shouldSuppressKeyboardEvent)(event);
46
41
  }
47
42
  }
48
43
  });
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.shouldSuppressKeyboardEvent = void 0;
7
+ /**
8
+ * Determines whether keyboard events should be suppressed when the block menu is open.
9
+ *
10
+ * When the block menu is open, we want to block most keyboard events to prevent
11
+ * unintended interactions. However, certain actions should still be allowed:
12
+ * - Backspace/Delete: Allow deleting selected content
13
+ * - Copy/Cut/Paste: Allow clipboard operations (Cmd/Ctrl+C, Cmd/Ctrl+X, Cmd/Ctrl+V)
14
+ * - Undo/Redo: Allow undo/redo operations (Cmd/Ctrl+Z, Cmd/Ctrl+Y)
15
+ * - Copy Link to Block: Allow the keyboard shortcut (Cmd/Ctrl+Alt+A)
16
+ *
17
+ * @param event - The keyboard event to check
18
+ * @returns true if the event should be suppressed, false if it should be allowed
19
+ */
20
+ var shouldSuppressKeyboardEvent = exports.shouldSuppressKeyboardEvent = function shouldSuppressKeyboardEvent(event) {
21
+ var key = event.key.toLowerCase();
22
+ var code = event.code.toLowerCase();
23
+ var isMetaCtrl = event.metaKey || event.ctrlKey;
24
+ var isAlt = event.altKey;
25
+
26
+ // Check for allowed keyboard shortcuts
27
+ var isBackspaceDelete = ['backspace', 'delete'].includes(key);
28
+ var isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
29
+ var isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
30
+
31
+ // Use event.code to detect physical key 'A' because on macOS Option+A produces 'å'
32
+ var isCopyLinkToBlock = isMetaCtrl && isAlt && code === 'keya';
33
+
34
+ // Suppress all events except the allowed ones
35
+ var suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo && !isCopyLinkToBlock;
36
+ return suppressNativeHandling;
37
+ };
@@ -10,6 +10,7 @@ var _react = _interopRequireWildcard(require("react"));
10
10
  var _reactIntlNext = require("react-intl-next");
11
11
  var _analytics = require("@atlaskit/editor-common/analytics");
12
12
  var _hooks = require("@atlaskit/editor-common/hooks");
13
+ var _keymaps = require("@atlaskit/editor-common/keymaps");
13
14
  var _messages = require("@atlaskit/editor-common/messages");
14
15
  var _editorToolbar = require("@atlaskit/editor-toolbar");
15
16
  var _link = _interopRequireDefault(require("@atlaskit/icon/core/link"));
@@ -30,6 +31,7 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
30
31
  var _ref2 = config || {},
31
32
  getLinkPath = _ref2.getLinkPath,
32
33
  blockLinkHashPrefix = _ref2.blockLinkHashPrefix;
34
+ var shortcut = (0, _keymaps.formatShortcut)(_keymaps.copyLinkToBlock);
33
35
  var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls', 'selection'], function (_ref3) {
34
36
  var blockControlsState = _ref3.blockControlsState,
35
37
  selectionState = _ref3.selectionState;
@@ -90,7 +92,11 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
90
92
  onClick: handleClick,
91
93
  elemBefore: /*#__PURE__*/_react.default.createElement(_link.default, {
92
94
  label: ""
93
- })
95
+ }),
96
+ elemAfter: shortcut ? /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarKeyboardShortcutHint, {
97
+ shortcut: shortcut
98
+ }) : undefined,
99
+ ariaKeyshortcuts: shortcut
94
100
  }, formatMessage(_messages.blockMenuMessages.copyLinkToBlock));
95
101
  };
96
102
  var CopyLinkDropdownItem = exports.CopyLinkDropdownItem = (0, _reactIntlNext.injectIntl)(CopyLinkDropdownItemContent);
@@ -3,6 +3,7 @@ import { createBlockMenuRegistry } from './editor-actions';
3
3
  import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
4
4
  import { formatNode } from './editor-commands/formatNode';
5
5
  import { transformNode } from './editor-commands/transformNode';
6
+ import { keymapPlugin } from './pm-plugins/keymap';
6
7
  import { blockMenuPluginKey, createPlugin } from './pm-plugins/main';
7
8
  import BlockMenu from './ui/block-menu';
8
9
  import { getBlockMenuComponents } from './ui/block-menu-components';
@@ -23,6 +24,9 @@ export const blockMenuPlugin = ({
23
24
  return [{
24
25
  name: 'blockMenuPlugin',
25
26
  plugin: () => createPlugin(api)
27
+ }, {
28
+ name: 'blockMenuKeymap',
29
+ plugin: () => keymapPlugin(api, config)
26
30
  }];
27
31
  },
28
32
  actions: {
@@ -0,0 +1,56 @@
1
+ import { bindKeymapWithCommand, copyLinkToBlock, keymap } from '@atlaskit/editor-common/keymaps';
2
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import { FLAG_ID } from '../blockMenuPluginType';
5
+ import { blockMenuPluginKey } from '../pm-plugins/main';
6
+ import { copyLink } from '../ui/utils/copyLink';
7
+ export function keymapPlugin(api, config) {
8
+ const list = {};
9
+ const copyLinkToBlockCommand = (state, dispatch) => {
10
+ var _api$blockControls, _api$blockControls$sh, _node$attrs;
11
+ // Check if feature flag is enabled
12
+ if (!fg('platform_editor_adf_with_localid')) {
13
+ return false;
14
+ }
15
+
16
+ // Get the preserved selection (only works when block menu is open and selection is preserved)
17
+ const selection = api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : (_api$blockControls$sh = _api$blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.preservedSelection;
18
+ if (!selection) {
19
+ return false;
20
+ }
21
+
22
+ // Check if the selection has a valid block range with localId
23
+ const blockRange = expandSelectionToBlockRange(selection);
24
+ if (!blockRange) {
25
+ return false;
26
+ }
27
+ const node = blockRange.$from.nodeAfter;
28
+ if (!(node !== null && node !== void 0 && (_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.localId)) {
29
+ return false;
30
+ }
31
+
32
+ // Execute the copy link action
33
+ const {
34
+ getLinkPath,
35
+ blockLinkHashPrefix
36
+ } = config || {};
37
+ copyLink({
38
+ getLinkPath,
39
+ blockLinkHashPrefix,
40
+ selection
41
+ }).then(success => {
42
+ if (success && dispatch) {
43
+ dispatch(state.tr.setMeta(blockMenuPluginKey, {
44
+ showFlag: FLAG_ID.LINK_COPIED_TO_CLIPBOARD
45
+ }));
46
+ }
47
+ });
48
+ return true;
49
+ };
50
+
51
+ // Ignored via go/ees005
52
+ bindKeymapWithCommand(
53
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
54
+ copyLinkToBlock.common, copyLinkToBlockCommand, list);
55
+ return keymap(list);
56
+ }
@@ -1,5 +1,6 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { shouldSuppressKeyboardEvent } from './utils/shouldSuppressKeyboardEvent';
3
4
  export const blockMenuPluginKey = new PluginKey('blockMenuPlugin');
4
5
  export const createPlugin = api => {
5
6
  return new SafePlugin({
@@ -29,14 +30,8 @@ export const createPlugin = api => {
29
30
  }
30
31
 
31
32
  // Block further handling of key events when block menu is open
32
- // Except for backspace/delete/copy/cut/paste/undo/redo which should be handled by the selection preservation plugin
33
- const key = event.key.toLowerCase();
34
- const isMetaCtrl = event.metaKey || event.ctrlKey;
35
- const isBackspaceDelete = ['backspace', 'delete'].includes(key);
36
- const isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
37
- const isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
38
- const suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo;
39
- return suppressNativeHandling;
33
+ // Except for backspace/delete/copy/cut/paste/undo/redo/copy-link-to-block which should be handled by the selection preservation plugin
34
+ return shouldSuppressKeyboardEvent(event);
40
35
  }
41
36
  }
42
37
  });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Determines whether keyboard events should be suppressed when the block menu is open.
3
+ *
4
+ * When the block menu is open, we want to block most keyboard events to prevent
5
+ * unintended interactions. However, certain actions should still be allowed:
6
+ * - Backspace/Delete: Allow deleting selected content
7
+ * - Copy/Cut/Paste: Allow clipboard operations (Cmd/Ctrl+C, Cmd/Ctrl+X, Cmd/Ctrl+V)
8
+ * - Undo/Redo: Allow undo/redo operations (Cmd/Ctrl+Z, Cmd/Ctrl+Y)
9
+ * - Copy Link to Block: Allow the keyboard shortcut (Cmd/Ctrl+Alt+A)
10
+ *
11
+ * @param event - The keyboard event to check
12
+ * @returns true if the event should be suppressed, false if it should be allowed
13
+ */
14
+ export const shouldSuppressKeyboardEvent = event => {
15
+ const key = event.key.toLowerCase();
16
+ const code = event.code.toLowerCase();
17
+ const isMetaCtrl = event.metaKey || event.ctrlKey;
18
+ const isAlt = event.altKey;
19
+
20
+ // Check for allowed keyboard shortcuts
21
+ const isBackspaceDelete = ['backspace', 'delete'].includes(key);
22
+ const isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
23
+ const isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
24
+
25
+ // Use event.code to detect physical key 'A' because on macOS Option+A produces 'å'
26
+ const isCopyLinkToBlock = isMetaCtrl && isAlt && code === 'keya';
27
+
28
+ // Suppress all events except the allowed ones
29
+ const suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo && !isCopyLinkToBlock;
30
+ return suppressNativeHandling;
31
+ };
@@ -2,8 +2,9 @@ import React, { useCallback } from 'react';
2
2
  import { injectIntl, useIntl } from 'react-intl-next';
3
3
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
4
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
+ import { copyLinkToBlock, formatShortcut } from '@atlaskit/editor-common/keymaps';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
6
- import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
7
+ import { ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
7
8
  import LinkIcon from '@atlaskit/icon/core/link';
8
9
  import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import { FLAG_ID } from '../blockMenuPluginType';
@@ -25,6 +26,7 @@ const CopyLinkDropdownItemContent = ({
25
26
  getLinkPath,
26
27
  blockLinkHashPrefix
27
28
  } = config || {};
29
+ const shortcut = formatShortcut(copyLinkToBlock);
28
30
  const {
29
31
  preservedSelection,
30
32
  defaultSelection
@@ -89,7 +91,11 @@ const CopyLinkDropdownItemContent = ({
89
91
  onClick: handleClick,
90
92
  elemBefore: /*#__PURE__*/React.createElement(LinkIcon, {
91
93
  label: ""
92
- })
94
+ }),
95
+ elemAfter: shortcut ? /*#__PURE__*/React.createElement(ToolbarKeyboardShortcutHint, {
96
+ shortcut: shortcut
97
+ }) : undefined,
98
+ ariaKeyshortcuts: shortcut
93
99
  }, formatMessage(messages.copyLinkToBlock));
94
100
  };
95
101
  export const CopyLinkDropdownItem = injectIntl(CopyLinkDropdownItemContent);
@@ -3,6 +3,7 @@ import { createBlockMenuRegistry } from './editor-actions';
3
3
  import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
4
4
  import { formatNode as _formatNode } from './editor-commands/formatNode';
5
5
  import { transformNode as _transformNode } from './editor-commands/transformNode';
6
+ import { keymapPlugin } from './pm-plugins/keymap';
6
7
  import { blockMenuPluginKey, createPlugin } from './pm-plugins/main';
7
8
  import BlockMenu from './ui/block-menu';
8
9
  import { getBlockMenuComponents } from './ui/block-menu-components';
@@ -24,6 +25,11 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
24
25
  plugin: function plugin() {
25
26
  return createPlugin(api);
26
27
  }
28
+ }, {
29
+ name: 'blockMenuKeymap',
30
+ plugin: function plugin() {
31
+ return keymapPlugin(api, config);
32
+ }
27
33
  }];
28
34
  },
29
35
  actions: {
@@ -0,0 +1,55 @@
1
+ import { bindKeymapWithCommand, copyLinkToBlock, keymap } from '@atlaskit/editor-common/keymaps';
2
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import { FLAG_ID } from '../blockMenuPluginType';
5
+ import { blockMenuPluginKey } from '../pm-plugins/main';
6
+ import { copyLink } from '../ui/utils/copyLink';
7
+ export function keymapPlugin(api, config) {
8
+ var list = {};
9
+ var copyLinkToBlockCommand = function copyLinkToBlockCommand(state, dispatch) {
10
+ var _api$blockControls, _node$attrs;
11
+ // Check if feature flag is enabled
12
+ if (!fg('platform_editor_adf_with_localid')) {
13
+ return false;
14
+ }
15
+
16
+ // Get the preserved selection (only works when block menu is open and selection is preserved)
17
+ var selection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
18
+ if (!selection) {
19
+ return false;
20
+ }
21
+
22
+ // Check if the selection has a valid block range with localId
23
+ var blockRange = expandSelectionToBlockRange(selection);
24
+ if (!blockRange) {
25
+ return false;
26
+ }
27
+ var node = blockRange.$from.nodeAfter;
28
+ if (!(node !== null && node !== void 0 && (_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.localId)) {
29
+ return false;
30
+ }
31
+
32
+ // Execute the copy link action
33
+ var _ref = config || {},
34
+ getLinkPath = _ref.getLinkPath,
35
+ blockLinkHashPrefix = _ref.blockLinkHashPrefix;
36
+ copyLink({
37
+ getLinkPath: getLinkPath,
38
+ blockLinkHashPrefix: blockLinkHashPrefix,
39
+ selection: selection
40
+ }).then(function (success) {
41
+ if (success && dispatch) {
42
+ dispatch(state.tr.setMeta(blockMenuPluginKey, {
43
+ showFlag: FLAG_ID.LINK_COPIED_TO_CLIPBOARD
44
+ }));
45
+ }
46
+ });
47
+ return true;
48
+ };
49
+
50
+ // Ignored via go/ees005
51
+ bindKeymapWithCommand(
52
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
53
+ copyLinkToBlock.common, copyLinkToBlockCommand, list);
54
+ return keymap(list);
55
+ }
@@ -1,5 +1,6 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { shouldSuppressKeyboardEvent } from './utils/shouldSuppressKeyboardEvent';
3
4
  export var blockMenuPluginKey = new PluginKey('blockMenuPlugin');
4
5
  export var createPlugin = function createPlugin(api) {
5
6
  return new SafePlugin({
@@ -29,14 +30,8 @@ export var createPlugin = function createPlugin(api) {
29
30
  }
30
31
 
31
32
  // Block further handling of key events when block menu is open
32
- // Except for backspace/delete/copy/cut/paste/undo/redo which should be handled by the selection preservation plugin
33
- var key = event.key.toLowerCase();
34
- var isMetaCtrl = event.metaKey || event.ctrlKey;
35
- var isBackspaceDelete = ['backspace', 'delete'].includes(key);
36
- var isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
37
- var isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
38
- var suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo;
39
- return suppressNativeHandling;
33
+ // Except for backspace/delete/copy/cut/paste/undo/redo/copy-link-to-block which should be handled by the selection preservation plugin
34
+ return shouldSuppressKeyboardEvent(event);
40
35
  }
41
36
  }
42
37
  });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Determines whether keyboard events should be suppressed when the block menu is open.
3
+ *
4
+ * When the block menu is open, we want to block most keyboard events to prevent
5
+ * unintended interactions. However, certain actions should still be allowed:
6
+ * - Backspace/Delete: Allow deleting selected content
7
+ * - Copy/Cut/Paste: Allow clipboard operations (Cmd/Ctrl+C, Cmd/Ctrl+X, Cmd/Ctrl+V)
8
+ * - Undo/Redo: Allow undo/redo operations (Cmd/Ctrl+Z, Cmd/Ctrl+Y)
9
+ * - Copy Link to Block: Allow the keyboard shortcut (Cmd/Ctrl+Alt+A)
10
+ *
11
+ * @param event - The keyboard event to check
12
+ * @returns true if the event should be suppressed, false if it should be allowed
13
+ */
14
+ export var shouldSuppressKeyboardEvent = function shouldSuppressKeyboardEvent(event) {
15
+ var key = event.key.toLowerCase();
16
+ var code = event.code.toLowerCase();
17
+ var isMetaCtrl = event.metaKey || event.ctrlKey;
18
+ var isAlt = event.altKey;
19
+
20
+ // Check for allowed keyboard shortcuts
21
+ var isBackspaceDelete = ['backspace', 'delete'].includes(key);
22
+ var isCopyCutPaste = isMetaCtrl && ['c', 'x', 'v'].includes(key);
23
+ var isUndoRedo = isMetaCtrl && ['z', 'y'].includes(key);
24
+
25
+ // Use event.code to detect physical key 'A' because on macOS Option+A produces 'å'
26
+ var isCopyLinkToBlock = isMetaCtrl && isAlt && code === 'keya';
27
+
28
+ // Suppress all events except the allowed ones
29
+ var suppressNativeHandling = !isCopyCutPaste && !isBackspaceDelete && !isUndoRedo && !isCopyLinkToBlock;
30
+ return suppressNativeHandling;
31
+ };
@@ -2,8 +2,9 @@ import React, { useCallback } from 'react';
2
2
  import { injectIntl, useIntl } from 'react-intl-next';
3
3
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
4
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
+ import { copyLinkToBlock, formatShortcut } from '@atlaskit/editor-common/keymaps';
5
6
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
6
- import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
7
+ import { ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
7
8
  import LinkIcon from '@atlaskit/icon/core/link';
8
9
  import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import { FLAG_ID } from '../blockMenuPluginType';
@@ -21,6 +22,7 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
21
22
  var _ref2 = config || {},
22
23
  getLinkPath = _ref2.getLinkPath,
23
24
  blockLinkHashPrefix = _ref2.blockLinkHashPrefix;
25
+ var shortcut = formatShortcut(copyLinkToBlock);
24
26
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls', 'selection'], function (_ref3) {
25
27
  var blockControlsState = _ref3.blockControlsState,
26
28
  selectionState = _ref3.selectionState;
@@ -81,7 +83,11 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
81
83
  onClick: handleClick,
82
84
  elemBefore: /*#__PURE__*/React.createElement(LinkIcon, {
83
85
  label: ""
84
- })
86
+ }),
87
+ elemAfter: shortcut ? /*#__PURE__*/React.createElement(ToolbarKeyboardShortcutHint, {
88
+ shortcut: shortcut
89
+ }) : undefined,
90
+ ariaKeyshortcuts: shortcut
85
91
  }, formatMessage(messages.copyLinkToBlock));
86
92
  };
87
93
  export var CopyLinkDropdownItem = injectIntl(CopyLinkDropdownItemContent);
@@ -0,0 +1,4 @@
1
+ import type { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { BlockMenuPlugin, BlockMenuPluginOptions } from '../blockMenuPluginType';
4
+ export declare function keymapPlugin(api: ExtractInjectionAPI<BlockMenuPlugin> | undefined, config: BlockMenuPluginOptions | undefined): SafePlugin;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Determines whether keyboard events should be suppressed when the block menu is open.
3
+ *
4
+ * When the block menu is open, we want to block most keyboard events to prevent
5
+ * unintended interactions. However, certain actions should still be allowed:
6
+ * - Backspace/Delete: Allow deleting selected content
7
+ * - Copy/Cut/Paste: Allow clipboard operations (Cmd/Ctrl+C, Cmd/Ctrl+X, Cmd/Ctrl+V)
8
+ * - Undo/Redo: Allow undo/redo operations (Cmd/Ctrl+Z, Cmd/Ctrl+Y)
9
+ * - Copy Link to Block: Allow the keyboard shortcut (Cmd/Ctrl+Alt+A)
10
+ *
11
+ * @param event - The keyboard event to check
12
+ * @returns true if the event should be suppressed, false if it should be allowed
13
+ */
14
+ export declare const shouldSuppressKeyboardEvent: (event: KeyboardEvent) => boolean;
@@ -0,0 +1,4 @@
1
+ import type { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { BlockMenuPlugin, BlockMenuPluginOptions } from '../blockMenuPluginType';
4
+ export declare function keymapPlugin(api: ExtractInjectionAPI<BlockMenuPlugin> | undefined, config: BlockMenuPluginOptions | undefined): SafePlugin;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Determines whether keyboard events should be suppressed when the block menu is open.
3
+ *
4
+ * When the block menu is open, we want to block most keyboard events to prevent
5
+ * unintended interactions. However, certain actions should still be allowed:
6
+ * - Backspace/Delete: Allow deleting selected content
7
+ * - Copy/Cut/Paste: Allow clipboard operations (Cmd/Ctrl+C, Cmd/Ctrl+X, Cmd/Ctrl+V)
8
+ * - Undo/Redo: Allow undo/redo operations (Cmd/Ctrl+Z, Cmd/Ctrl+Y)
9
+ * - Copy Link to Block: Allow the keyboard shortcut (Cmd/Ctrl+Alt+A)
10
+ *
11
+ * @param event - The keyboard event to check
12
+ * @returns true if the event should be suppressed, false if it should be allowed
13
+ */
14
+ export declare const shouldSuppressKeyboardEvent: (event: KeyboardEvent) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "6.0.22",
3
+ "version": "6.0.24",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -41,12 +41,12 @@
41
41
  "@atlaskit/editor-tables": "^2.9.0",
42
42
  "@atlaskit/editor-toolbar": "^0.19.0",
43
43
  "@atlaskit/flag": "^17.8.0",
44
- "@atlaskit/icon": "^29.4.0",
44
+ "@atlaskit/icon": "^30.0.0",
45
45
  "@atlaskit/platform-feature-flags": "^1.1.0",
46
46
  "@atlaskit/platform-feature-flags-react": "^0.4.0",
47
47
  "@atlaskit/primitives": "^17.1.0",
48
48
  "@atlaskit/prosemirror-history": "^0.2.0",
49
- "@atlaskit/tmp-editor-statsig": "^16.28.0",
49
+ "@atlaskit/tmp-editor-statsig": "^16.30.0",
50
50
  "@atlaskit/tokens": "^10.1.0",
51
51
  "@babel/runtime": "^7.0.0"
52
52
  },