@atlaskit/editor-plugin-block-menu 5.2.15 → 5.2.17
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 +21 -0
- package/dist/cjs/editor-commands/transform-node-utils/nodeChecks.js +33 -0
- package/dist/cjs/editor-commands/transform-node-utils/steps/flattenListStep.js +7 -12
- package/dist/cjs/editor-commands/transform-node-utils/steps/listToDecisionListStep.js +3 -3
- package/dist/cjs/editor-commands/transform-node-utils/steps/listToListStep.js +11 -11
- package/dist/cjs/editor-commands/transform-node-utils/steps/wrapTextToCodeblock.js +21 -0
- package/dist/cjs/editor-commands/transform-node-utils/transform.js +11 -11
- package/dist/cjs/editor-commands/transform-node-utils/utils.js +20 -7
- package/dist/cjs/editor-commands/transform-node-utils/wrapIntoListStep.js +29 -7
- package/dist/cjs/editor-commands/transformNode.js +3 -2
- package/dist/cjs/ui/block-menu-components.js +1 -3
- package/dist/cjs/ui/block-menu.js +38 -33
- package/dist/cjs/ui/copy-link.js +2 -2
- package/dist/cjs/ui/delete-section.js +1 -8
- package/dist/es2019/editor-commands/transform-node-utils/nodeChecks.js +23 -0
- package/dist/es2019/editor-commands/transform-node-utils/steps/flattenListStep.js +7 -6
- package/dist/es2019/editor-commands/transform-node-utils/steps/listToDecisionListStep.js +3 -4
- package/dist/es2019/editor-commands/transform-node-utils/steps/listToListStep.js +11 -12
- package/dist/es2019/editor-commands/transform-node-utils/steps/wrapTextToCodeblock.js +18 -0
- package/dist/es2019/editor-commands/transform-node-utils/transform.js +11 -11
- package/dist/es2019/editor-commands/transform-node-utils/utils.js +19 -4
- package/dist/es2019/editor-commands/transform-node-utils/wrapIntoListStep.js +29 -7
- package/dist/es2019/editor-commands/transformNode.js +3 -2
- package/dist/es2019/ui/block-menu-components.js +1 -3
- package/dist/es2019/ui/block-menu.js +38 -33
- package/dist/es2019/ui/copy-link.js +2 -2
- package/dist/es2019/ui/delete-section.js +0 -7
- package/dist/esm/editor-commands/transform-node-utils/nodeChecks.js +27 -0
- package/dist/esm/editor-commands/transform-node-utils/steps/flattenListStep.js +7 -12
- package/dist/esm/editor-commands/transform-node-utils/steps/listToDecisionListStep.js +3 -4
- package/dist/esm/editor-commands/transform-node-utils/steps/listToListStep.js +11 -12
- package/dist/esm/editor-commands/transform-node-utils/steps/wrapTextToCodeblock.js +16 -0
- package/dist/esm/editor-commands/transform-node-utils/transform.js +11 -11
- package/dist/esm/editor-commands/transform-node-utils/utils.js +19 -6
- package/dist/esm/editor-commands/transform-node-utils/wrapIntoListStep.js +29 -7
- package/dist/esm/editor-commands/transformNode.js +3 -2
- package/dist/esm/ui/block-menu-components.js +1 -3
- package/dist/esm/ui/block-menu.js +38 -33
- package/dist/esm/ui/copy-link.js +2 -2
- package/dist/esm/ui/delete-section.js +1 -8
- package/dist/types/editor-commands/transform-node-utils/nodeChecks.d.ts +17 -0
- package/dist/types/editor-commands/transform-node-utils/steps/wrapTextToCodeblock.d.ts +9 -0
- package/dist/types/editor-commands/transform-node-utils/utils.d.ts +8 -1
- package/dist/types/editor-commands/transform-node-utils/wrapIntoListStep.d.ts +7 -1
- package/dist/types/ui/delete-section.d.ts +1 -4
- package/dist/types-ts4.5/editor-commands/transform-node-utils/nodeChecks.d.ts +17 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/wrapTextToCodeblock.d.ts +9 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/utils.d.ts +8 -1
- package/dist/types-ts4.5/editor-commands/transform-node-utils/wrapIntoListStep.d.ts +7 -1
- package/dist/types-ts4.5/ui/delete-section.d.ts +1 -4
- package/package.json +4 -4
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { isListWithIndentation } from '../nodeChecks';
|
|
4
3
|
/**
|
|
5
4
|
* Recursively converts nested lists to the target list type.
|
|
6
5
|
* This function handles the conversion of both the list container and its items,
|
|
@@ -14,13 +13,13 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
14
13
|
const schema = node.type.schema;
|
|
15
14
|
const taskListType = schema.nodes.taskList;
|
|
16
15
|
const isSourceTaskList = node.type === taskListType;
|
|
17
|
-
const isTargetTaskList = targetListType ===
|
|
16
|
+
const isTargetTaskList = targetListType === taskListType.name;
|
|
18
17
|
const convertFromTaskListStructure = (node, targetListType, targetItemType) => {
|
|
19
18
|
const schema = node.type.schema;
|
|
20
19
|
const targetListNodeType = schema.nodes[targetListType];
|
|
21
20
|
const transformedContent = [];
|
|
22
21
|
node.forEach(child => {
|
|
23
|
-
if (
|
|
22
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
24
23
|
// This is a nested list - it should become a child of the previous item
|
|
25
24
|
if (transformedContent.length > 0) {
|
|
26
25
|
const previousItem = transformedContent[transformedContent.length - 1];
|
|
@@ -32,7 +31,7 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
32
31
|
}
|
|
33
32
|
// If there's no previous item, skip this nested list (orphaned)
|
|
34
33
|
} else {
|
|
35
|
-
const transformedItem = transformListItem(child,
|
|
34
|
+
const transformedItem = transformListItem(child, targetListType, targetItemType);
|
|
36
35
|
if (transformedItem) {
|
|
37
36
|
transformedContent.push(transformedItem);
|
|
38
37
|
}
|
|
@@ -45,19 +44,19 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
45
44
|
const targetListNodeType = schema.nodes[targetListType];
|
|
46
45
|
const transformedContent = [];
|
|
47
46
|
node.forEach(itemNode => {
|
|
48
|
-
const transformedItem = transformListItem(itemNode,
|
|
47
|
+
const transformedItem = transformListItem(itemNode, targetListType, targetItemType, true);
|
|
49
48
|
if (transformedItem) {
|
|
50
49
|
transformedContent.push(transformedItem);
|
|
51
50
|
}
|
|
52
51
|
itemNode.forEach(child => {
|
|
53
|
-
if (
|
|
52
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
54
53
|
transformedContent.push(transformList(child, targetListType, targetItemType, unsupportedContent));
|
|
55
54
|
}
|
|
56
55
|
});
|
|
57
56
|
});
|
|
58
57
|
return targetListNodeType.create(node.attrs, transformedContent);
|
|
59
58
|
};
|
|
60
|
-
const transformListItem = (itemNode,
|
|
59
|
+
const transformListItem = (itemNode, targetListType, targetItemType, excludeNestedLists = false) => {
|
|
61
60
|
const schema = itemNode.type.schema;
|
|
62
61
|
const targetItemNodeType = schema.nodes[targetItemType];
|
|
63
62
|
const isTargetTaskItem = targetItemType === 'taskItem';
|
|
@@ -71,7 +70,7 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
71
70
|
} else if (child.isText) {
|
|
72
71
|
inlineContent.push(child);
|
|
73
72
|
// Nested lists will be extracted and placed as siblings in the taskList
|
|
74
|
-
} else if (!
|
|
73
|
+
} else if (!isListWithIndentation(child.type.name, schema)) {
|
|
75
74
|
unsupportedContent.push(child);
|
|
76
75
|
}
|
|
77
76
|
});
|
|
@@ -82,7 +81,7 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
82
81
|
transformedContent.push(paragraphType.create(null, itemNode.content));
|
|
83
82
|
} else {
|
|
84
83
|
itemNode.forEach(child => {
|
|
85
|
-
if (
|
|
84
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
86
85
|
if (excludeNestedLists) {
|
|
87
86
|
// Skip nested lists - they will be handled separately as siblings
|
|
88
87
|
return;
|
|
@@ -102,7 +101,7 @@ const transformList = (node, targetListType, targetItemType, unsupportedContent)
|
|
|
102
101
|
const targetListNodeType = schema.nodes[targetListType];
|
|
103
102
|
const transformedContent = [];
|
|
104
103
|
node.forEach(childNode => {
|
|
105
|
-
const transformedItem =
|
|
104
|
+
const transformedItem = isListWithIndentation(childNode.type.name, schema) ? transformList(childNode, targetListType, targetItemType, unsupportedContent) : transformListItem(childNode, targetListType, targetItemType);
|
|
106
105
|
if (transformedItem) {
|
|
107
106
|
transformedContent.push(transformedItem);
|
|
108
107
|
}
|
|
@@ -187,7 +186,7 @@ export const listToListStep = (nodes, context) => {
|
|
|
187
186
|
} = context;
|
|
188
187
|
const unsupportedContent = [];
|
|
189
188
|
const transformedNodes = nodes.map(node => {
|
|
190
|
-
if (
|
|
189
|
+
if (isListWithIndentation(node.type.name, schema)) {
|
|
191
190
|
const targetItemType = targetNodeTypeName === 'taskList' ? 'taskItem' : 'listItem';
|
|
192
191
|
return transformList(node, targetNodeTypeName, targetItemType, unsupportedContent);
|
|
193
192
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createTextContent } from '../utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transforms a paragraph (or heading) into a codeBlock by extracting its text content.
|
|
5
|
+
* This step handles the conversion of inline content (including marks) to plain text,
|
|
6
|
+
* which is required because codeBlocks can only contain plain text nodes.
|
|
7
|
+
*
|
|
8
|
+
* Example: paragraph with bold/italic/status → codeBlock with plain text
|
|
9
|
+
*/
|
|
10
|
+
export const wrapTextToCodeblockStep = (nodes, context) => {
|
|
11
|
+
const {
|
|
12
|
+
schema
|
|
13
|
+
} = context;
|
|
14
|
+
return nodes.map(node => {
|
|
15
|
+
const codeBlockNode = schema.nodes.codeBlock.createAndFill({}, schema.text(createTextContent(node)));
|
|
16
|
+
return codeBlockNode !== null && codeBlockNode !== void 0 ? codeBlockNode : node;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
@@ -8,6 +8,7 @@ import { unwrapLayoutStep } from './steps/unwrapLayoutStep';
|
|
|
8
8
|
import { unwrapListStep } from './steps/unwrapListStep';
|
|
9
9
|
import { wrapBlockquoteToDecisionListStep } from './steps/wrapBlockquoteToDecisionListStep';
|
|
10
10
|
import { wrapMixedContentStep } from './steps/wrapMixedContentStep';
|
|
11
|
+
import { wrapTextToCodeblockStep } from './steps/wrapTextToCodeblock';
|
|
11
12
|
import { stubStep } from './stubStep';
|
|
12
13
|
import { NODE_CATEGORY_BY_TYPE, toNodeTypeValue } from './types';
|
|
13
14
|
import { unwrapExpandStep } from './unwrapExpandStep';
|
|
@@ -16,14 +17,6 @@ import { wrapIntoLayoutStep } from './wrapIntoLayoutStep';
|
|
|
16
17
|
import { wrapIntoListStep } from './wrapIntoListStep';
|
|
17
18
|
import { wrapStep } from './wrapStep';
|
|
18
19
|
|
|
19
|
-
// Exampled step for overrides:
|
|
20
|
-
// - open Block menu on a paragraph, click 'Panel' in the Turn into'
|
|
21
|
-
// - expected to put paragraph into a panel
|
|
22
|
-
const wrapIntoPanelStep = (nodes, context) => {
|
|
23
|
-
const newNode = context.schema.nodes.panel.createAndFill({}, nodes);
|
|
24
|
-
return newNode ? [newNode] : [];
|
|
25
|
-
};
|
|
26
|
-
|
|
27
20
|
// Transform steps for combinations of node categories (block/container/list/text)
|
|
28
21
|
const TRANSFORM_STEPS = {
|
|
29
22
|
atomic: {
|
|
@@ -46,8 +39,8 @@ const TRANSFORM_STEPS = {
|
|
|
46
39
|
},
|
|
47
40
|
text: {
|
|
48
41
|
atomic: undefined,
|
|
49
|
-
container: [
|
|
50
|
-
list: [
|
|
42
|
+
container: [wrapStep],
|
|
43
|
+
list: [wrapIntoListStep],
|
|
51
44
|
text: [stubStep]
|
|
52
45
|
}
|
|
53
46
|
};
|
|
@@ -56,7 +49,8 @@ const TRANSFORM_STEPS = {
|
|
|
56
49
|
// using generic rules/steps from TRANSFORM_STEPS.
|
|
57
50
|
const TRANSFORM_STEPS_OVERRIDE = {
|
|
58
51
|
paragraph: {
|
|
59
|
-
|
|
52
|
+
codeBlock: [wrapTextToCodeblockStep],
|
|
53
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
60
54
|
},
|
|
61
55
|
panel: {
|
|
62
56
|
layoutSection: [unwrapStep, wrapIntoLayoutStep],
|
|
@@ -130,6 +124,12 @@ const TRANSFORM_STEPS_OVERRIDE = {
|
|
|
130
124
|
orderedList: [decisionListToListStep],
|
|
131
125
|
taskList: [decisionListToListStep],
|
|
132
126
|
layoutSection: [wrapIntoLayoutStep]
|
|
127
|
+
},
|
|
128
|
+
blockCard: {
|
|
129
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
130
|
+
},
|
|
131
|
+
embedCard: {
|
|
132
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
133
133
|
}
|
|
134
134
|
};
|
|
135
135
|
const getTransformStepsForNodeTypes = (selectedNodeTypeName, targetNodeTypeName) => {
|
|
@@ -50,10 +50,6 @@ export const getTargetNodeTypeNameInContext = (nodeTypeName, isNested) => {
|
|
|
50
50
|
}
|
|
51
51
|
return nodeTypeName;
|
|
52
52
|
};
|
|
53
|
-
export const isListType = (node, schema) => {
|
|
54
|
-
const lists = [schema.nodes.taskList, schema.nodes.bulletList, schema.nodes.orderedList];
|
|
55
|
-
return lists.some(list => list === node.type);
|
|
56
|
-
};
|
|
57
53
|
|
|
58
54
|
/**
|
|
59
55
|
* Converts a nestedExpand to a regular expand node.
|
|
@@ -100,4 +96,23 @@ export const getBlockNodesInRange = range => {
|
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
return blockNodes;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Iterates over a nodes children and extracting text content, removing all other inline content and converting
|
|
103
|
+
* hardbreaks to newlines.
|
|
104
|
+
*
|
|
105
|
+
* @param node - The node to create text content from (should be paragraph)
|
|
106
|
+
* @returns The text content string.
|
|
107
|
+
*/
|
|
108
|
+
export const createTextContent = node => {
|
|
109
|
+
const textContent = node.children.map(child => {
|
|
110
|
+
if (child.isText) {
|
|
111
|
+
return child.text;
|
|
112
|
+
} else if (child.type.name === 'hardBreak') {
|
|
113
|
+
return '\n';
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
116
|
+
});
|
|
117
|
+
return textContent.join('');
|
|
103
118
|
};
|
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
import { isListWithTextContentOnly } from './nodeChecks';
|
|
2
|
+
const wrapIntoTaskOrDecisionList = (nodes, targetNodeTypeName, schema) => {
|
|
3
|
+
const itemNodeType = targetNodeTypeName === 'taskList' ? schema.nodes.taskItem : schema.nodes.decisionItem;
|
|
4
|
+
const inlineContent = nodes.flatMap(node => {
|
|
5
|
+
if (node.isTextblock) {
|
|
6
|
+
return node.children;
|
|
7
|
+
} else if (node.isText) {
|
|
8
|
+
return [node];
|
|
9
|
+
}
|
|
10
|
+
return [];
|
|
11
|
+
});
|
|
12
|
+
const itemNode = itemNodeType.create({}, inlineContent);
|
|
13
|
+
const outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, itemNode);
|
|
14
|
+
return outputNode ? [outputNode] : nodes;
|
|
15
|
+
};
|
|
16
|
+
const wrapIntoBulletOrOrderedList = (nodes, targetNodeTypeName, schema) => {
|
|
17
|
+
const listItemNode = schema.nodes.listItem.createAndFill({}, nodes);
|
|
18
|
+
const outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, listItemNode);
|
|
19
|
+
return outputNode ? [outputNode] : nodes;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wraps nodes into bullet list, numbered list, task list, or decision list.
|
|
24
|
+
*
|
|
25
|
+
* @param nodes - The nodes to wrap.
|
|
26
|
+
* @param context - The transformation context containing schema and target node type.
|
|
27
|
+
* @returns The wrapped nodes.
|
|
28
|
+
*/
|
|
2
29
|
export const wrapIntoListStep = (nodes, context) => {
|
|
3
30
|
const {
|
|
4
31
|
schema,
|
|
5
32
|
targetNodeTypeName
|
|
6
33
|
} = context;
|
|
7
|
-
|
|
8
|
-
const outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, listItemNode);
|
|
9
|
-
if (outputNode) {
|
|
10
|
-
return [outputNode];
|
|
11
|
-
}
|
|
12
|
-
return nodes;
|
|
34
|
+
return isListWithTextContentOnly(targetNodeTypeName, schema) ? wrapIntoTaskOrDecisionList(nodes, targetNodeTypeName, schema) : wrapIntoBulletOrOrderedList(nodes, targetNodeTypeName, schema);
|
|
13
35
|
};
|
|
@@ -23,8 +23,9 @@ export const transformNode = api =>
|
|
|
23
23
|
$from,
|
|
24
24
|
$to
|
|
25
25
|
} = expandSelectionToBlockRange(preservedSelection);
|
|
26
|
-
const isNested = isNestedNode(preservedSelection, '');
|
|
27
26
|
const selectedParent = $from.parent;
|
|
27
|
+
const isParentLayout = selectedParent.type === nodes.layoutColumn;
|
|
28
|
+
const isNestedExceptLayout = isNestedNode(preservedSelection, '') && !isParentLayout;
|
|
28
29
|
let fragment = Fragment.empty;
|
|
29
30
|
const isList = isListNode(selectedParent);
|
|
30
31
|
const slice = tr.doc.slice(isList ? $from.pos - 1 : $from.pos, isList ? $to.pos + 1 : $to.pos);
|
|
@@ -33,7 +34,7 @@ export const transformNode = api =>
|
|
|
33
34
|
sourceNode: node,
|
|
34
35
|
targetNodeType: targetType,
|
|
35
36
|
schema: tr.doc.type.schema,
|
|
36
|
-
isNested
|
|
37
|
+
isNested: isNestedExceptLayout
|
|
37
38
|
});
|
|
38
39
|
if (outputNode) {
|
|
39
40
|
fragment = fragment.append(Fragment.fromArray(outputNode));
|
|
@@ -188,9 +188,7 @@ export const getBlockMenuComponents = ({
|
|
|
188
188
|
component: ({
|
|
189
189
|
children
|
|
190
190
|
}) => {
|
|
191
|
-
return /*#__PURE__*/React.createElement(DeleteSection,
|
|
192
|
-
api: api
|
|
193
|
-
}, children);
|
|
191
|
+
return /*#__PURE__*/React.createElement(DeleteSection, null, children);
|
|
194
192
|
}
|
|
195
193
|
}, {
|
|
196
194
|
type: 'block-menu-item',
|
|
@@ -124,7 +124,7 @@ const BlockMenu = ({
|
|
|
124
124
|
boundariesElement,
|
|
125
125
|
scrollableElement
|
|
126
126
|
}) => {
|
|
127
|
-
var _editorView$dom, _ref;
|
|
127
|
+
var _editorView$dom, _ref, _api$analytics3;
|
|
128
128
|
const {
|
|
129
129
|
menuTriggerBy,
|
|
130
130
|
isSelectedViaDragHandle,
|
|
@@ -194,6 +194,13 @@ const BlockMenu = ({
|
|
|
194
194
|
return tr;
|
|
195
195
|
});
|
|
196
196
|
};
|
|
197
|
+
const handleClickOutside = e => {
|
|
198
|
+
// check if the clicked element was another drag handle, if so don't close the menu
|
|
199
|
+
if (e.target instanceof HTMLElement && e.target.closest(DRAG_HANDLE_SELECTOR)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
closeMenu();
|
|
203
|
+
};
|
|
197
204
|
const closeMenu = () => {
|
|
198
205
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
199
206
|
tr
|
|
@@ -220,39 +227,37 @@ const BlockMenu = ({
|
|
|
220
227
|
popupRef.current = el;
|
|
221
228
|
}
|
|
222
229
|
};
|
|
223
|
-
if (targetHandleRef instanceof HTMLElement) {
|
|
224
|
-
var _api$analytics3;
|
|
225
|
-
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
226
|
-
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
227
|
-
dispatchAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
228
|
-
fallbackComponent: null
|
|
229
|
-
}, /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
230
|
-
alignX: 'right',
|
|
231
|
-
alignY: 'start',
|
|
232
|
-
handleClickOutside: closeMenu,
|
|
233
|
-
handleEscapeKeydown: closeMenu,
|
|
234
|
-
handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
|
|
235
|
-
mountTo: mountTo,
|
|
236
|
-
boundariesElement: boundariesElement,
|
|
237
|
-
scrollableElement: scrollableElement,
|
|
238
|
-
target: targetHandleRef,
|
|
239
|
-
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
240
|
-
fitWidth: DEFAULT_MENU_WIDTH,
|
|
241
|
-
fitHeight: menuHeight,
|
|
242
|
-
preventOverflow: true,
|
|
243
|
-
stick: true,
|
|
244
|
-
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
245
|
-
focusTrap: openedViaKeyboard ?
|
|
246
|
-
// Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
|
|
247
|
-
{
|
|
248
|
-
initialFocus: undefined
|
|
249
|
-
} : undefined
|
|
250
|
-
}, /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
251
|
-
api: api,
|
|
252
|
-
setRef: setRef
|
|
253
|
-
})));
|
|
254
|
-
} else {
|
|
230
|
+
if (!(targetHandleRef instanceof HTMLElement)) {
|
|
255
231
|
return null;
|
|
256
232
|
}
|
|
233
|
+
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
234
|
+
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
235
|
+
dispatchAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
236
|
+
fallbackComponent: null
|
|
237
|
+
}, /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
238
|
+
alignX: 'right',
|
|
239
|
+
alignY: 'start',
|
|
240
|
+
handleClickOutside: handleClickOutside,
|
|
241
|
+
handleEscapeKeydown: closeMenu,
|
|
242
|
+
handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
|
|
243
|
+
mountTo: mountTo,
|
|
244
|
+
boundariesElement: boundariesElement,
|
|
245
|
+
scrollableElement: scrollableElement,
|
|
246
|
+
target: targetHandleRef,
|
|
247
|
+
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
248
|
+
fitWidth: DEFAULT_MENU_WIDTH,
|
|
249
|
+
fitHeight: menuHeight,
|
|
250
|
+
preventOverflow: true,
|
|
251
|
+
stick: true,
|
|
252
|
+
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
253
|
+
focusTrap: openedViaKeyboard ?
|
|
254
|
+
// Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
|
|
255
|
+
{
|
|
256
|
+
initialFocus: undefined
|
|
257
|
+
} : undefined
|
|
258
|
+
}, /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
259
|
+
api: api,
|
|
260
|
+
setRef: setRef
|
|
261
|
+
})));
|
|
257
262
|
};
|
|
258
263
|
export default injectIntl(BlockMenu);
|
|
@@ -84,8 +84,8 @@ const CopyLinkDropdownItemContent = ({
|
|
|
84
84
|
});
|
|
85
85
|
}, [api, blockLinkHashPrefix, getLinkPath, onDropdownOpenChanged, selection]);
|
|
86
86
|
|
|
87
|
-
// Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested
|
|
88
|
-
if (!fg('platform_editor_adf_with_localid') || !!menuTriggerBy && isNestedNode(selection, menuTriggerBy)
|
|
87
|
+
// Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested
|
|
88
|
+
if (!fg('platform_editor_adf_with_localid') || !!menuTriggerBy && isNestedNode(selection, menuTriggerBy)) {
|
|
89
89
|
return null;
|
|
90
90
|
}
|
|
91
91
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
|
|
3
3
|
export const DeleteSection = ({
|
|
4
|
-
api,
|
|
5
4
|
children
|
|
6
5
|
}) => {
|
|
7
|
-
var _api$selection, _api$selection$shared, _api$selection$shared2;
|
|
8
|
-
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;
|
|
9
|
-
const isEmptyLineSelected = !!(selection !== null && selection !== void 0 && selection.empty);
|
|
10
|
-
if (isEmptyLineSelected) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
6
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
14
7
|
hasSeparator: true
|
|
15
8
|
}, children);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a node is a list type that supports indentation (bulletList, orderedList, taskList).
|
|
3
|
+
*
|
|
4
|
+
* @param node - The node to check.
|
|
5
|
+
* @param schema - ProseMirror schema for check
|
|
6
|
+
* @returns True if the node is a list type, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export var isListWithIndentation = function isListWithIndentation(nodeTypeName, schema) {
|
|
9
|
+
var lists = [schema.nodes.taskList, schema.nodes.bulletList, schema.nodes.orderedList];
|
|
10
|
+
return lists.some(function (list) {
|
|
11
|
+
return list.name === nodeTypeName;
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a node is a list where its list items only support text content (taskList or decisionList).
|
|
17
|
+
*
|
|
18
|
+
* @param nodeTypeName - The node type name to check.
|
|
19
|
+
* @param schema - ProseMirror schema for check
|
|
20
|
+
* @returns True if the node is a list text type, false otherwise.
|
|
21
|
+
*/
|
|
22
|
+
export var isListWithTextContentOnly = function isListWithTextContentOnly(nodeTypeName, schema) {
|
|
23
|
+
var lists = [schema.nodes.taskList, schema.nodes.decisionList];
|
|
24
|
+
return lists.some(function (list) {
|
|
25
|
+
return list.name === nodeTypeName;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
|
|
2
|
+
import { isListWithIndentation } from '../nodeChecks';
|
|
3
|
+
var extractNestedLists = function extractNestedLists(node, schema) {
|
|
3
4
|
var items = [];
|
|
4
5
|
var paragraph = schema.nodes.paragraph;
|
|
6
|
+
var itemTypes = [schema.nodes.listItem, schema.nodes.taskItem];
|
|
5
7
|
var _extract = function extract(currentNode) {
|
|
6
8
|
currentNode.forEach(function (child) {
|
|
7
9
|
if (itemTypes.some(function (type) {
|
|
@@ -10,9 +12,7 @@ var extractNestedLists = function extractNestedLists(node, listTypes, itemTypes,
|
|
|
10
12
|
var contentWithoutNestedLists = [];
|
|
11
13
|
var nestedLists = [];
|
|
12
14
|
child.forEach(function (grandChild) {
|
|
13
|
-
if (
|
|
14
|
-
return grandChild.type === type;
|
|
15
|
-
})) {
|
|
15
|
+
if (isListWithIndentation(grandChild.type.name, schema)) {
|
|
16
16
|
nestedLists.push(grandChild);
|
|
17
17
|
} else if (grandChild.isText) {
|
|
18
18
|
contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
|
|
@@ -24,9 +24,7 @@ var extractNestedLists = function extractNestedLists(node, listTypes, itemTypes,
|
|
|
24
24
|
nestedLists.forEach(function (nestedList) {
|
|
25
25
|
_extract(nestedList);
|
|
26
26
|
});
|
|
27
|
-
} else if (
|
|
28
|
-
return child.type === type;
|
|
29
|
-
})) {
|
|
27
|
+
} else if (isListWithIndentation(child.type.name, schema)) {
|
|
30
28
|
_extract(child);
|
|
31
29
|
}
|
|
32
30
|
});
|
|
@@ -65,12 +63,9 @@ var extractNestedLists = function extractNestedLists(node, listTypes, itemTypes,
|
|
|
65
63
|
* TODO: Lists with mixed types (e.g. bulletList with a taskItem) doesn't full flatten
|
|
66
64
|
*/
|
|
67
65
|
export var flattenListStep = function flattenListStep(nodes, context) {
|
|
68
|
-
var listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList];
|
|
69
66
|
return nodes.map(function (node) {
|
|
70
|
-
if (
|
|
71
|
-
return node.
|
|
72
|
-
})) {
|
|
73
|
-
return node.copy(Fragment.from(extractNestedLists(node, listTypes, [context.schema.nodes.listItem, context.schema.nodes.taskItem], context.schema)));
|
|
67
|
+
if (isListWithIndentation(node.type.name, context.schema)) {
|
|
68
|
+
return node.copy(Fragment.from(extractNestedLists(node, context.schema)));
|
|
74
69
|
}
|
|
75
70
|
return node;
|
|
76
71
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { isListWithIndentation } from '../nodeChecks';
|
|
4
3
|
/**
|
|
5
4
|
* Transforms a bulletList, orderedList, or taskList into a decisionList.
|
|
6
5
|
*
|
|
@@ -29,7 +28,7 @@ export var listToDecisionListStep = function listToDecisionListStep(nodes, conte
|
|
|
29
28
|
var paragraphType = schema.nodes.paragraph;
|
|
30
29
|
var unsupportedContent = [];
|
|
31
30
|
var transformedNodes = nodes.map(function (node) {
|
|
32
|
-
if (!
|
|
31
|
+
if (!isListWithIndentation(node.type.name, schema)) {
|
|
33
32
|
return node;
|
|
34
33
|
}
|
|
35
34
|
var decisionItems = [];
|
|
@@ -41,7 +40,7 @@ export var listToDecisionListStep = function listToDecisionListStep(nodes, conte
|
|
|
41
40
|
itemContent.push.apply(itemContent, _toConsumableArray(child.children));
|
|
42
41
|
} else if (child.isText) {
|
|
43
42
|
itemContent.push(child);
|
|
44
|
-
} else if (!
|
|
43
|
+
} else if (!isListWithIndentation(child.type.name, schema)) {
|
|
45
44
|
unsupportedContent.push(child);
|
|
46
45
|
}
|
|
47
46
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { isListWithIndentation } from '../nodeChecks';
|
|
5
4
|
/**
|
|
6
5
|
* Recursively converts nested lists to the target list type.
|
|
7
6
|
* This function handles the conversion of both the list container and its items,
|
|
@@ -15,13 +14,13 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
15
14
|
var schema = node.type.schema;
|
|
16
15
|
var taskListType = schema.nodes.taskList;
|
|
17
16
|
var isSourceTaskList = node.type === taskListType;
|
|
18
|
-
var isTargetTaskList = targetListType ===
|
|
17
|
+
var isTargetTaskList = targetListType === taskListType.name;
|
|
19
18
|
var convertFromTaskListStructure = function convertFromTaskListStructure(node, targetListType, targetItemType) {
|
|
20
19
|
var schema = node.type.schema;
|
|
21
20
|
var targetListNodeType = schema.nodes[targetListType];
|
|
22
21
|
var transformedContent = [];
|
|
23
22
|
node.forEach(function (child) {
|
|
24
|
-
if (
|
|
23
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
25
24
|
// This is a nested list - it should become a child of the previous item
|
|
26
25
|
if (transformedContent.length > 0) {
|
|
27
26
|
var previousItem = transformedContent[transformedContent.length - 1];
|
|
@@ -33,7 +32,7 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
33
32
|
}
|
|
34
33
|
// If there's no previous item, skip this nested list (orphaned)
|
|
35
34
|
} else {
|
|
36
|
-
var transformedItem = transformListItem(child,
|
|
35
|
+
var transformedItem = transformListItem(child, targetListType, targetItemType);
|
|
37
36
|
if (transformedItem) {
|
|
38
37
|
transformedContent.push(transformedItem);
|
|
39
38
|
}
|
|
@@ -46,19 +45,19 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
46
45
|
var targetListNodeType = schema.nodes[targetListType];
|
|
47
46
|
var transformedContent = [];
|
|
48
47
|
node.forEach(function (itemNode) {
|
|
49
|
-
var transformedItem = transformListItem(itemNode,
|
|
48
|
+
var transformedItem = transformListItem(itemNode, targetListType, targetItemType, true);
|
|
50
49
|
if (transformedItem) {
|
|
51
50
|
transformedContent.push(transformedItem);
|
|
52
51
|
}
|
|
53
52
|
itemNode.forEach(function (child) {
|
|
54
|
-
if (
|
|
53
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
55
54
|
transformedContent.push(_transformList(child, targetListType, targetItemType, unsupportedContent));
|
|
56
55
|
}
|
|
57
56
|
});
|
|
58
57
|
});
|
|
59
58
|
return targetListNodeType.create(node.attrs, transformedContent);
|
|
60
59
|
};
|
|
61
|
-
var transformListItem = function transformListItem(itemNode,
|
|
60
|
+
var transformListItem = function transformListItem(itemNode, targetListType, targetItemType) {
|
|
62
61
|
var excludeNestedLists = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
63
62
|
var schema = itemNode.type.schema;
|
|
64
63
|
var targetItemNodeType = schema.nodes[targetItemType];
|
|
@@ -73,7 +72,7 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
73
72
|
} else if (child.isText) {
|
|
74
73
|
inlineContent.push(child);
|
|
75
74
|
// Nested lists will be extracted and placed as siblings in the taskList
|
|
76
|
-
} else if (!
|
|
75
|
+
} else if (!isListWithIndentation(child.type.name, schema)) {
|
|
77
76
|
unsupportedContent.push(child);
|
|
78
77
|
}
|
|
79
78
|
});
|
|
@@ -84,7 +83,7 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
84
83
|
transformedContent.push(paragraphType.create(null, itemNode.content));
|
|
85
84
|
} else {
|
|
86
85
|
itemNode.forEach(function (child) {
|
|
87
|
-
if (
|
|
86
|
+
if (isListWithIndentation(child.type.name, schema)) {
|
|
88
87
|
if (excludeNestedLists) {
|
|
89
88
|
// Skip nested lists - they will be handled separately as siblings
|
|
90
89
|
return;
|
|
@@ -104,7 +103,7 @@ var _transformList = function transformList(node, targetListType, targetItemType
|
|
|
104
103
|
var targetListNodeType = schema.nodes[targetListType];
|
|
105
104
|
var transformedContent = [];
|
|
106
105
|
node.forEach(function (childNode) {
|
|
107
|
-
var transformedItem =
|
|
106
|
+
var transformedItem = isListWithIndentation(childNode.type.name, schema) ? _transformList(childNode, targetListType, targetItemType, unsupportedContent) : transformListItem(childNode, targetListType, targetItemType);
|
|
108
107
|
if (transformedItem) {
|
|
109
108
|
transformedContent.push(transformedItem);
|
|
110
109
|
}
|
|
@@ -187,7 +186,7 @@ export var listToListStep = function listToListStep(nodes, context) {
|
|
|
187
186
|
targetNodeTypeName = context.targetNodeTypeName;
|
|
188
187
|
var unsupportedContent = [];
|
|
189
188
|
var transformedNodes = nodes.map(function (node) {
|
|
190
|
-
if (
|
|
189
|
+
if (isListWithIndentation(node.type.name, schema)) {
|
|
191
190
|
var targetItemType = targetNodeTypeName === 'taskList' ? 'taskItem' : 'listItem';
|
|
192
191
|
return _transformList(node, targetNodeTypeName, targetItemType, unsupportedContent);
|
|
193
192
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createTextContent } from '../utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transforms a paragraph (or heading) into a codeBlock by extracting its text content.
|
|
5
|
+
* This step handles the conversion of inline content (including marks) to plain text,
|
|
6
|
+
* which is required because codeBlocks can only contain plain text nodes.
|
|
7
|
+
*
|
|
8
|
+
* Example: paragraph with bold/italic/status → codeBlock with plain text
|
|
9
|
+
*/
|
|
10
|
+
export var wrapTextToCodeblockStep = function wrapTextToCodeblockStep(nodes, context) {
|
|
11
|
+
var schema = context.schema;
|
|
12
|
+
return nodes.map(function (node) {
|
|
13
|
+
var codeBlockNode = schema.nodes.codeBlock.createAndFill({}, schema.text(createTextContent(node)));
|
|
14
|
+
return codeBlockNode !== null && codeBlockNode !== void 0 ? codeBlockNode : node;
|
|
15
|
+
});
|
|
16
|
+
};
|