@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
@@ -3,13 +3,14 @@ import _extends from "@babel/runtime/helpers/extends";
3
3
  import "./SyncedLocationDropdown.compiled.css";
4
4
  import * as React from 'react';
5
5
  import { ax, ix } from "@compiled/react/runtime";
6
- import { useEffect, useState } from 'react';
6
+ import { useCallback, useEffect, useMemo, useState } from 'react';
7
7
  import { cx } from '@compiled/react';
8
8
  import DropdownMenu, { DropdownItem, DropdownItemGroup } from '@atlaskit/dropdown-menu';
9
9
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
10
10
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
11
11
  import { SYNCED_BLOCKS_DOCUMENTATION_URL } from '@atlaskit/editor-common/sync-block';
12
12
  import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
13
+ import { ArrowKeyNavigationType, DropdownContainer } from '@atlaskit/editor-common/ui-menu';
13
14
  import { getPageIdAndTypeFromConfluencePageAri } from '@atlaskit/editor-synced-block-provider';
14
15
  import { IconTile } from '@atlaskit/icon';
15
16
  import PageLiveDocIcon from '@atlaskit/icon-lab/core/page-live-doc';
@@ -24,6 +25,7 @@ import SubtaskIcon from '@atlaskit/icon/core/subtasks';
24
25
  import TaskIcon from '@atlaskit/icon/core/task';
25
26
  import { ConfluenceIcon, JiraIcon, AtlassianIcon } from '@atlaskit/logo';
26
27
  import Lozenge from '@atlaskit/lozenge';
28
+ import { fg } from '@atlaskit/platform-feature-flags';
27
29
  import { Box, Text, Inline, Anchor, Stack } from '@atlaskit/primitives/compiled';
28
30
  import Spinner from '@atlaskit/spinner';
29
31
  import Tooltip from '@atlaskit/tooltip';
@@ -33,6 +35,7 @@ const dropdownItemStyles = null;
33
35
 
34
36
  // logo icon does not fit in ADS IconTile, hence we need custom styles to match with other icons
35
37
  const logoTileStyles = null;
38
+ const SYNCED_LOCATIONS_DROPDOWN_TEST_ID = 'synced-block-synced-locations-dropdown';
36
39
  const styles = {
37
40
  title: "_1reo15vq _18m915vq _syazazsu _1bto1l2s _o5721q9c",
38
41
  note: "_syaz1rpy _o5721q9c",
@@ -278,6 +281,101 @@ export const processReferenceData = (referenceData, intl) => {
278
281
  return sortedReferences;
279
282
  };
280
283
  export const SyncedLocationDropdown = ({
284
+ syncBlockStore,
285
+ resourceId,
286
+ intl,
287
+ isSource,
288
+ localId,
289
+ api,
290
+ floatingToolbarRenderContext
291
+ }) => {
292
+ if (fg('platform_synced_block_patch_13')) {
293
+ return /*#__PURE__*/React.createElement(EditorPositionedSyncedLocationDropdown, {
294
+ syncBlockStore: syncBlockStore,
295
+ resourceId: resourceId,
296
+ intl: intl,
297
+ isSource: isSource,
298
+ localId: localId,
299
+ api: api,
300
+ floatingToolbarRenderContext: floatingToolbarRenderContext
301
+ });
302
+ }
303
+ return /*#__PURE__*/React.createElement(LegacySyncedLocationDropdown, {
304
+ syncBlockStore: syncBlockStore,
305
+ resourceId: resourceId,
306
+ intl: intl,
307
+ isSource: isSource,
308
+ localId: localId,
309
+ api: api
310
+ });
311
+ };
312
+ const EditorPositionedSyncedLocationDropdown = ({
313
+ syncBlockStore,
314
+ resourceId,
315
+ intl,
316
+ isSource,
317
+ localId,
318
+ api,
319
+ floatingToolbarRenderContext
320
+ }) => {
321
+ const {
322
+ formatMessage
323
+ } = intl;
324
+ const triggerTitle = formatMessage(messages.syncedLocationDropdownTitle);
325
+ const [isOpen, setIsOpen] = useState(false);
326
+ const content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
327
+ syncBlockStore: syncBlockStore,
328
+ resourceId: resourceId,
329
+ intl: intl,
330
+ isSource: isSource,
331
+ localId: localId,
332
+ api: api
333
+ }) : null;
334
+ const toggleOpen = useCallback(() => {
335
+ setIsOpen(currentIsOpen => !currentIsOpen);
336
+ }, []);
337
+ const closeDropdown = useCallback(() => {
338
+ setIsOpen(false);
339
+ }, []);
340
+ const setDisableParentScroll = floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.setDisableParentScroll;
341
+ useEffect(() => {
342
+ if (!isOpen) {
343
+ return;
344
+ }
345
+ setDisableParentScroll === null || setDisableParentScroll === void 0 ? void 0 : setDisableParentScroll(true);
346
+ return () => {
347
+ setDisableParentScroll === null || setDisableParentScroll === void 0 ? void 0 : setDisableParentScroll(false);
348
+ };
349
+ }, [isOpen, setDisableParentScroll]);
350
+ const trigger = useMemo(() => /*#__PURE__*/React.createElement(Button, {
351
+ areAnyNewToolbarFlagsEnabled: true,
352
+ selected: isOpen,
353
+ iconAfter: /*#__PURE__*/React.createElement(ChevronDownIcon, {
354
+ color: "currentColor",
355
+ spacing: "spacious",
356
+ label: "",
357
+ size: "small"
358
+ }),
359
+ onClick: toggleOpen,
360
+ ariaHasPopup: true
361
+ }, triggerTitle), [isOpen, toggleOpen, triggerTitle]);
362
+ return /*#__PURE__*/React.createElement(DropdownContainer, {
363
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID,
364
+ isOpen: isOpen,
365
+ trigger: trigger,
366
+ handleClickOutside: closeDropdown,
367
+ handleEscapeKeydown: closeDropdown,
368
+ mountTo: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsMountPoint,
369
+ boundariesElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsBoundariesElement,
370
+ scrollableElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsScrollableElement
371
+ // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
372
+ ,
373
+ arrowKeyNavigationProviderOptions: {
374
+ type: ArrowKeyNavigationType.MENU
375
+ }
376
+ }, content);
377
+ };
378
+ const LegacySyncedLocationDropdown = ({
281
379
  syncBlockStore,
282
380
  resourceId,
283
381
  intl,
@@ -290,6 +388,14 @@ export const SyncedLocationDropdown = ({
290
388
  } = intl;
291
389
  const triggerTitle = formatMessage(messages.syncedLocationDropdownTitle);
292
390
  const [isOpen, setIsOpen] = useState(false);
391
+ const content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
392
+ syncBlockStore: syncBlockStore,
393
+ resourceId: resourceId,
394
+ intl: intl,
395
+ isSource: isSource,
396
+ localId: localId,
397
+ api: api
398
+ }) : null;
293
399
  return /*#__PURE__*/React.createElement(DropdownMenu, {
294
400
  isOpen: isOpen
295
401
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
@@ -297,7 +403,7 @@ export const SyncedLocationDropdown = ({
297
403
  onOpenChange: ({
298
404
  isOpen
299
405
  }) => setIsOpen(isOpen),
300
- testId: "synced-block-synced-locations-dropdown"
406
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID
301
407
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
302
408
  ,
303
409
  trigger: ({
@@ -315,14 +421,7 @@ export const SyncedLocationDropdown = ({
315
421
  })
316
422
  // eslint-disable-next-line react/jsx-props-no-spreading
317
423
  }, triggerProps), triggerTitle)
318
- }, isOpen && /*#__PURE__*/React.createElement(DropdownContent, {
319
- syncBlockStore: syncBlockStore,
320
- resourceId: resourceId,
321
- intl: intl,
322
- isSource: isSource,
323
- localId: localId,
324
- api: api
325
- }));
424
+ }, content);
326
425
  };
327
426
  const DropdownContent = ({
328
427
  syncBlockStore,
@@ -65,14 +65,15 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
65
65
  const syncedLocation = {
66
66
  type: 'custom',
67
67
  fallback: [],
68
- render: () => {
68
+ render: (_view, _idx, _dispatchAnalyticsEvent, floatingToolbarRenderContext) => {
69
69
  return /*#__PURE__*/React.createElement(SyncedLocationDropdown, {
70
70
  syncBlockStore: syncBlockStore,
71
71
  resourceId: resourceId,
72
72
  localId: localId,
73
73
  intl: intl,
74
74
  isSource: isBodiedSyncBlock,
75
- api: api
75
+ api: api,
76
+ floatingToolbarRenderContext: floatingToolbarRenderContext
76
77
  });
77
78
  }
78
79
  };
@@ -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
+ }
@@ -11,13 +11,14 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
11
11
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
12
12
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
13
13
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
14
- import { useEffect, useState } from 'react';
14
+ import { useCallback, useEffect, useMemo, useState } from 'react';
15
15
  import { cx } from '@compiled/react';
16
16
  import DropdownMenu, { DropdownItem, DropdownItemGroup } from '@atlaskit/dropdown-menu';
17
17
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
18
18
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
19
19
  import { SYNCED_BLOCKS_DOCUMENTATION_URL } from '@atlaskit/editor-common/sync-block';
20
20
  import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
21
+ import { ArrowKeyNavigationType, DropdownContainer } from '@atlaskit/editor-common/ui-menu';
21
22
  import { getPageIdAndTypeFromConfluencePageAri } from '@atlaskit/editor-synced-block-provider';
22
23
  import { IconTile } from '@atlaskit/icon';
23
24
  import PageLiveDocIcon from '@atlaskit/icon-lab/core/page-live-doc';
@@ -32,6 +33,7 @@ import SubtaskIcon from '@atlaskit/icon/core/subtasks';
32
33
  import TaskIcon from '@atlaskit/icon/core/task';
33
34
  import { ConfluenceIcon, JiraIcon, AtlassianIcon } from '@atlaskit/logo';
34
35
  import Lozenge from '@atlaskit/lozenge';
36
+ import { fg } from '@atlaskit/platform-feature-flags';
35
37
  import { Box, Text, Inline, Anchor, Stack } from '@atlaskit/primitives/compiled';
36
38
  import Spinner from '@atlaskit/spinner';
37
39
  import Tooltip from '@atlaskit/tooltip';
@@ -41,6 +43,7 @@ var dropdownItemStyles = null;
41
43
 
42
44
  // logo icon does not fit in ADS IconTile, hence we need custom styles to match with other icons
43
45
  var logoTileStyles = null;
46
+ var SYNCED_LOCATIONS_DROPDOWN_TEST_ID = 'synced-block-synced-locations-dropdown';
44
47
  var styles = {
45
48
  title: "_1reo15vq _18m915vq _syazazsu _1bto1l2s _o5721q9c",
46
49
  note: "_syaz1rpy _o5721q9c",
@@ -296,27 +299,133 @@ export var SyncedLocationDropdown = function SyncedLocationDropdown(_ref4) {
296
299
  intl = _ref4.intl,
297
300
  isSource = _ref4.isSource,
298
301
  localId = _ref4.localId,
299
- api = _ref4.api;
302
+ api = _ref4.api,
303
+ floatingToolbarRenderContext = _ref4.floatingToolbarRenderContext;
304
+ if (fg('platform_synced_block_patch_13')) {
305
+ return /*#__PURE__*/React.createElement(EditorPositionedSyncedLocationDropdown, {
306
+ syncBlockStore: syncBlockStore,
307
+ resourceId: resourceId,
308
+ intl: intl,
309
+ isSource: isSource,
310
+ localId: localId,
311
+ api: api,
312
+ floatingToolbarRenderContext: floatingToolbarRenderContext
313
+ });
314
+ }
315
+ return /*#__PURE__*/React.createElement(LegacySyncedLocationDropdown, {
316
+ syncBlockStore: syncBlockStore,
317
+ resourceId: resourceId,
318
+ intl: intl,
319
+ isSource: isSource,
320
+ localId: localId,
321
+ api: api
322
+ });
323
+ };
324
+ var EditorPositionedSyncedLocationDropdown = function EditorPositionedSyncedLocationDropdown(_ref5) {
325
+ var syncBlockStore = _ref5.syncBlockStore,
326
+ resourceId = _ref5.resourceId,
327
+ intl = _ref5.intl,
328
+ isSource = _ref5.isSource,
329
+ localId = _ref5.localId,
330
+ api = _ref5.api,
331
+ floatingToolbarRenderContext = _ref5.floatingToolbarRenderContext;
300
332
  var formatMessage = intl.formatMessage;
301
333
  var triggerTitle = formatMessage(messages.syncedLocationDropdownTitle);
302
334
  var _useState = useState(false),
303
335
  _useState2 = _slicedToArray(_useState, 2),
304
336
  isOpen = _useState2[0],
305
337
  setIsOpen = _useState2[1];
338
+ var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
339
+ syncBlockStore: syncBlockStore,
340
+ resourceId: resourceId,
341
+ intl: intl,
342
+ isSource: isSource,
343
+ localId: localId,
344
+ api: api
345
+ }) : null;
346
+ var toggleOpen = useCallback(function () {
347
+ setIsOpen(function (currentIsOpen) {
348
+ return !currentIsOpen;
349
+ });
350
+ }, []);
351
+ var closeDropdown = useCallback(function () {
352
+ setIsOpen(false);
353
+ }, []);
354
+ var setDisableParentScroll = floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.setDisableParentScroll;
355
+ useEffect(function () {
356
+ if (!isOpen) {
357
+ return;
358
+ }
359
+ setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(true);
360
+ return function () {
361
+ setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(false);
362
+ };
363
+ }, [isOpen, setDisableParentScroll]);
364
+ var trigger = useMemo(function () {
365
+ return /*#__PURE__*/React.createElement(Button, {
366
+ areAnyNewToolbarFlagsEnabled: true,
367
+ selected: isOpen,
368
+ iconAfter: /*#__PURE__*/React.createElement(ChevronDownIcon, {
369
+ color: "currentColor",
370
+ spacing: "spacious",
371
+ label: "",
372
+ size: "small"
373
+ }),
374
+ onClick: toggleOpen,
375
+ ariaHasPopup: true
376
+ }, triggerTitle);
377
+ }, [isOpen, toggleOpen, triggerTitle]);
378
+ return /*#__PURE__*/React.createElement(DropdownContainer, {
379
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID,
380
+ isOpen: isOpen,
381
+ trigger: trigger,
382
+ handleClickOutside: closeDropdown,
383
+ handleEscapeKeydown: closeDropdown,
384
+ mountTo: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsMountPoint,
385
+ boundariesElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsBoundariesElement,
386
+ scrollableElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsScrollableElement
387
+ // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
388
+ ,
389
+ arrowKeyNavigationProviderOptions: {
390
+ type: ArrowKeyNavigationType.MENU
391
+ }
392
+ }, content);
393
+ };
394
+ var LegacySyncedLocationDropdown = function LegacySyncedLocationDropdown(_ref6) {
395
+ var syncBlockStore = _ref6.syncBlockStore,
396
+ resourceId = _ref6.resourceId,
397
+ intl = _ref6.intl,
398
+ isSource = _ref6.isSource,
399
+ localId = _ref6.localId,
400
+ api = _ref6.api;
401
+ var formatMessage = intl.formatMessage;
402
+ var triggerTitle = formatMessage(messages.syncedLocationDropdownTitle);
403
+ var _useState3 = useState(false),
404
+ _useState4 = _slicedToArray(_useState3, 2),
405
+ isOpen = _useState4[0],
406
+ setIsOpen = _useState4[1];
407
+ var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, {
408
+ syncBlockStore: syncBlockStore,
409
+ resourceId: resourceId,
410
+ intl: intl,
411
+ isSource: isSource,
412
+ localId: localId,
413
+ api: api
414
+ }) : null;
306
415
  return /*#__PURE__*/React.createElement(DropdownMenu, {
307
416
  isOpen: isOpen
308
417
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
309
418
  ,
310
- onOpenChange: function onOpenChange(_ref5) {
311
- var isOpen = _ref5.isOpen;
419
+ onOpenChange: function onOpenChange(_ref7) {
420
+ var isOpen = _ref7.isOpen;
312
421
  return setIsOpen(isOpen);
313
422
  },
314
- testId: "synced-block-synced-locations-dropdown"
423
+ testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID
315
424
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
316
425
  ,
317
- trigger: function trigger(_ref6) {
318
- var triggerRef = _ref6.triggerRef,
319
- triggerProps = _objectWithoutProperties(_ref6, _excluded);
426
+ trigger: function trigger(_ref8) {
427
+ var triggerRef = _ref8.triggerRef,
428
+ triggerProps = _objectWithoutProperties(_ref8, _excluded);
320
429
  return /*#__PURE__*/React.createElement(Button, _extends({
321
430
  ref: triggerRef,
322
431
  areAnyNewToolbarFlagsEnabled: true,
@@ -330,35 +439,28 @@ export var SyncedLocationDropdown = function SyncedLocationDropdown(_ref4) {
330
439
  // eslint-disable-next-line react/jsx-props-no-spreading
331
440
  }, triggerProps), triggerTitle);
332
441
  }
333
- }, isOpen && /*#__PURE__*/React.createElement(DropdownContent, {
334
- syncBlockStore: syncBlockStore,
335
- resourceId: resourceId,
336
- intl: intl,
337
- isSource: isSource,
338
- localId: localId,
339
- api: api
340
- }));
442
+ }, content);
341
443
  };
342
- var DropdownContent = function DropdownContent(_ref7) {
343
- var syncBlockStore = _ref7.syncBlockStore,
344
- resourceId = _ref7.resourceId,
345
- intl = _ref7.intl,
346
- isSource = _ref7.isSource,
347
- localId = _ref7.localId,
348
- api = _ref7.api;
444
+ var DropdownContent = function DropdownContent(_ref9) {
445
+ var syncBlockStore = _ref9.syncBlockStore,
446
+ resourceId = _ref9.resourceId,
447
+ intl = _ref9.intl,
448
+ isSource = _ref9.isSource,
449
+ localId = _ref9.localId,
450
+ api = _ref9.api;
349
451
  var formatMessage = intl.formatMessage;
350
- var _useState3 = useState('none'),
351
- _useState4 = _slicedToArray(_useState3, 2),
352
- fetchStatus = _useState4[0],
353
- setFetchStatus = _useState4[1];
354
- var _useState5 = useState([]),
452
+ var _useState5 = useState('none'),
355
453
  _useState6 = _slicedToArray(_useState5, 2),
356
- referenceData = _useState6[0],
357
- setReferenceData = _useState6[1];
454
+ fetchStatus = _useState6[0],
455
+ setFetchStatus = _useState6[1];
456
+ var _useState7 = useState([]),
457
+ _useState8 = _slicedToArray(_useState7, 2),
458
+ referenceData = _useState8[0],
459
+ setReferenceData = _useState8[1];
358
460
  useEffect(function () {
359
461
  setFetchStatus('loading');
360
462
  var getReferenceData = /*#__PURE__*/function () {
361
- var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
463
+ var _ref0 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
362
464
  var response;
363
465
  return _regeneratorRuntime.wrap(function _callee$(_context) {
364
466
  while (1) switch (_context.prev = _context.next) {
@@ -383,7 +485,7 @@ var DropdownContent = function DropdownContent(_ref7) {
383
485
  }, _callee);
384
486
  }));
385
487
  return function getReferenceData() {
386
- return _ref8.apply(this, arguments);
488
+ return _ref0.apply(this, arguments);
387
489
  };
388
490
  }();
389
491
  getReferenceData();
@@ -461,8 +563,8 @@ var DropdownContent = function DropdownContent(_ref7) {
461
563
  var LoadingScreen = function LoadingScreen() {
462
564
  return /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Spinner, null));
463
565
  };
464
- var ErrorScreen = function ErrorScreen(_ref9) {
465
- var formatMessage = _ref9.formatMessage;
566
+ var ErrorScreen = function ErrorScreen(_ref1) {
567
+ var formatMessage = _ref1.formatMessage;
466
568
  return /*#__PURE__*/React.createElement(Box, {
467
569
  xcss: styles.errorContainer,
468
570
  testId: "synced-locations-dropdown-content-error"
@@ -478,8 +580,8 @@ var ErrorScreen = function ErrorScreen(_ref9) {
478
580
  size: "medium"
479
581
  }, formatMessage(messages.syncedLocationDropdownError)));
480
582
  };
481
- var NoResultScreen = function NoResultScreen(_ref0) {
482
- var formatMessage = _ref0.formatMessage;
583
+ var NoResultScreen = function NoResultScreen(_ref10) {
584
+ var formatMessage = _ref10.formatMessage;
483
585
  return /*#__PURE__*/React.createElement(Stack, {
484
586
  xcss: styles.noResultsContainer,
485
587
  space: "space.100",
@@ -60,14 +60,15 @@ export var getToolbarConfig = function getToolbarConfig(state, intl, api, syncBl
60
60
  var syncedLocation = {
61
61
  type: 'custom',
62
62
  fallback: [],
63
- render: function render() {
63
+ render: function render(_view, _idx, _dispatchAnalyticsEvent, floatingToolbarRenderContext) {
64
64
  return /*#__PURE__*/React.createElement(SyncedLocationDropdown, {
65
65
  syncBlockStore: syncBlockStore,
66
66
  resourceId: resourceId,
67
67
  localId: localId,
68
68
  intl: intl,
69
69
  isSource: isBodiedSyncBlock,
70
- api: api
70
+ api: api,
71
+ floatingToolbarRenderContext: floatingToolbarRenderContext
71
72
  });
72
73
  }
73
74
  };
@@ -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 {};