@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.
- package/CHANGELOG.md +18 -0
- package/dist/cjs/blockMenuPlugin.js +12 -0
- package/dist/cjs/editor-commands/transforms/container-transforms.js +20 -0
- package/dist/cjs/pm-plugins/getIsFormatMenuHidden.js +40 -0
- package/dist/cjs/pm-plugins/main.js +13 -3
- package/dist/cjs/ui/block-menu-components.js +8 -4
- package/dist/cjs/ui/copy-link.js +12 -0
- package/dist/cjs/ui/format-menu-section.js +19 -0
- package/dist/cjs/ui/utils/isNestedNode.js +54 -0
- package/dist/es2019/blockMenuPlugin.js +13 -1
- package/dist/es2019/editor-commands/transforms/container-transforms.js +20 -0
- package/dist/es2019/pm-plugins/getIsFormatMenuHidden.js +34 -0
- package/dist/es2019/pm-plugins/main.js +13 -3
- package/dist/es2019/ui/block-menu-components.js +8 -4
- package/dist/es2019/ui/copy-link.js +12 -0
- package/dist/es2019/ui/format-menu-section.js +13 -0
- package/dist/es2019/ui/utils/isNestedNode.js +51 -0
- package/dist/esm/blockMenuPlugin.js +13 -1
- package/dist/esm/editor-commands/transforms/container-transforms.js +20 -0
- package/dist/esm/pm-plugins/getIsFormatMenuHidden.js +34 -0
- package/dist/esm/pm-plugins/main.js +12 -3
- package/dist/esm/ui/block-menu-components.js +8 -4
- package/dist/esm/ui/copy-link.js +12 -0
- package/dist/esm/ui/format-menu-section.js +12 -0
- package/dist/esm/ui/utils/isNestedNode.js +49 -0
- package/dist/types/blockMenuPluginType.d.ts +3 -0
- package/dist/types/pm-plugins/getIsFormatMenuHidden.d.ts +2 -0
- package/dist/types/pm-plugins/main.d.ts +3 -1
- package/dist/types/ui/format-menu-section.d.ts +7 -0
- package/dist/types/ui/utils/isNestedNode.d.ts +14 -0
- package/dist/types-ts4.5/blockMenuPluginType.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/getIsFormatMenuHidden.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +3 -1
- package/dist/types-ts4.5/ui/format-menu-section.d.ts +7 -0
- package/dist/types-ts4.5/ui/utils/isNestedNode.d.ts +14 -0
- 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
|
-
|
|
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(
|
|
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:
|
|
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
|
}, {
|
package/dist/cjs/ui/copy-link.js
CHANGED
|
@@ -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
|
|
20
|
+
return {
|
|
21
|
+
...currentPluginState,
|
|
22
|
+
...meta
|
|
23
|
+
};
|
|
18
24
|
}
|
|
19
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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
|
}, {
|
package/dist/esm/ui/copy-link.js
CHANGED
|
@@ -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
|
/**
|
|
@@ -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
|
/**
|
|
@@ -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.
|
|
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.
|
|
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
|
}
|