@atlaskit/react-ufo 4.15.4 → 4.15.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 (26) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +7 -0
  3. package/dist/cjs/vc/vc-observer-new/metric-calculator/vcnext/index.js +4 -1
  4. package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +290 -191
  5. package/dist/cjs/vc/vc-observer-new/viewport-observer/intersection-observer/index.js +45 -2
  6. package/dist/cjs/vc/vc-observer-new/viewport-observer/utils/get-mutated-elements.js +15 -4
  7. package/dist/cjs/vc/vc-observer-new/viewport-observer/utils/is-zero-dimension-rectangle.js +9 -0
  8. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +5 -0
  9. package/dist/es2019/vc/vc-observer-new/metric-calculator/vcnext/index.js +4 -1
  10. package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +158 -81
  11. package/dist/es2019/vc/vc-observer-new/viewport-observer/intersection-observer/index.js +33 -2
  12. package/dist/es2019/vc/vc-observer-new/viewport-observer/utils/get-mutated-elements.js +15 -4
  13. package/dist/es2019/vc/vc-observer-new/viewport-observer/utils/is-zero-dimension-rectangle.js +3 -0
  14. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +7 -0
  15. package/dist/esm/vc/vc-observer-new/metric-calculator/vcnext/index.js +4 -1
  16. package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +288 -189
  17. package/dist/esm/vc/vc-observer-new/viewport-observer/intersection-observer/index.js +45 -2
  18. package/dist/esm/vc/vc-observer-new/viewport-observer/utils/get-mutated-elements.js +15 -4
  19. package/dist/esm/vc/vc-observer-new/viewport-observer/utils/is-zero-dimension-rectangle.js +3 -0
  20. package/dist/types/vc/vc-observer/observers/ssr-placeholders/index.d.ts +1 -0
  21. package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
  22. package/dist/types/vc/vc-observer-new/viewport-observer/utils/is-zero-dimension-rectangle.d.ts +1 -0
  23. package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/index.d.ts +1 -0
  24. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +1 -1
  25. package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/utils/is-zero-dimension-rectangle.d.ts +1 -0
  26. package/package.json +7 -1
@@ -4,6 +4,11 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createIntersectionObserver = createIntersectionObserver;
7
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
8
+ var _isZeroDimensionRectangle = require("../utils/is-zero-dimension-rectangle");
9
+ 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; } } }; }
10
+ 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; } }
11
+ 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; }
7
12
  function isValidEntry(entry) {
8
13
  return entry.isIntersecting && entry.intersectionRect.width > 0 && entry.intersectionRect.height > 0;
9
14
  }
@@ -18,12 +23,50 @@ function createIntersectionObserver(_ref) {
18
23
  var validEntries = [];
19
24
  var startTime = performance.now();
20
25
  entries.forEach(function (entry) {
21
- if (!(entry.target instanceof HTMLElement) || !isValidEntry(entry)) {
26
+ if (!(entry.target instanceof HTMLElement)) {
27
+ return;
28
+ }
29
+ var tagOrCallback = callbacksPerElement.get(entry.target);
30
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_detect_zero_dimension_rectangles')) {
31
+ if ((0, _isZeroDimensionRectangle.isZeroDimensionRectangle)(entry.intersectionRect)) {
32
+ var zeroDimensionRectangleTagCallback = function zeroDimensionRectangleTagCallback(props) {
33
+ var tagOrCallbackResult = typeof tagOrCallback === 'function' ? tagOrCallback(props) : tagOrCallback;
34
+
35
+ // override as display-contents mutation
36
+ if (tagOrCallbackResult === 'mutation:element') {
37
+ return 'mutation:display-contents-children-element';
38
+ }
39
+
40
+ // override as display-contents mutation
41
+ if (tagOrCallbackResult && typeof tagOrCallbackResult !== 'string' && tagOrCallbackResult.type === 'mutation:attribute') {
42
+ return {
43
+ type: 'mutation:display-contents-children-attribute',
44
+ mutationData: tagOrCallbackResult.mutationData
45
+ };
46
+ }
47
+ return tagOrCallbackResult;
48
+ };
49
+ var _iterator = _createForOfIteratorHelper(entry.target.children),
50
+ _step;
51
+ try {
52
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
53
+ var child = _step.value;
54
+ observer.observe(child);
55
+ callbacksPerElement.set(child, zeroDimensionRectangleTagCallback);
56
+ }
57
+ } catch (err) {
58
+ _iterator.e(err);
59
+ } finally {
60
+ _iterator.f();
61
+ }
62
+ return;
63
+ }
64
+ }
65
+ if (!isValidEntry(entry)) {
22
66
  return;
23
67
  }
24
68
  var mutationTag = null;
25
69
  var mutationData = null;
26
- var tagOrCallback = callbacksPerElement.get(entry.target);
27
70
  if (typeof tagOrCallback === 'function') {
28
71
  var tagOrCallbackResult = tagOrCallback({
29
72
  target: entry.target,
@@ -10,9 +10,21 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
10
  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; } } }; }
11
11
  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; } }
12
12
  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; }
13
+ function isElementStyledWithDisplayContents(element) {
14
+ var _window2;
15
+ // To minimise calling `getComputedStyle`, we are making an assumption that if an element is from the Entrypoints framework, then it will have `display: contents` styling
16
+ // as per https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/e4ccf437262ef4c0fd3c651ffb7ad4770b15aed4/jira/src/packages/platform/entry-points/entry-point-placeholder/src/index.tsx#lines-136
17
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_detect_entrypoint_parent')) {
18
+ var _window;
19
+ if (element.hasAttribute('data-ep-placeholder-id')) {
20
+ return true;
21
+ }
22
+ return ((_window = window) === null || _window === void 0 || (_window = _window.getComputedStyle(element)) === null || _window === void 0 ? void 0 : _window.display) === 'contents';
23
+ }
24
+ return ((_window2 = window) === null || _window2 === void 0 || (_window2 = _window2.getComputedStyle(element)) === null || _window2 === void 0 ? void 0 : _window2.display) === 'contents';
25
+ }
13
26
  var MAX_NESTED_LEVELS_OF_DISPLAY_CONTENT_ELEMENTS_HANDLED = 3;
14
27
  function getMutatedElements(element) {
15
- var _window;
16
28
  var depthLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
17
29
  if ((0, _platformFeatureFlags.fg)('platform_ufo_disable_vcnext_observations')) {
18
30
  return [{
@@ -20,16 +32,15 @@ function getMutatedElements(element) {
20
32
  isDisplayContentsElementChildren: false
21
33
  }];
22
34
  }
23
- if (((_window = window) === null || _window === void 0 || (_window = _window.getComputedStyle(element)) === null || _window === void 0 ? void 0 : _window.display) === 'contents') {
35
+ if (isElementStyledWithDisplayContents(element)) {
24
36
  var mutatedElements = [];
25
37
  var nestedDisplayContentsElementChildren = [];
26
38
  var _iterator = _createForOfIteratorHelper(element.children),
27
39
  _step;
28
40
  try {
29
41
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
30
- var _window2;
31
42
  var child = _step.value;
32
- if (((_window2 = window) === null || _window2 === void 0 || (_window2 = _window2.getComputedStyle(child)) === null || _window2 === void 0 ? void 0 : _window2.display) === 'contents') {
43
+ if (isElementStyledWithDisplayContents(child)) {
33
44
  nestedDisplayContentsElementChildren.push(child);
34
45
  }
35
46
  mutatedElements.push({
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isZeroDimensionRectangle = isZeroDimensionRectangle;
7
+ function isZeroDimensionRectangle(rect) {
8
+ return rect.bottom === 0 && rect.top === 0 && rect.left === 0 && rect.right === 0 && rect.x === 0 && rect.y === 0 && rect.width === 0 && rect.height === 0;
9
+ }
@@ -233,6 +233,11 @@ export class SSRPlaceholderHandlers {
233
233
  }
234
234
  });
235
235
  }
236
+ validateReactComponentMatchToPlaceholderV4(el) {
237
+ el = this.findNearestPlaceholderContainerIfIgnored(el);
238
+ const id = this.getPlaceholderReplacementId(el);
239
+ return this.staticPlaceholders.has(id);
240
+ }
236
241
  hasSameSizePosition(rect, boundingClientRect) {
237
242
  if (!rect) {
238
243
  return false;
@@ -8,7 +8,10 @@ const getConsideredEntryTypes = () => {
8
8
  if (fg('platform_ufo_remove_ssr_placeholder_in_ttvc_v4')) {
9
9
  consideredEntryTypes.push('mutation:ssr-placeholder');
10
10
  }
11
- return ['mutation:display-contents-children-element'];
11
+ if (fg('platform_ufo_detect_zero_dimension_rectangles')) {
12
+ consideredEntryTypes.push('mutation:display-contents-children-attribute');
13
+ }
14
+ return consideredEntryTypes;
12
15
  };
13
16
  const getExcludedEntryTypes = () => {
14
17
  const excludedEntryTypes = ['layout-shift:same-rect'];
@@ -31,6 +31,67 @@ const createElementMutationsWatcher = removedNodeRects => ({
31
31
  }
32
32
  return 'mutation:element';
33
33
  };
34
+ const createElementMutationsWatcherV4 = (removedNodeRects, isWithinThirdPartySegment, hasSameDeletedNode, timestamp, isTargetReactRoot, getSSRState, getSSRPlaceholderHandler) => ({
35
+ target,
36
+ rect
37
+ }) => {
38
+ if (getSSRState) {
39
+ const ssrState = getSSRState();
40
+ const SSRStateEnum = {
41
+ normal: 1,
42
+ waitingForFirstRender: 2,
43
+ ignoring: 3
44
+ };
45
+ if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && isTargetReactRoot) {
46
+ ssrState.state = SSRStateEnum.ignoring;
47
+ if (ssrState.renderStop === -1) {
48
+ // arbitrary 500ms DOM update window
49
+ ssrState.renderStop = timestamp + 500;
50
+ }
51
+ return 'ssr-hydration';
52
+ }
53
+ if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && isTargetReactRoot) {
54
+ if (timestamp <= ssrState.renderStop) {
55
+ return 'ssr-hydration';
56
+ } else {
57
+ ssrState.state = SSRStateEnum.normal;
58
+ }
59
+ }
60
+ }
61
+ if (getSSRPlaceholderHandler) {
62
+ const ssrPlaceholderHandler = getSSRPlaceholderHandler();
63
+ if (ssrPlaceholderHandler) {
64
+ if ((ssrPlaceholderHandler.isPlaceholder(target) || ssrPlaceholderHandler.isPlaceholderIgnored(target)) && ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(target)) {
65
+ return 'mutation:ssr-placeholder';
66
+ }
67
+ if ((ssrPlaceholderHandler.isPlaceholderReplacement(target) || ssrPlaceholderHandler.isPlaceholderIgnored(target)) && ssrPlaceholderHandler.validateReactComponentMatchToPlaceholderV4(target)) {
68
+ return 'mutation:ssr-placeholder';
69
+ }
70
+ }
71
+ }
72
+ if (hasSameDeletedNode && isInVCIgnoreIfNoLayoutShiftMarker(target)) {
73
+ return 'mutation:remount';
74
+ }
75
+ if (isContainedWithinMediaWrapper(target)) {
76
+ return 'mutation:media';
77
+ }
78
+ if (isWithinThirdPartySegment) {
79
+ return 'mutation:third-party-element';
80
+ }
81
+ const isInIgnoreLsMarker = isInVCIgnoreIfNoLayoutShiftMarker(target);
82
+ if (!isInIgnoreLsMarker) {
83
+ return 'mutation:element';
84
+ }
85
+ const isRLLPlaceholder = RLLPlaceholderHandlers.getInstance().isRLLPlaceholderHydration(rect);
86
+ if (isRLLPlaceholder && isInIgnoreLsMarker) {
87
+ return 'mutation:rll-placeholder';
88
+ }
89
+ const wasDeleted = removedNodeRects.some(nr => isSameRectDimensions(nr, rect));
90
+ if (wasDeleted && isInIgnoreLsMarker) {
91
+ return 'mutation:element-replacement';
92
+ }
93
+ return 'mutation:element';
94
+ };
34
95
  export default class ViewportObserver {
35
96
  // SSR context functions
36
97
 
@@ -81,96 +142,112 @@ export default class ViewportObserver {
81
142
  if (!addedNode) {
82
143
  continue;
83
144
  }
84
- for (const {
85
- isDisplayContentsElementChildren,
86
- element
87
- } of getMutatedElements(addedNode)) {
88
- // SSR hydration logic
89
- if (this.getSSRState) {
90
- const ssrState = this.getSSRState();
91
- const SSRStateEnum = {
92
- normal: 1,
93
- waitingForFirstRender: 2,
94
- ignoring: 3
95
- };
96
- if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
97
- var _this$intersectionObs;
98
- ssrState.state = SSRStateEnum.ignoring;
99
- if (ssrState.renderStop === -1) {
100
- // arbitrary 500ms DOM update window
101
- ssrState.renderStop = timestamp + 500;
102
- }
103
- (_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.watchAndTag(element, 'ssr-hydration');
104
- continue;
145
+ if (fg('platform_ufo_detect_zero_dimension_rectangles')) {
146
+ var _this$getSSRState, _this$getSSRState$cal, _this$intersectionObs;
147
+ const hasSameDeletedNode = removedNodes.find(ref => {
148
+ const n = ref.deref();
149
+ if (!n || !addedNode) {
150
+ return false;
105
151
  }
106
- if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
107
- if (timestamp <= ssrState.renderStop) {
152
+ return n.isEqualNode(addedNode);
153
+ });
154
+ const {
155
+ isWithin: isWithinThirdPartySegment
156
+ } = checkWithinComponent(addedNode, 'UFOThirdPartySegment', this.mapIs3pResult);
157
+ const isTargetReactRoot = targetNode === ((_this$getSSRState = this.getSSRState) === null || _this$getSSRState === void 0 ? void 0 : (_this$getSSRState$cal = _this$getSSRState.call(this)) === null || _this$getSSRState$cal === void 0 ? void 0 : _this$getSSRState$cal.reactRootElement);
158
+ (_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.watchAndTag(addedNode, createElementMutationsWatcherV4(removedNodeRects, isWithinThirdPartySegment, !!hasSameDeletedNode, timestamp, isTargetReactRoot, this.getSSRState, this.getSSRPlaceholderHandler));
159
+ } else {
160
+ for (const {
161
+ isDisplayContentsElementChildren,
162
+ element
163
+ } of getMutatedElements(addedNode)) {
164
+ // SSR hydration logic
165
+ if (this.getSSRState) {
166
+ const ssrState = this.getSSRState();
167
+ const SSRStateEnum = {
168
+ normal: 1,
169
+ waitingForFirstRender: 2,
170
+ ignoring: 3
171
+ };
172
+ if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
108
173
  var _this$intersectionObs2;
174
+ ssrState.state = SSRStateEnum.ignoring;
175
+ if (ssrState.renderStop === -1) {
176
+ // arbitrary 500ms DOM update window
177
+ ssrState.renderStop = timestamp + 500;
178
+ }
109
179
  (_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(element, 'ssr-hydration');
110
180
  continue;
111
- } else {
112
- ssrState.state = SSRStateEnum.normal;
113
181
  }
114
- }
115
- }
116
-
117
- // SSR placeholder logic - check and handle with await
118
- if (this.getSSRPlaceholderHandler) {
119
- const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
120
- if (ssrPlaceholderHandler) {
121
- if (ssrPlaceholderHandler.isPlaceholder(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
122
- if (ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(element)) {
182
+ if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
183
+ if (timestamp <= ssrState.renderStop) {
123
184
  var _this$intersectionObs3;
124
- (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(element, 'mutation:ssr-placeholder');
185
+ (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(element, 'ssr-hydration');
125
186
  continue;
187
+ } else {
188
+ ssrState.state = SSRStateEnum.normal;
126
189
  }
127
- // If result is false, continue to normal mutation logic below
128
190
  }
129
- if (ssrPlaceholderHandler.isPlaceholderReplacement(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
130
- const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(element);
131
- if (result !== false) {
132
- var _this$intersectionObs4;
133
- (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(element, 'mutation:ssr-placeholder');
134
- continue;
191
+ }
192
+
193
+ // SSR placeholder logic - check and handle with await
194
+ if (this.getSSRPlaceholderHandler) {
195
+ const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
196
+ if (ssrPlaceholderHandler) {
197
+ if (ssrPlaceholderHandler.isPlaceholder(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
198
+ if (ssrPlaceholderHandler.checkIfExistedAndSizeMatchingV3(element)) {
199
+ var _this$intersectionObs4;
200
+ (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(element, 'mutation:ssr-placeholder');
201
+ continue;
202
+ }
203
+ // If result is false, continue to normal mutation logic below
204
+ }
205
+ if (ssrPlaceholderHandler.isPlaceholderReplacement(element) || ssrPlaceholderHandler.isPlaceholderIgnored(element)) {
206
+ const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(element);
207
+ if (result !== false) {
208
+ var _this$intersectionObs5;
209
+ (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(element, 'mutation:ssr-placeholder');
210
+ continue;
211
+ }
212
+ // If result is false, continue to normal mutation logic below
135
213
  }
136
- // If result is false, continue to normal mutation logic below
137
214
  }
138
215
  }
139
- }
140
- const sameDeletedNode = removedNodes.find(ref => {
141
- const n = ref.deref();
142
- if (!n || !element) {
143
- return false;
216
+ const sameDeletedNode = removedNodes.find(ref => {
217
+ const n = ref.deref();
218
+ if (!n || !element) {
219
+ return false;
220
+ }
221
+ return n.isEqualNode(element);
222
+ });
223
+ const isInIgnoreLsMarker = element instanceof HTMLElement ? isInVCIgnoreIfNoLayoutShiftMarker(element) : false;
224
+ if (sameDeletedNode && isInIgnoreLsMarker) {
225
+ var _this$intersectionObs6;
226
+ (_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.watchAndTag(element, 'mutation:remount');
227
+ continue;
228
+ }
229
+ if (isContainedWithinMediaWrapper(element)) {
230
+ var _this$intersectionObs7;
231
+ (_this$intersectionObs7 = this.intersectionObserver) === null || _this$intersectionObs7 === void 0 ? void 0 : _this$intersectionObs7.watchAndTag(element, 'mutation:media');
232
+ continue;
233
+ }
234
+ const {
235
+ isWithin: isWithinThirdPartySegment
236
+ } = element instanceof HTMLElement ? checkWithinComponent(element, 'UFOThirdPartySegment', this.mapIs3pResult) : {
237
+ isWithin: false
238
+ };
239
+ if (isWithinThirdPartySegment) {
240
+ var _this$intersectionObs8;
241
+ (_this$intersectionObs8 = this.intersectionObserver) === null || _this$intersectionObs8 === void 0 ? void 0 : _this$intersectionObs8.watchAndTag(element, 'mutation:third-party-element');
242
+ continue;
243
+ }
244
+ if (isDisplayContentsElementChildren) {
245
+ var _this$intersectionObs9;
246
+ (_this$intersectionObs9 = this.intersectionObserver) === null || _this$intersectionObs9 === void 0 ? void 0 : _this$intersectionObs9.watchAndTag(element, 'mutation:display-contents-children-element');
247
+ } else {
248
+ var _this$intersectionObs0;
249
+ (_this$intersectionObs0 = this.intersectionObserver) === null || _this$intersectionObs0 === void 0 ? void 0 : _this$intersectionObs0.watchAndTag(element, createElementMutationsWatcher(removedNodeRects));
144
250
  }
145
- return n.isEqualNode(element);
146
- });
147
- const isInIgnoreLsMarker = element instanceof HTMLElement ? isInVCIgnoreIfNoLayoutShiftMarker(element) : false;
148
- if (sameDeletedNode && isInIgnoreLsMarker) {
149
- var _this$intersectionObs5;
150
- (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(element, 'mutation:remount');
151
- continue;
152
- }
153
- if (isContainedWithinMediaWrapper(element)) {
154
- var _this$intersectionObs6;
155
- (_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.watchAndTag(element, 'mutation:media');
156
- continue;
157
- }
158
- const {
159
- isWithin: isWithinThirdPartySegment
160
- } = element instanceof HTMLElement ? checkWithinComponent(element, 'UFOThirdPartySegment', this.mapIs3pResult) : {
161
- isWithin: false
162
- };
163
- if (isWithinThirdPartySegment) {
164
- var _this$intersectionObs7;
165
- (_this$intersectionObs7 = this.intersectionObserver) === null || _this$intersectionObs7 === void 0 ? void 0 : _this$intersectionObs7.watchAndTag(element, 'mutation:third-party-element');
166
- continue;
167
- }
168
- if (isDisplayContentsElementChildren) {
169
- var _this$intersectionObs8;
170
- (_this$intersectionObs8 = this.intersectionObserver) === null || _this$intersectionObs8 === void 0 ? void 0 : _this$intersectionObs8.watchAndTag(element, 'mutation:display-contents-children-element');
171
- } else {
172
- var _this$intersectionObs9;
173
- (_this$intersectionObs9 = this.intersectionObserver) === null || _this$intersectionObs9 === void 0 ? void 0 : _this$intersectionObs9.watchAndTag(element, createElementMutationsWatcher(removedNodeRects));
174
251
  }
175
252
  }
176
253
  }
@@ -181,8 +258,8 @@ export default class ViewportObserver {
181
258
  oldValue,
182
259
  newValue
183
260
  }) => {
184
- var _this$intersectionObs0;
185
- (_this$intersectionObs0 = this.intersectionObserver) === null || _this$intersectionObs0 === void 0 ? void 0 : _this$intersectionObs0.watchAndTag(target, ({
261
+ var _this$intersectionObs1;
262
+ (_this$intersectionObs1 = this.intersectionObserver) === null || _this$intersectionObs1 === void 0 ? void 0 : _this$intersectionObs1.watchAndTag(target, ({
186
263
  target,
187
264
  rect
188
265
  }) => {
@@ -339,12 +416,12 @@ export default class ViewportObserver {
339
416
  this.isStarted = true;
340
417
  }
341
418
  stop() {
342
- var _this$mutationObserve2, _this$intersectionObs1, _this$performanceObse2;
419
+ var _this$mutationObserve2, _this$intersectionObs10, _this$performanceObse2;
343
420
  if (!this.isStarted) {
344
421
  return;
345
422
  }
346
423
  (_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 ? void 0 : _this$mutationObserve2.disconnect();
347
- (_this$intersectionObs1 = this.intersectionObserver) === null || _this$intersectionObs1 === void 0 ? void 0 : _this$intersectionObs1.disconnect();
424
+ (_this$intersectionObs10 = this.intersectionObserver) === null || _this$intersectionObs10 === void 0 ? void 0 : _this$intersectionObs10.disconnect();
348
425
  (_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 ? void 0 : _this$performanceObse2.disconnect();
349
426
  this.isStarted = false;
350
427
  // Clean up caches when stopping
@@ -1,3 +1,5 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ import { isZeroDimensionRectangle } from '../utils/is-zero-dimension-rectangle';
1
3
  function isValidEntry(entry) {
2
4
  return entry.isIntersecting && entry.intersectionRect.width > 0 && entry.intersectionRect.height > 0;
3
5
  }
@@ -14,12 +16,41 @@ export function createIntersectionObserver({
14
16
  const startTime = performance.now();
15
17
  entries.forEach(entry => {
16
18
  var _mutationTag;
17
- if (!(entry.target instanceof HTMLElement) || !isValidEntry(entry)) {
19
+ if (!(entry.target instanceof HTMLElement)) {
20
+ return;
21
+ }
22
+ const tagOrCallback = callbacksPerElement.get(entry.target);
23
+ if (fg('platform_ufo_detect_zero_dimension_rectangles')) {
24
+ if (isZeroDimensionRectangle(entry.intersectionRect)) {
25
+ const zeroDimensionRectangleTagCallback = props => {
26
+ const tagOrCallbackResult = typeof tagOrCallback === 'function' ? tagOrCallback(props) : tagOrCallback;
27
+
28
+ // override as display-contents mutation
29
+ if (tagOrCallbackResult === 'mutation:element') {
30
+ return 'mutation:display-contents-children-element';
31
+ }
32
+
33
+ // override as display-contents mutation
34
+ if (tagOrCallbackResult && typeof tagOrCallbackResult !== 'string' && tagOrCallbackResult.type === 'mutation:attribute') {
35
+ return {
36
+ type: 'mutation:display-contents-children-attribute',
37
+ mutationData: tagOrCallbackResult.mutationData
38
+ };
39
+ }
40
+ return tagOrCallbackResult;
41
+ };
42
+ for (const child of entry.target.children) {
43
+ observer.observe(child);
44
+ callbacksPerElement.set(child, zeroDimensionRectangleTagCallback);
45
+ }
46
+ return;
47
+ }
48
+ }
49
+ if (!isValidEntry(entry)) {
18
50
  return;
19
51
  }
20
52
  let mutationTag = null;
21
53
  let mutationData = null;
22
- const tagOrCallback = callbacksPerElement.get(entry.target);
23
54
  if (typeof tagOrCallback === 'function') {
24
55
  const tagOrCallbackResult = tagOrCallback({
25
56
  target: entry.target,
@@ -1,19 +1,30 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
+ function isElementStyledWithDisplayContents(element) {
3
+ var _window2, _window2$getComputedS;
4
+ // To minimise calling `getComputedStyle`, we are making an assumption that if an element is from the Entrypoints framework, then it will have `display: contents` styling
5
+ // as per https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/e4ccf437262ef4c0fd3c651ffb7ad4770b15aed4/jira/src/packages/platform/entry-points/entry-point-placeholder/src/index.tsx#lines-136
6
+ if (fg('platform_ufo_detect_entrypoint_parent')) {
7
+ var _window, _window$getComputedSt;
8
+ if (element.hasAttribute('data-ep-placeholder-id')) {
9
+ return true;
10
+ }
11
+ return ((_window = window) === null || _window === void 0 ? void 0 : (_window$getComputedSt = _window.getComputedStyle(element)) === null || _window$getComputedSt === void 0 ? void 0 : _window$getComputedSt.display) === 'contents';
12
+ }
13
+ return ((_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$getComputedS = _window2.getComputedStyle(element)) === null || _window2$getComputedS === void 0 ? void 0 : _window2$getComputedS.display) === 'contents';
14
+ }
2
15
  const MAX_NESTED_LEVELS_OF_DISPLAY_CONTENT_ELEMENTS_HANDLED = 3;
3
16
  export function getMutatedElements(element, depthLevel = 0) {
4
- var _window, _window$getComputedSt;
5
17
  if (fg('platform_ufo_disable_vcnext_observations')) {
6
18
  return [{
7
19
  element,
8
20
  isDisplayContentsElementChildren: false
9
21
  }];
10
22
  }
11
- if (((_window = window) === null || _window === void 0 ? void 0 : (_window$getComputedSt = _window.getComputedStyle(element)) === null || _window$getComputedSt === void 0 ? void 0 : _window$getComputedSt.display) === 'contents') {
23
+ if (isElementStyledWithDisplayContents(element)) {
12
24
  const mutatedElements = [];
13
25
  const nestedDisplayContentsElementChildren = [];
14
26
  for (const child of element.children) {
15
- var _window2, _window2$getComputedS;
16
- if (((_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$getComputedS = _window2.getComputedStyle(child)) === null || _window2$getComputedS === void 0 ? void 0 : _window2$getComputedS.display) === 'contents') {
27
+ if (isElementStyledWithDisplayContents(child)) {
17
28
  nestedDisplayContentsElementChildren.push(child);
18
29
  }
19
30
  mutatedElements.push({
@@ -0,0 +1,3 @@
1
+ export function isZeroDimensionRectangle(rect) {
2
+ return rect.bottom === 0 && rect.top === 0 && rect.left === 0 && rect.right === 0 && rect.x === 0 && rect.y === 0 && rect.width === 0 && rect.height === 0;
3
+ }
@@ -266,6 +266,13 @@ export var SSRPlaceholderHandlers = /*#__PURE__*/function () {
266
266
  }
267
267
  });
268
268
  }
269
+ }, {
270
+ key: "validateReactComponentMatchToPlaceholderV4",
271
+ value: function validateReactComponentMatchToPlaceholderV4(el) {
272
+ el = this.findNearestPlaceholderContainerIfIgnored(el);
273
+ var id = this.getPlaceholderReplacementId(el);
274
+ return this.staticPlaceholders.has(id);
275
+ }
269
276
  }, {
270
277
  key: "hasSameSizePosition",
271
278
  value: function hasSameSizePosition(rect, boundingClientRect) {
@@ -17,7 +17,10 @@ var getConsideredEntryTypes = function getConsideredEntryTypes() {
17
17
  if (fg('platform_ufo_remove_ssr_placeholder_in_ttvc_v4')) {
18
18
  consideredEntryTypes.push('mutation:ssr-placeholder');
19
19
  }
20
- return ['mutation:display-contents-children-element'];
20
+ if (fg('platform_ufo_detect_zero_dimension_rectangles')) {
21
+ consideredEntryTypes.push('mutation:display-contents-children-attribute');
22
+ }
23
+ return consideredEntryTypes;
21
24
  };
22
25
  var getExcludedEntryTypes = function getExcludedEntryTypes() {
23
26
  var excludedEntryTypes = ['layout-shift:same-rect'];