@atlaskit/react-ufo 3.13.18 → 3.13.19
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 +8 -0
- package/dist/cjs/vc/index.js +2 -0
- package/dist/cjs/vc/vc-observer/getVCRevisionDebugDetails.js +109 -11
- package/dist/cjs/vc/vc-observer/index.js +35 -29
- package/dist/cjs/vc/vc-observer/observers/index.js +4 -0
- package/dist/cjs/vc/vc-observer/observers/rll-placeholders/index.js +208 -0
- package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +123 -18
- package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +16 -0
- package/dist/es2019/vc/index.js +2 -0
- package/dist/es2019/vc/vc-observer/getVCRevisionDebugDetails.js +71 -9
- package/dist/es2019/vc/vc-observer/index.js +39 -33
- package/dist/es2019/vc/vc-observer/observers/index.js +4 -0
- package/dist/es2019/vc/vc-observer/observers/rll-placeholders/index.js +182 -0
- package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +96 -16
- package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +16 -0
- package/dist/esm/vc/index.js +2 -0
- package/dist/esm/vc/vc-observer/getVCRevisionDebugDetails.js +108 -11
- package/dist/esm/vc/vc-observer/index.js +35 -29
- package/dist/esm/vc/vc-observer/observers/index.js +4 -0
- package/dist/esm/vc/vc-observer/observers/rll-placeholders/index.js +201 -0
- package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +124 -18
- package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +16 -0
- package/dist/types/common/vc/types.d.ts +1 -1
- package/dist/types/vc/vc-observer/getVCRevisionDebugDetails.d.ts +16 -14
- package/dist/types/vc/vc-observer/observers/rll-placeholders/index.d.ts +49 -0
- package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types-ts4.5/common/vc/types.d.ts +1 -1
- package/dist/types-ts4.5/vc/vc-observer/getVCRevisionDebugDetails.d.ts +16 -14
- package/dist/types-ts4.5/vc/vc-observer/observers/rll-placeholders/index.d.ts +49 -0
- package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +1 -1
- package/package.json +4 -1
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
8
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
11
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
10
12
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
13
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
@@ -14,9 +16,12 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
|
14
16
|
var _percentileCalc = require("./percentile-calc");
|
|
15
17
|
var _getViewportHeight = _interopRequireDefault(require("./utils/get-viewport-height"));
|
|
16
18
|
var _getViewportWidth = _interopRequireDefault(require("./utils/get-viewport-width"));
|
|
19
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
20
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17
21
|
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; } } }; }
|
|
18
22
|
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; } }
|
|
19
23
|
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; }
|
|
24
|
+
// Create comprehensive debug details including ignored entries
|
|
20
25
|
var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
|
|
21
26
|
function AbstractVCCalculatorBase(revisionNo) {
|
|
22
27
|
(0, _classCallCheck2.default)(this, AbstractVCCalculatorBase);
|
|
@@ -79,9 +84,9 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
|
|
|
79
84
|
}, {
|
|
80
85
|
key: "calculateWithDebugInfo",
|
|
81
86
|
value: function () {
|
|
82
|
-
var _calculateWithDebugInfo = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason) {
|
|
83
|
-
var _window, _window3;
|
|
84
|
-
var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator3, _step3, _entry2, time, viewportPercentage, entries, elementNames, previousResult, i, percentile,
|
|
87
|
+
var _calculateWithDebugInfo = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries) {
|
|
88
|
+
var _window, _window2, _window3, _window5;
|
|
89
|
+
var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator3, _step3, _entry2, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator4, _step4, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator5, _step5, _entry3, _ignoredEntriesByTime, viewportData, timestamp, additionalVcLogs, _iterator6, _step6, _step6$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
|
|
85
90
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
86
91
|
while (1) switch (_context.prev = _context.next) {
|
|
87
92
|
case 0:
|
|
@@ -171,38 +176,138 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
|
|
|
171
176
|
previousResult = vcDetails["".concat(percentile)];
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
enhancedVcLogs = vcLogs ? vcLogs.map(function (log) {
|
|
180
|
+
return _objectSpread(_objectSpread({}, log), {}, {
|
|
181
|
+
viewportPercentage: log.viewportPercentage
|
|
182
|
+
});
|
|
183
|
+
}) : []; // Only calculate enhanced debug details if devtool callbacks exist
|
|
184
|
+
shouldCalculateDebugDetails = !isPostInteraction && (typeof ((_window = window) === null || _window === void 0 ? void 0 : _window.__ufo_devtool_onVCRevisionReady__) === 'function' || typeof ((_window2 = window) === null || _window2 === void 0 ? void 0 : _window2.__on_ufo_vc_debug_data_ready) === 'function' && (0, _platformFeatureFlags.fg)('platform_ufo_emit_vc_debug_data'));
|
|
185
|
+
if (shouldCalculateDebugDetails && allEntries && vcLogs) {
|
|
186
|
+
// Pre-sort vcLogs by time for efficient lookups
|
|
187
|
+
sortedVcLogs = (0, _toConsumableArray2.default)(vcLogs).sort(function (a, b) {
|
|
188
|
+
return a.time - b.time;
|
|
189
|
+
}); // Pre-calculate max viewport percentage up to each time for efficient lookups
|
|
190
|
+
maxViewportPercentageAtTime = new Map();
|
|
191
|
+
maxSoFar = 0;
|
|
192
|
+
_iterator4 = _createForOfIteratorHelper(sortedVcLogs);
|
|
193
|
+
try {
|
|
194
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
195
|
+
log = _step4.value;
|
|
196
|
+
if (log.viewportPercentage !== null) {
|
|
197
|
+
maxSoFar = Math.max(maxSoFar, log.viewportPercentage);
|
|
198
|
+
maxViewportPercentageAtTime.set(log.time, maxSoFar);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Helper function to find the biggest previous viewport percentage
|
|
203
|
+
} catch (err) {
|
|
204
|
+
_iterator4.e(err);
|
|
205
|
+
} finally {
|
|
206
|
+
_iterator4.f();
|
|
207
|
+
}
|
|
208
|
+
getBiggestPreviousViewportPercentage = function getBiggestPreviousViewportPercentage(targetTime) {
|
|
209
|
+
// Binary search for the largest time <= targetTime
|
|
210
|
+
var left = 0;
|
|
211
|
+
var right = sortedVcLogs.length - 1;
|
|
212
|
+
var result = -1;
|
|
213
|
+
while (left <= right) {
|
|
214
|
+
var mid = Math.floor((left + right) / 2);
|
|
215
|
+
if (sortedVcLogs[mid].time <= targetTime) {
|
|
216
|
+
result = mid;
|
|
217
|
+
left = mid + 1;
|
|
218
|
+
} else {
|
|
219
|
+
right = mid - 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return result >= 0 ? maxViewportPercentageAtTime.get(sortedVcLogs[result].time) || null : null;
|
|
223
|
+
}; // Group ignored entries by timestamp
|
|
224
|
+
ignoredEntriesByTime = new Map();
|
|
225
|
+
_iterator5 = _createForOfIteratorHelper(allEntries);
|
|
226
|
+
try {
|
|
227
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
228
|
+
_entry3 = _step5.value;
|
|
229
|
+
if ('rect' in _entry3.data && !this.isEntryIncluded(_entry3)) {
|
|
230
|
+
viewportData = _entry3.data;
|
|
231
|
+
timestamp = Math.round(_entry3.time);
|
|
232
|
+
if (!ignoredEntriesByTime.has(timestamp)) {
|
|
233
|
+
ignoredEntriesByTime.set(timestamp, []);
|
|
234
|
+
}
|
|
235
|
+
(_ignoredEntriesByTime = ignoredEntriesByTime.get(timestamp)) === null || _ignoredEntriesByTime === void 0 || _ignoredEntriesByTime.push(_objectSpread(_objectSpread({}, viewportData), {}, {
|
|
236
|
+
ignoreReason: viewportData.visible ? viewportData.type : 'not-visible'
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Add ignored entries to vcLogs
|
|
242
|
+
} catch (err) {
|
|
243
|
+
_iterator5.e(err);
|
|
244
|
+
} finally {
|
|
245
|
+
_iterator5.f();
|
|
246
|
+
}
|
|
247
|
+
additionalVcLogs = [];
|
|
248
|
+
_iterator6 = _createForOfIteratorHelper(ignoredEntriesByTime);
|
|
249
|
+
try {
|
|
250
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
251
|
+
_step6$value = (0, _slicedToArray2.default)(_step6.value, 2), _timestamp = _step6$value[0], ignoredEntries = _step6$value[1];
|
|
252
|
+
if (ignoredEntries.length > 0) {
|
|
253
|
+
_viewportPercentage = getBiggestPreviousViewportPercentage(_timestamp);
|
|
254
|
+
additionalVcLogs.push({
|
|
255
|
+
time: _timestamp,
|
|
256
|
+
viewportPercentage: _viewportPercentage,
|
|
257
|
+
entries: ignoredEntries
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Combine and sort all vcLogs
|
|
263
|
+
} catch (err) {
|
|
264
|
+
_iterator6.e(err);
|
|
265
|
+
} finally {
|
|
266
|
+
_iterator6.f();
|
|
267
|
+
}
|
|
268
|
+
enhancedVcLogs = [].concat((0, _toConsumableArray2.default)(enhancedVcLogs), additionalVcLogs).sort(function (a, b) {
|
|
269
|
+
return a.time - b.time;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Only create debug details if callbacks exist
|
|
274
|
+
v3RevisionDebugDetails = null;
|
|
275
|
+
if (shouldCalculateDebugDetails) {
|
|
276
|
+
v3RevisionDebugDetails = {
|
|
277
|
+
revision: this.revisionNo,
|
|
278
|
+
isClean: isVCClean,
|
|
279
|
+
abortReason: dirtyReason,
|
|
280
|
+
vcLogs: enhancedVcLogs,
|
|
281
|
+
interactionId: interactionId
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Handle devtool callback
|
|
286
|
+
if (v3RevisionDebugDetails && typeof ((_window3 = window) === null || _window3 === void 0 ? void 0 : _window3.__ufo_devtool_onVCRevisionReady__) === 'function') {
|
|
182
287
|
try {
|
|
183
|
-
(
|
|
288
|
+
(_window4 = window) === null || _window4 === void 0 || (_window4$__ufo_devtoo = _window4.__ufo_devtool_onVCRevisionReady__) === null || _window4$__ufo_devtoo === void 0 || _window4$__ufo_devtoo.call(_window4, v3RevisionDebugDetails);
|
|
184
289
|
} catch (e) {
|
|
185
290
|
// if any error communicating with devtool, we don't want to break the app
|
|
186
291
|
// eslint-disable-next-line no-console
|
|
187
292
|
console.error('Error in onVCRevisionReady', e);
|
|
188
293
|
}
|
|
189
294
|
}
|
|
190
|
-
if (
|
|
295
|
+
if (v3RevisionDebugDetails && typeof ((_window5 = window) === null || _window5 === void 0 ? void 0 : _window5.__on_ufo_vc_debug_data_ready) === 'function' && (0, _platformFeatureFlags.fg)('platform_ufo_emit_vc_debug_data')) {
|
|
191
296
|
try {
|
|
192
|
-
(
|
|
297
|
+
(_window6 = window) === null || _window6 === void 0 || (_window6$__on_ufo_vc_ = _window6.__on_ufo_vc_debug_data_ready) === null || _window6$__on_ufo_vc_ === void 0 || _window6$__on_ufo_vc_.call(_window6, v3RevisionDebugDetails);
|
|
193
298
|
} catch (e) {
|
|
194
299
|
// eslint-disable-next-line no-console
|
|
195
300
|
console.error('Error in onVCRevisionReady', e);
|
|
196
301
|
}
|
|
197
302
|
}
|
|
198
303
|
return _context.abrupt("return", vcDetails);
|
|
199
|
-
case
|
|
304
|
+
case 38:
|
|
200
305
|
case "end":
|
|
201
306
|
return _context.stop();
|
|
202
307
|
}
|
|
203
308
|
}, _callee, this, [[10, 22, 25, 28]]);
|
|
204
309
|
}));
|
|
205
|
-
function calculateWithDebugInfo(_x, _x2, _x3, _x4, _x5, _x6, _x7) {
|
|
310
|
+
function calculateWithDebugInfo(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8) {
|
|
206
311
|
return _calculateWithDebugInfo.apply(this, arguments);
|
|
207
312
|
}
|
|
208
313
|
return calculateWithDebugInfo;
|
|
@@ -237,7 +342,7 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
|
|
|
237
342
|
});
|
|
238
343
|
case 7:
|
|
239
344
|
_context2.next = 9;
|
|
240
|
-
return this.calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason);
|
|
345
|
+
return this.calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, orderedEntries);
|
|
241
346
|
case 9:
|
|
242
347
|
vcDetails = _context2.sent;
|
|
243
348
|
result = {
|
|
@@ -256,7 +361,7 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
|
|
|
256
361
|
}
|
|
257
362
|
}, _callee2, this);
|
|
258
363
|
}));
|
|
259
|
-
function calculate(
|
|
364
|
+
function calculate(_x9) {
|
|
260
365
|
return _calculate.apply(this, arguments);
|
|
261
366
|
}
|
|
262
367
|
return calculate;
|
|
@@ -10,6 +10,7 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
|
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
var _vcUtils = require("../../vc-observer/media-wrapper/vc-utils");
|
|
12
12
|
var _isNonVisualStyleMutation = _interopRequireDefault(require("../../vc-observer/observers/non-visual-styles/is-non-visual-style-mutation"));
|
|
13
|
+
var _rllPlaceholders = require("../../vc-observer/observers/rll-placeholders");
|
|
13
14
|
var _intersectionObserver = require("./intersection-observer");
|
|
14
15
|
var _mutationObserver = _interopRequireDefault(require("./mutation-observer"));
|
|
15
16
|
var _performanceObserver = _interopRequireDefault(require("./performance-observer"));
|
|
@@ -48,6 +49,10 @@ function sameRectDimensions(a, b) {
|
|
|
48
49
|
var createElementMutationsWatcher = function createElementMutationsWatcher(removedNodeRects) {
|
|
49
50
|
return function (_ref) {
|
|
50
51
|
var rect = _ref.rect;
|
|
52
|
+
var isRLLPlaceholder = _rllPlaceholders.RLLPlaceholderHandlers.getInstance().isRLLPlaceholderHydration(rect);
|
|
53
|
+
if (isRLLPlaceholder) {
|
|
54
|
+
return 'mutation:rll-placeholder';
|
|
55
|
+
}
|
|
51
56
|
var wasDeleted = removedNodeRects.some(function (nr) {
|
|
52
57
|
return sameRectDimensions(nr, rect);
|
|
53
58
|
});
|
|
@@ -153,6 +158,17 @@ var ViewportObserver = exports.default = /*#__PURE__*/function () {
|
|
|
153
158
|
}
|
|
154
159
|
};
|
|
155
160
|
}
|
|
161
|
+
var isRLLPlaceholder = _rllPlaceholders.RLLPlaceholderHandlers.getInstance().isRLLPlaceholderHydration(rect);
|
|
162
|
+
if (isRLLPlaceholder) {
|
|
163
|
+
return {
|
|
164
|
+
type: 'mutation:rll-placeholder',
|
|
165
|
+
mutationData: {
|
|
166
|
+
attributeName: attributeName,
|
|
167
|
+
oldValue: oldValue,
|
|
168
|
+
newValue: newValue
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
156
172
|
var lastElementRect = _this.mapVisibleNodeRects.get(target);
|
|
157
173
|
if (lastElementRect && sameRectSize(rect, lastElementRect)) {
|
|
158
174
|
return {
|
package/dist/es2019/vc/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isVCRevisionEnabled } from '../config';
|
|
|
3
3
|
import { VCObserverNOOP } from './no-op-vc-observer';
|
|
4
4
|
import { VCObserver } from './vc-observer';
|
|
5
5
|
import VCObserverNew from './vc-observer-new';
|
|
6
|
+
import { RLLPlaceholderHandlers } from './vc-observer/observers/rll-placeholders';
|
|
6
7
|
export class VCObserverWrapper {
|
|
7
8
|
constructor(opts = {}) {
|
|
8
9
|
this.newVCObserver = null;
|
|
@@ -66,6 +67,7 @@ export class VCObserverWrapper {
|
|
|
66
67
|
var _this$newVCObserver2;
|
|
67
68
|
(_this$newVCObserver2 = this.newVCObserver) === null || _this$newVCObserver2 === void 0 ? void 0 : _this$newVCObserver2.stop();
|
|
68
69
|
}
|
|
70
|
+
RLLPlaceholderHandlers.getInstance().reset();
|
|
69
71
|
}
|
|
70
72
|
getVCRawData() {
|
|
71
73
|
var _this$oldVCObserver$g, _this$oldVCObserver3;
|
|
@@ -6,16 +6,44 @@ export function getVCRevisionDebugDetails({
|
|
|
6
6
|
componentsLog,
|
|
7
7
|
interactionId
|
|
8
8
|
}) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
// Pre-sort VCEntries by time for efficient lookups
|
|
10
|
+
const sortedVCEntries = [...VCEntries].sort((a, b) => a.time - b.time);
|
|
11
|
+
|
|
12
|
+
// Pre-calculate max viewport percentage up to each time for efficient lookups
|
|
13
|
+
const maxViewportPercentageAtTime = new Map();
|
|
14
|
+
let maxSoFar = 0;
|
|
15
|
+
for (const entry of sortedVCEntries) {
|
|
16
|
+
maxSoFar = Math.max(maxSoFar, entry.vc);
|
|
17
|
+
maxViewportPercentageAtTime.set(entry.time, maxSoFar);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Helper function to find the biggest previous viewport percentage
|
|
21
|
+
const getBiggestPreviousViewportPercentage = targetTime => {
|
|
22
|
+
// Binary search for the largest time <= targetTime
|
|
23
|
+
let left = 0;
|
|
24
|
+
let right = sortedVCEntries.length - 1;
|
|
25
|
+
let result = -1;
|
|
26
|
+
while (left <= right) {
|
|
27
|
+
const mid = Math.floor((left + right) / 2);
|
|
28
|
+
if (sortedVCEntries[mid].time <= targetTime) {
|
|
29
|
+
result = mid;
|
|
30
|
+
left = mid + 1;
|
|
31
|
+
} else {
|
|
32
|
+
right = mid - 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result >= 0 ? maxViewportPercentageAtTime.get(sortedVCEntries[result].time) || null : null;
|
|
36
|
+
};
|
|
37
|
+
const allVcLogs = [];
|
|
38
|
+
|
|
39
|
+
// Add regular VC entries
|
|
40
|
+
for (const entry of VCEntries) {
|
|
41
|
+
const timeLogEntries = componentsLog[entry.time];
|
|
42
|
+
allVcLogs.push({
|
|
14
43
|
time: entry.time,
|
|
15
44
|
viewportPercentage: entry.vc,
|
|
16
45
|
entries: entry.elements.map(element => {
|
|
17
|
-
|
|
18
|
-
const logEntry = (_componentsLog$entry$ = componentsLog[entry.time]) === null || _componentsLog$entry$ === void 0 ? void 0 : _componentsLog$entry$.find(log => log.targetName === element);
|
|
46
|
+
const logEntry = timeLogEntries === null || timeLogEntries === void 0 ? void 0 : timeLogEntries.find(log => log.targetName === element);
|
|
19
47
|
return {
|
|
20
48
|
elementName: element,
|
|
21
49
|
type: logEntry === null || logEntry === void 0 ? void 0 : logEntry.type,
|
|
@@ -23,10 +51,44 @@ export function getVCRevisionDebugDetails({
|
|
|
23
51
|
visible: true,
|
|
24
52
|
attributeName: logEntry === null || logEntry === void 0 ? void 0 : logEntry.attributeName,
|
|
25
53
|
oldValue: logEntry === null || logEntry === void 0 ? void 0 : logEntry.oldValue,
|
|
26
|
-
newValue: logEntry === null || logEntry === void 0 ? void 0 : logEntry.newValue
|
|
54
|
+
newValue: logEntry === null || logEntry === void 0 ? void 0 : logEntry.newValue,
|
|
55
|
+
ignoreReason: logEntry === null || logEntry === void 0 ? void 0 : logEntry.ignoreReason
|
|
27
56
|
};
|
|
28
57
|
})
|
|
29
|
-
})
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add ignored elements - only process timestamps that have ignored elements
|
|
62
|
+
for (const [timestamp, timeLogEntries] of Object.entries(componentsLog)) {
|
|
63
|
+
const ignoredElements = timeLogEntries.filter(log => log.ignoreReason);
|
|
64
|
+
if (ignoredElements.length === 0) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const time = Number(timestamp);
|
|
68
|
+
const viewportPercentage = getBiggestPreviousViewportPercentage(time);
|
|
69
|
+
allVcLogs.push({
|
|
70
|
+
time,
|
|
71
|
+
viewportPercentage,
|
|
72
|
+
entries: ignoredElements.map(logEntry => ({
|
|
73
|
+
elementName: logEntry.targetName,
|
|
74
|
+
type: logEntry.type,
|
|
75
|
+
rect: logEntry.intersectionRect,
|
|
76
|
+
visible: false,
|
|
77
|
+
attributeName: logEntry.attributeName,
|
|
78
|
+
oldValue: logEntry.oldValue,
|
|
79
|
+
newValue: logEntry.newValue,
|
|
80
|
+
ignoreReason: logEntry.ignoreReason
|
|
81
|
+
}))
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Sort once at the end
|
|
86
|
+
allVcLogs.sort((a, b) => a.time - b.time);
|
|
87
|
+
return {
|
|
88
|
+
revision,
|
|
89
|
+
isClean,
|
|
90
|
+
abortReason,
|
|
91
|
+
vcLogs: allVcLogs,
|
|
30
92
|
interactionId
|
|
31
93
|
};
|
|
32
94
|
}
|
|
@@ -282,42 +282,48 @@ export class VCObserver {
|
|
|
282
282
|
entries: isTTVCv1Disabled ? vcNext.VCEntries.rel : VCEntries.rel
|
|
283
283
|
}
|
|
284
284
|
}));
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
285
|
+
}
|
|
286
|
+
if (!this.isPostInteraction) {
|
|
287
|
+
// Only create revision debug details if callbacks exist
|
|
288
|
+
const shouldCreateDebugDetails = typeof window.__ufo_devtool_onVCRevisionReady__ === 'function' || typeof window.__on_ufo_vc_debug_data_ready === 'function' && fg('platform_ufo_emit_vc_debug_data');
|
|
289
|
+
if (shouldCreateDebugDetails) {
|
|
290
|
+
const v1RevisionDebugDetails = getVCRevisionDebugDetails({
|
|
291
|
+
revision: 'fy25.01',
|
|
292
|
+
isClean: !abortReasonInfo,
|
|
293
|
+
abortReason: abortReason.reason,
|
|
294
|
+
VCEntries: VCEntries.rel,
|
|
295
|
+
componentsLog,
|
|
296
|
+
interactionId
|
|
297
|
+
});
|
|
298
|
+
const v2RevisionDebugDetails = getVCRevisionDebugDetails({
|
|
299
|
+
revision: 'fy25.02',
|
|
300
|
+
isClean: !abortReasonInfo,
|
|
301
|
+
abortReason: abortReason.reason,
|
|
302
|
+
VCEntries: vcNext.VCEntries.rel,
|
|
303
|
+
componentsLog,
|
|
304
|
+
interactionId
|
|
305
|
+
});
|
|
301
306
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
307
|
+
// Add devtool callback for both v1 and v2
|
|
308
|
+
if (typeof window.__ufo_devtool_onVCRevisionReady__ === 'function') {
|
|
309
|
+
var _window$__ufo_devtool2, _window2;
|
|
310
|
+
// Handle v1 if not disabled
|
|
311
|
+
if (!isTTVCv1Disabled) {
|
|
312
|
+
var _window$__ufo_devtool, _window;
|
|
313
|
+
(_window$__ufo_devtool = (_window = window).__ufo_devtool_onVCRevisionReady__) === null || _window$__ufo_devtool === void 0 ? void 0 : _window$__ufo_devtool.call(_window, v1RevisionDebugDetails);
|
|
314
|
+
}
|
|
310
315
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
// Handle v2
|
|
317
|
+
(_window$__ufo_devtool2 = (_window2 = window).__ufo_devtool_onVCRevisionReady__) === null || _window$__ufo_devtool2 === void 0 ? void 0 : _window$__ufo_devtool2.call(_window2, v2RevisionDebugDetails);
|
|
318
|
+
}
|
|
319
|
+
if (typeof window.__on_ufo_vc_debug_data_ready === 'function' && fg('platform_ufo_emit_vc_debug_data')) {
|
|
320
|
+
var _window$__on_ufo_vc_d2, _window4;
|
|
321
|
+
if (!isTTVCv1Disabled) {
|
|
322
|
+
var _window$__on_ufo_vc_d, _window3;
|
|
323
|
+
(_window$__on_ufo_vc_d = (_window3 = window).__on_ufo_vc_debug_data_ready) === null || _window$__on_ufo_vc_d === void 0 ? void 0 : _window$__on_ufo_vc_d.call(_window3, v1RevisionDebugDetails);
|
|
324
|
+
}
|
|
325
|
+
(_window$__on_ufo_vc_d2 = (_window4 = window).__on_ufo_vc_debug_data_ready) === null || _window$__on_ufo_vc_d2 === void 0 ? void 0 : _window$__on_ufo_vc_d2.call(_window4, v2RevisionDebugDetails);
|
|
319
326
|
}
|
|
320
|
-
(_window$__on_ufo_vc_d2 = (_window4 = window).__on_ufo_vc_debug_data_ready) === null || _window$__on_ufo_vc_d2 === void 0 ? void 0 : _window$__on_ufo_vc_d2.call(_window4, v2RevisionDebugDetails);
|
|
321
327
|
}
|
|
322
328
|
}
|
|
323
329
|
} catch (e) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { isContainedWithinMediaWrapper } from '../media-wrapper/vc-utils';
|
|
3
3
|
import isNonVisualStyleMutation from './non-visual-styles/is-non-visual-style-mutation';
|
|
4
|
+
import { RLLPlaceholderHandlers } from './rll-placeholders';
|
|
4
5
|
import { SSRPlaceholderHandlers } from './ssr-placeholders';
|
|
5
6
|
const state = {
|
|
6
7
|
normal: 1,
|
|
@@ -244,6 +245,9 @@ export class Observers {
|
|
|
244
245
|
if (!isElementVisible(target)) {
|
|
245
246
|
data.ignoreReason = 'not-visible';
|
|
246
247
|
}
|
|
248
|
+
if (RLLPlaceholderHandlers.getInstance().isRLLPlaceholderHydration(ir)) {
|
|
249
|
+
data.ignoreReason = 'rll-placeholder';
|
|
250
|
+
}
|
|
247
251
|
this.callbacks.forEach(callback => {
|
|
248
252
|
let elementName;
|
|
249
253
|
try {
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
const GLOBAL_RLL_HANDLERS_KEY = '__REACT_UFO_RLL_PLACEHOLDER_HANDLERS__';
|
|
4
|
+
export class RLLPlaceholderHandlers {
|
|
5
|
+
constructor() {
|
|
6
|
+
_defineProperty(this, "placeholders", []);
|
|
7
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined' && typeof window.document !== 'undefined') {
|
|
8
|
+
this.collectRLLPlaceholders();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the global singleton instance of RLLPlaceholderHandlers.
|
|
14
|
+
* Creates the instance if it doesn't exist and stores it in globalThis.
|
|
15
|
+
* @returns The singleton instance of RLLPlaceholderHandlers
|
|
16
|
+
*/
|
|
17
|
+
static getInstance() {
|
|
18
|
+
if (typeof globalThis !== 'undefined') {
|
|
19
|
+
if (!globalThis[GLOBAL_RLL_HANDLERS_KEY]) {
|
|
20
|
+
globalThis[GLOBAL_RLL_HANDLERS_KEY] = new RLLPlaceholderHandlers();
|
|
21
|
+
}
|
|
22
|
+
return globalThis[GLOBAL_RLL_HANDLERS_KEY];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Fallback for environments without globalThis (should be rare)
|
|
26
|
+
return new RLLPlaceholderHandlers();
|
|
27
|
+
}
|
|
28
|
+
reset() {
|
|
29
|
+
this.placeholders = [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Collects all React Loosely Lazy (RLL) placeholders from the DOM and caches their viewport intersecting rectangles.
|
|
34
|
+
* RLL placeholders are marked with data-lazy-begin and data-lazy-end attributes on hidden input elements.
|
|
35
|
+
* Performance optimized to batch getBoundingClientRect calls and minimize layout thrashing.
|
|
36
|
+
* Only stores the intersecting portions of rectangles that are currently visible in the viewport.
|
|
37
|
+
*/
|
|
38
|
+
collectRLLPlaceholders() {
|
|
39
|
+
if (typeof window === 'undefined' || typeof document === 'undefined' || typeof window.document === 'undefined') {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!fg('platform_ufo_rll_placeholder_ignore')) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const beginElements = document.querySelectorAll('input[data-lazy-begin]');
|
|
46
|
+
const beginCount = beginElements.length;
|
|
47
|
+
if (beginCount === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Performance optimization: pre-allocate array with estimated size
|
|
52
|
+
const allElements = [];
|
|
53
|
+
|
|
54
|
+
// Performance optimization: use traditional for loop instead of forEach
|
|
55
|
+
for (let i = 0; i < beginCount; i++) {
|
|
56
|
+
const beginEl = beginElements[i];
|
|
57
|
+
const id = beginEl.getAttribute('data-lazy-begin');
|
|
58
|
+
if (!id) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const elements = this.refElements(beginEl, id);
|
|
62
|
+
if (elements.length > 0) {
|
|
63
|
+
allElements.push(...elements);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Second pass: batch all getBoundingClientRect calls to minimize reflow cycles
|
|
68
|
+
const allElementsLength = allElements.length;
|
|
69
|
+
if (allElementsLength > 0) {
|
|
70
|
+
// Performance optimization: pre-allocate array with exact size
|
|
71
|
+
const intersectingRects = [];
|
|
72
|
+
const windowWidth = window.innerWidth;
|
|
73
|
+
const windowHeight = window.innerHeight;
|
|
74
|
+
for (let i = 0; i < allElementsLength; i++) {
|
|
75
|
+
const rect = allElements[i].getBoundingClientRect();
|
|
76
|
+
|
|
77
|
+
// Performance optimization: inline intersection calculation to avoid function call overhead
|
|
78
|
+
const left = Math.max(rect.left, 0);
|
|
79
|
+
const top = Math.max(rect.top, 0);
|
|
80
|
+
const right = Math.min(rect.right, windowWidth);
|
|
81
|
+
const bottom = Math.min(rect.bottom, windowHeight);
|
|
82
|
+
|
|
83
|
+
// Check if there's a valid intersection with non-zero width and height
|
|
84
|
+
if (left < right && top < bottom) {
|
|
85
|
+
intersectingRects.push(new DOMRect(left, top, right - left, bottom - top));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
this.placeholders = intersectingRects;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Traverses DOM siblings to find all elements between RLL begin and end markers.
|
|
94
|
+
* Based on the refElements pattern from react-loosely-lazy's platform/packages/async/react-loosely-lazy/src/collect/hydrate.ts
|
|
95
|
+
* Performance optimized to minimize iterations and early exit conditions.
|
|
96
|
+
*
|
|
97
|
+
* @param fromEl - The input element with data-lazy-begin attribute
|
|
98
|
+
* @param id - The placeholder ID to match against data-lazy-end
|
|
99
|
+
* @returns Array of DOM elements between the begin/end markers
|
|
100
|
+
*/
|
|
101
|
+
refElements(fromEl, id) {
|
|
102
|
+
const result = [];
|
|
103
|
+
let el = fromEl.nextSibling;
|
|
104
|
+
|
|
105
|
+
// Performance optimization: use while loop instead of recursive calls
|
|
106
|
+
while (el) {
|
|
107
|
+
var _el$dataset;
|
|
108
|
+
if (((_el$dataset = el.dataset) === null || _el$dataset === void 0 ? void 0 : _el$dataset.lazyEnd) === id) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
if (el.nodeType === Node.ELEMENT_NODE) {
|
|
112
|
+
result.push(el);
|
|
113
|
+
}
|
|
114
|
+
el = el.nextSibling;
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns the cached intersecting viewport rectangles for all RLL placeholder elements.
|
|
121
|
+
* @returns Array of DOMRect objects representing the intersecting portions of placeholders within the viewport
|
|
122
|
+
*/
|
|
123
|
+
getPlaceholders() {
|
|
124
|
+
return this.placeholders;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Checks if the given intersecting rectangle matches any of the cached RLL placeholder intersecting rectangles.
|
|
129
|
+
* This is designed to be called from IntersectionObserver with the intersectionRect.
|
|
130
|
+
* Performance optimized with early exits and minimal calculations.
|
|
131
|
+
* @param intersectingRect - The intersecting rectangle from IntersectionObserver
|
|
132
|
+
* @returns true if the intersecting rectangle matches a cached placeholder rectangle and hasn't exceeded match limit, false otherwise
|
|
133
|
+
*/
|
|
134
|
+
isRLLPlaceholderHydration(intersectingRect) {
|
|
135
|
+
const placeholdersLength = this.placeholders.length;
|
|
136
|
+
if (placeholdersLength === 0) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Performance optimization: cache array length and use traditional for loop
|
|
141
|
+
for (let i = 0; i < placeholdersLength; i++) {
|
|
142
|
+
const placeholderRect = this.placeholders[i];
|
|
143
|
+
if (this.areRectsEqual(intersectingRect, placeholderRect)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Compares two DOMRect objects for equality with ±1 pixel tolerance.
|
|
152
|
+
* Performance optimized to minimize calculations and early exit on major differences.
|
|
153
|
+
* @param rect1 - First rectangle to compare
|
|
154
|
+
* @param rect2 - Second rectangle to compare
|
|
155
|
+
* @returns true if rectangles are within 1 pixel tolerance for all properties
|
|
156
|
+
*/
|
|
157
|
+
areRectsEqual(rect1, rect2) {
|
|
158
|
+
// Early exit for exact matches (most common case)
|
|
159
|
+
if (rect1.left === rect2.left && rect1.top === rect2.top && rect1.right === rect2.right && rect1.bottom === rect2.bottom) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Performance optimization: check largest differences first for early exit
|
|
164
|
+
const leftDiff = rect1.left - rect2.left;
|
|
165
|
+
if (leftDiff > 1 || leftDiff < -1) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const rightDiff = rect1.right - rect2.right;
|
|
169
|
+
if (rightDiff > 1 || rightDiff < -1) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const topDiff = rect1.top - rect2.top;
|
|
173
|
+
if (topDiff > 1 || topDiff < -1) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
const bottomDiff = rect1.bottom - rect2.bottom;
|
|
177
|
+
if (bottomDiff > 1 || bottomDiff < -1) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|