@atlaskit/editor-common 109.12.0 → 109.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cjs/ai-messages/ai-failed-state.js +45 -10
  3. package/dist/cjs/block-menu/messages.js +2 -0
  4. package/dist/cjs/block-menu/rank.js +1 -1
  5. package/dist/cjs/messages/block-controls.js +5 -0
  6. package/dist/cjs/messages/block-menu.js +20 -0
  7. package/dist/cjs/monitoring/error.js +1 -1
  8. package/dist/cjs/node-width/index.js +20 -5
  9. package/dist/cjs/ui/DropList/index.js +1 -1
  10. package/dist/cjs/utils/document.js +33 -1
  11. package/dist/es2019/ai-messages/ai-failed-state.js +45 -10
  12. package/dist/es2019/block-menu/messages.js +3 -0
  13. package/dist/es2019/block-menu/rank.js +15 -15
  14. package/dist/es2019/messages/block-controls.js +5 -0
  15. package/dist/es2019/messages/block-menu.js +20 -0
  16. package/dist/es2019/monitoring/error.js +1 -1
  17. package/dist/es2019/node-width/index.js +21 -6
  18. package/dist/es2019/ui/DropList/index.js +1 -1
  19. package/dist/es2019/utils/document.js +32 -1
  20. package/dist/esm/ai-messages/ai-failed-state.js +45 -10
  21. package/dist/esm/block-menu/messages.js +3 -0
  22. package/dist/esm/block-menu/rank.js +1 -1
  23. package/dist/esm/messages/block-controls.js +5 -0
  24. package/dist/esm/messages/block-menu.js +20 -0
  25. package/dist/esm/monitoring/error.js +1 -1
  26. package/dist/esm/node-width/index.js +21 -6
  27. package/dist/esm/ui/DropList/index.js +1 -1
  28. package/dist/esm/utils/document.js +32 -1
  29. package/dist/types/ai-messages/ai-failed-state.d.ts +45 -10
  30. package/dist/types/block-menu/rank.d.ts +6 -6
  31. package/dist/types/messages/block-controls.d.ts +5 -0
  32. package/dist/types/messages/block-menu.d.ts +20 -0
  33. package/dist/types/toolbar/EditorToolbarUIProvider.d.ts +1 -1
  34. package/dist/types/utils/document.d.ts +11 -0
  35. package/dist/types-ts4.5/ai-messages/ai-failed-state.d.ts +45 -10
  36. package/dist/types-ts4.5/block-menu/rank.d.ts +6 -6
  37. package/dist/types-ts4.5/messages/block-controls.d.ts +5 -0
  38. package/dist/types-ts4.5/messages/block-menu.d.ts +20 -0
  39. package/dist/types-ts4.5/toolbar/EditorToolbarUIProvider.d.ts +1 -1
  40. package/dist/types-ts4.5/utils/document.d.ts +11 -0
  41. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @atlaskit/editor-common
2
2
 
3
+ ## 109.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`b8555904ec1cc`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b8555904ec1cc) -
8
+ Add new util for comparing nodes ignoring attributes.
9
+
10
+ ### Patch Changes
11
+
12
+ - [`f7bc2f60e0fc6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f7bc2f60e0fc6) -
13
+ [ux] Updates copy text for drag handle, copy block, copy link and updates order of items in Turn
14
+ into menu.
15
+
16
+ ## 109.13.0
17
+
18
+ ### Minor Changes
19
+
20
+ - [`23e11d126d7c9`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/23e11d126d7c9) -
21
+ EDITOR-1312: Add new AIFC error messages.
22
+
23
+ ### Patch Changes
24
+
25
+ - [`6d186dc817ef9`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6d186dc817ef9) -
26
+ [ux] ED-26884 fix bug where resize columns for nested table results in a scrollbar
27
+ - [`407e1dc11eeed`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/407e1dc11eeed) -
28
+ Minor changes to border radius values.
29
+ - Updated dependencies
30
+
3
31
  ## 109.12.0
4
32
 
5
33
  ### Minor Changes
@@ -13,11 +13,6 @@ var aiFailedStateMessages = exports.aiFailedStateMessages = (0, _reactIntlNext.d
13
13
  defaultMessage: 'Your prompt or content might not comply with our Acceptable Use Policy. Please review both and refer to our <link>Acceptable Use Policy</link> if needed. If the problem persists, consider trying a different prompt or content.',
14
14
  description: 'Message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy. Note the markdown link -- this is expected to remain as markdown as this string is converted to html.'
15
15
  },
16
- cmdPaletteAupViolationMessage: {
17
- id: 'fabric.editor.ai.experience.cmdPaletteAupViolationMessage',
18
- defaultMessage: "We couldn’t complete that request because it doesn't comply with our <link>Acceptable Use Policy</link>.",
19
- description: 'Message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy. Note the markdown link -- this is expected to remain as markdown as this string is converted to html.'
20
- },
21
16
  documentInsertError: {
22
17
  id: 'fabric.editor.ai.experience-application.documentInsertError',
23
18
  defaultMessage: "We're having trouble inserting the response. Close the dialog and try again.",
@@ -38,11 +33,6 @@ var aiFailedStateMessages = exports.aiFailedStateMessages = (0, _reactIntlNext.d
38
33
  defaultMessage: "We couldn\u2019t get a response, please try again.",
39
34
  description: "We couldn't get a response due to an api error (ie. the backend responded with an error, or got a timeout)"
40
35
  },
41
- cmdPaletteApiError: {
42
- id: 'fabric.editor.ai.experience.cmdPaletteApiError',
43
- defaultMessage: "An error occurred while generating your response.",
44
- description: "We couldn't get a response due to an api error (ie. the backend responded with an error, or got a timeout)"
45
- },
46
36
  elevateDisabledGenerateError: {
47
37
  id: 'fabric.editor.ai.experience.elevateDisabledGenetateError',
48
38
  defaultMessage: "Free generate is disabled in Elevate at this time.",
@@ -67,5 +57,50 @@ var aiFailedStateMessages = exports.aiFailedStateMessages = (0, _reactIntlNext.d
67
57
  id: 'fabric.editor.ai.experience.adfStreamingError',
68
58
  defaultMessage: "Our apologies, we couldn't get a response.",
69
59
  description: "This error message is displayed when error(s) are encountered during processing of LLM response in ADF format."
60
+ },
61
+ aifcAupViolationMessage: {
62
+ id: 'fabric.editor.ai.experience.aifcAupViolationMessage',
63
+ defaultMessage: 'Content does not comply with our <link>Acceptable Use Policy</link>.',
64
+ description: 'Error message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy.'
65
+ },
66
+ aifcApiError: {
67
+ id: 'fabric.editor.ai.experience.aifcApiError',
68
+ defaultMessage: 'An unknown error occurred.',
69
+ description: 'Message for users when a non-retryable API error occurs.'
70
+ },
71
+ aifcApiErrorRetry: {
72
+ id: 'fabric.editor.ai.experience.aifcApiErrorRetry',
73
+ defaultMessage: 'An unknown error occurred. Please reload and try again.',
74
+ description: 'Message for users when an API error occurs'
75
+ },
76
+ aifcTokenLimitExceeded: {
77
+ id: 'fabric.editor.ai.experience.aifcTokenLimitExceeded',
78
+ defaultMessage: 'There’s too much content to process. Select less content and try again.',
79
+ description: 'Message to users that displays when their request has exceeded the maximum input or output limit.'
80
+ },
81
+ aifcInputTooShortError: {
82
+ id: 'fabric.editor.ai.experience.aifcInputTooShortError',
83
+ defaultMessage: 'More content needed to complete your request. Please select more content and try again.',
84
+ description: 'Error message when the input was too short to process.'
85
+ },
86
+ aifcHipaaContentError: {
87
+ id: 'fabric.editor.ai.experience.aifcHipaaContentError',
88
+ defaultMessage: 'Your content contains links to HIPAA restricted content. Remove links and try again.',
89
+ description: 'Error message when HIPAA links have been detected.'
90
+ },
91
+ aifcRateLimitEnforced: {
92
+ id: 'fabric.editor.ai.experience.aifcRateLimitEnforced',
93
+ defaultMessage: 'You’ve reached the <link>maximum number of requests</link>. Try again in 5 minutes.',
94
+ description: 'Message to users that rate limiting has been enforced.'
95
+ },
96
+ aifcInternalServerError: {
97
+ id: 'fabric.editor.ai.experience.aifcInternalServerError',
98
+ defaultMessage: 'Our apologies, we couldn’t get a response. Try again in 5 minutes or <link>check Rovo status</link>.',
99
+ description: 'Error message when a Rovo internal server occurs.'
100
+ },
101
+ aifcAdfStreamingError: {
102
+ id: 'fabric.editor.ai.experience.aifcAdfStreamingError',
103
+ defaultMessage: 'Our apologies, we couldn’t get a response.',
104
+ description: 'This error message is displayed when error(s) are encountered during processing of LLM response in ADF format.'
70
105
  }
71
106
  });
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.messages = void 0;
7
7
  var _reactIntlNext = require("react-intl-next");
8
+ // Do not add messages to this file
9
+ // Add them here platform/packages/editor/editor-common/src/messages/block-menu.ts instead
8
10
  var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
9
11
  copyBlock: {
10
12
  id: 'fabric.editor.block.menu.copy.block',
@@ -9,7 +9,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
9
9
  var _key = require("./key");
10
10
  var _FORMAT_NESTED_MENU_R, _FORMAT_NESTED_MENU_R2;
11
11
  var FORMAT_NESTED_MENU_RANK = exports.FORMAT_NESTED_MENU_RANK = (_FORMAT_NESTED_MENU_R = {}, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R, _key.FORMAT_HEADING_1_MENU_ITEM.key, 50), _key.FORMAT_HEADING_2_MENU_ITEM.key, 100), _key.FORMAT_HEADING_3_MENU_ITEM.key, 150), _key.FORMAT_PARAGRAPH_MENU_ITEM.key, 200), _key.FORMAT_QUOTE_MENU_ITEM.key, 250), _key.FORMAT_EXPAND_MENU_ITEM.key, 300), _key.FORMAT_LAYOUT_MENU_ITEM.key, 350), _key.FORMAT_PANEL_MENU_ITEM.key, 400), _key.FORMAT_CODE_BLOCK_MENU_ITEM.key, 450), _key.FORMAT_BULLETED_LIST_MENU_ITEM.key, 500), (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R, _key.FORMAT_NUMBERED_LIST_MENU_ITEM.key, 550), _key.FORMAT_TASK_LIST_MENU_ITEM.key, 600), _key.FORMAT_HEADING_4_MENU_ITEM.key, 650), _key.FORMAT_HEADING_5_MENU_ITEM.key, 700), _key.FORMAT_HEADING_6_MENU_ITEM.key, 750));
12
- var FORMAT_NESTED_MENU_RANK_REVISED = exports.FORMAT_NESTED_MENU_RANK_REVISED = (_FORMAT_NESTED_MENU_R2 = {}, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R2, _key.FORMAT_HEADING_1_MENU_ITEM.key, 50), _key.FORMAT_HEADING_2_MENU_ITEM.key, 100), _key.FORMAT_HEADING_3_MENU_ITEM.key, 150), _key.FORMAT_HEADING_4_MENU_ITEM.key, 200), _key.FORMAT_HEADING_5_MENU_ITEM.key, 250), _key.FORMAT_HEADING_6_MENU_ITEM.key, 300), _key.FORMAT_PARAGRAPH_MENU_ITEM.key, 350), _key.FORMAT_QUOTE_MENU_ITEM.key, 400), _key.FORMAT_EXPAND_MENU_ITEM.key, 450), _key.FORMAT_LAYOUT_MENU_ITEM.key, 500), (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R2, _key.FORMAT_PANEL_MENU_ITEM.key, 550), _key.FORMAT_CODE_BLOCK_MENU_ITEM.key, 600), _key.FORMAT_BULLETED_LIST_MENU_ITEM.key, 650), _key.FORMAT_NUMBERED_LIST_MENU_ITEM.key, 700), _key.FORMAT_TASK_LIST_MENU_ITEM.key, 750));
12
+ var FORMAT_NESTED_MENU_RANK_REVISED = exports.FORMAT_NESTED_MENU_RANK_REVISED = (_FORMAT_NESTED_MENU_R2 = {}, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R2, _key.FORMAT_PARAGRAPH_MENU_ITEM.key, 50), _key.FORMAT_QUOTE_MENU_ITEM.key, 100), _key.FORMAT_EXPAND_MENU_ITEM.key, 150), _key.FORMAT_LAYOUT_MENU_ITEM.key, 200), _key.FORMAT_PANEL_MENU_ITEM.key, 250), _key.FORMAT_CODE_BLOCK_MENU_ITEM.key, 300), _key.FORMAT_BULLETED_LIST_MENU_ITEM.key, 350), _key.FORMAT_NUMBERED_LIST_MENU_ITEM.key, 400), _key.FORMAT_TASK_LIST_MENU_ITEM.key, 450), _key.FORMAT_HEADING_1_MENU_ITEM.key, 500), (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)(_FORMAT_NESTED_MENU_R2, _key.FORMAT_HEADING_2_MENU_ITEM.key, 550), _key.FORMAT_HEADING_3_MENU_ITEM.key, 600), _key.FORMAT_HEADING_4_MENU_ITEM.key, 650), _key.FORMAT_HEADING_5_MENU_ITEM.key, 700), _key.FORMAT_HEADING_6_MENU_ITEM.key, 750));
13
13
  var BLOCK_MENU_SECTION_RANK = exports.BLOCK_MENU_SECTION_RANK = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, _key.PRIMARY_MENU_SECTION.key, 100), _key.COPY_MENU_SECTION.key, 300), _key.MOVE_UP_DOWN_MENU_SECTION.key, 400), _key.DELETE_MENU_SECTION.key, 500);
14
14
  var PRIMARY_MENU_SECTION_RANK = exports.PRIMARY_MENU_SECTION_RANK = (0, _defineProperty2.default)({}, _key.FORMAT_MENU_ITEM.key, 50);
15
15
  var COPY_MENU_SECTION_RANK = exports.COPY_MENU_SECTION_RANK = (0, _defineProperty2.default)((0, _defineProperty2.default)({}, _key.COPY_LINK_MENU_ITEM.key, 50), _key.COPY_BLOCK_MENU_ITEM.key, 100);
@@ -11,6 +11,11 @@ var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
11
11
  defaultMessage: 'Drag to move',
12
12
  description: 'Use drag handle to move content'
13
13
  },
14
+ dragToMoveClickToOpen: {
15
+ id: 'fabric.editor.blockControlDragHandleMoveOrOpen',
16
+ defaultMessage: 'Drag to move {br} Click to open menu',
17
+ description: 'Use drag handle to move content or click to open the menu'
18
+ },
14
19
  dragToRearrange: {
15
20
  id: 'fabric.editor.blockControlDragHandleRearrange',
16
21
  defaultMessage: 'Drag to rearrange',
@@ -11,6 +11,11 @@ var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
11
11
  defaultMessage: 'Copy block',
12
12
  description: 'Copy the selected block to the clipboard'
13
13
  },
14
+ copyContent: {
15
+ id: 'fabric.editor.block.menu.copy.content',
16
+ defaultMessage: 'Copy content',
17
+ description: 'Copy the selected content to the clipboard'
18
+ },
14
19
  moveUpBlock: {
15
20
  id: 'fabric.editor.block.menu.move.up',
16
21
  defaultMessage: 'Move up',
@@ -26,6 +31,11 @@ var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
26
31
  defaultMessage: 'Copy link',
27
32
  description: 'Copy link to the selected block'
28
33
  },
34
+ copyLinkToBlock: {
35
+ id: 'fabric.editor.block.menu.copy.link.to.block',
36
+ defaultMessage: 'Copy link to block',
37
+ description: 'Copy link to the selected block'
38
+ },
29
39
  paragraph: {
30
40
  id: 'fabric.editor.block.menu.paragraph',
31
41
  defaultMessage: 'Paragraph',
@@ -40,5 +50,15 @@ var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
40
50
  id: 'fabric.editor.block.menu.layout',
41
51
  defaultMessage: 'Layout',
42
52
  description: 'Convert to a layout node'
53
+ },
54
+ deleteBlock: {
55
+ id: 'fabric.editor.block.menu.delete.block',
56
+ defaultMessage: 'Delete',
57
+ description: 'Delete the selected block'
58
+ },
59
+ turnInto: {
60
+ id: 'fabric.editor.block.menu.turn.into',
61
+ defaultMessage: 'Turn into',
62
+ description: 'Turn the selected block into another type'
43
63
  }
44
64
  });
@@ -16,7 +16,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
16
16
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
17
17
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
18
18
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
19
- var packageVersion = "109.11.4";
19
+ var packageVersion = "109.13.0";
20
20
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
21
21
  // Remove URL as it has UGC
22
22
  // Ignored via go/ees007
@@ -6,11 +6,15 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.layoutToWidth = exports.getTableWidthWithNumberColumn = exports.getTableContainerWidth = exports.getParentNodeWidth = void 0;
7
7
  var _utils = require("@atlaskit/editor-prosemirror/utils");
8
8
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
9
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
9
11
  var _extension = require("../styles/shared/extension");
10
12
  var _layout = require("../styles/shared/layout");
11
13
  var _table = require("../styles/shared/table");
12
14
  var _breakout = require("../utils/breakout");
13
15
  var GRID_SIZE = 8;
16
+ var NESTED_DND_GUTTER_OFFSET = 8;
17
+ var NESTED_DND_MARGIN_OFFSET = 12;
14
18
  var layoutToWidth = exports.layoutToWidth = {
15
19
  // eslint-disable-next-line @atlaskit/editor/no-re-export
16
20
  default: _editorSharedStyles.akEditorDefaultLayoutWidth,
@@ -39,7 +43,8 @@ var getParentNodeWidth = exports.getParentNodeWidth = function getParentNodeWidt
39
43
  if (breakoutMark && breakoutMark.attrs.mode) {
40
44
  layout = breakoutMark.attrs.mode;
41
45
  }
42
- var parentWidth = calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled);
46
+ var breakoutWidth = breakoutMark ? breakoutMark.attrs.width : undefined;
47
+ var parentWidth = calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled, breakoutWidth);
43
48
 
44
49
  // Please, do not copy or use this kind of code below
45
50
  // @ts-ignore
@@ -53,13 +58,17 @@ var getParentNodeWidth = exports.getParentNodeWidth = function getParentNodeWidt
53
58
  };
54
59
  switch (node.type) {
55
60
  case schema.nodes.layoutSection:
56
- parentWidth += _editorSharedStyles.akLayoutGutterOffset * 2; // extra width that gets added to layout
61
+ // the extra width of the layout does not add to the width of the area the table can be inside
62
+ if (!(0, _expValEquals.expValEquals)('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true)) {
63
+ parentWidth += _editorSharedStyles.akLayoutGutterOffset * 2; // extra width that gets added to layout
64
+ }
57
65
 
58
66
  // Calculate width of parent layout column when
59
67
  // Parallel layout with viewport greater than 1024px
60
68
  // OR side panel of an extension is open and change the node width to smaller than containerWidth
61
69
  if (containerWidth.width > _editorSharedStyles.gridMediumMaxWidth || ((_contextPanelPluginKe = contextPanelPluginKey.getState(state)) === null || _contextPanelPluginKe === void 0 ? void 0 : _contextPanelPluginKe.contents.length) > 0 && ((_contextPanelPluginKe2 = contextPanelPluginKey.getState(state)) === null || _contextPanelPluginKe2 === void 0 ? void 0 : _contextPanelPluginKe2.contents[0]) !== undefined) {
62
- parentWidth -= (_layout.LAYOUT_SECTION_MARGIN + 2) * (node.childCount - 1); // margin between sections
70
+ // margin between sections
71
+ parentWidth -= (0, _expValEquals.expValEquals)('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true) && (0, _platformFeatureFlags.fg)('platform_editor_nested_dnd_styles_changes') ? (_layout.LAYOUT_SECTION_MARGIN + NESTED_DND_MARGIN_OFFSET + 2) * (node.childCount - 1) : (_layout.LAYOUT_SECTION_MARGIN + 2) * (node.childCount - 1);
63
72
  var $pos = state.doc.resolve(pos);
64
73
  var column = (0, _utils.findParentNodeOfTypeClosestToPos)($pos, [state.schema.nodes.layoutColumn]);
65
74
  if (column && column.node && !isNaN(column.node.attrs.width)) {
@@ -69,7 +78,7 @@ var getParentNodeWidth = exports.getParentNodeWidth = function getParentNodeWidt
69
78
  }
70
79
 
71
80
  // account for the padding of the parent node
72
- parentWidth -= _layout.LAYOUT_COLUMN_PADDING * 2;
81
+ parentWidth -= (0, _expValEquals.expValEquals)('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true) && (0, _platformFeatureFlags.fg)('platform_editor_nested_dnd_styles_changes') ? (_layout.LAYOUT_COLUMN_PADDING + NESTED_DND_GUTTER_OFFSET) * 2 : _layout.LAYOUT_COLUMN_PADDING * 2;
73
82
  break;
74
83
  case schema.nodes.bodiedExtension:
75
84
  parentWidth -= _extension.BODIED_EXT_PADDING * 2;
@@ -111,7 +120,13 @@ var getNestedParentNode = function getNestedParentNode(tablePos, state) {
111
120
  var parent = (0, _utils.findParentNodeOfTypeClosestToPos)($pos, [state.schema.nodes.bodiedExtension, state.schema.nodes.extensionFrame, state.schema.nodes.layoutSection, state.schema.nodes.expand, state.schema.nodes.tableCell, state.schema.nodes.tableHeader]);
112
121
  return parent ? parent.node : null;
113
122
  };
114
- var calcBreakoutNodeWidth = function calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled) {
123
+ var calcBreakoutNodeWidth = function calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled, breakoutWidth) {
124
+ if (breakoutWidth && (0, _expValEquals.expValEquals)('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true)) {
125
+ return isFullWidthModeEnabled ? Math.min(containerWidth.lineLength, breakoutWidth) :
126
+ // container width minus breakout padding
127
+ // --ak-editor--breakout-full-page-guttering-padding = (--ak-editor--large-gutter-padding * 2) + --ak-editor--default-gutter-padding
128
+ Math.min(containerWidth.width - ((0, _editorSharedStyles.akEditorGutterPaddingDynamic)() * 2 + _editorSharedStyles.akEditorGutterPadding), breakoutWidth);
129
+ }
115
130
  return isFullWidthModeEnabled ? Math.min(containerWidth.lineLength, _editorSharedStyles.akEditorFullWidthLayoutWidth) : (0, _breakout.absoluteBreakoutWidth)(layout, containerWidth.width);
116
131
  };
117
132
  var getTableContainerWidth = exports.getTableContainerWidth = function getTableContainerWidth(node) {
@@ -24,7 +24,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
24
24
  * @jsx jsx
25
25
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
26
26
  var packageName = "@atlaskit/editor-common";
27
- var packageVersion = "109.11.4";
27
+ var packageVersion = "109.13.0";
28
28
  var halfFocusRing = 1;
29
29
  var dropOffset = '0, 8';
30
30
  var fadeIn = (0, _react2.keyframes)({
@@ -4,6 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
+ exports.areNodesEqualIgnoreAttrs = areNodesEqualIgnoreAttrs;
7
8
  exports.bracketTyped = bracketTyped;
8
9
  exports.getChangedNodes = getChangedNodes;
9
10
  exports.getStepRange = void 0;
@@ -157,4 +158,35 @@ var isReplaceDocOperation = exports.isReplaceDocOperation = function isReplaceDo
157
158
  });
158
159
  return hasStepReplacingEntireDocument;
159
160
  });
160
- };
161
+ };
162
+
163
+ /**
164
+ * Compares two ProseMirror documents for equality, ignoring attributes
165
+ * which don't affect the document structure.
166
+ *
167
+ * This is almost a copy of the .eq() PM function - tweaked to ignore attrs
168
+ *
169
+ * @param doc1 PMNode
170
+ * @param doc2 PMNode
171
+ * @returns boolean
172
+ */
173
+ function areNodesEqualIgnoreAttrs(node1, node2) {
174
+ if (node1.isText) {
175
+ return node1.eq(node2);
176
+ }
177
+ return node1 === node2 || node1.hasMarkup(node2.type, node1.attrs, node2.marks) && areFragmentsEqual(node1.content, node2.content);
178
+ }
179
+ function areFragmentsEqual(frag1, frag2) {
180
+ if (frag1.content.length !== frag2.content.length) {
181
+ return false;
182
+ }
183
+ var childrenEqual = true;
184
+ frag1.content.forEach(function (child, i) {
185
+ var otherChild = frag2.child(i);
186
+ if (child === otherChild || otherChild && areNodesEqualIgnoreAttrs(child, otherChild)) {
187
+ return;
188
+ }
189
+ childrenEqual = false;
190
+ });
191
+ return childrenEqual;
192
+ }
@@ -6,11 +6,6 @@ export const aiFailedStateMessages = defineMessages({
6
6
  defaultMessage: 'Your prompt or content might not comply with our Acceptable Use Policy. Please review both and refer to our <link>Acceptable Use Policy</link> if needed. If the problem persists, consider trying a different prompt or content.',
7
7
  description: 'Message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy. Note the markdown link -- this is expected to remain as markdown as this string is converted to html.'
8
8
  },
9
- cmdPaletteAupViolationMessage: {
10
- id: 'fabric.editor.ai.experience.cmdPaletteAupViolationMessage',
11
- defaultMessage: "We couldn’t complete that request because it doesn't comply with our <link>Acceptable Use Policy</link>.",
12
- description: 'Message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy. Note the markdown link -- this is expected to remain as markdown as this string is converted to html.'
13
- },
14
9
  documentInsertError: {
15
10
  id: 'fabric.editor.ai.experience-application.documentInsertError',
16
11
  defaultMessage: `We're having trouble inserting the response. Close the dialog and try again.`,
@@ -31,11 +26,6 @@ export const aiFailedStateMessages = defineMessages({
31
26
  defaultMessage: `We couldn’t get a response, please try again.`,
32
27
  description: `We couldn't get a response due to an api error (ie. the backend responded with an error, or got a timeout)`
33
28
  },
34
- cmdPaletteApiError: {
35
- id: 'fabric.editor.ai.experience.cmdPaletteApiError',
36
- defaultMessage: `An error occurred while generating your response.`,
37
- description: `We couldn't get a response due to an api error (ie. the backend responded with an error, or got a timeout)`
38
- },
39
29
  elevateDisabledGenerateError: {
40
30
  id: 'fabric.editor.ai.experience.elevateDisabledGenetateError',
41
31
  defaultMessage: `Free generate is disabled in Elevate at this time.`,
@@ -60,5 +50,50 @@ export const aiFailedStateMessages = defineMessages({
60
50
  id: 'fabric.editor.ai.experience.adfStreamingError',
61
51
  defaultMessage: `Our apologies, we couldn't get a response.`,
62
52
  description: `This error message is displayed when error(s) are encountered during processing of LLM response in ADF format.`
53
+ },
54
+ aifcAupViolationMessage: {
55
+ id: 'fabric.editor.ai.experience.aifcAupViolationMessage',
56
+ defaultMessage: 'Content does not comply with our <link>Acceptable Use Policy</link>.',
57
+ description: 'Error message to indicate to user their prompt or content (this can be a range of content, such as a selection or document -- we used content to keep it vague -- as this will change without user knowing) has been detected as violating Atlassians acceptable use policy.'
58
+ },
59
+ aifcApiError: {
60
+ id: 'fabric.editor.ai.experience.aifcApiError',
61
+ defaultMessage: 'An unknown error occurred.',
62
+ description: 'Message for users when a non-retryable API error occurs.'
63
+ },
64
+ aifcApiErrorRetry: {
65
+ id: 'fabric.editor.ai.experience.aifcApiErrorRetry',
66
+ defaultMessage: 'An unknown error occurred. Please reload and try again.',
67
+ description: 'Message for users when an API error occurs'
68
+ },
69
+ aifcTokenLimitExceeded: {
70
+ id: 'fabric.editor.ai.experience.aifcTokenLimitExceeded',
71
+ defaultMessage: 'There’s too much content to process. Select less content and try again.',
72
+ description: 'Message to users that displays when their request has exceeded the maximum input or output limit.'
73
+ },
74
+ aifcInputTooShortError: {
75
+ id: 'fabric.editor.ai.experience.aifcInputTooShortError',
76
+ defaultMessage: 'More content needed to complete your request. Please select more content and try again.',
77
+ description: 'Error message when the input was too short to process.'
78
+ },
79
+ aifcHipaaContentError: {
80
+ id: 'fabric.editor.ai.experience.aifcHipaaContentError',
81
+ defaultMessage: 'Your content contains links to HIPAA restricted content. Remove links and try again.',
82
+ description: 'Error message when HIPAA links have been detected.'
83
+ },
84
+ aifcRateLimitEnforced: {
85
+ id: 'fabric.editor.ai.experience.aifcRateLimitEnforced',
86
+ defaultMessage: 'You’ve reached the <link>maximum number of requests</link>. Try again in 5 minutes.',
87
+ description: 'Message to users that rate limiting has been enforced.'
88
+ },
89
+ aifcInternalServerError: {
90
+ id: 'fabric.editor.ai.experience.aifcInternalServerError',
91
+ defaultMessage: 'Our apologies, we couldn’t get a response. Try again in 5 minutes or <link>check Rovo status</link>.',
92
+ description: 'Error message when a Rovo internal server occurs.'
93
+ },
94
+ aifcAdfStreamingError: {
95
+ id: 'fabric.editor.ai.experience.aifcAdfStreamingError',
96
+ defaultMessage: 'Our apologies, we couldn’t get a response.',
97
+ description: 'This error message is displayed when error(s) are encountered during processing of LLM response in ADF format.'
63
98
  }
64
99
  });
@@ -1,4 +1,7 @@
1
1
  import { defineMessages } from 'react-intl-next';
2
+
3
+ // Do not add messages to this file
4
+ // Add them here platform/packages/editor/editor-common/src/messages/block-menu.ts instead
2
5
  export const messages = defineMessages({
3
6
  copyBlock: {
4
7
  id: 'fabric.editor.block.menu.copy.block',
@@ -17,21 +17,21 @@ export const FORMAT_NESTED_MENU_RANK = {
17
17
  [FORMAT_HEADING_6_MENU_ITEM.key]: 750
18
18
  };
19
19
  export const FORMAT_NESTED_MENU_RANK_REVISED = {
20
- [FORMAT_HEADING_1_MENU_ITEM.key]: 50,
21
- [FORMAT_HEADING_2_MENU_ITEM.key]: 100,
22
- [FORMAT_HEADING_3_MENU_ITEM.key]: 150,
23
- [FORMAT_HEADING_4_MENU_ITEM.key]: 200,
24
- [FORMAT_HEADING_5_MENU_ITEM.key]: 250,
25
- [FORMAT_HEADING_6_MENU_ITEM.key]: 300,
26
- [FORMAT_PARAGRAPH_MENU_ITEM.key]: 350,
27
- [FORMAT_QUOTE_MENU_ITEM.key]: 400,
28
- [FORMAT_EXPAND_MENU_ITEM.key]: 450,
29
- [FORMAT_LAYOUT_MENU_ITEM.key]: 500,
30
- [FORMAT_PANEL_MENU_ITEM.key]: 550,
31
- [FORMAT_CODE_BLOCK_MENU_ITEM.key]: 600,
32
- [FORMAT_BULLETED_LIST_MENU_ITEM.key]: 650,
33
- [FORMAT_NUMBERED_LIST_MENU_ITEM.key]: 700,
34
- [FORMAT_TASK_LIST_MENU_ITEM.key]: 750
20
+ [FORMAT_PARAGRAPH_MENU_ITEM.key]: 50,
21
+ [FORMAT_QUOTE_MENU_ITEM.key]: 100,
22
+ [FORMAT_EXPAND_MENU_ITEM.key]: 150,
23
+ [FORMAT_LAYOUT_MENU_ITEM.key]: 200,
24
+ [FORMAT_PANEL_MENU_ITEM.key]: 250,
25
+ [FORMAT_CODE_BLOCK_MENU_ITEM.key]: 300,
26
+ [FORMAT_BULLETED_LIST_MENU_ITEM.key]: 350,
27
+ [FORMAT_NUMBERED_LIST_MENU_ITEM.key]: 400,
28
+ [FORMAT_TASK_LIST_MENU_ITEM.key]: 450,
29
+ [FORMAT_HEADING_1_MENU_ITEM.key]: 500,
30
+ [FORMAT_HEADING_2_MENU_ITEM.key]: 550,
31
+ [FORMAT_HEADING_3_MENU_ITEM.key]: 600,
32
+ [FORMAT_HEADING_4_MENU_ITEM.key]: 650,
33
+ [FORMAT_HEADING_5_MENU_ITEM.key]: 700,
34
+ [FORMAT_HEADING_6_MENU_ITEM.key]: 750
35
35
  };
36
36
  export const BLOCK_MENU_SECTION_RANK = {
37
37
  [PRIMARY_MENU_SECTION.key]: 100,
@@ -5,6 +5,11 @@ export const messages = defineMessages({
5
5
  defaultMessage: 'Drag to move',
6
6
  description: 'Use drag handle to move content'
7
7
  },
8
+ dragToMoveClickToOpen: {
9
+ id: 'fabric.editor.blockControlDragHandleMoveOrOpen',
10
+ defaultMessage: 'Drag to move {br} Click to open menu',
11
+ description: 'Use drag handle to move content or click to open the menu'
12
+ },
8
13
  dragToRearrange: {
9
14
  id: 'fabric.editor.blockControlDragHandleRearrange',
10
15
  defaultMessage: 'Drag to rearrange',
@@ -5,6 +5,11 @@ export const messages = defineMessages({
5
5
  defaultMessage: 'Copy block',
6
6
  description: 'Copy the selected block to the clipboard'
7
7
  },
8
+ copyContent: {
9
+ id: 'fabric.editor.block.menu.copy.content',
10
+ defaultMessage: 'Copy content',
11
+ description: 'Copy the selected content to the clipboard'
12
+ },
8
13
  moveUpBlock: {
9
14
  id: 'fabric.editor.block.menu.move.up',
10
15
  defaultMessage: 'Move up',
@@ -20,6 +25,11 @@ export const messages = defineMessages({
20
25
  defaultMessage: 'Copy link',
21
26
  description: 'Copy link to the selected block'
22
27
  },
28
+ copyLinkToBlock: {
29
+ id: 'fabric.editor.block.menu.copy.link.to.block',
30
+ defaultMessage: 'Copy link to block',
31
+ description: 'Copy link to the selected block'
32
+ },
23
33
  paragraph: {
24
34
  id: 'fabric.editor.block.menu.paragraph',
25
35
  defaultMessage: 'Paragraph',
@@ -34,5 +44,15 @@ export const messages = defineMessages({
34
44
  id: 'fabric.editor.block.menu.layout',
35
45
  defaultMessage: 'Layout',
36
46
  description: 'Convert to a layout node'
47
+ },
48
+ deleteBlock: {
49
+ id: 'fabric.editor.block.menu.delete.block',
50
+ defaultMessage: 'Delete',
51
+ description: 'Delete the selected block'
52
+ },
53
+ turnInto: {
54
+ id: 'fabric.editor.block.menu.turn.into',
55
+ defaultMessage: 'Turn into',
56
+ description: 'Turn the selected block into another type'
37
57
  }
38
58
  });
@@ -1,7 +1,7 @@
1
1
  import { isFedRamp } from './environment';
2
2
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
3
3
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
4
- const packageVersion = "109.11.4";
4
+ const packageVersion = "109.13.0";
5
5
  const sanitiseSentryEvents = (data, _hint) => {
6
6
  // Remove URL as it has UGC
7
7
  // Ignored via go/ees007
@@ -1,10 +1,14 @@
1
1
  import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
2
- import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorWideLayoutWidth, akLayoutGutterOffset, gridMediumMaxWidth } from '@atlaskit/editor-shared-styles';
2
+ import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorGutterPaddingDynamic, akEditorWideLayoutWidth, akLayoutGutterOffset, gridMediumMaxWidth } from '@atlaskit/editor-shared-styles';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
5
  import { BODIED_EXT_PADDING } from '../styles/shared/extension';
4
6
  import { LAYOUT_COLUMN_PADDING, LAYOUT_SECTION_MARGIN } from '../styles/shared/layout';
5
7
  import { tableCellPadding } from '../styles/shared/table';
6
8
  import { absoluteBreakoutWidth } from '../utils/breakout';
7
9
  const GRID_SIZE = 8;
10
+ const NESTED_DND_GUTTER_OFFSET = 8;
11
+ const NESTED_DND_MARGIN_OFFSET = 12;
8
12
  export const layoutToWidth = {
9
13
  // eslint-disable-next-line @atlaskit/editor/no-re-export
10
14
  default: akEditorDefaultLayoutWidth,
@@ -35,7 +39,8 @@ export const getParentNodeWidth = (pos, state, containerWidth, isFullWidthModeEn
35
39
  if (breakoutMark && breakoutMark.attrs.mode) {
36
40
  layout = breakoutMark.attrs.mode;
37
41
  }
38
- let parentWidth = calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled);
42
+ const breakoutWidth = breakoutMark ? breakoutMark.attrs.width : undefined;
43
+ let parentWidth = calcBreakoutNodeWidth(layout, containerWidth, isFullWidthModeEnabled, breakoutWidth);
39
44
 
40
45
  // Please, do not copy or use this kind of code below
41
46
  // @ts-ignore
@@ -49,13 +54,17 @@ export const getParentNodeWidth = (pos, state, containerWidth, isFullWidthModeEn
49
54
  };
50
55
  switch (node.type) {
51
56
  case schema.nodes.layoutSection:
52
- parentWidth += akLayoutGutterOffset * 2; // extra width that gets added to layout
57
+ // the extra width of the layout does not add to the width of the area the table can be inside
58
+ if (!expValEquals('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true)) {
59
+ parentWidth += akLayoutGutterOffset * 2; // extra width that gets added to layout
60
+ }
53
61
 
54
62
  // Calculate width of parent layout column when
55
63
  // Parallel layout with viewport greater than 1024px
56
64
  // OR side panel of an extension is open and change the node width to smaller than containerWidth
57
65
  if (containerWidth.width > gridMediumMaxWidth || ((_contextPanelPluginKe = contextPanelPluginKey.getState(state)) === null || _contextPanelPluginKe === void 0 ? void 0 : _contextPanelPluginKe.contents.length) > 0 && ((_contextPanelPluginKe2 = contextPanelPluginKey.getState(state)) === null || _contextPanelPluginKe2 === void 0 ? void 0 : _contextPanelPluginKe2.contents[0]) !== undefined) {
58
- parentWidth -= (LAYOUT_SECTION_MARGIN + 2) * (node.childCount - 1); // margin between sections
66
+ // margin between sections
67
+ parentWidth -= expValEquals('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true) && fg('platform_editor_nested_dnd_styles_changes') ? (LAYOUT_SECTION_MARGIN + NESTED_DND_MARGIN_OFFSET + 2) * (node.childCount - 1) : (LAYOUT_SECTION_MARGIN + 2) * (node.childCount - 1);
59
68
  const $pos = state.doc.resolve(pos);
60
69
  const column = findParentNodeOfTypeClosestToPos($pos, [state.schema.nodes.layoutColumn]);
61
70
  if (column && column.node && !isNaN(column.node.attrs.width)) {
@@ -65,7 +74,7 @@ export const getParentNodeWidth = (pos, state, containerWidth, isFullWidthModeEn
65
74
  }
66
75
 
67
76
  // account for the padding of the parent node
68
- parentWidth -= LAYOUT_COLUMN_PADDING * 2;
77
+ parentWidth -= expValEquals('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true) && fg('platform_editor_nested_dnd_styles_changes') ? (LAYOUT_COLUMN_PADDING + NESTED_DND_GUTTER_OFFSET) * 2 : LAYOUT_COLUMN_PADDING * 2;
69
78
  break;
70
79
  case schema.nodes.bodiedExtension:
71
80
  parentWidth -= BODIED_EXT_PADDING * 2;
@@ -105,7 +114,13 @@ const getNestedParentNode = (tablePos, state) => {
105
114
  const parent = findParentNodeOfTypeClosestToPos($pos, [state.schema.nodes.bodiedExtension, state.schema.nodes.extensionFrame, state.schema.nodes.layoutSection, state.schema.nodes.expand, state.schema.nodes.tableCell, state.schema.nodes.tableHeader]);
106
115
  return parent ? parent.node : null;
107
116
  };
108
- const calcBreakoutNodeWidth = (layout, containerWidth, isFullWidthModeEnabled) => {
117
+ const calcBreakoutNodeWidth = (layout, containerWidth, isFullWidthModeEnabled, breakoutWidth) => {
118
+ if (breakoutWidth && expValEquals('platform_editor_nested_table_refresh_width_fix', 'isEnabled', true)) {
119
+ return isFullWidthModeEnabled ? Math.min(containerWidth.lineLength, breakoutWidth) :
120
+ // container width minus breakout padding
121
+ // --ak-editor--breakout-full-page-guttering-padding = (--ak-editor--large-gutter-padding * 2) + --ak-editor--default-gutter-padding
122
+ Math.min(containerWidth.width - (akEditorGutterPaddingDynamic() * 2 + akEditorGutterPadding), breakoutWidth);
123
+ }
109
124
  return isFullWidthModeEnabled ? Math.min(containerWidth.lineLength, akEditorFullWidthLayoutWidth) : absoluteBreakoutWidth(layout, containerWidth.width);
110
125
  };
111
126
  export const getTableContainerWidth = node => {
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
15
  import Layer from '../Layer';
16
16
  const packageName = "@atlaskit/editor-common";
17
- const packageVersion = "109.11.4";
17
+ const packageVersion = "109.13.0";
18
18
  const halfFocusRing = 1;
19
19
  const dropOffset = '0, 8';
20
20
  const fadeIn = keyframes({
@@ -145,4 +145,35 @@ export const isReplaceDocOperation = (transactions, oldState) => {
145
145
  });
146
146
  return hasStepReplacingEntireDocument;
147
147
  });
148
- };
148
+ };
149
+
150
+ /**
151
+ * Compares two ProseMirror documents for equality, ignoring attributes
152
+ * which don't affect the document structure.
153
+ *
154
+ * This is almost a copy of the .eq() PM function - tweaked to ignore attrs
155
+ *
156
+ * @param doc1 PMNode
157
+ * @param doc2 PMNode
158
+ * @returns boolean
159
+ */
160
+ export function areNodesEqualIgnoreAttrs(node1, node2) {
161
+ if (node1.isText) {
162
+ return node1.eq(node2);
163
+ }
164
+ return node1 === node2 || node1.hasMarkup(node2.type, node1.attrs, node2.marks) && areFragmentsEqual(node1.content, node2.content);
165
+ }
166
+ function areFragmentsEqual(frag1, frag2) {
167
+ if (frag1.content.length !== frag2.content.length) {
168
+ return false;
169
+ }
170
+ let childrenEqual = true;
171
+ frag1.content.forEach((child, i) => {
172
+ const otherChild = frag2.child(i);
173
+ if (child === otherChild || otherChild && areNodesEqualIgnoreAttrs(child, otherChild)) {
174
+ return;
175
+ }
176
+ childrenEqual = false;
177
+ });
178
+ return childrenEqual;
179
+ }