@atlaskit/editor-plugin-block-menu 6.0.10 → 6.0.12
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 +14 -0
- package/dist/cjs/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +1 -12
- package/dist/cjs/editor-commands/transform-node-utils/utils.js +11 -33
- package/dist/cjs/ui/block-menu-components.js +12 -0
- package/dist/cjs/ui/block-menu-renderer/BlockMenuComponent.js +3 -3
- package/dist/cjs/ui/block-menu-renderer/utils.js +4 -7
- package/dist/cjs/ui/hooks/useSuggestedItems.js +4 -37
- package/dist/cjs/ui/utils/createMenuItemsMap.js +19 -0
- package/dist/cjs/ui/utils/getSuggestedItemsFromSelection.js +40 -0
- package/dist/es2019/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +2 -13
- package/dist/es2019/editor-commands/transform-node-utils/utils.js +10 -32
- package/dist/es2019/ui/block-menu-components.js +13 -1
- package/dist/es2019/ui/block-menu-renderer/BlockMenuComponent.js +3 -3
- package/dist/es2019/ui/block-menu-renderer/utils.js +4 -7
- package/dist/es2019/ui/hooks/useSuggestedItems.js +4 -28
- package/dist/es2019/ui/utils/createMenuItemsMap.js +9 -0
- package/dist/es2019/ui/utils/getSuggestedItemsFromSelection.js +30 -0
- package/dist/esm/editor-commands/transform-node-utils/steps/wrapMixedContentStep.js +2 -13
- package/dist/esm/editor-commands/transform-node-utils/utils.js +10 -32
- package/dist/esm/ui/block-menu-components.js +12 -0
- package/dist/esm/ui/block-menu-renderer/BlockMenuComponent.js +3 -3
- package/dist/esm/ui/block-menu-renderer/utils.js +4 -7
- package/dist/esm/ui/hooks/useSuggestedItems.js +4 -37
- package/dist/esm/ui/utils/createMenuItemsMap.js +13 -0
- package/dist/esm/ui/utils/getSuggestedItemsFromSelection.js +35 -0
- package/dist/types/blockMenuPluginType.d.ts +1 -0
- package/dist/types/editor-commands/transform-node-utils/utils.d.ts +5 -10
- package/dist/types/ui/block-menu-renderer/utils.d.ts +2 -3
- package/dist/types/ui/utils/createMenuItemsMap.d.ts +6 -0
- package/dist/types/ui/utils/getSuggestedItemsFromSelection.d.ts +6 -0
- package/dist/types-ts4.5/blockMenuPluginType.d.ts +1 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/utils.d.ts +5 -10
- package/dist/types-ts4.5/ui/block-menu-renderer/utils.d.ts +2 -3
- package/dist/types-ts4.5/ui/utils/createMenuItemsMap.d.ts +6 -0
- package/dist/types-ts4.5/ui/utils/getSuggestedItemsFromSelection.d.ts +6 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-menu
|
|
2
2
|
|
|
3
|
+
## 6.0.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`b909e5f47ea91`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b909e5f47ea91) -
|
|
8
|
+
EDITOR-4159 Make sure block-menu-item type component return null when tranform disabled
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
11
|
+
## 6.0.11
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
|
|
3
17
|
## 6.0.10
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -155,18 +155,7 @@ var wrapMixedContentStep = exports.wrapMixedContentStep = function wrapMixedCont
|
|
|
155
155
|
(_currentContainerCont = currentContainerContent).push.apply(_currentContainerCont, (0, _toConsumableArray2.default)((0, _marks.removeDisallowedMarks)([node], validationType)));
|
|
156
156
|
};
|
|
157
157
|
var handleCodeblockTextNode = function handleCodeblockTextNode(node) {
|
|
158
|
-
|
|
159
|
-
var parts = (0, _utils.splitTextNodeForCodeBlock)(node, schema);
|
|
160
|
-
parts.forEach(function (part) {
|
|
161
|
-
if (typeof part === 'string') {
|
|
162
|
-
// Text content - add to current codeBlock
|
|
163
|
-
currentContainerContent.push(part);
|
|
164
|
-
} else {
|
|
165
|
-
// Incompatible inline node wrapped in paragraph - break it out
|
|
166
|
-
flushCurrentContainer();
|
|
167
|
-
result.push(part);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
158
|
+
currentContainerContent.push((0, _utils.createTextContent)(node));
|
|
170
159
|
};
|
|
171
160
|
var handleConvertibleTextNode = function handleConvertibleTextNode(node) {
|
|
172
161
|
var paragraph = (0, _utils.convertTextNodeToParagraph)(node, schema);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.isTextNode = exports.getTargetNodeTypeNameInContext = exports.getSelectedNode = exports.getBlockNodesInRange = exports.createTextContent = exports.convertTextNodeToParagraph = exports.convertNestedExpandToExpand = exports.convertExpandToNestedExpand = void 0;
|
|
7
7
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
8
|
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
9
9
|
var _editorTables = require("@atlaskit/editor-tables");
|
|
@@ -131,42 +131,20 @@ var getBlockNodesInRange = exports.getBlockNodesInRange = function getBlockNodes
|
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* - strings (text content that can go into codeBlock)
|
|
137
|
-
* - PMNodes (incompatible inline nodes wrapped in paragraphs that need to break out)
|
|
134
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
135
|
+
* hardbreaks to newlines.
|
|
138
136
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* @param node - The text node (paragraph or heading) to split
|
|
142
|
-
* @param schema - The schema to use for creating paragraph nodes
|
|
143
|
-
* @returns Array of strings (for codeBlock) and PMNodes (to break out)
|
|
137
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
138
|
+
* @returns The text content string.
|
|
144
139
|
*/
|
|
145
|
-
var
|
|
146
|
-
var
|
|
147
|
-
var currentText = '';
|
|
148
|
-
node.content.forEach(function (child) {
|
|
140
|
+
var createTextContent = exports.createTextContent = function createTextContent(node) {
|
|
141
|
+
var textContent = node.children.map(function (child) {
|
|
149
142
|
if (child.isText) {
|
|
150
|
-
|
|
143
|
+
return child.text;
|
|
151
144
|
} else if (child.type.name === 'hardBreak') {
|
|
152
|
-
|
|
153
|
-
} else {
|
|
154
|
-
// Incompatible inline node (status, inlineExtension, etc.)
|
|
155
|
-
// Flush accumulated text if any
|
|
156
|
-
if (currentText) {
|
|
157
|
-
result.push(currentText);
|
|
158
|
-
currentText = '';
|
|
159
|
-
}
|
|
160
|
-
// Wrap the inline node in a paragraph and add it to break out
|
|
161
|
-
var paragraph = schema.nodes.paragraph.create({}, child);
|
|
162
|
-
result.push(paragraph);
|
|
145
|
+
return '\n';
|
|
163
146
|
}
|
|
147
|
+
return '';
|
|
164
148
|
});
|
|
165
|
-
|
|
166
|
-
// Don't forget remaining text (or empty string for empty nodes)
|
|
167
|
-
// Always push at least an empty string so empty paragraphs create empty codeBlocks
|
|
168
|
-
if (currentText || result.length === 0) {
|
|
169
|
-
result.push(currentText);
|
|
170
|
-
}
|
|
171
|
-
return result;
|
|
149
|
+
return textContent.join('');
|
|
172
150
|
};
|
|
@@ -19,6 +19,8 @@ var _moveDown = require("./move-down");
|
|
|
19
19
|
var _moveUp = require("./move-up");
|
|
20
20
|
var _suggestedItemsMenuSection = require("./suggested-items-menu-section");
|
|
21
21
|
var _suggestedMenuItems = require("./suggested-menu-items");
|
|
22
|
+
var _createMenuItemsMap = require("./utils/createMenuItemsMap");
|
|
23
|
+
var _getSuggestedItemsFromSelection = require("./utils/getSuggestedItemsFromSelection");
|
|
22
24
|
var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
|
|
23
25
|
return [{
|
|
24
26
|
type: 'block-menu-item',
|
|
@@ -95,6 +97,16 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
|
|
|
95
97
|
return /*#__PURE__*/_react.default.createElement(_suggestedMenuItems.SuggestedMenuItems, {
|
|
96
98
|
api: api
|
|
97
99
|
});
|
|
100
|
+
},
|
|
101
|
+
isHidden: function isHidden() {
|
|
102
|
+
var _api$blockMenu, _api$selection, _api$blockControls;
|
|
103
|
+
var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
104
|
+
var menuItemsMap = (0, _createMenuItemsMap.createMenuItemsMap)(blockMenuComponents);
|
|
105
|
+
var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
|
|
106
|
+
var preservedSelection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
|
|
107
|
+
var currentSelection = preservedSelection || selection;
|
|
108
|
+
var suggestedItems = (0, _getSuggestedItemsFromSelection.getSuggestedItemsFromSelection)(menuItemsMap, currentSelection);
|
|
109
|
+
return suggestedItems.length === 0;
|
|
98
110
|
}
|
|
99
111
|
}, {
|
|
100
112
|
type: 'block-menu-section',
|
|
@@ -15,15 +15,15 @@ var BlockMenuComponent = exports.BlockMenuComponent = function BlockMenuComponen
|
|
|
15
15
|
var registeredComponent = _ref.registeredComponent,
|
|
16
16
|
childrenMap = _ref.childrenMap,
|
|
17
17
|
fallbacks = _ref.fallbacks;
|
|
18
|
+
if (!(0, _utils.willComponentRender)(registeredComponent, childrenMap)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
18
21
|
if (registeredComponent.type === 'block-menu-item') {
|
|
19
22
|
var ItemComponent = registeredComponent.component || fallbacks['block-menu-item'];
|
|
20
23
|
return /*#__PURE__*/_react.default.createElement(ItemComponent, {
|
|
21
24
|
key: registeredComponent.key
|
|
22
25
|
});
|
|
23
26
|
}
|
|
24
|
-
if (!(0, _utils.willComponentRender)(registeredComponent, childrenMap)) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
27
|
var ParentComponent = registeredComponent.component || fallbacks[registeredComponent.type];
|
|
28
28
|
var childrenMapKey = (0, _utils.getChildrenMapKey)(registeredComponent.key, registeredComponent.type);
|
|
29
29
|
var registeredComponents = childrenMap.get(childrenMapKey);
|
|
@@ -106,21 +106,18 @@ var buildChildrenMap = exports.buildChildrenMap = function buildChildrenMap(comp
|
|
|
106
106
|
* Determines whether a component will render based on its type and children
|
|
107
107
|
*
|
|
108
108
|
* Rules:
|
|
109
|
-
* - An item will not render if has
|
|
110
|
-
* - A nested menu will render if
|
|
109
|
+
* - An item will not render if it has isHidden that returns true OR if its component returns null (fallback)
|
|
110
|
+
* - A nested menu will render if at least one section, that has at least one registered child
|
|
111
111
|
* - A section will render if it has at least one registered child component that will render
|
|
112
112
|
*
|
|
113
|
-
* NOTE: This requires invoking each item's component function to check for null return
|
|
114
113
|
*/
|
|
115
114
|
var _willComponentRender = exports.willComponentRender = function willComponentRender(registeredComponent, childrenMap) {
|
|
116
115
|
if (registeredComponent.type === 'block-menu-item') {
|
|
117
|
-
|
|
116
|
+
var _registeredComponent$;
|
|
117
|
+
return !(registeredComponent !== null && registeredComponent !== void 0 && (_registeredComponent$ = registeredComponent.isHidden) !== null && _registeredComponent$ !== void 0 && _registeredComponent$.call(registeredComponent));
|
|
118
118
|
}
|
|
119
119
|
var childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
|
|
120
120
|
var registeredComponents = childrenMap.get(childrenMapKey) || [];
|
|
121
|
-
if (registeredComponent.type === 'block-menu-nested') {
|
|
122
|
-
return registeredComponents.length > 0;
|
|
123
|
-
}
|
|
124
121
|
return registeredComponents.some(function (childComponent) {
|
|
125
122
|
return _willComponentRender(childComponent, childrenMap);
|
|
126
123
|
});
|
|
@@ -6,9 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.useSuggestedItems = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var _suggestedItemsRank = require("../utils/suggested-items-rank");
|
|
9
|
+
var _createMenuItemsMap = require("../utils/createMenuItemsMap");
|
|
10
|
+
var _getSuggestedItemsFromSelection = require("../utils/getSuggestedItemsFromSelection");
|
|
12
11
|
var useSuggestedItems = exports.useSuggestedItems = function useSuggestedItems(api) {
|
|
13
12
|
var _api$blockMenu;
|
|
14
13
|
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls', 'selection'], function (states) {
|
|
@@ -22,43 +21,11 @@ var useSuggestedItems = exports.useSuggestedItems = function useSuggestedItems(a
|
|
|
22
21
|
selection = _useSharedPluginState.selection;
|
|
23
22
|
var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
24
23
|
var menuItemsMap = (0, _react.useMemo)(function () {
|
|
25
|
-
|
|
26
|
-
return new Map();
|
|
27
|
-
}
|
|
28
|
-
return new Map(blockMenuComponents.filter(function (c) {
|
|
29
|
-
return c.type === 'block-menu-item';
|
|
30
|
-
}).map(function (item) {
|
|
31
|
-
return [item.key, item];
|
|
32
|
-
}));
|
|
24
|
+
return (0, _createMenuItemsMap.createMenuItemsMap)(blockMenuComponents);
|
|
33
25
|
}, [blockMenuComponents]);
|
|
34
26
|
var suggestedItems = (0, _react.useMemo)(function () {
|
|
35
27
|
var currentSelection = preservedSelection || selection;
|
|
36
|
-
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
39
|
-
var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(currentSelection),
|
|
40
|
-
range = _expandSelectionToBlo.range;
|
|
41
|
-
if (!range) {
|
|
42
|
-
return [];
|
|
43
|
-
}
|
|
44
|
-
var blockNodes = (0, _utils.getBlockNodesInRange)(range);
|
|
45
|
-
if (blockNodes.length === 0) {
|
|
46
|
-
return [];
|
|
47
|
-
}
|
|
48
|
-
var firstNodeType = blockNodes[0].type.name;
|
|
49
|
-
var allSameType = blockNodes.every(function (node) {
|
|
50
|
-
return node.type.name === firstNodeType;
|
|
51
|
-
});
|
|
52
|
-
if (!allSameType) {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
var nodeTypeName = firstNodeType;
|
|
56
|
-
var sortedKeys = (0, _suggestedItemsRank.getSortedSuggestedItems)(nodeTypeName);
|
|
57
|
-
return sortedKeys.map(function (key) {
|
|
58
|
-
return menuItemsMap.get(key);
|
|
59
|
-
}).filter(function (item) {
|
|
60
|
-
return item !== undefined;
|
|
61
|
-
});
|
|
28
|
+
return (0, _getSuggestedItemsFromSelection.getSuggestedItemsFromSelection)(menuItemsMap, currentSelection);
|
|
62
29
|
}, [menuItemsMap, preservedSelection, selection]);
|
|
63
30
|
return suggestedItems;
|
|
64
31
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createMenuItemsMap = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to create menu items map from block menu components.
|
|
9
|
+
*/
|
|
10
|
+
var createMenuItemsMap = exports.createMenuItemsMap = function createMenuItemsMap(blockMenuComponents) {
|
|
11
|
+
if (!blockMenuComponents) {
|
|
12
|
+
return new Map();
|
|
13
|
+
}
|
|
14
|
+
return new Map(blockMenuComponents.filter(function (c) {
|
|
15
|
+
return c.type === 'block-menu-item';
|
|
16
|
+
}).map(function (item) {
|
|
17
|
+
return [item.key, item];
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getSuggestedItemsFromSelection = void 0;
|
|
7
|
+
var _selection = require("@atlaskit/editor-common/selection");
|
|
8
|
+
var _utils = require("../../editor-commands/transform-node-utils/utils");
|
|
9
|
+
var _suggestedItemsRank = require("../utils/suggested-items-rank");
|
|
10
|
+
/**
|
|
11
|
+
* Pure function to calculate suggested items based on selection and menu components.
|
|
12
|
+
*/
|
|
13
|
+
var getSuggestedItemsFromSelection = exports.getSuggestedItemsFromSelection = function getSuggestedItemsFromSelection(menuItemsMap, currentSelection) {
|
|
14
|
+
if (menuItemsMap.size === 0 || !currentSelection) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(currentSelection),
|
|
18
|
+
range = _expandSelectionToBlo.range;
|
|
19
|
+
if (!range) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
var blockNodes = (0, _utils.getBlockNodesInRange)(range);
|
|
23
|
+
if (blockNodes.length === 0) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
var firstNodeType = blockNodes[0].type.name;
|
|
27
|
+
var allSameType = blockNodes.every(function (node) {
|
|
28
|
+
return node.type.name === firstNodeType;
|
|
29
|
+
});
|
|
30
|
+
if (!allSameType) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
var nodeTypeName = firstNodeType;
|
|
34
|
+
var sortedKeys = (0, _suggestedItemsRank.getSortedSuggestedItems)(nodeTypeName);
|
|
35
|
+
return sortedKeys.map(function (key) {
|
|
36
|
+
return menuItemsMap.get(key);
|
|
37
|
+
}).filter(function (item) {
|
|
38
|
+
return item !== undefined;
|
|
39
|
+
});
|
|
40
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
2
|
import { removeDisallowedMarks } from '../marks';
|
|
3
3
|
import { NODE_CATEGORY_BY_TYPE } from '../types';
|
|
4
|
-
import { convertTextNodeToParagraph,
|
|
4
|
+
import { convertTextNodeToParagraph, createTextContent, isTextNode } from '../utils';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a layout section with two columns, where the first column contains the provided content.
|
|
@@ -150,18 +150,7 @@ export const wrapMixedContentStep = (nodes, context) => {
|
|
|
150
150
|
currentContainerContent.push(...removeDisallowedMarks([node], validationType));
|
|
151
151
|
};
|
|
152
152
|
const handleCodeblockTextNode = node => {
|
|
153
|
-
|
|
154
|
-
const parts = splitTextNodeForCodeBlock(node, schema);
|
|
155
|
-
parts.forEach(part => {
|
|
156
|
-
if (typeof part === 'string') {
|
|
157
|
-
// Text content - add to current codeBlock
|
|
158
|
-
currentContainerContent.push(part);
|
|
159
|
-
} else {
|
|
160
|
-
// Incompatible inline node wrapped in paragraph - break it out
|
|
161
|
-
flushCurrentContainer();
|
|
162
|
-
result.push(part);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
153
|
+
currentContainerContent.push(createTextContent(node));
|
|
165
154
|
};
|
|
166
155
|
const handleConvertibleTextNode = node => {
|
|
167
156
|
const paragraph = convertTextNodeToParagraph(node, schema);
|
|
@@ -127,42 +127,20 @@ export const getBlockNodesInRange = range => {
|
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* - strings (text content that can go into codeBlock)
|
|
133
|
-
* - PMNodes (incompatible inline nodes wrapped in paragraphs that need to break out)
|
|
130
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
131
|
+
* hardbreaks to newlines.
|
|
134
132
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* @param node - The text node (paragraph or heading) to split
|
|
138
|
-
* @param schema - The schema to use for creating paragraph nodes
|
|
139
|
-
* @returns Array of strings (for codeBlock) and PMNodes (to break out)
|
|
133
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
134
|
+
* @returns The text content string.
|
|
140
135
|
*/
|
|
141
|
-
export const
|
|
142
|
-
const
|
|
143
|
-
let currentText = '';
|
|
144
|
-
node.content.forEach(child => {
|
|
136
|
+
export const createTextContent = node => {
|
|
137
|
+
const textContent = node.children.map(child => {
|
|
145
138
|
if (child.isText) {
|
|
146
|
-
|
|
139
|
+
return child.text;
|
|
147
140
|
} else if (child.type.name === 'hardBreak') {
|
|
148
|
-
|
|
149
|
-
} else {
|
|
150
|
-
// Incompatible inline node (status, inlineExtension, etc.)
|
|
151
|
-
// Flush accumulated text if any
|
|
152
|
-
if (currentText) {
|
|
153
|
-
result.push(currentText);
|
|
154
|
-
currentText = '';
|
|
155
|
-
}
|
|
156
|
-
// Wrap the inline node in a paragraph and add it to break out
|
|
157
|
-
const paragraph = schema.nodes.paragraph.create({}, child);
|
|
158
|
-
result.push(paragraph);
|
|
141
|
+
return '\n';
|
|
159
142
|
}
|
|
143
|
+
return '';
|
|
160
144
|
});
|
|
161
|
-
|
|
162
|
-
// Don't forget remaining text (or empty string for empty nodes)
|
|
163
|
-
// Always push at least an empty string so empty paragraphs create empty codeBlocks
|
|
164
|
-
if (currentText || result.length === 0) {
|
|
165
|
-
result.push(currentText);
|
|
166
|
-
}
|
|
167
|
-
return result;
|
|
145
|
+
return textContent.join('');
|
|
168
146
|
};
|
|
@@ -11,6 +11,8 @@ import { MoveDownDropdownItem } from './move-down';
|
|
|
11
11
|
import { MoveUpDropdownItem } from './move-up';
|
|
12
12
|
import { SuggestedItemsMenuSection } from './suggested-items-menu-section';
|
|
13
13
|
import { SuggestedMenuItems } from './suggested-menu-items';
|
|
14
|
+
import { createMenuItemsMap } from './utils/createMenuItemsMap';
|
|
15
|
+
import { getSuggestedItemsFromSelection } from './utils/getSuggestedItemsFromSelection';
|
|
14
16
|
const getMoveUpMoveDownMenuComponents = api => {
|
|
15
17
|
return [{
|
|
16
18
|
type: 'block-menu-item',
|
|
@@ -79,7 +81,17 @@ const getTurnIntoMenuComponents = api => {
|
|
|
79
81
|
},
|
|
80
82
|
component: () => /*#__PURE__*/React.createElement(SuggestedMenuItems, {
|
|
81
83
|
api: api
|
|
82
|
-
})
|
|
84
|
+
}),
|
|
85
|
+
isHidden: () => {
|
|
86
|
+
var _api$blockMenu, _api$selection, _api$selection$shared, _api$blockControls, _api$blockControls$sh;
|
|
87
|
+
const blockMenuComponents = api === null || api === void 0 ? void 0 : (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
88
|
+
const menuItemsMap = createMenuItemsMap(blockMenuComponents);
|
|
89
|
+
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.currentState()) === null || _api$selection$shared === void 0 ? void 0 : _api$selection$shared.selection;
|
|
90
|
+
const preservedSelection = api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : (_api$blockControls$sh = _api$blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.preservedSelection;
|
|
91
|
+
const currentSelection = preservedSelection || selection;
|
|
92
|
+
const suggestedItems = getSuggestedItemsFromSelection(menuItemsMap, currentSelection);
|
|
93
|
+
return suggestedItems.length === 0;
|
|
94
|
+
}
|
|
83
95
|
}, {
|
|
84
96
|
type: 'block-menu-section',
|
|
85
97
|
key: TRANSFORM_CREATE_MENU_SECTION.key,
|
|
@@ -9,15 +9,15 @@ export const BlockMenuComponent = ({
|
|
|
9
9
|
childrenMap,
|
|
10
10
|
fallbacks
|
|
11
11
|
}) => {
|
|
12
|
+
if (!willComponentRender(registeredComponent, childrenMap)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
12
15
|
if (registeredComponent.type === 'block-menu-item') {
|
|
13
16
|
const ItemComponent = registeredComponent.component || fallbacks['block-menu-item'];
|
|
14
17
|
return /*#__PURE__*/React.createElement(ItemComponent, {
|
|
15
18
|
key: registeredComponent.key
|
|
16
19
|
});
|
|
17
20
|
}
|
|
18
|
-
if (!willComponentRender(registeredComponent, childrenMap)) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
21
|
const ParentComponent = registeredComponent.component || fallbacks[registeredComponent.type];
|
|
22
22
|
const childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
|
|
23
23
|
const registeredComponents = childrenMap.get(childrenMapKey);
|
|
@@ -74,20 +74,17 @@ export const buildChildrenMap = components => {
|
|
|
74
74
|
* Determines whether a component will render based on its type and children
|
|
75
75
|
*
|
|
76
76
|
* Rules:
|
|
77
|
-
* - An item will not render if has
|
|
78
|
-
* - A nested menu will render if
|
|
77
|
+
* - An item will not render if it has isHidden that returns true OR if its component returns null (fallback)
|
|
78
|
+
* - A nested menu will render if at least one section, that has at least one registered child
|
|
79
79
|
* - A section will render if it has at least one registered child component that will render
|
|
80
80
|
*
|
|
81
|
-
* NOTE: This requires invoking each item's component function to check for null return
|
|
82
81
|
*/
|
|
83
82
|
export const willComponentRender = (registeredComponent, childrenMap) => {
|
|
84
83
|
if (registeredComponent.type === 'block-menu-item') {
|
|
85
|
-
|
|
84
|
+
var _registeredComponent$;
|
|
85
|
+
return !(registeredComponent !== null && registeredComponent !== void 0 && (_registeredComponent$ = registeredComponent.isHidden) !== null && _registeredComponent$ !== void 0 && _registeredComponent$.call(registeredComponent));
|
|
86
86
|
}
|
|
87
87
|
const childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
|
|
88
88
|
const registeredComponents = childrenMap.get(childrenMapKey) || [];
|
|
89
|
-
if (registeredComponent.type === 'block-menu-nested') {
|
|
90
|
-
return registeredComponents.length > 0;
|
|
91
|
-
}
|
|
92
89
|
return registeredComponents.some(childComponent => willComponentRender(childComponent, childrenMap));
|
|
93
90
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getSortedSuggestedItems } from '../utils/suggested-items-rank';
|
|
3
|
+
import { createMenuItemsMap } from '../utils/createMenuItemsMap';
|
|
4
|
+
import { getSuggestedItemsFromSelection } from '../utils/getSuggestedItemsFromSelection';
|
|
6
5
|
export const useSuggestedItems = api => {
|
|
7
6
|
var _api$blockMenu;
|
|
8
7
|
const {
|
|
@@ -17,34 +16,11 @@ export const useSuggestedItems = api => {
|
|
|
17
16
|
});
|
|
18
17
|
const blockMenuComponents = api === null || api === void 0 ? void 0 : (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
19
18
|
const menuItemsMap = useMemo(() => {
|
|
20
|
-
|
|
21
|
-
return new Map();
|
|
22
|
-
}
|
|
23
|
-
return new Map(blockMenuComponents.filter(c => c.type === 'block-menu-item').map(item => [item.key, item]));
|
|
19
|
+
return createMenuItemsMap(blockMenuComponents);
|
|
24
20
|
}, [blockMenuComponents]);
|
|
25
21
|
const suggestedItems = useMemo(() => {
|
|
26
22
|
const currentSelection = preservedSelection || selection;
|
|
27
|
-
|
|
28
|
-
return [];
|
|
29
|
-
}
|
|
30
|
-
const {
|
|
31
|
-
range
|
|
32
|
-
} = expandSelectionToBlockRange(currentSelection);
|
|
33
|
-
if (!range) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
const blockNodes = getBlockNodesInRange(range);
|
|
37
|
-
if (blockNodes.length === 0) {
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
const firstNodeType = blockNodes[0].type.name;
|
|
41
|
-
const allSameType = blockNodes.every(node => node.type.name === firstNodeType);
|
|
42
|
-
if (!allSameType) {
|
|
43
|
-
return [];
|
|
44
|
-
}
|
|
45
|
-
const nodeTypeName = firstNodeType;
|
|
46
|
-
const sortedKeys = getSortedSuggestedItems(nodeTypeName);
|
|
47
|
-
return sortedKeys.map(key => menuItemsMap.get(key)).filter(item => item !== undefined);
|
|
23
|
+
return getSuggestedItemsFromSelection(menuItemsMap, currentSelection);
|
|
48
24
|
}, [menuItemsMap, preservedSelection, selection]);
|
|
49
25
|
return suggestedItems;
|
|
50
26
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to create menu items map from block menu components.
|
|
3
|
+
*/
|
|
4
|
+
export const createMenuItemsMap = blockMenuComponents => {
|
|
5
|
+
if (!blockMenuComponents) {
|
|
6
|
+
return new Map();
|
|
7
|
+
}
|
|
8
|
+
return new Map(blockMenuComponents.filter(c => c.type === 'block-menu-item').map(item => [item.key, item]));
|
|
9
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
|
|
2
|
+
import { getBlockNodesInRange } from '../../editor-commands/transform-node-utils/utils';
|
|
3
|
+
import { getSortedSuggestedItems } from '../utils/suggested-items-rank';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Pure function to calculate suggested items based on selection and menu components.
|
|
7
|
+
*/
|
|
8
|
+
export const getSuggestedItemsFromSelection = (menuItemsMap, currentSelection) => {
|
|
9
|
+
if (menuItemsMap.size === 0 || !currentSelection) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const {
|
|
13
|
+
range
|
|
14
|
+
} = expandSelectionToBlockRange(currentSelection);
|
|
15
|
+
if (!range) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const blockNodes = getBlockNodesInRange(range);
|
|
19
|
+
if (blockNodes.length === 0) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const firstNodeType = blockNodes[0].type.name;
|
|
23
|
+
const allSameType = blockNodes.every(node => node.type.name === firstNodeType);
|
|
24
|
+
if (!allSameType) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const nodeTypeName = firstNodeType;
|
|
28
|
+
const sortedKeys = getSortedSuggestedItems(nodeTypeName);
|
|
29
|
+
return sortedKeys.map(key => menuItemsMap.get(key)).filter(item => item !== undefined);
|
|
30
|
+
};
|
|
@@ -2,7 +2,7 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
3
|
import { removeDisallowedMarks } from '../marks';
|
|
4
4
|
import { NODE_CATEGORY_BY_TYPE } from '../types';
|
|
5
|
-
import { convertTextNodeToParagraph,
|
|
5
|
+
import { convertTextNodeToParagraph, createTextContent, isTextNode } from '../utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Creates a layout section with two columns, where the first column contains the provided content.
|
|
@@ -149,18 +149,7 @@ export var wrapMixedContentStep = function wrapMixedContentStep(nodes, context)
|
|
|
149
149
|
(_currentContainerCont = currentContainerContent).push.apply(_currentContainerCont, _toConsumableArray(removeDisallowedMarks([node], validationType)));
|
|
150
150
|
};
|
|
151
151
|
var handleCodeblockTextNode = function handleCodeblockTextNode(node) {
|
|
152
|
-
|
|
153
|
-
var parts = splitTextNodeForCodeBlock(node, schema);
|
|
154
|
-
parts.forEach(function (part) {
|
|
155
|
-
if (typeof part === 'string') {
|
|
156
|
-
// Text content - add to current codeBlock
|
|
157
|
-
currentContainerContent.push(part);
|
|
158
|
-
} else {
|
|
159
|
-
// Incompatible inline node wrapped in paragraph - break it out
|
|
160
|
-
flushCurrentContainer();
|
|
161
|
-
result.push(part);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
152
|
+
currentContainerContent.push(createTextContent(node));
|
|
164
153
|
};
|
|
165
154
|
var handleConvertibleTextNode = function handleConvertibleTextNode(node) {
|
|
166
155
|
var paragraph = convertTextNodeToParagraph(node, schema);
|
|
@@ -126,42 +126,20 @@ export var getBlockNodesInRange = function getBlockNodesInRange(range) {
|
|
|
126
126
|
};
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* - strings (text content that can go into codeBlock)
|
|
132
|
-
* - PMNodes (incompatible inline nodes wrapped in paragraphs that need to break out)
|
|
129
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
130
|
+
* hardbreaks to newlines.
|
|
133
131
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* @param node - The text node (paragraph or heading) to split
|
|
137
|
-
* @param schema - The schema to use for creating paragraph nodes
|
|
138
|
-
* @returns Array of strings (for codeBlock) and PMNodes (to break out)
|
|
132
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
133
|
+
* @returns The text content string.
|
|
139
134
|
*/
|
|
140
|
-
export var
|
|
141
|
-
var
|
|
142
|
-
var currentText = '';
|
|
143
|
-
node.content.forEach(function (child) {
|
|
135
|
+
export var createTextContent = function createTextContent(node) {
|
|
136
|
+
var textContent = node.children.map(function (child) {
|
|
144
137
|
if (child.isText) {
|
|
145
|
-
|
|
138
|
+
return child.text;
|
|
146
139
|
} else if (child.type.name === 'hardBreak') {
|
|
147
|
-
|
|
148
|
-
} else {
|
|
149
|
-
// Incompatible inline node (status, inlineExtension, etc.)
|
|
150
|
-
// Flush accumulated text if any
|
|
151
|
-
if (currentText) {
|
|
152
|
-
result.push(currentText);
|
|
153
|
-
currentText = '';
|
|
154
|
-
}
|
|
155
|
-
// Wrap the inline node in a paragraph and add it to break out
|
|
156
|
-
var paragraph = schema.nodes.paragraph.create({}, child);
|
|
157
|
-
result.push(paragraph);
|
|
140
|
+
return '\n';
|
|
158
141
|
}
|
|
142
|
+
return '';
|
|
159
143
|
});
|
|
160
|
-
|
|
161
|
-
// Don't forget remaining text (or empty string for empty nodes)
|
|
162
|
-
// Always push at least an empty string so empty paragraphs create empty codeBlocks
|
|
163
|
-
if (currentText || result.length === 0) {
|
|
164
|
-
result.push(currentText);
|
|
165
|
-
}
|
|
166
|
-
return result;
|
|
144
|
+
return textContent.join('');
|
|
167
145
|
};
|
|
@@ -12,6 +12,8 @@ import { MoveDownDropdownItem } from './move-down';
|
|
|
12
12
|
import { MoveUpDropdownItem } from './move-up';
|
|
13
13
|
import { SuggestedItemsMenuSection } from './suggested-items-menu-section';
|
|
14
14
|
import { SuggestedMenuItems } from './suggested-menu-items';
|
|
15
|
+
import { createMenuItemsMap } from './utils/createMenuItemsMap';
|
|
16
|
+
import { getSuggestedItemsFromSelection } from './utils/getSuggestedItemsFromSelection';
|
|
15
17
|
var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
|
|
16
18
|
return [{
|
|
17
19
|
type: 'block-menu-item',
|
|
@@ -88,6 +90,16 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
|
|
|
88
90
|
return /*#__PURE__*/React.createElement(SuggestedMenuItems, {
|
|
89
91
|
api: api
|
|
90
92
|
});
|
|
93
|
+
},
|
|
94
|
+
isHidden: function isHidden() {
|
|
95
|
+
var _api$blockMenu, _api$selection, _api$blockControls;
|
|
96
|
+
var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
97
|
+
var menuItemsMap = createMenuItemsMap(blockMenuComponents);
|
|
98
|
+
var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
|
|
99
|
+
var preservedSelection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
|
|
100
|
+
var currentSelection = preservedSelection || selection;
|
|
101
|
+
var suggestedItems = getSuggestedItemsFromSelection(menuItemsMap, currentSelection);
|
|
102
|
+
return suggestedItems.length === 0;
|
|
91
103
|
}
|
|
92
104
|
}, {
|
|
93
105
|
type: 'block-menu-section',
|
|
@@ -8,15 +8,15 @@ export var BlockMenuComponent = function BlockMenuComponent(_ref) {
|
|
|
8
8
|
var registeredComponent = _ref.registeredComponent,
|
|
9
9
|
childrenMap = _ref.childrenMap,
|
|
10
10
|
fallbacks = _ref.fallbacks;
|
|
11
|
+
if (!willComponentRender(registeredComponent, childrenMap)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
11
14
|
if (registeredComponent.type === 'block-menu-item') {
|
|
12
15
|
var ItemComponent = registeredComponent.component || fallbacks['block-menu-item'];
|
|
13
16
|
return /*#__PURE__*/React.createElement(ItemComponent, {
|
|
14
17
|
key: registeredComponent.key
|
|
15
18
|
});
|
|
16
19
|
}
|
|
17
|
-
if (!willComponentRender(registeredComponent, childrenMap)) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
20
|
var ParentComponent = registeredComponent.component || fallbacks[registeredComponent.type];
|
|
21
21
|
var childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
|
|
22
22
|
var registeredComponents = childrenMap.get(childrenMapKey);
|
|
@@ -99,21 +99,18 @@ export var buildChildrenMap = function buildChildrenMap(components) {
|
|
|
99
99
|
* Determines whether a component will render based on its type and children
|
|
100
100
|
*
|
|
101
101
|
* Rules:
|
|
102
|
-
* - An item will not render if has
|
|
103
|
-
* - A nested menu will render if
|
|
102
|
+
* - An item will not render if it has isHidden that returns true OR if its component returns null (fallback)
|
|
103
|
+
* - A nested menu will render if at least one section, that has at least one registered child
|
|
104
104
|
* - A section will render if it has at least one registered child component that will render
|
|
105
105
|
*
|
|
106
|
-
* NOTE: This requires invoking each item's component function to check for null return
|
|
107
106
|
*/
|
|
108
107
|
var _willComponentRender = function willComponentRender(registeredComponent, childrenMap) {
|
|
109
108
|
if (registeredComponent.type === 'block-menu-item') {
|
|
110
|
-
|
|
109
|
+
var _registeredComponent$;
|
|
110
|
+
return !(registeredComponent !== null && registeredComponent !== void 0 && (_registeredComponent$ = registeredComponent.isHidden) !== null && _registeredComponent$ !== void 0 && _registeredComponent$.call(registeredComponent));
|
|
111
111
|
}
|
|
112
112
|
var childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
|
|
113
113
|
var registeredComponents = childrenMap.get(childrenMapKey) || [];
|
|
114
|
-
if (registeredComponent.type === 'block-menu-nested') {
|
|
115
|
-
return registeredComponents.length > 0;
|
|
116
|
-
}
|
|
117
114
|
return registeredComponents.some(function (childComponent) {
|
|
118
115
|
return _willComponentRender(childComponent, childrenMap);
|
|
119
116
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getSortedSuggestedItems } from '../utils/suggested-items-rank';
|
|
3
|
+
import { createMenuItemsMap } from '../utils/createMenuItemsMap';
|
|
4
|
+
import { getSuggestedItemsFromSelection } from '../utils/getSuggestedItemsFromSelection';
|
|
6
5
|
export var useSuggestedItems = function useSuggestedItems(api) {
|
|
7
6
|
var _api$blockMenu;
|
|
8
7
|
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls', 'selection'], function (states) {
|
|
@@ -16,43 +15,11 @@ export var useSuggestedItems = function useSuggestedItems(api) {
|
|
|
16
15
|
selection = _useSharedPluginState.selection;
|
|
17
16
|
var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
|
|
18
17
|
var menuItemsMap = useMemo(function () {
|
|
19
|
-
|
|
20
|
-
return new Map();
|
|
21
|
-
}
|
|
22
|
-
return new Map(blockMenuComponents.filter(function (c) {
|
|
23
|
-
return c.type === 'block-menu-item';
|
|
24
|
-
}).map(function (item) {
|
|
25
|
-
return [item.key, item];
|
|
26
|
-
}));
|
|
18
|
+
return createMenuItemsMap(blockMenuComponents);
|
|
27
19
|
}, [blockMenuComponents]);
|
|
28
20
|
var suggestedItems = useMemo(function () {
|
|
29
21
|
var currentSelection = preservedSelection || selection;
|
|
30
|
-
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
var _expandSelectionToBlo = expandSelectionToBlockRange(currentSelection),
|
|
34
|
-
range = _expandSelectionToBlo.range;
|
|
35
|
-
if (!range) {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
var blockNodes = getBlockNodesInRange(range);
|
|
39
|
-
if (blockNodes.length === 0) {
|
|
40
|
-
return [];
|
|
41
|
-
}
|
|
42
|
-
var firstNodeType = blockNodes[0].type.name;
|
|
43
|
-
var allSameType = blockNodes.every(function (node) {
|
|
44
|
-
return node.type.name === firstNodeType;
|
|
45
|
-
});
|
|
46
|
-
if (!allSameType) {
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
var nodeTypeName = firstNodeType;
|
|
50
|
-
var sortedKeys = getSortedSuggestedItems(nodeTypeName);
|
|
51
|
-
return sortedKeys.map(function (key) {
|
|
52
|
-
return menuItemsMap.get(key);
|
|
53
|
-
}).filter(function (item) {
|
|
54
|
-
return item !== undefined;
|
|
55
|
-
});
|
|
22
|
+
return getSuggestedItemsFromSelection(menuItemsMap, currentSelection);
|
|
56
23
|
}, [menuItemsMap, preservedSelection, selection]);
|
|
57
24
|
return suggestedItems;
|
|
58
25
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to create menu items map from block menu components.
|
|
3
|
+
*/
|
|
4
|
+
export var createMenuItemsMap = function createMenuItemsMap(blockMenuComponents) {
|
|
5
|
+
if (!blockMenuComponents) {
|
|
6
|
+
return new Map();
|
|
7
|
+
}
|
|
8
|
+
return new Map(blockMenuComponents.filter(function (c) {
|
|
9
|
+
return c.type === 'block-menu-item';
|
|
10
|
+
}).map(function (item) {
|
|
11
|
+
return [item.key, item];
|
|
12
|
+
}));
|
|
13
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
|
|
2
|
+
import { getBlockNodesInRange } from '../../editor-commands/transform-node-utils/utils';
|
|
3
|
+
import { getSortedSuggestedItems } from '../utils/suggested-items-rank';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Pure function to calculate suggested items based on selection and menu components.
|
|
7
|
+
*/
|
|
8
|
+
export var getSuggestedItemsFromSelection = function getSuggestedItemsFromSelection(menuItemsMap, currentSelection) {
|
|
9
|
+
if (menuItemsMap.size === 0 || !currentSelection) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
var _expandSelectionToBlo = expandSelectionToBlockRange(currentSelection),
|
|
13
|
+
range = _expandSelectionToBlo.range;
|
|
14
|
+
if (!range) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
var blockNodes = getBlockNodesInRange(range);
|
|
18
|
+
if (blockNodes.length === 0) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
var firstNodeType = blockNodes[0].type.name;
|
|
22
|
+
var allSameType = blockNodes.every(function (node) {
|
|
23
|
+
return node.type.name === firstNodeType;
|
|
24
|
+
});
|
|
25
|
+
if (!allSameType) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
var nodeTypeName = firstNodeType;
|
|
29
|
+
var sortedKeys = getSortedSuggestedItems(nodeTypeName);
|
|
30
|
+
return sortedKeys.map(function (key) {
|
|
31
|
+
return menuItemsMap.get(key);
|
|
32
|
+
}).filter(function (item) {
|
|
33
|
+
return item !== undefined;
|
|
34
|
+
});
|
|
35
|
+
};
|
|
@@ -106,6 +106,7 @@ export type RegisterBlockMenuSection = BlockMenuSection & {
|
|
|
106
106
|
};
|
|
107
107
|
export type RegisterBlockMenuItem = BlockMenuItem & {
|
|
108
108
|
component?: BlockMenuItemComponent;
|
|
109
|
+
isHidden?: () => boolean;
|
|
109
110
|
parent: Parent<BlockMenuSection>;
|
|
110
111
|
};
|
|
111
112
|
export type RegisterBlockMenuComponent = RegisterBlockMenuNested | RegisterBlockMenuSection | RegisterBlockMenuItem;
|
|
@@ -29,15 +29,10 @@ export declare const convertExpandToNestedExpand: (node: PMNode, schema: Schema)
|
|
|
29
29
|
export declare const convertTextNodeToParagraph: (node: PMNode, schema: Schema) => PMNode | null;
|
|
30
30
|
export declare const getBlockNodesInRange: (range: NodeRange) => PMNode[];
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* - strings (text content that can go into codeBlock)
|
|
35
|
-
* - PMNodes (incompatible inline nodes wrapped in paragraphs that need to break out)
|
|
32
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
33
|
+
* hardbreaks to newlines.
|
|
36
34
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param node - The text node (paragraph or heading) to split
|
|
40
|
-
* @param schema - The schema to use for creating paragraph nodes
|
|
41
|
-
* @returns Array of strings (for codeBlock) and PMNodes (to break out)
|
|
35
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
36
|
+
* @returns The text content string.
|
|
42
37
|
*/
|
|
43
|
-
export declare const
|
|
38
|
+
export declare const createTextContent: (node: PMNode) => string;
|
|
@@ -28,10 +28,9 @@ export declare const buildChildrenMap: (components: RegisterBlockMenuComponent[]
|
|
|
28
28
|
* Determines whether a component will render based on its type and children
|
|
29
29
|
*
|
|
30
30
|
* Rules:
|
|
31
|
-
* - An item will not render if has
|
|
32
|
-
* - A nested menu will render if
|
|
31
|
+
* - An item will not render if it has isHidden that returns true OR if its component returns null (fallback)
|
|
32
|
+
* - A nested menu will render if at least one section, that has at least one registered child
|
|
33
33
|
* - A section will render if it has at least one registered child component that will render
|
|
34
34
|
*
|
|
35
|
-
* NOTE: This requires invoking each item's component function to check for null return
|
|
36
35
|
*/
|
|
37
36
|
export declare const willComponentRender: (registeredComponent: RegisterBlockMenuComponent, childrenMap: ChildrenMap) => boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
|
+
import type { BlockMenuPlugin, RegisterBlockMenuItem } from '../../blockMenuPluginType';
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to create menu items map from block menu components.
|
|
5
|
+
*/
|
|
6
|
+
export declare const createMenuItemsMap: (blockMenuComponents: ReturnType<ExtractInjectionAPI<BlockMenuPlugin>["blockMenu"]["actions"]["getBlockMenuComponents"]> | undefined) => Map<string, RegisterBlockMenuItem>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { RegisterBlockMenuItem } from '../../blockMenuPluginType';
|
|
3
|
+
/**
|
|
4
|
+
* Pure function to calculate suggested items based on selection and menu components.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getSuggestedItemsFromSelection: (menuItemsMap: Map<string, RegisterBlockMenuItem>, currentSelection: Selection | null | undefined) => RegisterBlockMenuItem[];
|
|
@@ -106,6 +106,7 @@ export type RegisterBlockMenuSection = BlockMenuSection & {
|
|
|
106
106
|
};
|
|
107
107
|
export type RegisterBlockMenuItem = BlockMenuItem & {
|
|
108
108
|
component?: BlockMenuItemComponent;
|
|
109
|
+
isHidden?: () => boolean;
|
|
109
110
|
parent: Parent<BlockMenuSection>;
|
|
110
111
|
};
|
|
111
112
|
export type RegisterBlockMenuComponent = RegisterBlockMenuNested | RegisterBlockMenuSection | RegisterBlockMenuItem;
|
|
@@ -29,15 +29,10 @@ export declare const convertExpandToNestedExpand: (node: PMNode, schema: Schema)
|
|
|
29
29
|
export declare const convertTextNodeToParagraph: (node: PMNode, schema: Schema) => PMNode | null;
|
|
30
30
|
export declare const getBlockNodesInRange: (range: NodeRange) => PMNode[];
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* - strings (text content that can go into codeBlock)
|
|
35
|
-
* - PMNodes (incompatible inline nodes wrapped in paragraphs that need to break out)
|
|
32
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
33
|
+
* hardbreaks to newlines.
|
|
36
34
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param node - The text node (paragraph or heading) to split
|
|
40
|
-
* @param schema - The schema to use for creating paragraph nodes
|
|
41
|
-
* @returns Array of strings (for codeBlock) and PMNodes (to break out)
|
|
35
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
36
|
+
* @returns The text content string.
|
|
42
37
|
*/
|
|
43
|
-
export declare const
|
|
38
|
+
export declare const createTextContent: (node: PMNode) => string;
|
|
@@ -28,10 +28,9 @@ export declare const buildChildrenMap: (components: RegisterBlockMenuComponent[]
|
|
|
28
28
|
* Determines whether a component will render based on its type and children
|
|
29
29
|
*
|
|
30
30
|
* Rules:
|
|
31
|
-
* - An item will not render if has
|
|
32
|
-
* - A nested menu will render if
|
|
31
|
+
* - An item will not render if it has isHidden that returns true OR if its component returns null (fallback)
|
|
32
|
+
* - A nested menu will render if at least one section, that has at least one registered child
|
|
33
33
|
* - A section will render if it has at least one registered child component that will render
|
|
34
34
|
*
|
|
35
|
-
* NOTE: This requires invoking each item's component function to check for null return
|
|
36
35
|
*/
|
|
37
36
|
export declare const willComponentRender: (registeredComponent: RegisterBlockMenuComponent, childrenMap: ChildrenMap) => boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
|
+
import type { BlockMenuPlugin, RegisterBlockMenuItem } from '../../blockMenuPluginType';
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to create menu items map from block menu components.
|
|
5
|
+
*/
|
|
6
|
+
export declare const createMenuItemsMap: (blockMenuComponents: ReturnType<ExtractInjectionAPI<BlockMenuPlugin>["blockMenu"]["actions"]["getBlockMenuComponents"]> | undefined) => Map<string, RegisterBlockMenuItem>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { RegisterBlockMenuItem } from '../../blockMenuPluginType';
|
|
3
|
+
/**
|
|
4
|
+
* Pure function to calculate suggested items based on selection and menu components.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getSuggestedItemsFromSelection: (menuItemsMap: Map<string, RegisterBlockMenuItem>, currentSelection: Selection | null | undefined) => RegisterBlockMenuItem[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-block-menu",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.12",
|
|
4
4
|
"description": "BlockMenu plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -38,18 +38,18 @@
|
|
|
38
38
|
"@atlaskit/editor-prosemirror": "^7.2.0",
|
|
39
39
|
"@atlaskit/editor-shared-styles": "^3.10.0",
|
|
40
40
|
"@atlaskit/editor-tables": "^2.9.0",
|
|
41
|
-
"@atlaskit/editor-toolbar": "^0.
|
|
42
|
-
"@atlaskit/flag": "^17.
|
|
41
|
+
"@atlaskit/editor-toolbar": "^0.19.0",
|
|
42
|
+
"@atlaskit/flag": "^17.8.0",
|
|
43
43
|
"@atlaskit/icon": "^29.4.0",
|
|
44
44
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
45
45
|
"@atlaskit/platform-feature-flags-react": "^0.4.0",
|
|
46
46
|
"@atlaskit/primitives": "^17.0.0",
|
|
47
|
-
"@atlaskit/tmp-editor-statsig": "^16.
|
|
47
|
+
"@atlaskit/tmp-editor-statsig": "^16.11.0",
|
|
48
48
|
"@atlaskit/tokens": "^9.1.0",
|
|
49
49
|
"@babel/runtime": "^7.0.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@atlaskit/editor-common": "^111.
|
|
52
|
+
"@atlaskit/editor-common": "^111.7.0",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
55
55
|
},
|