@atlaskit/editor-plugin-synced-block 10.1.10 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/cjs/editor-commands/index.js +15 -1
- package/dist/cjs/pm-plugins/main.js +60 -2
- package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-creation.js +6 -3
- package/dist/cjs/syncedBlockPlugin.js +3 -2
- package/dist/cjs/ui/CreateSyncedBlockButton.js +3 -2
- package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +2 -2
- package/dist/cjs/ui/quick-insert.js +3 -1
- package/dist/es2019/editor-commands/index.js +16 -2
- package/dist/es2019/pm-plugins/main.js +61 -1
- package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-creation.js +6 -3
- package/dist/es2019/syncedBlockPlugin.js +3 -2
- package/dist/es2019/ui/CreateSyncedBlockButton.js +3 -2
- package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +2 -2
- package/dist/es2019/ui/quick-insert.js +3 -1
- package/dist/esm/editor-commands/index.js +16 -2
- package/dist/esm/pm-plugins/main.js +59 -1
- package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-creation.js +6 -3
- package/dist/esm/syncedBlockPlugin.js +3 -2
- package/dist/esm/ui/CreateSyncedBlockButton.js +3 -2
- package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +2 -2
- package/dist/esm/ui/quick-insert.js +3 -1
- package/dist/types/editor-commands/index.d.ts +6 -1
- package/dist/types/pm-plugins/main.d.ts +13 -0
- package/dist/types/pm-plugins/utils/handle-bodied-sync-block-creation.d.ts +6 -2
- package/dist/types/syncedBlockPluginType.d.ts +6 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-synced-block
|
|
2
2
|
|
|
3
|
+
## 10.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`c0b0b98789f7a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c0b0b98789f7a) -
|
|
8
|
+
Add analytics for synced block source creation: record the creation input method and whether the
|
|
9
|
+
block was created empty, and emit a one-off event the first time an empty source block gains
|
|
10
|
+
content.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
|
|
3
16
|
## 10.1.10
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -78,11 +78,17 @@ var createSyncedBlock = exports.createSyncedBlock = function createSyncedBlock(_
|
|
|
78
78
|
var tr = _ref.tr,
|
|
79
79
|
syncBlockStore = _ref.syncBlockStore,
|
|
80
80
|
typeAheadInsert = _ref.typeAheadInsert,
|
|
81
|
-
fireAnalyticsEvent = _ref.fireAnalyticsEvent
|
|
81
|
+
fireAnalyticsEvent = _ref.fireAnalyticsEvent,
|
|
82
|
+
inputMethod = _ref.inputMethod;
|
|
82
83
|
var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
|
|
83
84
|
bodiedSyncBlock = _tr$doc$type$schema$n.bodiedSyncBlock,
|
|
84
85
|
paragraph = _tr$doc$type$schema$n.paragraph;
|
|
85
86
|
|
|
87
|
+
// Capture createdEmpty before any insertion mutates the selection. The meta is
|
|
88
|
+
// set on the final transaction before returning (see below), since the
|
|
89
|
+
// typeahead path may reassign `tr` and drop meta set here.
|
|
90
|
+
var createdEmpty = tr.selection.empty;
|
|
91
|
+
|
|
86
92
|
// If the selection is empty, we want to insert the sync block on a new line
|
|
87
93
|
if (tr.selection.empty) {
|
|
88
94
|
var attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
|
|
@@ -149,6 +155,14 @@ var createSyncedBlock = exports.createSyncedBlock = function createSyncedBlock(_
|
|
|
149
155
|
tr.setSelection(_state.TextSelection.create(tr.doc, conversionInfo.from));
|
|
150
156
|
}
|
|
151
157
|
}
|
|
158
|
+
|
|
159
|
+
// Stash creation-type signals on the final transaction (after any typeahead
|
|
160
|
+
// reassignment). Set unconditionally — the store manager only reads it behind
|
|
161
|
+
// the feature gate.
|
|
162
|
+
tr.setMeta(_main.creationMetaKey, {
|
|
163
|
+
createdEmpty: createdEmpty,
|
|
164
|
+
inputMethod: inputMethod
|
|
165
|
+
});
|
|
152
166
|
return tr;
|
|
153
167
|
};
|
|
154
168
|
var copySyncedBlockReferenceToClipboardEditorCommand = exports.copySyncedBlockReferenceToClipboardEditorCommand = function copySyncedBlockReferenceToClipboardEditorCommand(syncBlockStore, inputMethod, api) {
|
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.syncedBlockPluginKey = exports.getDeleteMechanism = exports.deleteMechanismMetaKey = exports.createPlugin = void 0;
|
|
7
|
+
exports.syncedBlockPluginKey = exports.getDeleteMechanism = exports.deleteMechanismMetaKey = exports.creationMetaKey = exports.createPlugin = void 0;
|
|
8
8
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
9
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
@@ -53,6 +53,16 @@ var syncedBlockPluginKey = exports.syncedBlockPluginKey = new _state.PluginKey('
|
|
|
53
53
|
* `platform_editor_blocks_patch_4`.
|
|
54
54
|
*/
|
|
55
55
|
var deleteMechanismMetaKey = exports.deleteMechanismMetaKey = new _state.PluginKey('syncedBlockDeleteMechanism');
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creation-type signals set by {@link createSyncedBlock} on the creating
|
|
59
|
+
* transaction. The async creation handler forwards them to the store manager,
|
|
60
|
+
* which attaches them to the `syncedBlockCreate` event. A dedicated key keeps
|
|
61
|
+
* this transient signal isolated from plugin state. Consumed behind
|
|
62
|
+
* `platform_editor_blocks_patch_4`.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
var creationMetaKey = exports.creationMetaKey = new _state.PluginKey('syncedBlockCreationMeta');
|
|
56
66
|
var mapRetryCreationPosMap = function mapRetryCreationPosMap(oldMap, newRetryCreationPos, mapPos, isPerfExperimentOn) {
|
|
57
67
|
var resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
|
|
58
68
|
|
|
@@ -182,6 +192,43 @@ var getDeleteMechanism = exports.getDeleteMechanism = function getDeleteMechanis
|
|
|
182
192
|
var isNodeSelected = selection instanceof _state.NodeSelection && ((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type.name) === 'bodiedSyncBlock';
|
|
183
193
|
return isNodeSelected ? 'selectionReplaced' : 'keyboardDelete';
|
|
184
194
|
};
|
|
195
|
+
/**
|
|
196
|
+
* True when a source `bodiedSyncBlock` holds user content — i.e. not just the
|
|
197
|
+
* single empty paragraph it is created with (used to detect empty→content).
|
|
198
|
+
*/
|
|
199
|
+
var bodiedSyncBlockHasContent = function bodiedSyncBlockHasContent(node) {
|
|
200
|
+
if (node.childCount === 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (node.childCount === 1) {
|
|
204
|
+
var child = node.firstChild;
|
|
205
|
+
// A freshly-created block is a single empty paragraph; anything else
|
|
206
|
+
// (non-empty paragraph, or a different/first block) counts as content.
|
|
207
|
+
return !((child === null || child === void 0 ? void 0 : child.type.name) === 'paragraph' && child.content.size === 0);
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Ask the store manager to fire the one-shot first-content-added event for every
|
|
214
|
+
* populated source block. The manager only emits for blocks it created empty
|
|
215
|
+
* this session and dedupes per block, so iterating all populated blocks is safe
|
|
216
|
+
* and self-limiting. Called only when `hasEditInSyncBlock` flagged an in-block
|
|
217
|
+
* edit, so this walk runs rarely.
|
|
218
|
+
*/
|
|
219
|
+
var emitFirstContentAddedForEditedBlocks = function emitFirstContentAddedForEditedBlocks(tr, state, syncBlockStore) {
|
|
220
|
+
var bodiedSyncBlock = state.schema.nodes.bodiedSyncBlock;
|
|
221
|
+
tr.doc.descendants(function (node) {
|
|
222
|
+
if (node.type === bodiedSyncBlock) {
|
|
223
|
+
if (bodiedSyncBlockHasContent(node)) {
|
|
224
|
+
syncBlockStore.sourceManager.maybeEmitFirstContentAdded(node.attrs.resourceId, node.attrs.localId);
|
|
225
|
+
}
|
|
226
|
+
// bodiedSyncBlocks are top-level and not nested, so no need to descend.
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
});
|
|
231
|
+
};
|
|
185
232
|
var filterTransactionOnline = function filterTransactionOnline(_ref3) {
|
|
186
233
|
var _tr$getMeta;
|
|
187
234
|
var tr = _ref3.tr,
|
|
@@ -262,9 +309,20 @@ var filterTransactionOnline = function filterTransactionOnline(_ref3) {
|
|
|
262
309
|
if (isPasteOrDrop && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_13')) {
|
|
263
310
|
return true;
|
|
264
311
|
}
|
|
265
|
-
|
|
312
|
+
|
|
313
|
+
// Forward creation-type signals captured by createSyncedBlock onto the async
|
|
314
|
+
// `syncedBlockCreate` success event.
|
|
315
|
+
var creationMeta = tr.getMeta(creationMetaKey);
|
|
316
|
+
(0, _handleBodiedSyncBlockCreation.handleBodiedSyncBlockCreation)(bodiedSyncBlockAdded, state, api, creationMeta);
|
|
266
317
|
return true;
|
|
267
318
|
}
|
|
319
|
+
|
|
320
|
+
// On an in-block edit, let the store manager fire the one-shot first-content
|
|
321
|
+
// event (dedupe + empty→content scoping live there). After the add/remove
|
|
322
|
+
// branches so it never runs for the creation transaction itself.
|
|
323
|
+
if ((0, _trackSyncBlocks7.hasEditInSyncBlock)(tr, state)) {
|
|
324
|
+
emitFirstContentAddedForEditedBlocks(tr, state, syncBlockStore);
|
|
325
|
+
}
|
|
268
326
|
showExtensionInSyncBlockWarningIfNeeded(tr, state, api, extensionFlagShown);
|
|
269
327
|
return true;
|
|
270
328
|
};
|
|
@@ -74,9 +74,12 @@ var buildRevertCreationTr = function buildRevertCreationTr(tr, pos) {
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
*
|
|
77
|
-
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow
|
|
77
|
+
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow.
|
|
78
|
+
*
|
|
79
|
+
* @param enrichment optional creation-type signals from `createSyncedBlock`,
|
|
80
|
+
* forwarded to the store manager to attach to the `syncedBlockCreate` event.
|
|
78
81
|
*/
|
|
79
|
-
var handleBodiedSyncBlockCreation = exports.handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, editorState, api) {
|
|
82
|
+
var handleBodiedSyncBlockCreation = exports.handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, editorState, api, enrichment) {
|
|
80
83
|
var syncBlockStore = _main.syncedBlockPluginKey.getState(editorState).syncBlockStore;
|
|
81
84
|
bodiedSyncBlockAdded.forEach(function (node) {
|
|
82
85
|
if (node.from === undefined || node.to === undefined) {
|
|
@@ -137,6 +140,6 @@ var handleBodiedSyncBlockCreation = exports.handleBodiedSyncBlockCreation = func
|
|
|
137
140
|
});
|
|
138
141
|
});
|
|
139
142
|
}
|
|
140
|
-
});
|
|
143
|
+
}, enrichment);
|
|
141
144
|
});
|
|
142
145
|
};
|
|
@@ -107,7 +107,7 @@ var syncedBlockPlugin = exports.syncedBlockPlugin = function syncedBlockPlugin(_
|
|
|
107
107
|
copySyncedBlockReferenceToClipboard: function copySyncedBlockReferenceToClipboard(inputMethod) {
|
|
108
108
|
return (0, _editorCommands.copySyncedBlockReferenceToClipboardEditorCommand)(syncBlockStore, inputMethod, api);
|
|
109
109
|
},
|
|
110
|
-
insertSyncedBlock: function insertSyncedBlock() {
|
|
110
|
+
insertSyncedBlock: function insertSyncedBlock(inputMethod) {
|
|
111
111
|
return function (_ref3) {
|
|
112
112
|
var _api$analytics3;
|
|
113
113
|
var tr = _ref3.tr;
|
|
@@ -117,7 +117,8 @@ var syncedBlockPlugin = exports.syncedBlockPlugin = function syncedBlockPlugin(_
|
|
|
117
117
|
return (0, _editorCommands.createSyncedBlock)({
|
|
118
118
|
tr: tr,
|
|
119
119
|
syncBlockStore: syncBlockStore,
|
|
120
|
-
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent
|
|
120
|
+
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
121
|
+
inputMethod: inputMethod
|
|
121
122
|
}) || null;
|
|
122
123
|
};
|
|
123
124
|
}
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
8
8
|
exports.CreateSyncedBlockButton = void 0;
|
|
9
9
|
var _react = _interopRequireWildcard(require("react"));
|
|
10
10
|
var _reactIntl = require("react-intl");
|
|
11
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
11
12
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
12
13
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
13
14
|
var _editorPluginConnectivity = require("@atlaskit/editor-plugin-connectivity");
|
|
@@ -51,7 +52,7 @@ var CreateSyncedBlockButton = exports.CreateSyncedBlockButton = function CreateS
|
|
|
51
52
|
var dispatched = api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(function (_ref2) {
|
|
52
53
|
var _api$blockControls;
|
|
53
54
|
var tr = _ref2.tr;
|
|
54
|
-
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
55
|
+
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(_analytics.INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
55
56
|
tr: tr
|
|
56
57
|
});
|
|
57
58
|
if (!result) {
|
|
@@ -70,7 +71,7 @@ var CreateSyncedBlockButton = exports.CreateSyncedBlockButton = function CreateS
|
|
|
70
71
|
}
|
|
71
72
|
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
|
|
72
73
|
var tr = _ref3.tr;
|
|
73
|
-
return api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
74
|
+
return api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(_analytics.INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
74
75
|
tr: tr
|
|
75
76
|
});
|
|
76
77
|
});
|
|
@@ -65,7 +65,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref2
|
|
|
65
65
|
// stopping selection preservation — otherwise we would dispatch an
|
|
66
66
|
// effectively-empty transaction and close the menu despite nothing
|
|
67
67
|
// having been inserted.
|
|
68
|
-
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
68
|
+
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(_analytics.INPUT_METHOD.BLOCK_MENU)({
|
|
69
69
|
tr: tr
|
|
70
70
|
});
|
|
71
71
|
if (!result) {
|
|
@@ -90,7 +90,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref2
|
|
|
90
90
|
|
|
91
91
|
// Legacy behaviour: insert then close the block menu as two separate executes
|
|
92
92
|
// (batching them caused selection collisions — EDITOR-2751).
|
|
93
|
-
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock());
|
|
93
|
+
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(_analytics.INPUT_METHOD.BLOCK_MENU));
|
|
94
94
|
api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || (_api$blockControls3 = _api$blockControls3.commands) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.toggleBlockMenu({
|
|
95
95
|
closeMenu: true
|
|
96
96
|
}));
|
|
@@ -10,6 +10,7 @@ exports.getQuickInsertConfig = void 0;
|
|
|
10
10
|
require("./quick-insert.compiled.css");
|
|
11
11
|
var React = _interopRequireWildcard(require("react"));
|
|
12
12
|
var _runtime = require("@compiled/react/runtime");
|
|
13
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
13
14
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
14
15
|
var _quickInsert = require("@atlaskit/editor-common/quick-insert");
|
|
15
16
|
var _lozenge = _interopRequireDefault(require("@atlaskit/lozenge"));
|
|
@@ -49,7 +50,8 @@ var getQuickInsertConfig = exports.getQuickInsertConfig = function getQuickInser
|
|
|
49
50
|
tr: state.tr,
|
|
50
51
|
syncBlockStore: syncBlockStore,
|
|
51
52
|
typeAheadInsert: insert,
|
|
52
|
-
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent
|
|
53
|
+
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
|
|
54
|
+
inputMethod: _analytics.INPUT_METHOD.QUICK_INSERT
|
|
53
55
|
});
|
|
54
56
|
},
|
|
55
57
|
testId: _types.SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate
|
|
@@ -5,7 +5,7 @@ import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
|
5
5
|
import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
7
7
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
|
-
import { deleteMechanismMetaKey, syncedBlockPluginKey } from '../pm-plugins/main';
|
|
8
|
+
import { creationMetaKey, deleteMechanismMetaKey, syncedBlockPluginKey } from '../pm-plugins/main';
|
|
9
9
|
import { canBeConvertedToSyncBlock, deferDispatch, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
10
10
|
import { FLAG_ID } from '../types';
|
|
11
11
|
import { findBodiedSyncBlockByLocalId, pasteSyncBlockHTMLContent } from './utils';
|
|
@@ -68,7 +68,8 @@ export const createSyncedBlock = ({
|
|
|
68
68
|
tr,
|
|
69
69
|
syncBlockStore,
|
|
70
70
|
typeAheadInsert,
|
|
71
|
-
fireAnalyticsEvent
|
|
71
|
+
fireAnalyticsEvent,
|
|
72
|
+
inputMethod
|
|
72
73
|
}) => {
|
|
73
74
|
const {
|
|
74
75
|
schema: {
|
|
@@ -79,6 +80,11 @@ export const createSyncedBlock = ({
|
|
|
79
80
|
}
|
|
80
81
|
} = tr.doc.type;
|
|
81
82
|
|
|
83
|
+
// Capture createdEmpty before any insertion mutates the selection. The meta is
|
|
84
|
+
// set on the final transaction before returning (see below), since the
|
|
85
|
+
// typeahead path may reassign `tr` and drop meta set here.
|
|
86
|
+
const createdEmpty = tr.selection.empty;
|
|
87
|
+
|
|
82
88
|
// If the selection is empty, we want to insert the sync block on a new line
|
|
83
89
|
if (tr.selection.empty) {
|
|
84
90
|
const attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
|
|
@@ -145,6 +151,14 @@ export const createSyncedBlock = ({
|
|
|
145
151
|
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.from));
|
|
146
152
|
}
|
|
147
153
|
}
|
|
154
|
+
|
|
155
|
+
// Stash creation-type signals on the final transaction (after any typeahead
|
|
156
|
+
// reassignment). Set unconditionally — the store manager only reads it behind
|
|
157
|
+
// the feature gate.
|
|
158
|
+
tr.setMeta(creationMetaKey, {
|
|
159
|
+
createdEmpty,
|
|
160
|
+
inputMethod
|
|
161
|
+
});
|
|
148
162
|
return tr;
|
|
149
163
|
};
|
|
150
164
|
export const copySyncedBlockReferenceToClipboardEditorCommand = (syncBlockStore, inputMethod, api) => ({
|
|
@@ -37,6 +37,16 @@ export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
|
37
37
|
* `platform_editor_blocks_patch_4`.
|
|
38
38
|
*/
|
|
39
39
|
export const deleteMechanismMetaKey = new PluginKey('syncedBlockDeleteMechanism');
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creation-type signals set by {@link createSyncedBlock} on the creating
|
|
43
|
+
* transaction. The async creation handler forwards them to the store manager,
|
|
44
|
+
* which attaches them to the `syncedBlockCreate` event. A dedicated key keeps
|
|
45
|
+
* this transient signal isolated from plugin state. Consumed behind
|
|
46
|
+
* `platform_editor_blocks_patch_4`.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
export const creationMetaKey = new PluginKey('syncedBlockCreationMeta');
|
|
40
50
|
const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos, isPerfExperimentOn) => {
|
|
41
51
|
const resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
|
|
42
52
|
|
|
@@ -153,6 +163,45 @@ export const getDeleteMechanism = (tr, state) => {
|
|
|
153
163
|
const isNodeSelected = selection instanceof NodeSelection && ((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type.name) === 'bodiedSyncBlock';
|
|
154
164
|
return isNodeSelected ? 'selectionReplaced' : 'keyboardDelete';
|
|
155
165
|
};
|
|
166
|
+
/**
|
|
167
|
+
* True when a source `bodiedSyncBlock` holds user content — i.e. not just the
|
|
168
|
+
* single empty paragraph it is created with (used to detect empty→content).
|
|
169
|
+
*/
|
|
170
|
+
const bodiedSyncBlockHasContent = node => {
|
|
171
|
+
if (node.childCount === 0) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (node.childCount === 1) {
|
|
175
|
+
const child = node.firstChild;
|
|
176
|
+
// A freshly-created block is a single empty paragraph; anything else
|
|
177
|
+
// (non-empty paragraph, or a different/first block) counts as content.
|
|
178
|
+
return !((child === null || child === void 0 ? void 0 : child.type.name) === 'paragraph' && child.content.size === 0);
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Ask the store manager to fire the one-shot first-content-added event for every
|
|
185
|
+
* populated source block. The manager only emits for blocks it created empty
|
|
186
|
+
* this session and dedupes per block, so iterating all populated blocks is safe
|
|
187
|
+
* and self-limiting. Called only when `hasEditInSyncBlock` flagged an in-block
|
|
188
|
+
* edit, so this walk runs rarely.
|
|
189
|
+
*/
|
|
190
|
+
const emitFirstContentAddedForEditedBlocks = (tr, state, syncBlockStore) => {
|
|
191
|
+
const {
|
|
192
|
+
bodiedSyncBlock
|
|
193
|
+
} = state.schema.nodes;
|
|
194
|
+
tr.doc.descendants(node => {
|
|
195
|
+
if (node.type === bodiedSyncBlock) {
|
|
196
|
+
if (bodiedSyncBlockHasContent(node)) {
|
|
197
|
+
syncBlockStore.sourceManager.maybeEmitFirstContentAdded(node.attrs.resourceId, node.attrs.localId);
|
|
198
|
+
}
|
|
199
|
+
// bodiedSyncBlocks are top-level and not nested, so no need to descend.
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
});
|
|
204
|
+
};
|
|
156
205
|
const filterTransactionOnline = ({
|
|
157
206
|
tr,
|
|
158
207
|
state,
|
|
@@ -235,9 +284,20 @@ const filterTransactionOnline = ({
|
|
|
235
284
|
if (isPasteOrDrop && fg('platform_synced_block_patch_13')) {
|
|
236
285
|
return true;
|
|
237
286
|
}
|
|
238
|
-
|
|
287
|
+
|
|
288
|
+
// Forward creation-type signals captured by createSyncedBlock onto the async
|
|
289
|
+
// `syncedBlockCreate` success event.
|
|
290
|
+
const creationMeta = tr.getMeta(creationMetaKey);
|
|
291
|
+
handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, state, api, creationMeta);
|
|
239
292
|
return true;
|
|
240
293
|
}
|
|
294
|
+
|
|
295
|
+
// On an in-block edit, let the store manager fire the one-shot first-content
|
|
296
|
+
// event (dedupe + empty→content scoping live there). After the add/remove
|
|
297
|
+
// branches so it never runs for the creation transaction itself.
|
|
298
|
+
if (hasEditInSyncBlock(tr, state)) {
|
|
299
|
+
emitFirstContentAddedForEditedBlocks(tr, state, syncBlockStore);
|
|
300
|
+
}
|
|
241
301
|
showExtensionInSyncBlockWarningIfNeeded(tr, state, api, extensionFlagShown);
|
|
242
302
|
return true;
|
|
243
303
|
};
|
|
@@ -65,9 +65,12 @@ const buildRevertCreationTr = (tr, pos) => {
|
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
*
|
|
68
|
-
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow
|
|
68
|
+
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow.
|
|
69
|
+
*
|
|
70
|
+
* @param enrichment optional creation-type signals from `createSyncedBlock`,
|
|
71
|
+
* forwarded to the store manager to attach to the `syncedBlockCreate` event.
|
|
69
72
|
*/
|
|
70
|
-
export const handleBodiedSyncBlockCreation = (bodiedSyncBlockAdded, editorState, api) => {
|
|
73
|
+
export const handleBodiedSyncBlockCreation = (bodiedSyncBlockAdded, editorState, api, enrichment) => {
|
|
71
74
|
const syncBlockStore = syncedBlockPluginKey.getState(editorState).syncBlockStore;
|
|
72
75
|
bodiedSyncBlockAdded.forEach(node => {
|
|
73
76
|
if (node.from === undefined || node.to === undefined) {
|
|
@@ -130,6 +133,6 @@ export const handleBodiedSyncBlockCreation = (bodiedSyncBlockAdded, editorState,
|
|
|
130
133
|
});
|
|
131
134
|
});
|
|
132
135
|
}
|
|
133
|
-
});
|
|
136
|
+
}, enrichment);
|
|
134
137
|
});
|
|
135
138
|
};
|
|
@@ -97,7 +97,7 @@ export const syncedBlockPlugin = ({
|
|
|
97
97
|
},
|
|
98
98
|
commands: {
|
|
99
99
|
copySyncedBlockReferenceToClipboard: inputMethod => copySyncedBlockReferenceToClipboardEditorCommand(syncBlockStore, inputMethod, api),
|
|
100
|
-
insertSyncedBlock:
|
|
100
|
+
insertSyncedBlock: inputMethod => ({
|
|
101
101
|
tr
|
|
102
102
|
}) => {
|
|
103
103
|
var _api$analytics3;
|
|
@@ -107,7 +107,8 @@ export const syncedBlockPlugin = ({
|
|
|
107
107
|
return createSyncedBlock({
|
|
108
108
|
tr,
|
|
109
109
|
syncBlockStore,
|
|
110
|
-
fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent
|
|
110
|
+
fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
111
|
+
inputMethod
|
|
111
112
|
}) || null;
|
|
112
113
|
}
|
|
113
114
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
3
4
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
4
5
|
import { syncBlockMessages } from '@atlaskit/editor-common/messages';
|
|
5
6
|
import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
|
|
@@ -45,7 +46,7 @@ export const CreateSyncedBlockButton = ({
|
|
|
45
46
|
tr
|
|
46
47
|
}) => {
|
|
47
48
|
var _api$blockControls, _api$blockControls$co;
|
|
48
|
-
const result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
49
|
+
const result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
49
50
|
tr
|
|
50
51
|
});
|
|
51
52
|
if (!result) {
|
|
@@ -64,7 +65,7 @@ export const CreateSyncedBlockButton = ({
|
|
|
64
65
|
}
|
|
65
66
|
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
|
|
66
67
|
tr
|
|
67
|
-
}) => api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
68
|
+
}) => api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
68
69
|
tr
|
|
69
70
|
}));
|
|
70
71
|
api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.focus();
|
|
@@ -57,7 +57,7 @@ const CreateSyncedBlockDropdownItem = ({
|
|
|
57
57
|
// stopping selection preservation — otherwise we would dispatch an
|
|
58
58
|
// effectively-empty transaction and close the menu despite nothing
|
|
59
59
|
// having been inserted.
|
|
60
|
-
const result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
60
|
+
const result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.BLOCK_MENU)({
|
|
61
61
|
tr
|
|
62
62
|
});
|
|
63
63
|
if (!result) {
|
|
@@ -82,7 +82,7 @@ const CreateSyncedBlockDropdownItem = ({
|
|
|
82
82
|
|
|
83
83
|
// Legacy behaviour: insert then close the block menu as two separate executes
|
|
84
84
|
// (batching them caused selection collisions — EDITOR-2751).
|
|
85
|
-
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock());
|
|
85
|
+
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.BLOCK_MENU));
|
|
86
86
|
api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : (_api$blockControls3$c = _api$blockControls3.commands) === null || _api$blockControls3$c === void 0 ? void 0 : _api$blockControls3$c.toggleBlockMenu({
|
|
87
87
|
closeMenu: true
|
|
88
88
|
}));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import "./quick-insert.compiled.css";
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
5
6
|
import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
6
7
|
import { IconSyncBlock } from '@atlaskit/editor-common/quick-insert';
|
|
7
8
|
import Lozenge from '@atlaskit/lozenge';
|
|
@@ -39,7 +40,8 @@ export const getQuickInsertConfig = (config, api, syncBlockStore) => {
|
|
|
39
40
|
tr: state.tr,
|
|
40
41
|
syncBlockStore,
|
|
41
42
|
typeAheadInsert: insert,
|
|
42
|
-
fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent
|
|
43
|
+
fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
|
|
44
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT
|
|
43
45
|
});
|
|
44
46
|
},
|
|
45
47
|
testId: SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate
|
|
@@ -8,7 +8,7 @@ import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
|
8
8
|
import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
9
9
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
10
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
|
-
import { deleteMechanismMetaKey, syncedBlockPluginKey } from '../pm-plugins/main';
|
|
11
|
+
import { creationMetaKey, deleteMechanismMetaKey, syncedBlockPluginKey } from '../pm-plugins/main';
|
|
12
12
|
import { canBeConvertedToSyncBlock, deferDispatch, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
13
13
|
import { FLAG_ID } from '../types';
|
|
14
14
|
import { findBodiedSyncBlockByLocalId, pasteSyncBlockHTMLContent } from './utils';
|
|
@@ -71,11 +71,17 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
|
|
|
71
71
|
var tr = _ref.tr,
|
|
72
72
|
syncBlockStore = _ref.syncBlockStore,
|
|
73
73
|
typeAheadInsert = _ref.typeAheadInsert,
|
|
74
|
-
fireAnalyticsEvent = _ref.fireAnalyticsEvent
|
|
74
|
+
fireAnalyticsEvent = _ref.fireAnalyticsEvent,
|
|
75
|
+
inputMethod = _ref.inputMethod;
|
|
75
76
|
var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
|
|
76
77
|
bodiedSyncBlock = _tr$doc$type$schema$n.bodiedSyncBlock,
|
|
77
78
|
paragraph = _tr$doc$type$schema$n.paragraph;
|
|
78
79
|
|
|
80
|
+
// Capture createdEmpty before any insertion mutates the selection. The meta is
|
|
81
|
+
// set on the final transaction before returning (see below), since the
|
|
82
|
+
// typeahead path may reassign `tr` and drop meta set here.
|
|
83
|
+
var createdEmpty = tr.selection.empty;
|
|
84
|
+
|
|
79
85
|
// If the selection is empty, we want to insert the sync block on a new line
|
|
80
86
|
if (tr.selection.empty) {
|
|
81
87
|
var attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
|
|
@@ -142,6 +148,14 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
|
|
|
142
148
|
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.from));
|
|
143
149
|
}
|
|
144
150
|
}
|
|
151
|
+
|
|
152
|
+
// Stash creation-type signals on the final transaction (after any typeahead
|
|
153
|
+
// reassignment). Set unconditionally — the store manager only reads it behind
|
|
154
|
+
// the feature gate.
|
|
155
|
+
tr.setMeta(creationMetaKey, {
|
|
156
|
+
createdEmpty: createdEmpty,
|
|
157
|
+
inputMethod: inputMethod
|
|
158
|
+
});
|
|
145
159
|
return tr;
|
|
146
160
|
};
|
|
147
161
|
export var copySyncedBlockReferenceToClipboardEditorCommand = function copySyncedBlockReferenceToClipboardEditorCommand(syncBlockStore, inputMethod, api) {
|
|
@@ -46,6 +46,16 @@ export var syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
|
46
46
|
* `platform_editor_blocks_patch_4`.
|
|
47
47
|
*/
|
|
48
48
|
export var deleteMechanismMetaKey = new PluginKey('syncedBlockDeleteMechanism');
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creation-type signals set by {@link createSyncedBlock} on the creating
|
|
52
|
+
* transaction. The async creation handler forwards them to the store manager,
|
|
53
|
+
* which attaches them to the `syncedBlockCreate` event. A dedicated key keeps
|
|
54
|
+
* this transient signal isolated from plugin state. Consumed behind
|
|
55
|
+
* `platform_editor_blocks_patch_4`.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export var creationMetaKey = new PluginKey('syncedBlockCreationMeta');
|
|
49
59
|
var mapRetryCreationPosMap = function mapRetryCreationPosMap(oldMap, newRetryCreationPos, mapPos, isPerfExperimentOn) {
|
|
50
60
|
var resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
|
|
51
61
|
|
|
@@ -175,6 +185,43 @@ export var getDeleteMechanism = function getDeleteMechanism(tr, state) {
|
|
|
175
185
|
var isNodeSelected = selection instanceof NodeSelection && ((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type.name) === 'bodiedSyncBlock';
|
|
176
186
|
return isNodeSelected ? 'selectionReplaced' : 'keyboardDelete';
|
|
177
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* True when a source `bodiedSyncBlock` holds user content — i.e. not just the
|
|
190
|
+
* single empty paragraph it is created with (used to detect empty→content).
|
|
191
|
+
*/
|
|
192
|
+
var bodiedSyncBlockHasContent = function bodiedSyncBlockHasContent(node) {
|
|
193
|
+
if (node.childCount === 0) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (node.childCount === 1) {
|
|
197
|
+
var child = node.firstChild;
|
|
198
|
+
// A freshly-created block is a single empty paragraph; anything else
|
|
199
|
+
// (non-empty paragraph, or a different/first block) counts as content.
|
|
200
|
+
return !((child === null || child === void 0 ? void 0 : child.type.name) === 'paragraph' && child.content.size === 0);
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Ask the store manager to fire the one-shot first-content-added event for every
|
|
207
|
+
* populated source block. The manager only emits for blocks it created empty
|
|
208
|
+
* this session and dedupes per block, so iterating all populated blocks is safe
|
|
209
|
+
* and self-limiting. Called only when `hasEditInSyncBlock` flagged an in-block
|
|
210
|
+
* edit, so this walk runs rarely.
|
|
211
|
+
*/
|
|
212
|
+
var emitFirstContentAddedForEditedBlocks = function emitFirstContentAddedForEditedBlocks(tr, state, syncBlockStore) {
|
|
213
|
+
var bodiedSyncBlock = state.schema.nodes.bodiedSyncBlock;
|
|
214
|
+
tr.doc.descendants(function (node) {
|
|
215
|
+
if (node.type === bodiedSyncBlock) {
|
|
216
|
+
if (bodiedSyncBlockHasContent(node)) {
|
|
217
|
+
syncBlockStore.sourceManager.maybeEmitFirstContentAdded(node.attrs.resourceId, node.attrs.localId);
|
|
218
|
+
}
|
|
219
|
+
// bodiedSyncBlocks are top-level and not nested, so no need to descend.
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
});
|
|
224
|
+
};
|
|
178
225
|
var filterTransactionOnline = function filterTransactionOnline(_ref3) {
|
|
179
226
|
var _tr$getMeta;
|
|
180
227
|
var tr = _ref3.tr,
|
|
@@ -255,9 +302,20 @@ var filterTransactionOnline = function filterTransactionOnline(_ref3) {
|
|
|
255
302
|
if (isPasteOrDrop && fg('platform_synced_block_patch_13')) {
|
|
256
303
|
return true;
|
|
257
304
|
}
|
|
258
|
-
|
|
305
|
+
|
|
306
|
+
// Forward creation-type signals captured by createSyncedBlock onto the async
|
|
307
|
+
// `syncedBlockCreate` success event.
|
|
308
|
+
var creationMeta = tr.getMeta(creationMetaKey);
|
|
309
|
+
handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, state, api, creationMeta);
|
|
259
310
|
return true;
|
|
260
311
|
}
|
|
312
|
+
|
|
313
|
+
// On an in-block edit, let the store manager fire the one-shot first-content
|
|
314
|
+
// event (dedupe + empty→content scoping live there). After the add/remove
|
|
315
|
+
// branches so it never runs for the creation transaction itself.
|
|
316
|
+
if (hasEditInSyncBlock(tr, state)) {
|
|
317
|
+
emitFirstContentAddedForEditedBlocks(tr, state, syncBlockStore);
|
|
318
|
+
}
|
|
261
319
|
showExtensionInSyncBlockWarningIfNeeded(tr, state, api, extensionFlagShown);
|
|
262
320
|
return true;
|
|
263
321
|
};
|
|
@@ -67,9 +67,12 @@ var buildRevertCreationTr = function buildRevertCreationTr(tr, pos) {
|
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
*
|
|
70
|
-
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow
|
|
70
|
+
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow.
|
|
71
|
+
*
|
|
72
|
+
* @param enrichment optional creation-type signals from `createSyncedBlock`,
|
|
73
|
+
* forwarded to the store manager to attach to the `syncedBlockCreate` event.
|
|
71
74
|
*/
|
|
72
|
-
export var handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, editorState, api) {
|
|
75
|
+
export var handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, editorState, api, enrichment) {
|
|
73
76
|
var syncBlockStore = syncedBlockPluginKey.getState(editorState).syncBlockStore;
|
|
74
77
|
bodiedSyncBlockAdded.forEach(function (node) {
|
|
75
78
|
if (node.from === undefined || node.to === undefined) {
|
|
@@ -130,6 +133,6 @@ export var handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreatio
|
|
|
130
133
|
});
|
|
131
134
|
});
|
|
132
135
|
}
|
|
133
|
-
});
|
|
136
|
+
}, enrichment);
|
|
134
137
|
});
|
|
135
138
|
};
|
|
@@ -101,7 +101,7 @@ export var syncedBlockPlugin = function syncedBlockPlugin(_ref2) {
|
|
|
101
101
|
copySyncedBlockReferenceToClipboard: function copySyncedBlockReferenceToClipboard(inputMethod) {
|
|
102
102
|
return copySyncedBlockReferenceToClipboardEditorCommand(syncBlockStore, inputMethod, api);
|
|
103
103
|
},
|
|
104
|
-
insertSyncedBlock: function insertSyncedBlock() {
|
|
104
|
+
insertSyncedBlock: function insertSyncedBlock(inputMethod) {
|
|
105
105
|
return function (_ref3) {
|
|
106
106
|
var _api$analytics3;
|
|
107
107
|
var tr = _ref3.tr;
|
|
@@ -111,7 +111,8 @@ export var syncedBlockPlugin = function syncedBlockPlugin(_ref2) {
|
|
|
111
111
|
return createSyncedBlock({
|
|
112
112
|
tr: tr,
|
|
113
113
|
syncBlockStore: syncBlockStore,
|
|
114
|
-
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent
|
|
114
|
+
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
|
|
115
|
+
inputMethod: inputMethod
|
|
115
116
|
}) || null;
|
|
116
117
|
};
|
|
117
118
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
3
4
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
4
5
|
import { syncBlockMessages } from '@atlaskit/editor-common/messages';
|
|
5
6
|
import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
|
|
@@ -42,7 +43,7 @@ export var CreateSyncedBlockButton = function CreateSyncedBlockButton(_ref) {
|
|
|
42
43
|
var dispatched = api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(function (_ref2) {
|
|
43
44
|
var _api$blockControls;
|
|
44
45
|
var tr = _ref2.tr;
|
|
45
|
-
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
46
|
+
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
46
47
|
tr: tr
|
|
47
48
|
});
|
|
48
49
|
if (!result) {
|
|
@@ -61,7 +62,7 @@ export var CreateSyncedBlockButton = function CreateSyncedBlockButton(_ref) {
|
|
|
61
62
|
}
|
|
62
63
|
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
|
|
63
64
|
var tr = _ref3.tr;
|
|
64
|
-
return api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
65
|
+
return api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.SYNCED_BLOCK_TB)({
|
|
65
66
|
tr: tr
|
|
66
67
|
});
|
|
67
68
|
});
|
|
@@ -56,7 +56,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref2
|
|
|
56
56
|
// stopping selection preservation — otherwise we would dispatch an
|
|
57
57
|
// effectively-empty transaction and close the menu despite nothing
|
|
58
58
|
// having been inserted.
|
|
59
|
-
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
|
|
59
|
+
var result = api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.BLOCK_MENU)({
|
|
60
60
|
tr: tr
|
|
61
61
|
});
|
|
62
62
|
if (!result) {
|
|
@@ -81,7 +81,7 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref2
|
|
|
81
81
|
|
|
82
82
|
// Legacy behaviour: insert then close the block menu as two separate executes
|
|
83
83
|
// (batching them caused selection collisions — EDITOR-2751).
|
|
84
|
-
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock());
|
|
84
|
+
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock(INPUT_METHOD.BLOCK_MENU));
|
|
85
85
|
api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || (_api$blockControls3 = _api$blockControls3.commands) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.toggleBlockMenu({
|
|
86
86
|
closeMenu: true
|
|
87
87
|
}));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import "./quick-insert.compiled.css";
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
5
6
|
import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
6
7
|
import { IconSyncBlock } from '@atlaskit/editor-common/quick-insert';
|
|
7
8
|
import Lozenge from '@atlaskit/lozenge';
|
|
@@ -40,7 +41,8 @@ export var getQuickInsertConfig = function getQuickInsertConfig(config, api, syn
|
|
|
40
41
|
tr: state.tr,
|
|
41
42
|
syncBlockStore: syncBlockStore,
|
|
42
43
|
typeAheadInsert: insert,
|
|
43
|
-
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent
|
|
44
|
+
fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
|
|
45
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT
|
|
44
46
|
});
|
|
45
47
|
},
|
|
46
48
|
testId: SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate
|
|
@@ -6,11 +6,16 @@ import type { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provid
|
|
|
6
6
|
import type { SyncedBlockPlugin } from '../syncedBlockPluginType';
|
|
7
7
|
type createSyncedBlockProps = {
|
|
8
8
|
fireAnalyticsEvent?: DispatchAnalyticsEvent;
|
|
9
|
+
/**
|
|
10
|
+
* Creating surface, stashed on the transaction to attach to the async
|
|
11
|
+
* `syncedBlockCreate` event. Optional so legacy callers still type-check.
|
|
12
|
+
*/
|
|
13
|
+
inputMethod?: INPUT_METHOD;
|
|
9
14
|
syncBlockStore: SyncBlockStoreManager;
|
|
10
15
|
tr: Transaction;
|
|
11
16
|
typeAheadInsert?: TypeAheadInsert;
|
|
12
17
|
};
|
|
13
|
-
export declare const createSyncedBlock: ({ tr, syncBlockStore, typeAheadInsert, fireAnalyticsEvent, }: createSyncedBlockProps) => false | Transaction;
|
|
18
|
+
export declare const createSyncedBlock: ({ tr, syncBlockStore, typeAheadInsert, fireAnalyticsEvent, inputMethod, }: createSyncedBlockProps) => false | Transaction;
|
|
14
19
|
export declare const copySyncedBlockReferenceToClipboardEditorCommand: (syncBlockStore: SyncBlockStoreManager, inputMethod: INPUT_METHOD, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => EditorCommand;
|
|
15
20
|
export declare const copySyncedBlockReferenceToClipboard: (syncBlockStore: SyncBlockStoreManager, inputMethod: INPUT_METHOD, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
16
21
|
export declare const editSyncedBlockSource: (syncBlockStore: SyncBlockStoreManager, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
1
2
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
3
|
import type { ExtractInjectionAPI, PMPluginFactoryParams } from '@atlaskit/editor-common/types';
|
|
3
4
|
import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
@@ -18,6 +19,18 @@ export declare const syncedBlockPluginKey: PluginKey;
|
|
|
18
19
|
* `platform_editor_blocks_patch_4`.
|
|
19
20
|
*/
|
|
20
21
|
export declare const deleteMechanismMetaKey: PluginKey<DeletionMechanism>;
|
|
22
|
+
/**
|
|
23
|
+
* Creation-type signals set by {@link createSyncedBlock} on the creating
|
|
24
|
+
* transaction. The async creation handler forwards them to the store manager,
|
|
25
|
+
* which attaches them to the `syncedBlockCreate` event. A dedicated key keeps
|
|
26
|
+
* this transient signal isolated from plugin state. Consumed behind
|
|
27
|
+
* `platform_editor_blocks_patch_4`.
|
|
28
|
+
*/
|
|
29
|
+
export type SyncedBlockCreationMeta = {
|
|
30
|
+
createdEmpty?: boolean;
|
|
31
|
+
inputMethod?: INPUT_METHOD;
|
|
32
|
+
};
|
|
33
|
+
export declare const creationMetaKey: PluginKey<SyncedBlockCreationMeta>;
|
|
21
34
|
type SyncedBlockPluginState = {
|
|
22
35
|
activeFlag: ActiveFlag;
|
|
23
36
|
bodiedSyncBlockDeletionStatus?: BodiedSyncBlockDeletionStatus;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
2
|
import type { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import type { CreateSuccessEnrichment } from '@atlaskit/editor-synced-block-provider/errorHandling';
|
|
3
4
|
import type { SyncedBlockPlugin } from '../../syncedBlockPluginType';
|
|
4
5
|
import type { SyncBlockInfo } from '../../types';
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
7
|
-
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow
|
|
8
|
+
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow.
|
|
9
|
+
*
|
|
10
|
+
* @param enrichment optional creation-type signals from `createSyncedBlock`,
|
|
11
|
+
* forwarded to the store manager to attach to the `syncedBlockCreate` event.
|
|
8
12
|
*/
|
|
9
|
-
export declare const handleBodiedSyncBlockCreation: (bodiedSyncBlockAdded: SyncBlockInfo[], editorState: EditorState, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined) => void;
|
|
13
|
+
export declare const handleBodiedSyncBlockCreation: (bodiedSyncBlockAdded: SyncBlockInfo[], editorState: EditorState, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined, enrichment?: CreateSuccessEnrichment) => void;
|
|
@@ -85,7 +85,12 @@ export type SyncedBlockPlugin = NextEditorPlugin<'syncedBlock', {
|
|
|
85
85
|
};
|
|
86
86
|
commands: {
|
|
87
87
|
copySyncedBlockReferenceToClipboard: (inputMethod: INPUT_METHOD) => EditorCommand;
|
|
88
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Insert a new source synced block. `inputMethod` records the creating
|
|
90
|
+
* surface for the `syncedBlockCreate` event; optional so existing callers
|
|
91
|
+
* keep working.
|
|
92
|
+
*/
|
|
93
|
+
insertSyncedBlock: (inputMethod?: INPUT_METHOD) => EditorCommand;
|
|
89
94
|
};
|
|
90
95
|
dependencies: [
|
|
91
96
|
SelectionPlugin,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-synced-block",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.2.0",
|
|
4
4
|
"description": "SyncedBlock plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@atlaskit/editor-plugin-user-intent": "^10.0.0",
|
|
36
36
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
37
37
|
"@atlaskit/editor-shared-styles": "^4.0.0",
|
|
38
|
-
"@atlaskit/editor-synced-block-provider": "^8.
|
|
38
|
+
"@atlaskit/editor-synced-block-provider": "^8.6.0",
|
|
39
39
|
"@atlaskit/editor-toolbar": "^2.1.0",
|
|
40
40
|
"@atlaskit/flag": "^18.1.0",
|
|
41
41
|
"@atlaskit/icon": "36.2.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@atlaskit/platform-feature-flags": "^2.0.0",
|
|
47
47
|
"@atlaskit/primitives": "^20.5.0",
|
|
48
48
|
"@atlaskit/spinner": "20.1.0",
|
|
49
|
-
"@atlaskit/tmp-editor-statsig": "^124.
|
|
49
|
+
"@atlaskit/tmp-editor-statsig": "^124.1.0",
|
|
50
50
|
"@atlaskit/tokens": "15.5.0",
|
|
51
51
|
"@atlaskit/tooltip": "^23.1.0",
|
|
52
52
|
"@atlaskit/visually-hidden": "^4.1.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"date-fns": "^2.17.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@atlaskit/editor-common": "^116.
|
|
59
|
+
"@atlaskit/editor-common": "^116.25.0",
|
|
60
60
|
"react": "^18.2.0",
|
|
61
61
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|
|
62
62
|
},
|