@atlaskit/editor-plugin-synced-block 11.0.0 → 11.0.1

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/AGENTS.md +3 -3
  2. package/CHANGELOG.md +13 -0
  3. package/dist/cjs/nodeviews/bodiedSyncedBlock.js +25 -193
  4. package/dist/cjs/nodeviews/syncedBlock.js +4 -25
  5. package/dist/cjs/pm-plugins/main.js +64 -130
  6. package/dist/cjs/pm-plugins/menu-and-toolbar-experiences.js +2 -7
  7. package/dist/cjs/pm-plugins/utils/has-synced-blocks.js +2 -2
  8. package/dist/cjs/syncedBlockPlugin.js +3 -12
  9. package/dist/es2019/nodeviews/bodiedSyncedBlock.js +9 -150
  10. package/dist/es2019/nodeviews/syncedBlock.js +3 -17
  11. package/dist/es2019/pm-plugins/main.js +65 -133
  12. package/dist/es2019/pm-plugins/menu-and-toolbar-experiences.js +2 -7
  13. package/dist/es2019/pm-plugins/utils/has-synced-blocks.js +2 -2
  14. package/dist/es2019/syncedBlockPlugin.js +3 -12
  15. package/dist/esm/nodeviews/bodiedSyncedBlock.js +24 -192
  16. package/dist/esm/nodeviews/syncedBlock.js +4 -25
  17. package/dist/esm/pm-plugins/main.js +65 -131
  18. package/dist/esm/pm-plugins/menu-and-toolbar-experiences.js +2 -7
  19. package/dist/esm/pm-plugins/utils/has-synced-blocks.js +2 -2
  20. package/dist/esm/syncedBlockPlugin.js +3 -12
  21. package/dist/types/nodeviews/bodiedSyncedBlock.d.ts +1 -13
  22. package/dist/types/pm-plugins/main.d.ts +6 -10
  23. package/dist/types/pm-plugins/utils/has-synced-blocks.d.ts +2 -2
  24. package/dist/types/types/index.d.ts +1 -2
  25. package/package.json +4 -4
  26. package/dist/cjs/ui/BodiedSyncBlockWrapper.js +0 -25
  27. package/dist/es2019/ui/BodiedSyncBlockWrapper.js +0 -19
  28. package/dist/esm/ui/BodiedSyncBlockWrapper.js +0 -18
  29. package/dist/types/ui/BodiedSyncBlockWrapper.d.ts +0 -9
@@ -2,153 +2,12 @@ import React from 'react';
2
2
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
3
  import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
4
4
  import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
5
- import ReactNodeView from '@atlaskit/editor-common/react-node-view';
6
5
  import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
7
6
  import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
8
7
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
9
8
  import { fg } from '@atlaskit/platform-feature-flags';
10
- import { BodiedSyncBlockWrapper } from '../ui/BodiedSyncBlockWrapper';
11
9
  import { SyncBlockLabel } from '../ui/SyncBlockLabel';
12
10
  import { isEmptySourceSyncBlock } from './isEmptySourceSyncBlock';
13
- const toDOMOld = () => ['div', {
14
- class: BodiedSyncBlockSharedCssClassName.content,
15
- contenteditable: true
16
- }, 0];
17
- class BodiedSyncBlockOld extends ReactNodeView {
18
- constructor(props) {
19
- super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
20
- this.api = props.api;
21
- this.syncBlockStore = props.syncBlockStore;
22
- this.handleConnectivityModeChange();
23
- this.handleViewModeChange();
24
- }
25
- updateContentEditable({
26
- contentDOM,
27
- nextConnectivityMode,
28
- nextViewMode
29
- }) {
30
- var _this$api, _this$api$connectivit, _this$api$connectivit2, _this$api$connectivit3, _this$api2, _this$api2$editorView, _this$api2$editorView2, _this$api2$editorView3;
31
- const connectivityMode = nextConnectivityMode !== null && nextConnectivityMode !== void 0 ? nextConnectivityMode : (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$connectivit = _this$api.connectivity) === null || _this$api$connectivit === void 0 ? void 0 : (_this$api$connectivit2 = _this$api$connectivit.sharedState) === null || _this$api$connectivit2 === void 0 ? void 0 : (_this$api$connectivit3 = _this$api$connectivit2.currentState()) === null || _this$api$connectivit3 === void 0 ? void 0 : _this$api$connectivit3.mode;
32
- const viewMode = nextViewMode !== null && nextViewMode !== void 0 ? nextViewMode : (_this$api2 = this.api) === null || _this$api2 === void 0 ? void 0 : (_this$api2$editorView = _this$api2.editorViewMode) === null || _this$api2$editorView === void 0 ? void 0 : (_this$api2$editorView2 = _this$api2$editorView.sharedState) === null || _this$api2$editorView2 === void 0 ? void 0 : (_this$api2$editorView3 = _this$api2$editorView2.currentState()) === null || _this$api2$editorView3 === void 0 ? void 0 : _this$api2$editorView3.mode;
33
- const isOnline = !isOfflineMode(connectivityMode);
34
- const isEditMode = viewMode !== 'view';
35
- const shouldBeEditable = isOnline && isEditMode;
36
- contentDOM === null || contentDOM === void 0 ? void 0 : contentDOM.setAttribute('contenteditable', shouldBeEditable ? 'true' : 'false');
37
- }
38
- handleConnectivityModeChange() {
39
- var _this$api3;
40
- if ((_this$api3 = this.api) !== null && _this$api3 !== void 0 && _this$api3.connectivity) {
41
- this.cleanupConnectivityModeListener = this.api.connectivity.sharedState.onChange(({
42
- nextSharedState
43
- }) => {
44
- this.updateContentEditable({
45
- contentDOM: this.contentDOM,
46
- nextConnectivityMode: nextSharedState.mode
47
- });
48
- });
49
- }
50
- }
51
- handleViewModeChange() {
52
- var _this$api4;
53
- if ((_this$api4 = this.api) !== null && _this$api4 !== void 0 && _this$api4.editorViewMode) {
54
- this.cleanupViewModeListener = this.api.editorViewMode.sharedState.onChange(({
55
- nextSharedState
56
- }) => {
57
- this.updateContentEditable({
58
- contentDOM: this.contentDOM,
59
- nextViewMode: nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.mode
60
- });
61
- });
62
- }
63
- }
64
- createDomRef() {
65
- // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
66
- const domRef = document.createElement('div');
67
- domRef.classList.add(BodiedSyncBlockSharedCssClassName.prefix);
68
- domRef.classList.toggle(BodiedSyncBlockSharedCssClassName.empty, isEmptySourceSyncBlock(this.node));
69
- return domRef;
70
- }
71
-
72
- /**
73
- * Keeps the empty marker class in sync so the source placeholder can be shown purely from
74
- * document state. See `isEmptySourceSyncBlock` for why the DOM is not used to decide this.
75
- */
76
- update(node, decorations) {
77
- const updated = super.update(node, decorations);
78
- if (updated) {
79
- // `ReactNodeView`'s `dom` getter throws rather than returning nullish once the view is
80
- // destroyed, so optional chaining here would be misleading. `super.update()` only
81
- // returns true while the view is still mounted, so the ref is guaranteed.
82
- this.dom.classList.toggle(BodiedSyncBlockSharedCssClassName.empty, isEmptySourceSyncBlock(this.node));
83
- }
84
- return updated;
85
- }
86
- render(_props, forwardRef) {
87
- var _this$api$syncedBlock, _this$api5, _this$api5$syncedBloc, _this$api5$syncedBloc2, _this$api6, _this$api6$analytics;
88
- // Use passed syncBlockStore for SSR where sharedState.currentState() is delayed
89
- const syncBlockStore = (_this$api$syncedBlock = (_this$api5 = this.api) === null || _this$api5 === void 0 ? void 0 : (_this$api5$syncedBloc = _this$api5.syncedBlock.sharedState) === null || _this$api5$syncedBloc === void 0 ? void 0 : (_this$api5$syncedBloc2 = _this$api5$syncedBloc.currentState()) === null || _this$api5$syncedBloc2 === void 0 ? void 0 : _this$api5$syncedBloc2.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : this.syncBlockStore;
90
- if (!syncBlockStore) {
91
- return null;
92
- }
93
- return /*#__PURE__*/React.createElement(ErrorBoundary, {
94
- component: ACTION_SUBJECT.SYNCED_BLOCK,
95
- dispatchAnalyticsEvent: (_this$api6 = this.api) === null || _this$api6 === void 0 ? void 0 : (_this$api6$analytics = _this$api6.analytics) === null || _this$api6$analytics === void 0 ? void 0 : _this$api6$analytics.actions.fireAnalyticsEvent,
96
- fallbackComponent: null
97
- }, /*#__PURE__*/React.createElement(BodiedSyncBlockWrapper, {
98
- ref: forwardRef,
99
- syncBlockStore: syncBlockStore,
100
- node: this.node
101
- }));
102
- }
103
- getContentDOM() {
104
- // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
105
- const {
106
- dom,
107
- contentDOM
108
- } = DOMSerializer.renderSpec(document, toDOMOld());
109
- // In SSR, the first check won't work, so fallback to nodeType check
110
- if (dom instanceof HTMLElement || dom.nodeType === 1) {
111
- this.updateContentEditable({
112
- contentDOM
113
- });
114
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
115
- return {
116
- dom: dom,
117
- contentDOM
118
- };
119
- }
120
- return undefined;
121
- }
122
- destroy() {
123
- if (this.cleanupConnectivityModeListener) {
124
- this.cleanupConnectivityModeListener();
125
- }
126
- if (this.cleanupViewModeListener) {
127
- this.cleanupViewModeListener();
128
- }
129
- }
130
- }
131
- export const bodiedSyncBlockNodeViewOld = ({
132
- pluginOptions,
133
- pmPluginFactoryParams,
134
- api,
135
- syncBlockStore
136
- }) => (node, view, getPos) => {
137
- const {
138
- portalProviderAPI,
139
- eventDispatcher
140
- } = pmPluginFactoryParams;
141
- return new BodiedSyncBlockOld({
142
- api,
143
- pluginOptions,
144
- node,
145
- view,
146
- getPos,
147
- portalProviderAPI,
148
- eventDispatcher,
149
- syncBlockStore
150
- }).init();
151
- };
152
11
  const toDOM = node => ['div', {
153
12
  class: `${BodiedSyncBlockSharedCssClassName.prefix} bodiedSyncBlockView-content-wrap`,
154
13
  localid: node.attrs.localId,
@@ -192,11 +51,11 @@ export class BodiedSyncBlock {
192
51
  }
193
52
  this.labelKey = crypto.randomUUID();
194
53
  this.nodeViewPortalProviderAPI.render(() => {
195
- var _this$api7, _this$api7$analytics;
54
+ var _this$api, _this$api$analytics;
196
55
  return /*#__PURE__*/React.createElement(ErrorBoundary, {
197
56
  component: ACTION_SUBJECT.SYNCED_BLOCK,
198
57
  componentId: ACTION_SUBJECT_ID.SYNCED_BLOCK_LABEL,
199
- dispatchAnalyticsEvent: (_this$api7 = this.api) === null || _this$api7 === void 0 ? void 0 : (_this$api7$analytics = _this$api7.analytics) === null || _this$api7$analytics === void 0 ? void 0 : _this$api7$analytics.actions.fireAnalyticsEvent,
58
+ dispatchAnalyticsEvent: (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$analytics = _this$api.analytics) === null || _this$api$analytics === void 0 ? void 0 : _this$api$analytics.actions.fireAnalyticsEvent,
200
59
  fallbackComponent: null
201
60
  }, /*#__PURE__*/React.createElement(SyncBlockLabel, {
202
61
  isSource: true,
@@ -215,17 +74,17 @@ export class BodiedSyncBlock {
215
74
  nextConnectivityMode,
216
75
  nextViewMode
217
76
  }) {
218
- var _this$api8, _this$api8$connectivi, _this$api8$connectivi2, _this$api8$connectivi3, _this$api9, _this$api9$editorView, _this$api9$editorView2, _this$api9$editorView3;
219
- const connectivityMode = nextConnectivityMode !== null && nextConnectivityMode !== void 0 ? nextConnectivityMode : (_this$api8 = this.api) === null || _this$api8 === void 0 ? void 0 : (_this$api8$connectivi = _this$api8.connectivity) === null || _this$api8$connectivi === void 0 ? void 0 : (_this$api8$connectivi2 = _this$api8$connectivi.sharedState) === null || _this$api8$connectivi2 === void 0 ? void 0 : (_this$api8$connectivi3 = _this$api8$connectivi2.currentState()) === null || _this$api8$connectivi3 === void 0 ? void 0 : _this$api8$connectivi3.mode;
220
- const viewMode = nextViewMode !== null && nextViewMode !== void 0 ? nextViewMode : (_this$api9 = this.api) === null || _this$api9 === void 0 ? void 0 : (_this$api9$editorView = _this$api9.editorViewMode) === null || _this$api9$editorView === void 0 ? void 0 : (_this$api9$editorView2 = _this$api9$editorView.sharedState) === null || _this$api9$editorView2 === void 0 ? void 0 : (_this$api9$editorView3 = _this$api9$editorView2.currentState()) === null || _this$api9$editorView3 === void 0 ? void 0 : _this$api9$editorView3.mode;
77
+ var _this$api2, _this$api2$connectivi, _this$api2$connectivi2, _this$api2$connectivi3, _this$api3, _this$api3$editorView, _this$api3$editorView2, _this$api3$editorView3;
78
+ const connectivityMode = nextConnectivityMode !== null && nextConnectivityMode !== void 0 ? nextConnectivityMode : (_this$api2 = this.api) === null || _this$api2 === void 0 ? void 0 : (_this$api2$connectivi = _this$api2.connectivity) === null || _this$api2$connectivi === void 0 ? void 0 : (_this$api2$connectivi2 = _this$api2$connectivi.sharedState) === null || _this$api2$connectivi2 === void 0 ? void 0 : (_this$api2$connectivi3 = _this$api2$connectivi2.currentState()) === null || _this$api2$connectivi3 === void 0 ? void 0 : _this$api2$connectivi3.mode;
79
+ const viewMode = nextViewMode !== null && nextViewMode !== void 0 ? nextViewMode : (_this$api3 = this.api) === null || _this$api3 === void 0 ? void 0 : (_this$api3$editorView = _this$api3.editorViewMode) === null || _this$api3$editorView === void 0 ? void 0 : (_this$api3$editorView2 = _this$api3$editorView.sharedState) === null || _this$api3$editorView2 === void 0 ? void 0 : (_this$api3$editorView3 = _this$api3$editorView2.currentState()) === null || _this$api3$editorView3 === void 0 ? void 0 : _this$api3$editorView3.mode;
221
80
  const isOnline = !isOfflineMode(connectivityMode);
222
81
  const isEditMode = viewMode !== 'view';
223
82
  const shouldBeEditable = isOnline && isEditMode;
224
83
  this.contentDOM.setAttribute('contenteditable', shouldBeEditable ? 'true' : 'false');
225
84
  }
226
85
  handleConnectivityModeChange() {
227
- var _this$api0;
228
- if ((_this$api0 = this.api) !== null && _this$api0 !== void 0 && _this$api0.connectivity) {
86
+ var _this$api4;
87
+ if ((_this$api4 = this.api) !== null && _this$api4 !== void 0 && _this$api4.connectivity) {
229
88
  this.cleanupConnectivityModeListener = this.api.connectivity.sharedState.onChange(({
230
89
  nextSharedState
231
90
  }) => {
@@ -236,8 +95,8 @@ export class BodiedSyncBlock {
236
95
  }
237
96
  }
238
97
  handleViewModeChange() {
239
- var _this$api1;
240
- if ((_this$api1 = this.api) !== null && _this$api1 !== void 0 && _this$api1.editorViewMode) {
98
+ var _this$api5;
99
+ if ((_this$api5 = this.api) !== null && _this$api5 !== void 0 && _this$api5.editorViewMode) {
241
100
  this.cleanupViewModeListener = this.api.editorViewMode.sharedState.onChange(({
242
101
  nextSharedState
243
102
  }) => {
@@ -6,7 +6,6 @@ import ReactNodeView from '@atlaskit/editor-common/react-node-view';
6
6
  import { SyncBlockSharedCssClassName, SyncBlockLabelSharedCssClassName, SyncBlockActionsProvider } from '@atlaskit/editor-common/sync-block';
7
7
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
8
8
  import { fg } from '@atlaskit/platform-feature-flags';
9
- import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
10
9
  import { removeSyncedBlockAtPos } from '../editor-commands';
11
10
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
12
11
  import { SyncBlockSSRReactContextsProvider } from '../ui/SyncBlockSSRReactContextsProvider';
@@ -184,10 +183,6 @@ export class SyncBlock extends ReactNodeView {
184
183
  return null;
185
184
  }
186
185
 
187
- // Use expValEqualsNoExposure — the exposure is already fired once at plugin
188
- // creation time in syncedBlockPlugin.tsx and main.ts createPlugin().
189
- const isPerfEnabled = expValEqualsNoExposure('editor_synced_block_perf', 'isEnabled', true);
190
-
191
186
  // get document node from data provider
192
187
  return /*#__PURE__*/React.createElement(SyncBlockSSRReactContextsProvider, {
193
188
  intl: this.intl
@@ -195,18 +190,9 @@ export class SyncBlock extends ReactNodeView {
195
190
  component: ACTION_SUBJECT.SYNCED_BLOCK,
196
191
  dispatchAnalyticsEvent: (_this$api3 = this.api) === null || _this$api3 === void 0 ? void 0 : (_this$api3$analytics = _this$api3.analytics) === null || _this$api3$analytics === void 0 ? void 0 : _this$api3$analytics.actions.fireAnalyticsEvent,
197
192
  fallbackComponent: null
198
- }, /*#__PURE__*/React.createElement(SyncBlockActionsProvider
199
- // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
200
- , {
201
- removeSyncBlock: isPerfEnabled ? this.removeSyncBlockStable : () => {
202
- const pos = getPos();
203
- if (pos !== undefined) {
204
- removeSyncedBlockAtPos(this.api, pos);
205
- }
206
- }
207
- // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
208
- ,
209
- fetchSyncBlockSourceInfo: isPerfEnabled ? this.fetchSyncBlockSourceInfoStable : sourceAri => syncBlockStore.referenceManager.fetchSyncBlockSourceInfoBySourceAri(sourceAri)
193
+ }, /*#__PURE__*/React.createElement(SyncBlockActionsProvider, {
194
+ removeSyncBlock: this.removeSyncBlockStable,
195
+ fetchSyncBlockSourceInfo: this.fetchSyncBlockSourceInfoStable
210
196
  }, /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
211
197
  localId: localId,
212
198
  resourceId: resourceId,
@@ -12,10 +12,8 @@ import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
12
12
  import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/editor-synced-block-provider';
13
13
  import { getSourceProductFromResourceIdSafe } from '@atlaskit/editor-synced-block-provider/utils';
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
16
15
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
17
- import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
18
- import { bodiedSyncBlockNodeView, bodiedSyncBlockNodeViewOld } from '../nodeviews/bodiedSyncedBlock';
16
+ import { bodiedSyncBlockNodeView } from '../nodeviews/bodiedSyncedBlock';
19
17
  import { SyncBlock as SyncBlockView } from '../nodeviews/syncedBlock';
20
18
  import { FLAG_ID } from '../types';
21
19
  import { handleBodiedSyncBlockCreation } from './utils/handle-bodied-sync-block-creation';
@@ -49,13 +47,13 @@ const syncedBlockPromptedFeedbackMetaKey = new PluginKey('syncedBlockPromptedFee
49
47
  */
50
48
 
51
49
  export const creationMetaKey = new PluginKey('syncedBlockCreationMeta');
52
- const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos, isPerfExperimentOn) => {
50
+ const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos) => {
53
51
  const resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
54
52
 
55
53
  // Fast path: no new entry and nothing to remap — return the same reference.
56
54
  // This is critical for PR-E (EDITOR-6929) which relies on reference equality
57
55
  // to short-circuit SharedStateAPI deep-equality checks.
58
- if (isPerfExperimentOn && !resourceId && oldMap.size === 0) {
56
+ if (!resourceId && oldMap.size === 0) {
59
57
  return oldMap;
60
58
  }
61
59
  const newMap = new Map(oldMap);
@@ -574,12 +572,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
574
572
  const {
575
573
  useLongPressSelection = false
576
574
  } = options || {};
577
-
578
- // Cache the experiment value once at plugin creation time.
579
- // This fires the exposure event exactly once (correct per Exposure Events 101)
580
- // and avoids ~10 redundant Statsig SDK evaluations per keystroke in hot paths
581
- // (apply, filterTransaction, appendTransaction, decorations).
582
- const isPerfExperimentOn = expValEquals('editor_synced_block_perf', 'isEnabled', true);
583
575
  const ctx = new SyncedBlockPluginContext(options === null || options === void 0 ? void 0 : options.onGiveFeedback, options === null || options === void 0 ? void 0 : options.shouldShowFeedbackPrompt, api);
584
576
  const confirmationTransactionRef = ctx.confirmationTransactionRef;
585
577
  const unpublishedFlagShown = ctx.unpublishedFlagShown;
@@ -634,11 +626,11 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
634
626
  state: {
635
627
  init(_, instance) {
636
628
  var _api$connectivity2, _api$connectivity2$sh, _api$editorViewMode, _api$editorViewMode$s, _api$userIntent, _api$userIntent$share;
637
- // When `editor_synced_block_perf` is ON and the document has no
638
- // synced blocks, we skip the eager fetch + cache walks. They will be
639
- // re-run lazily by `apply` the first time a synced block enters the
640
- // document (paste, collab insert, or programmatic insert).
641
- const docHasSyncedBlocks = isPerfExperimentOn ? hasSyncedBlocks(instance.doc) : true;
629
+ // When the document has no synced blocks, we skip the eager fetch +
630
+ // cache walks. They will be re-run lazily by `apply` the first time a
631
+ // synced block enters the document (paste, collab insert, or
632
+ // programmatic insert).
633
+ const docHasSyncedBlocks = hasSyncedBlocks(instance.doc);
642
634
  if (docHasSyncedBlocks) {
643
635
  const syncBlockNodes = instance.doc.children.filter(syncBlockStore.referenceManager.isReferenceBlock);
644
636
  syncBlockStore.referenceManager.fetchSyncBlocksData(convertPMNodesToSyncBlockNodes(syncBlockNodes));
@@ -664,7 +656,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
664
656
  // When the perf gate is ON and the doc has synced blocks we do a
665
657
  // single traversal here; afterwards `apply()` will map or rebuild
666
658
  // only when a status signal changes.
667
- const initStatusDecorationSet = docHasSyncedBlocks && isPerfExperimentOn ? buildStatusDecorations(instance.doc, syncBlockStore, initIsOffline, initIsViewMode, initIsDragging) : DecorationSet.empty;
659
+ const initStatusDecorationSet = docHasSyncedBlocks ? buildStatusDecorations(instance.doc, syncBlockStore, initIsOffline, initIsViewMode, initIsDragging) : DecorationSet.empty;
668
660
  return {
669
661
  selectionDecorationSet: calculateDecorations(instance.doc, instance.selection, instance.schema),
670
662
  activeFlag: false,
@@ -681,8 +673,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
681
673
  apply: (tr, currentPluginState, oldEditorState) => {
682
674
  var _api$userIntent2, _api$userIntent2$shar, _api$connectivity3, _api$connectivity3$sh, _api$editorViewMode2, _api$editorViewMode2$, _meta$activeFlag, _meta$bodiedSyncBlock;
683
675
  const meta = tr.getMeta(syncedBlockPluginKey);
684
- // isPerfExperimentOn is cached at createPlugin() level — see above
685
-
686
676
  const {
687
677
  activeFlag,
688
678
  selectionDecorationSet,
@@ -714,14 +704,14 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
714
704
  // status decoration rebuilds (e.g. drag border). Without this check the
715
705
  // fast path would swallow drag-start transactions and the synced block
716
706
  // border would never appear (see VR test: synced-block-drag-selection).
717
- if (isPerfExperimentOn && !meta && !tr.docChanged && tr.selection.eq(oldEditorState.selection) && nextHasUnsavedBodiedSyncBlockChanges === currentPluginState.hasUnsavedBodiedSyncBlockChanges && (api === null || api === void 0 ? void 0 : (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : (_api$userIntent2$shar = _api$userIntent2.sharedState.currentState()) === null || _api$userIntent2$shar === void 0 ? void 0 : _api$userIntent2$shar.currentUserIntent) === 'dragging' === prevDragging && isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity3 = api.connectivity) === null || _api$connectivity3 === void 0 ? void 0 : (_api$connectivity3$sh = _api$connectivity3.sharedState.currentState()) === null || _api$connectivity3$sh === void 0 ? void 0 : _api$connectivity3$sh.mode) === prevOffline && (api === null || api === void 0 ? void 0 : (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : (_api$editorViewMode2$ = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2$ === void 0 ? void 0 : _api$editorViewMode2$.mode) === 'view' === prevViewMode) {
707
+ if (!meta && !tr.docChanged && tr.selection.eq(oldEditorState.selection) && nextHasUnsavedBodiedSyncBlockChanges === currentPluginState.hasUnsavedBodiedSyncBlockChanges && (api === null || api === void 0 ? void 0 : (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : (_api$userIntent2$shar = _api$userIntent2.sharedState.currentState()) === null || _api$userIntent2$shar === void 0 ? void 0 : _api$userIntent2$shar.currentUserIntent) === 'dragging' === prevDragging && isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity3 = api.connectivity) === null || _api$connectivity3 === void 0 ? void 0 : (_api$connectivity3$sh = _api$connectivity3.sharedState.currentState()) === null || _api$connectivity3$sh === void 0 ? void 0 : _api$connectivity3$sh.mode) === prevOffline && (api === null || api === void 0 ? void 0 : (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : (_api$editorViewMode2$ = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2$ === void 0 ? void 0 : _api$editorViewMode2$.mode) === 'view' === prevViewMode) {
718
708
  return currentPluginState;
719
709
  }
720
710
 
721
711
  // Lazy-init bookkeeping: once a synced block enters the document we
722
712
  // flip `hasSyncedBlocks` to `true` for the lifetime of this editor
723
713
  let nextHasSyncedBlocks = prevHasSyncedBlocks;
724
- if (!prevHasSyncedBlocks && tr.docChanged && isPerfExperimentOn) {
714
+ if (!prevHasSyncedBlocks && tr.docChanged) {
725
715
  if (transactionInsertsSyncedBlock(tr)) {
726
716
  nextHasSyncedBlocks = true;
727
717
  }
@@ -749,42 +739,40 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
749
739
  let nextIsOffline = prevOffline;
750
740
  let nextIsViewMode = prevViewMode;
751
741
  let nextIsDragging = prevDragging;
752
- if (isPerfExperimentOn) {
753
- if (!nextHasSyncedBlocks) {
754
- // No synced blocks → keep empty status decorations
755
- nextStatusDecorationSet = DecorationSet.empty;
756
- } else {
757
- var _api$connectivity4, _api$connectivity4$sh, _api$editorViewMode3, _api$editorViewMode3$, _api$userIntent3, _api$userIntent3$shar;
758
- // Read current shared-state signals
759
- nextIsOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity4 = api.connectivity) === null || _api$connectivity4 === void 0 ? void 0 : (_api$connectivity4$sh = _api$connectivity4.sharedState.currentState()) === null || _api$connectivity4$sh === void 0 ? void 0 : _api$connectivity4$sh.mode);
760
- nextIsViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 ? void 0 : (_api$editorViewMode3$ = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3$ === void 0 ? void 0 : _api$editorViewMode3$.mode) === 'view';
761
- nextIsDragging = (api === null || api === void 0 ? void 0 : (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 ? void 0 : (_api$userIntent3$shar = _api$userIntent3.sharedState.currentState()) === null || _api$userIntent3$shar === void 0 ? void 0 : _api$userIntent3$shar.currentUserIntent) === 'dragging';
742
+ if (!nextHasSyncedBlocks) {
743
+ // No synced blocks → keep empty status decorations
744
+ nextStatusDecorationSet = DecorationSet.empty;
745
+ } else {
746
+ var _api$connectivity4, _api$connectivity4$sh, _api$editorViewMode3, _api$editorViewMode3$, _api$userIntent3, _api$userIntent3$shar;
747
+ // Read current shared-state signals
748
+ nextIsOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity4 = api.connectivity) === null || _api$connectivity4 === void 0 ? void 0 : (_api$connectivity4$sh = _api$connectivity4.sharedState.currentState()) === null || _api$connectivity4$sh === void 0 ? void 0 : _api$connectivity4$sh.mode);
749
+ nextIsViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 ? void 0 : (_api$editorViewMode3$ = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3$ === void 0 ? void 0 : _api$editorViewMode3$.mode) === 'view';
750
+ nextIsDragging = (api === null || api === void 0 ? void 0 : (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 ? void 0 : (_api$userIntent3$shar = _api$userIntent3.sharedState.currentState()) === null || _api$userIntent3$shar === void 0 ? void 0 : _api$userIntent3$shar.currentUserIntent) === 'dragging';
762
751
 
763
- // Determine whether we need a full rebuild or a cheap map
764
- const hasSyncedBlocksJustFlipped = nextHasSyncedBlocks && !prevHasSyncedBlocks;
765
- const statusSignalChanged = nextIsOffline !== prevOffline || nextIsViewMode !== prevViewMode || nextIsDragging !== prevDragging;
766
- // Meta-driven status changes (e.g. pending creation
767
- // completed, retry creation pos updated)
768
- const hasMetaStatusChange = !!(meta !== null && meta !== void 0 && meta.retryCreationPos) || !!(meta !== null && meta !== void 0 && meta.activeFlag);
769
- if (hasSyncedBlocksJustFlipped || statusSignalChanged || hasMetaStatusChange) {
770
- // Full rebuild — a status signal changed
771
- nextStatusDecorationSet = buildStatusDecorations(tr.doc, syncBlockStore, nextIsOffline, nextIsViewMode, nextIsDragging);
772
- } else if (tr.docChanged) {
773
- // Cheap map — positions shifted but status unchanged
774
- nextStatusDecorationSet = prevStatusDecorationSet.map(tr.mapping, tr.doc);
775
- }
776
- // else: nothing changed, keep same reference
752
+ // Determine whether we need a full rebuild or a cheap map
753
+ const hasSyncedBlocksJustFlipped = nextHasSyncedBlocks && !prevHasSyncedBlocks;
754
+ const statusSignalChanged = nextIsOffline !== prevOffline || nextIsViewMode !== prevViewMode || nextIsDragging !== prevDragging;
755
+ // Meta-driven status changes (e.g. pending creation
756
+ // completed, retry creation pos updated)
757
+ const hasMetaStatusChange = !!(meta !== null && meta !== void 0 && meta.retryCreationPos) || !!(meta !== null && meta !== void 0 && meta.activeFlag);
758
+ if (hasSyncedBlocksJustFlipped || statusSignalChanged || hasMetaStatusChange) {
759
+ // Full rebuild — a status signal changed
760
+ nextStatusDecorationSet = buildStatusDecorations(tr.doc, syncBlockStore, nextIsOffline, nextIsViewMode, nextIsDragging);
761
+ } else if (tr.docChanged) {
762
+ // Cheap map — positions shifted but status unchanged
763
+ nextStatusDecorationSet = prevStatusDecorationSet.map(tr.mapping, tr.doc);
777
764
  }
765
+ // else: nothing changed, keep same reference
778
766
  }
779
767
  const newPosEntry = meta === null || meta === void 0 ? void 0 : meta.retryCreationPos;
780
- const newRetryCreationPosMap = mapRetryCreationPosMap(retryCreationPosMap, newPosEntry, tr.mapping.map.bind(tr.mapping), isPerfExperimentOn);
768
+ const newRetryCreationPosMap = mapRetryCreationPosMap(retryCreationPosMap, newPosEntry, tr.mapping.map.bind(tr.mapping));
781
769
  const nextActiveFlag = (_meta$activeFlag = meta === null || meta === void 0 ? void 0 : meta.activeFlag) !== null && _meta$activeFlag !== void 0 ? _meta$activeFlag : activeFlag;
782
770
  const nextBodiedSyncBlockDeletionStatus = (_meta$bodiedSyncBlock = meta === null || meta === void 0 ? void 0 : meta.bodiedSyncBlockDeletionStatus) !== null && _meta$bodiedSyncBlock !== void 0 ? _meta$bodiedSyncBlock : bodiedSyncBlockDeletionStatus;
783
771
 
784
772
  // --- Reference equality (EDITOR-6929): return the same object
785
773
  // when ALL fields are reference-equal to avoid SharedStateAPI
786
774
  // notifying subscribers and triggering React re-renders. ---
787
- if (nextActiveFlag === activeFlag && newDecorationSet === selectionDecorationSet && newRetryCreationPosMap === retryCreationPosMap && nextHasSyncedBlocks === prevHasSyncedBlocks && nextBodiedSyncBlockDeletionStatus === bodiedSyncBlockDeletionStatus && nextHasUnsavedBodiedSyncBlockChanges === currentPluginState.hasUnsavedBodiedSyncBlockChanges && nextStatusDecorationSet === prevStatusDecorationSet && nextIsOffline === prevOffline && nextIsViewMode === prevViewMode && nextIsDragging === prevDragging && isPerfExperimentOn) {
775
+ if (nextActiveFlag === activeFlag && newDecorationSet === selectionDecorationSet && newRetryCreationPosMap === retryCreationPosMap && nextHasSyncedBlocks === prevHasSyncedBlocks && nextBodiedSyncBlockDeletionStatus === bodiedSyncBlockDeletionStatus && nextHasUnsavedBodiedSyncBlockChanges === currentPluginState.hasUnsavedBodiedSyncBlockChanges && nextStatusDecorationSet === prevStatusDecorationSet && nextIsOffline === prevOffline && nextIsViewMode === prevViewMode && nextIsDragging === prevDragging) {
788
776
  return currentPluginState;
789
777
  }
790
778
  return {
@@ -820,14 +808,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
820
808
  syncBlockStore: syncBlockStore,
821
809
  intl: pmPluginFactoryParams.getIntl()
822
810
  }).init(),
823
- bodiedSyncBlock: editorExperiment('platform_synced_block_use_new_source_nodeview', true, {
824
- exposure: true
825
- }) ? bodiedSyncBlockNodeView({
826
- pluginOptions: options,
827
- pmPluginFactoryParams,
828
- api,
829
- syncBlockStore
830
- }) : bodiedSyncBlockNodeViewOld({
811
+ bodiedSyncBlock: bodiedSyncBlockNodeView({
831
812
  pluginOptions: options,
832
813
  pmPluginFactoryParams,
833
814
  api,
@@ -835,6 +816,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
835
816
  })
836
817
  },
837
818
  decorations: state => {
819
+ var _api$focus$sharedStat, _api$focus, _api$focus$sharedStat2, _api$focus$sharedStat3;
838
820
  const currentPluginState = syncedBlockPluginKey.getState(state);
839
821
  if (!currentPluginState) {
840
822
  return DecorationSet.empty;
@@ -850,70 +832,24 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
850
832
  // `apply()`. The `decorations` prop is now an O(1) merge of
851
833
  // the two cached sets — no `doc.descendants()` walk, no
852
834
  // shared-state reads.
853
- if (isPerfExperimentOn) {
854
- var _api$focus$sharedStat, _api$focus, _api$focus$sharedStat2, _api$focus$sharedStat3;
855
- if (!docHasSyncedBlocks) {
856
- return selectionDecorationSet;
857
- }
835
+ if (!docHasSyncedBlocks) {
836
+ return selectionDecorationSet;
837
+ }
858
838
 
859
- // Focus state is read live here (single cheap read) because
860
- // it only gates whether selection decorations are included —
861
- // it does not affect the status decoration set and can change
862
- // within the same transaction cycle.
863
- const hasFocus = (_api$focus$sharedStat = api === null || api === void 0 ? void 0 : (_api$focus = api.focus) === null || _api$focus === void 0 ? void 0 : (_api$focus$sharedStat2 = _api$focus.sharedState) === null || _api$focus$sharedStat2 === void 0 ? void 0 : (_api$focus$sharedStat3 = _api$focus$sharedStat2.currentState()) === null || _api$focus$sharedStat3 === void 0 ? void 0 : _api$focus$sharedStat3.hasFocus) !== null && _api$focus$sharedStat !== void 0 ? _api$focus$sharedStat : true;
839
+ // Focus state is read live here (single cheap read) because
840
+ // it only gates whether selection decorations are included —
841
+ // it does not affect the status decoration set and can change
842
+ // within the same transaction cycle.
843
+ const hasFocus = (_api$focus$sharedStat = api === null || api === void 0 ? void 0 : (_api$focus = api.focus) === null || _api$focus === void 0 ? void 0 : (_api$focus$sharedStat2 = _api$focus.sharedState) === null || _api$focus$sharedStat2 === void 0 ? void 0 : (_api$focus$sharedStat3 = _api$focus$sharedStat2.currentState()) === null || _api$focus$sharedStat3 === void 0 ? void 0 : _api$focus$sharedStat3.hasFocus) !== null && _api$focus$sharedStat !== void 0 ? _api$focus$sharedStat : true;
864
844
 
865
- // Merge selection + status decorations.
866
- // When the editor is unfocused,
867
- // omit selection decorations (matches old behaviour).
868
- const statusDecorations = statusDecorationSet.find();
869
- if (statusDecorations.length === 0) {
870
- return hasFocus ? selectionDecorationSet : DecorationSet.empty;
871
- } else {
872
- return hasFocus ? selectionDecorationSet.add(state.doc, statusDecorations) : statusDecorationSet;
873
- }
845
+ // Merge selection + status decorations.
846
+ // When the editor is unfocused,
847
+ // omit selection decorations (matches old behaviour).
848
+ const statusDecorations = statusDecorationSet.find();
849
+ if (statusDecorations.length === 0) {
850
+ return hasFocus ? selectionDecorationSet : DecorationSet.empty;
874
851
  } else {
875
- var _api$connectivity5, _api$connectivity5$sh, _api$editorViewMode4, _api$editorViewMode4$, _api$userIntent4, _api$userIntent4$shar, _api$focus2, _api$focus2$sharedSta, _api$focus2$sharedSta2;
876
- // --- Legacy path (perf gate OFF) ---
877
- // Full `doc.descendants()` walk every transaction. Preserved
878
- // for safe rollback.
879
- const syncBlockStore = currentPluginState.syncBlockStore;
880
- const {
881
- doc
882
- } = state;
883
- const isOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity5 = api.connectivity) === null || _api$connectivity5 === void 0 ? void 0 : (_api$connectivity5$sh = _api$connectivity5.sharedState.currentState()) === null || _api$connectivity5$sh === void 0 ? void 0 : _api$connectivity5$sh.mode);
884
- const isViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode4 = api.editorViewMode) === null || _api$editorViewMode4 === void 0 ? void 0 : (_api$editorViewMode4$ = _api$editorViewMode4.sharedState.currentState()) === null || _api$editorViewMode4$ === void 0 ? void 0 : _api$editorViewMode4$.mode) === 'view';
885
- const isDragging = (api === null || api === void 0 ? void 0 : (_api$userIntent4 = api.userIntent) === null || _api$userIntent4 === void 0 ? void 0 : (_api$userIntent4$shar = _api$userIntent4.sharedState.currentState()) === null || _api$userIntent4$shar === void 0 ? void 0 : _api$userIntent4$shar.currentUserIntent) === 'dragging';
886
- const offlineDecorations = [];
887
- const viewModeDecorations = [];
888
- const loadingDecorations = [];
889
- const dragDecorations = [];
890
- state.doc.descendants((node, pos) => {
891
- if (node.type.name === 'bodiedSyncBlock' && isOffline) {
892
- offlineDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
893
- class: SyncBlockStateCssClassName.disabledClassName
894
- }));
895
- }
896
- if (syncBlockStore.isSyncBlock(node) && isViewMode) {
897
- viewModeDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
898
- class: SyncBlockStateCssClassName.viewModeClassName
899
- }));
900
- }
901
- if (node.type.name === 'bodiedSyncBlock' && syncBlockStore.sourceManager.isPendingCreation(node.attrs.resourceId)) {
902
- loadingDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
903
- class: SyncBlockStateCssClassName.creationLoadingClassName
904
- }));
905
- }
906
- if (isDragging && syncBlockStore.isSyncBlock(node)) {
907
- dragDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
908
- class: SyncBlockStateCssClassName.draggingClassName
909
- }));
910
- }
911
- });
912
- if (api !== null && api !== void 0 && (_api$focus2 = api.focus) !== null && _api$focus2 !== void 0 && (_api$focus2$sharedSta = _api$focus2.sharedState) !== null && _api$focus2$sharedSta !== void 0 && (_api$focus2$sharedSta2 = _api$focus2$sharedSta.currentState()) !== null && _api$focus2$sharedSta2 !== void 0 && _api$focus2$sharedSta2.hasFocus) {
913
- return selectionDecorationSet.add(doc, offlineDecorations).add(doc, viewModeDecorations).add(doc, loadingDecorations).add(doc, dragDecorations);
914
- } else {
915
- return DecorationSet.empty.add(doc, offlineDecorations).add(doc, viewModeDecorations).add(doc, loadingDecorations).add(doc, dragDecorations);
916
- }
852
+ return hasFocus ? selectionDecorationSet.add(state.doc, statusDecorations) : statusDecorationSet;
917
853
  }
918
854
  },
919
855
  handleClickOn: createSelectionClickHandler(['bodiedSyncBlock'], target => !!target.closest(`.${BodiedSyncBlockSharedCssClassName.prefix}`), {
@@ -1037,22 +973,20 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
1037
973
  }
1038
974
  },
1039
975
  filterTransaction: (tr, state) => {
1040
- var _api$editorViewMode5, _api$editorViewMode5$, _api$connectivity6, _api$connectivity6$sh;
976
+ var _api$editorViewMode4, _api$editorViewMode4$, _api$connectivity5, _api$connectivity5$sh;
1041
977
  // Lazy-init: when no synced block currently exists in the doc and the
1042
978
  // transaction does not insert one, all downstream filter logic is a
1043
979
  // no-op. Avoid both the shared-state reads and the `trackSyncBlocks`
1044
980
  // walks for the ~99.97% of pages that have no synced blocks.
1045
- if (isPerfExperimentOn) {
1046
- const pluginState = syncedBlockPluginKey.getState(state);
1047
- if (pluginState && !pluginState.hasSyncedBlocks && !transactionInsertsSyncedBlock(tr)) {
1048
- return true;
1049
- }
981
+ const pluginState = syncedBlockPluginKey.getState(state);
982
+ if (pluginState && !pluginState.hasSyncedBlocks && !transactionInsertsSyncedBlock(tr)) {
983
+ return true;
1050
984
  }
1051
- const viewMode = api === null || api === void 0 ? void 0 : (_api$editorViewMode5 = api.editorViewMode) === null || _api$editorViewMode5 === void 0 ? void 0 : (_api$editorViewMode5$ = _api$editorViewMode5.sharedState.currentState()) === null || _api$editorViewMode5$ === void 0 ? void 0 : _api$editorViewMode5$.mode;
985
+ const viewMode = api === null || api === void 0 ? void 0 : (_api$editorViewMode4 = api.editorViewMode) === null || _api$editorViewMode4 === void 0 ? void 0 : (_api$editorViewMode4$ = _api$editorViewMode4.sharedState.currentState()) === null || _api$editorViewMode4$ === void 0 ? void 0 : _api$editorViewMode4$.mode;
1052
986
  if (viewMode === 'view') {
1053
987
  return true;
1054
988
  }
1055
- const isOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity6 = api.connectivity) === null || _api$connectivity6 === void 0 ? void 0 : (_api$connectivity6$sh = _api$connectivity6.sharedState.currentState()) === null || _api$connectivity6$sh === void 0 ? void 0 : _api$connectivity6$sh.mode);
989
+ const isOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity5 = api.connectivity) === null || _api$connectivity5 === void 0 ? void 0 : (_api$connectivity5$sh = _api$connectivity5.sharedState.currentState()) === null || _api$connectivity5$sh === void 0 ? void 0 : _api$connectivity5$sh.mode);
1056
990
  const isConfirmedSyncBlockDeletion = Boolean(tr.getMeta('isConfirmedSyncBlockDeletion'));
1057
991
 
1058
992
  // Track newly added reference sync blocks before processing the transaction
@@ -1120,20 +1054,18 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
1120
1054
  });
1121
1055
  },
1122
1056
  appendTransaction: (trs, oldState, newState) => {
1123
- var _api$editorViewMode6, _api$editorViewMode6$;
1057
+ var _api$editorViewMode5, _api$editorViewMode5$;
1124
1058
  // Lazy-init: when neither the previous nor the new state contains a
1125
1059
  // synced block (and none of the dispatched transactions inserts one),
1126
1060
  // skip all downstream work. This is the hot path on the ~99.97% of
1127
1061
  // pages that don't use synced blocks (see EDITOR-6586).
1128
- if (isPerfExperimentOn) {
1129
- const oldPluginState = syncedBlockPluginKey.getState(oldState);
1130
- const newPluginState = syncedBlockPluginKey.getState(newState);
1131
- const hadOrHasSyncedBlocks = !!(oldPluginState !== null && oldPluginState !== void 0 && oldPluginState.hasSyncedBlocks) || !!(newPluginState !== null && newPluginState !== void 0 && newPluginState.hasSyncedBlocks);
1132
- if (!hadOrHasSyncedBlocks) {
1133
- return null;
1134
- }
1062
+ const oldPluginState = syncedBlockPluginKey.getState(oldState);
1063
+ const newPluginState = syncedBlockPluginKey.getState(newState);
1064
+ const hadOrHasSyncedBlocks = !!(oldPluginState !== null && oldPluginState !== void 0 && oldPluginState.hasSyncedBlocks) || !!(newPluginState !== null && newPluginState !== void 0 && newPluginState.hasSyncedBlocks);
1065
+ if (!hadOrHasSyncedBlocks) {
1066
+ return null;
1135
1067
  }
1136
- const viewMode = api === null || api === void 0 ? void 0 : (_api$editorViewMode6 = api.editorViewMode) === null || _api$editorViewMode6 === void 0 ? void 0 : (_api$editorViewMode6$ = _api$editorViewMode6.sharedState.currentState()) === null || _api$editorViewMode6$ === void 0 ? void 0 : _api$editorViewMode6$.mode;
1068
+ const viewMode = api === null || api === void 0 ? void 0 : (_api$editorViewMode5 = api.editorViewMode) === null || _api$editorViewMode5 === void 0 ? void 0 : (_api$editorViewMode5$ = _api$editorViewMode5.sharedState.currentState()) === null || _api$editorViewMode5$ === void 0 ? void 0 : _api$editorViewMode5$.mode;
1137
1069
  if (viewMode === 'view') {
1138
1070
  return null;
1139
1071
  }
@@ -3,7 +3,6 @@ import { ACTION, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
3
  import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getNodeQuery, getPopupContainerFromEditorView, popupWithNestedElement, getSelectionAncestorDOM } from '@atlaskit/editor-common/experiences';
4
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
6
  import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
8
7
  import { syncedBlockPluginKey } from './main';
9
8
  const TIMEOUT_DURATION = 30000;
@@ -14,10 +13,6 @@ export const getMenuAndToolbarExperiencesPlugin = ({
14
13
  refs,
15
14
  dispatchAnalyticsEvent
16
15
  }) => {
17
- // Cache the experiment value once at plugin creation time.
18
- // This fires the exposure event exactly once (correct per Exposure Events 101)
19
- // and avoids redundant Statsig SDK evaluations in the view() and update() hooks.
20
- const isPerfExperimentOn = expValEquals('editor_synced_block_perf', 'isEnabled', true);
21
16
  let popupsTargetEl;
22
17
  const editorViewRef = {
23
18
  current: undefined
@@ -180,13 +175,13 @@ export const getMenuAndToolbarExperiencesPlugin = ({
180
175
  unbindClickListener = unbinders.unbindClickListener;
181
176
  unbindKeydownListener = unbinders.unbindKeydownListener;
182
177
  };
183
- if ((_syncedBlockPluginKey = syncedBlockPluginKey.getState(view.state)) !== null && _syncedBlockPluginKey !== void 0 && _syncedBlockPluginKey.hasSyncedBlocks || !isPerfExperimentOn) {
178
+ if ((_syncedBlockPluginKey = syncedBlockPluginKey.getState(view.state)) !== null && _syncedBlockPluginKey !== void 0 && _syncedBlockPluginKey.hasSyncedBlocks) {
184
179
  ensureListenersBound();
185
180
  }
186
181
  return {
187
182
  update: (view, prevState) => {
188
183
  var _syncedBlockPluginKey2;
189
- if (!listenersBound && view.state.doc !== prevState.doc && (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(view.state)) !== null && _syncedBlockPluginKey2 !== void 0 && _syncedBlockPluginKey2.hasSyncedBlocks && isPerfExperimentOn) {
184
+ if (!listenersBound && view.state.doc !== prevState.doc && (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(view.state)) !== null && _syncedBlockPluginKey2 !== void 0 && _syncedBlockPluginKey2.hasSyncedBlocks) {
190
185
  // Bind listeners now that synced blocks are present.
191
186
  ensureListenersBound();
192
187
  }
@@ -4,8 +4,8 @@
4
4
  *
5
5
  * Both `syncBlock` and `bodiedSyncBlock` are top-level nodes in the schema, so
6
6
  * a single shallow scan is sufficient — no need for a recursive `descendants`
7
- * walk. This is used by the `editor_synced_block_perf` experiment to avoid
8
- * spinning up the synced block subsystem on documents that don't contain any
7
+ * walk. This is used to avoid spinning up the synced block subsystem on
8
+ * documents that don't contain any
9
9
  * synced blocks (which is ~99.97% of pages, see EDITOR-6586).
10
10
  */
11
11
  export const hasSyncedBlocks = doc => {