@atlaskit/editor-plugin-block-menu 1.0.8 → 1.0.10

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/blockMenuPlugin.js +12 -0
  3. package/dist/cjs/editor-commands/transforms/container-transforms.js +20 -0
  4. package/dist/cjs/pm-plugins/getIsFormatMenuHidden.js +40 -0
  5. package/dist/cjs/pm-plugins/main.js +13 -3
  6. package/dist/cjs/ui/block-menu-components.js +8 -4
  7. package/dist/cjs/ui/copy-link.js +12 -0
  8. package/dist/cjs/ui/format-menu-section.js +19 -0
  9. package/dist/cjs/ui/utils/isNestedNode.js +54 -0
  10. package/dist/es2019/blockMenuPlugin.js +13 -1
  11. package/dist/es2019/editor-commands/transforms/container-transforms.js +20 -0
  12. package/dist/es2019/pm-plugins/getIsFormatMenuHidden.js +34 -0
  13. package/dist/es2019/pm-plugins/main.js +13 -3
  14. package/dist/es2019/ui/block-menu-components.js +8 -4
  15. package/dist/es2019/ui/copy-link.js +12 -0
  16. package/dist/es2019/ui/format-menu-section.js +13 -0
  17. package/dist/es2019/ui/utils/isNestedNode.js +51 -0
  18. package/dist/esm/blockMenuPlugin.js +13 -1
  19. package/dist/esm/editor-commands/transforms/container-transforms.js +20 -0
  20. package/dist/esm/pm-plugins/getIsFormatMenuHidden.js +34 -0
  21. package/dist/esm/pm-plugins/main.js +12 -3
  22. package/dist/esm/ui/block-menu-components.js +8 -4
  23. package/dist/esm/ui/copy-link.js +12 -0
  24. package/dist/esm/ui/format-menu-section.js +12 -0
  25. package/dist/esm/ui/utils/isNestedNode.js +49 -0
  26. package/dist/types/blockMenuPluginType.d.ts +3 -0
  27. package/dist/types/pm-plugins/getIsFormatMenuHidden.d.ts +2 -0
  28. package/dist/types/pm-plugins/main.d.ts +3 -1
  29. package/dist/types/ui/format-menu-section.d.ts +7 -0
  30. package/dist/types/ui/utils/isNestedNode.d.ts +14 -0
  31. package/dist/types-ts4.5/blockMenuPluginType.d.ts +3 -0
  32. package/dist/types-ts4.5/pm-plugins/getIsFormatMenuHidden.d.ts +2 -0
  33. package/dist/types-ts4.5/pm-plugins/main.d.ts +3 -1
  34. package/dist/types-ts4.5/ui/format-menu-section.d.ts +7 -0
  35. package/dist/types-ts4.5/ui/utils/isNestedNode.d.ts +14 -0
  36. package/package.json +7 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 1.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [`74c42a764926a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/74c42a764926a) -
8
+ Hide copy link option when platform_editor_adf_with_localid FG is off or when selection is a
9
+ nested node
10
+ - [`614ef1a575e84`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/614ef1a575e84) -
11
+ [ux] ED-29183: Fixed p and headings with alignment not able to convert to panel, expand, block
12
+ quote
13
+
14
+ ## 1.0.9
15
+
16
+ ### Patch Changes
17
+
18
+ - [`da23530028aac`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/da23530028aac) -
19
+ [ux] ED-29145 Hide format menu for unsupported and nested nodes
20
+
3
21
  ## 1.0.8
4
22
 
5
23
  ### Patch Changes
@@ -40,6 +40,18 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
40
40
  return (0, _formatNode2.formatNode)(targetType);
41
41
  }
42
42
  },
43
+ getSharedState: function getSharedState(editorState) {
44
+ if (!editorState) {
45
+ return;
46
+ }
47
+ var pluginState = _main.blockMenuPluginKey.getState(editorState);
48
+ if (!pluginState) {
49
+ return;
50
+ }
51
+ return {
52
+ isFormatMenuHidden: pluginState === null || pluginState === void 0 ? void 0 : pluginState.isFormatMenuHidden
53
+ };
54
+ },
43
55
  contentComponent: function contentComponent(_ref2) {
44
56
  var editorView = _ref2.editorView,
45
57
  popupsMountPoint = _ref2.popupsMountPoint,
@@ -20,6 +20,19 @@ var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeTy
20
20
  });
21
21
  return _model.Fragment.from(validTransformedContent);
22
22
  };
23
+ var filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
24
+ var withValidMarks = [];
25
+ content.forEach(function (node) {
26
+ if (node.marks.length > 0) {
27
+ var allowedMarks = targetNodeType.allowedMarks(node.marks);
28
+ var updatedNode = node.mark(allowedMarks);
29
+ withValidMarks.push(updatedNode);
30
+ } else {
31
+ withValidMarks.push(node);
32
+ }
33
+ });
34
+ return _model.Fragment.from(withValidMarks);
35
+ };
23
36
 
24
37
  /**
25
38
  * Transform selection to container type
@@ -39,6 +52,13 @@ var transformToContainer = exports.transformToContainer = function transformToCo
39
52
  if (targetNodeType === schema.nodes.blockquote) {
40
53
  transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
41
54
  }
55
+
56
+ // Preserve marks that are allowed in the target node type
57
+ // e.g. blocks (heading/ paragraph) with alignment need to remove alignment
58
+ // as panel/ blockQuote/ expands does not support alignment
59
+ if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
60
+ transformedContent = filterMarksForTargetNodeType(transformedContent, targetNodeType);
61
+ }
42
62
  var newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
43
63
  if (!newNode) {
44
64
  return null;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getIsFormatMenuHidden = void 0;
7
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
8
+ var TOP_LEVEL_NODE_DEPTHS = {
9
+ LIST_TYPE: 2,
10
+ PARAGRAPH_OR_HEADING: 1,
11
+ BLOCKQUOTE: 1,
12
+ BLOCK: 0
13
+ };
14
+ var getIsFormatMenuHidden = exports.getIsFormatMenuHidden = function getIsFormatMenuHidden(tr) {
15
+ var selection = tr.selection;
16
+ var nodes = tr.doc.type.schema.nodes;
17
+ if (selection.from === selection.to || selection.empty || !nodes) {
18
+ return false;
19
+ }
20
+ var content;
21
+ var isTopLevelNode = false;
22
+ 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);
23
+ if (selectedNode) {
24
+ content = selectedNode.node;
25
+ isTopLevelNode = selectedNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCK;
26
+ } else {
27
+ var listTypeOrBlockQuoteNode = (0, _utils.findParentNodeOfType)([nodes.blockquote, nodes.listItem, nodes.taskItem])(selection);
28
+ if (listTypeOrBlockQuoteNode) {
29
+ content = listTypeOrBlockQuoteNode.node;
30
+ isTopLevelNode = listTypeOrBlockQuoteNode.node.type === nodes.blockquote ? listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCKQUOTE : listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.LIST_TYPE;
31
+ } else {
32
+ var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
33
+ if (paragraphOrHeadingNode) {
34
+ content = paragraphOrHeadingNode.node;
35
+ isTopLevelNode = paragraphOrHeadingNode.depth === TOP_LEVEL_NODE_DEPTHS.PARAGRAPH_OR_HEADING;
36
+ }
37
+ }
38
+ }
39
+ return !content || !isTopLevelNode;
40
+ };
@@ -1,11 +1,16 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.createPlugin = exports.blockMenuPluginKey = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
9
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
8
10
  var _state = require("@atlaskit/editor-prosemirror/state");
11
+ var _getIsFormatMenuHidden = require("./getIsFormatMenuHidden");
12
+ 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; }
13
+ 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; }
9
14
  var blockMenuPluginKey = exports.blockMenuPluginKey = new _state.PluginKey('blockMenuPlugin');
10
15
 
11
16
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -15,14 +20,19 @@ var createPlugin = exports.createPlugin = function createPlugin() {
15
20
  key: blockMenuPluginKey,
16
21
  state: {
17
22
  init: function init() {
18
- return {};
23
+ return {
24
+ isFormatMenuHidden: false
25
+ };
19
26
  },
20
27
  apply: function apply(tr, currentPluginState) {
21
28
  var meta = tr.getMeta(blockMenuPluginKey);
22
29
  if (meta) {
23
- return meta;
30
+ return _objectSpread(_objectSpread({}, currentPluginState), meta);
24
31
  }
25
- return currentPluginState;
32
+ var isFormatMenuHidden = (0, _getIsFormatMenuHidden.getIsFormatMenuHidden)(tr);
33
+ return _objectSpread(_objectSpread({}, currentPluginState), {}, {
34
+ isFormatMenuHidden: isFormatMenuHidden
35
+ });
26
36
  }
27
37
  }
28
38
  });
@@ -14,6 +14,7 @@ var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-
14
14
  var _copyBlock = _interopRequireDefault(require("./copy-block"));
15
15
  var _copyLink = require("./copy-link");
16
16
  var _deleteButton = require("./delete-button");
17
+ var _formatMenuSection = require("./format-menu-section");
17
18
  var _moveDown = require("./move-down");
18
19
  var _moveUp = require("./move-up");
19
20
  var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
@@ -45,7 +46,7 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
45
46
  }
46
47
  }];
47
48
  };
48
- var getFormatMenuComponents = function getFormatMenuComponents() {
49
+ var getFormatMenuComponents = function getFormatMenuComponents(api) {
49
50
  return [{
50
51
  type: 'block-menu-nested',
51
52
  key: _blockMenu.NESTED_FORMAT_MENU.key,
@@ -91,21 +92,24 @@ var getFormatMenuComponents = function getFormatMenuComponents() {
91
92
  rank: 100,
92
93
  component: function component(_ref3) {
93
94
  var children = _ref3.children;
94
- return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, children);
95
+ return /*#__PURE__*/_react.default.createElement(_formatMenuSection.FormatMenuSection, {
96
+ api: api
97
+ }, children);
95
98
  }
96
99
  }];
97
100
  };
98
101
  var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockMenuComponents(_ref4) {
99
102
  var api = _ref4.api,
100
103
  config = _ref4.config;
101
- return [].concat((0, _toConsumableArray2.default)(getFormatMenuComponents()), [{
104
+ return [].concat((0, _toConsumableArray2.default)(getFormatMenuComponents(api)), [{
102
105
  type: 'block-menu-section',
103
106
  key: _blockMenu.COPY_MENU_SECTION.key,
104
107
  rank: _blockMenu.BLOCK_MENU_SECTION_RANK[_blockMenu.COPY_MENU_SECTION.key],
105
108
  component: function component(_ref5) {
109
+ var _api$blockMenu$shared;
106
110
  var children = _ref5.children;
107
111
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
108
- hasSeparator: true
112
+ hasSeparator: !(api !== null && api !== void 0 && (_api$blockMenu$shared = api.blockMenu.sharedState.currentState()) !== null && _api$blockMenu$shared !== void 0 && _api$blockMenu$shared.isFormatMenuHidden)
109
113
  }, children);
110
114
  }
111
115
  }, {
@@ -11,7 +11,9 @@ var _reactIntlNext = require("react-intl-next");
11
11
  var _messages = require("@atlaskit/editor-common/messages");
12
12
  var _editorToolbar = require("@atlaskit/editor-toolbar");
13
13
  var _link = _interopRequireDefault(require("@atlaskit/icon/core/link"));
14
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
15
  var _copyLink = require("./utils/copyLink");
16
+ var _isNestedNode = require("./utils/isNestedNode");
15
17
  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); }
16
18
  var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
17
19
  var api = _ref.api,
@@ -32,6 +34,16 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
32
34
  api === null || api === void 0 || api.core.actions.focus();
33
35
  return (0, _copyLink.copyLink)(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
34
36
  }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api]);
37
+ var checkIsNestedNode = (0, _react.useCallback)(function () {
38
+ var _api$selection;
39
+ var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState) === null || _api$selection === void 0 || (_api$selection = _api$selection.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
40
+ return (0, _isNestedNode.isNestedNode)(selection);
41
+ }, [api]);
42
+
43
+ // Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested
44
+ if (!(0, _platformFeatureFlags.fg)('platform_editor_adf_with_localid') || checkIsNestedNode()) {
45
+ return null;
46
+ }
35
47
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
36
48
  onClick: handleClick,
37
49
  elemBefore: /*#__PURE__*/_react.default.createElement(_link.default, {
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.FormatMenuSection = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
10
+ var _editorToolbar = require("@atlaskit/editor-toolbar");
11
+ var FormatMenuSection = exports.FormatMenuSection = function FormatMenuSection(_ref) {
12
+ var children = _ref.children,
13
+ api = _ref.api;
14
+ var isFormatMenuHidden = (0, _useSharedPluginStateSelector.useSharedPluginStateSelector)(api, 'blockMenu.isFormatMenuHidden');
15
+ if (isFormatMenuHidden) {
16
+ return null;
17
+ }
18
+ return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, children);
19
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isNestedNode = void 0;
7
+ var _state = require("@atlaskit/editor-prosemirror/state");
8
+ /**
9
+ * Determines if a node is nested (not at top-level) based on its depth and context.
10
+ *
11
+ * Simple rules:
12
+ * - Depth 0-1: Always top-level (not nested)
13
+ * - Depth 2: Top-level for blockquotes and task lists
14
+ * - Depth 3: Top-level for list items only
15
+ * - Depth 4+: Always nested
16
+ *
17
+ * @param selection - The current ProseMirror selection
18
+ * @returns true if nested, false if top-level
19
+ */
20
+ var isNestedNode = exports.isNestedNode = function isNestedNode(selection) {
21
+ if (!selection) {
22
+ return false;
23
+ }
24
+ var $from = selection.$from;
25
+ var depth = $from.depth;
26
+ if ($from.depth > 0 && selection instanceof _state.NodeSelection) {
27
+ return true;
28
+ }
29
+
30
+ // Depth 0-1: Always top-level
31
+ if (depth <= 1) {
32
+ return false;
33
+ }
34
+
35
+ // Depth 4+: Always nested
36
+ if (depth > 3) {
37
+ return true;
38
+ }
39
+
40
+ // Check parent node type for depth 2-3
41
+ var parentNode = $from.node(depth - 1);
42
+ if (!parentNode) {
43
+ return true;
44
+ }
45
+ var parentType = parentNode.type.name;
46
+
47
+ // Special cases where content is still top-level
48
+ if (parentType === 'listItem' && depth === 3 || parentType === 'blockquote' && depth === 2 || parentType === 'taskList' && depth === 2) {
49
+ return false;
50
+ }
51
+
52
+ // Everything else at depth 2-3 is nested
53
+ return true;
54
+ };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { createBlockMenuRegistry } from './editor-actions';
3
3
  import { formatNode } from './editor-commands/formatNode';
4
- import { createPlugin } from './pm-plugins/main';
4
+ import { blockMenuPluginKey, createPlugin } from './pm-plugins/main';
5
5
  import BlockMenu from './ui/block-menu';
6
6
  import { getBlockMenuComponents } from './ui/block-menu-components';
7
7
  export const blockMenuPlugin = ({
@@ -34,6 +34,18 @@ export const blockMenuPlugin = ({
34
34
  return formatNode(targetType);
35
35
  }
36
36
  },
37
+ getSharedState: editorState => {
38
+ if (!editorState) {
39
+ return;
40
+ }
41
+ const pluginState = blockMenuPluginKey.getState(editorState);
42
+ if (!pluginState) {
43
+ return;
44
+ }
45
+ return {
46
+ isFormatMenuHidden: pluginState === null || pluginState === void 0 ? void 0 : pluginState.isFormatMenuHidden
47
+ };
48
+ },
37
49
  contentComponent({
38
50
  editorView,
39
51
  popupsMountPoint,
@@ -12,6 +12,19 @@ const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validN
12
12
  });
13
13
  return Fragment.from(validTransformedContent);
14
14
  };
15
+ const filterMarksForTargetNodeType = (content, targetNodeType) => {
16
+ const withValidMarks = [];
17
+ content.forEach(node => {
18
+ if (node.marks.length > 0) {
19
+ const allowedMarks = targetNodeType.allowedMarks(node.marks);
20
+ const updatedNode = node.mark(allowedMarks);
21
+ withValidMarks.push(updatedNode);
22
+ } else {
23
+ withValidMarks.push(node);
24
+ }
25
+ });
26
+ return Fragment.from(withValidMarks);
27
+ };
15
28
 
16
29
  /**
17
30
  * Transform selection to container type
@@ -32,6 +45,13 @@ export const transformToContainer = ({
32
45
  if (targetNodeType === schema.nodes.blockquote) {
33
46
  transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
34
47
  }
48
+
49
+ // Preserve marks that are allowed in the target node type
50
+ // e.g. blocks (heading/ paragraph) with alignment need to remove alignment
51
+ // as panel/ blockQuote/ expands does not support alignment
52
+ if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
53
+ transformedContent = filterMarksForTargetNodeType(transformedContent, targetNodeType);
54
+ }
35
55
  const newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
36
56
  if (!newNode) {
37
57
  return null;
@@ -0,0 +1,34 @@
1
+ import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
2
+ const TOP_LEVEL_NODE_DEPTHS = {
3
+ LIST_TYPE: 2,
4
+ PARAGRAPH_OR_HEADING: 1,
5
+ BLOCKQUOTE: 1,
6
+ BLOCK: 0
7
+ };
8
+ export const getIsFormatMenuHidden = tr => {
9
+ const selection = tr.selection;
10
+ const nodes = tr.doc.type.schema.nodes;
11
+ if (selection.from === selection.to || selection.empty || !nodes) {
12
+ return false;
13
+ }
14
+ let content;
15
+ let isTopLevelNode = false;
16
+ const selectedNode = findSelectedNodeOfType([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
17
+ if (selectedNode) {
18
+ content = selectedNode.node;
19
+ isTopLevelNode = selectedNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCK;
20
+ } else {
21
+ const listTypeOrBlockQuoteNode = findParentNodeOfType([nodes.blockquote, nodes.listItem, nodes.taskItem])(selection);
22
+ if (listTypeOrBlockQuoteNode) {
23
+ content = listTypeOrBlockQuoteNode.node;
24
+ isTopLevelNode = listTypeOrBlockQuoteNode.node.type === nodes.blockquote ? listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCKQUOTE : listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.LIST_TYPE;
25
+ } else {
26
+ const paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
27
+ if (paragraphOrHeadingNode) {
28
+ content = paragraphOrHeadingNode.node;
29
+ isTopLevelNode = paragraphOrHeadingNode.depth === TOP_LEVEL_NODE_DEPTHS.PARAGRAPH_OR_HEADING;
30
+ }
31
+ }
32
+ }
33
+ return !content || !isTopLevelNode;
34
+ };
@@ -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 { getIsFormatMenuHidden } from './getIsFormatMenuHidden';
3
4
  export const blockMenuPluginKey = new PluginKey('blockMenuPlugin');
4
5
 
5
6
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -9,14 +10,23 @@ export const createPlugin = () => {
9
10
  key: blockMenuPluginKey,
10
11
  state: {
11
12
  init() {
12
- return {};
13
+ return {
14
+ isFormatMenuHidden: false
15
+ };
13
16
  },
14
17
  apply: (tr, currentPluginState) => {
15
18
  const meta = tr.getMeta(blockMenuPluginKey);
16
19
  if (meta) {
17
- return meta;
20
+ return {
21
+ ...currentPluginState,
22
+ ...meta
23
+ };
18
24
  }
19
- return currentPluginState;
25
+ const isFormatMenuHidden = getIsFormatMenuHidden(tr);
26
+ return {
27
+ ...currentPluginState,
28
+ isFormatMenuHidden
29
+ };
20
30
  }
21
31
  }
22
32
  });
@@ -6,6 +6,7 @@ import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
6
6
  import CopyBlockMenuItem from './copy-block';
7
7
  import { CopyLinkDropdownItem } from './copy-link';
8
8
  import { DeleteDropdownItem } from './delete-button';
9
+ import { FormatMenuSection } from './format-menu-section';
9
10
  import { MoveDownDropdownItem } from './move-down';
10
11
  import { MoveUpDropdownItem } from './move-up';
11
12
  const getMoveUpMoveDownMenuComponents = api => {
@@ -33,7 +34,7 @@ const getMoveUpMoveDownMenuComponents = api => {
33
34
  })
34
35
  }];
35
36
  };
36
- const getFormatMenuComponents = () => {
37
+ const getFormatMenuComponents = api => {
37
38
  return [{
38
39
  type: 'block-menu-nested',
39
40
  key: NESTED_FORMAT_MENU.key,
@@ -80,7 +81,9 @@ const getFormatMenuComponents = () => {
80
81
  component: ({
81
82
  children
82
83
  }) => {
83
- return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
84
+ return /*#__PURE__*/React.createElement(FormatMenuSection, {
85
+ api: api
86
+ }, children);
84
87
  }
85
88
  }];
86
89
  };
@@ -88,15 +91,16 @@ export const getBlockMenuComponents = ({
88
91
  api,
89
92
  config
90
93
  }) => {
91
- return [...getFormatMenuComponents(), {
94
+ return [...getFormatMenuComponents(api), {
92
95
  type: 'block-menu-section',
93
96
  key: COPY_MENU_SECTION.key,
94
97
  rank: BLOCK_MENU_SECTION_RANK[COPY_MENU_SECTION.key],
95
98
  component: ({
96
99
  children
97
100
  }) => {
101
+ var _api$blockMenu$shared;
98
102
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
99
- hasSeparator: true
103
+ hasSeparator: !(api !== null && api !== void 0 && (_api$blockMenu$shared = api.blockMenu.sharedState.currentState()) !== null && _api$blockMenu$shared !== void 0 && _api$blockMenu$shared.isFormatMenuHidden)
100
104
  }, children);
101
105
  }
102
106
  }, {
@@ -3,7 +3,9 @@ import { useIntl, injectIntl } from 'react-intl-next';
3
3
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import LinkIcon from '@atlaskit/icon/core/link';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
6
7
  import { copyLink } from './utils/copyLink';
8
+ import { isNestedNode } from './utils/isNestedNode';
7
9
  const CopyLinkDropdownItemContent = ({
8
10
  api,
9
11
  config
@@ -26,6 +28,16 @@ const CopyLinkDropdownItemContent = ({
26
28
  api === null || api === void 0 ? void 0 : api.core.actions.focus();
27
29
  return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
28
30
  }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api]);
31
+ const checkIsNestedNode = useCallback(() => {
32
+ var _api$selection, _api$selection$shared, _api$selection$shared2;
33
+ const selection = api === null || api === void 0 ? void 0 : (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : (_api$selection$shared = _api$selection.sharedState) === null || _api$selection$shared === void 0 ? void 0 : (_api$selection$shared2 = _api$selection$shared.currentState()) === null || _api$selection$shared2 === void 0 ? void 0 : _api$selection$shared2.selection;
34
+ return isNestedNode(selection);
35
+ }, [api]);
36
+
37
+ // Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested
38
+ if (!fg('platform_editor_adf_with_localid') || checkIsNestedNode()) {
39
+ return null;
40
+ }
29
41
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
30
42
  onClick: handleClick,
31
43
  elemBefore: /*#__PURE__*/React.createElement(LinkIcon, {
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
3
+ import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
4
+ export const FormatMenuSection = ({
5
+ children,
6
+ api
7
+ }) => {
8
+ const isFormatMenuHidden = useSharedPluginStateSelector(api, 'blockMenu.isFormatMenuHidden');
9
+ if (isFormatMenuHidden) {
10
+ return null;
11
+ }
12
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
13
+ };
@@ -0,0 +1,51 @@
1
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
2
+
3
+ /**
4
+ * Determines if a node is nested (not at top-level) based on its depth and context.
5
+ *
6
+ * Simple rules:
7
+ * - Depth 0-1: Always top-level (not nested)
8
+ * - Depth 2: Top-level for blockquotes and task lists
9
+ * - Depth 3: Top-level for list items only
10
+ * - Depth 4+: Always nested
11
+ *
12
+ * @param selection - The current ProseMirror selection
13
+ * @returns true if nested, false if top-level
14
+ */
15
+ export const isNestedNode = selection => {
16
+ if (!selection) {
17
+ return false;
18
+ }
19
+ const {
20
+ $from
21
+ } = selection;
22
+ const depth = $from.depth;
23
+ if ($from.depth > 0 && selection instanceof NodeSelection) {
24
+ return true;
25
+ }
26
+
27
+ // Depth 0-1: Always top-level
28
+ if (depth <= 1) {
29
+ return false;
30
+ }
31
+
32
+ // Depth 4+: Always nested
33
+ if (depth > 3) {
34
+ return true;
35
+ }
36
+
37
+ // Check parent node type for depth 2-3
38
+ const parentNode = $from.node(depth - 1);
39
+ if (!parentNode) {
40
+ return true;
41
+ }
42
+ const parentType = parentNode.type.name;
43
+
44
+ // Special cases where content is still top-level
45
+ if (parentType === 'listItem' && depth === 3 || parentType === 'blockquote' && depth === 2 || parentType === 'taskList' && depth === 2) {
46
+ return false;
47
+ }
48
+
49
+ // Everything else at depth 2-3 is nested
50
+ return true;
51
+ };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { createBlockMenuRegistry } from './editor-actions';
3
3
  import { formatNode as _formatNode } from './editor-commands/formatNode';
4
- import { createPlugin } from './pm-plugins/main';
4
+ import { blockMenuPluginKey, createPlugin } from './pm-plugins/main';
5
5
  import BlockMenu from './ui/block-menu';
6
6
  import { getBlockMenuComponents } from './ui/block-menu-components';
7
7
  export var blockMenuPlugin = function blockMenuPlugin(_ref) {
@@ -33,6 +33,18 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
33
33
  return _formatNode(targetType);
34
34
  }
35
35
  },
36
+ getSharedState: function getSharedState(editorState) {
37
+ if (!editorState) {
38
+ return;
39
+ }
40
+ var pluginState = blockMenuPluginKey.getState(editorState);
41
+ if (!pluginState) {
42
+ return;
43
+ }
44
+ return {
45
+ isFormatMenuHidden: pluginState === null || pluginState === void 0 ? void 0 : pluginState.isFormatMenuHidden
46
+ };
47
+ },
36
48
  contentComponent: function contentComponent(_ref2) {
37
49
  var editorView = _ref2.editorView,
38
50
  popupsMountPoint = _ref2.popupsMountPoint,
@@ -13,6 +13,19 @@ var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeTy
13
13
  });
14
14
  return Fragment.from(validTransformedContent);
15
15
  };
16
+ var filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
17
+ var withValidMarks = [];
18
+ content.forEach(function (node) {
19
+ if (node.marks.length > 0) {
20
+ var allowedMarks = targetNodeType.allowedMarks(node.marks);
21
+ var updatedNode = node.mark(allowedMarks);
22
+ withValidMarks.push(updatedNode);
23
+ } else {
24
+ withValidMarks.push(node);
25
+ }
26
+ });
27
+ return Fragment.from(withValidMarks);
28
+ };
16
29
 
17
30
  /**
18
31
  * Transform selection to container type
@@ -32,6 +45,13 @@ export var transformToContainer = function transformToContainer(_ref) {
32
45
  if (targetNodeType === schema.nodes.blockquote) {
33
46
  transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
34
47
  }
48
+
49
+ // Preserve marks that are allowed in the target node type
50
+ // e.g. blocks (heading/ paragraph) with alignment need to remove alignment
51
+ // as panel/ blockQuote/ expands does not support alignment
52
+ if (sourceNode.type === schema.nodes.paragraph || sourceNode.type === schema.nodes.heading) {
53
+ transformedContent = filterMarksForTargetNodeType(transformedContent, targetNodeType);
54
+ }
35
55
  var newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
36
56
  if (!newNode) {
37
57
  return null;
@@ -0,0 +1,34 @@
1
+ import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
2
+ var TOP_LEVEL_NODE_DEPTHS = {
3
+ LIST_TYPE: 2,
4
+ PARAGRAPH_OR_HEADING: 1,
5
+ BLOCKQUOTE: 1,
6
+ BLOCK: 0
7
+ };
8
+ export var getIsFormatMenuHidden = function getIsFormatMenuHidden(tr) {
9
+ var selection = tr.selection;
10
+ var nodes = tr.doc.type.schema.nodes;
11
+ if (selection.from === selection.to || selection.empty || !nodes) {
12
+ return false;
13
+ }
14
+ var content;
15
+ var isTopLevelNode = false;
16
+ var selectedNode = findSelectedNodeOfType([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
17
+ if (selectedNode) {
18
+ content = selectedNode.node;
19
+ isTopLevelNode = selectedNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCK;
20
+ } else {
21
+ var listTypeOrBlockQuoteNode = findParentNodeOfType([nodes.blockquote, nodes.listItem, nodes.taskItem])(selection);
22
+ if (listTypeOrBlockQuoteNode) {
23
+ content = listTypeOrBlockQuoteNode.node;
24
+ isTopLevelNode = listTypeOrBlockQuoteNode.node.type === nodes.blockquote ? listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.BLOCKQUOTE : listTypeOrBlockQuoteNode.depth === TOP_LEVEL_NODE_DEPTHS.LIST_TYPE;
25
+ } else {
26
+ var paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
27
+ if (paragraphOrHeadingNode) {
28
+ content = paragraphOrHeadingNode.node;
29
+ isTopLevelNode = paragraphOrHeadingNode.depth === TOP_LEVEL_NODE_DEPTHS.PARAGRAPH_OR_HEADING;
30
+ }
31
+ }
32
+ }
33
+ return !content || !isTopLevelNode;
34
+ };
@@ -1,5 +1,9 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ 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; }
3
+ 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; }
1
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { getIsFormatMenuHidden } from './getIsFormatMenuHidden';
3
7
  export var blockMenuPluginKey = new PluginKey('blockMenuPlugin');
4
8
 
5
9
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -9,14 +13,19 @@ export var createPlugin = function createPlugin() {
9
13
  key: blockMenuPluginKey,
10
14
  state: {
11
15
  init: function init() {
12
- return {};
16
+ return {
17
+ isFormatMenuHidden: false
18
+ };
13
19
  },
14
20
  apply: function apply(tr, currentPluginState) {
15
21
  var meta = tr.getMeta(blockMenuPluginKey);
16
22
  if (meta) {
17
- return meta;
23
+ return _objectSpread(_objectSpread({}, currentPluginState), meta);
18
24
  }
19
- return currentPluginState;
25
+ var isFormatMenuHidden = getIsFormatMenuHidden(tr);
26
+ return _objectSpread(_objectSpread({}, currentPluginState), {}, {
27
+ isFormatMenuHidden: isFormatMenuHidden
28
+ });
20
29
  }
21
30
  }
22
31
  });
@@ -7,6 +7,7 @@ import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
7
7
  import CopyBlockMenuItem from './copy-block';
8
8
  import { CopyLinkDropdownItem } from './copy-link';
9
9
  import { DeleteDropdownItem } from './delete-button';
10
+ import { FormatMenuSection } from './format-menu-section';
10
11
  import { MoveDownDropdownItem } from './move-down';
11
12
  import { MoveUpDropdownItem } from './move-up';
12
13
  var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
@@ -38,7 +39,7 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
38
39
  }
39
40
  }];
40
41
  };
41
- var getFormatMenuComponents = function getFormatMenuComponents() {
42
+ var getFormatMenuComponents = function getFormatMenuComponents(api) {
42
43
  return [{
43
44
  type: 'block-menu-nested',
44
45
  key: NESTED_FORMAT_MENU.key,
@@ -84,21 +85,24 @@ var getFormatMenuComponents = function getFormatMenuComponents() {
84
85
  rank: 100,
85
86
  component: function component(_ref3) {
86
87
  var children = _ref3.children;
87
- return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
88
+ return /*#__PURE__*/React.createElement(FormatMenuSection, {
89
+ api: api
90
+ }, children);
88
91
  }
89
92
  }];
90
93
  };
91
94
  export var getBlockMenuComponents = function getBlockMenuComponents(_ref4) {
92
95
  var api = _ref4.api,
93
96
  config = _ref4.config;
94
- return [].concat(_toConsumableArray(getFormatMenuComponents()), [{
97
+ return [].concat(_toConsumableArray(getFormatMenuComponents(api)), [{
95
98
  type: 'block-menu-section',
96
99
  key: COPY_MENU_SECTION.key,
97
100
  rank: BLOCK_MENU_SECTION_RANK[COPY_MENU_SECTION.key],
98
101
  component: function component(_ref5) {
102
+ var _api$blockMenu$shared;
99
103
  var children = _ref5.children;
100
104
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
101
- hasSeparator: true
105
+ hasSeparator: !(api !== null && api !== void 0 && (_api$blockMenu$shared = api.blockMenu.sharedState.currentState()) !== null && _api$blockMenu$shared !== void 0 && _api$blockMenu$shared.isFormatMenuHidden)
102
106
  }, children);
103
107
  }
104
108
  }, {
@@ -3,7 +3,9 @@ import { useIntl, injectIntl } from 'react-intl-next';
3
3
  import { blockMenuMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import LinkIcon from '@atlaskit/icon/core/link';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
6
7
  import { copyLink } from './utils/copyLink';
8
+ import { isNestedNode } from './utils/isNestedNode';
7
9
  var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
8
10
  var api = _ref.api,
9
11
  config = _ref.config;
@@ -23,6 +25,16 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
23
25
  api === null || api === void 0 || api.core.actions.focus();
24
26
  return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
25
27
  }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api]);
28
+ var checkIsNestedNode = useCallback(function () {
29
+ var _api$selection;
30
+ var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState) === null || _api$selection === void 0 || (_api$selection = _api$selection.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
31
+ return isNestedNode(selection);
32
+ }, [api]);
33
+
34
+ // Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested
35
+ if (!fg('platform_editor_adf_with_localid') || checkIsNestedNode()) {
36
+ return null;
37
+ }
26
38
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
27
39
  onClick: handleClick,
28
40
  elemBefore: /*#__PURE__*/React.createElement(LinkIcon, {
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
3
+ import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
4
+ export var FormatMenuSection = function FormatMenuSection(_ref) {
5
+ var children = _ref.children,
6
+ api = _ref.api;
7
+ var isFormatMenuHidden = useSharedPluginStateSelector(api, 'blockMenu.isFormatMenuHidden');
8
+ if (isFormatMenuHidden) {
9
+ return null;
10
+ }
11
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
12
+ };
@@ -0,0 +1,49 @@
1
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
2
+
3
+ /**
4
+ * Determines if a node is nested (not at top-level) based on its depth and context.
5
+ *
6
+ * Simple rules:
7
+ * - Depth 0-1: Always top-level (not nested)
8
+ * - Depth 2: Top-level for blockquotes and task lists
9
+ * - Depth 3: Top-level for list items only
10
+ * - Depth 4+: Always nested
11
+ *
12
+ * @param selection - The current ProseMirror selection
13
+ * @returns true if nested, false if top-level
14
+ */
15
+ export var isNestedNode = function isNestedNode(selection) {
16
+ if (!selection) {
17
+ return false;
18
+ }
19
+ var $from = selection.$from;
20
+ var depth = $from.depth;
21
+ if ($from.depth > 0 && selection instanceof NodeSelection) {
22
+ return true;
23
+ }
24
+
25
+ // Depth 0-1: Always top-level
26
+ if (depth <= 1) {
27
+ return false;
28
+ }
29
+
30
+ // Depth 4+: Always nested
31
+ if (depth > 3) {
32
+ return true;
33
+ }
34
+
35
+ // Check parent node type for depth 2-3
36
+ var parentNode = $from.node(depth - 1);
37
+ if (!parentNode) {
38
+ return true;
39
+ }
40
+ var parentType = parentNode.type.name;
41
+
42
+ // Special cases where content is still top-level
43
+ if (parentType === 'listItem' && depth === 3 || parentType === 'blockquote' && depth === 2 || parentType === 'taskList' && depth === 2) {
44
+ return false;
45
+ }
46
+
47
+ // Everything else at depth 2-3 is nested
48
+ return true;
49
+ };
@@ -19,6 +19,9 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
19
19
  OptionalPlugin<DecorationsPlugin>
20
20
  ];
21
21
  pluginConfiguration?: BlockMenuPluginOptions;
22
+ sharedState: {
23
+ isFormatMenuHidden?: boolean;
24
+ } | undefined;
22
25
  }>;
23
26
  export type BlockMenuPluginOptions = {
24
27
  /**
@@ -0,0 +1,2 @@
1
+ import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const getIsFormatMenuHidden: (tr: ReadonlyTransaction) => boolean;
@@ -1,6 +1,8 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
3
  export declare const blockMenuPluginKey: PluginKey<any>;
4
- type BlockMenuPluginState = {};
4
+ type BlockMenuPluginState = {
5
+ isFormatMenuHidden: boolean;
6
+ };
5
7
  export declare const createPlugin: () => SafePlugin<BlockMenuPluginState>;
6
8
  export {};
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
4
+ export declare const FormatMenuSection: ({ children, api, }: {
5
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
6
+ children: React.ReactNode;
7
+ }) => React.JSX.Element | null;
@@ -0,0 +1,14 @@
1
+ import { type Selection } from '@atlaskit/editor-prosemirror/state';
2
+ /**
3
+ * Determines if a node is nested (not at top-level) based on its depth and context.
4
+ *
5
+ * Simple rules:
6
+ * - Depth 0-1: Always top-level (not nested)
7
+ * - Depth 2: Top-level for blockquotes and task lists
8
+ * - Depth 3: Top-level for list items only
9
+ * - Depth 4+: Always nested
10
+ *
11
+ * @param selection - The current ProseMirror selection
12
+ * @returns true if nested, false if top-level
13
+ */
14
+ export declare const isNestedNode: (selection: Selection | undefined) => boolean;
@@ -19,6 +19,9 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
19
19
  OptionalPlugin<DecorationsPlugin>
20
20
  ];
21
21
  pluginConfiguration?: BlockMenuPluginOptions;
22
+ sharedState: {
23
+ isFormatMenuHidden?: boolean;
24
+ } | undefined;
22
25
  }>;
23
26
  export type BlockMenuPluginOptions = {
24
27
  /**
@@ -0,0 +1,2 @@
1
+ import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const getIsFormatMenuHidden: (tr: ReadonlyTransaction) => boolean;
@@ -1,6 +1,8 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
3
  export declare const blockMenuPluginKey: PluginKey<any>;
4
- type BlockMenuPluginState = {};
4
+ type BlockMenuPluginState = {
5
+ isFormatMenuHidden: boolean;
6
+ };
5
7
  export declare const createPlugin: () => SafePlugin<BlockMenuPluginState>;
6
8
  export {};
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
4
+ export declare const FormatMenuSection: ({ children, api, }: {
5
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
6
+ children: React.ReactNode;
7
+ }) => React.JSX.Element | null;
@@ -0,0 +1,14 @@
1
+ import { type Selection } from '@atlaskit/editor-prosemirror/state';
2
+ /**
3
+ * Determines if a node is nested (not at top-level) based on its depth and context.
4
+ *
5
+ * Simple rules:
6
+ * - Depth 0-1: Always top-level (not nested)
7
+ * - Depth 2: Top-level for blockquotes and task lists
8
+ * - Depth 3: Top-level for list items only
9
+ * - Depth 4+: Always nested
10
+ *
11
+ * @param selection - The current ProseMirror selection
12
+ * @returns true if nested, false if top-level
13
+ */
14
+ export declare const isNestedNode: (selection: Selection | undefined) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -46,7 +46,7 @@
46
46
  "@babel/runtime": "^7.0.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@atlaskit/editor-common": "^108.5.0",
49
+ "@atlaskit/editor-common": "^108.6.0",
50
50
  "react": "^18.2.0",
51
51
  "react-intl-next": "npm:react-intl@^5.18.1"
52
52
  },
@@ -85,5 +85,10 @@
85
85
  "import-no-extraneous-disable-for-examples-and-docs"
86
86
  ]
87
87
  }
88
+ },
89
+ "platform-feature-flags": {
90
+ "platform_editor_adf_with_localid": {
91
+ "type": "boolean"
92
+ }
88
93
  }
89
94
  }