@atlaskit/editor-plugin-block-menu 12.0.2 → 12.1.0

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.
Files changed (29) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/afm-products/tsconfig.json +3 -0
  4. package/dist/cjs/blockMenuPlugin.js +13 -2
  5. package/dist/cjs/editor-actions/isTransformToTargetDisabled.js +13 -1
  6. package/dist/cjs/editor-actions/transformSource.js +23 -0
  7. package/dist/cjs/editor-actions/transformSourceRegistry.js +54 -0
  8. package/dist/cjs/editor-commands/transformNode.js +133 -25
  9. package/dist/cjs/ui/utils/checkIsFormatMenuHidden.js +3 -1
  10. package/dist/es2019/blockMenuPlugin.js +13 -4
  11. package/dist/es2019/editor-actions/isTransformToTargetDisabled.js +13 -1
  12. package/dist/es2019/editor-actions/transformSource.js +15 -0
  13. package/dist/es2019/editor-actions/transformSourceRegistry.js +49 -0
  14. package/dist/es2019/editor-commands/transformNode.js +122 -12
  15. package/dist/es2019/ui/block-menu-components.js +3 -5
  16. package/dist/es2019/ui/utils/checkIsFormatMenuHidden.js +3 -1
  17. package/dist/esm/blockMenuPlugin.js +13 -2
  18. package/dist/esm/editor-actions/isTransformToTargetDisabled.js +13 -1
  19. package/dist/esm/editor-actions/transformSource.js +17 -0
  20. package/dist/esm/editor-actions/transformSourceRegistry.js +48 -0
  21. package/dist/esm/editor-commands/transformNode.js +131 -24
  22. package/dist/esm/ui/utils/checkIsFormatMenuHidden.js +3 -1
  23. package/dist/types/blockMenuPluginType.d.ts +2 -0
  24. package/dist/types/editor-actions/isTransformToTargetDisabled.d.ts +3 -1
  25. package/dist/types/editor-actions/transformSource.d.ts +4 -0
  26. package/dist/types/editor-actions/transformSourceRegistry.d.ts +13 -0
  27. package/dist/types/editor-commands/transformNode.d.ts +2 -1
  28. package/package.json +4 -3
  29. package/tsconfig.json +5 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 12.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`337e6777c26aa`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/337e6777c26aa) -
8
+ Add Block Menu transform extension APIs. Extension manifests can declare ADF-only transform
9
+ capabilities without importing Editor internals:
10
+
11
+ ```ts
12
+ const extensionNode = {
13
+ blockTransform: {
14
+ key: 'convert-tabs-to-panel',
15
+ isSupported: ({ targetTypeName }) => targetTypeName === 'panel',
16
+ transform: ({ source }) => ({ output: [{ type: 'panel', content: source.content }] }),
17
+ },
18
+ };
19
+ ```
20
+
21
+ The Extension Plugin registers each keyed transform with Block Menu after manifests load. Block
22
+ Menu checks support, validates returned ADF, and owns replacement, selection, history, focus, and
23
+ analytics.
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies
28
+
29
+ ## 12.0.3
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies
34
+
3
35
  ## 12.0.2
4
36
 
5
37
  ### Patch Changes
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../design-system/icon/afm-cc/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-experiments/afm-cc/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../platform/feature-flags/afm-cc/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../design-system/icon/afm-products/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-experiments/afm-products/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../platform/feature-flags/afm-products/tsconfig.json"
61
64
  },
@@ -7,9 +7,11 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.blockMenuPlugin = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _react = _interopRequireDefault(require("react"));
10
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
10
11
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
11
12
  var _editorActions = require("./editor-actions");
12
13
  var _isTransformToTargetDisabled = require("./editor-actions/isTransformToTargetDisabled");
14
+ var _transformSourceRegistry = require("./editor-actions/transformSourceRegistry");
13
15
  var _transformNode2 = require("./editor-commands/transformNode");
14
16
  var _blockMenuExperiences = require("./pm-plugins/experiences/block-menu-experiences");
15
17
  var _keymap = require("./pm-plugins/keymap");
@@ -22,6 +24,7 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
22
24
  var api = _ref.api,
23
25
  config = _ref.config;
24
26
  var registry = (0, _editorActions.createBlockMenuRegistry)();
27
+ var transformSourceRegistry = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions') ? (0, _transformSourceRegistry.createBlockMenuTransformSourceRegistry)() : undefined;
25
28
  registry.register((0, _blockMenuComponents.getBlockMenuComponents)({
26
29
  api: api,
27
30
  config: config
@@ -71,13 +74,21 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
71
74
  return (0, _isTransformToTargetDisabled.isTransformToTargetDisabled)({
72
75
  selection: currentSelection,
73
76
  targetNodeTypeName: optionNodeTypeName,
74
- targetNodeTypeAttrs: optionNodeTypeAttrs
77
+ targetNodeTypeAttrs: optionNodeTypeAttrs,
78
+ transformRegistry: transformSourceRegistry
75
79
  });
80
+ },
81
+ registerBlockMenuTransforms: function registerBlockMenuTransforms(transforms) {
82
+ if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions')) {
83
+ var _transformSourceRegis;
84
+ return (_transformSourceRegis = transformSourceRegistry === null || transformSourceRegistry === void 0 ? void 0 : transformSourceRegistry.register(transforms)) !== null && _transformSourceRegis !== void 0 ? _transformSourceRegis : function () {};
85
+ }
86
+ return function () {};
76
87
  }
77
88
  },
78
89
  commands: {
79
90
  transformNode: function transformNode(targetType, metadata) {
80
- return (0, _transformNode2.transformNode)(api)(targetType, metadata);
91
+ return (0, _transformNode2.transformNode)(api, transformSourceRegistry)(targetType, metadata);
81
92
  }
82
93
  },
83
94
  getSharedState: function getSharedState(editorState) {
@@ -6,9 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.isTransformToTargetDisabled = exports.canParentContainNodeType = void 0;
7
7
  var _selection = require("@atlaskit/editor-common/selection");
8
8
  var _model = require("@atlaskit/editor-prosemirror/model");
9
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
9
10
  var _transform = require("../editor-commands/transform-node-utils/transform");
10
11
  var _types = require("../editor-commands/transform-node-utils/types");
11
12
  var _utils = require("../editor-commands/transform-node-utils/utils");
13
+ var _transformSource = require("./transformSource");
12
14
  var canParentContainNodeType = exports.canParentContainNodeType = function canParentContainNodeType(schema, selectedNodeTypeName, parentNode, nodeTypeName, nodeTypeAttrs) {
13
15
  var adjustedNodeTypeName = (0, _utils.getTargetNodeTypeNameInContext)(nodeTypeName, true, parentNode, schema);
14
16
  if (!adjustedNodeTypeName) {
@@ -52,12 +54,22 @@ var isTransformEnabledForNode = function isTransformEnabledForNode(node, targetN
52
54
  var isTransformToTargetDisabled = exports.isTransformToTargetDisabled = function isTransformToTargetDisabled(_ref) {
53
55
  var selection = _ref.selection,
54
56
  targetNodeTypeName = _ref.targetNodeTypeName,
55
- targetNodeTypeAttrs = _ref.targetNodeTypeAttrs;
57
+ targetNodeTypeAttrs = _ref.targetNodeTypeAttrs,
58
+ transformRegistry = _ref.transformRegistry;
56
59
  var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(selection),
57
60
  range = _expandSelectionToBlo.range;
58
61
  if (!range) {
59
62
  return false;
60
63
  }
64
+ if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions')) {
65
+ var sourceNode = (0, _transformSource.getSingleTransformSourceNode)(selection, range);
66
+ if ((0, _transformSource.isExtensionTransformSource)(sourceNode)) {
67
+ return (transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve({
68
+ source: sourceNode.toJSON(),
69
+ targetTypeName: targetNodeTypeName
70
+ }).status) !== 'supported';
71
+ }
72
+ }
61
73
  var selectedNodes = (0, _utils.getBlockNodesInRange)(range);
62
74
  var parent = range.parent;
63
75
  var isNested = range.depth >= 1;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isExtensionTransformSource = exports.getSingleTransformSourceNode = void 0;
7
+ var _utils = require("../editor-commands/transform-node-utils/utils");
8
+ var EXTENSION_NODE_TYPES = new Set(['extension', 'bodiedExtension', 'multiBodiedExtension']);
9
+ var getSingleTransformSourceNode = exports.getSingleTransformSourceNode = function getSingleTransformSourceNode(selection, range) {
10
+ var _getSelectedNode;
11
+ var selectedNode = (_getSelectedNode = (0, _utils.getSelectedNode)(selection)) === null || _getSelectedNode === void 0 ? void 0 : _getSelectedNode.node;
12
+ if (selectedNode) {
13
+ return selectedNode;
14
+ }
15
+ if (!range) {
16
+ return undefined;
17
+ }
18
+ var blockNodes = (0, _utils.getBlockNodesInRange)(range);
19
+ return blockNodes.length === 1 ? blockNodes[0] : undefined;
20
+ };
21
+ var isExtensionTransformSource = exports.isExtensionTransformSource = function isExtensionTransformSource(node) {
22
+ return Boolean(node && EXTENSION_NODE_TYPES.has(node.type.name));
23
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createBlockMenuTransformSourceRegistry = void 0;
7
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
8
+ var createBlockMenuTransformSourceRegistry = exports.createBlockMenuTransformSourceRegistry = function createBlockMenuTransformSourceRegistry() {
9
+ var transforms = new Map();
10
+ return {
11
+ register: function register(registeredTransforms) {
12
+ var registered = [];
13
+ registeredTransforms.forEach(function (transform) {
14
+ if (transforms.has(transform.key)) {
15
+ void (0, _monitoring.logException)(new Error("Duplicate Block Menu transform key: ".concat(transform.key)), {
16
+ location: 'editor-plugin-block-menu'
17
+ });
18
+ return;
19
+ }
20
+ transforms.set(transform.key, transform);
21
+ registered.push(transform);
22
+ });
23
+ if (registered.length === 0) {
24
+ return function () {};
25
+ }
26
+ return function () {
27
+ registered.forEach(function (transform) {
28
+ if (transforms.get(transform.key) === transform) {
29
+ transforms.delete(transform.key);
30
+ }
31
+ });
32
+ };
33
+ },
34
+ resolve: function resolve(context) {
35
+ var transform = Array.from(transforms.values()).find(function (_ref) {
36
+ var isSupported = _ref.isSupported;
37
+ try {
38
+ return isSupported(context);
39
+ } catch (error) {
40
+ void (0, _monitoring.logException)(error instanceof Error ? error : new Error('Block Menu transform support check failed'), {
41
+ location: 'editor-plugin-block-menu'
42
+ });
43
+ return false;
44
+ }
45
+ });
46
+ return transform ? {
47
+ status: 'supported',
48
+ transform: transform
49
+ } : {
50
+ status: 'unsupported'
51
+ };
52
+ }
53
+ };
54
+ };
@@ -1,21 +1,26 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.transformNode = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
9
  var _analytics = require("@atlaskit/editor-common/analytics");
8
- var _expand = require("@atlaskit/editor-common/expand");
10
+ var _expand2 = require("@atlaskit/editor-common/expand");
9
11
  var _monitoring = require("@atlaskit/editor-common/monitoring");
10
12
  var _performanceMeasures = require("@atlaskit/editor-common/performance-measures");
11
13
  var _selection = require("@atlaskit/editor-common/selection");
14
+ var _model = require("@atlaskit/editor-prosemirror/model");
12
15
  var _state = require("@atlaskit/editor-prosemirror/state");
13
16
  var _transform = require("@atlaskit/editor-prosemirror/transform");
14
17
  var _editorTables = require("@atlaskit/editor-tables");
18
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
19
+ var _transformSource = require("../editor-actions/transformSource");
15
20
  var _isNestedNode = require("../ui/utils/isNestedNode");
16
21
  var _transform2 = require("./transform-node-utils/transform");
17
22
  var _utils = require("./transform-node-utils/utils");
18
- var transformNode = exports.transformNode = function transformNode(api) {
23
+ var transformNode = exports.transformNode = function transformNode(api, transformRegistry) {
19
24
  return function (targetType, metadata) {
20
25
  return function (_ref) {
21
26
  var _api$blockControls;
@@ -24,12 +29,115 @@ var transformNode = exports.transformNode = function transformNode(api) {
24
29
  if (!preservedSelection) {
25
30
  return tr;
26
31
  }
32
+ if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions')) {
33
+ var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(preservedSelection),
34
+ _$from = _expandSelectionToBlo.$from,
35
+ _$to = _expandSelectionToBlo.$to,
36
+ range = _expandSelectionToBlo.range;
37
+ var sourceNode = (0, _transformSource.getSingleTransformSourceNode)(preservedSelection, range);
38
+ if ((0, _transformSource.isExtensionTransformSource)(sourceNode)) {
39
+ var _metadata$targetTypeN;
40
+ var context = {
41
+ source: sourceNode.toJSON(),
42
+ targetTypeName: (_metadata$targetTypeN = metadata === null || metadata === void 0 ? void 0 : metadata.targetTypeName) !== null && _metadata$targetTypeN !== void 0 ? _metadata$targetTypeN : targetType.name
43
+ };
44
+ var resolution = transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve(context);
45
+ if (!resolution || resolution.status === 'unsupported') {
46
+ return tr;
47
+ }
48
+ var _measureId = "transformNode_".concat(targetType.name, "_").concat(Date.now());
49
+ (0, _performanceMeasures.startMeasure)(_measureId);
50
+ try {
51
+ var _api$blockControls2, _api$blockControls3;
52
+ var transformResult = resolution.transform.transform(context);
53
+ if (!transformResult) {
54
+ (0, _performanceMeasures.stopMeasure)(_measureId);
55
+ return tr;
56
+ }
57
+ if (!Array.isArray(transformResult.output) || transformResult.output.length === 0) {
58
+ throw new Error('Block menu transform returned no output');
59
+ }
60
+ var resultNodes = transformResult.output.map(function (nodeAdf) {
61
+ var node = _model.Node.fromJSON(tr.doc.type.schema, nodeAdf);
62
+ node.check();
63
+ return node;
64
+ });
65
+ if (!range || !range.parent.canReplace(range.startIndex, range.endIndex, _model.Fragment.from(resultNodes))) {
66
+ throw new Error('Block menu transform output is invalid at the selected position');
67
+ }
68
+ var sliceStart = _$from.pos;
69
+ tr.replaceWith(sliceStart, _$to.pos, resultNodes);
70
+ var insertedNode = tr.doc.nodeAt(sliceStart);
71
+ var nextSelection = insertedNode && _state.NodeSelection.isSelectable(insertedNode) ? _state.NodeSelection.create(tr.doc, sliceStart) : _state.Selection.near(tr.doc.resolve(sliceStart));
72
+ tr.setSelection(nextSelection);
73
+ api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.stopPreservingSelection()({
74
+ tr: tr
75
+ });
76
+ api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
77
+ closeMenu: true
78
+ })({
79
+ tr: tr
80
+ });
81
+ var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
82
+ expand = _tr$doc$type$schema$n.expand,
83
+ nestedExpand = _tr$doc$type$schema$n.nestedExpand;
84
+ resultNodes.forEach(function (node) {
85
+ if (node.type === expand || node.type === nestedExpand) {
86
+ _expand2.expandedState.set(node, true);
87
+ }
88
+ });
89
+ (0, _performanceMeasures.stopMeasure)(_measureId, function (duration, startTime) {
90
+ var _api$analytics;
91
+ 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({
92
+ action: _analytics.ACTION.TRANSFORMED,
93
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
94
+ attributes: {
95
+ duration: duration,
96
+ isEmptyLine: false,
97
+ isNested: (0, _isNestedNode.isNestedNode)(preservedSelection, ''),
98
+ isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
99
+ sourceNodesCount: 1,
100
+ sourceNodesCountByType: (0, _defineProperty2.default)({}, sourceNode.type.name, 1),
101
+ sourceNodeType: sourceNode.type.name,
102
+ startTime: startTime,
103
+ targetNodeType: targetType.name,
104
+ outputNodesCount: resultNodes.length,
105
+ inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU
106
+ },
107
+ eventType: _analytics.EVENT_TYPE.TRACK
108
+ })(tr);
109
+ });
110
+ } catch (error) {
111
+ var _api$analytics2;
112
+ (0, _performanceMeasures.stopMeasure)(_measureId);
113
+ (0, _monitoring.logException)(error, {
114
+ location: 'editor-plugin-block-menu'
115
+ });
116
+ 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({
117
+ action: _analytics.ACTION.ERRORED,
118
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
119
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.TRANSFORM,
120
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
121
+ attributes: {
122
+ docSize: tr.doc.nodeSize,
123
+ error: error.message,
124
+ errorStack: error.stack,
125
+ from: sourceNode.type.name,
126
+ inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU,
127
+ selection: preservedSelection.toJSON(),
128
+ to: targetType.name
129
+ }
130
+ })(tr);
131
+ }
132
+ return tr;
133
+ }
134
+ }
27
135
  var measureId = "transformNode_".concat(targetType.name, "_").concat(Date.now());
28
136
  (0, _performanceMeasures.startMeasure)(measureId);
29
137
  var nodes = tr.doc.type.schema.nodes;
30
- var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(preservedSelection),
31
- $from = _expandSelectionToBlo.$from,
32
- $to = _expandSelectionToBlo.$to;
138
+ var _expandSelectionToBlo2 = (0, _selection.expandSelectionToBlockRange)(preservedSelection),
139
+ $from = _expandSelectionToBlo2.$from,
140
+ $to = _expandSelectionToBlo2.$to;
33
141
  var selectedParent = $from.parent;
34
142
  var isParentLayout = selectedParent.type === nodes.layoutColumn;
35
143
  var isNested = (0, _isNestedNode.isNestedNode)(preservedSelection, '') && !isParentLayout;
@@ -45,8 +153,8 @@ var transformNode = exports.transformNode = function transformNode(api) {
45
153
  var isEmptyLine = sourceNodes.length === 1 && (sourceNodes[0].type === nodes.paragraph || sourceNodes[0].type === nodes.heading) && (sourceNodes[0].content.size === 0 || sourceNodes[0].textContent.trim() === '');
46
154
  var isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
47
155
  try {
48
- var _api$blockControls4;
49
- var resultNodes = (0, _transform2.convertNodesToTargetType)({
156
+ var _api$blockControls6;
157
+ var _resultNodes = (0, _transform2.convertNodesToTargetType)({
50
158
  sourceNodes: sourceNodes,
51
159
  targetNodeType: targetType,
52
160
  schema: tr.doc.type.schema,
@@ -54,17 +162,17 @@ var transformNode = exports.transformNode = function transformNode(api) {
54
162
  targetAttrs: metadata === null || metadata === void 0 ? void 0 : metadata.targetAttrs,
55
163
  parentNode: selectedParent
56
164
  });
57
- var content = resultNodes.length > 0 ? resultNodes : sourceNodes;
58
- var sliceStart = isList ? $from.pos - 1 : $from.pos;
59
- var expand = nodes.expand,
60
- nestedExpand = nodes.nestedExpand;
165
+ var content = _resultNodes.length > 0 ? _resultNodes : sourceNodes;
166
+ var _sliceStart = isList ? $from.pos - 1 : $from.pos;
167
+ var _expand = nodes.expand,
168
+ _nestedExpand = nodes.nestedExpand;
61
169
  content.forEach(function (node) {
62
- if (node.type === expand || node.type === nestedExpand) {
63
- _expand.expandedState.set(node, true);
170
+ if (node.type === _expand || node.type === _nestedExpand) {
171
+ _expand2.expandedState.set(node, true);
64
172
  }
65
173
  });
66
174
  if (preservedSelection instanceof _state.NodeSelection && preservedSelection.node.type === nodes.mediaSingle) {
67
- var _api$blockControls2;
175
+ var _api$blockControls4;
68
176
  // when node is media single, use tr.replaceWith freeze editor, if modify position, tr.replaceWith creates duplicats
69
177
  var deleteFrom = $from.pos;
70
178
  var deleteTo = $to.pos;
@@ -83,32 +191,32 @@ var transformNode = exports.transformNode = function transformNode(api) {
83
191
  var newSize = content.reduce(function (sum, node) {
84
192
  return sum + node.nodeSize;
85
193
  }, 0);
86
- api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.mapPreservedSelection(new _transform.Mapping([new _transform.StepMap([0, oldSize, newSize])]))({
194
+ api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.mapPreservedSelection(new _transform.Mapping([new _transform.StepMap([0, oldSize, newSize])]))({
87
195
  tr: tr
88
196
  });
89
197
  } else {
90
- tr.replaceWith(sliceStart, $to.pos, content);
198
+ tr.replaceWith(_sliceStart, $to.pos, content);
91
199
  }
92
200
  if (preservedSelection instanceof _editorTables.CellSelection) {
93
- var insertedNode = tr.doc.nodeAt($from.pos);
94
- var isSelectable = insertedNode && _state.NodeSelection.isSelectable(insertedNode);
201
+ var _insertedNode = tr.doc.nodeAt($from.pos);
202
+ var isSelectable = _insertedNode && _state.NodeSelection.isSelectable(_insertedNode);
95
203
  if (isSelectable) {
96
- var _api$blockControls3;
204
+ var _api$blockControls5;
97
205
  var nodeSelection = _state.NodeSelection.create(tr.doc, $from.pos);
98
206
  tr.setSelection(nodeSelection);
99
- api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.startPreservingSelection()({
207
+ api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.startPreservingSelection()({
100
208
  tr: tr
101
209
  });
102
210
  }
103
211
  }
104
- api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.toggleBlockMenu({
212
+ api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.toggleBlockMenu({
105
213
  closeMenu: true
106
214
  })({
107
215
  tr: tr
108
216
  });
109
217
  (0, _performanceMeasures.stopMeasure)(measureId, function (duration, startTime) {
110
- var _api$analytics;
111
- 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({
218
+ var _api$analytics3;
219
+ 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({
112
220
  action: _analytics.ACTION.TRANSFORMED,
113
221
  actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
114
222
  attributes: {
@@ -128,12 +236,12 @@ var transformNode = exports.transformNode = function transformNode(api) {
128
236
  })(tr);
129
237
  });
130
238
  } catch (error) {
131
- var _api$analytics2;
239
+ var _api$analytics4;
132
240
  (0, _performanceMeasures.stopMeasure)(measureId);
133
241
  (0, _monitoring.logException)(error, {
134
242
  location: 'editor-plugin-block-menu'
135
243
  });
136
- 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({
244
+ 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({
137
245
  action: _analytics.ACTION.ERRORED,
138
246
  actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
139
247
  actionSubjectId: _analytics.ACTION_SUBJECT_ID.TRANSFORM,
@@ -8,6 +8,7 @@ exports.checkIsFormatMenuHidden = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _memoizeOne = _interopRequireDefault(require("memoize-one"));
10
10
  var _utils = require("@atlaskit/editor-prosemirror/utils");
11
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
11
12
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
12
13
  var getDisabledNodeTypes = (0, _memoizeOne.default)(function (nodes) {
13
14
  return [nodes.rule].concat((0, _toConsumableArray2.default)((0, _expValEquals.expValEquals)('confluence_native_tabs_experiment', 'isEnabled', true) ? [nodes.multiBodiedExtension] : []));
@@ -17,7 +18,8 @@ var getIsFormatMenuHidden = function getIsFormatMenuHidden(selection, schema) {
17
18
  if (!nodes) {
18
19
  return false;
19
20
  }
20
- var disabledNode = (0, _utils.findSelectedNodeOfType)(getDisabledNodeTypes(nodes))(selection);
21
+ var disabledNodeTypes = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions') ? [nodes.rule] : getDisabledNodeTypes(nodes);
22
+ var disabledNode = (0, _utils.findSelectedNodeOfType)(disabledNodeTypes)(selection);
21
23
  return !!disabledNode;
22
24
  };
23
25
  var checkIsFormatMenuHidden = exports.checkIsFormatMenuHidden = function checkIsFormatMenuHidden(api) {
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
3
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
3
4
  import { createBlockMenuRegistry } from './editor-actions';
4
5
  import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
6
+ import { createBlockMenuTransformSourceRegistry } from './editor-actions/transformSourceRegistry';
5
7
  import { transformNode } from './editor-commands/transformNode';
6
8
  import { getBlockMenuExperiencesPlugin } from './pm-plugins/experiences/block-menu-experiences';
7
9
  import { keymapPlugin } from './pm-plugins/keymap';
@@ -15,6 +17,7 @@ export const blockMenuPlugin = ({
15
17
  config
16
18
  }) => {
17
19
  const registry = createBlockMenuRegistry();
20
+ const transformSourceRegistry = isExperimentEnabled('platform_editor_block_menu_transform_extensions') ? createBlockMenuTransformSourceRegistry() : undefined;
18
21
  registry.register(getBlockMenuComponents({
19
22
  api,
20
23
  config
@@ -58,14 +61,20 @@ export const blockMenuPlugin = ({
58
61
  return isTransformToTargetDisabled({
59
62
  selection: currentSelection,
60
63
  targetNodeTypeName: optionNodeTypeName,
61
- targetNodeTypeAttrs: optionNodeTypeAttrs
64
+ targetNodeTypeAttrs: optionNodeTypeAttrs,
65
+ transformRegistry: transformSourceRegistry
62
66
  });
67
+ },
68
+ registerBlockMenuTransforms: transforms => {
69
+ if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
70
+ var _transformSourceRegis;
71
+ return (_transformSourceRegis = transformSourceRegistry === null || transformSourceRegistry === void 0 ? void 0 : transformSourceRegistry.register(transforms)) !== null && _transformSourceRegis !== void 0 ? _transformSourceRegis : () => {};
72
+ }
73
+ return () => {};
63
74
  }
64
75
  },
65
76
  commands: {
66
- transformNode: (targetType, metadata) => {
67
- return transformNode(api)(targetType, metadata);
68
- }
77
+ transformNode: (targetType, metadata) => transformNode(api, transformSourceRegistry)(targetType, metadata)
69
78
  },
70
79
  getSharedState(editorState) {
71
80
  var _config$useStandardNo, _api$blockControls2, _api$blockControls2$s, _pluginState$showFlag;
@@ -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 const canParentContainNodeType = (schema, selectedNodeTypeName, parentNode, nodeTypeName, nodeTypeAttrs) => {
7
9
  const adjustedNodeTypeName = getTargetNodeTypeNameInContext(nodeTypeName, true, parentNode, schema);
8
10
  if (!adjustedNodeTypeName) {
@@ -46,7 +48,8 @@ const isTransformEnabledForNode = (node, targetNodeTypeName, targetNodeTypeAttrs
46
48
  export const isTransformToTargetDisabled = ({
47
49
  selection,
48
50
  targetNodeTypeName,
49
- targetNodeTypeAttrs
51
+ targetNodeTypeAttrs,
52
+ transformRegistry
50
53
  }) => {
51
54
  const {
52
55
  range
@@ -54,6 +57,15 @@ export const isTransformToTargetDisabled = ({
54
57
  if (!range) {
55
58
  return false;
56
59
  }
60
+ if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
61
+ const sourceNode = getSingleTransformSourceNode(selection, range);
62
+ if (isExtensionTransformSource(sourceNode)) {
63
+ return (transformRegistry === null || transformRegistry === void 0 ? void 0 : transformRegistry.resolve({
64
+ source: sourceNode.toJSON(),
65
+ targetTypeName: targetNodeTypeName
66
+ }).status) !== 'supported';
67
+ }
68
+ }
57
69
  const selectedNodes = getBlockNodesInRange(range);
58
70
  const parent = range.parent;
59
71
  const isNested = range.depth >= 1;
@@ -0,0 +1,15 @@
1
+ import { getBlockNodesInRange, getSelectedNode } from '../editor-commands/transform-node-utils/utils';
2
+ const EXTENSION_NODE_TYPES = new Set(['extension', 'bodiedExtension', 'multiBodiedExtension']);
3
+ export const getSingleTransformSourceNode = (selection, range) => {
4
+ var _getSelectedNode;
5
+ const 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
+ const blockNodes = getBlockNodesInRange(range);
13
+ return blockNodes.length === 1 ? blockNodes[0] : undefined;
14
+ };
15
+ export const isExtensionTransformSource = node => Boolean(node && EXTENSION_NODE_TYPES.has(node.type.name));
@@ -0,0 +1,49 @@
1
+ import { logException } from '@atlaskit/editor-common/monitoring';
2
+ export const createBlockMenuTransformSourceRegistry = () => {
3
+ const transforms = new Map();
4
+ return {
5
+ register: registeredTransforms => {
6
+ const registered = [];
7
+ registeredTransforms.forEach(transform => {
8
+ if (transforms.has(transform.key)) {
9
+ void logException(new Error(`Duplicate Block Menu transform key: ${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 () => {};
19
+ }
20
+ return () => {
21
+ registered.forEach(transform => {
22
+ if (transforms.get(transform.key) === transform) {
23
+ transforms.delete(transform.key);
24
+ }
25
+ });
26
+ };
27
+ },
28
+ resolve: context => {
29
+ const transform = Array.from(transforms.values()).find(({
30
+ isSupported
31
+ }) => {
32
+ try {
33
+ return isSupported(context);
34
+ } catch (error) {
35
+ void logException(error instanceof Error ? error : new Error('Block Menu transform support check failed'), {
36
+ location: 'editor-plugin-block-menu'
37
+ });
38
+ return false;
39
+ }
40
+ });
41
+ return transform ? {
42
+ status: 'supported',
43
+ transform
44
+ } : {
45
+ status: 'unsupported'
46
+ };
47
+ }
48
+ };
49
+ };