@atlaskit/editor-plugin-synced-block 8.3.13 → 8.3.15

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 8.3.15
4
+
5
+ ### Patch Changes
6
+
7
+ - [`1c77cce42b15b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1c77cce42b15b) -
8
+ Updated sync blocks to support ssr streaming
9
+ - Updated dependencies
10
+
11
+ ## 8.3.14
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 8.3.13
4
18
 
5
19
  ### 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
+ }
@@ -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
+ }
@@ -7,11 +7,13 @@ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstruct
7
7
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
8
8
  import React from 'react';
9
9
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
10
+ import { isSSR } from '@atlaskit/editor-common/core-utils';
10
11
  import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
11
12
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
12
13
  import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
13
14
  import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
14
15
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
16
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
15
17
  import { BodiedSyncBlockWrapper } from '../ui/BodiedSyncBlockWrapper';
16
18
  import { SyncBlockLabel } from '../ui/SyncBlockLabel';
17
19
  var toDOMOld = function toDOMOld() {
@@ -79,6 +81,7 @@ var BodiedSyncBlockOld = /*#__PURE__*/function (_ReactNodeView) {
79
81
  }, {
80
82
  key: "createDomRef",
81
83
  value: function createDomRef() {
84
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
82
85
  var domRef = document.createElement('div');
83
86
  domRef.classList.add(BodiedSyncBlockSharedCssClassName.prefix);
84
87
  return domRef;
@@ -105,6 +108,7 @@ var BodiedSyncBlockOld = /*#__PURE__*/function (_ReactNodeView) {
105
108
  }, {
106
109
  key: "getContentDOM",
107
110
  value: function getContentDOM() {
111
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
108
112
  var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOMOld()),
109
113
  dom = _DOMSerializer$render.dom,
110
114
  contentDOM = _DOMSerializer$render.contentDOM;
@@ -172,6 +176,7 @@ export var BodiedSyncBlock = /*#__PURE__*/function () {
172
176
  this.getPos = getPos;
173
177
  this.api = api;
174
178
  this.nodeViewPortalProviderAPI = nodeViewPortalProviderAPI;
179
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView serialization must target active runtime document
175
180
  var _DOMSerializer$render2 = DOMSerializer.renderSpec(document, toDOM(this.node)),
176
181
  dom = _DOMSerializer$render2.dom,
177
182
  contentDOM = _DOMSerializer$render2.contentDOM;
@@ -179,6 +184,18 @@ export var BodiedSyncBlock = /*#__PURE__*/function () {
179
184
  this.dom = dom;
180
185
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
181
186
  this.contentDOM = contentDOM;
187
+
188
+ // During SSR, the portal's renderToStaticMarkup + innerHTML clobbers
189
+ // contentDOM. Render the label into a separate container to prevent this.
190
+ // On client, render directly into this.dom as before.
191
+ var labelContainer;
192
+ if (isSSR() && expValEquals('platform_editor_editor_ssr_streaming', 'isEnabled', true)) {
193
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
194
+ labelContainer = document.createElement('div');
195
+ this.dom.appendChild(labelContainer);
196
+ } else {
197
+ labelContainer = this.dom;
198
+ }
182
199
  this.labelKey = crypto.randomUUID();
183
200
  this.nodeViewPortalProviderAPI.render(function () {
184
201
  var _this4$api;
@@ -191,7 +208,7 @@ export var BodiedSyncBlock = /*#__PURE__*/function () {
191
208
  isSource: true,
192
209
  localId: node.attrs.localId
193
210
  }));
194
- }, this.dom, this.labelKey);
211
+ }, labelContainer, this.labelKey);
195
212
  this.updateContentEditable({});
196
213
  this.handleConnectivityModeChange();
197
214
  this.handleViewModeChange();
@@ -16,6 +16,7 @@ import { SyncBlockSharedCssClassName, SyncBlockActionsProvider } from '@atlaskit
16
16
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
17
17
  import { removeSyncedBlockAtPos } from '../editor-commands';
18
18
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
19
+ import { SyncBlockSSRReactContextsProvider } from '../ui/SyncBlockSSRReactContextsProvider';
19
20
  export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
20
21
  function SyncBlock(props) {
21
22
  var _this;
@@ -40,12 +41,14 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
40
41
  _this.options = props.options;
41
42
  _this.api = props.api;
42
43
  _this.syncBlockStore = props.syncBlockStore;
44
+ _this.intl = props.intl;
43
45
  return _this;
44
46
  }
45
47
  _inherits(SyncBlock, _ReactNodeView);
46
48
  return _createClass(SyncBlock, [{
47
49
  key: "createDomRef",
48
50
  value: function createDomRef() {
51
+ // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- NodeView DOM must be created against active runtime document
49
52
  var domRef = document.createElement('div');
50
53
  domRef.classList.add(SyncBlockSharedCssClassName.prefix);
51
54
  return domRef;
@@ -91,7 +94,9 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
91
94
  var isPerfEnabled = expValEqualsNoExposure('editor_synced_block_perf', 'isEnabled', true);
92
95
 
93
96
  // get document node from data provider
94
- return /*#__PURE__*/React.createElement(ErrorBoundary, {
97
+ return /*#__PURE__*/React.createElement(SyncBlockSSRReactContextsProvider, {
98
+ intl: this.intl
99
+ }, /*#__PURE__*/React.createElement(ErrorBoundary, {
95
100
  component: ACTION_SUBJECT.SYNCED_BLOCK,
96
101
  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,
97
102
  fallbackComponent: null
@@ -116,7 +121,7 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
116
121
  syncBlockStore: syncBlockStore,
117
122
  syncedBlockRenderer: (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.syncedBlockRenderer,
118
123
  api: this.api
119
- })));
124
+ }))));
120
125
  }
121
126
  }, {
122
127
  key: "destroy",
@@ -541,7 +541,8 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
541
541
  getPos: getPos,
542
542
  portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
543
543
  eventDispatcher: pmPluginFactoryParams.eventDispatcher,
544
- syncBlockStore: syncBlockStore
544
+ syncBlockStore: syncBlockStore,
545
+ intl: pmPluginFactoryParams.getIntl()
545
546
  }).init()
546
547
  );
547
548
  },
@@ -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
@@ -7,7 +8,7 @@ export var BodiedSyncBlockWrapper = /*#__PURE__*/React.forwardRef(function (_ref
7
8
  syncBlockStore = _ref.syncBlockStore;
8
9
  // TODO: EDITOR-2429 - this should be debounced (either here or in the data provider) to avoid excessive API writes
9
10
  useHandleContentChanges(syncBlockStore, node);
10
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
11
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(NodeViewContentHole, {
11
12
  "data-testid": "bodied-sync-block-wrapper",
12
13
  ref: ref
13
14
  }), /*#__PURE__*/React.createElement(SyncBlockLabel, {
@@ -0,0 +1,28 @@
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(_ref) {
17
+ var children = _ref.children,
18
+ intl = _ref.intl;
19
+ if (!expValEquals('platform_editor_editor_ssr_streaming', 'isEnabled', true) || !isSSR()) {
20
+ return children;
21
+ }
22
+ if (!intl) {
23
+ return children;
24
+ }
25
+ return /*#__PURE__*/React.createElement(RawIntlProvider, {
26
+ value: intl
27
+ }, children);
28
+ }
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import type { IntlShape } from 'react-intl';
2
3
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
3
4
  import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
4
5
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
@@ -13,6 +14,7 @@ export interface SyncBlockNodeViewProps extends ReactComponentProps {
13
14
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
14
15
  eventDispatcher: EventDispatcher;
15
16
  getPos: getPosHandlerNode;
17
+ intl?: IntlShape;
16
18
  isNodeNested?: boolean;
17
19
  node: PMNode;
18
20
  options: SyncedBlockPluginOptions | undefined;
@@ -24,6 +26,7 @@ export declare class SyncBlock extends ReactNodeView<SyncBlockNodeViewProps> {
24
26
  private options;
25
27
  private api?;
26
28
  private syncBlockStore?;
29
+ private intl?;
27
30
  constructor(props: SyncBlockNodeViewProps);
28
31
  private removeSyncBlockStable;
29
32
  private fetchSyncBlockSourceInfoStable;
@@ -0,0 +1,19 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type IntlShape } from 'react-intl';
3
+ interface Props {
4
+ children: ReactNode;
5
+ intl: IntlShape | undefined;
6
+ }
7
+ /**
8
+ * Wraps syncBlock nodeview children with the editor's actual IntlProvider during
9
+ * SSR streaming (renderToStaticMarkup). This ensures that components using
10
+ * useIntl() — such as SyncBlockLabel, SyncedBlockLoadingState, and
11
+ * ReactRenderer's table/code-block node renderers — have a valid intl context
12
+ * and do not throw during the static render pass.
13
+ *
14
+ * Outside of SSR streaming this is a no-op passthrough.
15
+ *
16
+ * Follows the same pattern as MediaSSRReactContextsProvider.
17
+ */
18
+ export declare function SyncBlockSSRReactContextsProvider({ children, intl }: Props): ReactNode;
19
+ export {};
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import type { IntlShape } from 'react-intl';
2
3
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
3
4
  import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
4
5
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
@@ -13,6 +14,7 @@ export interface SyncBlockNodeViewProps extends ReactComponentProps {
13
14
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
14
15
  eventDispatcher: EventDispatcher;
15
16
  getPos: getPosHandlerNode;
17
+ intl?: IntlShape;
16
18
  isNodeNested?: boolean;
17
19
  node: PMNode;
18
20
  options: SyncedBlockPluginOptions | undefined;
@@ -24,6 +26,7 @@ export declare class SyncBlock extends ReactNodeView<SyncBlockNodeViewProps> {
24
26
  private options;
25
27
  private api?;
26
28
  private syncBlockStore?;
29
+ private intl?;
27
30
  constructor(props: SyncBlockNodeViewProps);
28
31
  private removeSyncBlockStable;
29
32
  private fetchSyncBlockSourceInfoStable;
@@ -0,0 +1,19 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type IntlShape } from 'react-intl';
3
+ interface Props {
4
+ children: ReactNode;
5
+ intl: IntlShape | undefined;
6
+ }
7
+ /**
8
+ * Wraps syncBlock nodeview children with the editor's actual IntlProvider during
9
+ * SSR streaming (renderToStaticMarkup). This ensures that components using
10
+ * useIntl() — such as SyncBlockLabel, SyncedBlockLoadingState, and
11
+ * ReactRenderer's table/code-block node renderers — have a valid intl context
12
+ * and do not throw during the static render pass.
13
+ *
14
+ * Outside of SSR streaming this is a no-op passthrough.
15
+ *
16
+ * Follows the same pattern as MediaSSRReactContextsProvider.
17
+ */
18
+ export declare function SyncBlockSSRReactContextsProvider({ children, intl }: Props): ReactNode;
19
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "8.3.13",
3
+ "version": "8.3.15",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,9 +28,9 @@
28
28
  "sideEffects": false,
29
29
  "atlaskit:src": "src/index.ts",
30
30
  "dependencies": {
31
- "@atlaskit/adf-schema": "^52.12.0",
32
- "@atlaskit/button": "23.11.6",
33
- "@atlaskit/dropdown-menu": "16.9.1",
31
+ "@atlaskit/adf-schema": "^52.13.0",
32
+ "@atlaskit/button": "23.11.7",
33
+ "@atlaskit/dropdown-menu": "16.9.2",
34
34
  "@atlaskit/editor-json-transformer": "^8.32.0",
35
35
  "@atlaskit/editor-plugin-analytics": "^10.1.0",
36
36
  "@atlaskit/editor-plugin-block-menu": "^9.2.0",
@@ -44,7 +44,7 @@
44
44
  "@atlaskit/editor-prosemirror": "^7.3.0",
45
45
  "@atlaskit/editor-shared-styles": "^3.11.0",
46
46
  "@atlaskit/editor-synced-block-provider": "^6.6.0",
47
- "@atlaskit/editor-toolbar": "^1.6.0",
47
+ "@atlaskit/editor-toolbar": "^1.7.0",
48
48
  "@atlaskit/flag": "^17.12.0",
49
49
  "@atlaskit/icon": "35.0.0",
50
50
  "@atlaskit/icon-lab": "^6.9.0",
@@ -54,7 +54,7 @@
54
54
  "@atlaskit/platform-feature-flags": "^1.1.0",
55
55
  "@atlaskit/primitives": "^19.0.0",
56
56
  "@atlaskit/spinner": "19.1.2",
57
- "@atlaskit/tmp-editor-statsig": "^81.3.0",
57
+ "@atlaskit/tmp-editor-statsig": "^82.3.0",
58
58
  "@atlaskit/tokens": "13.0.4",
59
59
  "@atlaskit/tooltip": "^22.2.0",
60
60
  "@atlaskit/visually-hidden": "^3.1.0",
@@ -64,11 +64,12 @@
64
64
  "date-fns": "^2.17.0"
65
65
  },
66
66
  "peerDependencies": {
67
- "@atlaskit/editor-common": "^114.36.0",
67
+ "@atlaskit/editor-common": "^114.41.0",
68
68
  "react": "^18.2.0",
69
69
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
70
70
  },
71
71
  "devDependencies": {
72
+ "react": "^18.2.0",
72
73
  "react-intl": "^6.6.2",
73
74
  "typescript": "5.9.2"
74
75
  },