@atlaskit/editor-plugin-block-menu 15.0.13 → 15.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 15.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`0ac8aba669ed5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0ac8aba669ed5) -
8
+ Add transformInlineNode so the block menu can replace one selected block with a paragraph wrapping
9
+ a caller-built inline node.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 15.0.14
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+
3
21
  ## 15.0.13
4
22
 
5
23
  ### Patch Changes
@@ -12,6 +12,7 @@ var _unsafeExpValNoExposure = require("@atlaskit/platform-feature-experiments/un
12
12
  var _editorActions = require("./editor-actions");
13
13
  var _isTransformToTargetDisabled = require("./editor-actions/isTransformToTargetDisabled");
14
14
  var _transformSourceRegistry = require("./editor-actions/transformSourceRegistry");
15
+ var _transformInlineNode2 = require("./editor-commands/transformInlineNode");
15
16
  var _transformNode2 = require("./editor-commands/transformNode");
16
17
  var _blockMenuExperiences = require("./pm-plugins/experiences/block-menu-experiences");
17
18
  var _keymap = require("./pm-plugins/keymap");
@@ -88,6 +89,9 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
88
89
  }
89
90
  },
90
91
  commands: {
92
+ transformInlineNode: function transformInlineNode(metadata) {
93
+ return (0, _transformInlineNode2.transformInlineNode)(api)(metadata);
94
+ },
91
95
  transformNode: function transformNode(targetType, metadata) {
92
96
  return (0, _transformNode2.transformNode)(api, transformSourceRegistry)(targetType, metadata);
93
97
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isEmptyLine = void 0;
7
+ /** True when there is one source node and it is an empty or whitespace-only paragraph or heading. */
8
+ var isEmptyLine = exports.isEmptyLine = function isEmptyLine(sourceNodes) {
9
+ if (sourceNodes.length !== 1) {
10
+ return false;
11
+ }
12
+ var source = sourceNodes[0];
13
+ var _source$type$schema$n = source.type.schema.nodes,
14
+ heading = _source$type$schema$n.heading,
15
+ paragraph = _source$type$schema$n.paragraph;
16
+ return (source.type === paragraph || source.type === heading) && (source.content.size === 0 || source.textContent.trim() === '');
17
+ };
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createTransformAnalytics = void 0;
7
+ var _analytics = require("@atlaskit/editor-common/analytics");
8
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
9
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
10
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
11
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
12
+ var sourceTypeName = function sourceTypeName(sourceNodes) {
13
+ return sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple';
14
+ };
15
+ var sourceNodesCountByType = function sourceNodesCountByType(sourceNodes) {
16
+ var counts = {};
17
+ var _iterator = _createForOfIteratorHelper(sourceNodes),
18
+ _step;
19
+ try {
20
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
21
+ var node = _step.value;
22
+ counts[node.type.name] = (counts[node.type.name] || 0) + 1;
23
+ }
24
+ } catch (err) {
25
+ _iterator.e(err);
26
+ } finally {
27
+ _iterator.f();
28
+ }
29
+ return counts;
30
+ };
31
+ var createTransformAnalytics = exports.createTransformAnalytics = function createTransformAnalytics(api, tr, selection) {
32
+ return {
33
+ transformed: function transformed(duration, startTime, _ref) {
34
+ var _api$analytics;
35
+ var _ref$isEmptyLine = _ref.isEmptyLine,
36
+ isEmptyLine = _ref$isEmptyLine === void 0 ? false : _ref$isEmptyLine,
37
+ isNested = _ref.isNested,
38
+ _ref$isSuggested = _ref.isSuggested,
39
+ isSuggested = _ref$isSuggested === void 0 ? false : _ref$isSuggested,
40
+ outputNodesCount = _ref.outputNodesCount,
41
+ sourceNodes = _ref.sourceNodes,
42
+ targetNodeType = _ref.targetNodeType;
43
+ 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({
44
+ action: _analytics.ACTION.TRANSFORMED,
45
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
46
+ attributes: {
47
+ duration: duration,
48
+ isEmptyLine: isEmptyLine,
49
+ isNested: isNested,
50
+ isSuggested: isSuggested,
51
+ outputNodesCount: outputNodesCount,
52
+ sourceNodeType: sourceTypeName(sourceNodes),
53
+ sourceNodesCount: sourceNodes.length,
54
+ sourceNodesCountByType: sourceNodesCountByType(sourceNodes),
55
+ startTime: startTime,
56
+ targetNodeType: targetNodeType,
57
+ inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU
58
+ },
59
+ eventType: _analytics.EVENT_TYPE.TRACK
60
+ })(tr);
61
+ },
62
+ errored: function errored(error, sourceNodes, to) {
63
+ var _api$analytics2;
64
+ (0, _monitoring.logException)(error, {
65
+ location: 'editor-plugin-block-menu'
66
+ });
67
+ 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({
68
+ action: _analytics.ACTION.ERRORED,
69
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
70
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.TRANSFORM,
71
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
72
+ attributes: {
73
+ docSize: tr.doc.nodeSize,
74
+ error: error.message,
75
+ errorStack: error.stack,
76
+ from: sourceTypeName(sourceNodes),
77
+ inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU,
78
+ selection: selection.toJSON(),
79
+ to: to
80
+ }
81
+ })(tr);
82
+ }
83
+ };
84
+ };
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.transformInlineNode = void 0;
7
+ var _performanceMeasures = require("@atlaskit/editor-common/performance-measures");
8
+ var _state = require("@atlaskit/editor-prosemirror/state");
9
+ var _isNestedNode = require("../ui/utils/isNestedNode");
10
+ var _isEmptyLine = require("./is-empty-line");
11
+ var _transformAnalytics = require("./transform-analytics");
12
+ var transformInlineNode = exports.transformInlineNode = function transformInlineNode(api) {
13
+ return function (metadata) {
14
+ return function (_ref) {
15
+ var _api$blockControls;
16
+ var tr = _ref.tr;
17
+ var preservedSelection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
18
+ if (!preservedSelection || !(preservedSelection instanceof _state.NodeSelection)) {
19
+ return tr;
20
+ }
21
+ var source = {
22
+ node: preservedSelection.node,
23
+ pos: preservedSelection.from
24
+ };
25
+ var analytics = (0, _transformAnalytics.createTransformAnalytics)(api, tr, preservedSelection);
26
+ var measureId = "transformInlineNode_".concat(metadata.targetTypeName, "_").concat(Date.now());
27
+ (0, _performanceMeasures.startMeasure)(measureId);
28
+ var isParentLayout = tr.doc.resolve(source.pos).parent.type === tr.doc.type.schema.nodes.layoutColumn;
29
+ var isNested = (0, _isNestedNode.isNestedNode)(preservedSelection, '') && !isParentLayout;
30
+ try {
31
+ var _api$blockControls2, _api$blockControls3;
32
+ var inlineNode = metadata.buildInlineNode(source.node);
33
+ var paragraphNode = tr.doc.type.schema.nodes.paragraph.createChecked({}, [inlineNode]);
34
+ tr.replaceWith(source.pos, source.pos + source.node.nodeSize, paragraphNode);
35
+ if (_state.NodeSelection.isSelectable(inlineNode)) {
36
+ tr.setSelection(_state.NodeSelection.create(tr.doc, source.pos + 1));
37
+ }
38
+ api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.stopPreservingSelection()({
39
+ tr: tr
40
+ });
41
+ api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
42
+ closeMenu: true
43
+ })({
44
+ tr: tr
45
+ });
46
+ (0, _performanceMeasures.stopMeasure)(measureId, function (duration, startTime) {
47
+ analytics.transformed(duration, startTime, {
48
+ isEmptyLine: (0, _isEmptyLine.isEmptyLine)([source.node]),
49
+ isNested: isNested,
50
+ isSuggested: Boolean(metadata.isSuggested),
51
+ outputNodesCount: 1,
52
+ sourceNodes: [source.node],
53
+ targetNodeType: metadata.targetTypeName
54
+ });
55
+ });
56
+ } catch (error) {
57
+ (0, _performanceMeasures.stopMeasure)(measureId);
58
+ analytics.errored(error, [source.node], metadata.targetTypeName);
59
+ }
60
+ return tr;
61
+ };
62
+ };
63
+ };
@@ -1,14 +1,10 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
6
  exports.transformNode = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
- var _analytics = require("@atlaskit/editor-common/analytics");
10
7
  var _expand2 = require("@atlaskit/editor-common/expand");
11
- var _monitoring = require("@atlaskit/editor-common/monitoring");
12
8
  var _performanceMeasures = require("@atlaskit/editor-common/performance-measures");
13
9
  var _selection = require("@atlaskit/editor-common/selection");
14
10
  var _model = require("@atlaskit/editor-prosemirror/model");
@@ -18,6 +14,8 @@ var _editorTables = require("@atlaskit/editor-tables");
18
14
  var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
19
15
  var _transformSource = require("../editor-actions/transformSource");
20
16
  var _isNestedNode = require("../ui/utils/isNestedNode");
17
+ var _isEmptyLine = require("./is-empty-line");
18
+ var _transformAnalytics = require("./transform-analytics");
21
19
  var _transform2 = require("./transform-node-utils/transform");
22
20
  var _utils = require("./transform-node-utils/utils");
23
21
  var transformNode = exports.transformNode = function transformNode(api, transformRegistry) {
@@ -29,6 +27,7 @@ var transformNode = exports.transformNode = function transformNode(api, transfor
29
27
  if (!preservedSelection) {
30
28
  return tr;
31
29
  }
30
+ var analytics = (0, _transformAnalytics.createTransformAnalytics)(api, tr, preservedSelection);
32
31
  if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_block_menu_transform_extensions')) {
33
32
  var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(preservedSelection),
34
33
  _$from = _expandSelectionToBlo.$from,
@@ -87,47 +86,17 @@ var transformNode = exports.transformNode = function transformNode(api, transfor
87
86
  }
88
87
  });
89
88
  (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);
89
+ analytics.transformed(duration, startTime, {
90
+ isNested: (0, _isNestedNode.isNestedNode)(preservedSelection, ''),
91
+ isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
92
+ outputNodesCount: resultNodes.length,
93
+ sourceNodes: [sourceNode],
94
+ targetNodeType: targetType.name
95
+ });
109
96
  });
110
97
  } catch (error) {
111
- var _api$analytics2;
112
98
  (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);
99
+ analytics.errored(error, [sourceNode], targetType.name);
131
100
  }
132
101
  return tr;
133
102
  }
@@ -143,14 +112,6 @@ var transformNode = exports.transformNode = function transformNode(api, transfor
143
112
  var isNested = (0, _isNestedNode.isNestedNode)(preservedSelection, '') && !isParentLayout;
144
113
  var isList = (0, _utils.isListNode)(selectedParent);
145
114
  var sourceNodes = (0, _selection.getSourceNodesFromSelectionRange)(tr, preservedSelection);
146
- var sourceNodeTypes = {};
147
- sourceNodes.forEach(function (node) {
148
- var typeName = node.type.name;
149
- sourceNodeTypes[typeName] = (sourceNodeTypes[typeName] || 0) + 1;
150
- });
151
-
152
- // Check if source node is empty paragraph or heading
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() === '');
154
115
  var isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
155
116
  try {
156
117
  var _api$blockControls6;
@@ -215,47 +176,18 @@ var transformNode = exports.transformNode = function transformNode(api, transfor
215
176
  tr: tr
216
177
  });
217
178
  (0, _performanceMeasures.stopMeasure)(measureId, function (duration, startTime) {
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({
220
- action: _analytics.ACTION.TRANSFORMED,
221
- actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
222
- attributes: {
223
- duration: duration,
224
- isEmptyLine: isEmptyLine,
225
- isNested: isNested,
226
- isSuggested: isSuggested,
227
- sourceNodesCount: sourceNodes.length,
228
- sourceNodesCountByType: sourceNodeTypes,
229
- sourceNodeType: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
230
- startTime: startTime,
231
- targetNodeType: targetType.name,
232
- outputNodesCount: content.length,
233
- inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU
234
- },
235
- eventType: _analytics.EVENT_TYPE.TRACK
236
- })(tr);
179
+ analytics.transformed(duration, startTime, {
180
+ isEmptyLine: (0, _isEmptyLine.isEmptyLine)(sourceNodes),
181
+ isNested: isNested,
182
+ isSuggested: isSuggested,
183
+ outputNodesCount: content.length,
184
+ sourceNodes: sourceNodes,
185
+ targetNodeType: targetType.name
186
+ });
237
187
  });
238
188
  } catch (error) {
239
- var _api$analytics4;
240
189
  (0, _performanceMeasures.stopMeasure)(measureId);
241
- (0, _monitoring.logException)(error, {
242
- location: 'editor-plugin-block-menu'
243
- });
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({
245
- action: _analytics.ACTION.ERRORED,
246
- actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
247
- actionSubjectId: _analytics.ACTION_SUBJECT_ID.TRANSFORM,
248
- eventType: _analytics.EVENT_TYPE.OPERATIONAL,
249
- attributes: {
250
- docSize: tr.doc.nodeSize,
251
- error: error.message,
252
- errorStack: error.stack,
253
- from: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
254
- inputMethod: _analytics.INPUT_METHOD.BLOCK_MENU,
255
- selection: preservedSelection.toJSON(),
256
- to: targetType.name
257
- }
258
- })(tr);
190
+ analytics.errored(error, sourceNodes, targetType.name);
259
191
  }
260
192
  return tr;
261
193
  };
@@ -4,6 +4,7 @@ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/
4
4
  import { createBlockMenuRegistry } from './editor-actions';
5
5
  import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
6
6
  import { createBlockMenuTransformSourceRegistry } from './editor-actions/transformSourceRegistry';
7
+ import { transformInlineNode } from './editor-commands/transformInlineNode';
7
8
  import { transformNode } from './editor-commands/transformNode';
8
9
  import { getBlockMenuExperiencesPlugin } from './pm-plugins/experiences/block-menu-experiences';
9
10
  import { keymapPlugin } from './pm-plugins/keymap';
@@ -75,6 +76,7 @@ export const blockMenuPlugin = ({
75
76
  }
76
77
  },
77
78
  commands: {
79
+ transformInlineNode: metadata => transformInlineNode(api)(metadata),
78
80
  transformNode: (targetType, metadata) => transformNode(api, transformSourceRegistry)(targetType, metadata)
79
81
  },
80
82
  getSharedState(editorState) {
@@ -0,0 +1,12 @@
1
+ /** True when there is one source node and it is an empty or whitespace-only paragraph or heading. */
2
+ export const isEmptyLine = sourceNodes => {
3
+ if (sourceNodes.length !== 1) {
4
+ return false;
5
+ }
6
+ const source = sourceNodes[0];
7
+ const {
8
+ heading,
9
+ paragraph
10
+ } = source.type.schema.nodes;
11
+ return (source.type === paragraph || source.type === heading) && (source.content.size === 0 || source.textContent.trim() === '');
12
+ };
@@ -0,0 +1,61 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import { logException } from '@atlaskit/editor-common/monitoring';
3
+ const sourceTypeName = sourceNodes => sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple';
4
+ const sourceNodesCountByType = sourceNodes => {
5
+ const counts = {};
6
+ for (const node of sourceNodes) {
7
+ counts[node.type.name] = (counts[node.type.name] || 0) + 1;
8
+ }
9
+ return counts;
10
+ };
11
+ export const createTransformAnalytics = (api, tr, selection) => ({
12
+ transformed: (duration, startTime, {
13
+ isEmptyLine = false,
14
+ isNested,
15
+ isSuggested = false,
16
+ outputNodesCount,
17
+ sourceNodes,
18
+ targetNodeType
19
+ }) => {
20
+ var _api$analytics, _api$analytics$action;
21
+ 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({
22
+ action: ACTION.TRANSFORMED,
23
+ actionSubject: ACTION_SUBJECT.ELEMENT,
24
+ attributes: {
25
+ duration,
26
+ isEmptyLine,
27
+ isNested,
28
+ isSuggested,
29
+ outputNodesCount,
30
+ sourceNodeType: sourceTypeName(sourceNodes),
31
+ sourceNodesCount: sourceNodes.length,
32
+ sourceNodesCountByType: sourceNodesCountByType(sourceNodes),
33
+ startTime,
34
+ targetNodeType,
35
+ inputMethod: INPUT_METHOD.BLOCK_MENU
36
+ },
37
+ eventType: EVENT_TYPE.TRACK
38
+ })(tr);
39
+ },
40
+ errored: (error, sourceNodes, to) => {
41
+ var _api$analytics2, _api$analytics2$actio;
42
+ logException(error, {
43
+ location: 'editor-plugin-block-menu'
44
+ });
45
+ 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({
46
+ action: ACTION.ERRORED,
47
+ actionSubject: ACTION_SUBJECT.ELEMENT,
48
+ actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
49
+ eventType: EVENT_TYPE.OPERATIONAL,
50
+ attributes: {
51
+ docSize: tr.doc.nodeSize,
52
+ error: error.message,
53
+ errorStack: error.stack,
54
+ from: sourceTypeName(sourceNodes),
55
+ inputMethod: INPUT_METHOD.BLOCK_MENU,
56
+ selection: selection.toJSON(),
57
+ to
58
+ }
59
+ })(tr);
60
+ }
61
+ });
@@ -0,0 +1,54 @@
1
+ import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
2
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
+ import { isNestedNode } from '../ui/utils/isNestedNode';
4
+ import { isEmptyLine } from './is-empty-line';
5
+ import { createTransformAnalytics } from './transform-analytics';
6
+ export const transformInlineNode = api => metadata => ({
7
+ tr
8
+ }) => {
9
+ var _api$blockControls, _api$blockControls$sh;
10
+ const preservedSelection = api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : (_api$blockControls$sh = _api$blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.preservedSelection;
11
+ if (!preservedSelection || !(preservedSelection instanceof NodeSelection)) {
12
+ return tr;
13
+ }
14
+ const source = {
15
+ node: preservedSelection.node,
16
+ pos: preservedSelection.from
17
+ };
18
+ const analytics = createTransformAnalytics(api, tr, preservedSelection);
19
+ const measureId = `transformInlineNode_${metadata.targetTypeName}_${Date.now()}`;
20
+ startMeasure(measureId);
21
+ const isParentLayout = tr.doc.resolve(source.pos).parent.type === tr.doc.type.schema.nodes.layoutColumn;
22
+ const isNested = isNestedNode(preservedSelection, '') && !isParentLayout;
23
+ try {
24
+ var _api$blockControls2, _api$blockControls3;
25
+ const inlineNode = metadata.buildInlineNode(source.node);
26
+ const paragraphNode = tr.doc.type.schema.nodes.paragraph.createChecked({}, [inlineNode]);
27
+ tr.replaceWith(source.pos, source.pos + source.node.nodeSize, paragraphNode);
28
+ if (NodeSelection.isSelectable(inlineNode)) {
29
+ tr.setSelection(NodeSelection.create(tr.doc, source.pos + 1));
30
+ }
31
+ api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.stopPreservingSelection()({
32
+ tr
33
+ });
34
+ api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.toggleBlockMenu({
35
+ closeMenu: true
36
+ })({
37
+ tr
38
+ });
39
+ stopMeasure(measureId, (duration, startTime) => {
40
+ analytics.transformed(duration, startTime, {
41
+ isEmptyLine: isEmptyLine([source.node]),
42
+ isNested,
43
+ isSuggested: Boolean(metadata.isSuggested),
44
+ outputNodesCount: 1,
45
+ sourceNodes: [source.node],
46
+ targetNodeType: metadata.targetTypeName
47
+ });
48
+ });
49
+ } catch (error) {
50
+ stopMeasure(measureId);
51
+ analytics.errored(error, [source.node], metadata.targetTypeName);
52
+ }
53
+ return tr;
54
+ };
@@ -1,6 +1,4 @@
1
- import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
1
  import { expandedState } from '@atlaskit/editor-common/expand';
3
- import { logException } from '@atlaskit/editor-common/monitoring';
4
2
  import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
5
3
  import { expandSelectionToBlockRange, getSourceNodesFromSelectionRange } from '@atlaskit/editor-common/selection';
6
4
  import { Fragment, Node } from '@atlaskit/editor-prosemirror/model';
@@ -10,6 +8,8 @@ import { CellSelection } from '@atlaskit/editor-tables';
10
8
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
11
9
  import { getSingleTransformSourceNode, isExtensionTransformSource } from '../editor-actions/transformSource';
12
10
  import { isNestedNode } from '../ui/utils/isNestedNode';
11
+ import { isEmptyLine } from './is-empty-line';
12
+ import { createTransformAnalytics } from './transform-analytics';
13
13
  import { convertNodesToTargetType } from './transform-node-utils/transform';
14
14
  import { isListNode } from './transform-node-utils/utils';
15
15
  export const transformNode = (api, transformRegistry) => (targetType, metadata) => ({
@@ -20,6 +20,7 @@ export const transformNode = (api, transformRegistry) => (targetType, metadata)
20
20
  if (!preservedSelection) {
21
21
  return tr;
22
22
  }
23
+ const analytics = createTransformAnalytics(api, tr, preservedSelection);
23
24
  if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
24
25
  const {
25
26
  $from,
@@ -80,49 +81,17 @@ export const transformNode = (api, transformRegistry) => (targetType, metadata)
80
81
  }
81
82
  });
82
83
  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);
84
+ analytics.transformed(duration, startTime, {
85
+ isNested: isNestedNode(preservedSelection, ''),
86
+ isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
87
+ outputNodesCount: resultNodes.length,
88
+ sourceNodes: [sourceNode],
89
+ targetNodeType: targetType.name
90
+ });
104
91
  });
105
92
  } catch (error) {
106
- var _api$analytics2, _api$analytics2$actio;
107
93
  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);
94
+ analytics.errored(error, [sourceNode], targetType.name);
126
95
  }
127
96
  return tr;
128
97
  }
@@ -141,14 +110,6 @@ export const transformNode = (api, transformRegistry) => (targetType, metadata)
141
110
  const isNested = isNestedNode(preservedSelection, '') && !isParentLayout;
142
111
  const isList = isListNode(selectedParent);
143
112
  const sourceNodes = getSourceNodesFromSelectionRange(tr, preservedSelection);
144
- const sourceNodeTypes = {};
145
- sourceNodes.forEach(node => {
146
- const typeName = node.type.name;
147
- sourceNodeTypes[typeName] = (sourceNodeTypes[typeName] || 0) + 1;
148
- });
149
-
150
- // Check if source node is empty paragraph or heading
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() === '');
152
113
  const isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
153
114
  try {
154
115
  var _api$blockControls6;
@@ -211,47 +172,18 @@ export const transformNode = (api, transformRegistry) => (targetType, metadata)
211
172
  tr
212
173
  });
213
174
  stopMeasure(measureId, (duration, startTime) => {
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({
216
- action: ACTION.TRANSFORMED,
217
- actionSubject: ACTION_SUBJECT.ELEMENT,
218
- attributes: {
219
- duration,
220
- isEmptyLine,
221
- isNested,
222
- isSuggested,
223
- sourceNodesCount: sourceNodes.length,
224
- sourceNodesCountByType: sourceNodeTypes,
225
- sourceNodeType: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
226
- startTime,
227
- targetNodeType: targetType.name,
228
- outputNodesCount: content.length,
229
- inputMethod: INPUT_METHOD.BLOCK_MENU
230
- },
231
- eventType: EVENT_TYPE.TRACK
232
- })(tr);
175
+ analytics.transformed(duration, startTime, {
176
+ isEmptyLine: isEmptyLine(sourceNodes),
177
+ isNested,
178
+ isSuggested,
179
+ outputNodesCount: content.length,
180
+ sourceNodes,
181
+ targetNodeType: targetType.name
182
+ });
233
183
  });
234
184
  } catch (error) {
235
- var _api$analytics4, _api$analytics4$actio;
236
185
  stopMeasure(measureId);
237
- logException(error, {
238
- location: 'editor-plugin-block-menu'
239
- });
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({
241
- action: ACTION.ERRORED,
242
- actionSubject: ACTION_SUBJECT.ELEMENT,
243
- actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
244
- eventType: EVENT_TYPE.OPERATIONAL,
245
- attributes: {
246
- docSize: tr.doc.nodeSize,
247
- error: error.message,
248
- errorStack: error.stack,
249
- from: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
250
- inputMethod: INPUT_METHOD.BLOCK_MENU,
251
- selection: preservedSelection.toJSON(),
252
- to: targetType.name
253
- }
254
- })(tr);
186
+ analytics.errored(error, sourceNodes, targetType.name);
255
187
  }
256
188
  return tr;
257
189
  };
@@ -5,6 +5,7 @@ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/
5
5
  import { createBlockMenuRegistry } from './editor-actions';
6
6
  import { isTransformToTargetDisabled } from './editor-actions/isTransformToTargetDisabled';
7
7
  import { createBlockMenuTransformSourceRegistry } from './editor-actions/transformSourceRegistry';
8
+ import { transformInlineNode as _transformInlineNode } from './editor-commands/transformInlineNode';
8
9
  import { transformNode as _transformNode } from './editor-commands/transformNode';
9
10
  import { getBlockMenuExperiencesPlugin } from './pm-plugins/experiences/block-menu-experiences';
10
11
  import { keymapPlugin } from './pm-plugins/keymap';
@@ -81,6 +82,9 @@ export var blockMenuPlugin = function blockMenuPlugin(_ref) {
81
82
  }
82
83
  },
83
84
  commands: {
85
+ transformInlineNode: function transformInlineNode(metadata) {
86
+ return _transformInlineNode(api)(metadata);
87
+ },
84
88
  transformNode: function transformNode(targetType, metadata) {
85
89
  return _transformNode(api, transformSourceRegistry)(targetType, metadata);
86
90
  }
@@ -0,0 +1,11 @@
1
+ /** True when there is one source node and it is an empty or whitespace-only paragraph or heading. */
2
+ export var isEmptyLine = function isEmptyLine(sourceNodes) {
3
+ if (sourceNodes.length !== 1) {
4
+ return false;
5
+ }
6
+ var source = sourceNodes[0];
7
+ var _source$type$schema$n = source.type.schema.nodes,
8
+ heading = _source$type$schema$n.heading,
9
+ paragraph = _source$type$schema$n.paragraph;
10
+ return (source.type === paragraph || source.type === heading) && (source.content.size === 0 || source.textContent.trim() === '');
11
+ };
@@ -0,0 +1,78 @@
1
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
5
+ import { logException } from '@atlaskit/editor-common/monitoring';
6
+ var sourceTypeName = function sourceTypeName(sourceNodes) {
7
+ return sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple';
8
+ };
9
+ var sourceNodesCountByType = function sourceNodesCountByType(sourceNodes) {
10
+ var counts = {};
11
+ var _iterator = _createForOfIteratorHelper(sourceNodes),
12
+ _step;
13
+ try {
14
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
15
+ var node = _step.value;
16
+ counts[node.type.name] = (counts[node.type.name] || 0) + 1;
17
+ }
18
+ } catch (err) {
19
+ _iterator.e(err);
20
+ } finally {
21
+ _iterator.f();
22
+ }
23
+ return counts;
24
+ };
25
+ export var createTransformAnalytics = function createTransformAnalytics(api, tr, selection) {
26
+ return {
27
+ transformed: function transformed(duration, startTime, _ref) {
28
+ var _api$analytics;
29
+ var _ref$isEmptyLine = _ref.isEmptyLine,
30
+ isEmptyLine = _ref$isEmptyLine === void 0 ? false : _ref$isEmptyLine,
31
+ isNested = _ref.isNested,
32
+ _ref$isSuggested = _ref.isSuggested,
33
+ isSuggested = _ref$isSuggested === void 0 ? false : _ref$isSuggested,
34
+ outputNodesCount = _ref.outputNodesCount,
35
+ sourceNodes = _ref.sourceNodes,
36
+ targetNodeType = _ref.targetNodeType;
37
+ 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({
38
+ action: ACTION.TRANSFORMED,
39
+ actionSubject: ACTION_SUBJECT.ELEMENT,
40
+ attributes: {
41
+ duration: duration,
42
+ isEmptyLine: isEmptyLine,
43
+ isNested: isNested,
44
+ isSuggested: isSuggested,
45
+ outputNodesCount: outputNodesCount,
46
+ sourceNodeType: sourceTypeName(sourceNodes),
47
+ sourceNodesCount: sourceNodes.length,
48
+ sourceNodesCountByType: sourceNodesCountByType(sourceNodes),
49
+ startTime: startTime,
50
+ targetNodeType: targetNodeType,
51
+ inputMethod: INPUT_METHOD.BLOCK_MENU
52
+ },
53
+ eventType: EVENT_TYPE.TRACK
54
+ })(tr);
55
+ },
56
+ errored: function errored(error, sourceNodes, to) {
57
+ var _api$analytics2;
58
+ logException(error, {
59
+ location: 'editor-plugin-block-menu'
60
+ });
61
+ 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({
62
+ action: ACTION.ERRORED,
63
+ actionSubject: ACTION_SUBJECT.ELEMENT,
64
+ actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
65
+ eventType: EVENT_TYPE.OPERATIONAL,
66
+ attributes: {
67
+ docSize: tr.doc.nodeSize,
68
+ error: error.message,
69
+ errorStack: error.stack,
70
+ from: sourceTypeName(sourceNodes),
71
+ inputMethod: INPUT_METHOD.BLOCK_MENU,
72
+ selection: selection.toJSON(),
73
+ to: to
74
+ }
75
+ })(tr);
76
+ }
77
+ };
78
+ };
@@ -0,0 +1,57 @@
1
+ import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
2
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
+ import { isNestedNode } from '../ui/utils/isNestedNode';
4
+ import { isEmptyLine } from './is-empty-line';
5
+ import { createTransformAnalytics } from './transform-analytics';
6
+ export var transformInlineNode = function transformInlineNode(api) {
7
+ return function (metadata) {
8
+ return function (_ref) {
9
+ var _api$blockControls;
10
+ var tr = _ref.tr;
11
+ var preservedSelection = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.preservedSelection;
12
+ if (!preservedSelection || !(preservedSelection instanceof NodeSelection)) {
13
+ return tr;
14
+ }
15
+ var source = {
16
+ node: preservedSelection.node,
17
+ pos: preservedSelection.from
18
+ };
19
+ var analytics = createTransformAnalytics(api, tr, preservedSelection);
20
+ var measureId = "transformInlineNode_".concat(metadata.targetTypeName, "_").concat(Date.now());
21
+ startMeasure(measureId);
22
+ var isParentLayout = tr.doc.resolve(source.pos).parent.type === tr.doc.type.schema.nodes.layoutColumn;
23
+ var isNested = isNestedNode(preservedSelection, '') && !isParentLayout;
24
+ try {
25
+ var _api$blockControls2, _api$blockControls3;
26
+ var inlineNode = metadata.buildInlineNode(source.node);
27
+ var paragraphNode = tr.doc.type.schema.nodes.paragraph.createChecked({}, [inlineNode]);
28
+ tr.replaceWith(source.pos, source.pos + source.node.nodeSize, paragraphNode);
29
+ if (NodeSelection.isSelectable(inlineNode)) {
30
+ tr.setSelection(NodeSelection.create(tr.doc, source.pos + 1));
31
+ }
32
+ api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.stopPreservingSelection()({
33
+ tr: tr
34
+ });
35
+ api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
36
+ closeMenu: true
37
+ })({
38
+ tr: tr
39
+ });
40
+ stopMeasure(measureId, function (duration, startTime) {
41
+ analytics.transformed(duration, startTime, {
42
+ isEmptyLine: isEmptyLine([source.node]),
43
+ isNested: isNested,
44
+ isSuggested: Boolean(metadata.isSuggested),
45
+ outputNodesCount: 1,
46
+ sourceNodes: [source.node],
47
+ targetNodeType: metadata.targetTypeName
48
+ });
49
+ });
50
+ } catch (error) {
51
+ stopMeasure(measureId);
52
+ analytics.errored(error, [source.node], metadata.targetTypeName);
53
+ }
54
+ return tr;
55
+ };
56
+ };
57
+ };
@@ -1,7 +1,4 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
1
  import { expandedState } from '@atlaskit/editor-common/expand';
4
- import { logException } from '@atlaskit/editor-common/monitoring';
5
2
  import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
6
3
  import { expandSelectionToBlockRange, getSourceNodesFromSelectionRange } from '@atlaskit/editor-common/selection';
7
4
  import { Fragment, Node } from '@atlaskit/editor-prosemirror/model';
@@ -11,6 +8,8 @@ import { CellSelection } from '@atlaskit/editor-tables';
11
8
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
12
9
  import { getSingleTransformSourceNode, isExtensionTransformSource } from '../editor-actions/transformSource';
13
10
  import { isNestedNode } from '../ui/utils/isNestedNode';
11
+ import { isEmptyLine } from './is-empty-line';
12
+ import { createTransformAnalytics } from './transform-analytics';
14
13
  import { convertNodesToTargetType } from './transform-node-utils/transform';
15
14
  import { isListNode } from './transform-node-utils/utils';
16
15
  export var transformNode = function transformNode(api, transformRegistry) {
@@ -22,6 +21,7 @@ export var transformNode = function transformNode(api, transformRegistry) {
22
21
  if (!preservedSelection) {
23
22
  return tr;
24
23
  }
24
+ var analytics = createTransformAnalytics(api, tr, preservedSelection);
25
25
  if (isExperimentEnabled('platform_editor_block_menu_transform_extensions')) {
26
26
  var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection),
27
27
  _$from = _expandSelectionToBlo.$from,
@@ -80,47 +80,17 @@ export var transformNode = function transformNode(api, transformRegistry) {
80
80
  }
81
81
  });
82
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);
83
+ analytics.transformed(duration, startTime, {
84
+ isNested: isNestedNode(preservedSelection, ''),
85
+ isSuggested: Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested),
86
+ outputNodesCount: resultNodes.length,
87
+ sourceNodes: [sourceNode],
88
+ targetNodeType: targetType.name
89
+ });
102
90
  });
103
91
  } catch (error) {
104
- var _api$analytics2;
105
92
  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);
93
+ analytics.errored(error, [sourceNode], targetType.name);
124
94
  }
125
95
  return tr;
126
96
  }
@@ -136,14 +106,6 @@ export var transformNode = function transformNode(api, transformRegistry) {
136
106
  var isNested = isNestedNode(preservedSelection, '') && !isParentLayout;
137
107
  var isList = isListNode(selectedParent);
138
108
  var sourceNodes = getSourceNodesFromSelectionRange(tr, preservedSelection);
139
- var sourceNodeTypes = {};
140
- sourceNodes.forEach(function (node) {
141
- var typeName = node.type.name;
142
- sourceNodeTypes[typeName] = (sourceNodeTypes[typeName] || 0) + 1;
143
- });
144
-
145
- // Check if source node is empty paragraph or heading
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() === '');
147
109
  var isSuggested = Boolean(metadata === null || metadata === void 0 ? void 0 : metadata.isSuggested);
148
110
  try {
149
111
  var _api$blockControls6;
@@ -208,47 +170,18 @@ export var transformNode = function transformNode(api, transformRegistry) {
208
170
  tr: tr
209
171
  });
210
172
  stopMeasure(measureId, function (duration, startTime) {
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({
213
- action: ACTION.TRANSFORMED,
214
- actionSubject: ACTION_SUBJECT.ELEMENT,
215
- attributes: {
216
- duration: duration,
217
- isEmptyLine: isEmptyLine,
218
- isNested: isNested,
219
- isSuggested: isSuggested,
220
- sourceNodesCount: sourceNodes.length,
221
- sourceNodesCountByType: sourceNodeTypes,
222
- sourceNodeType: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
223
- startTime: startTime,
224
- targetNodeType: targetType.name,
225
- outputNodesCount: content.length,
226
- inputMethod: INPUT_METHOD.BLOCK_MENU
227
- },
228
- eventType: EVENT_TYPE.TRACK
229
- })(tr);
173
+ analytics.transformed(duration, startTime, {
174
+ isEmptyLine: isEmptyLine(sourceNodes),
175
+ isNested: isNested,
176
+ isSuggested: isSuggested,
177
+ outputNodesCount: content.length,
178
+ sourceNodes: sourceNodes,
179
+ targetNodeType: targetType.name
180
+ });
230
181
  });
231
182
  } catch (error) {
232
- var _api$analytics4;
233
183
  stopMeasure(measureId);
234
- logException(error, {
235
- location: 'editor-plugin-block-menu'
236
- });
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({
238
- action: ACTION.ERRORED,
239
- actionSubject: ACTION_SUBJECT.ELEMENT,
240
- actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM,
241
- eventType: EVENT_TYPE.OPERATIONAL,
242
- attributes: {
243
- docSize: tr.doc.nodeSize,
244
- error: error.message,
245
- errorStack: error.stack,
246
- from: sourceNodes.length === 1 ? sourceNodes[0].type.name : 'multiple',
247
- inputMethod: INPUT_METHOD.BLOCK_MENU,
248
- selection: preservedSelection.toJSON(),
249
- to: targetType.name
250
- }
251
- })(tr);
184
+ analytics.errored(error, sourceNodes, targetType.name);
252
185
  }
253
186
  return tr;
254
187
  };
@@ -6,11 +6,12 @@ import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
6
6
  import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
7
7
  import type { UserIntentPlugin } from '@atlaskit/editor-plugin-user-intent';
8
8
  import type { NodeType } from '@atlaskit/editor-prosemirror/model';
9
- import type { TransformNodeMetadata } from './editor-commands/types';
9
+ import type { TransformInlineNodeMetadata, TransformNodeMetadata } from './editor-commands/types';
10
10
  export declare enum FLAG_ID {
11
11
  LINK_COPIED_TO_CLIPBOARD = "link-copied-to-clipboard"
12
12
  }
13
13
  type TransformNodeCommand = (targetType: NodeType, metadata?: TransformNodeMetadata) => EditorCommand;
14
+ type TransformInlineNodeCommand = (metadata: TransformInlineNodeMetadata) => EditorCommand;
14
15
  export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
15
16
  actions: {
16
17
  getBlockMenuComponents: () => Array<RegisterBlockMenuComponent>;
@@ -19,6 +20,7 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
19
20
  registerBlockMenuTransforms: (transforms: readonly BlockTransformExtension[]) => () => void;
20
21
  };
21
22
  commands: {
23
+ transformInlineNode: TransformInlineNodeCommand;
22
24
  transformNode: TransformNodeCommand;
23
25
  };
24
26
  dependencies: [
@@ -0,0 +1,3 @@
1
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
+ /** True when there is one source node and it is an empty or whitespace-only paragraph or heading. */
3
+ export declare const isEmptyLine: (sourceNodes: readonly PMNode[]) => boolean;
@@ -0,0 +1,18 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
+ import type { Selection, Transaction } from '@atlaskit/editor-prosemirror/state';
4
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
5
+ type BlockMenuApi = ExtractInjectionAPI<BlockMenuPlugin> | undefined;
6
+ type TransformedAttrs = {
7
+ isEmptyLine?: boolean;
8
+ isNested: boolean;
9
+ isSuggested?: boolean;
10
+ outputNodesCount: number;
11
+ sourceNodes: readonly PMNode[];
12
+ targetNodeType: string;
13
+ };
14
+ export declare const createTransformAnalytics: (api: BlockMenuApi, tr: Transaction, selection: Selection) => {
15
+ transformed: (duration: number, startTime: number, { isEmptyLine, isNested, isSuggested, outputNodesCount, sourceNodes, targetNodeType, }: TransformedAttrs) => void;
16
+ errored: (error: unknown, sourceNodes: readonly PMNode[], to: string) => void;
17
+ };
18
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { EditorCommand, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
3
+ import type { TransformInlineNodeMetadata } from './types';
4
+ export declare const transformInlineNode: (api?: ExtractInjectionAPI<BlockMenuPlugin>) => (metadata: TransformInlineNodeMetadata) => EditorCommand;
@@ -1,4 +1,5 @@
1
1
  import type { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import type { Node } from '@atlaskit/editor-prosemirror/model';
2
3
  export type TransfromNodeTargetType = 'heading1' | 'heading2' | 'heading3' | 'heading4' | 'heading5' | 'heading6' | 'paragraph' | 'blockquote' | 'expand' | 'layoutSection' | 'panel' | 'panel_c1' | 'codeBlock' | 'bulletList' | 'orderedList' | 'taskList' | 'decisionList';
3
4
  export type TransformNodeMetadata = {
4
5
  inputMethod: INPUT_METHOD.BLOCK_MENU;
@@ -7,3 +8,8 @@ export type TransformNodeMetadata = {
7
8
  targetTypeName: TransfromNodeTargetType;
8
9
  triggeredFrom: INPUT_METHOD.MOUSE | INPUT_METHOD.KEYBOARD;
9
10
  };
11
+ export type TransformInlineNodeMetadata = {
12
+ buildInlineNode: (source: Node) => Node;
13
+ isSuggested?: boolean;
14
+ targetTypeName: string;
15
+ };
@@ -1 +1 @@
1
- export type { TransformNodeMetadata, TransfromNodeTargetType } from '../editor-commands/types';
1
+ export type { TransformInlineNodeMetadata, TransformNodeMetadata, TransfromNodeTargetType, } from '../editor-commands/types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "15.0.13",
3
+ "version": "15.1.0",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -37,53 +37,17 @@
37
37
  "@atlaskit/platform-feature-flags": "^2.2.0",
38
38
  "@atlaskit/primitives": "^22.5.0",
39
39
  "@atlaskit/prosemirror-history": "^1.2.0",
40
- "@atlaskit/tmp-editor-statsig": "^171.0.0",
40
+ "@atlaskit/tmp-editor-statsig": "^172.0.0",
41
41
  "@atlaskit/tokens": "^16.11.0",
42
42
  "@babel/runtime": "^7.0.0",
43
43
  "bind-event-listener": "^3.0.0",
44
44
  "memoize-one": "^6.0.0"
45
45
  },
46
46
  "peerDependencies": {
47
- "@atlaskit/editor-common": "^120.10.0",
47
+ "@atlaskit/editor-common": "^120.11.0",
48
48
  "react": "^18.2.0 || ^19.2.0",
49
49
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
50
50
  },
51
- "techstack": {
52
- "@atlassian/frontend": {
53
- "code-structure": [
54
- "editor-plugin"
55
- ],
56
- "import-structure": [
57
- "atlassian-conventions"
58
- ],
59
- "circular-dependencies": [
60
- "file-and-folder-level"
61
- ]
62
- },
63
- "@repo/internal": {
64
- "dom-events": "use-bind-event-listener",
65
- "analytics": [
66
- "analytics-next"
67
- ],
68
- "design-tokens": [
69
- "color"
70
- ],
71
- "theming": [
72
- "react-context"
73
- ],
74
- "ui-components": [
75
- "lite-mode"
76
- ],
77
- "deprecation": "no-deprecated-imports",
78
- "styling": [
79
- "emotion",
80
- "emotion"
81
- ],
82
- "imports": [
83
- "import-no-extraneous-disable-for-examples-and-docs"
84
- ]
85
- }
86
- },
87
51
  "platform-feature-flags": {
88
52
  "platform_editor_adf_with_localid": {
89
53
  "type": "boolean"