@atlaskit/editor-plugin-block-menu 12.0.3 → 12.1.1
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 +32 -0
- package/afm-cc/tsconfig.json +3 -0
- package/afm-products/tsconfig.json +3 -0
- package/dist/cjs/blockMenuPlugin.js +13 -2
- package/dist/cjs/editor-actions/isTransformToTargetDisabled.js +13 -1
- package/dist/cjs/editor-actions/transformSource.js +23 -0
- package/dist/cjs/editor-actions/transformSourceRegistry.js +54 -0
- package/dist/cjs/editor-commands/transformNode.js +133 -25
- package/dist/cjs/ui/utils/checkIsFormatMenuHidden.js +3 -1
- package/dist/es2019/blockMenuPlugin.js +13 -4
- package/dist/es2019/editor-actions/isTransformToTargetDisabled.js +13 -1
- package/dist/es2019/editor-actions/transformSource.js +15 -0
- package/dist/es2019/editor-actions/transformSourceRegistry.js +49 -0
- package/dist/es2019/editor-commands/transformNode.js +122 -12
- package/dist/es2019/ui/block-menu-components.js +3 -5
- package/dist/es2019/ui/utils/checkIsFormatMenuHidden.js +3 -1
- package/dist/esm/blockMenuPlugin.js +13 -2
- package/dist/esm/editor-actions/isTransformToTargetDisabled.js +13 -1
- package/dist/esm/editor-actions/transformSource.js +17 -0
- package/dist/esm/editor-actions/transformSourceRegistry.js +48 -0
- package/dist/esm/editor-commands/transformNode.js +131 -24
- package/dist/esm/ui/utils/checkIsFormatMenuHidden.js +3 -1
- package/dist/types/blockMenuPluginType.d.ts +2 -0
- package/dist/types/editor-actions/isTransformToTargetDisabled.d.ts +3 -1
- package/dist/types/editor-actions/transformSource.d.ts +4 -0
- package/dist/types/editor-actions/transformSourceRegistry.d.ts +13 -0
- package/dist/types/editor-commands/transformNode.d.ts +2 -1
- package/package.json +5 -4
- package/tsconfig.json +5 -2
|
@@ -3,13 +3,16 @@ import { expandedState } from '@atlaskit/editor-common/expand';
|
|
|
3
3
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
4
4
|
import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
|
|
5
5
|
import { expandSelectionToBlockRange, getSourceNodesFromSelectionRange } from '@atlaskit/editor-common/selection';
|
|
6
|
-
import {
|
|
6
|
+
import { Fragment, Node } from '@atlaskit/editor-prosemirror/model';
|
|
7
|
+
import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
|
|
7
8
|
import { Mapping, StepMap } from '@atlaskit/editor-prosemirror/transform';
|
|
8
9
|
import { CellSelection } from '@atlaskit/editor-tables';
|
|
10
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
11
|
+
import { getSingleTransformSourceNode, isExtensionTransformSource } from '../editor-actions/transformSource';
|
|
9
12
|
import { isNestedNode } from '../ui/utils/isNestedNode';
|
|
10
13
|
import { convertNodesToTargetType } from './transform-node-utils/transform';
|
|
11
14
|
import { isListNode } from './transform-node-utils/utils';
|
|
12
|
-
export const transformNode = api => (targetType, metadata) => ({
|
|
15
|
+
export const transformNode = (api, transformRegistry) => (targetType, metadata) => ({
|
|
13
16
|
tr
|
|
14
17
|
}) => {
|
|
15
18
|
var _api$blockControls, _api$blockControls$sh;
|
|
@@ -17,6 +20,113 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
17
20
|
if (!preservedSelection) {
|
|
18
21
|
return tr;
|
|
19
22
|
}
|
|
23
|
+
if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
|
|
24
|
+
const {
|
|
25
|
+
$from,
|
|
26
|
+
$to,
|
|
27
|
+
range
|
|
28
|
+
} = expandSelectionToBlockRange(preservedSelection);
|
|
29
|
+
const sourceNode = getSingleTransformSourceNode(preservedSelection, range);
|
|
30
|
+
if (isExtensionTransformSource(sourceNode)) {
|
|
31
|
+
var _metadata$targetTypeN;
|
|
32
|
+
const context = {
|
|
33
|
+
source: sourceNode.toJSON(),
|
|
34
|
+
targetTypeName: (_metadata$targetTypeN = metadata === null || metadata === void 0 ? void 0 : metadata.targetTypeName) !== null && _metadata$targetTypeN !== void 0 ? _metadata$targetTypeN : targetType.name
|
|
35
|
+
};
|
|
36
|
+
const resolution = transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve(context);
|
|
37
|
+
if (!resolution || resolution.status === 'unsupported') {
|
|
38
|
+
return tr;
|
|
39
|
+
}
|
|
40
|
+
const measureId = `transformNode_${targetType.name}_${Date.now()}`;
|
|
41
|
+
startMeasure(measureId);
|
|
42
|
+
try {
|
|
43
|
+
var _api$blockControls2, _api$blockControls3;
|
|
44
|
+
const transformResult = resolution.transform.transform(context);
|
|
45
|
+
if (!transformResult) {
|
|
46
|
+
stopMeasure(measureId);
|
|
47
|
+
return tr;
|
|
48
|
+
}
|
|
49
|
+
if (!Array.isArray(transformResult.output) || transformResult.output.length === 0) {
|
|
50
|
+
throw new Error('Block menu transform returned no output');
|
|
51
|
+
}
|
|
52
|
+
const resultNodes = transformResult.output.map(nodeAdf => {
|
|
53
|
+
const node = Node.fromJSON(tr.doc.type.schema, nodeAdf);
|
|
54
|
+
node.check();
|
|
55
|
+
return node;
|
|
56
|
+
});
|
|
57
|
+
if (!range || !range.parent.canReplace(range.startIndex, range.endIndex, Fragment.from(resultNodes))) {
|
|
58
|
+
throw new Error('Block menu transform output is invalid at the selected position');
|
|
59
|
+
}
|
|
60
|
+
const sliceStart = $from.pos;
|
|
61
|
+
tr.replaceWith(sliceStart, $to.pos, resultNodes);
|
|
62
|
+
const insertedNode = tr.doc.nodeAt(sliceStart);
|
|
63
|
+
const nextSelection = insertedNode && NodeSelection.isSelectable(insertedNode) ? NodeSelection.create(tr.doc, sliceStart) : Selection.near(tr.doc.resolve(sliceStart));
|
|
64
|
+
tr.setSelection(nextSelection);
|
|
65
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.stopPreservingSelection()({
|
|
66
|
+
tr
|
|
67
|
+
});
|
|
68
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.toggleBlockMenu({
|
|
69
|
+
closeMenu: true
|
|
70
|
+
})({
|
|
71
|
+
tr
|
|
72
|
+
});
|
|
73
|
+
const {
|
|
74
|
+
expand,
|
|
75
|
+
nestedExpand
|
|
76
|
+
} = tr.doc.type.schema.nodes;
|
|
77
|
+
resultNodes.forEach(node => {
|
|
78
|
+
if (node.type === expand || node.type === nestedExpand) {
|
|
79
|
+
expandedState.set(node, true);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
stopMeasure(measureId, (duration, startTime) => {
|
|
83
|
+
var _api$analytics, _api$analytics$action;
|
|
84
|
+
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.attachAnalyticsEvent({
|
|
85
|
+
action: ACTION.TRANSFORMED,
|
|
86
|
+
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
87
|
+
attributes: {
|
|
88
|
+
duration,
|
|
89
|
+
isEmptyLine: false,
|
|
90
|
+
isNested: isNestedNode(preservedSelection, ''),
|
|
91
|
+
isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
|
|
92
|
+
sourceNodesCount: 1,
|
|
93
|
+
sourceNodesCountByType: {
|
|
94
|
+
[sourceNode.type.name]: 1
|
|
95
|
+
},
|
|
96
|
+
sourceNodeType: sourceNode.type.name,
|
|
97
|
+
startTime,
|
|
98
|
+
targetNodeType: targetType.name,
|
|
99
|
+
outputNodesCount: resultNodes.length,
|
|
100
|
+
inputMethod: INPUT_METHOD.BLOCK_MENU
|
|
101
|
+
},
|
|
102
|
+
eventType: EVENT_TYPE.TRACK
|
|
103
|
+
})(tr);
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
var _api$analytics2, _api$analytics2$actio;
|
|
107
|
+
stopMeasure(measureId);
|
|
108
|
+
logException(error, {
|
|
109
|
+
location: 'editor-plugin-block-menu'
|
|
110
|
+
});
|
|
111
|
+
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.attachAnalyticsEvent({
|
|
112
|
+
action: ACTION.ERRORED,
|
|
113
|
+
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
114
|
+
actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
|
|
115
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
116
|
+
attributes: {
|
|
117
|
+
docSize: tr.doc.nodeSize,
|
|
118
|
+
error: error.message,
|
|
119
|
+
errorStack: error.stack,
|
|
120
|
+
from: sourceNode.type.name,
|
|
121
|
+
inputMethod: INPUT_METHOD.BLOCK_MENU,
|
|
122
|
+
selection: preservedSelection.toJSON(),
|
|
123
|
+
to: targetType.name
|
|
124
|
+
}
|
|
125
|
+
})(tr);
|
|
126
|
+
}
|
|
127
|
+
return tr;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
20
130
|
const measureId = `transformNode_${targetType.name}_${Date.now()}`;
|
|
21
131
|
startMeasure(measureId);
|
|
22
132
|
const {
|
|
@@ -41,7 +151,7 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
41
151
|
const isEmptyLine = sourceNodes.length === 1 && (sourceNodes[0].type === nodes.paragraph || sourceNodes[0].type === nodes.heading) && (sourceNodes[0].content.size === 0 || sourceNodes[0].textContent.trim() === '');
|
|
42
152
|
const isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
|
|
43
153
|
try {
|
|
44
|
-
var _api$
|
|
154
|
+
var _api$blockControls6;
|
|
45
155
|
const resultNodes = convertNodesToTargetType({
|
|
46
156
|
sourceNodes,
|
|
47
157
|
targetNodeType: targetType,
|
|
@@ -62,7 +172,7 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
62
172
|
}
|
|
63
173
|
});
|
|
64
174
|
if (preservedSelection instanceof NodeSelection && preservedSelection.node.type === nodes.mediaSingle) {
|
|
65
|
-
var _api$
|
|
175
|
+
var _api$blockControls4;
|
|
66
176
|
// when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
|
|
67
177
|
const deleteFrom = $from.pos;
|
|
68
178
|
const deleteTo = $to.pos;
|
|
@@ -77,7 +187,7 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
77
187
|
// and stop preserving it
|
|
78
188
|
const oldSize = sourceNodes.reduce((sum, node) => sum + node.nodeSize, 0);
|
|
79
189
|
const newSize = content.reduce((sum, node) => sum + node.nodeSize, 0);
|
|
80
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
190
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.mapPreservedSelection(new Mapping([new StepMap([0, oldSize, newSize])]))({
|
|
81
191
|
tr
|
|
82
192
|
});
|
|
83
193
|
} else {
|
|
@@ -87,22 +197,22 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
87
197
|
const insertedNode = tr.doc.nodeAt($from.pos);
|
|
88
198
|
const isSelectable = insertedNode && NodeSelection.isSelectable(insertedNode);
|
|
89
199
|
if (isSelectable) {
|
|
90
|
-
var _api$
|
|
200
|
+
var _api$blockControls5;
|
|
91
201
|
const nodeSelection = NodeSelection.create(tr.doc, $from.pos);
|
|
92
202
|
tr.setSelection(nodeSelection);
|
|
93
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
203
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.startPreservingSelection()({
|
|
94
204
|
tr
|
|
95
205
|
});
|
|
96
206
|
}
|
|
97
207
|
}
|
|
98
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
208
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 ? void 0 : _api$blockControls6.commands.toggleBlockMenu({
|
|
99
209
|
closeMenu: true
|
|
100
210
|
})({
|
|
101
211
|
tr
|
|
102
212
|
});
|
|
103
213
|
stopMeasure(measureId, (duration, startTime) => {
|
|
104
|
-
var _api$
|
|
105
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
214
|
+
var _api$analytics3, _api$analytics3$actio;
|
|
215
|
+
api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : (_api$analytics3$actio = _api$analytics3.actions) === null || _api$analytics3$actio === void 0 ? void 0 : _api$analytics3$actio.attachAnalyticsEvent({
|
|
106
216
|
action: ACTION.TRANSFORMED,
|
|
107
217
|
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
108
218
|
attributes: {
|
|
@@ -122,12 +232,12 @@ export const transformNode = api => (targetType, metadata) => ({
|
|
|
122
232
|
})(tr);
|
|
123
233
|
});
|
|
124
234
|
} catch (error) {
|
|
125
|
-
var _api$
|
|
235
|
+
var _api$analytics4, _api$analytics4$actio;
|
|
126
236
|
stopMeasure(measureId);
|
|
127
237
|
logException(error, {
|
|
128
238
|
location: 'editor-plugin-block-menu'
|
|
129
239
|
});
|
|
130
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
240
|
+
api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : (_api$analytics4$actio = _api$analytics4.actions) === null || _api$analytics4$actio === void 0 ? void 0 : _api$analytics4$actio.attachAnalyticsEvent({
|
|
131
241
|
action: ACTION.ERRORED,
|
|
132
242
|
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
133
243
|
actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
|
|
@@ -173,11 +173,9 @@ const getTurnIntoMenuComponents = api => {
|
|
|
173
173
|
rank: MAIN_BLOCK_MENU_SECTION_RANK[TRANSFORM_MENU_SECTION.key],
|
|
174
174
|
component: ({
|
|
175
175
|
children
|
|
176
|
-
}) => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}, children);
|
|
180
|
-
}
|
|
176
|
+
}) => /*#__PURE__*/React.createElement(FormatMenuSection, {
|
|
177
|
+
api: api
|
|
178
|
+
}, children)
|
|
181
179
|
}];
|
|
182
180
|
};
|
|
183
181
|
export const getBlockMenuComponents = ({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import memoizeOne from 'memoize-one';
|
|
2
2
|
import { findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
3
4
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
4
5
|
const getDisabledNodeTypes = memoizeOne(nodes => [nodes.rule, ...(expValEquals('confluence_native_tabs_experiment', 'isEnabled', true) ? [nodes.multiBodiedExtension] : [])]);
|
|
5
6
|
const getIsFormatMenuHidden = (selection, schema) => {
|
|
@@ -7,7 +8,8 @@ const getIsFormatMenuHidden = (selection, schema) => {
|
|
|
7
8
|
if (!nodes) {
|
|
8
9
|
return false;
|
|
9
10
|
}
|
|
10
|
-
const
|
|
11
|
+
const disabledNodeTypes = isExperimentEnabled('platform_editor_block_menu_transform_extensions') ? [nodes.rule] : getDisabledNodeTypes(nodes);
|
|
12
|
+
const disabledNode = findSelectedNodeOfType(disabledNodeTypes)(selection);
|
|
11
13
|
return !!disabledNode;
|
|
12
14
|
};
|
|
13
15
|
export const checkIsFormatMenuHidden = api => {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
3
4
|
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
4
5
|
import { createBlockMenuRegistry } from './editor-actions';
|
|
5
6
|
import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
|
|
7
|
+
import { createBlockMenuTransformSourceRegistry } from './editor-actions/transformSourceRegistry';
|
|
6
8
|
import { transformNode as _transformNode } from './editor-commands/transformNode';
|
|
7
9
|
import { getBlockMenuExperiencesPlugin } from './pm-plugins/experiences/block-menu-experiences';
|
|
8
10
|
import { keymapPlugin } from './pm-plugins/keymap';
|
|
@@ -15,6 +17,7 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
|
|
|
15
17
|
var api = _ref.api,
|
|
16
18
|
config = _ref.config;
|
|
17
19
|
var registry = createBlockMenuRegistry();
|
|
20
|
+
var transformSourceRegistry = isExperimentEnabled('platform_editor_block_menu_transform_extensions') ? createBlockMenuTransformSourceRegistry() : undefined;
|
|
18
21
|
registry.register(getBlockMenuComponents({
|
|
19
22
|
api: api,
|
|
20
23
|
config: config
|
|
@@ -64,13 +67,21 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
|
|
|
64
67
|
return isTransformToTargetDisabled({
|
|
65
68
|
selection: currentSelection,
|
|
66
69
|
targetNodeTypeName: optionNodeTypeName,
|
|
67
|
-
targetNodeTypeAttrs: optionNodeTypeAttrs
|
|
70
|
+
targetNodeTypeAttrs: optionNodeTypeAttrs,
|
|
71
|
+
transformRegistry: transformSourceRegistry
|
|
68
72
|
});
|
|
73
|
+
},
|
|
74
|
+
registerBlockMenuTransforms: function registerBlockMenuTransforms(transforms) {
|
|
75
|
+
if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
|
|
76
|
+
var _transformSourceRegis;
|
|
77
|
+
return (_transformSourceRegis = transformSourceRegistry === null || transformSourceRegistry === void 0 ? void 0 : transformSourceRegistry.register(transforms)) !== null && _transformSourceRegis !== void 0 ? _transformSourceRegis : function () {};
|
|
78
|
+
}
|
|
79
|
+
return function () {};
|
|
69
80
|
}
|
|
70
81
|
},
|
|
71
82
|
commands: {
|
|
72
83
|
transformNode: function transformNode(targetType, metadata) {
|
|
73
|
-
return _transformNode(api)(targetType, metadata);
|
|
84
|
+
return _transformNode(api, transformSourceRegistry)(targetType, metadata);
|
|
74
85
|
}
|
|
75
86
|
},
|
|
76
87
|
getSharedState: function getSharedState(editorState) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
3
4
|
import { isTransformDisabledBasedOnStepsConfig } from '../editor-commands/transform-node-utils/transform';
|
|
4
5
|
import { toNodeTypeValue } from '../editor-commands/transform-node-utils/types';
|
|
5
6
|
import { getBlockNodesInRange, getTargetNodeTypeNameInContext } from '../editor-commands/transform-node-utils/utils';
|
|
7
|
+
import { getSingleTransformSourceNode, isExtensionTransformSource } from './transformSource';
|
|
6
8
|
export var canParentContainNodeType = function canParentContainNodeType(schema, selectedNodeTypeName, parentNode, nodeTypeName, nodeTypeAttrs) {
|
|
7
9
|
var adjustedNodeTypeName = getTargetNodeTypeNameInContext(nodeTypeName, true, parentNode, schema);
|
|
8
10
|
if (!adjustedNodeTypeName) {
|
|
@@ -46,12 +48,22 @@ var isTransformEnabledForNode = function isTransformEnabledForNode(node, targetN
|
|
|
46
48
|
export var isTransformToTargetDisabled = function isTransformToTargetDisabled(_ref) {
|
|
47
49
|
var selection = _ref.selection,
|
|
48
50
|
targetNodeTypeName = _ref.targetNodeTypeName,
|
|
49
|
-
targetNodeTypeAttrs = _ref.targetNodeTypeAttrs
|
|
51
|
+
targetNodeTypeAttrs = _ref.targetNodeTypeAttrs,
|
|
52
|
+
transformRegistry = _ref.transformRegistry;
|
|
50
53
|
var _expandSelectionToBlo = expandSelectionToBlockRange(selection),
|
|
51
54
|
range = _expandSelectionToBlo.range;
|
|
52
55
|
if (!range) {
|
|
53
56
|
return false;
|
|
54
57
|
}
|
|
58
|
+
if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
|
|
59
|
+
var sourceNode = getSingleTransformSourceNode(selection, range);
|
|
60
|
+
if (isExtensionTransformSource(sourceNode)) {
|
|
61
|
+
return (transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve({
|
|
62
|
+
source: sourceNode.toJSON(),
|
|
63
|
+
targetTypeName: targetNodeTypeName
|
|
64
|
+
}).status) !== 'supported';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
55
67
|
var selectedNodes = getBlockNodesInRange(range);
|
|
56
68
|
var parent = range.parent;
|
|
57
69
|
var isNested = range.depth >= 1;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getBlockNodesInRange, getSelectedNode } from '../editor-commands/transform-node-utils/utils';
|
|
2
|
+
var EXTENSION_NODE_TYPES = new Set(['extension', 'bodiedExtension', 'multiBodiedExtension']);
|
|
3
|
+
export var getSingleTransformSourceNode = function getSingleTransformSourceNode(selection, range) {
|
|
4
|
+
var _getSelectedNode;
|
|
5
|
+
var selectedNode = (_getSelectedNode = getSelectedNode(selection)) === null || _getSelectedNode === void 0 ? void 0 : _getSelectedNode.node;
|
|
6
|
+
if (selectedNode) {
|
|
7
|
+
return selectedNode;
|
|
8
|
+
}
|
|
9
|
+
if (!range) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
var blockNodes = getBlockNodesInRange(range);
|
|
13
|
+
return blockNodes.length === 1 ? blockNodes[0] : undefined;
|
|
14
|
+
};
|
|
15
|
+
export var isExtensionTransformSource = function isExtensionTransformSource(node) {
|
|
16
|
+
return Boolean(node && EXTENSION_NODE_TYPES.has(node.type.name));
|
|
17
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
export var createBlockMenuTransformSourceRegistry = function createBlockMenuTransformSourceRegistry() {
|
|
3
|
+
var transforms = new Map();
|
|
4
|
+
return {
|
|
5
|
+
register: function register(registeredTransforms) {
|
|
6
|
+
var registered = [];
|
|
7
|
+
registeredTransforms.forEach(function (transform) {
|
|
8
|
+
if (transforms.has(transform.key)) {
|
|
9
|
+
void logException(new Error("Duplicate Block Menu transform key: ".concat(transform.key)), {
|
|
10
|
+
location: 'editor-plugin-block-menu'
|
|
11
|
+
});
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
transforms.set(transform.key, transform);
|
|
15
|
+
registered.push(transform);
|
|
16
|
+
});
|
|
17
|
+
if (registered.length === 0) {
|
|
18
|
+
return function () {};
|
|
19
|
+
}
|
|
20
|
+
return function () {
|
|
21
|
+
registered.forEach(function (transform) {
|
|
22
|
+
if (transforms.get(transform.key) === transform) {
|
|
23
|
+
transforms.delete(transform.key);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
resolve: function resolve(context) {
|
|
29
|
+
var transform = Array.from(transforms.values()).find(function (_ref) {
|
|
30
|
+
var isSupported = _ref.isSupported;
|
|
31
|
+
try {
|
|
32
|
+
return isSupported(context);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
void logException(error instanceof Error ? error : new Error('Block Menu transform support check failed'), {
|
|
35
|
+
location: 'editor-plugin-block-menu'
|
|
36
|
+
});
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return transform ? {
|
|
41
|
+
status: 'supported',
|
|
42
|
+
transform: transform
|
|
43
|
+
} : {
|
|
44
|
+
status: 'unsupported'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
1
2
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
3
|
import { expandedState } from '@atlaskit/editor-common/expand';
|
|
3
4
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
4
5
|
import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
|
|
5
6
|
import { expandSelectionToBlockRange, getSourceNodesFromSelectionRange } from '@atlaskit/editor-common/selection';
|
|
6
|
-
import {
|
|
7
|
+
import { Fragment, Node } from '@atlaskit/editor-prosemirror/model';
|
|
8
|
+
import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
|
|
7
9
|
import { Mapping, StepMap } from '@atlaskit/editor-prosemirror/transform';
|
|
8
10
|
import { CellSelection } from '@atlaskit/editor-tables';
|
|
11
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
12
|
+
import { getSingleTransformSourceNode, isExtensionTransformSource } from '../editor-actions/transformSource';
|
|
9
13
|
import { isNestedNode } from '../ui/utils/isNestedNode';
|
|
10
14
|
import { convertNodesToTargetType } from './transform-node-utils/transform';
|
|
11
15
|
import { isListNode } from './transform-node-utils/utils';
|
|
12
|
-
export var transformNode = function transformNode(api) {
|
|
16
|
+
export var transformNode = function transformNode(api, transformRegistry) {
|
|
13
17
|
return function (targetType, metadata) {
|
|
14
18
|
return function (_ref) {
|
|
15
19
|
var _api$blockControls;
|
|
@@ -18,12 +22,115 @@ export var transformNode = function transformNode(api) {
|
|
|
18
22
|
if (!preservedSelection) {
|
|
19
23
|
return tr;
|
|
20
24
|
}
|
|
25
|
+
if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
|
|
26
|
+
var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection),
|
|
27
|
+
_$from = _expandSelectionToBlo.$from,
|
|
28
|
+
_$to = _expandSelectionToBlo.$to,
|
|
29
|
+
range = _expandSelectionToBlo.range;
|
|
30
|
+
var sourceNode = getSingleTransformSourceNode(preservedSelection, range);
|
|
31
|
+
if (isExtensionTransformSource(sourceNode)) {
|
|
32
|
+
var _metadata$targetTypeN;
|
|
33
|
+
var context = {
|
|
34
|
+
source: sourceNode.toJSON(),
|
|
35
|
+
targetTypeName: (_metadata$targetTypeN = metadata === null || metadata === void 0 ? void 0 : metadata.targetTypeName) !== null && _metadata$targetTypeN !== void 0 ? _metadata$targetTypeN : targetType.name
|
|
36
|
+
};
|
|
37
|
+
var resolution = transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve(context);
|
|
38
|
+
if (!resolution || resolution.status === 'unsupported') {
|
|
39
|
+
return tr;
|
|
40
|
+
}
|
|
41
|
+
var _measureId = "transformNode_".concat(targetType.name, "_").concat(Date.now());
|
|
42
|
+
startMeasure(_measureId);
|
|
43
|
+
try {
|
|
44
|
+
var _api$blockControls2, _api$blockControls3;
|
|
45
|
+
var transformResult = resolution.transform.transform(context);
|
|
46
|
+
if (!transformResult) {
|
|
47
|
+
stopMeasure(_measureId);
|
|
48
|
+
return tr;
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(transformResult.output) || transformResult.output.length === 0) {
|
|
51
|
+
throw new Error('Block menu transform returned no output');
|
|
52
|
+
}
|
|
53
|
+
var resultNodes = transformResult.output.map(function (nodeAdf) {
|
|
54
|
+
var node = Node.fromJSON(tr.doc.type.schema, nodeAdf);
|
|
55
|
+
node.check();
|
|
56
|
+
return node;
|
|
57
|
+
});
|
|
58
|
+
if (!range || !range.parent.canReplace(range.startIndex, range.endIndex, Fragment.from(resultNodes))) {
|
|
59
|
+
throw new Error('Block menu transform output is invalid at the selected position');
|
|
60
|
+
}
|
|
61
|
+
var sliceStart = _$from.pos;
|
|
62
|
+
tr.replaceWith(sliceStart, _$to.pos, resultNodes);
|
|
63
|
+
var insertedNode = tr.doc.nodeAt(sliceStart);
|
|
64
|
+
var nextSelection = insertedNode && NodeSelection.isSelectable(insertedNode) ? NodeSelection.create(tr.doc, sliceStart) : Selection.near(tr.doc.resolve(sliceStart));
|
|
65
|
+
tr.setSelection(nextSelection);
|
|
66
|
+
api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.stopPreservingSelection()({
|
|
67
|
+
tr: tr
|
|
68
|
+
});
|
|
69
|
+
api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
|
|
70
|
+
closeMenu: true
|
|
71
|
+
})({
|
|
72
|
+
tr: tr
|
|
73
|
+
});
|
|
74
|
+
var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
|
|
75
|
+
expand = _tr$doc$type$schema$n.expand,
|
|
76
|
+
nestedExpand = _tr$doc$type$schema$n.nestedExpand;
|
|
77
|
+
resultNodes.forEach(function (node) {
|
|
78
|
+
if (node.type === expand || node.type === nestedExpand) {
|
|
79
|
+
expandedState.set(node, true);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
stopMeasure(_measureId, function (duration, startTime) {
|
|
83
|
+
var _api$analytics;
|
|
84
|
+
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.attachAnalyticsEvent({
|
|
85
|
+
action: ACTION.TRANSFORMED,
|
|
86
|
+
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
87
|
+
attributes: {
|
|
88
|
+
duration: duration,
|
|
89
|
+
isEmptyLine: false,
|
|
90
|
+
isNested: isNestedNode(preservedSelection, ''),
|
|
91
|
+
isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
|
|
92
|
+
sourceNodesCount: 1,
|
|
93
|
+
sourceNodesCountByType: _defineProperty({}, sourceNode.type.name, 1),
|
|
94
|
+
sourceNodeType: sourceNode.type.name,
|
|
95
|
+
startTime: startTime,
|
|
96
|
+
targetNodeType: targetType.name,
|
|
97
|
+
outputNodesCount: resultNodes.length,
|
|
98
|
+
inputMethod: INPUT_METHOD.BLOCK_MENU
|
|
99
|
+
},
|
|
100
|
+
eventType: EVENT_TYPE.TRACK
|
|
101
|
+
})(tr);
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
var _api$analytics2;
|
|
105
|
+
stopMeasure(_measureId);
|
|
106
|
+
logException(error, {
|
|
107
|
+
location: 'editor-plugin-block-menu'
|
|
108
|
+
});
|
|
109
|
+
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.attachAnalyticsEvent({
|
|
110
|
+
action: ACTION.ERRORED,
|
|
111
|
+
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
112
|
+
actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
|
|
113
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
114
|
+
attributes: {
|
|
115
|
+
docSize: tr.doc.nodeSize,
|
|
116
|
+
error: error.message,
|
|
117
|
+
errorStack: error.stack,
|
|
118
|
+
from: sourceNode.type.name,
|
|
119
|
+
inputMethod: INPUT_METHOD.BLOCK_MENU,
|
|
120
|
+
selection: preservedSelection.toJSON(),
|
|
121
|
+
to: targetType.name
|
|
122
|
+
}
|
|
123
|
+
})(tr);
|
|
124
|
+
}
|
|
125
|
+
return tr;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
21
128
|
var measureId = "transformNode_".concat(targetType.name, "_").concat(Date.now());
|
|
22
129
|
startMeasure(measureId);
|
|
23
130
|
var nodes = tr.doc.type.schema.nodes;
|
|
24
|
-
var
|
|
25
|
-
$from =
|
|
26
|
-
$to =
|
|
131
|
+
var _expandSelectionToBlo2 = expandSelectionToBlockRange(preservedSelection),
|
|
132
|
+
$from = _expandSelectionToBlo2.$from,
|
|
133
|
+
$to = _expandSelectionToBlo2.$to;
|
|
27
134
|
var selectedParent = $from.parent;
|
|
28
135
|
var isParentLayout = selectedParent.type === nodes.layoutColumn;
|
|
29
136
|
var isNested = isNestedNode(preservedSelection, '') && !isParentLayout;
|
|
@@ -39,8 +146,8 @@ export var transformNode = function transformNode(api) {
|
|
|
39
146
|
var isEmptyLine = sourceNodes.length === 1 && (sourceNodes[0].type === nodes.paragraph || sourceNodes[0].type === nodes.heading) && (sourceNodes[0].content.size === 0 || sourceNodes[0].textContent.trim() === '');
|
|
40
147
|
var isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
|
|
41
148
|
try {
|
|
42
|
-
var _api$
|
|
43
|
-
var
|
|
149
|
+
var _api$blockControls6;
|
|
150
|
+
var _resultNodes = convertNodesToTargetType({
|
|
44
151
|
sourceNodes: sourceNodes,
|
|
45
152
|
targetNodeType: targetType,
|
|
46
153
|
schema: tr.doc.type.schema,
|
|
@@ -48,17 +155,17 @@ export var transformNode = function transformNode(api) {
|
|
|
48
155
|
targetAttrs: metadata === null || metadata === void 0 ? void 0 : metadata.targetAttrs,
|
|
49
156
|
parentNode: selectedParent
|
|
50
157
|
});
|
|
51
|
-
var content =
|
|
52
|
-
var
|
|
53
|
-
var
|
|
54
|
-
|
|
158
|
+
var content = _resultNodes.length > 0 ? _resultNodes : sourceNodes;
|
|
159
|
+
var _sliceStart = isList ? $from.pos - 1 : $from.pos;
|
|
160
|
+
var _expand = nodes.expand,
|
|
161
|
+
_nestedExpand = nodes.nestedExpand;
|
|
55
162
|
content.forEach(function (node) {
|
|
56
|
-
if (node.type ===
|
|
163
|
+
if (node.type === _expand || node.type === _nestedExpand) {
|
|
57
164
|
expandedState.set(node, true);
|
|
58
165
|
}
|
|
59
166
|
});
|
|
60
167
|
if (preservedSelection instanceof NodeSelection && preservedSelection.node.type === nodes.mediaSingle) {
|
|
61
|
-
var _api$
|
|
168
|
+
var _api$blockControls4;
|
|
62
169
|
// when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
|
|
63
170
|
var deleteFrom = $from.pos;
|
|
64
171
|
var deleteTo = $to.pos;
|
|
@@ -77,32 +184,32 @@ export var transformNode = function transformNode(api) {
|
|
|
77
184
|
var newSize = content.reduce(function (sum, node) {
|
|
78
185
|
return sum + node.nodeSize;
|
|
79
186
|
}, 0);
|
|
80
|
-
api === null || api === void 0 || (_api$
|
|
187
|
+
api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.mapPreservedSelection(new Mapping([new StepMap([0, oldSize, newSize])]))({
|
|
81
188
|
tr: tr
|
|
82
189
|
});
|
|
83
190
|
} else {
|
|
84
|
-
tr.replaceWith(
|
|
191
|
+
tr.replaceWith(_sliceStart, $to.pos, content);
|
|
85
192
|
}
|
|
86
193
|
if (preservedSelection instanceof CellSelection) {
|
|
87
|
-
var
|
|
88
|
-
var isSelectable =
|
|
194
|
+
var _insertedNode = tr.doc.nodeAt($from.pos);
|
|
195
|
+
var isSelectable = _insertedNode && NodeSelection.isSelectable(_insertedNode);
|
|
89
196
|
if (isSelectable) {
|
|
90
|
-
var _api$
|
|
197
|
+
var _api$blockControls5;
|
|
91
198
|
var nodeSelection = NodeSelection.create(tr.doc, $from.pos);
|
|
92
199
|
tr.setSelection(nodeSelection);
|
|
93
|
-
api === null || api === void 0 || (_api$
|
|
200
|
+
api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.startPreservingSelection()({
|
|
94
201
|
tr: tr
|
|
95
202
|
});
|
|
96
203
|
}
|
|
97
204
|
}
|
|
98
|
-
api === null || api === void 0 || (_api$
|
|
205
|
+
api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.toggleBlockMenu({
|
|
99
206
|
closeMenu: true
|
|
100
207
|
})({
|
|
101
208
|
tr: tr
|
|
102
209
|
});
|
|
103
210
|
stopMeasure(measureId, function (duration, startTime) {
|
|
104
|
-
var _api$
|
|
105
|
-
api === null || api === void 0 || (_api$
|
|
211
|
+
var _api$analytics3;
|
|
212
|
+
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.attachAnalyticsEvent({
|
|
106
213
|
action: ACTION.TRANSFORMED,
|
|
107
214
|
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
108
215
|
attributes: {
|
|
@@ -122,12 +229,12 @@ export var transformNode = function transformNode(api) {
|
|
|
122
229
|
})(tr);
|
|
123
230
|
});
|
|
124
231
|
} catch (error) {
|
|
125
|
-
var _api$
|
|
232
|
+
var _api$analytics4;
|
|
126
233
|
stopMeasure(measureId);
|
|
127
234
|
logException(error, {
|
|
128
235
|
location: 'editor-plugin-block-menu'
|
|
129
236
|
});
|
|
130
|
-
api === null || api === void 0 || (_api$
|
|
237
|
+
api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || (_api$analytics4 = _api$analytics4.actions) === null || _api$analytics4 === void 0 || _api$analytics4.attachAnalyticsEvent({
|
|
131
238
|
action: ACTION.ERRORED,
|
|
132
239
|
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
133
240
|
actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
2
|
import memoizeOne from 'memoize-one';
|
|
3
3
|
import { findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
4
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
4
5
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
5
6
|
var getDisabledNodeTypes = memoizeOne(function (nodes) {
|
|
6
7
|
return [nodes.rule].concat(_toConsumableArray(expValEquals('confluence_native_tabs_experiment', 'isEnabled', true) ? [nodes.multiBodiedExtension] : []));
|
|
@@ -10,7 +11,8 @@ var getIsFormatMenuHidden = function getIsFormatMenuHidden(selection, schema) {
|
|
|
10
11
|
if (!nodes) {
|
|
11
12
|
return false;
|
|
12
13
|
}
|
|
13
|
-
var
|
|
14
|
+
var disabledNodeTypes = isExperimentEnabled('platform_editor_block_menu_transform_extensions') ? [nodes.rule] : getDisabledNodeTypes(nodes);
|
|
15
|
+
var disabledNode = findSelectedNodeOfType(disabledNodeTypes)(selection);
|
|
14
16
|
return !!disabledNode;
|
|
15
17
|
};
|
|
16
18
|
export var checkIsFormatMenuHidden = function checkIsFormatMenuHidden(api) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BlockTransformExtension } from '@atlaskit/editor-common/block-menu/block-transform-extension';
|
|
1
2
|
import type { EditorCommand, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
|
|
2
3
|
import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
|
|
3
4
|
import type { BlockControlsPlugin } from '@atlaskit/editor-plugin-block-controls';
|
|
@@ -15,6 +16,7 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
|
|
|
15
16
|
getBlockMenuComponents: () => Array<RegisterBlockMenuComponent>;
|
|
16
17
|
isTransformOptionDisabled: (optionNodeTypeName: string, optionNodeTypeAttrs?: Record<string, unknown>) => boolean;
|
|
17
18
|
registerBlockMenuComponents: (blockMenuComponents: Array<RegisterBlockMenuComponent>) => void;
|
|
19
|
+
registerBlockMenuTransforms: (transforms: readonly BlockTransformExtension[]) => () => void;
|
|
18
20
|
};
|
|
19
21
|
commands: {
|
|
20
22
|
transformNode: TransformNodeCommand;
|