@atlaskit/react-ufo 4.12.3 → 4.12.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.
Files changed (22) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/create-payload/utils/get-browser-metadata.js +9 -0
  3. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +53 -3
  4. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +54 -4
  5. package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +247 -89
  6. package/dist/es2019/create-payload/utils/get-browser-metadata.js +9 -0
  7. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +51 -3
  8. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +55 -4
  9. package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +175 -80
  10. package/dist/esm/create-payload/utils/get-browser-metadata.js +9 -0
  11. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +53 -3
  12. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +55 -4
  13. package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +247 -89
  14. package/dist/types/common/react-ufo-payload-schema.d.ts +1 -0
  15. package/dist/types/create-payload/utils/get-browser-metadata.d.ts +1 -0
  16. package/dist/types/resource-timing/index.d.ts +1 -1
  17. package/dist/types/vc/vc-observer/observers/ssr-placeholders/index.d.ts +5 -0
  18. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +1 -0
  19. package/dist/types-ts4.5/create-payload/utils/get-browser-metadata.d.ts +1 -0
  20. package/dist/types-ts4.5/resource-timing/index.d.ts +1 -1
  21. package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/index.d.ts +5 -0
  22. package/package.json +8 -1
@@ -1,22 +1,73 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+
1
3
  // lightweight script to scan the SSR response and collect all elements with data-ssr-placeholder attribute
2
4
  // and save their size/positions in a map __SSR_PLACEHOLDERS_DIMENSIONS__ on the Window object. Each placeholderId is
3
5
  // unique and maps to its corresponding elements bounding client rectangle dimensions.
4
6
  export function collectSSRPlaceholderDimensions(document, window, enablePageLayoutPlaceholder = false) {
7
+ const enableDisplayContentsSupport = fg('platform_ufo_ssr_placeholders_for_display_contents');
5
8
  const ssrPlaceholders = document === null || document === void 0 ? void 0 : document.querySelectorAll('[data-ssr-placeholder]');
6
9
  ssrPlaceholders.forEach(elem => {
7
10
  const placeholderId = elem.getAttribute('data-ssr-placeholder');
8
- const boundingClient = elem.getBoundingClientRect();
9
11
  if (placeholderId) {
10
12
  window.__SSR_PLACEHOLDERS_DIMENSIONS__ = window.__SSR_PLACEHOLDERS_DIMENSIONS__ || {};
11
- window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = boundingClient;
13
+ if (enableDisplayContentsSupport) {
14
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = getEffectiveBoundingRect(elem, window);
15
+ } else {
16
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = elem.getBoundingClientRect();
17
+ }
12
18
  }
13
19
  });
14
20
  if (enablePageLayoutPlaceholder) {
15
21
  const pageLayoutRoot = document === null || document === void 0 ? void 0 : document.getElementById('unsafe-design-system-page-layout-root');
16
22
  if (pageLayoutRoot) {
17
- const boundingClient = pageLayoutRoot.getBoundingClientRect();
18
23
  window.__SSR_PLACEHOLDERS_DIMENSIONS__ = window.__SSR_PLACEHOLDERS_DIMENSIONS__ || {};
19
- window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = boundingClient;
24
+ if (enableDisplayContentsSupport) {
25
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = getEffectiveBoundingRect(pageLayoutRoot, window);
26
+ } else {
27
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = pageLayoutRoot.getBoundingClientRect();
28
+ }
20
29
  }
21
30
  }
31
+ }
32
+
33
+ /**
34
+ * Gets the effective bounding rectangle for an element, handling display: contents elements
35
+ * by collecting dimensions from their children instead
36
+ */
37
+ function getEffectiveBoundingRect(elem, window) {
38
+ const computedStyle = window.getComputedStyle(elem);
39
+
40
+ // If element has display: contents, collect bounding rect from children
41
+ if (computedStyle.display === 'contents') {
42
+ const children = Array.from(elem.children);
43
+ if (children.length === 0) {
44
+ // No children, return zero rect
45
+ return new DOMRect(0, 0, 0, 0);
46
+ }
47
+
48
+ // Calculate union of all children's bounding rects
49
+ let minX = Infinity;
50
+ let minY = Infinity;
51
+ let maxX = -Infinity;
52
+ let maxY = -Infinity;
53
+ children.forEach(child => {
54
+ const childRect = child.getBoundingClientRect();
55
+ // Skip children with zero dimensions (likely also display: contents)
56
+ if (childRect.width > 0 || childRect.height > 0) {
57
+ minX = Math.min(minX, childRect.left);
58
+ minY = Math.min(minY, childRect.top);
59
+ maxX = Math.max(maxX, childRect.right);
60
+ maxY = Math.max(maxY, childRect.bottom);
61
+ }
62
+ });
63
+
64
+ // If no children with dimensions found, return zero rect
65
+ if (minX === Infinity) {
66
+ return new DOMRect(0, 0, 0, 0);
67
+ }
68
+ return new DOMRect(minX, minY, maxX - minX, maxY - minY);
69
+ }
70
+
71
+ // Normal element, return its bounding rect
72
+ return elem.getBoundingClientRect();
22
73
  }
@@ -1,4 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { isContainedWithinMediaWrapper } from '../../vc-observer/media-wrapper/vc-utils';
3
4
  import isDnDStyleMutation from '../../vc-observer/observers/non-visual-styles/is-dnd-style-mutation';
4
5
  import isNonVisualStyleMutation from '../../vc-observer/observers/non-visual-styles/is-non-visual-style-mutation';
@@ -80,95 +81,189 @@ export default class ViewportObserver {
80
81
  if (!addedNode) {
81
82
  continue;
82
83
  }
84
+ if (fg('platform_ufo_ssr_placeholders_for_display_contents')) {
85
+ for (const {
86
+ isDisplayContentsElementChildren,
87
+ element
88
+ } of getMutatedElements(addedNode)) {
89
+ // SSR hydration logic
90
+ if (this.getSSRState) {
91
+ const ssrState = this.getSSRState();
92
+ const SSRStateEnum = {
93
+ normal: 1,
94
+ waitingForFirstRender: 2,
95
+ ignoring: 3
96
+ };
97
+ if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
98
+ var _this$intersectionObs;
99
+ ssrState.state = SSRStateEnum.ignoring;
100
+ if (ssrState.renderStop === -1) {
101
+ // arbitrary 500ms DOM update window
102
+ ssrState.renderStop = timestamp + 500;
103
+ }
104
+ (_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.watchAndTag(element, 'ssr-hydration');
105
+ continue;
106
+ }
107
+ if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
108
+ if (timestamp <= ssrState.renderStop) {
109
+ var _this$intersectionObs2;
110
+ (_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(element, 'ssr-hydration');
111
+ continue;
112
+ } else {
113
+ ssrState.state = SSRStateEnum.normal;
114
+ }
115
+ }
116
+ }
83
117
 
84
- // SSR hydration logic
85
- if (this.getSSRState) {
86
- const ssrState = this.getSSRState();
87
- const SSRStateEnum = {
88
- normal: 1,
89
- waitingForFirstRender: 2,
90
- ignoring: 3
91
- };
92
- if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
93
- var _this$intersectionObs;
94
- ssrState.state = SSRStateEnum.ignoring;
95
- if (ssrState.renderStop === -1) {
96
- // arbitrary 500ms DOM update window
97
- ssrState.renderStop = timestamp + 500;
118
+ // SSR placeholder logic - check and handle with await
119
+ if (this.getSSRPlaceholderHandler) {
120
+ const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
121
+ if (ssrPlaceholderHandler) {
122
+ if (ssrPlaceholderHandler.isPlaceholder(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
123
+ if (ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(element)) {
124
+ var _this$intersectionObs3;
125
+ (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(element, 'mutation:ssr-placeholder');
126
+ continue;
127
+ }
128
+ // If result is false, continue to normal mutation logic below
129
+ }
130
+ if (ssrPlaceholderHandler.isPlaceholderReplacement(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
131
+ const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(element);
132
+ if (result !== false) {
133
+ var _this$intersectionObs4;
134
+ (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(element, 'mutation:ssr-placeholder');
135
+ continue;
136
+ }
137
+ // If result is false, continue to normal mutation logic below
138
+ }
139
+ }
98
140
  }
99
- (_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.watchAndTag(addedNode, 'ssr-hydration');
100
- continue;
101
- }
102
- if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
103
- if (timestamp <= ssrState.renderStop) {
104
- var _this$intersectionObs2;
105
- (_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(addedNode, 'ssr-hydration');
141
+ const sameDeletedNode = removedNodes.find(ref => {
142
+ const n = ref.deref();
143
+ if (!n || !element) {
144
+ return false;
145
+ }
146
+ return n.isEqualNode(element);
147
+ });
148
+ const isInIgnoreLsMarker = element instanceof HTMLElement ? isInVCIgnoreIfNoLayoutShiftMarker(element) : false;
149
+ if (sameDeletedNode && isInIgnoreLsMarker) {
150
+ var _this$intersectionObs5;
151
+ (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(element, 'mutation:remount');
152
+ continue;
153
+ }
154
+ if (isContainedWithinMediaWrapper(element)) {
155
+ var _this$intersectionObs6;
156
+ (_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.watchAndTag(element, 'mutation:media');
157
+ continue;
158
+ }
159
+ const {
160
+ isWithin: isWithinThirdPartySegment
161
+ } = element instanceof HTMLElement ? checkWithinComponent(element, 'UFOThirdPartySegment', this.mapIs3pResult) : {
162
+ isWithin: false
163
+ };
164
+ if (isWithinThirdPartySegment) {
165
+ var _this$intersectionObs7;
166
+ (_this$intersectionObs7 = this.intersectionObserver) === null || _this$intersectionObs7 === void 0 ? void 0 : _this$intersectionObs7.watchAndTag(element, 'mutation:third-party-element');
106
167
  continue;
168
+ }
169
+ if (isDisplayContentsElementChildren) {
170
+ var _this$intersectionObs8;
171
+ (_this$intersectionObs8 = this.intersectionObserver) === null || _this$intersectionObs8 === void 0 ? void 0 : _this$intersectionObs8.watchAndTag(element, 'mutation:display-contents-children-element');
107
172
  } else {
108
- ssrState.state = SSRStateEnum.normal;
173
+ var _this$intersectionObs9;
174
+ (_this$intersectionObs9 = this.intersectionObserver) === null || _this$intersectionObs9 === void 0 ? void 0 : _this$intersectionObs9.watchAndTag(element, createElementMutationsWatcher(removedNodeRects));
109
175
  }
110
176
  }
111
- }
112
-
113
- // SSR placeholder logic - check and handle with await
114
- if (this.getSSRPlaceholderHandler) {
115
- const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
116
- if (ssrPlaceholderHandler) {
117
- if (ssrPlaceholderHandler.isPlaceholder(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
118
- if (ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(addedNode)) {
119
- var _this$intersectionObs3;
120
- (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(addedNode, 'mutation:ssr-placeholder');
121
- continue;
177
+ } else {
178
+ // SSR hydration logic
179
+ if (this.getSSRState) {
180
+ const ssrState = this.getSSRState();
181
+ const SSRStateEnum = {
182
+ normal: 1,
183
+ waitingForFirstRender: 2,
184
+ ignoring: 3
185
+ };
186
+ if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
187
+ var _this$intersectionObs0;
188
+ ssrState.state = SSRStateEnum.ignoring;
189
+ if (ssrState.renderStop === -1) {
190
+ // arbitrary 500ms DOM update window
191
+ ssrState.renderStop = timestamp + 500;
122
192
  }
123
- // If result is false, continue to normal mutation logic below
193
+ (_this$intersectionObs0 = this.intersectionObserver) === null || _this$intersectionObs0 === void 0 ? void 0 : _this$intersectionObs0.watchAndTag(addedNode, 'ssr-hydration');
194
+ continue;
124
195
  }
125
- if (ssrPlaceholderHandler.isPlaceholderReplacement(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
126
- const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(addedNode);
127
- if (result !== false) {
128
- var _this$intersectionObs4;
129
- (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(addedNode, 'mutation:ssr-placeholder');
196
+ if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
197
+ if (timestamp <= ssrState.renderStop) {
198
+ var _this$intersectionObs1;
199
+ (_this$intersectionObs1 = this.intersectionObserver) === null || _this$intersectionObs1 === void 0 ? void 0 : _this$intersectionObs1.watchAndTag(addedNode, 'ssr-hydration');
130
200
  continue;
201
+ } else {
202
+ ssrState.state = SSRStateEnum.normal;
131
203
  }
132
- // If result is false, continue to normal mutation logic below
133
204
  }
134
205
  }
135
- }
136
- const sameDeletedNode = removedNodes.find(ref => {
137
- const n = ref.deref();
138
- if (!n || !addedNode) {
139
- return false;
206
+
207
+ // SSR placeholder logic - check and handle with await
208
+ if (this.getSSRPlaceholderHandler) {
209
+ const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
210
+ if (ssrPlaceholderHandler) {
211
+ if (ssrPlaceholderHandler.isPlaceholder(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
212
+ if (ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(addedNode)) {
213
+ var _this$intersectionObs10;
214
+ (_this$intersectionObs10 = this.intersectionObserver) === null || _this$intersectionObs10 === void 0 ? void 0 : _this$intersectionObs10.watchAndTag(addedNode, 'mutation:ssr-placeholder');
215
+ continue;
216
+ }
217
+ // If result is false, continue to normal mutation logic below
218
+ }
219
+ if (ssrPlaceholderHandler.isPlaceholderReplacement(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
220
+ const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(addedNode);
221
+ if (result !== false) {
222
+ var _this$intersectionObs11;
223
+ (_this$intersectionObs11 = this.intersectionObserver) === null || _this$intersectionObs11 === void 0 ? void 0 : _this$intersectionObs11.watchAndTag(addedNode, 'mutation:ssr-placeholder');
224
+ continue;
225
+ }
226
+ // If result is false, continue to normal mutation logic below
227
+ }
228
+ }
140
229
  }
141
- return n.isEqualNode(addedNode);
142
- });
143
- const isInIgnoreLsMarker = isInVCIgnoreIfNoLayoutShiftMarker(addedNode);
144
- if (sameDeletedNode && isInIgnoreLsMarker) {
145
- var _this$intersectionObs5;
146
- (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(addedNode, 'mutation:remount');
147
- continue;
148
- }
149
- if (isContainedWithinMediaWrapper(addedNode)) {
150
- var _this$intersectionObs6;
151
- (_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.watchAndTag(addedNode, 'mutation:media');
152
- continue;
153
- }
154
- const {
155
- isWithin: isWithinThirdPartySegment
156
- } = checkWithinComponent(addedNode, 'UFOThirdPartySegment', this.mapIs3pResult);
157
- if (isWithinThirdPartySegment) {
158
- var _this$intersectionObs7;
159
- (_this$intersectionObs7 = this.intersectionObserver) === null || _this$intersectionObs7 === void 0 ? void 0 : _this$intersectionObs7.watchAndTag(addedNode, 'mutation:third-party-element');
160
- continue;
161
- }
162
- for (const {
163
- isDisplayContentsElementChildren,
164
- element
165
- } of getMutatedElements(addedNode)) {
166
- if (isDisplayContentsElementChildren) {
167
- var _this$intersectionObs8;
168
- (_this$intersectionObs8 = this.intersectionObserver) === null || _this$intersectionObs8 === void 0 ? void 0 : _this$intersectionObs8.watchAndTag(element, 'mutation:display-contents-children-element');
169
- } else {
170
- var _this$intersectionObs9;
171
- (_this$intersectionObs9 = this.intersectionObserver) === null || _this$intersectionObs9 === void 0 ? void 0 : _this$intersectionObs9.watchAndTag(element, createElementMutationsWatcher(removedNodeRects));
230
+ const sameDeletedNode = removedNodes.find(ref => {
231
+ const n = ref.deref();
232
+ if (!n || !addedNode) {
233
+ return false;
234
+ }
235
+ return n.isEqualNode(addedNode);
236
+ });
237
+ const isInIgnoreLsMarker = isInVCIgnoreIfNoLayoutShiftMarker(addedNode);
238
+ if (sameDeletedNode && isInIgnoreLsMarker) {
239
+ var _this$intersectionObs12;
240
+ (_this$intersectionObs12 = this.intersectionObserver) === null || _this$intersectionObs12 === void 0 ? void 0 : _this$intersectionObs12.watchAndTag(addedNode, 'mutation:remount');
241
+ continue;
242
+ }
243
+ if (isContainedWithinMediaWrapper(addedNode)) {
244
+ var _this$intersectionObs13;
245
+ (_this$intersectionObs13 = this.intersectionObserver) === null || _this$intersectionObs13 === void 0 ? void 0 : _this$intersectionObs13.watchAndTag(addedNode, 'mutation:media');
246
+ continue;
247
+ }
248
+ const {
249
+ isWithin: isWithinThirdPartySegment
250
+ } = checkWithinComponent(addedNode, 'UFOThirdPartySegment', this.mapIs3pResult);
251
+ if (isWithinThirdPartySegment) {
252
+ var _this$intersectionObs14;
253
+ (_this$intersectionObs14 = this.intersectionObserver) === null || _this$intersectionObs14 === void 0 ? void 0 : _this$intersectionObs14.watchAndTag(addedNode, 'mutation:third-party-element');
254
+ continue;
255
+ }
256
+ for (const {
257
+ isDisplayContentsElementChildren,
258
+ element
259
+ } of getMutatedElements(addedNode)) {
260
+ if (isDisplayContentsElementChildren) {
261
+ var _this$intersectionObs15;
262
+ (_this$intersectionObs15 = this.intersectionObserver) === null || _this$intersectionObs15 === void 0 ? void 0 : _this$intersectionObs15.watchAndTag(element, 'mutation:display-contents-children-element');
263
+ } else {
264
+ var _this$intersectionObs16;
265
+ (_this$intersectionObs16 = this.intersectionObserver) === null || _this$intersectionObs16 === void 0 ? void 0 : _this$intersectionObs16.watchAndTag(element, createElementMutationsWatcher(removedNodeRects));
266
+ }
172
267
  }
173
268
  }
174
269
  }
@@ -179,8 +274,8 @@ export default class ViewportObserver {
179
274
  oldValue,
180
275
  newValue
181
276
  }) => {
182
- var _this$intersectionObs0;
183
- (_this$intersectionObs0 = this.intersectionObserver) === null || _this$intersectionObs0 === void 0 ? void 0 : _this$intersectionObs0.watchAndTag(target, ({
277
+ var _this$intersectionObs17;
278
+ (_this$intersectionObs17 = this.intersectionObserver) === null || _this$intersectionObs17 === void 0 ? void 0 : _this$intersectionObs17.watchAndTag(target, ({
184
279
  target,
185
280
  rect
186
281
  }) => {
@@ -322,12 +417,12 @@ export default class ViewportObserver {
322
417
  this.isStarted = true;
323
418
  }
324
419
  stop() {
325
- var _this$mutationObserve2, _this$intersectionObs1, _this$performanceObse2;
420
+ var _this$mutationObserve2, _this$intersectionObs18, _this$performanceObse2;
326
421
  if (!this.isStarted) {
327
422
  return;
328
423
  }
329
424
  (_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 ? void 0 : _this$mutationObserve2.disconnect();
330
- (_this$intersectionObs1 = this.intersectionObserver) === null || _this$intersectionObs1 === void 0 ? void 0 : _this$intersectionObs1.disconnect();
425
+ (_this$intersectionObs18 = this.intersectionObserver) === null || _this$intersectionObs18 === void 0 ? void 0 : _this$intersectionObs18.disconnect();
331
426
  (_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 ? void 0 : _this$performanceObse2.disconnect();
332
427
  this.isStarted = false;
333
428
  // Clean up caches when stopping
@@ -1,4 +1,5 @@
1
1
  import Bowser from 'bowser-ultralight';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  export default function getBrowserMetadata() {
3
4
  var data = {
4
5
  time: {
@@ -40,6 +41,9 @@ export default function getBrowserMetadata() {
40
41
  downlink: navigator.connection.downlink
41
42
  };
42
43
  }
44
+ if (typeof navigator !== 'undefined' && fg('react_ufo_add_webdriver_info')) {
45
+ data.webdriver = Boolean(navigator.webdriver);
46
+ }
43
47
  return data;
44
48
  }
45
49
 
@@ -59,6 +63,11 @@ export function getBrowserMetadataToLegacyFormat() {
59
63
  legacyFormat['event:browser:version'] = metadata.browser.version;
60
64
  }
61
65
 
66
+ // Webdriver data
67
+ if (metadata.webdriver !== undefined) {
68
+ legacyFormat['event:browser:webdriver'] = metadata.webdriver;
69
+ }
70
+
62
71
  // Device data
63
72
  if (metadata.device) {
64
73
  if (metadata.device.cpus !== undefined) {
@@ -1,6 +1,7 @@
1
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
2
  import _createClass from "@babel/runtime/helpers/createClass";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import { fg } from '@atlaskit/platform-feature-flags';
4
5
  var ANCESTOR_LOOKUP_LIMIT = 10;
5
6
  var PAGE_LAYOUT_ID = 'page-layout.root';
6
7
  export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
@@ -59,7 +60,7 @@ export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
59
60
  _resolve(hasSameSizePosition);
60
61
  } else {
61
62
  requestAnimationFrame(function () {
62
- var targetRect = target.getBoundingClientRect();
63
+ var targetRect = _this.getEffectiveBoundingRect(target);
63
64
  var hasSameSizePosition = _this.hasSameSizePosition(rect, targetRect);
64
65
  _resolve(hasSameSizePosition);
65
66
  });
@@ -78,7 +79,7 @@ export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
78
79
  _resolve2(_hasSameSizePosition);
79
80
  } else {
80
81
  requestAnimationFrame(function () {
81
- var targetRect = target.getBoundingClientRect();
82
+ var targetRect = _this.getEffectiveBoundingRect(target);
82
83
  var hasSameSizePosition = _this.hasSameSizePosition(_rect, targetRect);
83
84
  _resolve2(hasSameSizePosition);
84
85
  });
@@ -236,7 +237,7 @@ export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
236
237
  if (!placeholderRects) {
237
238
  return false;
238
239
  }
239
- return this.hasSameSizePosition(placeholderRects, el.getBoundingClientRect());
240
+ return this.hasSameSizePosition(placeholderRects, this.getEffectiveBoundingRect(el));
240
241
  }
241
242
  }, {
242
243
  key: "getSize",
@@ -275,6 +276,55 @@ export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
275
276
  var verticalCheck = Math.abs(rect.y - boundingClientRect.y) < this.EQUALITY_THRESHOLD && Math.abs(rect.height - boundingClientRect.height) < this.EQUALITY_THRESHOLD;
276
277
  return horizontalCheck && verticalCheck || false;
277
278
  }
279
+
280
+ /**
281
+ * Gets the effective bounding rectangle for an element, handling display: contents elements
282
+ * by collecting dimensions from their children instead
283
+ */
284
+ }, {
285
+ key: "getEffectiveBoundingRect",
286
+ value: function getEffectiveBoundingRect(el) {
287
+ var enableDisplayContentsSupport = fg('platform_ufo_ssr_placeholders_for_display_contents');
288
+
289
+ // Only handle display: contents if feature flag is enabled
290
+ if (enableDisplayContentsSupport) {
291
+ var computedStyle = window.getComputedStyle(el);
292
+
293
+ // If element has display: contents, collect bounding rect from children
294
+ if (computedStyle.display === 'contents') {
295
+ var children = Array.from(el.children);
296
+ if (children.length === 0) {
297
+ // No children, return zero rect
298
+ return new DOMRect(0, 0, 0, 0);
299
+ }
300
+
301
+ // Calculate union of all children's bounding rects
302
+ var minX = Infinity;
303
+ var minY = Infinity;
304
+ var maxX = -Infinity;
305
+ var maxY = -Infinity;
306
+ children.forEach(function (child) {
307
+ var childRect = child.getBoundingClientRect();
308
+ // Skip children with zero dimensions (likely also display: contents)
309
+ if (childRect.width > 0 || childRect.height > 0) {
310
+ minX = Math.min(minX, childRect.left);
311
+ minY = Math.min(minY, childRect.top);
312
+ maxX = Math.max(maxX, childRect.right);
313
+ maxY = Math.max(maxY, childRect.bottom);
314
+ }
315
+ });
316
+
317
+ // If no children with dimensions found, return zero rect
318
+ if (minX === Infinity) {
319
+ return new DOMRect(0, 0, 0, 0);
320
+ }
321
+ return new DOMRect(minX, minY, maxX - minX, maxY - minY);
322
+ }
323
+ }
324
+
325
+ // Normal element or feature flag disabled, return its bounding rect
326
+ return el.getBoundingClientRect();
327
+ }
278
328
  }, {
279
329
  key: "isDummyRect",
280
330
  value: function isDummyRect(rect) {
@@ -1,23 +1,74 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+
1
3
  // lightweight script to scan the SSR response and collect all elements with data-ssr-placeholder attribute
2
4
  // and save their size/positions in a map __SSR_PLACEHOLDERS_DIMENSIONS__ on the Window object. Each placeholderId is
3
5
  // unique and maps to its corresponding elements bounding client rectangle dimensions.
4
6
  export function collectSSRPlaceholderDimensions(document, window) {
5
7
  var enablePageLayoutPlaceholder = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
8
+ var enableDisplayContentsSupport = fg('platform_ufo_ssr_placeholders_for_display_contents');
6
9
  var ssrPlaceholders = document === null || document === void 0 ? void 0 : document.querySelectorAll('[data-ssr-placeholder]');
7
10
  ssrPlaceholders.forEach(function (elem) {
8
11
  var placeholderId = elem.getAttribute('data-ssr-placeholder');
9
- var boundingClient = elem.getBoundingClientRect();
10
12
  if (placeholderId) {
11
13
  window.__SSR_PLACEHOLDERS_DIMENSIONS__ = window.__SSR_PLACEHOLDERS_DIMENSIONS__ || {};
12
- window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = boundingClient;
14
+ if (enableDisplayContentsSupport) {
15
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = getEffectiveBoundingRect(elem, window);
16
+ } else {
17
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = elem.getBoundingClientRect();
18
+ }
13
19
  }
14
20
  });
15
21
  if (enablePageLayoutPlaceholder) {
16
22
  var pageLayoutRoot = document === null || document === void 0 ? void 0 : document.getElementById('unsafe-design-system-page-layout-root');
17
23
  if (pageLayoutRoot) {
18
- var boundingClient = pageLayoutRoot.getBoundingClientRect();
19
24
  window.__SSR_PLACEHOLDERS_DIMENSIONS__ = window.__SSR_PLACEHOLDERS_DIMENSIONS__ || {};
20
- window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = boundingClient;
25
+ if (enableDisplayContentsSupport) {
26
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = getEffectiveBoundingRect(pageLayoutRoot, window);
27
+ } else {
28
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = pageLayoutRoot.getBoundingClientRect();
29
+ }
21
30
  }
22
31
  }
32
+ }
33
+
34
+ /**
35
+ * Gets the effective bounding rectangle for an element, handling display: contents elements
36
+ * by collecting dimensions from their children instead
37
+ */
38
+ function getEffectiveBoundingRect(elem, window) {
39
+ var computedStyle = window.getComputedStyle(elem);
40
+
41
+ // If element has display: contents, collect bounding rect from children
42
+ if (computedStyle.display === 'contents') {
43
+ var children = Array.from(elem.children);
44
+ if (children.length === 0) {
45
+ // No children, return zero rect
46
+ return new DOMRect(0, 0, 0, 0);
47
+ }
48
+
49
+ // Calculate union of all children's bounding rects
50
+ var minX = Infinity;
51
+ var minY = Infinity;
52
+ var maxX = -Infinity;
53
+ var maxY = -Infinity;
54
+ children.forEach(function (child) {
55
+ var childRect = child.getBoundingClientRect();
56
+ // Skip children with zero dimensions (likely also display: contents)
57
+ if (childRect.width > 0 || childRect.height > 0) {
58
+ minX = Math.min(minX, childRect.left);
59
+ minY = Math.min(minY, childRect.top);
60
+ maxX = Math.max(maxX, childRect.right);
61
+ maxY = Math.max(maxY, childRect.bottom);
62
+ }
63
+ });
64
+
65
+ // If no children with dimensions found, return zero rect
66
+ if (minX === Infinity) {
67
+ return new DOMRect(0, 0, 0, 0);
68
+ }
69
+ return new DOMRect(minX, minY, maxX - minX, maxY - minY);
70
+ }
71
+
72
+ // Normal element, return its bounding rect
73
+ return elem.getBoundingClientRect();
23
74
  }