@atlaskit/editor-plugin-block-menu 6.0.47 → 6.0.48

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,15 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 6.0.48
4
+
5
+ ### Patch Changes
6
+
7
+ - [`3cfeff169fe0d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3cfeff169fe0d) -
8
+ [ux] Persist width marks for supported node types when transforming
9
+ - [`8d553b883996b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8d553b883996b) -
10
+ Add block menu transform experience tracking
11
+ - Updated dependencies
12
+
3
13
  ## 6.0.47
4
14
 
5
15
  ### Patch Changes
@@ -6,21 +6,23 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.wrapMixedContentStep = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _utils = require("@atlaskit/editor-common/utils");
9
10
  var _model = require("@atlaskit/editor-prosemirror/model");
10
11
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
12
  var _marks = require("../marks");
12
13
  var _types = require("../types");
13
- var _utils = require("../utils");
14
+ var _utils2 = require("../utils");
14
15
  /**
15
16
  * Creates a layout section with two columns, where the first column contains the provided content.
17
+ * Preserves breakout marks if provided.
16
18
  */
17
- var createLayoutSection = function createLayoutSection(content, layoutSection, layoutColumn) {
19
+ var createLayoutSection = function createLayoutSection(content, layoutSection, layoutColumn, marks) {
18
20
  var columnOne = layoutColumn.createAndFill({}, (0, _marks.removeDisallowedMarks)(content, layoutColumn));
19
21
  var columnTwo = layoutColumn.createAndFill();
20
22
  if (!columnOne || !columnTwo) {
21
23
  return null;
22
24
  }
23
- return layoutSection.createAndFill({}, [columnOne, columnTwo]);
25
+ return layoutSection.createAndFill({}, [columnOne, columnTwo], marks);
24
26
  };
25
27
 
26
28
  /**
@@ -140,6 +142,25 @@ var wrapMixedContentStep = exports.wrapMixedContentStep = function wrapMixedCont
140
142
  var _schema$nodes = schema.nodes,
141
143
  layoutSection = _schema$nodes.layoutSection,
142
144
  layoutColumn = _schema$nodes.layoutColumn;
145
+
146
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
147
+ // Preserves breakout mark width when transforming to layoutSection from resizable nodes.
148
+ // This ensures that custom width settings are maintained during block type transformations.
149
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 151-159).
150
+ var breakoutMark;
151
+ if ((0, _platformFeatureFlags.fg)('platform_editor_preserve_breakout_on_transform')) {
152
+ // NEW BEHAVIOR: Preserve breakout mark when both source and target support resizing
153
+ var sourceSupportsBreakout = _utils.breakoutResizableNodes.includes(fromNode.type.name);
154
+ var targetSupportsBreakout = _utils.breakoutResizableNodes.includes(targetNodeTypeName);
155
+ var shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
156
+ if (shouldPreserveBreakout) {
157
+ breakoutMark = fromNode.marks.find(function (mark) {
158
+ return mark.type.name === 'breakout';
159
+ });
160
+ }
161
+ }
162
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
163
+
143
164
  var result = [];
144
165
  var currentContainerContent = [];
145
166
  var hasCreatedContainer = false;
@@ -149,7 +170,7 @@ var wrapMixedContentStep = exports.wrapMixedContentStep = function wrapMixedCont
149
170
  }
150
171
  var container = null;
151
172
  if (isLayout) {
152
- container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn);
173
+ container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn, breakoutMark ? [breakoutMark] : undefined);
153
174
  } else if (isCodeblock) {
154
175
  container = createTextContentContainer(currentContainerContent, targetNodeType, schema);
155
176
  } else {
@@ -171,10 +192,10 @@ var wrapMixedContentStep = exports.wrapMixedContentStep = function wrapMixedCont
171
192
  (_currentContainerCont = currentContainerContent).push.apply(_currentContainerCont, (0, _toConsumableArray2.default)((0, _marks.removeDisallowedMarks)([node], validationType)));
172
193
  };
173
194
  var handleCodeblockTextNode = function handleCodeblockTextNode(node) {
174
- currentContainerContent.push((0, _utils.createTextContent)(node));
195
+ currentContainerContent.push((0, _utils2.createTextContent)(node));
175
196
  };
176
197
  var handleConvertibleTextNode = function handleConvertibleTextNode(node) {
177
- var paragraph = (0, _utils.convertTextNodeToParagraph)(node, schema);
198
+ var paragraph = (0, _utils2.convertTextNodeToParagraph)(node, schema);
178
199
  if (paragraph) {
179
200
  currentContainerContent.push(paragraph);
180
201
  }
@@ -188,11 +209,11 @@ var wrapMixedContentStep = exports.wrapMixedContentStep = function wrapMixedCont
188
209
  handleWrappableNode(node);
189
210
  return;
190
211
  }
191
- if ((0, _utils.isTextNode)(node) && isCodeblock) {
212
+ if ((0, _utils2.isTextNode)(node) && isCodeblock) {
192
213
  handleCodeblockTextNode(node);
193
214
  return;
194
215
  }
195
- if ((0, _utils.isTextNode)(node)) {
216
+ if ((0, _utils2.isTextNode)(node)) {
196
217
  handleConvertibleTextNode(node);
197
218
  return;
198
219
  }
@@ -4,17 +4,22 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.wrapStep = void 0;
7
+ var _utils = require("@atlaskit/editor-common/utils");
7
8
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
8
9
  var _marks = require("./marks");
9
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
10
11
  /**
11
12
  * Wraps nodes into the target container type.
12
13
  * When wrapping into expand, any expand children are converted to nestedExpand
13
14
  * since expand cannot be a direct child of expand.
15
+ *
16
+ * Preserves breakout marks when both source and target nodes support resizing
17
+ * (codeBlock, expand, layoutSection).
14
18
  */
15
19
  var wrapStep = exports.wrapStep = function wrapStep(nodes, context) {
16
20
  var schema = context.schema,
17
- targetNodeTypeName = context.targetNodeTypeName;
21
+ targetNodeTypeName = context.targetNodeTypeName,
22
+ fromNode = context.fromNode;
18
23
 
19
24
  // When wrapping into expand, convert any expand children to nestedExpand
20
25
  // since expand cannot be a direct child of expand
@@ -22,7 +27,7 @@ var wrapStep = exports.wrapStep = function wrapStep(nodes, context) {
22
27
  if (targetNodeTypeName === 'expand') {
23
28
  processedNodes = nodes.map(function (node) {
24
29
  if (node.type.name === 'expand') {
25
- var nestedExpandNode = (0, _utils.convertExpandToNestedExpand)(node, schema);
30
+ var nestedExpandNode = (0, _utils2.convertExpandToNestedExpand)(node, schema);
26
31
  return nestedExpandNode !== null && nestedExpandNode !== void 0 ? nestedExpandNode : node;
27
32
  }
28
33
  return node;
@@ -39,6 +44,28 @@ var wrapStep = exports.wrapStep = function wrapStep(nodes, context) {
39
44
  var nodeAttrs = isExpandType && (0, _platformFeatureFlags.fg)('platform_editor_block_menu_expand_localid_fix') ? {
40
45
  localId: crypto.randomUUID()
41
46
  } : {};
42
- var outputNode = targetNodeType.createAndFill(nodeAttrs, (0, _marks.removeDisallowedMarks)(processedNodes, schema.nodes[targetNodeTypeName]));
47
+
48
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
49
+ // Preserves breakout mark width when transforming between resizable nodes (codeBlock, expand, layoutSection).
50
+ // This ensures that custom width settings are maintained during block type transformations.
51
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 47-58).
52
+ var marks;
53
+ if ((0, _platformFeatureFlags.fg)('platform_editor_preserve_breakout_on_transform')) {
54
+ // NEW BEHAVIOR: Preserve breakout marks when both source and target support resizing
55
+ var sourceSupportsBreakout = _utils.breakoutResizableNodes.includes(fromNode.type.name);
56
+ var targetSupportsBreakout = _utils.breakoutResizableNodes.includes(targetNodeType.name);
57
+ var shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
58
+ if (shouldPreserveBreakout) {
59
+ var breakoutMark = fromNode.marks.find(function (mark) {
60
+ return mark.type.name === 'breakout';
61
+ });
62
+ if (breakoutMark) {
63
+ marks = [breakoutMark];
64
+ }
65
+ }
66
+ }
67
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
68
+
69
+ var outputNode = targetNodeType.createAndFill(nodeAttrs, (0, _marks.removeDisallowedMarks)(processedNodes, schema.nodes[targetNodeTypeName]), marks);
43
70
  return outputNode ? [outputNode] : nodes;
44
71
  };
@@ -91,6 +91,17 @@ var getBlockMenuExperiencesPlugin = exports.getBlockMenuExperiencesPlugin = func
91
91
  observeConfig: actionObserveConfig
92
92
  })]
93
93
  });
94
+ var blockTransformExperience = new _experiences.Experience(_experiences.EXPERIENCE_ID.MENU_ACTION, {
95
+ action: _analytics.ACTION.TRANSFORMED,
96
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.TRANSFORM_BLOCK,
97
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
98
+ checks: [new _experiences.ExperienceCheckTimeout({
99
+ durationMs: TIMEOUT_DURATION
100
+ }), new _experiences.ExperienceCheckDomMutation({
101
+ onDomMutation: _experienceCheckUtils.handleTransformDomMutation,
102
+ observeConfig: actionObserveConfig
103
+ })]
104
+ });
94
105
  var handleMenuOpened = function handleMenuOpened(method) {
95
106
  // Don't start if block menu is already visible
96
107
  if ((0, _experienceCheckUtils.isBlockMenuVisible)(getPopupsTarget())) {
@@ -100,7 +111,20 @@ var getBlockMenuExperiencesPlugin = exports.getBlockMenuExperiencesPlugin = func
100
111
  method: method
101
112
  });
102
113
  };
114
+ var handleTransformActioned = function handleTransformActioned(target) {
115
+ if (!target.closest('[data-testid="editor-turn-into-menu--content"]')) {
116
+ return false;
117
+ }
118
+ var turnIntoButton = target.closest('button');
119
+ if (turnIntoButton && turnIntoButton instanceof HTMLElement && !turnIntoButton.hasAttribute('disabled') && turnIntoButton.getAttribute('aria-disabled') !== 'true') {
120
+ blockTransformExperience.start();
121
+ }
122
+ return true;
123
+ };
103
124
  var handleItemActioned = function handleItemActioned(target) {
125
+ if (handleTransformActioned(target)) {
126
+ return;
127
+ }
104
128
  var button = target.closest('button[data-testid]');
105
129
  if (!button || !(button instanceof HTMLButtonElement) || button.disabled || button.getAttribute('aria-disabled') === 'true') {
106
130
  return;
@@ -180,6 +204,9 @@ var getBlockMenuExperiencesPlugin = exports.getBlockMenuExperiencesPlugin = func
180
204
  blockDeleteExperience.abort({
181
205
  reason: ABORT_REASON.EDITOR_DESTROYED
182
206
  });
207
+ blockTransformExperience.abort({
208
+ reason: ABORT_REASON.EDITOR_DESTROYED
209
+ });
183
210
  editorView = undefined;
184
211
  unbindClickListener();
185
212
  unbindKeydownListener();
@@ -4,9 +4,10 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.isDragHandleElement = exports.isBlockMenuVisible = exports.handleMoveDomMutation = exports.handleMenuOpenDomMutation = exports.handleDeleteDomMutation = exports.getParentDOMAtSelection = void 0;
7
+ exports.isDragHandleElement = exports.isBlockMenuVisible = exports.handleTransformDomMutation = exports.handleMoveDomMutation = exports.handleMenuOpenDomMutation = exports.handleDeleteDomMutation = exports.getParentDOMAtSelection = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _experiences = require("@atlaskit/editor-common/experiences");
10
+ var _editorTables = require("@atlaskit/editor-tables");
10
11
  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; } } }; }
11
12
  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; } }
12
13
  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; }
@@ -38,19 +39,31 @@ var isBlockMenuVisible = exports.isBlockMenuVisible = function isBlockMenuVisibl
38
39
  * from the provided editor view.
39
40
  *
40
41
  * @param editorView - The editor view from which to get the parent DOM element
41
- * @returns The parent HTMLElement at the selection start, or null if not found
42
+ * @returns The parent HTMLElement of the block at the selection, or null if not found
42
43
  */
43
44
  var getParentDOMAtSelection = exports.getParentDOMAtSelection = function getParentDOMAtSelection(editorView) {
44
45
  if (!editorView) {
45
46
  return null;
46
47
  }
47
48
  var selection = editorView.state.selection;
49
+ if (selection instanceof _editorTables.CellSelection) {
50
+ // $anchorCell resolves inside the row (before the cell), so
51
+ // $anchorCell.depth is the row's depth. Table is one level up.
52
+ var $cell = selection.$anchorCell;
53
+ var tableDepth = $cell.depth - 1;
54
+ if (tableDepth > 0) {
55
+ var dom = editorView.nodeDOM($cell.before(tableDepth));
56
+ if (dom instanceof HTMLElement && dom.parentElement) {
57
+ return dom.parentElement;
58
+ }
59
+ }
60
+ }
48
61
  var from = selection.from;
49
62
  var nodeDOM = editorView.nodeDOM(from);
50
63
  if (nodeDOM instanceof HTMLElement) {
51
64
  return nodeDOM.parentElement;
52
65
  }
53
- return null;
66
+ return editorView.dom || null;
54
67
  };
55
68
  var isBlockMenuAddedInMutation = function isBlockMenuAddedInMutation(_ref) {
56
69
  var type = _ref.type,
@@ -144,4 +157,29 @@ var handleDeleteDomMutation = exports.handleDeleteDomMutation = function handleD
144
157
  };
145
158
  }
146
159
  return undefined;
160
+ };
161
+
162
+ /**
163
+ * Handles DOM mutations to determine if a transform action was performed.
164
+ *
165
+ * Transforms replace one block type with another (e.g. paragraph → heading),
166
+ * producing childList mutations with both removed (old node) and added (new node).
167
+ *
168
+ * @param options.mutations - The list of DOM mutation records
169
+ * @returns An ExperienceCheckResult indicating success if a transform was detected, otherwise undefined
170
+ */
171
+ var handleTransformDomMutation = exports.handleTransformDomMutation = function handleTransformDomMutation(_ref5) {
172
+ var mutations = _ref5.mutations;
173
+ var hasRemovedNodes = mutations.some(function (m) {
174
+ return m.type === 'childList' && m.removedNodes.length > 0;
175
+ });
176
+ var hasAddedNodes = mutations.some(function (m) {
177
+ return m.type === 'childList' && m.addedNodes.length > 0;
178
+ });
179
+ if (hasRemovedNodes && hasAddedNodes) {
180
+ return {
181
+ status: 'success'
182
+ };
183
+ }
184
+ return undefined;
147
185
  };
@@ -1,3 +1,4 @@
1
+ import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
1
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
3
  import { fg } from '@atlaskit/platform-feature-flags';
3
4
  import { removeDisallowedMarks } from '../marks';
@@ -6,14 +7,15 @@ import { convertTextNodeToParagraph, createTextContent, isTextNode } from '../ut
6
7
 
7
8
  /**
8
9
  * Creates a layout section with two columns, where the first column contains the provided content.
10
+ * Preserves breakout marks if provided.
9
11
  */
10
- const createLayoutSection = (content, layoutSection, layoutColumn) => {
12
+ const createLayoutSection = (content, layoutSection, layoutColumn, marks) => {
11
13
  const columnOne = layoutColumn.createAndFill({}, removeDisallowedMarks(content, layoutColumn));
12
14
  const columnTwo = layoutColumn.createAndFill();
13
15
  if (!columnOne || !columnTwo) {
14
16
  return null;
15
17
  }
16
- return layoutSection.createAndFill({}, [columnOne, columnTwo]);
18
+ return layoutSection.createAndFill({}, [columnOne, columnTwo], marks);
17
19
  };
18
20
 
19
21
  /**
@@ -136,6 +138,23 @@ export const wrapMixedContentStep = (nodes, context) => {
136
138
  layoutSection,
137
139
  layoutColumn
138
140
  } = schema.nodes;
141
+
142
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
143
+ // Preserves breakout mark width when transforming to layoutSection from resizable nodes.
144
+ // This ensures that custom width settings are maintained during block type transformations.
145
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 151-159).
146
+ let breakoutMark;
147
+ if (fg('platform_editor_preserve_breakout_on_transform')) {
148
+ // NEW BEHAVIOR: Preserve breakout mark when both source and target support resizing
149
+ const sourceSupportsBreakout = breakoutResizableNodes.includes(fromNode.type.name);
150
+ const targetSupportsBreakout = breakoutResizableNodes.includes(targetNodeTypeName);
151
+ const shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
152
+ if (shouldPreserveBreakout) {
153
+ breakoutMark = fromNode.marks.find(mark => mark.type.name === 'breakout');
154
+ }
155
+ }
156
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
157
+
139
158
  const result = [];
140
159
  let currentContainerContent = [];
141
160
  let hasCreatedContainer = false;
@@ -145,7 +164,7 @@ export const wrapMixedContentStep = (nodes, context) => {
145
164
  }
146
165
  let container = null;
147
166
  if (isLayout) {
148
- container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn);
167
+ container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn, breakoutMark ? [breakoutMark] : undefined);
149
168
  } else if (isCodeblock) {
150
169
  container = createTextContentContainer(currentContainerContent, targetNodeType, schema);
151
170
  } else {
@@ -1,3 +1,4 @@
1
+ import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
1
2
  import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { removeDisallowedMarks } from './marks';
3
4
  import { convertExpandToNestedExpand } from './utils';
@@ -6,11 +7,15 @@ import { convertExpandToNestedExpand } from './utils';
6
7
  * Wraps nodes into the target container type.
7
8
  * When wrapping into expand, any expand children are converted to nestedExpand
8
9
  * since expand cannot be a direct child of expand.
10
+ *
11
+ * Preserves breakout marks when both source and target nodes support resizing
12
+ * (codeBlock, expand, layoutSection).
9
13
  */
10
14
  export const wrapStep = (nodes, context) => {
11
15
  const {
12
16
  schema,
13
- targetNodeTypeName
17
+ targetNodeTypeName,
18
+ fromNode
14
19
  } = context;
15
20
 
16
21
  // When wrapping into expand, convert any expand children to nestedExpand
@@ -36,6 +41,26 @@ export const wrapStep = (nodes, context) => {
36
41
  const nodeAttrs = isExpandType && fg('platform_editor_block_menu_expand_localid_fix') ? {
37
42
  localId: crypto.randomUUID()
38
43
  } : {};
39
- const outputNode = targetNodeType.createAndFill(nodeAttrs, removeDisallowedMarks(processedNodes, schema.nodes[targetNodeTypeName]));
44
+
45
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
46
+ // Preserves breakout mark width when transforming between resizable nodes (codeBlock, expand, layoutSection).
47
+ // This ensures that custom width settings are maintained during block type transformations.
48
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 47-58).
49
+ let marks;
50
+ if (fg('platform_editor_preserve_breakout_on_transform')) {
51
+ // NEW BEHAVIOR: Preserve breakout marks when both source and target support resizing
52
+ const sourceSupportsBreakout = breakoutResizableNodes.includes(fromNode.type.name);
53
+ const targetSupportsBreakout = breakoutResizableNodes.includes(targetNodeType.name);
54
+ const shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
55
+ if (shouldPreserveBreakout) {
56
+ const breakoutMark = fromNode.marks.find(mark => mark.type.name === 'breakout');
57
+ if (breakoutMark) {
58
+ marks = [breakoutMark];
59
+ }
60
+ }
61
+ }
62
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
63
+
64
+ const outputNode = targetNodeType.createAndFill(nodeAttrs, removeDisallowedMarks(processedNodes, schema.nodes[targetNodeTypeName]), marks);
40
65
  return outputNode ? [outputNode] : nodes;
41
66
  };
@@ -4,7 +4,7 @@ import { BLOCK_MENU_ACTION_TEST_ID } from '@atlaskit/editor-common/block-menu';
4
4
  import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView } from '@atlaskit/editor-common/experiences';
5
5
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
- import { getParentDOMAtSelection, handleDeleteDomMutation, handleMenuOpenDomMutation, handleMoveDomMutation, isBlockMenuVisible, isDragHandleElement } from './experience-check-utils';
7
+ import { getParentDOMAtSelection, handleDeleteDomMutation, handleMenuOpenDomMutation, handleMoveDomMutation, handleTransformDomMutation, isBlockMenuVisible, isDragHandleElement } from './experience-check-utils';
8
8
  const TIMEOUT_DURATION = 1000;
9
9
  const pluginKey = new PluginKey('blockMenuExperiences');
10
10
  const START_METHOD = {
@@ -82,6 +82,17 @@ export const getBlockMenuExperiencesPlugin = ({
82
82
  observeConfig: actionObserveConfig
83
83
  })]
84
84
  });
85
+ const blockTransformExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, {
86
+ action: ACTION.TRANSFORMED,
87
+ actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM_BLOCK,
88
+ dispatchAnalyticsEvent,
89
+ checks: [new ExperienceCheckTimeout({
90
+ durationMs: TIMEOUT_DURATION
91
+ }), new ExperienceCheckDomMutation({
92
+ onDomMutation: handleTransformDomMutation,
93
+ observeConfig: actionObserveConfig
94
+ })]
95
+ });
85
96
  const handleMenuOpened = method => {
86
97
  // Don't start if block menu is already visible
87
98
  if (isBlockMenuVisible(getPopupsTarget())) {
@@ -91,7 +102,20 @@ export const getBlockMenuExperiencesPlugin = ({
91
102
  method
92
103
  });
93
104
  };
105
+ const handleTransformActioned = target => {
106
+ if (!target.closest('[data-testid="editor-turn-into-menu--content"]')) {
107
+ return false;
108
+ }
109
+ const turnIntoButton = target.closest('button');
110
+ if (turnIntoButton && turnIntoButton instanceof HTMLElement && !turnIntoButton.hasAttribute('disabled') && turnIntoButton.getAttribute('aria-disabled') !== 'true') {
111
+ blockTransformExperience.start();
112
+ }
113
+ return true;
114
+ };
94
115
  const handleItemActioned = target => {
116
+ if (handleTransformActioned(target)) {
117
+ return;
118
+ }
95
119
  const button = target.closest('button[data-testid]');
96
120
  if (!button || !(button instanceof HTMLButtonElement) || button.disabled || button.getAttribute('aria-disabled') === 'true') {
97
121
  return;
@@ -171,6 +195,9 @@ export const getBlockMenuExperiencesPlugin = ({
171
195
  blockDeleteExperience.abort({
172
196
  reason: ABORT_REASON.EDITOR_DESTROYED
173
197
  });
198
+ blockTransformExperience.abort({
199
+ reason: ABORT_REASON.EDITOR_DESTROYED
200
+ });
174
201
  editorView = undefined;
175
202
  unbindClickListener();
176
203
  unbindKeydownListener();
@@ -1,4 +1,6 @@
1
1
  import { popupWithNestedElement } from '@atlaskit/editor-common/experiences';
2
+ import { CellSelection } from '@atlaskit/editor-tables';
3
+
2
4
  /**
3
5
  * Checks if the given element or any of its ancestors is a drag handle element.
4
6
  *
@@ -27,7 +29,7 @@ export const isBlockMenuVisible = popupsTarget => {
27
29
  * from the provided editor view.
28
30
  *
29
31
  * @param editorView - The editor view from which to get the parent DOM element
30
- * @returns The parent HTMLElement at the selection start, or null if not found
32
+ * @returns The parent HTMLElement of the block at the selection, or null if not found
31
33
  */
32
34
  export const getParentDOMAtSelection = editorView => {
33
35
  if (!editorView) {
@@ -36,12 +38,24 @@ export const getParentDOMAtSelection = editorView => {
36
38
  const {
37
39
  selection
38
40
  } = editorView.state;
41
+ if (selection instanceof CellSelection) {
42
+ // $anchorCell resolves inside the row (before the cell), so
43
+ // $anchorCell.depth is the row's depth. Table is one level up.
44
+ const $cell = selection.$anchorCell;
45
+ const tableDepth = $cell.depth - 1;
46
+ if (tableDepth > 0) {
47
+ const dom = editorView.nodeDOM($cell.before(tableDepth));
48
+ if (dom instanceof HTMLElement && dom.parentElement) {
49
+ return dom.parentElement;
50
+ }
51
+ }
52
+ }
39
53
  const from = selection.from;
40
54
  const nodeDOM = editorView.nodeDOM(from);
41
55
  if (nodeDOM instanceof HTMLElement) {
42
56
  return nodeDOM.parentElement;
43
57
  }
44
- return null;
58
+ return editorView.dom || null;
45
59
  };
46
60
  const isBlockMenuAddedInMutation = ({
47
61
  type,
@@ -122,4 +136,26 @@ export const handleDeleteDomMutation = ({
122
136
  };
123
137
  }
124
138
  return undefined;
139
+ };
140
+
141
+ /**
142
+ * Handles DOM mutations to determine if a transform action was performed.
143
+ *
144
+ * Transforms replace one block type with another (e.g. paragraph → heading),
145
+ * producing childList mutations with both removed (old node) and added (new node).
146
+ *
147
+ * @param options.mutations - The list of DOM mutation records
148
+ * @returns An ExperienceCheckResult indicating success if a transform was detected, otherwise undefined
149
+ */
150
+ export const handleTransformDomMutation = ({
151
+ mutations
152
+ }) => {
153
+ const hasRemovedNodes = mutations.some(m => m.type === 'childList' && m.removedNodes.length > 0);
154
+ const hasAddedNodes = mutations.some(m => m.type === 'childList' && m.addedNodes.length > 0);
155
+ if (hasRemovedNodes && hasAddedNodes) {
156
+ return {
157
+ status: 'success'
158
+ };
159
+ }
160
+ return undefined;
125
161
  };
@@ -1,4 +1,5 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
2
3
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
4
  import { fg } from '@atlaskit/platform-feature-flags';
4
5
  import { removeDisallowedMarks } from '../marks';
@@ -7,14 +8,15 @@ import { convertTextNodeToParagraph, createTextContent, isTextNode } from '../ut
7
8
 
8
9
  /**
9
10
  * Creates a layout section with two columns, where the first column contains the provided content.
11
+ * Preserves breakout marks if provided.
10
12
  */
11
- var createLayoutSection = function createLayoutSection(content, layoutSection, layoutColumn) {
13
+ var createLayoutSection = function createLayoutSection(content, layoutSection, layoutColumn, marks) {
12
14
  var columnOne = layoutColumn.createAndFill({}, removeDisallowedMarks(content, layoutColumn));
13
15
  var columnTwo = layoutColumn.createAndFill();
14
16
  if (!columnOne || !columnTwo) {
15
17
  return null;
16
18
  }
17
- return layoutSection.createAndFill({}, [columnOne, columnTwo]);
19
+ return layoutSection.createAndFill({}, [columnOne, columnTwo], marks);
18
20
  };
19
21
 
20
22
  /**
@@ -134,6 +136,25 @@ export var wrapMixedContentStep = function wrapMixedContentStep(nodes, context)
134
136
  var _schema$nodes = schema.nodes,
135
137
  layoutSection = _schema$nodes.layoutSection,
136
138
  layoutColumn = _schema$nodes.layoutColumn;
139
+
140
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
141
+ // Preserves breakout mark width when transforming to layoutSection from resizable nodes.
142
+ // This ensures that custom width settings are maintained during block type transformations.
143
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 151-159).
144
+ var breakoutMark;
145
+ if (fg('platform_editor_preserve_breakout_on_transform')) {
146
+ // NEW BEHAVIOR: Preserve breakout mark when both source and target support resizing
147
+ var sourceSupportsBreakout = breakoutResizableNodes.includes(fromNode.type.name);
148
+ var targetSupportsBreakout = breakoutResizableNodes.includes(targetNodeTypeName);
149
+ var shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
150
+ if (shouldPreserveBreakout) {
151
+ breakoutMark = fromNode.marks.find(function (mark) {
152
+ return mark.type.name === 'breakout';
153
+ });
154
+ }
155
+ }
156
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
157
+
137
158
  var result = [];
138
159
  var currentContainerContent = [];
139
160
  var hasCreatedContainer = false;
@@ -143,7 +164,7 @@ export var wrapMixedContentStep = function wrapMixedContentStep(nodes, context)
143
164
  }
144
165
  var container = null;
145
166
  if (isLayout) {
146
- container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn);
167
+ container = createLayoutSection(currentContainerContent, layoutSection, layoutColumn, breakoutMark ? [breakoutMark] : undefined);
147
168
  } else if (isCodeblock) {
148
169
  container = createTextContentContainer(currentContainerContent, targetNodeType, schema);
149
170
  } else {
@@ -1,3 +1,4 @@
1
+ import { breakoutResizableNodes } from '@atlaskit/editor-common/utils';
1
2
  import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { removeDisallowedMarks } from './marks';
3
4
  import { convertExpandToNestedExpand } from './utils';
@@ -6,10 +7,14 @@ import { convertExpandToNestedExpand } from './utils';
6
7
  * Wraps nodes into the target container type.
7
8
  * When wrapping into expand, any expand children are converted to nestedExpand
8
9
  * since expand cannot be a direct child of expand.
10
+ *
11
+ * Preserves breakout marks when both source and target nodes support resizing
12
+ * (codeBlock, expand, layoutSection).
9
13
  */
10
14
  export var wrapStep = function wrapStep(nodes, context) {
11
15
  var schema = context.schema,
12
- targetNodeTypeName = context.targetNodeTypeName;
16
+ targetNodeTypeName = context.targetNodeTypeName,
17
+ fromNode = context.fromNode;
13
18
 
14
19
  // When wrapping into expand, convert any expand children to nestedExpand
15
20
  // since expand cannot be a direct child of expand
@@ -34,6 +39,28 @@ export var wrapStep = function wrapStep(nodes, context) {
34
39
  var nodeAttrs = isExpandType && fg('platform_editor_block_menu_expand_localid_fix') ? {
35
40
  localId: crypto.randomUUID()
36
41
  } : {};
37
- var outputNode = targetNodeType.createAndFill(nodeAttrs, removeDisallowedMarks(processedNodes, schema.nodes[targetNodeTypeName]));
42
+
43
+ // [FEATURE FLAG: platform_editor_preserve_breakout_on_transform]
44
+ // Preserves breakout mark width when transforming between resizable nodes (codeBlock, expand, layoutSection).
45
+ // This ensures that custom width settings are maintained during block type transformations.
46
+ // To clean up: remove the if-else block and keep only the flag-on behavior (lines 47-58).
47
+ var marks;
48
+ if (fg('platform_editor_preserve_breakout_on_transform')) {
49
+ // NEW BEHAVIOR: Preserve breakout marks when both source and target support resizing
50
+ var sourceSupportsBreakout = breakoutResizableNodes.includes(fromNode.type.name);
51
+ var targetSupportsBreakout = breakoutResizableNodes.includes(targetNodeType.name);
52
+ var shouldPreserveBreakout = sourceSupportsBreakout && targetSupportsBreakout;
53
+ if (shouldPreserveBreakout) {
54
+ var breakoutMark = fromNode.marks.find(function (mark) {
55
+ return mark.type.name === 'breakout';
56
+ });
57
+ if (breakoutMark) {
58
+ marks = [breakoutMark];
59
+ }
60
+ }
61
+ }
62
+ // else: OLD BEHAVIOR - no breakout mark preservation (to be removed when flag is cleaned up)
63
+
64
+ var outputNode = targetNodeType.createAndFill(nodeAttrs, removeDisallowedMarks(processedNodes, schema.nodes[targetNodeTypeName]), marks);
38
65
  return outputNode ? [outputNode] : nodes;
39
66
  };
@@ -4,7 +4,7 @@ import { BLOCK_MENU_ACTION_TEST_ID } from '@atlaskit/editor-common/block-menu';
4
4
  import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView } from '@atlaskit/editor-common/experiences';
5
5
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
- import { getParentDOMAtSelection, handleDeleteDomMutation, handleMenuOpenDomMutation, handleMoveDomMutation, isBlockMenuVisible, isDragHandleElement } from './experience-check-utils';
7
+ import { getParentDOMAtSelection, handleDeleteDomMutation, handleMenuOpenDomMutation, handleMoveDomMutation, handleTransformDomMutation, isBlockMenuVisible, isDragHandleElement } from './experience-check-utils';
8
8
  var TIMEOUT_DURATION = 1000;
9
9
  var pluginKey = new PluginKey('blockMenuExperiences');
10
10
  var START_METHOD = {
@@ -85,6 +85,17 @@ export var getBlockMenuExperiencesPlugin = function getBlockMenuExperiencesPlugi
85
85
  observeConfig: actionObserveConfig
86
86
  })]
87
87
  });
88
+ var blockTransformExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, {
89
+ action: ACTION.TRANSFORMED,
90
+ actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM_BLOCK,
91
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
92
+ checks: [new ExperienceCheckTimeout({
93
+ durationMs: TIMEOUT_DURATION
94
+ }), new ExperienceCheckDomMutation({
95
+ onDomMutation: handleTransformDomMutation,
96
+ observeConfig: actionObserveConfig
97
+ })]
98
+ });
88
99
  var handleMenuOpened = function handleMenuOpened(method) {
89
100
  // Don't start if block menu is already visible
90
101
  if (isBlockMenuVisible(getPopupsTarget())) {
@@ -94,7 +105,20 @@ export var getBlockMenuExperiencesPlugin = function getBlockMenuExperiencesPlugi
94
105
  method: method
95
106
  });
96
107
  };
108
+ var handleTransformActioned = function handleTransformActioned(target) {
109
+ if (!target.closest('[data-testid="editor-turn-into-menu--content"]')) {
110
+ return false;
111
+ }
112
+ var turnIntoButton = target.closest('button');
113
+ if (turnIntoButton && turnIntoButton instanceof HTMLElement && !turnIntoButton.hasAttribute('disabled') && turnIntoButton.getAttribute('aria-disabled') !== 'true') {
114
+ blockTransformExperience.start();
115
+ }
116
+ return true;
117
+ };
97
118
  var handleItemActioned = function handleItemActioned(target) {
119
+ if (handleTransformActioned(target)) {
120
+ return;
121
+ }
98
122
  var button = target.closest('button[data-testid]');
99
123
  if (!button || !(button instanceof HTMLButtonElement) || button.disabled || button.getAttribute('aria-disabled') === 'true') {
100
124
  return;
@@ -174,6 +198,9 @@ export var getBlockMenuExperiencesPlugin = function getBlockMenuExperiencesPlugi
174
198
  blockDeleteExperience.abort({
175
199
  reason: ABORT_REASON.EDITOR_DESTROYED
176
200
  });
201
+ blockTransformExperience.abort({
202
+ reason: ABORT_REASON.EDITOR_DESTROYED
203
+ });
177
204
  editorView = undefined;
178
205
  unbindClickListener();
179
206
  unbindKeydownListener();
@@ -3,6 +3,8 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
3
3
  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; } }
4
4
  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; }
5
5
  import { popupWithNestedElement } from '@atlaskit/editor-common/experiences';
6
+ import { CellSelection } from '@atlaskit/editor-tables';
7
+
6
8
  /**
7
9
  * Checks if the given element or any of its ancestors is a drag handle element.
8
10
  *
@@ -31,19 +33,31 @@ export var isBlockMenuVisible = function isBlockMenuVisible(popupsTarget) {
31
33
  * from the provided editor view.
32
34
  *
33
35
  * @param editorView - The editor view from which to get the parent DOM element
34
- * @returns The parent HTMLElement at the selection start, or null if not found
36
+ * @returns The parent HTMLElement of the block at the selection, or null if not found
35
37
  */
36
38
  export var getParentDOMAtSelection = function getParentDOMAtSelection(editorView) {
37
39
  if (!editorView) {
38
40
  return null;
39
41
  }
40
42
  var selection = editorView.state.selection;
43
+ if (selection instanceof CellSelection) {
44
+ // $anchorCell resolves inside the row (before the cell), so
45
+ // $anchorCell.depth is the row's depth. Table is one level up.
46
+ var $cell = selection.$anchorCell;
47
+ var tableDepth = $cell.depth - 1;
48
+ if (tableDepth > 0) {
49
+ var dom = editorView.nodeDOM($cell.before(tableDepth));
50
+ if (dom instanceof HTMLElement && dom.parentElement) {
51
+ return dom.parentElement;
52
+ }
53
+ }
54
+ }
41
55
  var from = selection.from;
42
56
  var nodeDOM = editorView.nodeDOM(from);
43
57
  if (nodeDOM instanceof HTMLElement) {
44
58
  return nodeDOM.parentElement;
45
59
  }
46
- return null;
60
+ return editorView.dom || null;
47
61
  };
48
62
  var isBlockMenuAddedInMutation = function isBlockMenuAddedInMutation(_ref) {
49
63
  var type = _ref.type,
@@ -137,4 +151,29 @@ export var handleDeleteDomMutation = function handleDeleteDomMutation(_ref4) {
137
151
  };
138
152
  }
139
153
  return undefined;
154
+ };
155
+
156
+ /**
157
+ * Handles DOM mutations to determine if a transform action was performed.
158
+ *
159
+ * Transforms replace one block type with another (e.g. paragraph → heading),
160
+ * producing childList mutations with both removed (old node) and added (new node).
161
+ *
162
+ * @param options.mutations - The list of DOM mutation records
163
+ * @returns An ExperienceCheckResult indicating success if a transform was detected, otherwise undefined
164
+ */
165
+ export var handleTransformDomMutation = function handleTransformDomMutation(_ref5) {
166
+ var mutations = _ref5.mutations;
167
+ var hasRemovedNodes = mutations.some(function (m) {
168
+ return m.type === 'childList' && m.removedNodes.length > 0;
169
+ });
170
+ var hasAddedNodes = mutations.some(function (m) {
171
+ return m.type === 'childList' && m.addedNodes.length > 0;
172
+ });
173
+ if (hasRemovedNodes && hasAddedNodes) {
174
+ return {
175
+ status: 'success'
176
+ };
177
+ }
178
+ return undefined;
140
179
  };
@@ -3,5 +3,8 @@ import type { TransformStep } from './types';
3
3
  * Wraps nodes into the target container type.
4
4
  * When wrapping into expand, any expand children are converted to nestedExpand
5
5
  * since expand cannot be a direct child of expand.
6
+ *
7
+ * Preserves breakout marks when both source and target nodes support resizing
8
+ * (codeBlock, expand, layoutSection).
6
9
  */
7
10
  export declare const wrapStep: TransformStep;
@@ -19,7 +19,7 @@ export declare const isBlockMenuVisible: (popupsTarget: HTMLElement | undefined)
19
19
  * from the provided editor view.
20
20
  *
21
21
  * @param editorView - The editor view from which to get the parent DOM element
22
- * @returns The parent HTMLElement at the selection start, or null if not found
22
+ * @returns The parent HTMLElement of the block at the selection, or null if not found
23
23
  */
24
24
  export declare const getParentDOMAtSelection: (editorView?: EditorView) => HTMLElement | null;
25
25
  /**
@@ -60,3 +60,15 @@ export declare const handleMoveDomMutation: ({ mutations, }: {
60
60
  export declare const handleDeleteDomMutation: ({ mutations, }: {
61
61
  mutations: MutationRecord[];
62
62
  }) => ExperienceCheckResult | undefined;
63
+ /**
64
+ * Handles DOM mutations to determine if a transform action was performed.
65
+ *
66
+ * Transforms replace one block type with another (e.g. paragraph → heading),
67
+ * producing childList mutations with both removed (old node) and added (new node).
68
+ *
69
+ * @param options.mutations - The list of DOM mutation records
70
+ * @returns An ExperienceCheckResult indicating success if a transform was detected, otherwise undefined
71
+ */
72
+ export declare const handleTransformDomMutation: ({ mutations, }: {
73
+ mutations: MutationRecord[];
74
+ }) => ExperienceCheckResult | undefined;
@@ -3,5 +3,8 @@ import type { TransformStep } from './types';
3
3
  * Wraps nodes into the target container type.
4
4
  * When wrapping into expand, any expand children are converted to nestedExpand
5
5
  * since expand cannot be a direct child of expand.
6
+ *
7
+ * Preserves breakout marks when both source and target nodes support resizing
8
+ * (codeBlock, expand, layoutSection).
6
9
  */
7
10
  export declare const wrapStep: TransformStep;
@@ -19,7 +19,7 @@ export declare const isBlockMenuVisible: (popupsTarget: HTMLElement | undefined)
19
19
  * from the provided editor view.
20
20
  *
21
21
  * @param editorView - The editor view from which to get the parent DOM element
22
- * @returns The parent HTMLElement at the selection start, or null if not found
22
+ * @returns The parent HTMLElement of the block at the selection, or null if not found
23
23
  */
24
24
  export declare const getParentDOMAtSelection: (editorView?: EditorView) => HTMLElement | null;
25
25
  /**
@@ -60,3 +60,15 @@ export declare const handleMoveDomMutation: ({ mutations, }: {
60
60
  export declare const handleDeleteDomMutation: ({ mutations, }: {
61
61
  mutations: MutationRecord[];
62
62
  }) => ExperienceCheckResult | undefined;
63
+ /**
64
+ * Handles DOM mutations to determine if a transform action was performed.
65
+ *
66
+ * Transforms replace one block type with another (e.g. paragraph → heading),
67
+ * producing childList mutations with both removed (old node) and added (new node).
68
+ *
69
+ * @param options.mutations - The list of DOM mutation records
70
+ * @returns An ExperienceCheckResult indicating success if a transform was detected, otherwise undefined
71
+ */
72
+ export declare const handleTransformDomMutation: ({ mutations, }: {
73
+ mutations: MutationRecord[];
74
+ }) => ExperienceCheckResult | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "6.0.47",
3
+ "version": "6.0.48",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -46,13 +46,13 @@
46
46
  "@atlaskit/platform-feature-flags-react": "^0.4.0",
47
47
  "@atlaskit/primitives": "^18.0.0",
48
48
  "@atlaskit/prosemirror-history": "^0.2.0",
49
- "@atlaskit/tmp-editor-statsig": "^29.0.0",
49
+ "@atlaskit/tmp-editor-statsig": "^29.1.0",
50
50
  "@atlaskit/tokens": "^11.0.0",
51
51
  "@babel/runtime": "^7.0.0",
52
52
  "bind-event-listener": "^3.0.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@atlaskit/editor-common": "^111.16.0",
55
+ "@atlaskit/editor-common": "^111.17.0",
56
56
  "react": "^18.2.0",
57
57
  "react-intl-next": "npm:react-intl@^5.18.1"
58
58
  },
@@ -104,6 +104,9 @@
104
104
  },
105
105
  "platform_editor_table_transform_selection_fix": {
106
106
  "type": "boolean"
107
+ },
108
+ "platform_editor_preserve_breakout_on_transform": {
109
+ "type": "boolean"
107
110
  }
108
111
  }
109
112
  }