@atlaskit/editor-plugin-block-menu 4.0.0 → 4.0.2

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,22 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 4.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`9cf29da7572b3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9cf29da7572b3) -
8
+ [ux] Fires Element converted event when Turn into menu is used to transform a node from one node
9
+ type to another.
10
+ - Updated dependencies
11
+
12
+ ## 4.0.1
13
+
14
+ ### Patch Changes
15
+
16
+ - [`f4c0936dc05fe`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f4c0936dc05fe) -
17
+ ED-29391 Add keyboard support for block menu
18
+ - Updated dependencies
19
+
3
20
  ## 4.0.0
4
21
 
5
22
  ### Patch Changes
@@ -23,6 +23,9 @@
23
23
  {
24
24
  "path": "../../../design-system/dropdown-menu/afm-cc/tsconfig.json"
25
25
  },
26
+ {
27
+ "path": "../../editor-plugin-analytics/afm-cc/tsconfig.json"
28
+ },
26
29
  {
27
30
  "path": "../../editor-plugin-block-controls/afm-cc/tsconfig.json"
28
31
  },
@@ -38,7 +38,7 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
38
38
  },
39
39
  commands: {
40
40
  formatNode: function formatNode(targetType) {
41
- return (0, _formatNode2.formatNode)(targetType);
41
+ return (0, _formatNode2.formatNode)(api)(targetType);
42
42
  }
43
43
  },
44
44
  getSharedState: function getSharedState(editorState) {
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.formatNode = void 0;
7
+ var _analytics = require("@atlaskit/editor-common/analytics");
7
8
  var _utils = require("@atlaskit/editor-prosemirror/utils");
8
9
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
10
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
@@ -51,62 +52,83 @@ var formatNodeWhenSelectionEmpty = function formatNodeWhenSelectionEmpty(tr, tar
51
52
 
52
53
  /**
53
54
  * Formats the current node or selection to the specified target type
55
+ * @param api - The editor API injection that provides access to analytics and other plugin actions
54
56
  * @param targetType - The target node type to convert to
55
57
  */
56
- var formatNode = exports.formatNode = function formatNode(targetType) {
57
- return function (_ref) {
58
- var tr = _ref.tr;
59
- var selection = tr.selection;
60
- var schema = tr.doc.type.schema;
61
- var nodes = schema.nodes;
58
+ var formatNode = exports.formatNode = function formatNode(api) {
59
+ return function (targetType) {
60
+ return function (_ref) {
61
+ var tr = _ref.tr;
62
+ var selection = tr.selection;
63
+ var schema = tr.doc.type.schema;
64
+ var nodes = schema.nodes;
62
65
 
63
- // Find the node to format from the current selection
64
- var nodeToFormat;
65
- var nodePos = selection.from;
66
+ // Find the node to format from the current selection
67
+ var nodeToFormat;
68
+ var nodePos = selection.from;
66
69
 
67
- // when selection is empty, we insert a empty target node
68
- if (selection.empty && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_empty_line', 'isEnabled', true)) {
69
- return formatNodeWhenSelectionEmpty(tr, targetType, nodePos, schema);
70
- }
70
+ // when selection is empty, we insert a empty target node
71
+ if (selection.empty && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_empty_line', 'isEnabled', true)) {
72
+ return formatNodeWhenSelectionEmpty(tr, targetType, nodePos, schema);
73
+ }
71
74
 
72
- // Try to find the current node from selection
73
- var selectedNode = (0, _utils.findSelectedNodeOfType)([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
74
- if (selectedNode) {
75
- nodeToFormat = selectedNode.node;
76
- nodePos = selectedNode.pos;
77
- } else {
78
- // Try to find parent node (including list parents)
79
- var parentNode = (0, _utils.findParentNodeOfType)([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
80
- if (parentNode) {
81
- nodeToFormat = parentNode.node;
82
- nodePos = parentNode.pos;
83
- var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
84
- // Special case: if we found a listItem, check if we need the parent list instead
85
- if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
86
- var listParent = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
87
- if (listParent) {
88
- // For list transformations, we want the list parent, not the listItem
89
- nodeToFormat = listParent.node;
90
- nodePos = listParent.pos;
75
+ // Try to find the current node from selection
76
+ var selectedNode = (0, _utils.findSelectedNodeOfType)([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
77
+ if (selectedNode) {
78
+ nodeToFormat = selectedNode.node;
79
+ nodePos = selectedNode.pos;
80
+ } else {
81
+ // Try to find parent node (including list parents)
82
+ var parentNode = (0, _utils.findParentNodeOfType)([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
83
+ if (parentNode) {
84
+ nodeToFormat = parentNode.node;
85
+ nodePos = parentNode.pos;
86
+ var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
87
+ // Special case: if we found a listItem, check if we need the parent list instead
88
+ if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
89
+ var listParent = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
90
+ if (listParent) {
91
+ // For list transformations, we want the list parent, not the listItem
92
+ nodeToFormat = listParent.node;
93
+ nodePos = listParent.pos;
94
+ }
95
+ } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
96
+ nodeToFormat = paragraphOrHeadingNode.node;
97
+ nodePos = paragraphOrHeadingNode.pos;
91
98
  }
92
- } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
93
- nodeToFormat = paragraphOrHeadingNode.node;
94
- nodePos = paragraphOrHeadingNode.pos;
95
99
  }
96
100
  }
97
- }
98
- if (!nodeToFormat) {
99
- nodeToFormat = selection.$from.node();
100
- nodePos = selection.$from.pos;
101
- }
102
- try {
103
- var newTr = (0, _transformNodeToTargetType.transformNodeToTargetType)(tr, nodeToFormat, nodePos, targetType);
104
- if (newTr && (0, _platformFeatureFlags.fg)('platform_editor_block_menu_selection_fix')) {
105
- return (0, _selection.setSelectionAfterTransform)(newTr, nodePos, targetType);
101
+ if (!nodeToFormat) {
102
+ nodeToFormat = selection.$from.node();
103
+ nodePos = selection.$from.pos;
106
104
  }
107
- return newTr;
108
- } catch (_unused) {
109
- return null;
110
- }
105
+ try {
106
+ var _nodeToFormat$attrs;
107
+ var newTr = (0, _transformNodeToTargetType.transformNodeToTargetType)(tr, nodeToFormat, nodePos, targetType);
108
+ var sourceTypeName = nodeToFormat.type.name;
109
+ if (sourceTypeName === 'heading' && (_nodeToFormat$attrs = nodeToFormat.attrs) !== null && _nodeToFormat$attrs !== void 0 && _nodeToFormat$attrs.level) {
110
+ sourceTypeName = "heading".concat(nodeToFormat.attrs.level);
111
+ }
112
+ if (newTr && sourceTypeName !== targetType) {
113
+ var _api$analytics;
114
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.attachAnalyticsEvent({
115
+ action: _analytics.ACTION.CONVERTED,
116
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
117
+ eventType: _analytics.EVENT_TYPE.TRACK,
118
+ attributes: {
119
+ from: sourceTypeName,
120
+ to: targetType,
121
+ inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU
122
+ }
123
+ })(newTr);
124
+ }
125
+ if (newTr && (0, _platformFeatureFlags.fg)('platform_editor_block_menu_selection_fix')) {
126
+ return (0, _selection.setSelectionAfterTransform)(newTr, nodePos, targetType);
127
+ }
128
+ return newTr;
129
+ } catch (_unused) {
130
+ return null;
131
+ }
132
+ };
111
133
  };
112
134
  };
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.BlockMenuRenderer = void 0;
9
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
10
  var _react = _interopRequireWildcard(require("react"));
11
+ var _uiMenu = require("@atlaskit/editor-common/ui-menu");
11
12
  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); }
12
13
  var NoOp = function NoOp(props) {
13
14
  return null;
@@ -49,7 +50,9 @@ var BlockMenuRenderer = exports.BlockMenuRenderer = function BlockMenuRenderer(_
49
50
  var menuSections = getSortedNonNestedSections(components);
50
51
  var menuItems = components.filter(isMenuItem);
51
52
  var nestedMenus = components.filter(isNestedMenu);
52
- return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, menuSections.map(function (section) {
53
+ return /*#__PURE__*/_react.default.createElement(_uiMenu.ArrowKeyNavigationProvider, {
54
+ type: _uiMenu.ArrowKeyNavigationType.MENU
55
+ }, /*#__PURE__*/_react.default.createElement(_react.Fragment, null, menuSections.map(function (section) {
53
56
  // Get all items for the current section, including nested menus, and sort them by rank
54
57
  var currentSectionItemsSorted = getSortedChildren([].concat((0, _toConsumableArray2.default)(menuItems), (0, _toConsumableArray2.default)(nestedMenus)), section.key);
55
58
  if (currentSectionItemsSorted.length === 0) {
@@ -90,5 +93,5 @@ var BlockMenuRenderer = exports.BlockMenuRenderer = function BlockMenuRenderer(_
90
93
  return /*#__PURE__*/_react.default.createElement(SectionComponent, {
91
94
  key: section.key
92
95
  }, children);
93
- }));
96
+ })));
94
97
  };
@@ -83,13 +83,13 @@ var BlockMenu = function BlockMenu(_ref2) {
83
83
  var prevIsMenuOpenRef = (0, _react.useRef)(false);
84
84
  var hasFocus = (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref3 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef) !== null && _ref3 !== void 0 ? _ref3 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
85
85
  var hasSelection = !!editorView && !editorView.state.selection.empty;
86
-
87
86
  // hasSelection true, always show block menu
88
87
  // hasSelection false, only show block menu when empty line experiment is enabled
89
88
  var shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_empty_line', 'isEnabled', true);
89
+ var selectedByShortcutORDragHandle = isSelectedViaDragHandle;
90
90
  (0, _react.useEffect)(function () {
91
91
  var _api$userIntent;
92
- if (!isMenuOpen || !menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
92
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
93
93
  return;
94
94
  }
95
95
 
@@ -108,7 +108,7 @@ var BlockMenu = function BlockMenu(_ref2) {
108
108
  // Update the previous state
109
109
  prevIsMenuOpenRef.current = isMenuOpen;
110
110
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
111
- }, [api, isMenuOpen, menuTriggerBy, isSelectedViaDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
111
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutORDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
112
112
  if (!isMenuOpen) {
113
113
  return null;
114
114
  }
@@ -128,7 +128,7 @@ var BlockMenu = function BlockMenu(_ref2) {
128
128
  return tr;
129
129
  });
130
130
  };
131
- if (!menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
131
+ if (!menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
132
132
  closeMenu();
133
133
  return null;
134
134
  }
@@ -149,6 +149,7 @@ var BlockMenu = function BlockMenu(_ref2) {
149
149
  preventOverflow: true // disables forced horizontal placement when forcePlacement is on, so fitWidth controls flipping
150
150
  ,
151
151
  stick: true,
152
+ focusTrap: true,
152
153
  offset: [_styles.DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, 0]
153
154
  }, /*#__PURE__*/_react.default.createElement(BlockMenuContent, {
154
155
  api: api
@@ -18,6 +18,7 @@ var _delete = _interopRequireDefault(require("@atlaskit/icon/core/delete"));
18
18
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
19
19
  var _box = require("@atlaskit/primitives/box");
20
20
  var _text = _interopRequireDefault(require("@atlaskit/primitives/text"));
21
+ var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
21
22
  var _blockMenuProvider = require("./block-menu-provider");
22
23
  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); }
23
24
  var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
@@ -64,7 +65,7 @@ var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
64
65
  });
65
66
  api === null || api === void 0 || api.core.actions.focus();
66
67
  };
67
- var onMouseEnter = (0, _react.useCallback)(function () {
68
+ var onShowHoverDecoration = (0, _react.useCallback)(function () {
68
69
  api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
69
70
  var _api$decorations, _api$decorations$hove;
70
71
  var tr = _ref3.tr;
@@ -77,14 +78,16 @@ var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
77
78
  return tr;
78
79
  });
79
80
  }, [api, nodeTypes]);
80
- var onMouseLeave = function onMouseLeave() {
81
+ var onRemoveHoverDecoration = function onRemoveHoverDecoration() {
81
82
  var _api$decorations2, _api$decorations2$rem;
82
83
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$decorations2 = api.decorations) === null || _api$decorations2 === void 0 || (_api$decorations2 = _api$decorations2.commands) === null || _api$decorations2 === void 0 || (_api$decorations2$rem = _api$decorations2.removeDecoration) === null || _api$decorations2$rem === void 0 ? void 0 : _api$decorations2$rem.call(_api$decorations2));
83
84
  };
84
85
  var text = (0, _platformFeatureFlags.fg)('platform_editor_block_menu_patch_1') ? formatMessage(_messages.blockMenuMessages.deleteBlock) : formatMessage(_blockMenu.messages.deleteBlock);
85
86
  return /*#__PURE__*/_react.default.createElement(_box.Box, {
86
- onMouseEnter: onMouseEnter,
87
- onMouseLeave: onMouseLeave
87
+ onMouseEnter: onShowHoverDecoration,
88
+ onMouseLeave: onRemoveHoverDecoration,
89
+ onFocus: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onShowHoverDecoration : undefined,
90
+ onBlur: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onRemoveHoverDecoration : undefined
88
91
  }, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
89
92
  elemBefore: /*#__PURE__*/_react.default.createElement(_delete.default, {
90
93
  color: "var(--ds-icon-danger, #C9372C)",
@@ -50,6 +50,7 @@ var FormatMenuComponent = exports.FormatMenuComponent = function FormatMenuCompo
50
50
  }),
51
51
  enableMaxHeight: true,
52
52
  isDisabled: isDisabled,
53
- onClick: handleClick
53
+ onClick: handleClick,
54
+ dropdownTestId: "editor-nested-turn-into-menu"
54
55
  }, children);
55
56
  };
@@ -32,7 +32,7 @@ export const blockMenuPlugin = ({
32
32
  },
33
33
  commands: {
34
34
  formatNode: targetType => {
35
- return formatNode(targetType);
35
+ return formatNode(api)(targetType);
36
36
  }
37
37
  },
38
38
  getSharedState(editorState) {
@@ -1,3 +1,4 @@
1
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
1
2
  import { findParentNodeOfType, findSelectedNodeOfType, safeInsert as pmSafeInsert } from '@atlaskit/editor-prosemirror/utils';
2
3
  import { fg } from '@atlaskit/platform-feature-flags';
3
4
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
@@ -49,9 +50,10 @@ const formatNodeWhenSelectionEmpty = (tr, targetType, nodePos, schema) => {
49
50
 
50
51
  /**
51
52
  * Formats the current node or selection to the specified target type
53
+ * @param api - The editor API injection that provides access to analytics and other plugin actions
52
54
  * @param targetType - The target node type to convert to
53
55
  */
54
- export const formatNode = targetType => {
56
+ export const formatNode = api => targetType => {
55
57
  return ({
56
58
  tr
57
59
  }) => {
@@ -103,7 +105,25 @@ export const formatNode = targetType => {
103
105
  nodePos = selection.$from.pos;
104
106
  }
105
107
  try {
108
+ var _nodeToFormat$attrs;
106
109
  const newTr = transformNodeToTargetType(tr, nodeToFormat, nodePos, targetType);
110
+ let sourceTypeName = nodeToFormat.type.name;
111
+ if (sourceTypeName === 'heading' && (_nodeToFormat$attrs = nodeToFormat.attrs) !== null && _nodeToFormat$attrs !== void 0 && _nodeToFormat$attrs.level) {
112
+ sourceTypeName = `heading${nodeToFormat.attrs.level}`;
113
+ }
114
+ if (newTr && sourceTypeName !== targetType) {
115
+ var _api$analytics, _api$analytics$action;
116
+ api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.attachAnalyticsEvent({
117
+ action: ACTION.CONVERTED,
118
+ actionSubject: ACTION_SUBJECT.ELEMENT,
119
+ eventType: EVENT_TYPE.TRACK,
120
+ attributes: {
121
+ from: sourceTypeName,
122
+ to: targetType,
123
+ inputMethod: INPUT_METHOD.BLOCK_MENU
124
+ }
125
+ })(newTr);
126
+ }
107
127
  if (newTr && fg('platform_editor_block_menu_selection_fix')) {
108
128
  return setSelectionAfterTransform(newTr, nodePos, targetType);
109
129
  }
@@ -1,4 +1,5 @@
1
1
  import React, { Fragment } from 'react';
2
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType } from '@atlaskit/editor-common/ui-menu';
2
3
  const NoOp = props => null;
3
4
  const isNonNestedMenuSection = component => {
4
5
  return component.type === 'block-menu-section' && !('parent' in component);
@@ -28,7 +29,9 @@ export const BlockMenuRenderer = ({
28
29
  const menuSections = getSortedNonNestedSections(components);
29
30
  const menuItems = components.filter(isMenuItem);
30
31
  const nestedMenus = components.filter(isNestedMenu);
31
- return /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(section => {
32
+ return /*#__PURE__*/React.createElement(ArrowKeyNavigationProvider, {
33
+ type: ArrowKeyNavigationType.MENU
34
+ }, /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(section => {
32
35
  // Get all items for the current section, including nested menus, and sort them by rank
33
36
  const currentSectionItemsSorted = getSortedChildren([...menuItems, ...nestedMenus], section.key);
34
37
  if (currentSectionItemsSorted.length === 0) {
@@ -69,5 +72,5 @@ export const BlockMenuRenderer = ({
69
72
  return /*#__PURE__*/React.createElement(SectionComponent, {
70
73
  key: section.key
71
74
  }, children);
72
- }));
75
+ })));
73
76
  };
@@ -73,13 +73,13 @@ const BlockMenu = ({
73
73
  const prevIsMenuOpenRef = useRef(false);
74
74
  const hasFocus = expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef) !== null && _ref !== void 0 ? _ref : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
75
75
  const hasSelection = !!editorView && !editorView.state.selection.empty;
76
-
77
76
  // hasSelection true, always show block menu
78
77
  // hasSelection false, only show block menu when empty line experiment is enabled
79
78
  const shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true);
79
+ const selectedByShortcutORDragHandle = isSelectedViaDragHandle;
80
80
  useEffect(() => {
81
81
  var _api$userIntent;
82
- if (!isMenuOpen || !menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
82
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
83
83
  return;
84
84
  }
85
85
 
@@ -98,7 +98,7 @@ const BlockMenu = ({
98
98
  // Update the previous state
99
99
  prevIsMenuOpenRef.current = isMenuOpen;
100
100
  api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
101
- }, [api, isMenuOpen, menuTriggerBy, isSelectedViaDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
101
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutORDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
102
102
  if (!isMenuOpen) {
103
103
  return null;
104
104
  }
@@ -119,7 +119,7 @@ const BlockMenu = ({
119
119
  return tr;
120
120
  });
121
121
  };
122
- if (!menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
122
+ if (!menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
123
123
  closeMenu();
124
124
  return null;
125
125
  }
@@ -140,6 +140,7 @@ const BlockMenu = ({
140
140
  preventOverflow: true // disables forced horizontal placement when forcePlacement is on, so fitWidth controls flipping
141
141
  ,
142
142
  stick: true,
143
+ focusTrap: true,
143
144
  offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, 0]
144
145
  }, /*#__PURE__*/React.createElement(BlockMenuContent, {
145
146
  api: api
@@ -10,6 +10,7 @@ import DeleteIcon from '@atlaskit/icon/core/delete';
10
10
  import { fg } from '@atlaskit/platform-feature-flags';
11
11
  import { Box } from '@atlaskit/primitives/box';
12
12
  import Text from '@atlaskit/primitives/text';
13
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
13
14
  import { useBlockMenu } from './block-menu-provider';
14
15
  const DeleteDropdownItemContent = ({
15
16
  api
@@ -59,7 +60,7 @@ const DeleteDropdownItemContent = ({
59
60
  });
60
61
  api === null || api === void 0 ? void 0 : api.core.actions.focus();
61
62
  };
62
- const onMouseEnter = useCallback(() => {
63
+ const onShowHoverDecoration = useCallback(() => {
63
64
  api === null || api === void 0 ? void 0 : api.core.actions.execute(({
64
65
  tr
65
66
  }) => {
@@ -73,14 +74,16 @@ const DeleteDropdownItemContent = ({
73
74
  return tr;
74
75
  });
75
76
  }, [api, nodeTypes]);
76
- const onMouseLeave = () => {
77
+ const onRemoveHoverDecoration = () => {
77
78
  var _api$decorations2, _api$decorations2$com, _api$decorations2$com2;
78
79
  api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$decorations2 = api.decorations) === null || _api$decorations2 === void 0 ? void 0 : (_api$decorations2$com = _api$decorations2.commands) === null || _api$decorations2$com === void 0 ? void 0 : (_api$decorations2$com2 = _api$decorations2$com.removeDecoration) === null || _api$decorations2$com2 === void 0 ? void 0 : _api$decorations2$com2.call(_api$decorations2$com));
79
80
  };
80
81
  const text = fg('platform_editor_block_menu_patch_1') ? formatMessage(blockMenuMessages.deleteBlock) : formatMessage(messages.deleteBlock);
81
82
  return /*#__PURE__*/React.createElement(Box, {
82
- onMouseEnter: onMouseEnter,
83
- onMouseLeave: onMouseLeave
83
+ onMouseEnter: onShowHoverDecoration,
84
+ onMouseLeave: onRemoveHoverDecoration,
85
+ onFocus: expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onShowHoverDecoration : undefined,
86
+ onBlur: expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onRemoveHoverDecoration : undefined
84
87
  }, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
85
88
  elemBefore: /*#__PURE__*/React.createElement(DeleteIcon, {
86
89
  color: "var(--ds-icon-danger, #C9372C)",
@@ -44,6 +44,7 @@ export const FormatMenuComponent = ({
44
44
  }),
45
45
  enableMaxHeight: true,
46
46
  isDisabled: isDisabled,
47
- onClick: handleClick
47
+ onClick: handleClick,
48
+ dropdownTestId: "editor-nested-turn-into-menu"
48
49
  }, children);
49
50
  };
@@ -31,7 +31,7 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
31
31
  },
32
32
  commands: {
33
33
  formatNode: function formatNode(targetType) {
34
- return _formatNode(targetType);
34
+ return _formatNode(api)(targetType);
35
35
  }
36
36
  },
37
37
  getSharedState: function getSharedState(editorState) {
@@ -1,3 +1,4 @@
1
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
1
2
  import { findParentNodeOfType, findSelectedNodeOfType, safeInsert as pmSafeInsert } from '@atlaskit/editor-prosemirror/utils';
2
3
  import { fg } from '@atlaskit/platform-feature-flags';
3
4
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
@@ -45,62 +46,83 @@ var formatNodeWhenSelectionEmpty = function formatNodeWhenSelectionEmpty(tr, tar
45
46
 
46
47
  /**
47
48
  * Formats the current node or selection to the specified target type
49
+ * @param api - The editor API injection that provides access to analytics and other plugin actions
48
50
  * @param targetType - The target node type to convert to
49
51
  */
50
- export var formatNode = function formatNode(targetType) {
51
- return function (_ref) {
52
- var tr = _ref.tr;
53
- var selection = tr.selection;
54
- var schema = tr.doc.type.schema;
55
- var nodes = schema.nodes;
52
+ export var formatNode = function formatNode(api) {
53
+ return function (targetType) {
54
+ return function (_ref) {
55
+ var tr = _ref.tr;
56
+ var selection = tr.selection;
57
+ var schema = tr.doc.type.schema;
58
+ var nodes = schema.nodes;
56
59
 
57
- // Find the node to format from the current selection
58
- var nodeToFormat;
59
- var nodePos = selection.from;
60
+ // Find the node to format from the current selection
61
+ var nodeToFormat;
62
+ var nodePos = selection.from;
60
63
 
61
- // when selection is empty, we insert a empty target node
62
- if (selection.empty && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true)) {
63
- return formatNodeWhenSelectionEmpty(tr, targetType, nodePos, schema);
64
- }
64
+ // when selection is empty, we insert a empty target node
65
+ if (selection.empty && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true)) {
66
+ return formatNodeWhenSelectionEmpty(tr, targetType, nodePos, schema);
67
+ }
65
68
 
66
- // Try to find the current node from selection
67
- var selectedNode = findSelectedNodeOfType([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
68
- if (selectedNode) {
69
- nodeToFormat = selectedNode.node;
70
- nodePos = selectedNode.pos;
71
- } else {
72
- // Try to find parent node (including list parents)
73
- var parentNode = findParentNodeOfType([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
74
- if (parentNode) {
75
- nodeToFormat = parentNode.node;
76
- nodePos = parentNode.pos;
77
- var paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
78
- // Special case: if we found a listItem, check if we need the parent list instead
79
- if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
80
- var listParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
81
- if (listParent) {
82
- // For list transformations, we want the list parent, not the listItem
83
- nodeToFormat = listParent.node;
84
- nodePos = listParent.pos;
69
+ // Try to find the current node from selection
70
+ var selectedNode = findSelectedNodeOfType([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
71
+ if (selectedNode) {
72
+ nodeToFormat = selectedNode.node;
73
+ nodePos = selectedNode.pos;
74
+ } else {
75
+ // Try to find parent node (including list parents)
76
+ var parentNode = findParentNodeOfType([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
77
+ if (parentNode) {
78
+ nodeToFormat = parentNode.node;
79
+ nodePos = parentNode.pos;
80
+ var paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
81
+ // Special case: if we found a listItem, check if we need the parent list instead
82
+ if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
83
+ var listParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
84
+ if (listParent) {
85
+ // For list transformations, we want the list parent, not the listItem
86
+ nodeToFormat = listParent.node;
87
+ nodePos = listParent.pos;
88
+ }
89
+ } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
90
+ nodeToFormat = paragraphOrHeadingNode.node;
91
+ nodePos = paragraphOrHeadingNode.pos;
85
92
  }
86
- } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
87
- nodeToFormat = paragraphOrHeadingNode.node;
88
- nodePos = paragraphOrHeadingNode.pos;
89
93
  }
90
94
  }
91
- }
92
- if (!nodeToFormat) {
93
- nodeToFormat = selection.$from.node();
94
- nodePos = selection.$from.pos;
95
- }
96
- try {
97
- var newTr = transformNodeToTargetType(tr, nodeToFormat, nodePos, targetType);
98
- if (newTr && fg('platform_editor_block_menu_selection_fix')) {
99
- return setSelectionAfterTransform(newTr, nodePos, targetType);
95
+ if (!nodeToFormat) {
96
+ nodeToFormat = selection.$from.node();
97
+ nodePos = selection.$from.pos;
100
98
  }
101
- return newTr;
102
- } catch (_unused) {
103
- return null;
104
- }
99
+ try {
100
+ var _nodeToFormat$attrs;
101
+ var newTr = transformNodeToTargetType(tr, nodeToFormat, nodePos, targetType);
102
+ var sourceTypeName = nodeToFormat.type.name;
103
+ if (sourceTypeName === 'heading' && (_nodeToFormat$attrs = nodeToFormat.attrs) !== null && _nodeToFormat$attrs !== void 0 && _nodeToFormat$attrs.level) {
104
+ sourceTypeName = "heading".concat(nodeToFormat.attrs.level);
105
+ }
106
+ if (newTr && sourceTypeName !== targetType) {
107
+ var _api$analytics;
108
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.attachAnalyticsEvent({
109
+ action: ACTION.CONVERTED,
110
+ actionSubject: ACTION_SUBJECT.ELEMENT,
111
+ eventType: EVENT_TYPE.TRACK,
112
+ attributes: {
113
+ from: sourceTypeName,
114
+ to: targetType,
115
+ inputMethod: INPUT_METHOD.BLOCK_MENU
116
+ }
117
+ })(newTr);
118
+ }
119
+ if (newTr && fg('platform_editor_block_menu_selection_fix')) {
120
+ return setSelectionAfterTransform(newTr, nodePos, targetType);
121
+ }
122
+ return newTr;
123
+ } catch (_unused) {
124
+ return null;
125
+ }
126
+ };
105
127
  };
106
128
  };
@@ -1,5 +1,6 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import React, { Fragment } from 'react';
3
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType } from '@atlaskit/editor-common/ui-menu';
3
4
  var NoOp = function NoOp(props) {
4
5
  return null;
5
6
  };
@@ -40,7 +41,9 @@ export var BlockMenuRenderer = function BlockMenuRenderer(_ref) {
40
41
  var menuSections = getSortedNonNestedSections(components);
41
42
  var menuItems = components.filter(isMenuItem);
42
43
  var nestedMenus = components.filter(isNestedMenu);
43
- return /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(function (section) {
44
+ return /*#__PURE__*/React.createElement(ArrowKeyNavigationProvider, {
45
+ type: ArrowKeyNavigationType.MENU
46
+ }, /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(function (section) {
44
47
  // Get all items for the current section, including nested menus, and sort them by rank
45
48
  var currentSectionItemsSorted = getSortedChildren([].concat(_toConsumableArray(menuItems), _toConsumableArray(nestedMenus)), section.key);
46
49
  if (currentSectionItemsSorted.length === 0) {
@@ -81,5 +84,5 @@ export var BlockMenuRenderer = function BlockMenuRenderer(_ref) {
81
84
  return /*#__PURE__*/React.createElement(SectionComponent, {
82
85
  key: section.key
83
86
  }, children);
84
- }));
87
+ })));
85
88
  };
@@ -75,13 +75,13 @@ var BlockMenu = function BlockMenu(_ref2) {
75
75
  var prevIsMenuOpenRef = useRef(false);
76
76
  var hasFocus = expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref3 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef) !== null && _ref3 !== void 0 ? _ref3 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
77
77
  var hasSelection = !!editorView && !editorView.state.selection.empty;
78
-
79
78
  // hasSelection true, always show block menu
80
79
  // hasSelection false, only show block menu when empty line experiment is enabled
81
80
  var shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true);
81
+ var selectedByShortcutORDragHandle = isSelectedViaDragHandle;
82
82
  useEffect(function () {
83
83
  var _api$userIntent;
84
- if (!isMenuOpen || !menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
84
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
85
85
  return;
86
86
  }
87
87
 
@@ -100,7 +100,7 @@ var BlockMenu = function BlockMenu(_ref2) {
100
100
  // Update the previous state
101
101
  prevIsMenuOpenRef.current = isMenuOpen;
102
102
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
103
- }, [api, isMenuOpen, menuTriggerBy, isSelectedViaDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
103
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutORDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, fireAnalyticsEvent]);
104
104
  if (!isMenuOpen) {
105
105
  return null;
106
106
  }
@@ -120,7 +120,7 @@ var BlockMenu = function BlockMenu(_ref2) {
120
120
  return tr;
121
121
  });
122
122
  };
123
- if (!menuTriggerBy || !isSelectedViaDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
123
+ if (!menuTriggerBy || !selectedByShortcutORDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
124
124
  closeMenu();
125
125
  return null;
126
126
  }
@@ -141,6 +141,7 @@ var BlockMenu = function BlockMenu(_ref2) {
141
141
  preventOverflow: true // disables forced horizontal placement when forcePlacement is on, so fitWidth controls flipping
142
142
  ,
143
143
  stick: true,
144
+ focusTrap: true,
144
145
  offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, 0]
145
146
  }, /*#__PURE__*/React.createElement(BlockMenuContent, {
146
147
  api: api
@@ -10,6 +10,7 @@ import DeleteIcon from '@atlaskit/icon/core/delete';
10
10
  import { fg } from '@atlaskit/platform-feature-flags';
11
11
  import { Box } from '@atlaskit/primitives/box';
12
12
  import Text from '@atlaskit/primitives/text';
13
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
13
14
  import { useBlockMenu } from './block-menu-provider';
14
15
  var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
15
16
  var _api$core$sharedState;
@@ -55,7 +56,7 @@ var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
55
56
  });
56
57
  api === null || api === void 0 || api.core.actions.focus();
57
58
  };
58
- var onMouseEnter = useCallback(function () {
59
+ var onShowHoverDecoration = useCallback(function () {
59
60
  api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
60
61
  var _api$decorations, _api$decorations$hove;
61
62
  var tr = _ref3.tr;
@@ -68,14 +69,16 @@ var DeleteDropdownItemContent = function DeleteDropdownItemContent(_ref) {
68
69
  return tr;
69
70
  });
70
71
  }, [api, nodeTypes]);
71
- var onMouseLeave = function onMouseLeave() {
72
+ var onRemoveHoverDecoration = function onRemoveHoverDecoration() {
72
73
  var _api$decorations2, _api$decorations2$rem;
73
74
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$decorations2 = api.decorations) === null || _api$decorations2 === void 0 || (_api$decorations2 = _api$decorations2.commands) === null || _api$decorations2 === void 0 || (_api$decorations2$rem = _api$decorations2.removeDecoration) === null || _api$decorations2$rem === void 0 ? void 0 : _api$decorations2$rem.call(_api$decorations2));
74
75
  };
75
76
  var text = fg('platform_editor_block_menu_patch_1') ? formatMessage(blockMenuMessages.deleteBlock) : formatMessage(messages.deleteBlock);
76
77
  return /*#__PURE__*/React.createElement(Box, {
77
- onMouseEnter: onMouseEnter,
78
- onMouseLeave: onMouseLeave
78
+ onMouseEnter: onShowHoverDecoration,
79
+ onMouseLeave: onRemoveHoverDecoration,
80
+ onFocus: expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onShowHoverDecoration : undefined,
81
+ onBlur: expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? onRemoveHoverDecoration : undefined
79
82
  }, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
80
83
  elemBefore: /*#__PURE__*/React.createElement(DeleteIcon, {
81
84
  color: "var(--ds-icon-danger, #C9372C)",
@@ -41,6 +41,7 @@ export var FormatMenuComponent = function FormatMenuComponent(_ref) {
41
41
  }),
42
42
  enableMaxHeight: true,
43
43
  isDisabled: isDisabled,
44
- onClick: handleClick
44
+ onClick: handleClick,
45
+ dropdownTestId: "editor-nested-turn-into-menu"
45
46
  }, children);
46
47
  };
@@ -1,7 +1,9 @@
1
- import type { EditorCommand } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
2
3
  import type { FormatNodeTargetType } from './transforms/types';
3
4
  /**
4
5
  * Formats the current node or selection to the specified target type
6
+ * @param api - The editor API injection that provides access to analytics and other plugin actions
5
7
  * @param targetType - The target node type to convert to
6
8
  */
7
- export declare const formatNode: (targetType: FormatNodeTargetType) => EditorCommand;
9
+ export declare const formatNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: FormatNodeTargetType) => EditorCommand;
@@ -1,7 +1,9 @@
1
- import type { EditorCommand } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
2
3
  import type { FormatNodeTargetType } from './transforms/types';
3
4
  /**
4
5
  * Formats the current node or selection to the specified target type
6
+ * @param api - The editor API injection that provides access to analytics and other plugin actions
5
7
  * @param targetType - The target node type to convert to
6
8
  */
7
- export declare const formatNode: (targetType: FormatNodeTargetType) => EditorCommand;
9
+ export declare const formatNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: FormatNodeTargetType) => EditorCommand;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -30,24 +30,25 @@
30
30
  "dependencies": {
31
31
  "@atlaskit/css": "^0.14.0",
32
32
  "@atlaskit/dropdown-menu": "^16.3.0",
33
- "@atlaskit/editor-plugin-block-controls": "^7.0.0",
34
- "@atlaskit/editor-plugin-decorations": "^6.0.0",
33
+ "@atlaskit/editor-plugin-analytics": "^6.0.0",
34
+ "@atlaskit/editor-plugin-block-controls": "^7.1.0",
35
+ "@atlaskit/editor-plugin-decorations": "^6.1.0",
35
36
  "@atlaskit/editor-plugin-selection": "^6.0.0",
36
37
  "@atlaskit/editor-plugin-user-intent": "^4.0.0",
37
38
  "@atlaskit/editor-prosemirror": "7.0.0",
38
39
  "@atlaskit/editor-shared-styles": "^3.6.0",
39
40
  "@atlaskit/editor-tables": "^2.9.0",
40
- "@atlaskit/editor-toolbar": "^0.9.0",
41
+ "@atlaskit/editor-toolbar": "^0.10.0",
41
42
  "@atlaskit/icon": "^28.3.0",
42
43
  "@atlaskit/icon-lab": "^5.7.0",
43
44
  "@atlaskit/platform-feature-flags": "^1.1.0",
44
45
  "@atlaskit/primitives": "^14.15.0",
45
- "@atlaskit/tmp-editor-statsig": "^12.31.0",
46
- "@atlaskit/tokens": "^6.3.0",
46
+ "@atlaskit/tmp-editor-statsig": "^12.32.0",
47
+ "@atlaskit/tokens": "^6.4.0",
47
48
  "@babel/runtime": "^7.0.0"
48
49
  },
49
50
  "peerDependencies": {
50
- "@atlaskit/editor-common": "^110.0.0",
51
+ "@atlaskit/editor-common": "^110.2.0",
51
52
  "react": "^18.2.0",
52
53
  "react-intl-next": "npm:react-intl@^5.18.1"
53
54
  },