@atlaskit/editor-plugin-synced-block 8.3.14 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/nodeviews/bodiedSyncedBlock.js +18 -1
  3. package/dist/cjs/nodeviews/syncedBlock.js +7 -2
  4. package/dist/cjs/pm-plugins/main.js +2 -1
  5. package/dist/cjs/ui/BodiedSyncBlockWrapper.js +2 -1
  6. package/dist/cjs/ui/SyncBlockSSRReactContextsProvider.js +35 -0
  7. package/dist/cjs/ui/SyncedLocationDropdown.js +137 -35
  8. package/dist/cjs/ui/floating-toolbar.js +3 -2
  9. package/dist/es2019/nodeviews/bodiedSyncedBlock.js +18 -1
  10. package/dist/es2019/nodeviews/syncedBlock.js +7 -2
  11. package/dist/es2019/pm-plugins/main.js +2 -1
  12. package/dist/es2019/ui/BodiedSyncBlockWrapper.js +2 -1
  13. package/dist/es2019/ui/SyncBlockSSRReactContextsProvider.js +29 -0
  14. package/dist/es2019/ui/SyncedLocationDropdown.js +109 -10
  15. package/dist/es2019/ui/floating-toolbar.js +3 -2
  16. package/dist/esm/nodeviews/bodiedSyncedBlock.js +18 -1
  17. package/dist/esm/nodeviews/syncedBlock.js +7 -2
  18. package/dist/esm/pm-plugins/main.js +2 -1
  19. package/dist/esm/ui/BodiedSyncBlockWrapper.js +2 -1
  20. package/dist/esm/ui/SyncBlockSSRReactContextsProvider.js +28 -0
  21. package/dist/esm/ui/SyncedLocationDropdown.js +138 -36
  22. package/dist/esm/ui/floating-toolbar.js +3 -2
  23. package/dist/types/nodeviews/syncedBlock.d.ts +3 -0
  24. package/dist/types/ui/SyncBlockSSRReactContextsProvider.d.ts +19 -0
  25. package/dist/types/ui/SyncedLocationDropdown.d.ts +3 -2
  26. package/dist/types-ts4.5/nodeviews/syncedBlock.d.ts +3 -0
  27. package/dist/types-ts4.5/ui/SyncBlockSSRReactContextsProvider.d.ts +19 -0
  28. package/dist/types-ts4.5/ui/SyncedLocationDropdown.d.ts +3 -2
  29. package/package.json +11 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 8.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`6644994a61d9c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6644994a61d9c) -
8
+ Add editor-positioned dropdown support for custom floating toolbar items
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
14
+ ## 8.3.15
15
+
16
+ ### Patch Changes
17
+
18
+ - [`1c77cce42b15b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1c77cce42b15b) -
19
+ Updated sync blocks to support ssr streaming
20
+ - Updated dependencies
21
+
3
22
  ## 8.3.14
4
23
 
5
24
  ### Patch Changes
@@ -12,11 +12,13 @@ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/ge
12
12
  var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
13
13
  var _react = _interopRequireDefault(require("react"));
14
14
  var _analytics = require("@atlaskit/editor-common/analytics");
15
+ var _coreUtils = require("@atlaskit/editor-common/core-utils");
15
16
  var _errorBoundary = require("@atlaskit/editor-common/error-boundary");
16
17
  var _reactNodeView = _interopRequireDefault(require("@atlaskit/editor-common/react-node-view"));
17
18
  var _syncBlock = require("@atlaskit/editor-common/sync-block");
18
19
  var _editorPluginConnectivity = require("@atlaskit/editor-plugin-connectivity");
19
20
  var _model = require("@atlaskit/editor-prosemirror/model");
21
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
20
22
  var _BodiedSyncBlockWrapper = require("../ui/BodiedSyncBlockWrapper");
21
23
  var _SyncBlockLabel = require("../ui/SyncBlockLabel");
22
24
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
@@ -86,6 +88,7 @@ var BodiedSyncBlockOld = /*#__PURE__*/function (_ReactNodeView) {
86
88
  }, {
87
89
  key: "createDomRef",
88
90
  value: function createDomRef() {
91
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
89
92
  var domRef = document.createElement('div');
90
93
  domRef.classList.add(_syncBlock.BodiedSyncBlockSharedCssClassName.prefix);
91
94
  return domRef;
@@ -112,6 +115,7 @@ var BodiedSyncBlockOld = /*#__PURE__*/function (_ReactNodeView) {
112
115
  }, {
113
116
  key: "getContentDOM",
114
117
  value: function getContentDOM() {
118
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
115
119
  var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOMOld()),
116
120
  dom = _DOMSerializer$render.dom,
117
121
  contentDOM = _DOMSerializer$render.contentDOM;
@@ -179,6 +183,7 @@ var BodiedSyncBlock = exports.BodiedSyncBlock = /*#__PURE__*/function () {
179
183
  this.getPos = getPos;
180
184
  this.api = api;
181
185
  this.nodeViewPortalProviderAPI = nodeViewPortalProviderAPI;
186
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
182
187
  var _DOMSerializer$render2 = _model.DOMSerializer.renderSpec(document, toDOM(this.node)),
183
188
  dom = _DOMSerializer$render2.dom,
184
189
  contentDOM = _DOMSerializer$render2.contentDOM;
@@ -186,6 +191,18 @@ var BodiedSyncBlock = exports.BodiedSyncBlock = /*#__PURE__*/function () {
186
191
  this.dom = dom;
187
192
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
188
193
  this.contentDOM = contentDOM;
194
+
195
+ // During SSR, the portal's renderToStaticMarkup + innerHTML clobbers
196
+ // contentDOM. Render the label into a separate container to prevent this.
197
+ // On client, render directly into this.dom as before.
198
+ var labelContainer;
199
+ if ((0, _coreUtils.isSSR)() && (0, _expValEquals.expValEquals)('platform_editor_editor_ssr_streaming', 'isEnabled', true)) {
200
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
201
+ labelContainer = document.createElement('div');
202
+ this.dom.appendChild(labelContainer);
203
+ } else {
204
+ labelContainer = this.dom;
205
+ }
189
206
  this.labelKey = crypto.randomUUID();
190
207
  this.nodeViewPortalProviderAPI.render(function () {
191
208
  var _this4$api;
@@ -198,7 +215,7 @@ var BodiedSyncBlock = exports.BodiedSyncBlock = /*#__PURE__*/function () {
198
215
  isSource: true,
199
216
  localId: node.attrs.localId
200
217
  }));
201
- }, this.dom, this.labelKey);
218
+ }, labelContainer, this.labelKey);
202
219
  this.updateContentEditable({});
203
220
  this.handleConnectivityModeChange();
204
221
  this.handleViewModeChange();
@@ -20,6 +20,7 @@ var _syncBlock = require("@atlaskit/editor-common/sync-block");
20
20
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
21
21
  var _editorCommands = require("../editor-commands");
22
22
  var _SyncBlockRendererWrapper = require("../ui/SyncBlockRendererWrapper");
23
+ var _SyncBlockSSRReactContextsProvider = require("../ui/SyncBlockSSRReactContextsProvider");
23
24
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
24
25
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
25
26
  function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
@@ -47,12 +48,14 @@ var SyncBlock = exports.SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
47
48
  _this.options = props.options;
48
49
  _this.api = props.api;
49
50
  _this.syncBlockStore = props.syncBlockStore;
51
+ _this.intl = props.intl;
50
52
  return _this;
51
53
  }
52
54
  (0, _inherits2.default)(SyncBlock, _ReactNodeView);
53
55
  return (0, _createClass2.default)(SyncBlock, [{
54
56
  key: "createDomRef",
55
57
  value: function createDomRef() {
58
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
56
59
  var domRef = document.createElement('div');
57
60
  domRef.classList.add(_syncBlock.SyncBlockSharedCssClassName.prefix);
58
61
  return domRef;
@@ -98,7 +101,9 @@ var SyncBlock = exports.SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
98
101
  var isPerfEnabled = (0, _expValEqualsNoExposure.expValEqualsNoExposure)('editor_synced_block_perf', 'isEnabled', true);
99
102
 
100
103
  // get document node from data provider
101
- return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
104
+ return /*#__PURE__*/_react.default.createElement(_SyncBlockSSRReactContextsProvider.SyncBlockSSRReactContextsProvider, {
105
+ intl: this.intl
106
+ }, /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
102
107
  component: _analytics.ACTION_SUBJECT.SYNCED_BLOCK,
103
108
  dispatchAnalyticsEvent: (_this$api3 = this.api) === null || _this$api3 === void 0 || (_this$api3 = _this$api3.analytics) === null || _this$api3 === void 0 ? void 0 : _this$api3.actions.fireAnalyticsEvent,
104
109
  fallbackComponent: null
@@ -123,7 +128,7 @@ var SyncBlock = exports.SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
123
128
  syncBlockStore: syncBlockStore,
124
129
  syncedBlockRenderer: (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.syncedBlockRenderer,
125
130
  api: this.api
126
- })));
131
+ }))));
127
132
  }
128
133
  }, {
129
134
  key: "destroy",
@@ -548,7 +548,8 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
548
548
  getPos: getPos,
549
549
  portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
550
550
  eventDispatcher: pmPluginFactoryParams.eventDispatcher,
551
- syncBlockStore: syncBlockStore
551
+ syncBlockStore: syncBlockStore,
552
+ intl: pmPluginFactoryParams.getIntl()
552
553
  }).init()
553
554
  );
554
555
  },
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.BodiedSyncBlockWrapper = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
+ var _reactNodeView = require("@atlaskit/editor-common/react-node-view");
9
10
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
10
11
  var _SyncBlockLabel = require("./SyncBlockLabel");
11
12
  // Delete this file when cleaning up platform_synced_block_use_new_source_nodeview
@@ -14,7 +15,7 @@ var BodiedSyncBlockWrapper = exports.BodiedSyncBlockWrapper = /*#__PURE__*/_reac
14
15
  syncBlockStore = _ref.syncBlockStore;
15
16
  // TODO: EDITOR-2429 - this should be debounced (either here or in the data provider) to avoid excessive API writes
16
17
  (0, _editorSyncedBlockProvider.useHandleContentChanges)(syncBlockStore, node);
17
- return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", {
18
+ return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_reactNodeView.NodeViewContentHole, {
18
19
  "data-testid": "bodied-sync-block-wrapper",
19
20
  ref: ref
20
21
  }), /*#__PURE__*/_react.default.createElement(_SyncBlockLabel.SyncBlockLabel, {
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SyncBlockSSRReactContextsProvider = SyncBlockSSRReactContextsProvider;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactIntl = require("react-intl");
10
+ var _coreUtils = require("@atlaskit/editor-common/core-utils");
11
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
12
+ /**
13
+ * Wraps syncBlock nodeview children with the editor's actual IntlProvider during
14
+ * SSR streaming (renderToStaticMarkup). This ensures that components using
15
+ * useIntl() — such as SyncBlockLabel, SyncedBlockLoadingState, and
16
+ * ReactRenderer's table/code-block node renderers — have a valid intl context
17
+ * and do not throw during the static render pass.
18
+ *
19
+ * Outside of SSR streaming this is a no-op passthrough.
20
+ *
21
+ * Follows the same pattern as MediaSSRReactContextsProvider.
22
+ */
23
+ function SyncBlockSSRReactContextsProvider(_ref) {
24
+ var children = _ref.children,
25
+ intl = _ref.intl;
26
+ if (!(0, _expValEquals.expValEquals)('platform_editor_editor_ssr_streaming', 'isEnabled', true) || !(0, _coreUtils.isSSR)()) {
27
+ return children;
28
+ }
29
+ if (!intl) {
30
+ return children;
31
+ }
32
+ return /*#__PURE__*/_react.default.createElement(_reactIntl.RawIntlProvider, {
33
+ value: intl
34
+ }, children);
35
+ }
@@ -22,6 +22,7 @@ var _analytics = require("@atlaskit/editor-common/analytics");
22
22
  var _messages = require("@atlaskit/editor-common/messages");
23
23
  var _syncBlock = require("@atlaskit/editor-common/sync-block");
24
24
  var _ui = require("@atlaskit/editor-common/ui");
25
+ var _uiMenu = require("@atlaskit/editor-common/ui-menu");
25
26
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
26
27
  var _icon = require("@atlaskit/icon");
27
28
  var _pageLiveDoc = _interopRequireDefault(require("@atlaskit/icon-lab/core/page-live-doc"));
@@ -36,6 +37,7 @@ var _subtasks = _interopRequireDefault(require("@atlaskit/icon/core/subtasks"));
36
37
  var _task = _interopRequireDefault(require("@atlaskit/icon/core/task"));
37
38
  var _logo = require("@atlaskit/logo");
38
39
  var _lozenge = _interopRequireDefault(require("@atlaskit/lozenge"));
40
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
39
41
  var _compiled = require("@atlaskit/primitives/compiled");
40
42
  var _spinner = _interopRequireDefault(require("@atlaskit/spinner"));
41
43
  var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
@@ -50,6 +52,7 @@ var dropdownItemStyles = null;
50
52
 
51
53
  // logo icon does not fit in ADS IconTile, hence we need custom styles to match with other icons
52
54
  var logoTileStyles = null;
55
+ var SYNCED_LOCATIONS_DROPDOWN_TEST_ID = 'synced-block-synced-locations-dropdown';
53
56
  var styles = {
54
57
  title: "_1reo15vq _18m915vq _syazazsu _1bto1l2s _o5721q9c",
55
58
  note: "_syaz1rpy _o5721q9c",
@@ -305,27 +308,133 @@ var SyncedLocationDropdown = exports.SyncedLocationDropdown = function SyncedLoc
305
308
  intl = _ref4.intl,
306
309
  isSource = _ref4.isSource,
307
310
  localId = _ref4.localId,
308
- api = _ref4.api;
311
+ api = _ref4.api,
312
+ floatingToolbarRenderContext = _ref4.floatingToolbarRenderContext;
313
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_13')) {
314
+ return /*#__PURE__*/React.createElement(EditorPositionedSyncedLocationDropdown, {
315
+ syncBlockStore: syncBlockStore,
316
+ resourceId: resourceId,
317
+ intl: intl,
318
+ isSource: isSource,
319
+ localId: localId,
320
+ api: api,
321
+ floatingToolbarRenderContext: floatingToolbarRenderContext
322
+ });
323
+ }
324
+ return /*#__PURE__*/React.createElement(LegacySyncedLocationDropdown, {
325
+ syncBlockStore: syncBlockStore,
326
+ resourceId: resourceId,
327
+ intl: intl,
328
+ isSource: isSource,
329
+ localId: localId,
330
+ api: api
331
+ });
332
+ };
333
+ var EditorPositionedSyncedLocationDropdown = function EditorPositionedSyncedLocationDropdown(_ref5) {
334
+ var syncBlockStore = _ref5.syncBlockStore,
335
+ resourceId = _ref5.resourceId,
336
+ intl = _ref5.intl,
337
+ isSource = _ref5.isSource,
338
+ localId = _ref5.localId,
339
+ api = _ref5.api,
340
+ floatingToolbarRenderContext = _ref5.floatingToolbarRenderContext;
309
341
  var formatMessage = intl.formatMessage;
310
342
  var triggerTitle = formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitle);
311
343
  var _useState = (0, _react.useState)(false),
312
344
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
313
345
  isOpen = _useState2[0],
314
346
  setIsOpen = _useState2[1];
347
+ var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
348
+ syncBlockStore: syncBlockStore,
349
+ resourceId: resourceId,
350
+ intl: intl,
351
+ isSource: isSource,
352
+ localId: localId,
353
+ api: api
354
+ }) : null;
355
+ var toggleOpen = (0, _react.useCallback)(function () {
356
+ setIsOpen(function (currentIsOpen) {
357
+ return !currentIsOpen;
358
+ });
359
+ }, []);
360
+ var closeDropdown = (0, _react.useCallback)(function () {
361
+ setIsOpen(false);
362
+ }, []);
363
+ var setDisableParentScroll = floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.setDisableParentScroll;
364
+ (0, _react.useEffect)(function () {
365
+ if (!isOpen) {
366
+ return;
367
+ }
368
+ setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(true);
369
+ return function () {
370
+ setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(false);
371
+ };
372
+ }, [isOpen, setDisableParentScroll]);
373
+ var trigger = (0, _react.useMemo)(function () {
374
+ return /*#__PURE__*/React.createElement(_ui.FloatingToolbarButton, {
375
+ areAnyNewToolbarFlagsEnabled: true,
376
+ selected: isOpen,
377
+ iconAfter: /*#__PURE__*/React.createElement(_chevronDown.default, {
378
+ color: "currentColor",
379
+ spacing: "spacious",
380
+ label: "",
381
+ size: "small"
382
+ }),
383
+ onClick: toggleOpen,
384
+ ariaHasPopup: true
385
+ }, triggerTitle);
386
+ }, [isOpen, toggleOpen, triggerTitle]);
387
+ return /*#__PURE__*/React.createElement(_uiMenu.DropdownContainer, {
388
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID,
389
+ isOpen: isOpen,
390
+ trigger: trigger,
391
+ handleClickOutside: closeDropdown,
392
+ handleEscapeKeydown: closeDropdown,
393
+ mountTo: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsMountPoint,
394
+ boundariesElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsBoundariesElement,
395
+ scrollableElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsScrollableElement
396
+ // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
397
+ ,
398
+ arrowKeyNavigationProviderOptions: {
399
+ type: _uiMenu.ArrowKeyNavigationType.MENU
400
+ }
401
+ }, content);
402
+ };
403
+ var LegacySyncedLocationDropdown = function LegacySyncedLocationDropdown(_ref6) {
404
+ var syncBlockStore = _ref6.syncBlockStore,
405
+ resourceId = _ref6.resourceId,
406
+ intl = _ref6.intl,
407
+ isSource = _ref6.isSource,
408
+ localId = _ref6.localId,
409
+ api = _ref6.api;
410
+ var formatMessage = intl.formatMessage;
411
+ var triggerTitle = formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitle);
412
+ var _useState3 = (0, _react.useState)(false),
413
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
414
+ isOpen = _useState4[0],
415
+ setIsOpen = _useState4[1];
416
+ var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
417
+ syncBlockStore: syncBlockStore,
418
+ resourceId: resourceId,
419
+ intl: intl,
420
+ isSource: isSource,
421
+ localId: localId,
422
+ api: api
423
+ }) : null;
315
424
  return /*#__PURE__*/React.createElement(_dropdownMenu.default, {
316
425
  isOpen: isOpen
317
426
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
318
427
  ,
319
- onOpenChange: function onOpenChange(_ref5) {
320
- var isOpen = _ref5.isOpen;
428
+ onOpenChange: function onOpenChange(_ref7) {
429
+ var isOpen = _ref7.isOpen;
321
430
  return setIsOpen(isOpen);
322
431
  },
323
- testId: "synced-block-synced-locations-dropdown"
432
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID
324
433
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
325
434
  ,
326
- trigger: function trigger(_ref6) {
327
- var triggerRef = _ref6.triggerRef,
328
- triggerProps = (0, _objectWithoutProperties2.default)(_ref6, _excluded);
435
+ trigger: function trigger(_ref8) {
436
+ var triggerRef = _ref8.triggerRef,
437
+ triggerProps = (0, _objectWithoutProperties2.default)(_ref8, _excluded);
329
438
  return /*#__PURE__*/React.createElement(_ui.FloatingToolbarButton, (0, _extends2.default)({
330
439
  ref: triggerRef,
331
440
  areAnyNewToolbarFlagsEnabled: true,
@@ -339,35 +448,28 @@ var SyncedLocationDropdown = exports.SyncedLocationDropdown = function SyncedLoc
339
448
  // eslint-disable-next-line react/jsx-props-no-spreading
340
449
  }, triggerProps), triggerTitle);
341
450
  }
342
- }, isOpen && /*#__PURE__*/React.createElement(DropdownContent, {
343
- syncBlockStore: syncBlockStore,
344
- resourceId: resourceId,
345
- intl: intl,
346
- isSource: isSource,
347
- localId: localId,
348
- api: api
349
- }));
451
+ }, content);
350
452
  };
351
- var DropdownContent = function DropdownContent(_ref7) {
352
- var syncBlockStore = _ref7.syncBlockStore,
353
- resourceId = _ref7.resourceId,
354
- intl = _ref7.intl,
355
- isSource = _ref7.isSource,
356
- localId = _ref7.localId,
357
- api = _ref7.api;
453
+ var DropdownContent = function DropdownContent(_ref9) {
454
+ var syncBlockStore = _ref9.syncBlockStore,
455
+ resourceId = _ref9.resourceId,
456
+ intl = _ref9.intl,
457
+ isSource = _ref9.isSource,
458
+ localId = _ref9.localId,
459
+ api = _ref9.api;
358
460
  var formatMessage = intl.formatMessage;
359
- var _useState3 = (0, _react.useState)('none'),
360
- _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
361
- fetchStatus = _useState4[0],
362
- setFetchStatus = _useState4[1];
363
- var _useState5 = (0, _react.useState)([]),
461
+ var _useState5 = (0, _react.useState)('none'),
364
462
  _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
365
- referenceData = _useState6[0],
366
- setReferenceData = _useState6[1];
463
+ fetchStatus = _useState6[0],
464
+ setFetchStatus = _useState6[1];
465
+ var _useState7 = (0, _react.useState)([]),
466
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
467
+ referenceData = _useState8[0],
468
+ setReferenceData = _useState8[1];
367
469
  (0, _react.useEffect)(function () {
368
470
  setFetchStatus('loading');
369
471
  var getReferenceData = /*#__PURE__*/function () {
370
- var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
472
+ var _ref0 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
371
473
  var response;
372
474
  return _regenerator.default.wrap(function _callee$(_context) {
373
475
  while (1) switch (_context.prev = _context.next) {
@@ -392,7 +494,7 @@ var DropdownContent = function DropdownContent(_ref7) {
392
494
  }, _callee);
393
495
  }));
394
496
  return function getReferenceData() {
395
- return _ref8.apply(this, arguments);
497
+ return _ref0.apply(this, arguments);
396
498
  };
397
499
  }();
398
500
  getReferenceData();
@@ -470,8 +572,8 @@ var DropdownContent = function DropdownContent(_ref7) {
470
572
  var LoadingScreen = function LoadingScreen() {
471
573
  return /*#__PURE__*/React.createElement(_compiled.Box, null, /*#__PURE__*/React.createElement(_spinner.default, null));
472
574
  };
473
- var ErrorScreen = function ErrorScreen(_ref9) {
474
- var formatMessage = _ref9.formatMessage;
575
+ var ErrorScreen = function ErrorScreen(_ref1) {
576
+ var formatMessage = _ref1.formatMessage;
475
577
  return /*#__PURE__*/React.createElement(_compiled.Box, {
476
578
  xcss: styles.errorContainer,
477
579
  testId: "synced-locations-dropdown-content-error"
@@ -487,8 +589,8 @@ var ErrorScreen = function ErrorScreen(_ref9) {
487
589
  size: "medium"
488
590
  }, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownError)));
489
591
  };
490
- var NoResultScreen = function NoResultScreen(_ref0) {
491
- var formatMessage = _ref0.formatMessage;
592
+ var NoResultScreen = function NoResultScreen(_ref10) {
593
+ var formatMessage = _ref10.formatMessage;
492
594
  return /*#__PURE__*/React.createElement(_compiled.Stack, {
493
595
  xcss: styles.noResultsContainer,
494
596
  space: "space.100",
@@ -69,14 +69,15 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(stat
69
69
  var syncedLocation = {
70
70
  type: 'custom',
71
71
  fallback: [],
72
- render: function render() {
72
+ render: function render(_view, _idx, _dispatchAnalyticsEvent, floatingToolbarRenderContext) {
73
73
  return /*#__PURE__*/_react.default.createElement(_SyncedLocationDropdown.SyncedLocationDropdown, {
74
74
  syncBlockStore: syncBlockStore,
75
75
  resourceId: resourceId,
76
76
  localId: localId,
77
77
  intl: intl,
78
78
  isSource: isBodiedSyncBlock,
79
- api: api
79
+ api: api,
80
+ floatingToolbarRenderContext: floatingToolbarRenderContext
80
81
  });
81
82
  }
82
83
  };
@@ -1,10 +1,12 @@
1
1
  import React from 'react';
2
2
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
+ import { isSSR } from '@atlaskit/editor-common/core-utils';
3
4
  import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
4
5
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
5
6
  import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
6
7
  import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
7
8
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
9
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
8
10
  import { BodiedSyncBlockWrapper } from '../ui/BodiedSyncBlockWrapper';
9
11
  import { SyncBlockLabel } from '../ui/SyncBlockLabel';
10
12
  const toDOMOld = () => ['div', {
@@ -59,6 +61,7 @@ class BodiedSyncBlockOld extends ReactNodeView {
59
61
  }
60
62
  }
61
63
  createDomRef() {
64
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
62
65
  const domRef = document.createElement('div');
63
66
  domRef.classList.add(BodiedSyncBlockSharedCssClassName.prefix);
64
67
  return domRef;
@@ -81,6 +84,7 @@ class BodiedSyncBlockOld extends ReactNodeView {
81
84
  }));
82
85
  }
83
86
  getContentDOM() {
87
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
84
88
  const {
85
89
  dom,
86
90
  contentDOM
@@ -143,6 +147,7 @@ export class BodiedSyncBlock {
143
147
  this.getPos = getPos;
144
148
  this.api = api;
145
149
  this.nodeViewPortalProviderAPI = nodeViewPortalProviderAPI;
150
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
146
151
  const {
147
152
  dom,
148
153
  contentDOM
@@ -151,6 +156,18 @@ export class BodiedSyncBlock {
151
156
  this.dom = dom;
152
157
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
153
158
  this.contentDOM = contentDOM;
159
+
160
+ // During SSR, the portal's renderToStaticMarkup + innerHTML clobbers
161
+ // contentDOM. Render the label into a separate container to prevent this.
162
+ // On client, render directly into this.dom as before.
163
+ let labelContainer;
164
+ if (isSSR() && expValEquals('platform_editor_editor_ssr_streaming', 'isEnabled', true)) {
165
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
166
+ labelContainer = document.createElement('div');
167
+ this.dom.appendChild(labelContainer);
168
+ } else {
169
+ labelContainer = this.dom;
170
+ }
154
171
  this.labelKey = crypto.randomUUID();
155
172
  this.nodeViewPortalProviderAPI.render(() => {
156
173
  var _this$api7, _this$api7$analytics;
@@ -163,7 +180,7 @@ export class BodiedSyncBlock {
163
180
  isSource: true,
164
181
  localId: node.attrs.localId
165
182
  }));
166
- }, this.dom, this.labelKey);
183
+ }, labelContainer, this.labelKey);
167
184
  this.updateContentEditable({});
168
185
  this.handleConnectivityModeChange();
169
186
  this.handleViewModeChange();
@@ -7,6 +7,7 @@ import { SyncBlockSharedCssClassName, SyncBlockActionsProvider } from '@atlaskit
7
7
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
8
8
  import { removeSyncedBlockAtPos } from '../editor-commands';
9
9
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
10
+ import { SyncBlockSSRReactContextsProvider } from '../ui/SyncBlockSSRReactContextsProvider';
10
11
  export class SyncBlock extends ReactNodeView {
11
12
  constructor(props) {
12
13
  super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
@@ -29,8 +30,10 @@ export class SyncBlock extends ReactNodeView {
29
30
  this.options = props.options;
30
31
  this.api = props.api;
31
32
  this.syncBlockStore = props.syncBlockStore;
33
+ this.intl = props.intl;
32
34
  }
33
35
  createDomRef() {
36
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
34
37
  const domRef = document.createElement('div');
35
38
  domRef.classList.add(SyncBlockSharedCssClassName.prefix);
36
39
  return domRef;
@@ -67,7 +70,9 @@ export class SyncBlock extends ReactNodeView {
67
70
  const isPerfEnabled = expValEqualsNoExposure('editor_synced_block_perf', 'isEnabled', true);
68
71
 
69
72
  // get document node from data provider
70
- return /*#__PURE__*/React.createElement(ErrorBoundary, {
73
+ return /*#__PURE__*/React.createElement(SyncBlockSSRReactContextsProvider, {
74
+ intl: this.intl
75
+ }, /*#__PURE__*/React.createElement(ErrorBoundary, {
71
76
  component: ACTION_SUBJECT.SYNCED_BLOCK,
72
77
  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,
73
78
  fallbackComponent: null
@@ -90,7 +95,7 @@ export class SyncBlock extends ReactNodeView {
90
95
  syncBlockStore: syncBlockStore,
91
96
  syncedBlockRenderer: (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.syncedBlockRenderer,
92
97
  api: this.api
93
- })));
98
+ }))));
94
99
  }
95
100
  destroy() {
96
101
  var _this$unsubscribe;
@@ -516,7 +516,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
516
516
  getPos,
517
517
  portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
518
518
  eventDispatcher: pmPluginFactoryParams.eventDispatcher,
519
- syncBlockStore: syncBlockStore
519
+ syncBlockStore: syncBlockStore,
520
+ intl: pmPluginFactoryParams.getIntl()
520
521
  }).init(),
521
522
  bodiedSyncBlock: editorExperiment('platform_synced_block_use_new_source_nodeview', true, {
522
523
  exposure: true
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { NodeViewContentHole } from '@atlaskit/editor-common/react-node-view';
2
3
  import { useHandleContentChanges } from '@atlaskit/editor-synced-block-provider';
3
4
  import { SyncBlockLabel } from './SyncBlockLabel';
4
5
  // Delete this file when cleaning up platform_synced_block_use_new_source_nodeview
@@ -8,7 +9,7 @@ export const BodiedSyncBlockWrapper = /*#__PURE__*/React.forwardRef(({
8
9
  }, ref) => {
9
10
  // TODO: EDITOR-2429 - this should be debounced (either here or in the data provider) to avoid excessive API writes
10
11
  useHandleContentChanges(syncBlockStore, node);
11
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
12
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(NodeViewContentHole, {
12
13
  "data-testid": "bodied-sync-block-wrapper",
13
14
  ref: ref
14
15
  }), /*#__PURE__*/React.createElement(SyncBlockLabel, {
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import { RawIntlProvider } from 'react-intl';
3
+ import { isSSR } from '@atlaskit/editor-common/core-utils';
4
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
+ /**
6
+ * Wraps syncBlock nodeview children with the editor's actual IntlProvider during
7
+ * SSR streaming (renderToStaticMarkup). This ensures that components using
8
+ * useIntl() — such as SyncBlockLabel, SyncedBlockLoadingState, and
9
+ * ReactRenderer's table/code-block node renderers — have a valid intl context
10
+ * and do not throw during the static render pass.
11
+ *
12
+ * Outside of SSR streaming this is a no-op passthrough.
13
+ *
14
+ * Follows the same pattern as MediaSSRReactContextsProvider.
15
+ */
16
+ export function SyncBlockSSRReactContextsProvider({
17
+ children,
18
+ intl
19
+ }) {
20
+ if (!expValEquals('platform_editor_editor_ssr_streaming', 'isEnabled', true) || !isSSR()) {
21
+ return children;
22
+ }
23
+ if (!intl) {
24
+ return children;
25
+ }
26
+ return /*#__PURE__*/React.createElement(RawIntlProvider, {
27
+ value: intl
28
+ }, children);
29
+ }