@atlaskit/editor-plugin-synced-block 5.2.1 → 5.3.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 (76) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/afm-jira/tsconfig.json +1 -1
  3. package/dist/cjs/editor-commands/index.js +43 -5
  4. package/dist/cjs/editor-commands/utils.js +20 -0
  5. package/dist/cjs/pm-plugins/menu-and-toolbar-experiences.js +267 -0
  6. package/dist/cjs/syncedBlockPlugin.js +21 -12
  7. package/dist/cjs/types/index.js +6 -3
  8. package/dist/cjs/ui/CreateSyncedBlockButton.js +2 -1
  9. package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +2 -1
  10. package/dist/cjs/ui/SyncBlockRefresher.js +18 -4
  11. package/dist/cjs/ui/SyncedLocationDropdown.js +14 -11
  12. package/dist/cjs/ui/floating-toolbar.js +21 -2
  13. package/dist/es2019/editor-commands/index.js +44 -4
  14. package/dist/es2019/editor-commands/utils.js +14 -0
  15. package/dist/es2019/pm-plugins/menu-and-toolbar-experiences.js +261 -0
  16. package/dist/es2019/syncedBlockPlugin.js +19 -12
  17. package/dist/es2019/types/index.js +5 -2
  18. package/dist/es2019/ui/CreateSyncedBlockButton.js +2 -1
  19. package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +2 -1
  20. package/dist/es2019/ui/SyncBlockRefresher.js +18 -4
  21. package/dist/es2019/ui/SyncedLocationDropdown.js +14 -11
  22. package/dist/es2019/ui/floating-toolbar.js +20 -3
  23. package/dist/esm/editor-commands/index.js +42 -4
  24. package/dist/esm/editor-commands/utils.js +14 -0
  25. package/dist/esm/pm-plugins/menu-and-toolbar-experiences.js +260 -0
  26. package/dist/esm/syncedBlockPlugin.js +21 -12
  27. package/dist/esm/types/index.js +5 -2
  28. package/dist/esm/ui/CreateSyncedBlockButton.js +2 -1
  29. package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +2 -1
  30. package/dist/esm/ui/SyncBlockRefresher.js +18 -4
  31. package/dist/esm/ui/SyncedLocationDropdown.js +14 -11
  32. package/dist/esm/ui/floating-toolbar.js +22 -3
  33. package/dist/types/editor-commands/index.d.ts +8 -1
  34. package/dist/types/editor-commands/utils.d.ts +2 -0
  35. package/dist/types/pm-plugins/menu-and-toolbar-experiences.d.ts +12 -0
  36. package/dist/types/types/index.d.ts +5 -14
  37. package/dist/types-ts4.5/editor-commands/index.d.ts +8 -1
  38. package/dist/types-ts4.5/editor-commands/utils.d.ts +2 -0
  39. package/dist/types-ts4.5/pm-plugins/menu-and-toolbar-experiences.d.ts +12 -0
  40. package/dist/types-ts4.5/types/index.d.ts +5 -14
  41. package/package.json +3 -3
  42. package/dist/cjs/pm-plugins/experience-tracking/create-reference-experience.js +0 -113
  43. package/dist/cjs/pm-plugins/experience-tracking/create-source-experience.js +0 -169
  44. package/dist/cjs/pm-plugins/experience-tracking/delete-reference-experience.js +0 -175
  45. package/dist/cjs/pm-plugins/experience-tracking/delete-source-experience.js +0 -103
  46. package/dist/cjs/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -61
  47. package/dist/cjs/pm-plugins/experience-tracking/provider-only-experiences.js +0 -128
  48. package/dist/cjs/pm-plugins/utils/experience-tracking-utils.js +0 -85
  49. package/dist/es2019/pm-plugins/experience-tracking/create-reference-experience.js +0 -109
  50. package/dist/es2019/pm-plugins/experience-tracking/create-source-experience.js +0 -166
  51. package/dist/es2019/pm-plugins/experience-tracking/delete-reference-experience.js +0 -181
  52. package/dist/es2019/pm-plugins/experience-tracking/delete-source-experience.js +0 -98
  53. package/dist/es2019/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -46
  54. package/dist/es2019/pm-plugins/experience-tracking/provider-only-experiences.js +0 -127
  55. package/dist/es2019/pm-plugins/utils/experience-tracking-utils.js +0 -65
  56. package/dist/esm/pm-plugins/experience-tracking/create-reference-experience.js +0 -107
  57. package/dist/esm/pm-plugins/experience-tracking/create-source-experience.js +0 -163
  58. package/dist/esm/pm-plugins/experience-tracking/delete-reference-experience.js +0 -169
  59. package/dist/esm/pm-plugins/experience-tracking/delete-source-experience.js +0 -97
  60. package/dist/esm/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -55
  61. package/dist/esm/pm-plugins/experience-tracking/provider-only-experiences.js +0 -122
  62. package/dist/esm/pm-plugins/utils/experience-tracking-utils.js +0 -79
  63. package/dist/types/pm-plugins/experience-tracking/create-reference-experience.d.ts +0 -10
  64. package/dist/types/pm-plugins/experience-tracking/create-source-experience.d.ts +0 -10
  65. package/dist/types/pm-plugins/experience-tracking/delete-reference-experience.d.ts +0 -13
  66. package/dist/types/pm-plugins/experience-tracking/delete-source-experience.d.ts +0 -12
  67. package/dist/types/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +0 -5
  68. package/dist/types/pm-plugins/experience-tracking/provider-only-experiences.d.ts +0 -3
  69. package/dist/types/pm-plugins/utils/experience-tracking-utils.d.ts +0 -9
  70. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-reference-experience.d.ts +0 -10
  71. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-source-experience.d.ts +0 -10
  72. package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-reference-experience.d.ts +0 -13
  73. package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-source-experience.d.ts +0 -12
  74. package/dist/types-ts4.5/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +0 -5
  75. package/dist/types-ts4.5/pm-plugins/experience-tracking/provider-only-experiences.d.ts +0 -3
  76. package/dist/types-ts4.5/pm-plugins/utils/experience-tracking-utils.d.ts +0 -9
@@ -1,14 +1,17 @@
1
1
  import React from 'react';
2
2
  import commonMessages, { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
3
+ import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
3
4
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
4
5
  import { akEditorSelectedNodeClassName } from '@atlaskit/editor-shared-styles/consts';
5
6
  import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
6
7
  import CopyIcon from '@atlaskit/icon/core/copy';
7
8
  import DeleteIcon from '@atlaskit/icon/core/delete';
8
9
  import EditIcon from '@atlaskit/icon/core/edit';
10
+ import LinkBrokenIcon from '@atlaskit/icon/core/link-broken';
9
11
  import { fg } from '@atlaskit/platform-feature-flags';
10
- import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../editor-commands';
12
+ import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock, unsync } from '../editor-commands';
11
13
  import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
14
+ import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
12
15
  import { SyncedLocationDropdown } from './SyncedLocationDropdown';
13
16
  export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
14
17
  var _api$decorations, _api$connectivity, _api$connectivity$sha;
@@ -49,7 +52,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
49
52
  title: formatMessage(commonMessages.delete),
50
53
  onClick: removeSyncedBlock(api),
51
54
  icon: DeleteIcon,
52
- testId: fg('platform_synced_block_dogfooding') ? 'reference-synced-block-delete-button' : undefined,
55
+ testId: fg('platform_synced_block_dogfooding') ? SYNCED_BLOCK_BUTTON_TEST_ID.syncedBlockToolbarReferenceDelete : undefined,
53
56
  ...hoverDecorationProps(nodeType, akEditorSelectedNodeClassName)
54
57
  };
55
58
  items.push(deleteButton);
@@ -68,7 +71,21 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
68
71
  });
69
72
  }
70
73
  };
71
- items.push(syncedLocation);
74
+ const unsyncButton = {
75
+ type: 'custom',
76
+ fallback: [],
77
+ render: view => {
78
+ return /*#__PURE__*/React.createElement(Button, {
79
+ areAnyNewToolbarFlagsEnabled: true,
80
+ icon: /*#__PURE__*/React.createElement(LinkBrokenIcon, {
81
+ label: ""
82
+ }),
83
+ title: formatMessage(messages.unsyncButton),
84
+ onClick: () => unsync(syncBlockStore, isBodiedSyncBlock, view)
85
+ });
86
+ }
87
+ };
88
+ items.push(syncedLocation, unsyncButton);
72
89
  }
73
90
  const copyButton = {
74
91
  id: 'editor.syncedBlock.copy',
@@ -1,15 +1,19 @@
1
+ import { defaultSchema } from '@atlaskit/adf-schema/schema-default';
1
2
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
3
  import { copyDomNode, toDOM } from '@atlaskit/editor-common/copy-button';
4
+ import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
3
5
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
4
6
  import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
5
7
  import { fg } from '@atlaskit/platform-feature-flags';
6
8
  import { syncedBlockPluginKey } from '../pm-plugins/main';
7
9
  import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
8
10
  import { FLAG_ID } from '../types';
11
+ import { pasteSyncBlockHTMLContent } from './utils';
9
12
  export var createSyncedBlock = function createSyncedBlock(_ref) {
10
13
  var tr = _ref.tr,
11
14
  syncBlockStore = _ref.syncBlockStore,
12
- typeAheadInsert = _ref.typeAheadInsert;
15
+ typeAheadInsert = _ref.typeAheadInsert,
16
+ fireAnalyticsEvent = _ref.fireAnalyticsEvent;
13
17
  var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
14
18
  bodiedSyncBlock = _tr$doc$type$schema$n.bodiedSyncBlock,
15
19
  paragraph = _tr$doc$type$schema$n.paragraph;
@@ -35,9 +39,14 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
35
39
  var conversionInfo = canBeConvertedToSyncBlock(tr.selection);
36
40
  if (!conversionInfo) {
37
41
  if (fg('platform_synced_block_dogfooding')) {
38
- var _syncBlockStore$sourc;
39
- (_syncBlockStore$sourc = syncBlockStore.sourceManager.createExperience) === null || _syncBlockStore$sourc === void 0 || _syncBlockStore$sourc.failure({
40
- reason: 'Selection is not allowed to be converted to sync block'
42
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent({
43
+ action: ACTION.ERROR,
44
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
45
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
46
+ attributes: {
47
+ error: 'Content cannot be converted to sync block'
48
+ },
49
+ eventType: EVENT_TYPE.OPERATIONAL
41
50
  });
42
51
  }
43
52
  return false;
@@ -162,4 +171,33 @@ export var removeSyncedBlock = function removeSyncedBlock(api) {
162
171
  api === null || api === void 0 || api.core.actions.focus();
163
172
  return true;
164
173
  };
174
+ };
175
+
176
+ /**
177
+ * Deletes (bodied)SyncBlock node and paste its content to the editor
178
+ */
179
+ export var unsync = function unsync(storeManager, isBodiedSyncBlock, view) {
180
+ var _storeManager$referen;
181
+ if (!view) {
182
+ return false;
183
+ }
184
+ var state = view.state;
185
+ var syncBlock = findSyncBlockOrBodiedSyncBlock(state.schema, state.selection);
186
+ if (!syncBlock) {
187
+ return false;
188
+ }
189
+ if (isBodiedSyncBlock) {
190
+ return true;
191
+ }
192
+
193
+ // handle syncBlock unsync
194
+ var syncBlockContent = (_storeManager$referen = storeManager.referenceManager.getFromCache(syncBlock.node.attrs.resourceId)) === null || _storeManager$referen === void 0 || (_storeManager$referen = _storeManager$referen.data) === null || _storeManager$referen === void 0 ? void 0 : _storeManager$referen.content;
195
+ if (!syncBlockContent) {
196
+ return false;
197
+ }
198
+
199
+ // use defaultSchema for serialization so we can serialize any type of nodes and marks despite current editor's schema might not allow it
200
+ var contentFragment = Fragment.fromJSON(defaultSchema, syncBlockContent);
201
+ var contentDOM = DOMSerializer.fromSchema(defaultSchema).serializeFragment(contentFragment);
202
+ return pasteSyncBlockHTMLContent(contentDOM, view);
165
203
  };
@@ -0,0 +1,14 @@
1
+ export var pasteSyncBlockHTMLContent = function pasteSyncBlockHTMLContent(contentDOM, view) {
2
+ var tmpDiv = document.createElement('div');
3
+ tmpDiv.appendChild(contentDOM);
4
+
5
+ // This is required so that prosemirror can read the fragment context and slice properly
6
+ if (tmpDiv.firstChild instanceof HTMLElement) {
7
+ tmpDiv.firstChild.setAttribute('data-pm-slice', '0 0 []');
8
+
9
+ // As per requirement - when unsync reference block, it should render its content as copy&paste behaviour
10
+ // Hence here we call pasteHTML to evoke editor paste logic that handles any unsupported nodes/marks
11
+ return view.pasteHTML(tmpDiv.innerHTML);
12
+ }
13
+ return false;
14
+ };
@@ -0,0 +1,260 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import { bind } from 'bind-event-listener';
3
+ import { ACTION, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
4
+ import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getNodeQuery, getPopupContainerFromEditorView, popupWithNestedElement } from '@atlaskit/editor-common/experiences';
5
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
+ import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
8
+ var TIMEOUT_DURATION = 30000;
9
+ var pluginKey = new PluginKey('syncedBlockMenuAndToolbarExperience');
10
+ var SYNCED_BLOCK_BUTTON_TEST_IDS = Object.values(SYNCED_BLOCK_BUTTON_TEST_ID);
11
+ var syncedBlockButtonIds = new Set(SYNCED_BLOCK_BUTTON_TEST_IDS);
12
+ var targetEl;
13
+ export var getMenuAndToolbarExperiencesPlugin = function getMenuAndToolbarExperiencesPlugin(_ref) {
14
+ var refs = _ref.refs,
15
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
16
+ var popupsTargetEl;
17
+ var editorViewEl;
18
+ var getPopupsTarget = function getPopupsTarget() {
19
+ if (!popupsTargetEl) {
20
+ popupsTargetEl = refs.popupsMountPoint || refs.wrapperElement || getPopupContainerFromEditorView(editorViewEl);
21
+ }
22
+ return popupsTargetEl;
23
+ };
24
+ var createSourcePrimaryToolbarExperience = getCreateSourcePrimaryToolbarExperience({
25
+ refs: refs,
26
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
27
+ });
28
+ var createSourceBlockMenuExperience = getCreateSourceBlockMenuExperience({
29
+ refs: refs,
30
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
31
+ });
32
+ var createSourceQuickInsertMenuExperience = getCreateSourceQuickInsertMenuExperience({
33
+ refs: refs,
34
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
35
+ });
36
+ var deleteReferenceSyncedBlockExperience = getDeleteReferenceSyncedBlockToolbarExperience({
37
+ refs: refs,
38
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
39
+ });
40
+ var unbindClickListener = bind(document, {
41
+ type: 'click',
42
+ listener: function listener(event) {
43
+ var target = event.target;
44
+ if (!target) {
45
+ return;
46
+ }
47
+ var button = target.closest('button[data-testid]');
48
+ if (!button || !(button instanceof HTMLButtonElement)) {
49
+ return;
50
+ }
51
+ var testId = button.dataset.testid;
52
+ if (!isSyncedBlockButtonId(testId)) {
53
+ return;
54
+ }
55
+ handleButtonClick({
56
+ testId: testId,
57
+ createSourcePrimaryToolbarExperience: createSourcePrimaryToolbarExperience,
58
+ createSourceBlockMenuExperience: createSourceBlockMenuExperience,
59
+ createSourceQuickInsertMenuExperience: createSourceQuickInsertMenuExperience,
60
+ deleteReferenceSyncedBlockExperience: deleteReferenceSyncedBlockExperience
61
+ });
62
+ }
63
+ });
64
+ var unbindKeydownListener = bind(document, {
65
+ type: 'keydown',
66
+ listener: function listener(event) {
67
+ if (isEnterKey(event.key)) {
68
+ var typeaheadPopup = popupWithNestedElement(getPopupsTarget(), '.fabric-editor-typeahead');
69
+ if (!typeaheadPopup || !(typeaheadPopup instanceof HTMLElement)) {
70
+ return;
71
+ }
72
+ var firstItem = typeaheadPopup.querySelector('[role="option"]');
73
+ if (!firstItem || !(firstItem instanceof HTMLElement)) {
74
+ return;
75
+ }
76
+ var testId = firstItem.dataset.testid;
77
+ if (testId === SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate) {
78
+ createSourceQuickInsertMenuExperience.start();
79
+ }
80
+ }
81
+ },
82
+ options: {
83
+ capture: true
84
+ }
85
+ });
86
+ return new SafePlugin({
87
+ key: pluginKey,
88
+ view: function view(editorView) {
89
+ editorViewEl = editorView.dom;
90
+ return {
91
+ destroy: function destroy() {
92
+ createSourcePrimaryToolbarExperience.abort({
93
+ reason: 'editor-destroyed'
94
+ });
95
+ createSourceBlockMenuExperience.abort({
96
+ reason: 'editor-destroyed'
97
+ });
98
+ createSourceQuickInsertMenuExperience.abort({
99
+ reason: 'editor-destroyed'
100
+ });
101
+ deleteReferenceSyncedBlockExperience.abort({
102
+ reason: 'editor-destroyed'
103
+ });
104
+ unbindClickListener();
105
+ unbindKeydownListener();
106
+ }
107
+ };
108
+ }
109
+ });
110
+ };
111
+ var getCreateSourcePrimaryToolbarExperience = function getCreateSourcePrimaryToolbarExperience(_ref2) {
112
+ var refs = _ref2.refs,
113
+ dispatchAnalyticsEvent = _ref2.dispatchAnalyticsEvent;
114
+ return new Experience(EXPERIENCE_ID.TOOLBAR_ACTION, {
115
+ action: ACTION.SYNCED_BLOCK_CREATE,
116
+ actionSubjectId: ACTION_SUBJECT_ID.PRIMARY_TOOLBAR,
117
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
118
+ checks: [new ExperienceCheckTimeout({
119
+ durationMs: TIMEOUT_DURATION
120
+ }), syncedBlockAddedToDomCheck(refs)]
121
+ });
122
+ };
123
+ var getCreateSourceBlockMenuExperience = function getCreateSourceBlockMenuExperience(_ref3) {
124
+ var refs = _ref3.refs,
125
+ dispatchAnalyticsEvent = _ref3.dispatchAnalyticsEvent;
126
+ return new Experience(EXPERIENCE_ID.MENU_ACTION, {
127
+ action: ACTION.SYNCED_BLOCK_CREATE,
128
+ actionSubjectId: ACTION_SUBJECT_ID.BLOCK_MENU,
129
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
130
+ checks: [new ExperienceCheckTimeout({
131
+ durationMs: TIMEOUT_DURATION
132
+ }), syncedBlockAddedToDomCheck(refs)]
133
+ });
134
+ };
135
+ var getCreateSourceQuickInsertMenuExperience = function getCreateSourceQuickInsertMenuExperience(_ref4) {
136
+ var refs = _ref4.refs,
137
+ dispatchAnalyticsEvent = _ref4.dispatchAnalyticsEvent;
138
+ return new Experience(EXPERIENCE_ID.MENU_ACTION, {
139
+ action: ACTION.SYNCED_BLOCK_CREATE,
140
+ actionSubjectId: ACTION_SUBJECT_ID.QUICK_INSERT,
141
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
142
+ checks: [new ExperienceCheckTimeout({
143
+ durationMs: TIMEOUT_DURATION
144
+ }), syncedBlockAddedToDomCheck(refs)]
145
+ });
146
+ };
147
+ var getDeleteReferenceSyncedBlockToolbarExperience = function getDeleteReferenceSyncedBlockToolbarExperience(_ref5) {
148
+ var refs = _ref5.refs,
149
+ dispatchAnalyticsEvent = _ref5.dispatchAnalyticsEvent;
150
+ return new Experience(EXPERIENCE_ID.TOOLBAR_ACTION, {
151
+ action: ACTION.REFERENCE_SYNCED_BLOCK_DELETE,
152
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_TOOLBAR,
153
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
154
+ checks: [new ExperienceCheckTimeout({
155
+ durationMs: TIMEOUT_DURATION
156
+ }), referenceSyncBlockRemovedFromDomCheck(refs)]
157
+ });
158
+ };
159
+ var isSyncedBlockButtonId = function isSyncedBlockButtonId(value) {
160
+ return !!value && syncedBlockButtonIds.has(value);
161
+ };
162
+ var handleButtonClick = function handleButtonClick(_ref6) {
163
+ var testId = _ref6.testId,
164
+ createSourcePrimaryToolbarExperience = _ref6.createSourcePrimaryToolbarExperience,
165
+ createSourceBlockMenuExperience = _ref6.createSourceBlockMenuExperience,
166
+ createSourceQuickInsertMenuExperience = _ref6.createSourceQuickInsertMenuExperience,
167
+ deleteReferenceSyncedBlockExperience = _ref6.deleteReferenceSyncedBlockExperience;
168
+ switch (testId) {
169
+ case SYNCED_BLOCK_BUTTON_TEST_ID.primaryToolbarCreate:
170
+ createSourcePrimaryToolbarExperience.start();
171
+ break;
172
+ case SYNCED_BLOCK_BUTTON_TEST_ID.blockMenuCreate:
173
+ createSourceBlockMenuExperience.start();
174
+ break;
175
+ case SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate:
176
+ createSourceQuickInsertMenuExperience.start();
177
+ break;
178
+ case SYNCED_BLOCK_BUTTON_TEST_ID.syncedBlockToolbarReferenceDelete:
179
+ deleteReferenceSyncedBlockExperience.start();
180
+ break;
181
+ default:
182
+ {
183
+ // Exhaustiveness check: if a new SyncedBlockToolbarButtonId is added
184
+ // but not handled above, TypeScript will error here.
185
+ var _exhaustiveCheck = testId;
186
+ return _exhaustiveCheck;
187
+ }
188
+ }
189
+ };
190
+ var isEnterKey = function isEnterKey(key) {
191
+ return key === 'Enter';
192
+ };
193
+ var getTarget = function getTarget(containerElement) {
194
+ if (!targetEl) {
195
+ var element = containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelector('.ProseMirror');
196
+ if (!element || !(element instanceof HTMLElement)) {
197
+ return null;
198
+ }
199
+ targetEl = element;
200
+ }
201
+ return targetEl;
202
+ };
203
+ var syncedBlockAddedToDomCheck = function syncedBlockAddedToDomCheck(refs) {
204
+ return new ExperienceCheckDomMutation({
205
+ onDomMutation: function onDomMutation(_ref7) {
206
+ var mutations = _ref7.mutations;
207
+ if (mutations.some(isBodiedSyncBlockAddedInMutation)) {
208
+ return {
209
+ status: 'success'
210
+ };
211
+ }
212
+ return undefined;
213
+ },
214
+ observeConfig: function observeConfig() {
215
+ return {
216
+ target: getTarget(refs.containerElement),
217
+ options: {
218
+ childList: true
219
+ }
220
+ };
221
+ }
222
+ });
223
+ };
224
+ var isBodiedSyncBlockAddedInMutation = function isBodiedSyncBlockAddedInMutation(_ref8) {
225
+ var type = _ref8.type,
226
+ addedNodes = _ref8.addedNodes;
227
+ return type === 'childList' && _toConsumableArray(addedNodes).some(isBodiedSyncBlockWithinNode);
228
+ };
229
+ var isBodiedSyncBlockWithinNode = function isBodiedSyncBlockWithinNode(node) {
230
+ return getNodeQuery('[data-prosemirror-node-name="bodiedSyncBlock"]')(node);
231
+ };
232
+ var referenceSyncBlockRemovedFromDomCheck = function referenceSyncBlockRemovedFromDomCheck(refs) {
233
+ return new ExperienceCheckDomMutation({
234
+ onDomMutation: function onDomMutation(_ref9) {
235
+ var mutations = _ref9.mutations;
236
+ if (mutations.some(isSyncBlockRemovedInMutation)) {
237
+ return {
238
+ status: 'success'
239
+ };
240
+ }
241
+ return undefined;
242
+ },
243
+ observeConfig: function observeConfig() {
244
+ return {
245
+ target: getTarget(refs.containerElement),
246
+ options: {
247
+ childList: true
248
+ }
249
+ };
250
+ }
251
+ });
252
+ };
253
+ var isSyncBlockRemovedInMutation = function isSyncBlockRemovedInMutation(_ref0) {
254
+ var type = _ref0.type,
255
+ removedNodes = _ref0.removedNodes;
256
+ return type === 'childList' && _toConsumableArray(removedNodes).some(isSyncBlockWithinNode);
257
+ };
258
+ var isSyncBlockWithinNode = function isSyncBlockWithinNode(node) {
259
+ return getNodeQuery('[data-prosemirror-node-name="syncBlock"]')(node);
260
+ };
@@ -8,8 +8,9 @@ import Lozenge from '@atlaskit/lozenge';
8
8
  import { fg } from '@atlaskit/platform-feature-flags';
9
9
  import { flushBodiedSyncBlocks as _flushBodiedSyncBlocks, flushSyncBlocks } from './editor-actions';
10
10
  import { copySyncedBlockReferenceToClipboardEditorCommand, createSyncedBlock } from './editor-commands';
11
- import { getExperienceTrackingPlugins } from './pm-plugins/experience-tracking/get-experience-tracking-plugins';
12
11
  import { createPlugin, syncedBlockPluginKey } from './pm-plugins/main';
12
+ import { getMenuAndToolbarExperiencesPlugin } from './pm-plugins/menu-and-toolbar-experiences';
13
+ import { SYNCED_BLOCK_BUTTON_TEST_ID } from './types';
13
14
  import { getBlockMenuComponents } from './ui/block-menu-components';
14
15
  import { DeleteConfirmationModal } from './ui/DeleteConfirmationModal';
15
16
  import { Flag } from './ui/Flag';
@@ -42,14 +43,18 @@ export var syncedBlockPlugin = function syncedBlockPlugin(_ref) {
42
43
  plugin: function plugin(params) {
43
44
  return createPlugin(config, params, syncBlockStore, api);
44
45
  }
45
- }].concat(_toConsumableArray(fg('platform_synced_block_dogfooding') ? getExperienceTrackingPlugins({
46
- refs: refs,
47
- dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
48
- var _api$analytics2;
49
- return api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent(payload);
50
- },
51
- syncBlockStore: syncBlockStore
52
- }) : []));
46
+ }].concat(_toConsumableArray(fg('platform_synced_block_dogfooding') ? [{
47
+ name: 'menuAndToolbarExperiencesPlugin',
48
+ plugin: function plugin() {
49
+ return getMenuAndToolbarExperiencesPlugin({
50
+ refs: refs,
51
+ dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
52
+ var _api$analytics2;
53
+ return api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.fireAnalyticsEvent(payload);
54
+ }
55
+ });
56
+ }
57
+ }] : []));
53
58
  },
54
59
  commands: {
55
60
  copySyncedBlockReferenceToClipboard: function copySyncedBlockReferenceToClipboard() {
@@ -57,13 +62,15 @@ export var syncedBlockPlugin = function syncedBlockPlugin(_ref) {
57
62
  },
58
63
  insertSyncedBlock: function insertSyncedBlock() {
59
64
  return function (_ref2) {
65
+ var _api$analytics3;
60
66
  var tr = _ref2.tr;
61
67
  if (!(config !== null && config !== void 0 && config.enableSourceCreation)) {
62
68
  return null;
63
69
  }
64
70
  return createSyncedBlock({
65
71
  tr: tr,
66
- syncBlockStore: syncBlockStore
72
+ syncBlockStore: syncBlockStore,
73
+ fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent
67
74
  }) || null;
68
75
  };
69
76
  }
@@ -99,13 +106,15 @@ export var syncedBlockPlugin = function syncedBlockPlugin(_ref) {
99
106
  });
100
107
  },
101
108
  action: function action(insert, state) {
109
+ var _api$analytics4;
102
110
  return createSyncedBlock({
103
111
  tr: state.tr,
104
112
  syncBlockStore: syncBlockStore,
105
- typeAheadInsert: insert
113
+ typeAheadInsert: insert,
114
+ fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions.fireAnalyticsEvent
106
115
  });
107
116
  },
108
- testId: fg('platform_synced_block_dogfooding') ? 'create-synced-block-quick-insert-btn' : undefined
117
+ testId: fg('platform_synced_block_dogfooding') ? SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate : undefined
109
118
  }];
110
119
  },
111
120
  floatingToolbar: function floatingToolbar(state, intl) {
@@ -6,6 +6,9 @@ export var FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
6
6
  FLAG_ID["SYNC_BLOCK_COPIED"] = "sync-block-copied";
7
7
  return FLAG_ID;
8
8
  }({});
9
- export var EXPERIENCE_ABORT_REASON = {
10
- EDITOR_DESTROYED: 'editor-destroyed'
9
+ export var SYNCED_BLOCK_BUTTON_TEST_ID = {
10
+ primaryToolbarCreate: 'create-synced-block-toolbar-btn',
11
+ blockMenuCreate: 'create-synced-block-block-menu-btn',
12
+ quickInsertCreate: 'create-synced-block-quick-insert-btn',
13
+ syncedBlockToolbarReferenceDelete: 'reference-synced-block-delete-btn'
11
14
  };
@@ -6,6 +6,7 @@ import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
6
6
  import { ToolbarButton, ToolbarTooltip } from '@atlaskit/editor-toolbar';
7
7
  import BlockSyncedIcon from '@atlaskit/icon-lab/core/block-synced';
8
8
  import { canBeConvertedToSyncBlock } from '../pm-plugins/utils/utils';
9
+ import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
9
10
  export var CreateSyncedBlockButton = function CreateSyncedBlockButton(_ref) {
10
11
  var api = _ref.api;
11
12
  var intl = useIntl();
@@ -44,7 +45,7 @@ export var CreateSyncedBlockButton = function CreateSyncedBlockButton(_ref) {
44
45
  label: ""
45
46
  }),
46
47
  isDisabled: isDisabled,
47
- testId: "create-synced-block-toolbar-btn",
48
+ testId: SYNCED_BLOCK_BUTTON_TEST_ID.primaryToolbarCreate,
48
49
  onClick: onClick
49
50
  }));
50
51
  };
@@ -6,6 +6,7 @@ import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
6
6
  import { SyncBlocksIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
7
7
  import Lozenge from '@atlaskit/lozenge';
8
8
  import { canBeConvertedToSyncBlock } from '../pm-plugins/utils/utils';
9
+ import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
9
10
  var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref) {
10
11
  var api = _ref.api;
11
12
  var _useIntl = useIntl(),
@@ -42,7 +43,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref)
42
43
  }),
43
44
  onClick: onClick,
44
45
  isDisabled: isOffline,
45
- testId: "create-synced-block-block-menu-btn",
46
+ testId: SYNCED_BLOCK_BUTTON_TEST_ID.blockMenuCreate,
46
47
  elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
47
48
  appearance: "new"
48
49
  }, formatMessage(blockMenuMessages.newLozenge))
@@ -1,9 +1,13 @@
1
1
  import { useEffect } from 'react';
2
2
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
3
+ import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
3
5
  export var SYNC_BLOCK_FETCH_INTERVAL = 3000;
4
6
 
5
- // Component that refreshes synced block subscriptions at regular intervals
6
- // this is a workaround for the subscription mechanism not being real-time
7
+ // Component that manages synced block data synchronization.
8
+ // When the feature flag 'platform_synced_block_dogfooding' is enabled,
9
+ // it uses provider-based GraphQL subscriptions for updates.
10
+ // When disabled, it falls back to polling at regular intervals.
7
11
  export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
8
12
  var syncBlockStoreManager = _ref.syncBlockStoreManager,
9
13
  api = _ref.api;
@@ -14,9 +18,19 @@ export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
14
18
  };
15
19
  }),
16
20
  mode = _useSharedPluginState.mode;
21
+ var featureFlagEnabled = fg('platform_synced_block_dogfooding');
22
+ var isOnline = !isOfflineMode(mode);
17
23
  useEffect(function () {
24
+ var useRealTimeSubscriptions = featureFlagEnabled && isOnline;
25
+ syncBlockStoreManager.referenceManager.setRealTimeSubscriptionsEnabled(useRealTimeSubscriptions);
26
+ }, [syncBlockStoreManager, featureFlagEnabled, isOnline]);
27
+ useEffect(function () {
28
+ var useRealTimeSubscriptions = featureFlagEnabled && isOnline;
29
+ if (useRealTimeSubscriptions) {
30
+ return;
31
+ }
18
32
  var interval = -1;
19
- if (mode !== 'offline') {
33
+ if (isOnline) {
20
34
  interval = window.setInterval(function () {
21
35
  var _document;
22
36
  // check if document is visible to avoid unnecessary refreshes
@@ -30,6 +44,6 @@ export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
30
44
  return function () {
31
45
  window.clearInterval(interval);
32
46
  };
33
- }, [syncBlockStoreManager, mode]);
47
+ }, [syncBlockStoreManager, isOnline, featureFlagEnabled]);
34
48
  return null;
35
49
  };
@@ -47,16 +47,17 @@ var styles = {
47
47
  var ItemTitle = function ItemTitle(_ref) {
48
48
  var title = _ref.title,
49
49
  formatMessage = _ref.formatMessage,
50
- onSamePage = _ref.onSamePage,
50
+ onSameDocument = _ref.onSameDocument,
51
51
  isSource = _ref.isSource,
52
- hasAccess = _ref.hasAccess;
52
+ hasAccess = _ref.hasAccess,
53
+ productType = _ref.productType;
53
54
  return /*#__PURE__*/React.createElement(Inline, null, /*#__PURE__*/React.createElement(Box, {
54
55
  as: "span",
55
56
  xcss: styles.title
56
- }, title), onSamePage && /*#__PURE__*/React.createElement(Box, {
57
+ }, title), onSameDocument && /*#__PURE__*/React.createElement(Box, {
57
58
  as: "span",
58
59
  xcss: styles.note
59
- }, "\xA0- ", formatMessage(messages.syncedLocationDropdownTitleNote)), isSource && /*#__PURE__*/React.createElement(Box, {
60
+ }, "\xA0- ", formatMessage(productType === 'confluence-page' ? messages.syncedLocationDropdownTitleNoteForConfluencePage : messages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(Box, {
60
61
  as: "span",
61
62
  xcss: styles.lozenge
62
63
  }, /*#__PURE__*/React.createElement(Lozenge, null, formatMessage(messages.syncedLocationDropdownSourceLozenge))), !hasAccess && /*#__PURE__*/React.createElement(Box, {
@@ -73,7 +74,7 @@ var subTypeIconMap = {
73
74
  page: PageIcon,
74
75
  blogpost: QuotationMarkIcon
75
76
  };
76
- var getSubTypeIcon = function getSubTypeIcon(subType) {
77
+ var getConfluenceSubTypeIcon = function getConfluenceSubTypeIcon(subType) {
77
78
  return subType && subType in subTypeIconMap ? subTypeIconMap[subType] : PageIcon;
78
79
  };
79
80
  var ProductIcon = function ProductIcon(_ref2) {
@@ -90,17 +91,18 @@ var ProductIcon = function ProductIcon(_ref2) {
90
91
  var ItemIcon = function ItemIcon(_ref3) {
91
92
  var reference = _ref3.reference;
92
93
  var hasAccess = reference.hasAccess,
93
- subType = reference.subType;
94
- if (hasAccess) {
94
+ subType = reference.subType,
95
+ productType = reference.productType;
96
+ if (productType === 'confluence-page' && hasAccess) {
95
97
  return /*#__PURE__*/React.createElement(IconTile, {
96
- icon: getSubTypeIcon(subType),
98
+ icon: getConfluenceSubTypeIcon(subType),
97
99
  label: "",
98
100
  appearance: 'gray',
99
101
  size: "xsmall"
100
102
  });
101
103
  }
102
104
  return /*#__PURE__*/React.createElement(ProductIcon, {
103
- product: reference.productType
105
+ product: productType
104
106
  });
105
107
  };
106
108
  export var processReferenceData = function processReferenceData(referenceData, intl) {
@@ -268,9 +270,10 @@ var DropdownContent = function DropdownContent(_ref7) {
268
270
  }, /*#__PURE__*/React.createElement(ItemTitle, {
269
271
  title: reference.title || reference.url || '',
270
272
  formatMessage: formatMessage,
271
- onSamePage: reference.onSamePage,
273
+ onSameDocument: reference.onSameDocument,
272
274
  isSource: reference.isSource,
273
- hasAccess: reference.hasAccess
275
+ hasAccess: reference.hasAccess,
276
+ productType: reference.productType
274
277
  }))));
275
278
  })));
276
279
  } else {