@atlaskit/editor-plugin-block-menu 5.2.16 → 5.2.18
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 +20 -0
- package/dist/cjs/blockMenuPlugin.js +2 -2
- package/dist/cjs/editor-commands/transform-node-utils/flattenStep.js +18 -8
- package/dist/cjs/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +50 -0
- package/dist/cjs/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
- package/dist/cjs/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
- package/dist/cjs/editor-commands/transform-node-utils/transform.js +20 -5
- package/dist/cjs/editor-commands/transformNode.js +5 -3
- package/dist/cjs/editor-commands/transforms/utils.js +3 -1
- package/dist/cjs/ui/block-menu.js +38 -33
- package/dist/es2019/blockMenuPlugin.js +2 -2
- package/dist/es2019/editor-commands/transform-node-utils/flattenStep.js +16 -6
- package/dist/es2019/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +46 -0
- package/dist/es2019/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
- package/dist/es2019/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
- package/dist/es2019/editor-commands/transform-node-utils/transform.js +20 -5
- package/dist/es2019/editor-commands/transformNode.js +5 -3
- package/dist/es2019/editor-commands/transforms/utils.js +3 -1
- package/dist/es2019/ui/block-menu.js +38 -33
- package/dist/esm/blockMenuPlugin.js +2 -2
- package/dist/esm/editor-commands/transform-node-utils/flattenStep.js +18 -8
- package/dist/esm/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +44 -0
- package/dist/esm/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
- package/dist/esm/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
- package/dist/esm/editor-commands/transform-node-utils/transform.js +20 -5
- package/dist/esm/editor-commands/transformNode.js +5 -3
- package/dist/esm/editor-commands/transforms/utils.js +3 -1
- package/dist/esm/ui/block-menu.js +38 -33
- package/dist/types/blockMenuPluginType.d.ts +2 -2
- package/dist/types/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.d.ts +20 -0
- package/dist/types/editor-commands/transform-node-utils/steps/unwrapListStep.d.ts +3 -0
- package/dist/types/editor-commands/transform-node-utils/transform.d.ts +2 -1
- package/dist/types/editor-commands/transform-node-utils/types.d.ts +1 -0
- package/dist/types/editor-commands/transformNode.d.ts +2 -2
- package/dist/types/editor-commands/transforms/types.d.ts +2 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types-ts4.5/blockMenuPluginType.d.ts +2 -2
- package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.d.ts +20 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/unwrapListStep.d.ts +3 -0
- package/dist/types-ts4.5/editor-commands/transform-node-utils/transform.d.ts +2 -1
- package/dist/types-ts4.5/editor-commands/transform-node-utils/types.d.ts +1 -0
- package/dist/types-ts4.5/editor-commands/transformNode.d.ts +2 -2
- package/dist/types-ts4.5/editor-commands/transforms/types.d.ts +2 -1
- package/dist/types-ts4.5/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
|
|
1
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
2
4
|
export const getTargetNodeInfo = (targetType, nodes) => {
|
|
3
5
|
switch (targetType) {
|
|
4
6
|
case 'heading1':
|
|
@@ -198,7 +200,7 @@ export const convertCodeBlockContentToParagraphs = (codeBlockNode, schema) => {
|
|
|
198
200
|
return paragraphNodes;
|
|
199
201
|
};
|
|
200
202
|
const isBreakoutMarkSupported = nodeType => {
|
|
201
|
-
return ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
|
|
203
|
+
return editorExperiment('platform_synced_block', true) ? breakoutResizableNodes.includes(nodeType.name) : ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
|
|
202
204
|
};
|
|
203
205
|
export const getMarksWithBreakout = (sourceNode, targetNodeType) => {
|
|
204
206
|
const allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
|
|
@@ -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);
|
|
@@ -35,8 +35,8 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
|
|
|
35
35
|
formatNode: function formatNode(targetType, analyticsAttrs) {
|
|
36
36
|
return _formatNode(api)(targetType, analyticsAttrs);
|
|
37
37
|
},
|
|
38
|
-
transformNode: function transformNode(targetType,
|
|
39
|
-
return _transformNode(api)(targetType,
|
|
38
|
+
transformNode: function transformNode(targetType, metadata) {
|
|
39
|
+
return _transformNode(api)(targetType, metadata);
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
getSharedState: function getSharedState(editorState) {
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
export var flattenStep = function flattenStep(nodes, context) {
|
|
2
2
|
var schema = context.schema,
|
|
3
3
|
targetNodeTypeName = context.targetNodeTypeName;
|
|
4
|
+
var targetNodeType = schema.nodes[targetNodeTypeName];
|
|
5
|
+
if (!targetNodeType) {
|
|
6
|
+
return nodes;
|
|
7
|
+
}
|
|
4
8
|
|
|
5
9
|
// TODO: EDITOR-2920 - Implement flattening logic.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return nodes;
|
|
10
|
+
var isTargetCodeBlock = targetNodeTypeName === 'codeBlock';
|
|
11
|
+
if (isTargetCodeBlock) {
|
|
12
|
+
// This strips explicitly text nodes
|
|
13
|
+
var codeBlockContent = nodes.map(function (node) {
|
|
14
|
+
return node.content.textBetween(0, node.content.size, '\n');
|
|
15
|
+
}).join('\n');
|
|
16
|
+
return [schema.nodes.codeBlock.create({}, schema.text(codeBlockContent))];
|
|
13
17
|
}
|
|
14
|
-
return
|
|
18
|
+
return nodes.map(function (node) {
|
|
19
|
+
var isValidWithin = targetNodeType.validContent(node.content);
|
|
20
|
+
if (!isValidWithin) {
|
|
21
|
+
return node;
|
|
22
|
+
}
|
|
23
|
+
return schema.nodes.paragraph.create({}, node.content);
|
|
24
|
+
});
|
|
15
25
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applies target text type conversion. If the target type is a heading, converts textblock nodes
|
|
3
|
+
* (paragraphs, headings) to heading nodes with the specified level. Otherwise, leaves nodes unchanged.
|
|
4
|
+
* Non-textblock nodes are always left unchanged.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* Input:
|
|
8
|
+
* - paragraph "Heading 1"
|
|
9
|
+
* - paragraph "Heading 2"
|
|
10
|
+
*
|
|
11
|
+
* Output (with target: heading, level: 2):
|
|
12
|
+
* - heading (level: 2) "Heading 1"
|
|
13
|
+
* - heading (level: 2) "Heading 2"
|
|
14
|
+
*
|
|
15
|
+
* @param nodes
|
|
16
|
+
* @param context
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
export var applyTargetTextTypeStep = function applyTargetTextTypeStep(nodes, context) {
|
|
20
|
+
var schema = context.schema,
|
|
21
|
+
targetNodeTypeName = context.targetNodeTypeName,
|
|
22
|
+
targetAttrs = context.targetAttrs;
|
|
23
|
+
if (targetNodeTypeName !== 'heading') {
|
|
24
|
+
return nodes;
|
|
25
|
+
}
|
|
26
|
+
var headingType = schema.nodes.heading;
|
|
27
|
+
if (!headingType) {
|
|
28
|
+
return nodes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Default to level 1 if no level is specified
|
|
32
|
+
// The level should ideally come from targetAttrs, but if not available, use default
|
|
33
|
+
var headingLevel = typeof (targetAttrs === null || targetAttrs === void 0 ? void 0 : targetAttrs.level) === 'number' ? targetAttrs.level : 1;
|
|
34
|
+
return nodes.map(function (node) {
|
|
35
|
+
if (node.isTextblock) {
|
|
36
|
+
// Convert textblock nodes (paragraphs, headings) to heading with specified level
|
|
37
|
+
return headingType.create({
|
|
38
|
+
level: headingLevel
|
|
39
|
+
}, node.content);
|
|
40
|
+
}
|
|
41
|
+
// Non-textblock nodes are left unchanged
|
|
42
|
+
return node;
|
|
43
|
+
});
|
|
44
|
+
};
|
|
@@ -3,7 +3,7 @@ import { isListWithIndentation } from '../nodeChecks';
|
|
|
3
3
|
var extractNestedLists = function extractNestedLists(node, schema) {
|
|
4
4
|
var items = [];
|
|
5
5
|
var paragraph = schema.nodes.paragraph;
|
|
6
|
-
var itemTypes = [schema.nodes.listItem, schema.nodes.taskItem];
|
|
6
|
+
var itemTypes = [schema.nodes.listItem, schema.nodes.taskItem, schema.nodes.decisionItem];
|
|
7
7
|
var _extract = function extract(currentNode) {
|
|
8
8
|
currentNode.forEach(function (child) {
|
|
9
9
|
if (itemTypes.some(function (type) {
|
|
@@ -11,11 +11,21 @@ var extractNestedLists = function extractNestedLists(node, schema) {
|
|
|
11
11
|
})) {
|
|
12
12
|
var contentWithoutNestedLists = [];
|
|
13
13
|
var nestedLists = [];
|
|
14
|
+
|
|
15
|
+
// Check if this item type expects inline content (taskItem, decisionItem)
|
|
16
|
+
// vs block content (listItem) based on the schema definition
|
|
17
|
+
var isInlineItem = child.type.inlineContent;
|
|
14
18
|
child.forEach(function (grandChild) {
|
|
15
19
|
if (isListWithIndentation(grandChild.type.name, schema)) {
|
|
16
20
|
nestedLists.push(grandChild);
|
|
17
21
|
} else if (grandChild.isText) {
|
|
18
|
-
|
|
22
|
+
// For taskItem/decisionItem, keep text as-is (they support inline content)
|
|
23
|
+
// For listItem, wrap text in paragraph (they require block content)
|
|
24
|
+
if (isInlineItem) {
|
|
25
|
+
contentWithoutNestedLists.push(grandChild);
|
|
26
|
+
} else {
|
|
27
|
+
contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
|
|
28
|
+
}
|
|
19
29
|
} else {
|
|
20
30
|
contentWithoutNestedLists.push(grandChild);
|
|
21
31
|
}
|
|
@@ -3,6 +3,9 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
|
3
3
|
* Given an array of nodes, processes each list removing all parent list nodes and
|
|
4
4
|
* just returning their child contents.
|
|
5
5
|
*
|
|
6
|
+
* For lists with block content (bulletList, orderedList), it extracts the block nodes directly.
|
|
7
|
+
* For lists with inline content (taskList, decisionList), it wraps the content in paragraphs.
|
|
8
|
+
*
|
|
6
9
|
* @example
|
|
7
10
|
* Input:
|
|
8
11
|
* - bulletList
|
|
@@ -20,14 +23,19 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
|
20
23
|
* @returns
|
|
21
24
|
*/
|
|
22
25
|
export var unwrapListStep = function unwrapListStep(nodes, context) {
|
|
23
|
-
var listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList];
|
|
26
|
+
var listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList, context.schema.nodes.decisionList];
|
|
24
27
|
return nodes.flatMap(function (node) {
|
|
25
28
|
if (listTypes.some(function (type) {
|
|
26
29
|
return node.type === type;
|
|
27
30
|
})) {
|
|
28
31
|
var listItems = [];
|
|
29
32
|
node.forEach(function (listItem) {
|
|
30
|
-
|
|
33
|
+
// if isTaskItem or isDecisionItem, convert to paragraph
|
|
34
|
+
if (listItem.type.name === 'taskItem' || listItem.type.name === 'decisionItem') {
|
|
35
|
+
listItems.push(context.schema.nodes.paragraph.create({}, listItem.content));
|
|
36
|
+
} else {
|
|
37
|
+
listItems.push.apply(listItems, _toConsumableArray(listItem.children));
|
|
38
|
+
}
|
|
31
39
|
});
|
|
32
40
|
return listItems;
|
|
33
41
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getTargetNodeTypeNameInContext } from '../transform-node-utils/utils';
|
|
2
2
|
import { flattenStep } from './flattenStep';
|
|
3
|
+
import { applyTargetTextTypeStep } from './steps/applyTargetTextTypeStep';
|
|
3
4
|
import { decisionListToListStep } from './steps/decisionListToListStep';
|
|
4
5
|
import { flattenListStep } from './steps/flattenListStep';
|
|
5
6
|
import { listToDecisionListStep } from './steps/listToDecisionListStep';
|
|
@@ -29,19 +30,19 @@ var TRANSFORM_STEPS = {
|
|
|
29
30
|
atomic: undefined,
|
|
30
31
|
container: [unwrapStep, wrapStep],
|
|
31
32
|
list: undefined,
|
|
32
|
-
text: [unwrapStep]
|
|
33
|
+
text: [unwrapStep, applyTargetTextTypeStep]
|
|
33
34
|
},
|
|
34
35
|
list: {
|
|
35
36
|
atomic: undefined,
|
|
36
37
|
container: [wrapStep],
|
|
37
38
|
list: [listToListStep],
|
|
38
|
-
text: [flattenListStep, unwrapListStep]
|
|
39
|
+
text: [flattenListStep, unwrapListStep, applyTargetTextTypeStep]
|
|
39
40
|
},
|
|
40
41
|
text: {
|
|
41
42
|
atomic: undefined,
|
|
42
43
|
container: [wrapStep],
|
|
43
44
|
list: [wrapIntoListStep],
|
|
44
|
-
text: [
|
|
45
|
+
text: [flattenStep, applyTargetTextTypeStep]
|
|
45
46
|
}
|
|
46
47
|
};
|
|
47
48
|
|
|
@@ -124,6 +125,18 @@ var TRANSFORM_STEPS_OVERRIDE = {
|
|
|
124
125
|
orderedList: [decisionListToListStep],
|
|
125
126
|
taskList: [decisionListToListStep],
|
|
126
127
|
layoutSection: [wrapIntoLayoutStep]
|
|
128
|
+
},
|
|
129
|
+
blockCard: {
|
|
130
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
131
|
+
},
|
|
132
|
+
embedCard: {
|
|
133
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
134
|
+
},
|
|
135
|
+
extension: {
|
|
136
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
137
|
+
},
|
|
138
|
+
bodiedExtension: {
|
|
139
|
+
layoutSection: [wrapIntoLayoutStep]
|
|
127
140
|
}
|
|
128
141
|
};
|
|
129
142
|
var getTransformStepsForNodeTypes = function getTransformStepsForNodeTypes(selectedNodeTypeName, targetNodeTypeName) {
|
|
@@ -138,7 +151,8 @@ export var getOutputNodes = function getOutputNodes(_ref) {
|
|
|
138
151
|
var sourceNode = _ref.sourceNode,
|
|
139
152
|
targetNodeType = _ref.targetNodeType,
|
|
140
153
|
schema = _ref.schema,
|
|
141
|
-
isNested = _ref.isNested
|
|
154
|
+
isNested = _ref.isNested,
|
|
155
|
+
targetAttrs = _ref.targetAttrs;
|
|
142
156
|
var nodesToReplace = [sourceNode];
|
|
143
157
|
var selectedNodeTypeName = toNodeTypeValue(sourceNode.type.name);
|
|
144
158
|
var initialTargetNodeTypeName = toNodeTypeValue(targetNodeType.name);
|
|
@@ -151,7 +165,8 @@ export var getOutputNodes = function getOutputNodes(_ref) {
|
|
|
151
165
|
var context = {
|
|
152
166
|
fromNode: sourceNode,
|
|
153
167
|
targetNodeTypeName: targetNodeTypeName,
|
|
154
|
-
schema: schema
|
|
168
|
+
schema: schema,
|
|
169
|
+
targetAttrs: targetAttrs
|
|
155
170
|
};
|
|
156
171
|
if (!steps || steps.length === 0) {
|
|
157
172
|
return;
|
|
@@ -7,7 +7,7 @@ import { isListNode } from './transforms/utils';
|
|
|
7
7
|
export var transformNode = function transformNode(api) {
|
|
8
8
|
return (
|
|
9
9
|
// eslint-disable-next-line no-unused-vars
|
|
10
|
-
function (targetType,
|
|
10
|
+
function (targetType, metadata) {
|
|
11
11
|
return function (_ref) {
|
|
12
12
|
var _api$blockControls;
|
|
13
13
|
var tr = _ref.tr;
|
|
@@ -20,8 +20,9 @@ export var transformNode = function transformNode(api) {
|
|
|
20
20
|
var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection),
|
|
21
21
|
$from = _expandSelectionToBlo.$from,
|
|
22
22
|
$to = _expandSelectionToBlo.$to;
|
|
23
|
-
var isNested = isNestedNode(preservedSelection, '');
|
|
24
23
|
var selectedParent = $from.parent;
|
|
24
|
+
var isParentLayout = selectedParent.type === nodes.layoutColumn;
|
|
25
|
+
var isNestedExceptLayout = isNestedNode(preservedSelection, '') && !isParentLayout;
|
|
25
26
|
var fragment = Fragment.empty;
|
|
26
27
|
var isList = isListNode(selectedParent);
|
|
27
28
|
var slice = tr.doc.slice(isList ? $from.pos - 1 : $from.pos, isList ? $to.pos + 1 : $to.pos);
|
|
@@ -30,7 +31,8 @@ export var transformNode = function transformNode(api) {
|
|
|
30
31
|
sourceNode: node,
|
|
31
32
|
targetNodeType: targetType,
|
|
32
33
|
schema: tr.doc.type.schema,
|
|
33
|
-
isNested:
|
|
34
|
+
isNested: isNestedExceptLayout,
|
|
35
|
+
targetAttrs: metadata === null || metadata === void 0 ? void 0 : metadata.targetAttrs
|
|
34
36
|
});
|
|
35
37
|
if (outputNode) {
|
|
36
38
|
fragment = fragment.append(Fragment.fromArray(outputNode));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
|
|
2
3
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
4
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
3
5
|
export var getTargetNodeInfo = function getTargetNodeInfo(targetType, nodes) {
|
|
4
6
|
switch (targetType) {
|
|
5
7
|
case 'heading1':
|
|
@@ -199,7 +201,7 @@ export var convertCodeBlockContentToParagraphs = function convertCodeBlockConten
|
|
|
199
201
|
return paragraphNodes;
|
|
200
202
|
};
|
|
201
203
|
var isBreakoutMarkSupported = function isBreakoutMarkSupported(nodeType) {
|
|
202
|
-
return ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
|
|
204
|
+
return editorExperiment('platform_synced_block', true) ? breakoutResizableNodes.includes(nodeType.name) : ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
|
|
203
205
|
};
|
|
204
206
|
export var getMarksWithBreakout = function getMarksWithBreakout(sourceNode, targetNodeType) {
|
|
205
207
|
var allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
|
|
@@ -118,7 +118,7 @@ var BlockMenuContent = function BlockMenuContent(_ref3) {
|
|
|
118
118
|
})));
|
|
119
119
|
};
|
|
120
120
|
var BlockMenu = function BlockMenu(_ref4) {
|
|
121
|
-
var _editorView$dom, _ref5;
|
|
121
|
+
var _editorView$dom, _ref5, _api$analytics3;
|
|
122
122
|
var editorView = _ref4.editorView,
|
|
123
123
|
api = _ref4.api,
|
|
124
124
|
mountTo = _ref4.mountTo,
|
|
@@ -193,6 +193,13 @@ var BlockMenu = function BlockMenu(_ref4) {
|
|
|
193
193
|
return tr;
|
|
194
194
|
});
|
|
195
195
|
};
|
|
196
|
+
var handleClickOutside = function handleClickOutside(e) {
|
|
197
|
+
// check if the clicked element was another drag handle, if so don't close the menu
|
|
198
|
+
if (e.target instanceof HTMLElement && e.target.closest(DRAG_HANDLE_SELECTOR)) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
closeMenu();
|
|
202
|
+
};
|
|
196
203
|
var closeMenu = function closeMenu() {
|
|
197
204
|
api === null || api === void 0 || api.core.actions.execute(function (_ref7) {
|
|
198
205
|
var _api$blockControls3, _api$userIntent3;
|
|
@@ -218,39 +225,37 @@ var BlockMenu = function BlockMenu(_ref4) {
|
|
|
218
225
|
popupRef.current = el;
|
|
219
226
|
}
|
|
220
227
|
};
|
|
221
|
-
if (targetHandleRef instanceof HTMLElement) {
|
|
222
|
-
var _api$analytics3;
|
|
223
|
-
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
224
|
-
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
225
|
-
dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
226
|
-
fallbackComponent: null
|
|
227
|
-
}, /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
228
|
-
alignX: 'right',
|
|
229
|
-
alignY: 'start',
|
|
230
|
-
handleClickOutside: closeMenu,
|
|
231
|
-
handleEscapeKeydown: closeMenu,
|
|
232
|
-
handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
|
|
233
|
-
mountTo: mountTo,
|
|
234
|
-
boundariesElement: boundariesElement,
|
|
235
|
-
scrollableElement: scrollableElement,
|
|
236
|
-
target: targetHandleRef,
|
|
237
|
-
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
238
|
-
fitWidth: DEFAULT_MENU_WIDTH,
|
|
239
|
-
fitHeight: menuHeight,
|
|
240
|
-
preventOverflow: true,
|
|
241
|
-
stick: true,
|
|
242
|
-
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
243
|
-
focusTrap: openedViaKeyboard ?
|
|
244
|
-
// Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
|
|
245
|
-
{
|
|
246
|
-
initialFocus: undefined
|
|
247
|
-
} : undefined
|
|
248
|
-
}, /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
249
|
-
api: api,
|
|
250
|
-
setRef: setRef
|
|
251
|
-
})));
|
|
252
|
-
} else {
|
|
228
|
+
if (!(targetHandleRef instanceof HTMLElement)) {
|
|
253
229
|
return null;
|
|
254
230
|
}
|
|
231
|
+
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
232
|
+
component: ACTION_SUBJECT.BLOCK_MENU,
|
|
233
|
+
dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
234
|
+
fallbackComponent: null
|
|
235
|
+
}, /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
236
|
+
alignX: 'right',
|
|
237
|
+
alignY: 'start',
|
|
238
|
+
handleClickOutside: handleClickOutside,
|
|
239
|
+
handleEscapeKeydown: closeMenu,
|
|
240
|
+
handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
|
|
241
|
+
mountTo: mountTo,
|
|
242
|
+
boundariesElement: boundariesElement,
|
|
243
|
+
scrollableElement: scrollableElement,
|
|
244
|
+
target: targetHandleRef,
|
|
245
|
+
zIndex: akEditorFloatingOverlapPanelZIndex,
|
|
246
|
+
fitWidth: DEFAULT_MENU_WIDTH,
|
|
247
|
+
fitHeight: menuHeight,
|
|
248
|
+
preventOverflow: true,
|
|
249
|
+
stick: true,
|
|
250
|
+
offset: [DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
|
|
251
|
+
focusTrap: openedViaKeyboard ?
|
|
252
|
+
// Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
|
|
253
|
+
{
|
|
254
|
+
initialFocus: undefined
|
|
255
|
+
} : undefined
|
|
256
|
+
}, /*#__PURE__*/React.createElement(BlockMenuContent, {
|
|
257
|
+
api: api,
|
|
258
|
+
setRef: setRef
|
|
259
|
+
})));
|
|
255
260
|
};
|
|
256
261
|
export default injectIntl(BlockMenu);
|
|
@@ -5,12 +5,12 @@ import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
|
|
|
5
5
|
import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
|
|
6
6
|
import type { UserIntentPlugin } from '@atlaskit/editor-plugin-user-intent';
|
|
7
7
|
import type { NodeType } from '@atlaskit/editor-prosemirror/model';
|
|
8
|
-
import type { FormatNodeAnalyticsAttrs, FormatNodeTargetType,
|
|
8
|
+
import type { FormatNodeAnalyticsAttrs, FormatNodeTargetType, TransformNodeMetadata } from './editor-commands/transforms/types';
|
|
9
9
|
export declare enum FLAG_ID {
|
|
10
10
|
LINK_COPIED_TO_CLIPBOARD = "link-copied-to-clipboard"
|
|
11
11
|
}
|
|
12
12
|
type FormatNodeCommand = (targetType: FormatNodeTargetType, analyticsAttrs?: FormatNodeAnalyticsAttrs) => EditorCommand;
|
|
13
|
-
type TransformNodeCommand = (targetType: NodeType,
|
|
13
|
+
type TransformNodeCommand = (targetType: NodeType, metadata?: TransformNodeMetadata) => EditorCommand;
|
|
14
14
|
export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
|
|
15
15
|
actions: {
|
|
16
16
|
getBlockMenuComponents: () => Array<RegisterBlockMenuComponent>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TransformStep } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Applies target text type conversion. If the target type is a heading, converts textblock nodes
|
|
4
|
+
* (paragraphs, headings) to heading nodes with the specified level. Otherwise, leaves nodes unchanged.
|
|
5
|
+
* Non-textblock nodes are always left unchanged.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* Input:
|
|
9
|
+
* - paragraph "Heading 1"
|
|
10
|
+
* - paragraph "Heading 2"
|
|
11
|
+
*
|
|
12
|
+
* Output (with target: heading, level: 2):
|
|
13
|
+
* - heading (level: 2) "Heading 1"
|
|
14
|
+
* - heading (level: 2) "Heading 2"
|
|
15
|
+
*
|
|
16
|
+
* @param nodes
|
|
17
|
+
* @param context
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export declare const applyTargetTextTypeStep: TransformStep;
|
|
@@ -3,6 +3,9 @@ import type { TransformStep } from '../types';
|
|
|
3
3
|
* Given an array of nodes, processes each list removing all parent list nodes and
|
|
4
4
|
* just returning their child contents.
|
|
5
5
|
*
|
|
6
|
+
* For lists with block content (bulletList, orderedList), it extracts the block nodes directly.
|
|
7
|
+
* For lists with inline content (taskList, decisionList), it wraps the content in paragraphs.
|
|
8
|
+
*
|
|
6
9
|
* @example
|
|
7
10
|
* Input:
|
|
8
11
|
* - bulletList
|
|
@@ -3,7 +3,8 @@ interface GetOutputNodesArgs {
|
|
|
3
3
|
isNested: boolean;
|
|
4
4
|
schema: Schema;
|
|
5
5
|
sourceNode: PMNode;
|
|
6
|
+
targetAttrs?: Record<string, unknown>;
|
|
6
7
|
targetNodeType: NodeType;
|
|
7
8
|
}
|
|
8
|
-
export declare const getOutputNodes: ({ sourceNode, targetNodeType, schema, isNested, }: GetOutputNodesArgs) => PMNode[] | undefined;
|
|
9
|
+
export declare const getOutputNodes: ({ sourceNode, targetNodeType, schema, isNested, targetAttrs, }: GetOutputNodesArgs) => PMNode[] | undefined;
|
|
9
10
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EditorCommand, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
2
|
import { type NodeType } from '@atlaskit/editor-prosemirror/model';
|
|
3
3
|
import type { BlockMenuPlugin } from '../blockMenuPluginType';
|
|
4
|
-
import type {
|
|
5
|
-
export declare const transformNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: NodeType,
|
|
4
|
+
import type { TransformNodeMetadata } from './transforms/types';
|
|
5
|
+
export declare const transformNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: NodeType, metadata?: TransformNodeMetadata) => EditorCommand;
|
|
@@ -7,7 +7,8 @@ export type FormatNodeAnalyticsAttrs = {
|
|
|
7
7
|
inputMethod: INPUT_METHOD.BLOCK_MENU;
|
|
8
8
|
triggeredFrom: INPUT_METHOD.MOUSE | INPUT_METHOD.KEYBOARD;
|
|
9
9
|
};
|
|
10
|
-
export type
|
|
10
|
+
export type TransformNodeMetadata = FormatNodeAnalyticsAttrs & {
|
|
11
|
+
targetAttrs?: Record<string, unknown>;
|
|
11
12
|
targetTypeName: TransfromNodeTargetType;
|
|
12
13
|
};
|
|
13
14
|
export type TransformFunction = (context: TransformContext) => Transaction | null;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { blockMenuPlugin } from './blockMenuPlugin';
|
|
2
2
|
export type { BlockMenuPlugin, RegisterBlockMenuComponent, Parent, BlockMenuPluginOptions, BlockMenuSharedState, } from './blockMenuPluginType';
|
|
3
|
+
export type { TransformNodeMetadata } from './editor-commands/transforms/types';
|
|
@@ -5,12 +5,12 @@ import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
|
|
|
5
5
|
import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
|
|
6
6
|
import type { UserIntentPlugin } from '@atlaskit/editor-plugin-user-intent';
|
|
7
7
|
import type { NodeType } from '@atlaskit/editor-prosemirror/model';
|
|
8
|
-
import type { FormatNodeAnalyticsAttrs, FormatNodeTargetType,
|
|
8
|
+
import type { FormatNodeAnalyticsAttrs, FormatNodeTargetType, TransformNodeMetadata } from './editor-commands/transforms/types';
|
|
9
9
|
export declare enum FLAG_ID {
|
|
10
10
|
LINK_COPIED_TO_CLIPBOARD = "link-copied-to-clipboard"
|
|
11
11
|
}
|
|
12
12
|
type FormatNodeCommand = (targetType: FormatNodeTargetType, analyticsAttrs?: FormatNodeAnalyticsAttrs) => EditorCommand;
|
|
13
|
-
type TransformNodeCommand = (targetType: NodeType,
|
|
13
|
+
type TransformNodeCommand = (targetType: NodeType, metadata?: TransformNodeMetadata) => EditorCommand;
|
|
14
14
|
export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
|
|
15
15
|
actions: {
|
|
16
16
|
getBlockMenuComponents: () => Array<RegisterBlockMenuComponent>;
|
package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TransformStep } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Applies target text type conversion. If the target type is a heading, converts textblock nodes
|
|
4
|
+
* (paragraphs, headings) to heading nodes with the specified level. Otherwise, leaves nodes unchanged.
|
|
5
|
+
* Non-textblock nodes are always left unchanged.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* Input:
|
|
9
|
+
* - paragraph "Heading 1"
|
|
10
|
+
* - paragraph "Heading 2"
|
|
11
|
+
*
|
|
12
|
+
* Output (with target: heading, level: 2):
|
|
13
|
+
* - heading (level: 2) "Heading 1"
|
|
14
|
+
* - heading (level: 2) "Heading 2"
|
|
15
|
+
*
|
|
16
|
+
* @param nodes
|
|
17
|
+
* @param context
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export declare const applyTargetTextTypeStep: TransformStep;
|
|
@@ -3,6 +3,9 @@ import type { TransformStep } from '../types';
|
|
|
3
3
|
* Given an array of nodes, processes each list removing all parent list nodes and
|
|
4
4
|
* just returning their child contents.
|
|
5
5
|
*
|
|
6
|
+
* For lists with block content (bulletList, orderedList), it extracts the block nodes directly.
|
|
7
|
+
* For lists with inline content (taskList, decisionList), it wraps the content in paragraphs.
|
|
8
|
+
*
|
|
6
9
|
* @example
|
|
7
10
|
* Input:
|
|
8
11
|
* - bulletList
|
|
@@ -3,7 +3,8 @@ interface GetOutputNodesArgs {
|
|
|
3
3
|
isNested: boolean;
|
|
4
4
|
schema: Schema;
|
|
5
5
|
sourceNode: PMNode;
|
|
6
|
+
targetAttrs?: Record<string, unknown>;
|
|
6
7
|
targetNodeType: NodeType;
|
|
7
8
|
}
|
|
8
|
-
export declare const getOutputNodes: ({ sourceNode, targetNodeType, schema, isNested, }: GetOutputNodesArgs) => PMNode[] | undefined;
|
|
9
|
+
export declare const getOutputNodes: ({ sourceNode, targetNodeType, schema, isNested, targetAttrs, }: GetOutputNodesArgs) => PMNode[] | undefined;
|
|
9
10
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EditorCommand, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
2
|
import { type NodeType } from '@atlaskit/editor-prosemirror/model';
|
|
3
3
|
import type { BlockMenuPlugin } from '../blockMenuPluginType';
|
|
4
|
-
import type {
|
|
5
|
-
export declare const transformNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: NodeType,
|
|
4
|
+
import type { TransformNodeMetadata } from './transforms/types';
|
|
5
|
+
export declare const transformNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (targetType: NodeType, metadata?: TransformNodeMetadata) => EditorCommand;
|