@atlaskit/react-ufo 3.14.6 → 3.14.7
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 +39 -6
- package/dist/cjs/vc/vc-observer/index.js +10 -2
- package/dist/cjs/vc/vc-observer/observers/index.js +12 -7
- package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +76 -40
- package/dist/cjs/vc/vc-observer-new/index.js +84 -0
- package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +214 -71
- package/dist/cjs/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +97 -59
- package/dist/es2019/vc/index.js +37 -5
- package/dist/es2019/vc/vc-observer/index.js +8 -2
- package/dist/es2019/vc/vc-observer/observers/index.js +11 -5
- package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +57 -26
- package/dist/es2019/vc/vc-observer-new/index.js +67 -1
- package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +87 -22
- package/dist/es2019/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +50 -34
- package/dist/esm/vc/index.js +39 -6
- package/dist/esm/vc/vc-observer/index.js +10 -2
- package/dist/esm/vc/vc-observer/observers/index.js +12 -7
- package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +76 -40
- package/dist/esm/vc/vc-observer-new/index.js +84 -0
- package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +214 -71
- package/dist/esm/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +97 -59
- package/dist/types/vc/index.d.ts +2 -0
- package/dist/types/vc/types.d.ts +2 -0
- package/dist/types/vc/vc-observer/index.d.ts +1 -0
- package/dist/types/vc/vc-observer/observers/index.d.ts +2 -0
- package/dist/types/vc/vc-observer/observers/ssr-placeholders/index.d.ts +6 -0
- package/dist/types/vc/vc-observer-new/index.d.ts +30 -0
- package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types/vc/vc-observer-new/viewport-observer/index.d.ts +5 -1
- package/dist/types/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
- package/dist/types-ts4.5/vc/index.d.ts +2 -0
- package/dist/types-ts4.5/vc/types.d.ts +2 -0
- package/dist/types-ts4.5/vc/vc-observer/index.d.ts +1 -0
- package/dist/types-ts4.5/vc/vc-observer/observers/index.d.ts +2 -0
- package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/index.d.ts +6 -0
- package/dist/types-ts4.5/vc/vc-observer-new/index.d.ts +30 -0
- package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/index.d.ts +5 -1
- package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
- package/package.json +5 -3
|
@@ -21,7 +21,6 @@ function isElementVisible(target) {
|
|
|
21
21
|
}
|
|
22
22
|
export class Observers {
|
|
23
23
|
constructor(opts) {
|
|
24
|
-
var _opts$SSRConfig, _opts$SSRConfig2;
|
|
25
24
|
_defineProperty(this, "observedMutations", new WeakMap());
|
|
26
25
|
_defineProperty(this, "elementsInView", new Set());
|
|
27
26
|
_defineProperty(this, "callbacks", new Set());
|
|
@@ -61,10 +60,17 @@ export class Observers {
|
|
|
61
60
|
};
|
|
62
61
|
this.intersectionObserver = this.getIntersectionObserver();
|
|
63
62
|
this.mutationObserver = this.getMutationObserver();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
|
|
64
|
+
// Use shared SSR placeholder handler if provided, otherwise create new one
|
|
65
|
+
if (opts.ssrPlaceholderHandler) {
|
|
66
|
+
this.ssrPlaceholderHandler = opts.ssrPlaceholderHandler;
|
|
67
|
+
} else {
|
|
68
|
+
var _opts$SSRConfig, _opts$SSRConfig2;
|
|
69
|
+
this.ssrPlaceholderHandler = new SSRPlaceholderHandlers({
|
|
70
|
+
enablePageLayoutPlaceholder: (_opts$SSRConfig = opts.SSRConfig) === null || _opts$SSRConfig === void 0 ? void 0 : _opts$SSRConfig.enablePageLayoutPlaceholder,
|
|
71
|
+
disableSizeAndPositionCheck: (_opts$SSRConfig2 = opts.SSRConfig) === null || _opts$SSRConfig2 === void 0 ? void 0 : _opts$SSRConfig2.disableSizeAndPositionCheck
|
|
72
|
+
});
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
isBrowserSupported() {
|
|
70
76
|
return typeof window.IntersectionObserver === 'function' && typeof window.MutationObserver === 'function';
|
|
@@ -96,32 +96,8 @@ export class SSRPlaceholderHandlers {
|
|
|
96
96
|
this.disableSizeAndPositionCheck = disableSizeAndPositionCheck;
|
|
97
97
|
if (window.document) {
|
|
98
98
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
existingElements.forEach(el => {
|
|
102
|
-
const placeholderId = el instanceof HTMLElement && this.getPlaceholderId(el);
|
|
103
|
-
if (placeholderId) {
|
|
104
|
-
var _window$__SSR_PLACEHO, _this$intersectionObs2;
|
|
105
|
-
let width = -1;
|
|
106
|
-
let height = -1;
|
|
107
|
-
let x = -1;
|
|
108
|
-
let y = -1;
|
|
109
|
-
const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[placeholderId];
|
|
110
|
-
if (boundingClientRect) {
|
|
111
|
-
width = boundingClientRect.width;
|
|
112
|
-
height = boundingClientRect.height;
|
|
113
|
-
x = boundingClientRect.x;
|
|
114
|
-
y = boundingClientRect.y;
|
|
115
|
-
}
|
|
116
|
-
this.staticPlaceholders.set(placeholderId, {
|
|
117
|
-
width,
|
|
118
|
-
height,
|
|
119
|
-
x,
|
|
120
|
-
y
|
|
121
|
-
});
|
|
122
|
-
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.observe(el);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
99
|
+
// Collect initial placeholders using SSR dimensions
|
|
100
|
+
this.collectPlaceholdersInternal();
|
|
125
101
|
} catch (e) {} finally {
|
|
126
102
|
delete window.__SSR_PLACEHOLDERS_DIMENSIONS__;
|
|
127
103
|
}
|
|
@@ -133,6 +109,61 @@ export class SSRPlaceholderHandlers {
|
|
|
133
109
|
this.getSizeCallbacks = new Map();
|
|
134
110
|
this.reactValidateCallbacks = new Map();
|
|
135
111
|
}
|
|
112
|
+
collectPlaceholdersInternal() {
|
|
113
|
+
const selector = this.enablePageLayoutPlaceholder ? '[data-ssr-placeholder],[data-testid="page-layout.root"]' : '[data-ssr-placeholder]';
|
|
114
|
+
const existingElements = document.querySelectorAll(selector);
|
|
115
|
+
existingElements.forEach(el => {
|
|
116
|
+
const placeholderId = el instanceof HTMLElement && this.getPlaceholderId(el);
|
|
117
|
+
if (placeholderId && !this.staticPlaceholders.has(placeholderId)) {
|
|
118
|
+
var _window$__SSR_PLACEHO, _this$intersectionObs2;
|
|
119
|
+
let width = -1;
|
|
120
|
+
let height = -1;
|
|
121
|
+
let x = -1;
|
|
122
|
+
let y = -1;
|
|
123
|
+
|
|
124
|
+
// Use SSR dimensions from window global if available
|
|
125
|
+
const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[placeholderId];
|
|
126
|
+
if (boundingClientRect) {
|
|
127
|
+
width = boundingClientRect.width;
|
|
128
|
+
height = boundingClientRect.height;
|
|
129
|
+
x = boundingClientRect.x;
|
|
130
|
+
y = boundingClientRect.y;
|
|
131
|
+
} else {
|
|
132
|
+
// Fallback to current bounding rect if SSR dimensions not available
|
|
133
|
+
const rect = el.getBoundingClientRect();
|
|
134
|
+
width = rect.width;
|
|
135
|
+
height = rect.height;
|
|
136
|
+
x = rect.x;
|
|
137
|
+
y = rect.y;
|
|
138
|
+
}
|
|
139
|
+
this.staticPlaceholders.set(placeholderId, {
|
|
140
|
+
width,
|
|
141
|
+
height,
|
|
142
|
+
x,
|
|
143
|
+
y
|
|
144
|
+
});
|
|
145
|
+
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.observe(el);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Added this method to be utilised for testing purposes.
|
|
152
|
+
* In production it collection placeholder should only happens on constructor
|
|
153
|
+
*/
|
|
154
|
+
collectExistingPlaceholders() {
|
|
155
|
+
if (!window.document) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
// Collect placeholders using SSR dimensions or fallback to live dimensions
|
|
160
|
+
this.collectPlaceholdersInternal();
|
|
161
|
+
} catch (e) {
|
|
162
|
+
// Silently fail if there are any issues
|
|
163
|
+
} finally {
|
|
164
|
+
delete window.__SSR_PLACEHOLDERS_DIMENSIONS__;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
136
167
|
isPlaceholder(element) {
|
|
137
168
|
return Boolean(this.getPlaceholderId(element));
|
|
138
169
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
import { SSRPlaceholderHandlers } from '../vc-observer/observers/ssr-placeholders';
|
|
3
4
|
import EntriesTimeline from './entries-timeline';
|
|
4
5
|
import getElementName from './get-element-name';
|
|
5
6
|
import VCCalculator_FY25_03 from './metric-calculator/fy25_03';
|
|
@@ -7,6 +8,11 @@ import getViewportHeight from './metric-calculator/utils/get-viewport-height';
|
|
|
7
8
|
import getViewportWidth from './metric-calculator/utils/get-viewport-width';
|
|
8
9
|
import ViewportObserver from './viewport-observer';
|
|
9
10
|
import WindowEventObserver from './window-event-observer';
|
|
11
|
+
const SSRState = {
|
|
12
|
+
normal: 1,
|
|
13
|
+
waitingForFirstRender: 2,
|
|
14
|
+
ignoring: 3
|
|
15
|
+
};
|
|
10
16
|
const DEFAULT_SELECTOR_CONFIG = {
|
|
11
17
|
id: false,
|
|
12
18
|
testId: true,
|
|
@@ -19,9 +25,31 @@ export default class VCObserverNew {
|
|
|
19
25
|
var _config$isPostInterac, _config$selectorConfi;
|
|
20
26
|
_defineProperty(this, "viewportObserver", null);
|
|
21
27
|
_defineProperty(this, "windowEventObserver", null);
|
|
28
|
+
// SSR related properties
|
|
29
|
+
_defineProperty(this, "ssrPlaceholderHandler", null);
|
|
30
|
+
_defineProperty(this, "ssr", {
|
|
31
|
+
state: SSRState.normal,
|
|
32
|
+
reactRootElement: null,
|
|
33
|
+
renderStart: -1,
|
|
34
|
+
renderStop: -1
|
|
35
|
+
});
|
|
22
36
|
this.entriesTimeline = new EntriesTimeline();
|
|
23
37
|
this.isPostInteraction = (_config$isPostInterac = config.isPostInteraction) !== null && _config$isPostInterac !== void 0 ? _config$isPostInterac : false;
|
|
24
38
|
this.selectorConfig = (_config$selectorConfi = config.selectorConfig) !== null && _config$selectorConfi !== void 0 ? _config$selectorConfi : DEFAULT_SELECTOR_CONFIG;
|
|
39
|
+
|
|
40
|
+
// Use shared SSR placeholder handler if provided, otherwise create new one if feature flag is enabled
|
|
41
|
+
if (config.ssrPlaceholderHandler) {
|
|
42
|
+
this.ssrPlaceholderHandler = config.ssrPlaceholderHandler;
|
|
43
|
+
} else {
|
|
44
|
+
var _config$SSRConfig$ena, _config$SSRConfig, _config$SSRConfig$dis, _config$SSRConfig2;
|
|
45
|
+
this.ssrPlaceholderHandler = new SSRPlaceholderHandlers({
|
|
46
|
+
enablePageLayoutPlaceholder: (_config$SSRConfig$ena = (_config$SSRConfig = config.SSRConfig) === null || _config$SSRConfig === void 0 ? void 0 : _config$SSRConfig.enablePageLayoutPlaceholder) !== null && _config$SSRConfig$ena !== void 0 ? _config$SSRConfig$ena : false,
|
|
47
|
+
disableSizeAndPositionCheck: (_config$SSRConfig$dis = (_config$SSRConfig2 = config.SSRConfig) === null || _config$SSRConfig2 === void 0 ? void 0 : _config$SSRConfig2.disableSizeAndPositionCheck) !== null && _config$SSRConfig$dis !== void 0 ? _config$SSRConfig$dis : {
|
|
48
|
+
v: false,
|
|
49
|
+
h: false
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
25
53
|
this.viewportObserver = new ViewportObserver({
|
|
26
54
|
onChange: onChangeArg => {
|
|
27
55
|
const {
|
|
@@ -51,7 +79,10 @@ export default class VCObserverNew {
|
|
|
51
79
|
newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
|
|
52
80
|
}
|
|
53
81
|
});
|
|
54
|
-
}
|
|
82
|
+
},
|
|
83
|
+
// Pass SSR context to ViewportObserver
|
|
84
|
+
getSSRState: () => this.getSSRState(),
|
|
85
|
+
getSSRPlaceholderHandler: () => this.getSSRPlaceholderHandler()
|
|
55
86
|
});
|
|
56
87
|
this.windowEventObserver = new WindowEventObserver({
|
|
57
88
|
onEvent: ({
|
|
@@ -72,6 +103,14 @@ export default class VCObserverNew {
|
|
|
72
103
|
startTime
|
|
73
104
|
}) {
|
|
74
105
|
var _this$viewportObserve, _window, _this$windowEventObse;
|
|
106
|
+
// Reset SSR state on start (matches old VCObserver behavior)
|
|
107
|
+
this.ssr = {
|
|
108
|
+
state: SSRState.normal,
|
|
109
|
+
reactRootElement: null,
|
|
110
|
+
// Reset to null (matches old VCObserver)
|
|
111
|
+
renderStart: -1,
|
|
112
|
+
renderStop: -1
|
|
113
|
+
};
|
|
75
114
|
(_this$viewportObserve = this.viewportObserver) === null || _this$viewportObserve === void 0 ? void 0 : _this$viewportObserve.start();
|
|
76
115
|
if ((_window = window) !== null && _window !== void 0 && _window.__SSR_ABORT_LISTENERS__ && fg('platform_ufo_vc_observer_new_ssr_abort_listener')) {
|
|
77
116
|
const abortListeners = window.__SSR_ABORT_LISTENERS__;
|
|
@@ -97,6 +136,33 @@ export default class VCObserverNew {
|
|
|
97
136
|
var _this$viewportObserve2, _this$windowEventObse2;
|
|
98
137
|
(_this$viewportObserve2 = this.viewportObserver) === null || _this$viewportObserve2 === void 0 ? void 0 : _this$viewportObserve2.stop();
|
|
99
138
|
(_this$windowEventObse2 = this.windowEventObserver) === null || _this$windowEventObse2 === void 0 ? void 0 : _this$windowEventObse2.stop();
|
|
139
|
+
|
|
140
|
+
// Clear SSR state on stop (matches old VCObserver behavior)
|
|
141
|
+
this.ssr.reactRootElement = null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// SSR related methods
|
|
145
|
+
setReactRootElement(element) {
|
|
146
|
+
this.ssr.reactRootElement = element;
|
|
147
|
+
}
|
|
148
|
+
setReactRootRenderStart(startTime = performance.now()) {
|
|
149
|
+
this.ssr.renderStart = startTime;
|
|
150
|
+
this.ssr.state = SSRState.waitingForFirstRender;
|
|
151
|
+
}
|
|
152
|
+
setReactRootRenderStop(stopTime = performance.now()) {
|
|
153
|
+
this.ssr.renderStop = stopTime;
|
|
154
|
+
}
|
|
155
|
+
collectSSRPlaceholders() {
|
|
156
|
+
// This is handled by the shared SSRPlaceholderHandlers in VCObserverWrapper
|
|
157
|
+
// Individual observers don't need to implement this
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Internal methods for ViewportObserver to access SSR state
|
|
161
|
+
getSSRState() {
|
|
162
|
+
return this.ssr;
|
|
163
|
+
}
|
|
164
|
+
getSSRPlaceholderHandler() {
|
|
165
|
+
return this.ssrPlaceholderHandler;
|
|
100
166
|
}
|
|
101
167
|
addSSR(ssr) {
|
|
102
168
|
this.entriesTimeline.push({
|
|
@@ -14,7 +14,7 @@ function isElementVisible(element) {
|
|
|
14
14
|
}
|
|
15
15
|
try {
|
|
16
16
|
const visible = element.checkVisibility({
|
|
17
|
-
// @ts-
|
|
17
|
+
// @ts-ignore - visibilityProperty may not exist in all TS environments
|
|
18
18
|
visibilityProperty: true,
|
|
19
19
|
contentVisibilityAuto: true,
|
|
20
20
|
opacityProperty: true
|
|
@@ -59,8 +59,12 @@ const createElementMutationsWatcher = removedNodeRects => ({
|
|
|
59
59
|
return 'mutation:element';
|
|
60
60
|
};
|
|
61
61
|
export default class ViewportObserver {
|
|
62
|
+
// SSR context functions
|
|
63
|
+
|
|
62
64
|
constructor({
|
|
63
|
-
onChange
|
|
65
|
+
onChange,
|
|
66
|
+
getSSRState,
|
|
67
|
+
getSSRPlaceholderHandler
|
|
64
68
|
}) {
|
|
65
69
|
_defineProperty(this, "handleIntersectionEntry", ({
|
|
66
70
|
target,
|
|
@@ -85,9 +89,11 @@ export default class ViewportObserver {
|
|
|
85
89
|
mutationData
|
|
86
90
|
});
|
|
87
91
|
});
|
|
88
|
-
_defineProperty(this, "handleChildListMutation", ({
|
|
92
|
+
_defineProperty(this, "handleChildListMutation", async ({
|
|
93
|
+
target,
|
|
89
94
|
addedNodes,
|
|
90
|
-
removedNodes
|
|
95
|
+
removedNodes,
|
|
96
|
+
timestamp
|
|
91
97
|
}) => {
|
|
92
98
|
const removedNodeRects = removedNodes.map(ref => {
|
|
93
99
|
const n = ref.deref();
|
|
@@ -96,11 +102,66 @@ export default class ViewportObserver {
|
|
|
96
102
|
}
|
|
97
103
|
return this.mapVisibleNodeRects.get(n);
|
|
98
104
|
});
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
const targetNode = target.deref();
|
|
106
|
+
for (const addedNodeRef of addedNodes) {
|
|
107
|
+
var _this$intersectionObs8;
|
|
101
108
|
const addedNode = addedNodeRef.deref();
|
|
102
109
|
if (!addedNode) {
|
|
103
|
-
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// SSR hydration logic
|
|
114
|
+
if (this.getSSRState && fg('platform_ufo_vc_v3_ssr_placeholder')) {
|
|
115
|
+
const ssrState = this.getSSRState();
|
|
116
|
+
const SSRStateEnum = {
|
|
117
|
+
normal: 1,
|
|
118
|
+
waitingForFirstRender: 2,
|
|
119
|
+
ignoring: 3
|
|
120
|
+
};
|
|
121
|
+
if (ssrState.state === SSRStateEnum.waitingForFirstRender && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
|
|
122
|
+
var _this$intersectionObs;
|
|
123
|
+
ssrState.state = SSRStateEnum.ignoring;
|
|
124
|
+
if (ssrState.renderStop === -1) {
|
|
125
|
+
// arbitrary 500ms DOM update window
|
|
126
|
+
ssrState.renderStop = timestamp + 500;
|
|
127
|
+
}
|
|
128
|
+
(_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.watchAndTag(addedNode, 'ssr-hydration');
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (ssrState.state === SSRStateEnum.ignoring && timestamp > ssrState.renderStart && targetNode === ssrState.reactRootElement) {
|
|
132
|
+
if (timestamp <= ssrState.renderStop) {
|
|
133
|
+
var _this$intersectionObs2;
|
|
134
|
+
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(addedNode, 'ssr-hydration');
|
|
135
|
+
continue;
|
|
136
|
+
} else {
|
|
137
|
+
ssrState.state = SSRStateEnum.normal;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// SSR placeholder logic - check and handle with await
|
|
143
|
+
if (this.getSSRPlaceholderHandler && fg('platform_ufo_vc_v3_ssr_placeholder')) {
|
|
144
|
+
const ssrPlaceholderHandler = this.getSSRPlaceholderHandler();
|
|
145
|
+
if (ssrPlaceholderHandler) {
|
|
146
|
+
if (ssrPlaceholderHandler.isPlaceholder(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
|
|
147
|
+
const result = await ssrPlaceholderHandler.checkIfExistedAndSizeMatching(addedNode);
|
|
148
|
+
if (result !== false) {
|
|
149
|
+
var _this$intersectionObs3;
|
|
150
|
+
(_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(addedNode, 'mutation:ssr-placeholder');
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// If result is false, continue to normal mutation logic below
|
|
154
|
+
}
|
|
155
|
+
if (ssrPlaceholderHandler.isPlaceholderReplacement(addedNode) || ssrPlaceholderHandler.isPlaceholderIgnored(addedNode)) {
|
|
156
|
+
const result = await ssrPlaceholderHandler.validateReactComponentMatchToPlaceholder(addedNode);
|
|
157
|
+
if (result !== false) {
|
|
158
|
+
var _this$intersectionObs4;
|
|
159
|
+
(_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(addedNode, 'mutation:ssr-placeholder');
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// If result is false, continue to normal mutation logic below
|
|
163
|
+
}
|
|
164
|
+
}
|
|
104
165
|
}
|
|
105
166
|
const sameDeletedNode = removedNodes.find(ref => {
|
|
106
167
|
const n = ref.deref();
|
|
@@ -115,27 +176,27 @@ export default class ViewportObserver {
|
|
|
115
176
|
// When fg('platform_vc_ignore_no_ls_mutation_marker') is not enabled,
|
|
116
177
|
// no layout shift mutation is excluded as per existing fy25.03 logic
|
|
117
178
|
if (sameDeletedNode && (!isNoLsMarkerEnabled || isInIgnoreLsMarker)) {
|
|
118
|
-
var _this$
|
|
119
|
-
(_this$
|
|
120
|
-
|
|
179
|
+
var _this$intersectionObs5;
|
|
180
|
+
(_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(addedNode, 'mutation:remount');
|
|
181
|
+
continue;
|
|
121
182
|
}
|
|
122
183
|
if (isContainedWithinMediaWrapper(addedNode)) {
|
|
123
|
-
var _this$
|
|
124
|
-
(_this$
|
|
125
|
-
|
|
184
|
+
var _this$intersectionObs6;
|
|
185
|
+
(_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.watchAndTag(addedNode, 'mutation:media');
|
|
186
|
+
continue;
|
|
126
187
|
}
|
|
127
188
|
const {
|
|
128
189
|
isWithinThirdPartySegment,
|
|
129
190
|
ignoredReason
|
|
130
191
|
} = checkThirdPartySegmentWithIgnoreReason(addedNode);
|
|
131
192
|
if (isWithinThirdPartySegment) {
|
|
132
|
-
var _this$
|
|
193
|
+
var _this$intersectionObs7;
|
|
133
194
|
const assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
|
|
134
|
-
(_this$
|
|
135
|
-
|
|
195
|
+
(_this$intersectionObs7 = this.intersectionObserver) === null || _this$intersectionObs7 === void 0 ? void 0 : _this$intersectionObs7.watchAndTag(addedNode, assignedReason);
|
|
196
|
+
continue;
|
|
136
197
|
}
|
|
137
|
-
(_this$
|
|
138
|
-
}
|
|
198
|
+
(_this$intersectionObs8 = this.intersectionObserver) === null || _this$intersectionObs8 === void 0 ? void 0 : _this$intersectionObs8.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
|
|
199
|
+
}
|
|
139
200
|
});
|
|
140
201
|
_defineProperty(this, "handleAttributeMutation", ({
|
|
141
202
|
target,
|
|
@@ -143,8 +204,8 @@ export default class ViewportObserver {
|
|
|
143
204
|
oldValue,
|
|
144
205
|
newValue
|
|
145
206
|
}) => {
|
|
146
|
-
var _this$
|
|
147
|
-
(_this$
|
|
207
|
+
var _this$intersectionObs9;
|
|
208
|
+
(_this$intersectionObs9 = this.intersectionObserver) === null || _this$intersectionObs9 === void 0 ? void 0 : _this$intersectionObs9.watchAndTag(target, ({
|
|
148
209
|
target,
|
|
149
210
|
rect
|
|
150
211
|
}) => {
|
|
@@ -243,6 +304,10 @@ export default class ViewportObserver {
|
|
|
243
304
|
this.intersectionObserver = null;
|
|
244
305
|
this.mutationObserver = null;
|
|
245
306
|
this.performanceObserver = null;
|
|
307
|
+
|
|
308
|
+
// Initialize SSR context functions
|
|
309
|
+
this.getSSRState = getSSRState;
|
|
310
|
+
this.getSSRPlaceholderHandler = getSSRPlaceholderHandler;
|
|
246
311
|
}
|
|
247
312
|
initializeObservers() {
|
|
248
313
|
if (this.isStarted) {
|
|
@@ -280,12 +345,12 @@ export default class ViewportObserver {
|
|
|
280
345
|
this.isStarted = true;
|
|
281
346
|
}
|
|
282
347
|
stop() {
|
|
283
|
-
var _this$mutationObserve2, _this$
|
|
348
|
+
var _this$mutationObserve2, _this$intersectionObs0, _this$performanceObse2;
|
|
284
349
|
if (!this.isStarted) {
|
|
285
350
|
return;
|
|
286
351
|
}
|
|
287
352
|
(_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 ? void 0 : _this$mutationObserve2.disconnect();
|
|
288
|
-
(_this$
|
|
353
|
+
(_this$intersectionObs0 = this.intersectionObserver) === null || _this$intersectionObs0 === void 0 ? void 0 : _this$intersectionObs0.disconnect();
|
|
289
354
|
(_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 ? void 0 : _this$performanceObse2.disconnect();
|
|
290
355
|
this.isStarted = false;
|
|
291
356
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// Batched mutation data for performance optimization
|
|
2
|
+
|
|
2
3
|
function createMutationObserver({
|
|
3
4
|
onAttributeMutation,
|
|
4
5
|
onChildListMutation,
|
|
@@ -8,10 +9,10 @@ function createMutationObserver({
|
|
|
8
9
|
return null;
|
|
9
10
|
}
|
|
10
11
|
const mutationObserverCallback = mutations => {
|
|
11
|
-
const addedNodes = [];
|
|
12
|
-
const removedNodes = [];
|
|
13
|
-
const attributeMutations = [];
|
|
14
12
|
const targets = [];
|
|
13
|
+
// Use nested Maps for O(1) batching performance
|
|
14
|
+
// Short-lived Maps are safe since they're discarded after each callback
|
|
15
|
+
const batchedMutations = new Map();
|
|
15
16
|
for (const mut of mutations) {
|
|
16
17
|
if (!(mut.target instanceof HTMLElement)) {
|
|
17
18
|
continue;
|
|
@@ -29,51 +30,66 @@ function createMutationObserver({
|
|
|
29
30
|
const oldValue = (_mut$oldValue = mut.oldValue) !== null && _mut$oldValue !== void 0 ? _mut$oldValue : undefined;
|
|
30
31
|
const newValue = mut.attributeName ? mut.target.getAttribute(mut.attributeName) : undefined;
|
|
31
32
|
if (oldValue !== newValue) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
} else {
|
|
41
|
-
var _mut$attributeName2;
|
|
42
|
-
onAttributeMutation({
|
|
43
|
-
target: mut.target,
|
|
44
|
-
attributeName: (_mut$attributeName2 = mut.attributeName) !== null && _mut$attributeName2 !== void 0 ? _mut$attributeName2 : 'unknown',
|
|
45
|
-
oldValue,
|
|
46
|
-
newValue
|
|
47
|
-
});
|
|
48
|
-
}
|
|
33
|
+
var _mut$attributeName;
|
|
34
|
+
onAttributeMutation({
|
|
35
|
+
target: mut.target,
|
|
36
|
+
attributeName: (_mut$attributeName = mut.attributeName) !== null && _mut$attributeName !== void 0 ? _mut$attributeName : 'unknown',
|
|
37
|
+
oldValue,
|
|
38
|
+
newValue
|
|
39
|
+
});
|
|
49
40
|
}
|
|
50
41
|
continue;
|
|
51
42
|
} else if (mut.type === 'childList') {
|
|
52
43
|
var _mut$addedNodes, _mut$removedNodes;
|
|
44
|
+
// In chromium browser MutationRecord has timestamp field, which we should use.
|
|
45
|
+
const timestamp = Math.round(mut.timestamp || performance.now());
|
|
46
|
+
|
|
47
|
+
// Get or create timestamp bucket
|
|
48
|
+
let timestampBucket = batchedMutations.get(timestamp);
|
|
49
|
+
if (!timestampBucket) {
|
|
50
|
+
timestampBucket = new Map();
|
|
51
|
+
batchedMutations.set(timestamp, timestampBucket);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Get or create target batch within timestamp bucket
|
|
55
|
+
let batch = timestampBucket.get(mut.target);
|
|
56
|
+
if (!batch) {
|
|
57
|
+
batch = {
|
|
58
|
+
target: new WeakRef(mut.target),
|
|
59
|
+
addedNodes: [],
|
|
60
|
+
removedNodes: [],
|
|
61
|
+
timestamp
|
|
62
|
+
};
|
|
63
|
+
timestampBucket.set(mut.target, batch);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Accumulate added nodes
|
|
53
67
|
((_mut$addedNodes = mut.addedNodes) !== null && _mut$addedNodes !== void 0 ? _mut$addedNodes : []).forEach(node => {
|
|
54
68
|
if (node instanceof HTMLElement) {
|
|
55
|
-
addedNodes.push(new WeakRef(node));
|
|
69
|
+
batch.addedNodes.push(new WeakRef(node));
|
|
56
70
|
}
|
|
57
71
|
});
|
|
72
|
+
|
|
73
|
+
// Accumulate removed nodes
|
|
58
74
|
((_mut$removedNodes = mut.removedNodes) !== null && _mut$removedNodes !== void 0 ? _mut$removedNodes : []).forEach(node => {
|
|
59
75
|
if (node instanceof HTMLElement) {
|
|
60
|
-
removedNodes.push(new WeakRef(node));
|
|
76
|
+
batch.removedNodes.push(new WeakRef(node));
|
|
61
77
|
}
|
|
62
78
|
});
|
|
63
79
|
}
|
|
64
80
|
targets.push(mut.target);
|
|
65
81
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
82
|
+
|
|
83
|
+
// Process all batched childList mutations
|
|
84
|
+
for (const timestampBucket of batchedMutations.values()) {
|
|
85
|
+
for (const batch of timestampBucket.values()) {
|
|
86
|
+
onChildListMutation({
|
|
87
|
+
target: batch.target,
|
|
88
|
+
addedNodes: batch.addedNodes,
|
|
89
|
+
removedNodes: batch.removedNodes,
|
|
90
|
+
timestamp: batch.timestamp
|
|
91
|
+
});
|
|
92
|
+
}
|
|
77
93
|
}
|
|
78
94
|
onMutationFinished === null || onMutationFinished === void 0 ? void 0 : onMutationFinished({
|
|
79
95
|
targets
|
package/dist/esm/vc/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
-
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
2
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
4
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
5
5
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
6
6
|
var _process;
|
|
@@ -12,19 +12,42 @@ import { VCObserverNOOP } from './no-op-vc-observer';
|
|
|
12
12
|
import { VCObserver } from './vc-observer';
|
|
13
13
|
import VCObserverNew from './vc-observer-new';
|
|
14
14
|
import { RLLPlaceholderHandlers } from './vc-observer/observers/rll-placeholders';
|
|
15
|
+
import { SSRPlaceholderHandlers } from './vc-observer/observers/ssr-placeholders';
|
|
15
16
|
export var VCObserverWrapper = /*#__PURE__*/function () {
|
|
16
17
|
function VCObserverWrapper() {
|
|
18
|
+
var _opts$ssrEnablePageLa, _opts$disableSizeAndP;
|
|
17
19
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
18
20
|
_classCallCheck(this, VCObserverWrapper);
|
|
19
21
|
this.newVCObserver = null;
|
|
20
22
|
this.oldVCObserver = null;
|
|
23
|
+
|
|
24
|
+
// Initialize SSR placeholder handler once
|
|
25
|
+
this.ssrPlaceholderHandler = new SSRPlaceholderHandlers({
|
|
26
|
+
enablePageLayoutPlaceholder: (_opts$ssrEnablePageLa = opts.ssrEnablePageLayoutPlaceholder) !== null && _opts$ssrEnablePageLa !== void 0 ? _opts$ssrEnablePageLa : false,
|
|
27
|
+
disableSizeAndPositionCheck: (_opts$disableSizeAndP = opts.disableSizeAndPositionCheck) !== null && _opts$disableSizeAndP !== void 0 ? _opts$disableSizeAndP : {
|
|
28
|
+
v: false,
|
|
29
|
+
h: false
|
|
30
|
+
}
|
|
31
|
+
});
|
|
21
32
|
if (isVCRevisionEnabled('fy25.03')) {
|
|
33
|
+
var _opts$ssrEnablePageLa2, _opts$disableSizeAndP2;
|
|
22
34
|
this.newVCObserver = new VCObserverNew({
|
|
23
|
-
selectorConfig: opts.selectorConfig
|
|
35
|
+
selectorConfig: opts.selectorConfig,
|
|
36
|
+
isPostInteraction: opts.isPostInteraction,
|
|
37
|
+
SSRConfig: {
|
|
38
|
+
enablePageLayoutPlaceholder: (_opts$ssrEnablePageLa2 = opts.ssrEnablePageLayoutPlaceholder) !== null && _opts$ssrEnablePageLa2 !== void 0 ? _opts$ssrEnablePageLa2 : false,
|
|
39
|
+
disableSizeAndPositionCheck: (_opts$disableSizeAndP2 = opts.disableSizeAndPositionCheck) !== null && _opts$disableSizeAndP2 !== void 0 ? _opts$disableSizeAndP2 : {
|
|
40
|
+
v: false,
|
|
41
|
+
h: false
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
ssrPlaceholderHandler: this.ssrPlaceholderHandler
|
|
24
45
|
});
|
|
25
46
|
}
|
|
26
47
|
if (isVCRevisionEnabled('fy25.01') || isVCRevisionEnabled('fy25.02')) {
|
|
27
|
-
this.oldVCObserver = new VCObserver(opts)
|
|
48
|
+
this.oldVCObserver = new VCObserver(_objectSpread(_objectSpread({}, opts), {}, {
|
|
49
|
+
ssrPlaceholderHandler: this.ssrPlaceholderHandler
|
|
50
|
+
}));
|
|
28
51
|
}
|
|
29
52
|
}
|
|
30
53
|
|
|
@@ -83,6 +106,8 @@ export var VCObserverWrapper = /*#__PURE__*/function () {
|
|
|
83
106
|
(_this$newVCObserver2 = this.newVCObserver) === null || _this$newVCObserver2 === void 0 || _this$newVCObserver2.stop();
|
|
84
107
|
}
|
|
85
108
|
RLLPlaceholderHandlers.getInstance().reset();
|
|
109
|
+
// Clear shared SSR placeholder handler
|
|
110
|
+
this.ssrPlaceholderHandler.clear();
|
|
86
111
|
}
|
|
87
112
|
}, {
|
|
88
113
|
key: "getVCRawData",
|
|
@@ -156,20 +181,28 @@ export var VCObserverWrapper = /*#__PURE__*/function () {
|
|
|
156
181
|
}, {
|
|
157
182
|
key: "setSSRElement",
|
|
158
183
|
value: function setSSRElement(element) {
|
|
159
|
-
var _this$oldVCObserver5;
|
|
184
|
+
var _this$oldVCObserver5, _this$newVCObserver4;
|
|
160
185
|
(_this$oldVCObserver5 = this.oldVCObserver) === null || _this$oldVCObserver5 === void 0 || _this$oldVCObserver5.setSSRElement(element);
|
|
186
|
+
(_this$newVCObserver4 = this.newVCObserver) === null || _this$newVCObserver4 === void 0 || _this$newVCObserver4.setReactRootElement(element);
|
|
161
187
|
}
|
|
162
188
|
}, {
|
|
163
189
|
key: "setReactRootRenderStart",
|
|
164
190
|
value: function setReactRootRenderStart(startTime) {
|
|
165
|
-
var _this$oldVCObserver6;
|
|
191
|
+
var _this$oldVCObserver6, _this$newVCObserver5;
|
|
166
192
|
(_this$oldVCObserver6 = this.oldVCObserver) === null || _this$oldVCObserver6 === void 0 || _this$oldVCObserver6.setReactRootRenderStart(startTime || performance.now());
|
|
193
|
+
(_this$newVCObserver5 = this.newVCObserver) === null || _this$newVCObserver5 === void 0 || _this$newVCObserver5.setReactRootRenderStart(startTime || performance.now());
|
|
167
194
|
}
|
|
168
195
|
}, {
|
|
169
196
|
key: "setReactRootRenderStop",
|
|
170
197
|
value: function setReactRootRenderStop(stopTime) {
|
|
171
|
-
var _this$oldVCObserver7;
|
|
198
|
+
var _this$oldVCObserver7, _this$newVCObserver6;
|
|
172
199
|
(_this$oldVCObserver7 = this.oldVCObserver) === null || _this$oldVCObserver7 === void 0 || _this$oldVCObserver7.setReactRootRenderStop(stopTime || performance.now());
|
|
200
|
+
(_this$newVCObserver6 = this.newVCObserver) === null || _this$newVCObserver6 === void 0 || _this$newVCObserver6.setReactRootRenderStop(stopTime || performance.now());
|
|
201
|
+
}
|
|
202
|
+
}, {
|
|
203
|
+
key: "collectSSRPlaceholders",
|
|
204
|
+
value: function collectSSRPlaceholders() {
|
|
205
|
+
this.ssrPlaceholderHandler.collectExistingPlaceholders();
|
|
173
206
|
}
|
|
174
207
|
}]);
|
|
175
208
|
}();
|
|
@@ -448,7 +448,8 @@ export var VCObserver = /*#__PURE__*/function () {
|
|
|
448
448
|
this.devToolsEnabled = options.devToolsEnabled || false;
|
|
449
449
|
this.oldDomUpdatesEnabled = options.oldDomUpdates || false;
|
|
450
450
|
var ssrEnablePageLayoutPlaceholder = options.ssrEnablePageLayoutPlaceholder,
|
|
451
|
-
disableSizeAndPositionCheck = options.disableSizeAndPositionCheck
|
|
451
|
+
disableSizeAndPositionCheck = options.disableSizeAndPositionCheck,
|
|
452
|
+
ssrPlaceholderHandler = options.ssrPlaceholderHandler;
|
|
452
453
|
this.observers = new Observers({
|
|
453
454
|
selectorConfig: options.selectorConfig || {
|
|
454
455
|
id: false,
|
|
@@ -460,7 +461,8 @@ export var VCObserver = /*#__PURE__*/function () {
|
|
|
460
461
|
SSRConfig: {
|
|
461
462
|
enablePageLayoutPlaceholder: ssrEnablePageLayoutPlaceholder || false,
|
|
462
463
|
disableSizeAndPositionCheck: disableSizeAndPositionCheck
|
|
463
|
-
}
|
|
464
|
+
},
|
|
465
|
+
ssrPlaceholderHandler: ssrPlaceholderHandler
|
|
464
466
|
});
|
|
465
467
|
this.heatmap = !isVCRevisionEnabled('fy25.01') ? [] : this.getCleanHeatmap();
|
|
466
468
|
this.heatmapNext = this.getCleanHeatmap();
|
|
@@ -520,6 +522,12 @@ export var VCObserver = /*#__PURE__*/function () {
|
|
|
520
522
|
var stopTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : performance.now();
|
|
521
523
|
this.observers.setReactRootRenderStop(stopTime);
|
|
522
524
|
}
|
|
525
|
+
}, {
|
|
526
|
+
key: "collectSSRPlaceholders",
|
|
527
|
+
value: function collectSSRPlaceholders() {
|
|
528
|
+
// This is handled by the shared SSRPlaceholderHandlers in VCObserverWrapper
|
|
529
|
+
// Individual observers don't need to implement this
|
|
530
|
+
}
|
|
523
531
|
}, {
|
|
524
532
|
key: "setAbortReason",
|
|
525
533
|
value: function setAbortReason(abort, timestamp) {
|