@atlaskit/editor-plugin-synced-block 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/editor-commands/index.js +7 -1
  3. package/dist/cjs/pm-plugins/experience-tracking/create-reference-experience.js +113 -0
  4. package/dist/cjs/pm-plugins/experience-tracking/create-source-experience.js +185 -0
  5. package/dist/cjs/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +31 -0
  6. package/dist/cjs/syncedBlockPlugin.js +21 -3
  7. package/dist/cjs/ui/CreateSyncedBlockButton.js +1 -0
  8. package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +1 -0
  9. package/dist/es2019/editor-commands/index.js +7 -1
  10. package/dist/es2019/pm-plugins/experience-tracking/create-reference-experience.js +105 -0
  11. package/dist/es2019/pm-plugins/experience-tracking/create-source-experience.js +179 -0
  12. package/dist/es2019/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +22 -0
  13. package/dist/es2019/syncedBlockPlugin.js +21 -3
  14. package/dist/es2019/ui/CreateSyncedBlockButton.js +1 -0
  15. package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +1 -0
  16. package/dist/esm/editor-commands/index.js +7 -1
  17. package/dist/esm/pm-plugins/experience-tracking/create-reference-experience.js +106 -0
  18. package/dist/esm/pm-plugins/experience-tracking/create-source-experience.js +178 -0
  19. package/dist/esm/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +25 -0
  20. package/dist/esm/syncedBlockPlugin.js +21 -3
  21. package/dist/esm/ui/CreateSyncedBlockButton.js +1 -0
  22. package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +1 -0
  23. package/dist/types/pm-plugins/experience-tracking/create-reference-experience.d.ts +17 -0
  24. package/dist/types/pm-plugins/experience-tracking/create-source-experience.d.ts +21 -0
  25. package/dist/types/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +16 -0
  26. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-reference-experience.d.ts +17 -0
  27. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-source-experience.d.ts +21 -0
  28. package/dist/types-ts4.5/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +16 -0
  29. package/package.json +8 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 5.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 5.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`656adaeec9d0b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/656adaeec9d0b) -
14
+ [ux] EDITOR-1665 add experience tracking for create sync block
15
+ - Updated dependencies
16
+
3
17
  ## 5.1.0
4
18
 
5
19
  ### Minor Changes
@@ -8,6 +8,7 @@ var _analytics = require("@atlaskit/editor-common/analytics");
8
8
  var _copyButton = require("@atlaskit/editor-common/copy-button");
9
9
  var _state = require("@atlaskit/editor-prosemirror/state");
10
10
  var _utils = require("@atlaskit/editor-prosemirror/utils");
11
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
12
  var _main = require("../pm-plugins/main");
12
13
  var _utils2 = require("../pm-plugins/utils/utils");
13
14
  var _types = require("../types");
@@ -39,7 +40,12 @@ var createSyncedBlock = exports.createSyncedBlock = function createSyncedBlock(_
39
40
  } else {
40
41
  var conversionInfo = (0, _utils2.canBeConvertedToSyncBlock)(tr.selection);
41
42
  if (!conversionInfo) {
42
- // TODO: EDITOR-1665 - Raise an error analytics event
43
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding')) {
44
+ var _syncBlockStore$sourc;
45
+ (_syncBlockStore$sourc = syncBlockStore.sourceManager.createExperience) === null || _syncBlockStore$sourc === void 0 || _syncBlockStore$sourc.failure({
46
+ reason: 'Selection is not allowed to be converted to sync block'
47
+ });
48
+ }
43
49
  return false;
44
50
  }
45
51
  var _attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getCreateReferenceExperiencePlugin = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _analytics = require("@atlaskit/editor-common/analytics");
10
+ var _experiences = require("@atlaskit/editor-common/experiences");
11
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
12
+ var _state = require("@atlaskit/editor-prosemirror/state");
13
+ var isPastedFromFabricEditor = function isPastedFromFabricEditor(html) {
14
+ return !!html && html.indexOf('data-pm-slice="') >= 0;
15
+ };
16
+ var pluginKey = new _state.PluginKey('createReferenceSyncBlockExperience');
17
+ var START_METHOD = {
18
+ PASTE: 'paste'
19
+ };
20
+ var ABORT_REASON = {
21
+ EDITOR_DESTROYED: 'editor-destroyed'
22
+ };
23
+
24
+ /**
25
+ * This experience tracks when a reference sync block is inserted.
26
+ *
27
+ * Start: When user pastes a sync block from editor and createSyncedBlock is called
28
+ * Success: When the sync block is added to the DOM within 500ms of start
29
+ * Failure: When 500ms passes without the reference sync block being added to the DOM
30
+ */
31
+ var getCreateReferenceExperiencePlugin = exports.getCreateReferenceExperiencePlugin = function getCreateReferenceExperiencePlugin(_ref) {
32
+ var refs = _ref.refs,
33
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
34
+ var experience = getCreateReferenceExperience({
35
+ refs: refs,
36
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
37
+ });
38
+ return new _safePlugin.SafePlugin({
39
+ key: pluginKey,
40
+ view: function view() {
41
+ return {
42
+ destroy: function destroy() {
43
+ experience.abort({
44
+ reason: ABORT_REASON.EDITOR_DESTROYED
45
+ });
46
+ }
47
+ };
48
+ },
49
+ props: {
50
+ handlePaste: function handlePaste(_view, rawEvent, slice) {
51
+ var _event$clipboardData;
52
+ var event = rawEvent;
53
+ var html = (_event$clipboardData = event.clipboardData) === null || _event$clipboardData === void 0 ? void 0 : _event$clipboardData.getData('text/html');
54
+
55
+ // do not start on paste from renderer, because this flattens the content and does not create a reference block
56
+ if (isPastedFromFabricEditor(html)) {
57
+ slice.content.forEach(function (node) {
58
+ if (node.type.name === 'syncBlock' || node.type.name === 'bodiedSyncBlock') {
59
+ experience.start({
60
+ method: START_METHOD.PASTE
61
+ });
62
+ }
63
+ });
64
+ }
65
+ }
66
+ }
67
+ });
68
+ };
69
+ var getCreateReferenceExperience = function getCreateReferenceExperience(_ref2) {
70
+ var refs = _ref2.refs,
71
+ dispatchAnalyticsEvent = _ref2.dispatchAnalyticsEvent;
72
+ return new _experiences.Experience(_analytics.ACTION_SUBJECT.SYNCED_BLOCK, {
73
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
74
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
75
+ checks: [new _experiences.ExperienceCheckTimeout({
76
+ durationMs: 500
77
+ }), new _experiences.ExperienceCheckDomMutation({
78
+ onDomMutation: function onDomMutation(_ref3) {
79
+ var mutations = _ref3.mutations;
80
+ if (mutations.some(isReferenceSyncBlockAddedInMutation)) {
81
+ return {
82
+ status: 'success'
83
+ };
84
+ }
85
+ return undefined;
86
+ },
87
+ observeConfig: function observeConfig() {
88
+ var _refs$containerElemen;
89
+ var proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
90
+ if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
91
+ return null;
92
+ }
93
+ return {
94
+ target: proseMirrorElement,
95
+ options: {
96
+ childList: true
97
+ }
98
+ };
99
+ }
100
+ })]
101
+ });
102
+ };
103
+ var isReferenceSyncBlockAddedInMutation = function isReferenceSyncBlockAddedInMutation(_ref4) {
104
+ var type = _ref4.type,
105
+ addedNodes = _ref4.addedNodes;
106
+ return type === 'childList' && (0, _toConsumableArray2.default)(addedNodes).some(isReferenceSyncBlockNode);
107
+ };
108
+ var isReferenceSyncBlockNode = function isReferenceSyncBlockNode(node) {
109
+ if (!(node instanceof HTMLElement)) {
110
+ return false;
111
+ }
112
+ return !!node.querySelector('[data-prosemirror-node-name="syncBlock"]');
113
+ };
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getCreateSourceExperiencePlugin = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _bindEventListener = require("bind-event-listener");
10
+ var _analytics = require("@atlaskit/editor-common/analytics");
11
+ var _experiences = require("@atlaskit/editor-common/experiences");
12
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
13
+ var _state = require("@atlaskit/editor-prosemirror/state");
14
+ var pluginKey = new _state.PluginKey('createSourceSyncBlockExperience');
15
+ var ABORT_REASON = {
16
+ EDITOR_DESTROYED: 'editor-destroyed'
17
+ };
18
+ var START_METHOD = {
19
+ BLOCK_MENU: 'block-menu',
20
+ PINNED_TOOLBAR: 'pinned-toolbar',
21
+ QUICK_INSERT: 'quick-insert'
22
+ };
23
+ var SYNCED_BLOCK_CREATE_BUTTON_IDS = ['create-synced-block-toolbar-btn', 'create-synced-block-block-menu-btn', 'create-synced-block-quick-insert-btn'];
24
+ var syncedBlockCreateButtonIds = new Set(SYNCED_BLOCK_CREATE_BUTTON_IDS);
25
+
26
+ /**
27
+ * This experience tracks when a source sync block is inserted.
28
+ *
29
+ * Start: When user inserts a sync block via block menu, quick insert or pinned toolbar
30
+ * Success: When the sync block is added to the DOM within 2000ms of start
31
+ * Failure: When 500ms passes without the source sync block being added to the DOM
32
+ */
33
+ var getCreateSourceExperiencePlugin = exports.getCreateSourceExperiencePlugin = function getCreateSourceExperiencePlugin(_ref) {
34
+ var refs = _ref.refs,
35
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
36
+ syncBlockStore = _ref.syncBlockStore;
37
+ var popupsTargetEl;
38
+ var editorViewEl;
39
+ var getPopupsTarget = function getPopupsTarget() {
40
+ if (!popupsTargetEl) {
41
+ popupsTargetEl = refs.popupsMountPoint || refs.wrapperElement || (0, _experiences.getPopupContainerFromEditorView)(editorViewEl);
42
+ }
43
+ return popupsTargetEl;
44
+ };
45
+ var experience = getCreateSourceExperience({
46
+ refs: refs,
47
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
48
+ syncBlockStore: syncBlockStore
49
+ });
50
+ syncBlockStore.sourceManager.setCreateExperience(experience);
51
+ var unbindClickListener = (0, _bindEventListener.bind)(document, {
52
+ type: 'click',
53
+ listener: function listener(event) {
54
+ var target = event.target;
55
+ if (!target) {
56
+ return;
57
+ }
58
+ var button = target.closest('button[data-testid]');
59
+ if (!button || !(button instanceof HTMLButtonElement)) {
60
+ return;
61
+ }
62
+ var testId = button.dataset.testid;
63
+ if (!isSyncedBlockCreateButtonId(testId)) {
64
+ return;
65
+ }
66
+ handleButtonClick(testId, experience);
67
+ }
68
+ });
69
+ var unbindKeydownListener = (0, _bindEventListener.bind)(document, {
70
+ type: 'keydown',
71
+ listener: function listener(event) {
72
+ if (isEnterKey(event.key)) {
73
+ var typeaheadPopup = (0, _experiences.popupWithNestedElement)(getPopupsTarget(), '.fabric-editor-typeahead');
74
+ if (!typeaheadPopup || !(typeaheadPopup instanceof HTMLElement)) {
75
+ return;
76
+ }
77
+ var firstItem = typeaheadPopup.querySelector('[role="option"]');
78
+ if (!firstItem || !(firstItem instanceof HTMLElement)) {
79
+ return;
80
+ }
81
+ var testId = firstItem.dataset.testid;
82
+ if (testId === 'create-synced-block-quick-insert-btn') {
83
+ experience.start({
84
+ method: START_METHOD.QUICK_INSERT
85
+ });
86
+ }
87
+ }
88
+ },
89
+ options: {
90
+ capture: true
91
+ }
92
+ });
93
+ return new _safePlugin.SafePlugin({
94
+ key: pluginKey,
95
+ view: function view(editorView) {
96
+ editorViewEl = editorView.dom;
97
+ return {
98
+ destroy: function destroy() {
99
+ experience.abort({
100
+ reason: ABORT_REASON.EDITOR_DESTROYED
101
+ });
102
+ unbindClickListener();
103
+ unbindKeydownListener();
104
+ }
105
+ };
106
+ }
107
+ });
108
+ };
109
+ var getCreateSourceExperience = function getCreateSourceExperience(_ref2) {
110
+ var refs = _ref2.refs,
111
+ dispatchAnalyticsEvent = _ref2.dispatchAnalyticsEvent;
112
+ return new _experiences.Experience(_analytics.ACTION_SUBJECT.SYNCED_BLOCK, {
113
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
114
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
115
+ checks: [new _experiences.ExperienceCheckTimeout({
116
+ durationMs: 2000
117
+ }), new _experiences.ExperienceCheckDomMutation({
118
+ onDomMutation: function onDomMutation(_ref3) {
119
+ var mutations = _ref3.mutations;
120
+ if (mutations.some(isSourceSyncBlockAddedInMutation)) {
121
+ return {
122
+ status: 'success'
123
+ };
124
+ }
125
+ return undefined;
126
+ },
127
+ observeConfig: function observeConfig() {
128
+ var _refs$containerElemen;
129
+ var proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
130
+ if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
131
+ return null;
132
+ }
133
+ return {
134
+ target: proseMirrorElement,
135
+ options: {
136
+ childList: true
137
+ }
138
+ };
139
+ }
140
+ })]
141
+ });
142
+ };
143
+ var isSyncedBlockCreateButtonId = function isSyncedBlockCreateButtonId(value) {
144
+ return !!value && syncedBlockCreateButtonIds.has(value);
145
+ };
146
+ var handleButtonClick = function handleButtonClick(testId, experience) {
147
+ switch (testId) {
148
+ case 'create-synced-block-toolbar-btn':
149
+ experience.start({
150
+ method: START_METHOD.PINNED_TOOLBAR
151
+ });
152
+ break;
153
+ case 'create-synced-block-block-menu-btn':
154
+ experience.start({
155
+ method: START_METHOD.BLOCK_MENU
156
+ });
157
+ break;
158
+ case 'create-synced-block-quick-insert-btn':
159
+ experience.start({
160
+ method: START_METHOD.QUICK_INSERT
161
+ });
162
+ break;
163
+ default:
164
+ {
165
+ // Exhaustiveness check: if a new SyncedBlockToolbarButtonId is added
166
+ // but not handled above, TypeScript will error here.
167
+ var _exhaustiveCheck = testId;
168
+ return _exhaustiveCheck;
169
+ }
170
+ }
171
+ };
172
+ var isEnterKey = function isEnterKey(key) {
173
+ return key === 'Enter';
174
+ };
175
+ var isSourceSyncBlockAddedInMutation = function isSourceSyncBlockAddedInMutation(_ref4) {
176
+ var type = _ref4.type,
177
+ addedNodes = _ref4.addedNodes;
178
+ return type === 'childList' && (0, _toConsumableArray2.default)(addedNodes).some(isSourceSyncBlockNode);
179
+ };
180
+ var isSourceSyncBlockNode = function isSourceSyncBlockNode(node) {
181
+ if (!(node instanceof HTMLElement)) {
182
+ return false;
183
+ }
184
+ return !!node.querySelector('[data-prosemirror-node-name="bodiedSyncBlock"]');
185
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getExperienceTrackingPlugins = void 0;
7
+ var _createReferenceExperience = require("./create-reference-experience");
8
+ var _createSourceExperience = require("./create-source-experience");
9
+ var getExperienceTrackingPlugins = exports.getExperienceTrackingPlugins = function getExperienceTrackingPlugins(_ref) {
10
+ var refs = _ref.refs,
11
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
12
+ syncBlockStore = _ref.syncBlockStore;
13
+ return [{
14
+ name: 'createReferenceSyncedBlockExperiencePlugin',
15
+ plugin: function plugin() {
16
+ return (0, _createReferenceExperience.getCreateReferenceExperiencePlugin)({
17
+ refs: refs,
18
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
19
+ });
20
+ }
21
+ }, {
22
+ name: 'createSourceSyncedBlockExperiencePlugin',
23
+ plugin: function plugin() {
24
+ return (0, _createSourceExperience.getCreateSourceExperiencePlugin)({
25
+ refs: refs,
26
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
27
+ syncBlockStore: syncBlockStore
28
+ });
29
+ }
30
+ }];
31
+ };
@@ -5,14 +5,17 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.syncedBlockPlugin = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
8
9
  var _react = _interopRequireDefault(require("react"));
9
10
  var _adfSchema = require("@atlaskit/adf-schema");
10
11
  var _messages = require("@atlaskit/editor-common/messages");
11
12
  var _quickInsert = require("@atlaskit/editor-common/quick-insert");
12
13
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
13
14
  var _lozenge = _interopRequireDefault(require("@atlaskit/lozenge"));
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
16
  var _editorActions = require("./editor-actions");
15
17
  var _editorCommands = require("./editor-commands");
18
+ var _getExperienceTrackingPlugins = require("./pm-plugins/experience-tracking/get-experience-tracking-plugins");
16
19
  var _main = require("./pm-plugins/main");
17
20
  var _blockMenuComponents = require("./ui/block-menu-components");
18
21
  var _DeleteConfirmationModal = require("./ui/DeleteConfirmationModal");
@@ -24,6 +27,7 @@ var syncedBlockPlugin = exports.syncedBlockPlugin = function syncedBlockPlugin(_
24
27
  var _api$analytics, _api$blockMenu, _config$enableSourceC, _api$toolbar, _config$enableSourceC2;
25
28
  var config = _ref.config,
26
29
  api = _ref.api;
30
+ var refs = {};
27
31
  var syncBlockStore = new _editorSyncedBlockProvider.SyncBlockStoreManager(config === null || config === void 0 ? void 0 : config.syncBlockDataProvider);
28
32
  syncBlockStore.setFireAnalyticsEvent(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.fireAnalyticsEvent);
29
33
  api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 || _api$blockMenu.actions.registerBlockMenuComponents((0, _blockMenuComponents.getBlockMenuComponents)(api, (_config$enableSourceC = config === null || config === void 0 ? void 0 : config.enableSourceCreation) !== null && _config$enableSourceC !== void 0 ? _config$enableSourceC : false));
@@ -45,7 +49,14 @@ var syncedBlockPlugin = exports.syncedBlockPlugin = function syncedBlockPlugin(_
45
49
  plugin: function plugin(params) {
46
50
  return (0, _main.createPlugin)(config, params, syncBlockStore, api);
47
51
  }
48
- }];
52
+ }].concat((0, _toConsumableArray2.default)((0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? (0, _getExperienceTrackingPlugins.getExperienceTrackingPlugins)({
53
+ refs: refs,
54
+ dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
55
+ var _api$analytics2;
56
+ return api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent(payload);
57
+ },
58
+ syncBlockStore: syncBlockStore
59
+ }) : []));
49
60
  },
50
61
  commands: {
51
62
  copySyncedBlockReferenceToClipboard: function copySyncedBlockReferenceToClipboard() {
@@ -100,14 +111,21 @@ var syncedBlockPlugin = exports.syncedBlockPlugin = function syncedBlockPlugin(_
100
111
  syncBlockStore: syncBlockStore,
101
112
  typeAheadInsert: insert
102
113
  });
103
- }
114
+ },
115
+ testId: (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? 'create-synced-block-quick-insert-btn' : undefined
104
116
  }];
105
117
  },
106
118
  floatingToolbar: function floatingToolbar(state, intl) {
107
119
  return (0, _floatingToolbar.getToolbarConfig)(state, intl, api, syncBlockStore);
108
120
  }
109
121
  },
110
- contentComponent: function contentComponent() {
122
+ contentComponent: function contentComponent(_ref4) {
123
+ var containerElement = _ref4.containerElement,
124
+ wrapperElement = _ref4.wrapperElement,
125
+ popupsMountPoint = _ref4.popupsMountPoint;
126
+ refs.containerElement = containerElement || undefined;
127
+ refs.popupsMountPoint = popupsMountPoint || undefined;
128
+ refs.wrapperElement = wrapperElement || undefined;
111
129
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_SyncBlockRefresher.SyncBlockRefresher, {
112
130
  syncBlockStoreManager: syncBlockStore,
113
131
  api: api
@@ -53,6 +53,7 @@ var CreateSyncedBlockButton = exports.CreateSyncedBlockButton = function CreateS
53
53
  label: ""
54
54
  }),
55
55
  isDisabled: isDisabled,
56
+ testId: "create-synced-block-toolbar-btn",
56
57
  onClick: onClick
57
58
  }));
58
59
  };
@@ -51,6 +51,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref)
51
51
  }),
52
52
  onClick: onClick,
53
53
  isDisabled: isOffline,
54
+ testId: "create-synced-block-block-menu-btn",
54
55
  elemAfter: /*#__PURE__*/_react.default.createElement(_lozenge.default, {
55
56
  appearance: "new"
56
57
  }, formatMessage(_messages.blockMenuMessages.newLozenge))
@@ -2,6 +2,7 @@ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit
2
2
  import { copyDomNode, toDOM } from '@atlaskit/editor-common/copy-button';
3
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
4
4
  import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { syncedBlockPluginKey } from '../pm-plugins/main';
6
7
  import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
7
8
  import { FLAG_ID } from '../types';
@@ -39,7 +40,12 @@ export const createSyncedBlock = ({
39
40
  } else {
40
41
  const conversionInfo = canBeConvertedToSyncBlock(tr.selection);
41
42
  if (!conversionInfo) {
42
- // TODO: EDITOR-1665 - Raise an error analytics event
43
+ if (fg('platform_synced_block_dogfooding')) {
44
+ var _syncBlockStore$sourc;
45
+ (_syncBlockStore$sourc = syncBlockStore.sourceManager.createExperience) === null || _syncBlockStore$sourc === void 0 ? void 0 : _syncBlockStore$sourc.failure({
46
+ reason: 'Selection is not allowed to be converted to sync block'
47
+ });
48
+ }
43
49
  return false;
44
50
  }
45
51
  const attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
@@ -0,0 +1,105 @@
1
+ import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
2
+ import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
3
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ const isPastedFromFabricEditor = html => !!html && html.indexOf('data-pm-slice="') >= 0;
6
+ const pluginKey = new PluginKey('createReferenceSyncBlockExperience');
7
+ const START_METHOD = {
8
+ PASTE: 'paste'
9
+ };
10
+ const ABORT_REASON = {
11
+ EDITOR_DESTROYED: 'editor-destroyed'
12
+ };
13
+
14
+ /**
15
+ * This experience tracks when a reference sync block is inserted.
16
+ *
17
+ * Start: When user pastes a sync block from editor and createSyncedBlock is called
18
+ * Success: When the sync block is added to the DOM within 500ms of start
19
+ * Failure: When 500ms passes without the reference sync block being added to the DOM
20
+ */
21
+ export const getCreateReferenceExperiencePlugin = ({
22
+ refs,
23
+ dispatchAnalyticsEvent
24
+ }) => {
25
+ const experience = getCreateReferenceExperience({
26
+ refs,
27
+ dispatchAnalyticsEvent
28
+ });
29
+ return new SafePlugin({
30
+ key: pluginKey,
31
+ view: () => {
32
+ return {
33
+ destroy: () => {
34
+ experience.abort({
35
+ reason: ABORT_REASON.EDITOR_DESTROYED
36
+ });
37
+ }
38
+ };
39
+ },
40
+ props: {
41
+ handlePaste: (_view, rawEvent, slice) => {
42
+ var _event$clipboardData;
43
+ const event = rawEvent;
44
+ const html = (_event$clipboardData = event.clipboardData) === null || _event$clipboardData === void 0 ? void 0 : _event$clipboardData.getData('text/html');
45
+
46
+ // do not start on paste from renderer, because this flattens the content and does not create a reference block
47
+ if (isPastedFromFabricEditor(html)) {
48
+ slice.content.forEach(node => {
49
+ if (node.type.name === 'syncBlock' || node.type.name === 'bodiedSyncBlock') {
50
+ experience.start({
51
+ method: START_METHOD.PASTE
52
+ });
53
+ }
54
+ });
55
+ }
56
+ }
57
+ }
58
+ });
59
+ };
60
+ const getCreateReferenceExperience = ({
61
+ refs,
62
+ dispatchAnalyticsEvent
63
+ }) => {
64
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
65
+ actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
66
+ dispatchAnalyticsEvent,
67
+ checks: [new ExperienceCheckTimeout({
68
+ durationMs: 500
69
+ }), new ExperienceCheckDomMutation({
70
+ onDomMutation: ({
71
+ mutations
72
+ }) => {
73
+ if (mutations.some(isReferenceSyncBlockAddedInMutation)) {
74
+ return {
75
+ status: 'success'
76
+ };
77
+ }
78
+ return undefined;
79
+ },
80
+ observeConfig: () => {
81
+ var _refs$containerElemen;
82
+ const proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
83
+ if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
84
+ return null;
85
+ }
86
+ return {
87
+ target: proseMirrorElement,
88
+ options: {
89
+ childList: true
90
+ }
91
+ };
92
+ }
93
+ })]
94
+ });
95
+ };
96
+ const isReferenceSyncBlockAddedInMutation = ({
97
+ type,
98
+ addedNodes
99
+ }) => type === 'childList' && [...addedNodes].some(isReferenceSyncBlockNode);
100
+ const isReferenceSyncBlockNode = node => {
101
+ if (!(node instanceof HTMLElement)) {
102
+ return false;
103
+ }
104
+ return !!node.querySelector('[data-prosemirror-node-name="syncBlock"]');
105
+ };