@atlaskit/renderer 137.1.3 → 137.1.5

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,44 @@
1
1
  # @atlaskit/renderer
2
2
 
3
+ ## 137.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [`6f34a5002d9ed`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6f34a5002d9ed) -
8
+ [ux] Fix nested multi-bodied extensions so a parent active tab does not force a nested extension's
9
+ first frame to render behind the `platform_editor_nested_mbe_frames` feature gate.
10
+ - Updated dependencies
11
+
12
+ ## 137.1.4
13
+
14
+ ### Patch Changes
15
+
16
+ - [`53ad40b08a887`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/53ad40b08a887) -
17
+ Clean up platform_editor_video_caption_commit
18
+ - [`ad40c91e7c746`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ad40c91e7c746) -
19
+ Rework lazy loading of Expand body content behind the `hot-121622_lazy_load_expand_content`
20
+ feature gate, fixing an SSR hydration failure. Bodies were previously wrapped in `Suspense` +
21
+ `React.lazy`, which `renderToString` cannot resolve — it emitted an errored Suspense boundary and
22
+ hydration failed with "The server did not finish this Suspense boundary". That wrapper provided no
23
+ code splitting and has been removed.
24
+
25
+ A collapsed expand now renders a plain-text mirror of its body, and mounts the real children on
26
+ expand or on the browser's `beforematch` event. `Expand` takes the expand's ProseMirror `node` and
27
+ derives that mirror itself, replacing the `loadBodyContent` and `searchText` props. Deriving it in
28
+ the component means a nested expand — which is not mounted until its ancestor opens — never builds
29
+ a mirror on initial load, and the result is cached per node.
30
+
31
+ The mirror also now covers text the previous `node.textContent` call could not see: leaf nodes
32
+ that carry their text in attrs (mentions, emoji, status), text separated across block boundaries,
33
+ and ADF stashed in a coerced extension's `parameters.nestedContent` — which is how Confluence
34
+ stores nesting the schema cannot represent, and which renders on the page via a nested renderer.
35
+
36
+ Once an expand has been opened its children stay mounted, including after it is collapsed again
37
+ (PGXT-9021). Remounting them would re-run every macro and Forge data fetch inside the body on each
38
+ reopen; the saving this gate exists for is at initial load, where the body has never been opened.
39
+
40
+ - Updated dependencies
41
+
3
42
  ## 137.1.3
4
43
 
5
44
  ### Patch Changes
@@ -736,25 +736,14 @@ var ReactSerializer = exports.default = /*#__PURE__*/function () {
736
736
  value: function getExpandProps(node) {
737
737
  var _this7 = this;
738
738
  var _path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
739
- var loadBodyContent = false;
740
- if ((0, _fg.fg)('hot-121622_lazy_load_expand_content')) {
741
- var annotations = (0, _utils2.findChildrenByMark)(node, node.type.schema.marks.annotation, true);
742
- // Force rendering children if there are inline comments to support comments navigation
743
- // which relies on the HTML node to be present.
744
- loadBodyContent = annotations.some(function (annotation) {
745
- return annotation.node.marks.some(function (mark) {
746
- return mark.attrs.annotationType === 'inlineComment';
747
- });
748
- });
749
- }
750
-
751
- // Only compute searchText when the browser find experiment is enabled,
752
- // to avoid unnecessary node.textContent string allocations per expand node.
753
- var searchText = (0, _expValEquals.expValEquals)('platform_editor_close_expand_find', 'isEnabled', true) ? node.textContent : undefined;
739
+ // Expand receives the node rather than a precomputed string so it can derive the collapsed
740
+ // text mirror only when it actually renders one — a nested expand is not mounted until its
741
+ // ancestor opens and so that derivation can reach content the model walk cannot, such as
742
+ // the ADF stashed in a coerced extension's `parameters.nestedContent`. Expand owns the
743
+ // feature gate check.
754
744
  if (!(0, _links.isNestedHeaderLinksEnabled)(this.allowHeadingAnchorLinks)) {
755
745
  return _objectSpread(_objectSpread({}, this.getProps(node)), {}, {
756
- loadBodyContent: loadBodyContent,
757
- searchText: searchText
746
+ node: node
758
747
  });
759
748
  }
760
749
  var nestedHeaderIds = (0, _utils2.findChildrenByType)(node, node.type.schema.nodes.heading).map(function (_ref4) {
@@ -763,8 +752,7 @@ var ReactSerializer = exports.default = /*#__PURE__*/function () {
763
752
  });
764
753
  return _objectSpread(_objectSpread({}, this.getProps(node)), {}, {
765
754
  nestedHeaderIds: nestedHeaderIds,
766
- loadBodyContent: loadBodyContent,
767
- searchText: searchText
755
+ node: node
768
756
  });
769
757
  }
770
758
 
@@ -6,19 +6,20 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.default = void 0;
9
- var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
10
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
11
  var _react = require("@emotion/react");
12
12
  var _react2 = _interopRequireWildcard(require("react"));
13
13
  var _ui = require("@atlaskit/editor-common/ui");
14
14
  var _consts = require("../../consts");
15
15
  var _utils = require("@atlaskit/editor-common/utils");
16
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
16
17
  var _actions = require("./multiBodiedExtension/actions");
17
18
  var _context = require("./multiBodiedExtension/context");
18
19
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
19
20
  var _breakout = require("../utils/breakout");
20
21
  var _analyticsContext = _interopRequireDefault(require("../../analytics/analyticsContext"));
21
- var _templateObject;
22
+ var _templateObject, _templateObject2;
22
23
  /* eslint-disable @atlaskit/design-system/prefer-primitives, @atlaskit/design-system/consistent-css-prop-usage */
23
24
  /**
24
25
  * @jsxRuntime classic
@@ -39,9 +40,11 @@ var containerStyles = (0, _react.css)({
39
40
  }
40
41
  });
41
42
  var MultiBodiedExtensionChildrenContainer = function MultiBodiedExtensionChildrenContainer(_ref) {
42
- var children = _ref.children;
43
+ var children = _ref.children,
44
+ frameId = _ref.frameId;
43
45
  return (0, _react.jsx)("article", {
44
- "data-testid": "multiBodiedExtension--frames"
46
+ "data-testid": "multiBodiedExtension--frames",
47
+ "data-multibodiedextension-frames-id": frameId
45
48
  }, children);
46
49
  };
47
50
  var MultiBodiedExtensionNavigation = function MultiBodiedExtensionNavigation(_ref2) {
@@ -50,6 +53,11 @@ var MultiBodiedExtensionNavigation = function MultiBodiedExtensionNavigation(_re
50
53
  "data-testid": "multiBodiedExtension-navigation"
51
54
  }, children);
52
55
  };
56
+ var getContainerActiveFrameStyles = function getContainerActiveFrameStyles(activeChildIndex, frameId) {
57
+ return (0, _fg.fg)('platform_editor_nested_mbe_frames') ? // eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression
58
+ (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n\t\t\t\t&\n\t\t\t\t\t[data-multibodiedextension-frames-id='", "']\n\t\t\t\t\t> [data-extension-frame='true']:nth-of-type(", ") {\n\t\t\t\t\tdisplay: block;\n\t\t\t\t}\n\t\t\t"])), frameId, activeChildIndex + 1) : // eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression
59
+ (0, _react.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n\t\t\t\t& [data-extension-frame='true']:nth-of-type(", ") {\n\t\t\t\t\tdisplay: block;\n\t\t\t\t}\n\t\t\t"])), activeChildIndex + 1);
60
+ };
53
61
  var MultiBodiedExtensionWrapperLegacy = function MultiBodiedExtensionWrapperLegacy(_ref3) {
54
62
  var width = _ref3.width,
55
63
  path = _ref3.path,
@@ -136,10 +144,16 @@ var MultiBodiedExtension = function MultiBodiedExtension(props) {
136
144
  }),
137
145
  loading = _useMultiBodiedExtens.loading,
138
146
  extensionContext = _useMultiBodiedExtens.extensionContext;
147
+ // Used by the gated active-frame styles to scope selection to this MBE instance.
148
+ // Renderer frames are direct children of this article, so the id prevents a parent
149
+ // MBE selector from reaching into nested MBEs.
150
+ var frameId = _react2.default.useId();
139
151
  var actions = (0, _actions.useMultiBodiedExtensionActions)({
140
152
  updateActiveChild: setActiveChildIndex,
141
153
  children: children,
142
- childrenContainer: (0, _react.jsx)(MultiBodiedExtensionChildrenContainer, null, children),
154
+ childrenContainer: (0, _react.jsx)(MultiBodiedExtensionChildrenContainer, {
155
+ frameId: frameId
156
+ }, children),
143
157
  allowBodiedOverride: extensionContext === null || extensionContext === void 0 || (_extensionContext$pri = extensionContext.privateProps) === null || _extensionContext$pri === void 0 ? void 0 : _extensionContext$pri.__allowBodiedOverride,
144
158
  extensionKey: extensionKey,
145
159
  extensionType: extensionType,
@@ -173,13 +187,14 @@ var MultiBodiedExtension = function MultiBodiedExtension(props) {
173
187
  return (0, _react.jsx)(_react2.default.Fragment, null, (0, _react.jsx)(MultiBodiedExtensionNavigation, null, (0, _react.jsx)(NodeRenderer, {
174
188
  node: node,
175
189
  actions: actions
176
- })), (0, _react.jsx)(MultiBodiedExtensionChildrenContainer, null, children));
190
+ })), (0, _react.jsx)(MultiBodiedExtensionChildrenContainer, {
191
+ frameId: frameId
192
+ }, children));
177
193
  }
178
- }, [loading, extensionContext, marks, extensionKey, extensionType, parameters, content, getContent, localId, actions, children]);
194
+ }, [loading, extensionContext, marks, extensionKey, extensionType, parameters, content, getContent, localId, actions, children, frameId]);
179
195
 
180
196
  // make the frame visible
181
- // eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression
182
- var containerActiveFrameStyles = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n\t\t& [data-extension-frame='true']:nth-of-type(", ") {\n\t\t\tdisplay: block;\n\t\t}\n\t"])), activeChildIndex + 1);
197
+ var containerActiveFrameStyles = getContainerActiveFrameStyles(activeChildIndex, frameId);
183
198
  if ((0, _expValEquals.expValEquals)('platform_editor_renderer_extension_width_fix', 'isEnabled', true)) {
184
199
  var _isTopLevel = path.length < 1;
185
200
  var _useCenterWrapper = _isTopLevel && ['wide', 'full-width'].includes(layout);
@@ -16,7 +16,7 @@ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
16
16
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
17
17
  var getMediaClientConfigForRenderer = function getMediaClientConfigForRenderer(provider) {
18
18
  // eslint-disable-next-line @atlaskit/platform/no-preconditioning
19
- return provider.viewAndUploadMediaClientConfig && (0, _fg.fg)('platform_media_video_captions') && (0, _fg.fg)('platform_editor_video_caption_commit') ? provider.viewAndUploadMediaClientConfig : provider.viewMediaClientConfig;
19
+ return provider.viewAndUploadMediaClientConfig && (0, _fg.fg)('platform_media_video_captions') ? provider.viewAndUploadMediaClientConfig : provider.viewMediaClientConfig;
20
20
  };
21
21
  var EditorMediaClientProvider = exports.EditorMediaClientProvider = function EditorMediaClientProvider(_ref) {
22
22
  var children = _ref.children,
@@ -16,8 +16,9 @@ var _ui = require("@atlaskit/editor-common/ui");
16
16
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
17
17
  var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
18
18
  var _Tooltip = _interopRequireDefault(require("@atlaskit/tooltip/Tooltip"));
19
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
19
20
  var _fg = require("@atlaskit/platform-feature-flags/fg");
20
- var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
21
+ var _expandSearchText = require("./utils/expand-search-text");
21
22
  var _uniqueId2 = _interopRequireDefault(require("lodash/uniqueId"));
22
23
  var _reactIntl = require("react-intl");
23
24
  var _events = require("../analytics/events");
@@ -164,16 +165,6 @@ var clearNextSiblingMarginTopStyle = (0, _react.css)({
164
165
  marginTop: '0 !important'
165
166
  }
166
167
  });
167
-
168
- // Lazy-loaded children component
169
- var LazyChildren = /*#__PURE__*/(0, _react2.lazy)(function () {
170
- return Promise.resolve({
171
- default: function _default(_ref) {
172
- var children = _ref.children;
173
- return /*#__PURE__*/_react2.default.createElement(_react2.default.Fragment, null, children);
174
- }
175
- });
176
- });
177
168
  var Container = function Container(props) {
178
169
  return (0, _react.jsx)("div", {
179
170
  css: [containerStyles, props['data-node-type'] === 'expand' && containerStylesDataNodeTypeExpand, props.expanded && containerStylesExpanded, props.focused && containerStylesFocused],
@@ -222,29 +213,36 @@ function fireExpandToggleAnalytics(nodeType, expanded, fireAnalyticsEvent) {
222
213
  eventType: _analytics.EVENT_TYPE.TRACK
223
214
  });
224
215
  }
225
- function Expand(_ref2) {
226
- var title = _ref2.title,
227
- children = _ref2.children,
228
- nodeType = _ref2.nodeType,
229
- intl = _ref2.intl,
230
- fireAnalyticsEvent = _ref2.fireAnalyticsEvent,
231
- localId = _ref2.localId,
232
- nestedHeaderIds = _ref2.nestedHeaderIds,
233
- rendererContentMode = _ref2.rendererContentMode,
234
- loadBodyContent = _ref2.loadBodyContent,
235
- searchText = _ref2.searchText;
236
- var _React$useState = _react2.default.useState(false),
237
- _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
238
- expanded = _React$useState2[0],
239
- setExpanded = _React$useState2[1];
240
- var _React$useState3 = _react2.default.useState(false),
241
- _React$useState4 = (0, _slicedToArray2.default)(_React$useState3, 2),
242
- focused = _React$useState4[0],
243
- setFocused = _React$useState4[1];
244
- var _React$useState5 = _react2.default.useState(false),
245
- _React$useState6 = (0, _slicedToArray2.default)(_React$useState5, 2),
246
- hasLoadedChildren = _React$useState6[0],
247
- setHasLoadedChildren = _React$useState6[1];
216
+ function Expand(_ref) {
217
+ var title = _ref.title,
218
+ children = _ref.children,
219
+ nodeType = _ref.nodeType,
220
+ intl = _ref.intl,
221
+ fireAnalyticsEvent = _ref.fireAnalyticsEvent,
222
+ localId = _ref.localId,
223
+ nestedHeaderIds = _ref.nestedHeaderIds,
224
+ rendererContentMode = _ref.rendererContentMode,
225
+ node = _ref.node;
226
+ var _useState = (0, _react2.useState)(false),
227
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
228
+ expanded = _useState2[0],
229
+ setExpanded = _useState2[1];
230
+ var _useState3 = (0, _react2.useState)(false),
231
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
232
+ focused = _useState4[0],
233
+ setFocused = _useState4[1];
234
+ /**
235
+ * PGXT-9021: latches on the first open so the body stays mounted once rendered, including after
236
+ * the expand is collapsed again. Remounting it would re-run every macro and Forge data fetch
237
+ * inside on each reopen, which is both slower and visibly reloads content the reader has already
238
+ * seen. The saving this gate exists for is at initial load, where the body has never been opened,
239
+ * so nothing is given up by keeping it after that. Never set on the server, so the server and the
240
+ * client's first render agree and hydration cannot desync.
241
+ */
242
+ var _useState5 = (0, _react2.useState)(false),
243
+ _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
244
+ hasBeenExpanded = _useState6[0],
245
+ setHasBeenExpanded = _useState6[1];
248
246
  var isMobile = false;
249
247
  var label = intl.formatMessage(expanded ? _ui.expandMessages.collapseNode : _ui.expandMessages.expandNode);
250
248
  var _useRef = (0, _react2.useRef)((0, _uniqueId2.default)('expand-title-')),
@@ -257,16 +255,12 @@ function Expand(_ref2) {
257
255
  var handleBlur = (0, _react2.useCallback)(function () {
258
256
  return setFocused(false);
259
257
  }, []);
260
- var expandForBrowserFind = (0, _react2.useCallback)(function () {
261
- setHasLoadedChildren(true);
258
+ // Both state updates happen in the same handler so they land in one render, rather than the
259
+ // latch reacting to `expanded` from an effect.
260
+ var openBody = (0, _react2.useCallback)(function () {
262
261
  setExpanded(true);
262
+ setHasBeenExpanded(true);
263
263
  }, []);
264
- var shouldRenderLazyChildren = hasLoadedChildren || loadBodyContent;
265
- // Only render the lightweight text placeholder when lazy load is ON and
266
- // children haven't been loaded yet. When lazy load is OFF, children are
267
- // always in the DOM — hidden="until-found" on the wrapper already makes
268
- // them searchable by browser find, so no placeholder is needed.
269
- var shouldRenderBrowserFindText = !shouldRenderLazyChildren && searchText && (0, _fg.fg)('hot-121622_lazy_load_expand_content') && (0, _expValEquals.expValEquals)('platform_editor_close_expand_find', 'isEnabled', true);
270
264
 
271
265
  // Feature-detect hidden="until-found" support via the beforematch event.
272
266
  // Chrome 102+ and Firefox 130+ support it; Safari does not yet.
@@ -275,11 +269,11 @@ function Expand(_ref2) {
275
269
  // Initialised as false and set in useEffect to avoid SSR/client hydration mismatch —
276
270
  // useMemo would return true on the client's first render in supported browsers,
277
271
  // differing from the server snapshot which always produces false.
278
- var _React$useState7 = _react2.default.useState(false),
279
- _React$useState8 = (0, _slicedToArray2.default)(_React$useState7, 2),
280
- supportsHiddenUntilFound = _React$useState8[0],
281
- setSupportsHiddenUntilFound = _React$useState8[1];
282
- _react2.default.useEffect(function () {
272
+ var _useState7 = (0, _react2.useState)(false),
273
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
274
+ supportsHiddenUntilFound = _useState8[0],
275
+ setSupportsHiddenUntilFound = _useState8[1];
276
+ (0, _react2.useEffect)(function () {
283
277
  var doc = (0, _browserApis.getDocument)();
284
278
  setSupportsHiddenUntilFound(doc !== null && doc !== void 0 && doc.body ? 'onbeforematch' in doc.body : false);
285
279
  }, []);
@@ -295,13 +289,13 @@ function Expand(_ref2) {
295
289
  // In unsupported browsers (Safari), we skip this entirely and fall back to the normal
296
290
  // CSS hiding (visibility:hidden + height:0), which doesn't support find-in-page but
297
291
  // still works correctly for expand/collapse.
298
- _react2.default.useEffect(function () {
292
+ (0, _react2.useEffect)(function () {
299
293
  var contentContainer = contentContainerRef.current;
300
294
  var contentWrapper = contentWrapperRef.current;
301
295
  if (!contentWrapper) {
302
296
  return;
303
297
  }
304
- if (supportsHiddenUntilFound && (0, _expValEquals.expValEquals)('platform_editor_close_expand_find', 'isEnabled', true) && !expanded) {
298
+ if (supportsHiddenUntilFound && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_close_expand_find') && !expanded) {
305
299
  contentWrapper.setAttribute('hidden', 'until-found');
306
300
  // Override the CSS visibility:hidden from contentContainerStyles — hidden="until-found"
307
301
  // now handles hiding via content-visibility:hidden, which allows browser find to index
@@ -315,31 +309,29 @@ function Expand(_ref2) {
315
309
  contentWrapper.style.visibility = '';
316
310
  }
317
311
  }, [expanded, supportsHiddenUntilFound]);
318
- _react2.default.useEffect(function () {
319
- if (!(0, _expValEquals.expValEquals)('platform_editor_close_expand_find', 'isEnabled', true) || expanded) {
312
+ (0, _react2.useEffect)(function () {
313
+ if (!(0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_close_expand_find') || expanded) {
320
314
  return;
321
315
  }
322
316
  var contentWrapper = contentWrapperRef.current;
323
317
  var unbindWrapperBeforeMatch = contentWrapper && supportsHiddenUntilFound ? (0, _bindEventListener.bind)(contentWrapper, {
324
318
  type: 'beforematch',
325
- listener: expandForBrowserFind
319
+ listener: openBody
326
320
  }) : undefined;
327
321
  return function () {
328
322
  unbindWrapperBeforeMatch === null || unbindWrapperBeforeMatch === void 0 || unbindWrapperBeforeMatch();
329
323
  };
330
- }, [expandForBrowserFind, expanded, supportsHiddenUntilFound]);
331
- var expandContent = children;
332
- if (shouldRenderBrowserFindText) {
333
- // Browser find path: keep a lightweight text mirror in the closed expand
334
- // so Ctrl+F can index it without mounting the rich children tree.
335
- expandContent = (0, _react.jsx)("span", null, searchText);
336
- } else if (!shouldRenderLazyChildren && (0, _fg.fg)('hot-121622_lazy_load_expand_content')) {
337
- expandContent = null;
338
- } else if ((0, _fg.fg)('hot-121622_lazy_load_expand_content')) {
339
- expandContent = (0, _react.jsx)(_react2.Suspense, {
340
- fallback: (0, _react.jsx)("div", null, intl.formatMessage(_ui.expandMessages.loading))
341
- }, (0, _react.jsx)(LazyChildren, null, children));
342
- }
324
+ }, [expanded, openBody, supportsHiddenUntilFound]);
325
+
326
+ // Until the expand is first opened, stand in a plain-text mirror of the body so
327
+ // hidden="until-found" keeps the content findable by browser find without mounting the real
328
+ // subtree. The beforematch listener above expands before the browser scrolls to its match.
329
+ // Computed lazily: a nested expand is not mounted until its ancestor opens, so its mirror is
330
+ // never built on initial load.
331
+ var searchText = (0, _react2.useMemo)(function () {
332
+ return node && (0, _fg.fg)('hot-121622_lazy_load_expand_content') ? (0, _expandSearchText.getExpandSearchText)(node) : undefined;
333
+ }, [node]);
334
+ var expandContent = searchText && !expanded && !hasBeenExpanded ? (0, _react.jsx)("span", null, searchText) : children;
343
335
  return (0, _react.jsx)(Container, {
344
336
  "data-testid": "expand-container-".concat(nodeType, "-").concat(id),
345
337
  "data-node-type": nodeType,
@@ -349,15 +341,8 @@ function Expand(_ref2) {
349
341
  expanded: expanded,
350
342
  focused: focused
351
343
  }, nestedHeaderIds && nestedHeaderIds.length > 0 ? (0, _react.jsx)(_activeHeaderIdProvider.ActiveHeaderIdConsumer, {
352
- nestedHeaderIds: nestedHeaderIds
353
- // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
354
- ,
355
- onNestedHeaderIdMatch: function onNestedHeaderIdMatch() {
356
- if (!hasLoadedChildren) {
357
- setHasLoadedChildren(true);
358
- }
359
- setExpanded(true);
360
- }
344
+ nestedHeaderIds: nestedHeaderIds,
345
+ onNestedHeaderIdMatch: openBody
361
346
  }) : null, (0, _react.jsx)(TitleContainer
362
347
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
363
348
  , {
@@ -365,12 +350,11 @@ function Expand(_ref2) {
365
350
  e.preventDefault();
366
351
  e.stopPropagation();
367
352
  fireExpandToggleAnalytics(nodeType, expanded, fireAnalyticsEvent);
368
-
369
- // Mark children as loaded when expanding for the first time
370
- if (!expanded && !hasLoadedChildren) {
371
- setHasLoadedChildren(true);
353
+ if (expanded) {
354
+ setExpanded(false);
355
+ } else {
356
+ openBody();
372
357
  }
373
- setExpanded(!expanded);
374
358
  e.persist();
375
359
  // @ts-ignore detail doesn't exist on type
376
360
  e.detail ? handleBlur() : handleFocus();
@@ -405,7 +389,7 @@ function Expand(_ref2) {
405
389
  id: id
406
390
  }, title || intl.formatMessage(_ui.expandMessages.expandDefaultTitle))), (0, _react.jsx)(ContentContainer, {
407
391
  expanded: expanded,
408
- enableBrowserFind: supportsHiddenUntilFound && (0, _expValEquals.expValEquals)('platform_editor_close_expand_find', 'isEnabled', true),
392
+ enableBrowserFind: supportsHiddenUntilFound && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_close_expand_find'),
409
393
  contentRef: contentContainerRef
410
394
  }, (0, _react.jsx)("div", {
411
395
  className: "".concat(nodeType, "-content-wrapper"),
@@ -417,4 +401,4 @@ function Expand(_ref2) {
417
401
 
418
402
  // eslint-disable-next-line @typescript-eslint/ban-types
419
403
  var _default_1 = (0, _reactIntl.injectIntl)(Expand);
420
- var _default2 = exports.default = _default_1;
404
+ var _default = exports.default = _default_1;
@@ -74,7 +74,7 @@ var DEGRADED_SEVERITY_THRESHOLD = exports.DEGRADED_SEVERITY_THRESHOLD = 3000;
74
74
  var TABLE_INFO_TIMEOUT = 10000;
75
75
  var RENDER_EVENT_SAMPLE_RATE = 0.1;
76
76
  var packageName = "@atlaskit/renderer";
77
- var packageVersion = "137.1.2";
77
+ var packageVersion = "137.1.4";
78
78
  var setAsQueryContainerStyles = (0, _react2.css)({
79
79
  containerName: 'ak-renderer-wrapper',
80
80
  containerType: 'inline-size'
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getExpandSearchText = void 0;
7
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
8
+ /**
9
+ * Minimal structural view of an ADF entity. `parameters.nestedContent` holds raw ADF JSON rather
10
+ * than ProseMirror nodes, so it cannot be walked with the model API.
11
+ */
12
+
13
+ /** Separates text from adjacent blocks so phrases cannot fuse across block boundaries. */
14
+ var BLOCK_SEPARATOR = ' ';
15
+ var asText = function asText(value) {
16
+ return typeof value === 'string' ? value : '';
17
+ };
18
+
19
+ /**
20
+ * Extracts text from raw ADF JSON.
21
+ *
22
+ * Needed because some extensions stash a whole ADF subtree in `attrs.parameters.nestedContent`
23
+ * instead of in their node content — Confluence does this when it coerces nesting the schema
24
+ * cannot represent (an expand more than two collapsible layers deep, say). Such a node is a
25
+ * ProseMirror leaf, so the model walk cannot see the subtree even though it renders on the page
26
+ * via a nested renderer. Recurses, because nestedContent routinely holds further nested content.
27
+ */
28
+ var _adfEntityText = function adfEntityText(entity) {
29
+ var _entity$attrs, _entity$content;
30
+ if (!entity) {
31
+ return '';
32
+ }
33
+ var parts = [];
34
+ if (entity.type === 'text') {
35
+ parts.push(asText(entity.text));
36
+ }
37
+ var nestedContent = (_entity$attrs = entity.attrs) === null || _entity$attrs === void 0 || (_entity$attrs = _entity$attrs.parameters) === null || _entity$attrs === void 0 ? void 0 : _entity$attrs.nestedContent;
38
+ if (nestedContent) {
39
+ // Prefer the real subtree over `attrs.text`, which is only a placeholder label for it.
40
+ parts.push(_adfEntityText(nestedContent));
41
+ } else {
42
+ var _entity$attrs2;
43
+ parts.push(asText((_entity$attrs2 = entity.attrs) === null || _entity$attrs2 === void 0 ? void 0 : _entity$attrs2.text));
44
+ }
45
+ (_entity$content = entity.content) === null || _entity$content === void 0 || _entity$content.forEach(function (child) {
46
+ return parts.push(_adfEntityText(child));
47
+ });
48
+ return parts.filter(Boolean).join(BLOCK_SEPARATOR);
49
+ };
50
+
51
+ /**
52
+ * `textBetween` drops every non-text leaf unless the node spec declares `leafText`, and no ADF
53
+ * node does. Leaves carry their visible text in attrs, so recover it here.
54
+ */
55
+ var leafText = function leafText(leaf) {
56
+ var _leaf$attrs, _leaf$attrs2;
57
+ var nestedContent = (_leaf$attrs = leaf.attrs) === null || _leaf$attrs === void 0 || (_leaf$attrs = _leaf$attrs.parameters) === null || _leaf$attrs === void 0 ? void 0 : _leaf$attrs.nestedContent;
58
+ if (nestedContent) {
59
+ return _adfEntityText(nestedContent);
60
+ }
61
+ return asText((_leaf$attrs2 = leaf.attrs) === null || _leaf$attrs2 === void 0 ? void 0 : _leaf$attrs2.text);
62
+ };
63
+ var hasInlineComment = function hasInlineComment(node) {
64
+ return (0, _utils.findChildrenByMark)(node, node.type.schema.marks.annotation, true).some(function (annotation) {
65
+ return annotation.node.marks.some(function (mark) {
66
+ return mark.attrs.annotationType === 'inlineComment';
67
+ });
68
+ });
69
+ };
70
+
71
+ /** `null` is a cached "no mirror for this node", as distinct from `undefined` for a cache miss. */
72
+ var searchTextCache = new WeakMap();
73
+
74
+ /**
75
+ * Plain-text mirror of an expand's body, rendered in its place while collapsed so browser
76
+ * find-in-page can still reach the content.
77
+ *
78
+ * Cached on the node. ProseMirror nodes are immutable and `render-document` memoises
79
+ * `nodeFromJSON`, so the same node instance is reused across renders — including across the
80
+ * serializer rebuilds that invalidate the module-level `memoizeOne` caches.
81
+ *
82
+ * @returns the mirror text, or `undefined` if this expand must keep its body rendered.
83
+ */
84
+ var getExpandSearchText = exports.getExpandSearchText = function getExpandSearchText(node) {
85
+ var cached = searchTextCache.get(node);
86
+ if (cached === undefined) {
87
+ cached = hasInlineComment(node) ?
88
+ // Withhold the mirror, which makes Expand keep rendering `children`. Comment
89
+ // navigation walks the DOM to find the annotated node and scrolls it into view, so
90
+ // the annotation has to exist as a real element — a flat text mirror carries no
91
+ // annotation marks and cannot stand in for it. Without this, stepping through
92
+ // comments with the arrow keys silently fails to reach any comment inside a
93
+ // collapsed expand. Costs the lazy-load win for these expands, deliberately.
94
+ null : node.textBetween(0, node.content.size, BLOCK_SEPARATOR, leafText);
95
+ searchTextCache.set(node, cached);
96
+ }
97
+ return cached !== null && cached !== void 0 ? cached : undefined;
98
+ };
@@ -9,7 +9,7 @@ import TextWrapperComponent from './nodes/text-wrapper';
9
9
  import { isNestedHeaderLinksEnabled } from './utils/links';
10
10
  import { getColumnWidths } from '@atlaskit/editor-common/utils';
11
11
  import { getMarksByOrder, isSameMark } from '@atlaskit/editor-common/validator';
12
- import { findChildrenByMark, findChildrenByType } from '@atlaskit/editor-prosemirror/utils';
12
+ import { findChildrenByType } from '@atlaskit/editor-prosemirror/utils';
13
13
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
14
14
  import { fg } from '@atlaskit/platform-feature-flags/fg';
15
15
  import { getText } from '../utils';
@@ -655,24 +655,15 @@ export default class ReactSerializer {
655
655
  };
656
656
  }
657
657
  getExpandProps(node, _path = []) {
658
- let loadBodyContent = false;
659
- if (fg('hot-121622_lazy_load_expand_content')) {
660
- const annotations = findChildrenByMark(node, node.type.schema.marks.annotation, true);
661
- // Force rendering children if there are inline comments to support comments navigation
662
- // which relies on the HTML node to be present.
663
- loadBodyContent = annotations.some(annotation => {
664
- return annotation.node.marks.some(mark => mark.attrs.annotationType === 'inlineComment');
665
- });
666
- }
667
-
668
- // Only compute searchText when the browser find experiment is enabled,
669
- // to avoid unnecessary node.textContent string allocations per expand node.
670
- const searchText = expValEquals('platform_editor_close_expand_find', 'isEnabled', true) ? node.textContent : undefined;
658
+ // Expand receives the node rather than a precomputed string so it can derive the collapsed
659
+ // text mirror only when it actually renders one — a nested expand is not mounted until its
660
+ // ancestor opens and so that derivation can reach content the model walk cannot, such as
661
+ // the ADF stashed in a coerced extension's `parameters.nestedContent`. Expand owns the
662
+ // feature gate check.
671
663
  if (!isNestedHeaderLinksEnabled(this.allowHeadingAnchorLinks)) {
672
664
  return {
673
665
  ...this.getProps(node),
674
- loadBodyContent,
675
- searchText
666
+ node
676
667
  };
677
668
  }
678
669
  const nestedHeaderIds = findChildrenByType(node, node.type.schema.nodes.heading).map(({
@@ -681,8 +672,7 @@ export default class ReactSerializer {
681
672
  return {
682
673
  ...this.getProps(node),
683
674
  nestedHeaderIds,
684
- loadBodyContent,
685
- searchText
675
+ node
686
676
  };
687
677
  }
688
678