@atlaskit/react-ufo 3.14.0 → 3.14.2
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 +16 -0
- package/dist/cjs/ignore-holds/index.js +62 -0
- package/dist/cjs/interaction-ignore/ufo-interaction-ignore.js +7 -49
- package/dist/cjs/segment/index.js +7 -0
- package/dist/cjs/segment/segment.js +3 -1
- package/dist/cjs/segment/third-party-segment.js +25 -0
- package/dist/cjs/vc/vc-observer-new/metric-calculator/fy25_03/index.js +12 -6
- package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +30 -6
- package/dist/cjs/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +85 -0
- package/dist/es2019/ignore-holds/index.js +51 -0
- package/dist/es2019/interaction-ignore/ufo-interaction-ignore.js +7 -45
- package/dist/es2019/segment/index.js +2 -1
- package/dist/es2019/segment/segment.js +2 -1
- package/dist/es2019/segment/third-party-segment.js +18 -0
- package/dist/es2019/vc/vc-observer-new/metric-calculator/fy25_03/index.js +12 -6
- package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +32 -6
- package/dist/es2019/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +71 -0
- package/dist/esm/ignore-holds/index.js +53 -0
- package/dist/esm/interaction-ignore/ufo-interaction-ignore.js +7 -47
- package/dist/esm/segment/index.js +2 -1
- package/dist/esm/segment/segment.js +3 -1
- package/dist/esm/segment/third-party-segment.js +18 -0
- package/dist/esm/vc/vc-observer-new/metric-calculator/fy25_03/index.js +12 -6
- package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +30 -6
- package/dist/esm/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +76 -0
- package/dist/types/ignore-holds/index.d.ts +31 -0
- package/dist/types/interaction-ignore/ufo-interaction-ignore.d.ts +6 -21
- package/dist/types/segment/index.d.ts +1 -0
- package/dist/types/segment/segment.d.ts +4 -2
- package/dist/types/segment/third-party-segment.d.ts +6 -0
- package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.d.ts +15 -0
- package/dist/types-ts4.5/ignore-holds/index.d.ts +31 -0
- package/dist/types-ts4.5/interaction-ignore/ufo-interaction-ignore.d.ts +6 -21
- package/dist/types-ts4.5/segment/index.d.ts +1 -0
- package/dist/types-ts4.5/segment/segment.d.ts +4 -2
- package/dist/types-ts4.5/segment/third-party-segment.d.ts +6 -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/utils/get-component-name-and-child-props.d.ts +15 -0
- package/package.json +7 -4
|
@@ -5,6 +5,7 @@ import { RLLPlaceholderHandlers } from '../../vc-observer/observers/rll-placehol
|
|
|
5
5
|
import { createIntersectionObserver } from './intersection-observer';
|
|
6
6
|
import createMutationObserver from './mutation-observer';
|
|
7
7
|
import createPerformanceObserver from './performance-observer';
|
|
8
|
+
import { checkThirdPartySegmentWithIgnoreReason, createMutationTypeWithIgnoredReason } from './utils/get-component-name-and-child-props';
|
|
8
9
|
function isElementVisible(element) {
|
|
9
10
|
if (!(element instanceof HTMLElement)) {
|
|
10
11
|
return true;
|
|
@@ -86,7 +87,7 @@ export default class ViewportObserver {
|
|
|
86
87
|
return this.mapVisibleNodeRects.get(n);
|
|
87
88
|
});
|
|
88
89
|
addedNodes.forEach(addedNodeRef => {
|
|
89
|
-
var _this$
|
|
90
|
+
var _this$intersectionObs4;
|
|
90
91
|
const addedNode = addedNodeRef.deref();
|
|
91
92
|
if (!addedNode) {
|
|
92
93
|
return;
|
|
@@ -108,7 +109,17 @@ export default class ViewportObserver {
|
|
|
108
109
|
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(addedNode, 'mutation:media');
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
|
-
|
|
112
|
+
const {
|
|
113
|
+
isWithinThirdPartySegment,
|
|
114
|
+
ignoredReason
|
|
115
|
+
} = checkThirdPartySegmentWithIgnoreReason(addedNode);
|
|
116
|
+
if (isWithinThirdPartySegment) {
|
|
117
|
+
var _this$intersectionObs3;
|
|
118
|
+
const assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
|
|
119
|
+
(_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(addedNode, assignedReason);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
(_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
|
|
112
123
|
});
|
|
113
124
|
});
|
|
114
125
|
_defineProperty(this, "handleAttributeMutation", ({
|
|
@@ -117,8 +128,8 @@ export default class ViewportObserver {
|
|
|
117
128
|
oldValue,
|
|
118
129
|
newValue
|
|
119
130
|
}) => {
|
|
120
|
-
var _this$
|
|
121
|
-
(_this$
|
|
131
|
+
var _this$intersectionObs5;
|
|
132
|
+
(_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(target, ({
|
|
122
133
|
target,
|
|
123
134
|
rect
|
|
124
135
|
}) => {
|
|
@@ -157,6 +168,21 @@ export default class ViewportObserver {
|
|
|
157
168
|
}
|
|
158
169
|
};
|
|
159
170
|
}
|
|
171
|
+
const {
|
|
172
|
+
isWithinThirdPartySegment,
|
|
173
|
+
ignoredReason
|
|
174
|
+
} = checkThirdPartySegmentWithIgnoreReason(target);
|
|
175
|
+
if (isWithinThirdPartySegment) {
|
|
176
|
+
const assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
|
|
177
|
+
return {
|
|
178
|
+
type: assignedReason,
|
|
179
|
+
mutationData: {
|
|
180
|
+
attributeName,
|
|
181
|
+
oldValue,
|
|
182
|
+
newValue
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
160
186
|
const lastElementRect = this.mapVisibleNodeRects.get(target);
|
|
161
187
|
if (lastElementRect && sameRectSize(rect, lastElementRect)) {
|
|
162
188
|
return {
|
|
@@ -239,12 +265,12 @@ export default class ViewportObserver {
|
|
|
239
265
|
this.isStarted = true;
|
|
240
266
|
}
|
|
241
267
|
stop() {
|
|
242
|
-
var _this$mutationObserve2, _this$
|
|
268
|
+
var _this$mutationObserve2, _this$intersectionObs6, _this$performanceObse2;
|
|
243
269
|
if (!this.isStarted) {
|
|
244
270
|
return;
|
|
245
271
|
}
|
|
246
272
|
(_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 ? void 0 : _this$mutationObserve2.disconnect();
|
|
247
|
-
(_this$
|
|
273
|
+
(_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.disconnect();
|
|
248
274
|
(_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 ? void 0 : _this$performanceObse2.disconnect();
|
|
249
275
|
this.isStarted = false;
|
|
250
276
|
}
|
package/dist/es2019/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Using the React Fiber tree to traverse up the DOM and check if a node is within a specific component
|
|
2
|
+
// and extract child component props if needed.
|
|
3
|
+
export function checkWithinComponentAndExtractChildProps(node, targetComponentName, childComponentConfig) {
|
|
4
|
+
// Get the React fiber from the DOM node
|
|
5
|
+
const key = Object.keys(node).find(key => key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$'));
|
|
6
|
+
if (!key) {
|
|
7
|
+
return {
|
|
8
|
+
isWithin: false
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const fiber = node[key];
|
|
12
|
+
if (!fiber) {
|
|
13
|
+
return {
|
|
14
|
+
isWithin: false
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Traverse up the fiber tree
|
|
19
|
+
let currentFiber = fiber;
|
|
20
|
+
let childProp;
|
|
21
|
+
while (currentFiber) {
|
|
22
|
+
let componentName;
|
|
23
|
+
if (currentFiber.type) {
|
|
24
|
+
if (typeof currentFiber.type === 'function') {
|
|
25
|
+
componentName = currentFiber.type.displayName || currentFiber.type.name;
|
|
26
|
+
} else if (typeof currentFiber.type === 'object' && (currentFiber.type.displayName || currentFiber.type.name)) {
|
|
27
|
+
componentName = currentFiber.type.displayName || currentFiber.type.name;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if this is a child component we're looking for
|
|
32
|
+
if (childComponentConfig && componentName === childComponentConfig.componentName) {
|
|
33
|
+
const props = currentFiber.memoizedProps || currentFiber.pendingProps;
|
|
34
|
+
if (props && props[childComponentConfig.propName] !== undefined) {
|
|
35
|
+
// Overwrite with the nearest child prop (closest to the target component)
|
|
36
|
+
childProp = childComponentConfig.extractValue ? childComponentConfig.extractValue(props) : props[childComponentConfig.propName];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check if we found the target component
|
|
41
|
+
if (componentName === targetComponentName) {
|
|
42
|
+
return {
|
|
43
|
+
isWithin: true,
|
|
44
|
+
...(childComponentConfig && {
|
|
45
|
+
childProp: childProp
|
|
46
|
+
})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
currentFiber = currentFiber.return;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
isWithin: false
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if the node is within a UFOThirdPartySegment and extract any UFOIgnoreHolds reason
|
|
57
|
+
export function checkThirdPartySegmentWithIgnoreReason(node) {
|
|
58
|
+
const result = checkWithinComponentAndExtractChildProps(node, 'UFOThirdPartySegment', {
|
|
59
|
+
componentName: 'UFOIgnoreHolds',
|
|
60
|
+
propName: 'reason'
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
isWithinThirdPartySegment: result.isWithin,
|
|
64
|
+
ignoredReason: result.childProp
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Helper function to create mutation type from UFOIgnoreHoldsReason
|
|
69
|
+
export function createMutationTypeWithIgnoredReason(reason) {
|
|
70
|
+
return `mutation:${reason}`;
|
|
71
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; }
|
|
3
|
+
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) { _defineProperty(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; }
|
|
4
|
+
import React, { useContext, useMemo } from 'react';
|
|
5
|
+
import InteractionContext from '@atlaskit/interaction-context';
|
|
6
|
+
/**
|
|
7
|
+
* Prevent a subtree from holding up an interaction
|
|
8
|
+
* Use this when you have a component which loads in late, but
|
|
9
|
+
* isn't considered to be a breach of SLO
|
|
10
|
+
*
|
|
11
|
+
* ```js
|
|
12
|
+
* <App>
|
|
13
|
+
* <Main />
|
|
14
|
+
* <Sidebar>
|
|
15
|
+
* <UFOIgnoreHolds>
|
|
16
|
+
* <InsightsButton />
|
|
17
|
+
* </UFOIgnoreHolds>
|
|
18
|
+
* </Sidebar>
|
|
19
|
+
* </App>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Has an `ignore` prop, to allow you to use it conditionally
|
|
23
|
+
* Has a `reason` prop, to specify why the hold is being ignored
|
|
24
|
+
*/
|
|
25
|
+
export default function UFOIgnoreHolds(_ref) {
|
|
26
|
+
var children = _ref.children,
|
|
27
|
+
_ref$ignore = _ref.ignore,
|
|
28
|
+
ignore = _ref$ignore === void 0 ? true : _ref$ignore,
|
|
29
|
+
reason = _ref.reason;
|
|
30
|
+
var parentContext = useContext(InteractionContext);
|
|
31
|
+
var ignoredInteractionContext = useMemo(function () {
|
|
32
|
+
if (!parentContext) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return _objectSpread(_objectSpread({}, parentContext), {}, {
|
|
36
|
+
hold: function hold() {
|
|
37
|
+
if (!ignore) {
|
|
38
|
+
return parentContext.hold.apply(parentContext, arguments);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}, [parentContext, ignore]);
|
|
43
|
+
|
|
44
|
+
// react-18: Use children directly
|
|
45
|
+
var kids = children != null ? children : null;
|
|
46
|
+
if (!ignoredInteractionContext) {
|
|
47
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, kids);
|
|
48
|
+
}
|
|
49
|
+
return /*#__PURE__*/React.createElement(InteractionContext.Provider, {
|
|
50
|
+
value: ignoredInteractionContext
|
|
51
|
+
}, kids);
|
|
52
|
+
}
|
|
53
|
+
UFOIgnoreHolds.displayName = 'UFOIgnoreHolds';
|
|
@@ -1,51 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
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) { _defineProperty(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; }
|
|
4
|
-
import React, { useContext, useMemo } from 'react';
|
|
5
|
-
import InteractionContext from '@atlaskit/interaction-context';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import UFOIgnoreHolds from '../ignore-holds';
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
|
-
*
|
|
9
|
-
* Use
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* ```js
|
|
13
|
-
* <App>
|
|
14
|
-
* <Main />
|
|
15
|
-
* <Sidebar>
|
|
16
|
-
* <UFOInteractionIgnore>
|
|
17
|
-
* <InsightsButton />
|
|
18
|
-
* </UFOInteractionIgnore>
|
|
19
|
-
* </Sidebar>
|
|
20
|
-
* </App>
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* Has an `ignore` prop, to allow you to use it conditionally
|
|
5
|
+
* Legacy wrapper component that delegates to `UFOIgnoreHolds`.
|
|
6
|
+
* Use `UFOIgnoreHolds` instead for new implementations.
|
|
7
|
+
* This component is maintained for backward compatibility only.
|
|
24
8
|
*/
|
|
25
|
-
export default function UFOInteractionIgnore(
|
|
26
|
-
|
|
27
|
-
_ref$ignore = _ref.ignore,
|
|
28
|
-
ignore = _ref$ignore === void 0 ? true : _ref$ignore;
|
|
29
|
-
var parentContext = useContext(InteractionContext);
|
|
30
|
-
var ignoredInteractionContext = useMemo(function () {
|
|
31
|
-
if (!parentContext) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
return _objectSpread(_objectSpread({}, parentContext), {}, {
|
|
35
|
-
hold: function hold() {
|
|
36
|
-
if (!ignore) {
|
|
37
|
-
return parentContext.hold.apply(parentContext, arguments);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}, [parentContext, ignore]);
|
|
42
|
-
|
|
43
|
-
// react-18: Use children directly
|
|
44
|
-
var kids = children != null ? children : null;
|
|
45
|
-
if (!ignoredInteractionContext) {
|
|
46
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, kids);
|
|
47
|
-
}
|
|
48
|
-
return /*#__PURE__*/React.createElement(InteractionContext.Provider, {
|
|
49
|
-
value: ignoredInteractionContext
|
|
50
|
-
}, kids);
|
|
9
|
+
export default function UFOInteractionIgnore(props) {
|
|
10
|
+
return /*#__PURE__*/React.createElement(UFOIgnoreHolds, props);
|
|
51
11
|
}
|
|
@@ -30,7 +30,9 @@ export default function UFOSegment(_ref) {
|
|
|
30
30
|
var segmentName = _ref.name,
|
|
31
31
|
children = _ref.children,
|
|
32
32
|
_ref$mode = _ref.mode,
|
|
33
|
-
mode = _ref$mode === void 0 ? 'single' : _ref$mode
|
|
33
|
+
mode = _ref$mode === void 0 ? 'single' : _ref$mode,
|
|
34
|
+
_ref$type = _ref.type,
|
|
35
|
+
type = _ref$type === void 0 ? 'first-party' : _ref$type;
|
|
34
36
|
var parentContext = useContext(UFOInteractionContext);
|
|
35
37
|
var segmentIdMap = useMemo(function () {
|
|
36
38
|
if (!(parentContext !== null && parentContext !== void 0 && parentContext.segmentIdMap)) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
+
var _excluded = ["children"];
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
|
+
import UFOIgnoreHolds from '../ignore-holds';
|
|
7
|
+
import UFOSegment from './segment';
|
|
8
|
+
export function UFOThirdPartySegment(props) {
|
|
9
|
+
var children = props.children,
|
|
10
|
+
otherProps = _objectWithoutProperties(props, _excluded);
|
|
11
|
+
return /*#__PURE__*/React.createElement(UFOSegment, _extends({
|
|
12
|
+
type: "third-party"
|
|
13
|
+
}, otherProps), /*#__PURE__*/React.createElement(UFOIgnoreHolds, {
|
|
14
|
+
ignore: fg('platform_ufo_exclude_3p_elements_from_ttai'),
|
|
15
|
+
reason: "third-party-element"
|
|
16
|
+
}, children));
|
|
17
|
+
}
|
|
18
|
+
UFOThirdPartySegment.displayName = 'UFOThirdPartySegment';
|
|
@@ -10,7 +10,16 @@ import AbstractVCCalculatorBase from '../abstract-base-vc-calculator';
|
|
|
10
10
|
import isViewportEntryData from '../utils/is-viewport-entry-data';
|
|
11
11
|
var ABORTING_WINDOW_EVENT = ['wheel', 'scroll', 'keydown', 'resize'];
|
|
12
12
|
var REVISION_NO = 'fy25.03';
|
|
13
|
-
var
|
|
13
|
+
var getConsideredEntryTypes = function getConsideredEntryTypes() {
|
|
14
|
+
var entryTypes = ['mutation:child-element', 'mutation:element', 'mutation:attribute', 'layout-shift', 'window:event'];
|
|
15
|
+
|
|
16
|
+
// If not exclude 3p elements from ttvc,
|
|
17
|
+
// including the tags into the ConsideredEntryTypes so that it won't be ignored for TTVC calculation
|
|
18
|
+
if (!fg('platform_ufo_exclude_3p_elements_from_ttvc')) {
|
|
19
|
+
entryTypes.push('mutation:third-party-element');
|
|
20
|
+
}
|
|
21
|
+
return entryTypes;
|
|
22
|
+
};
|
|
14
23
|
|
|
15
24
|
// TODO: AFO-3523
|
|
16
25
|
// Those are the attributes we have found when testing the 'fy25.03' manually.
|
|
@@ -28,7 +37,7 @@ var VCCalculator_FY25_03 = /*#__PURE__*/function (_AbstractVCCalculator) {
|
|
|
28
37
|
return _createClass(VCCalculator_FY25_03, [{
|
|
29
38
|
key: "isEntryIncluded",
|
|
30
39
|
value: function isEntryIncluded(entry) {
|
|
31
|
-
if (!
|
|
40
|
+
if (!getConsideredEntryTypes().includes(entry.data.type)) {
|
|
32
41
|
return false;
|
|
33
42
|
}
|
|
34
43
|
if (entry.data.type === 'mutation:attribute') {
|
|
@@ -37,10 +46,7 @@ var VCCalculator_FY25_03 = /*#__PURE__*/function (_AbstractVCCalculator) {
|
|
|
37
46
|
if (!attributeName || KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS.includes(attributeName)) {
|
|
38
47
|
return false;
|
|
39
48
|
}
|
|
40
|
-
if (attributeName === 'data-aui-version' && fg('
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || (attributeName === 'data-renderer-start-pos' || attributeName === 'data-table-local-id' || attributeName === 'spellcheck') && fg('platform_ufo_ignore_extra_attributes') || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
|
|
49
|
+
if (attributeName === 'data-aui-version' || attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || (attributeName === 'data-renderer-start-pos' || attributeName === 'data-table-local-id' || attributeName === 'spellcheck') && fg('platform_ufo_ignore_extra_attributes') || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
|
|
44
50
|
return false;
|
|
45
51
|
}
|
|
46
52
|
return true;
|
|
@@ -10,6 +10,7 @@ import { RLLPlaceholderHandlers } from '../../vc-observer/observers/rll-placehol
|
|
|
10
10
|
import { createIntersectionObserver } from './intersection-observer';
|
|
11
11
|
import createMutationObserver from './mutation-observer';
|
|
12
12
|
import createPerformanceObserver from './performance-observer';
|
|
13
|
+
import { checkThirdPartySegmentWithIgnoreReason, createMutationTypeWithIgnoredReason } from './utils/get-component-name-and-child-props';
|
|
13
14
|
function isElementVisible(element) {
|
|
14
15
|
if (!(element instanceof HTMLElement)) {
|
|
15
16
|
return true;
|
|
@@ -93,7 +94,7 @@ var ViewportObserver = /*#__PURE__*/function () {
|
|
|
93
94
|
return _this.mapVisibleNodeRects.get(n);
|
|
94
95
|
});
|
|
95
96
|
addedNodes.forEach(function (addedNodeRef) {
|
|
96
|
-
var _this$
|
|
97
|
+
var _this$intersectionObs4;
|
|
97
98
|
var addedNode = addedNodeRef.deref();
|
|
98
99
|
if (!addedNode) {
|
|
99
100
|
return;
|
|
@@ -115,16 +116,25 @@ var ViewportObserver = /*#__PURE__*/function () {
|
|
|
115
116
|
(_this$intersectionObs2 = _this.intersectionObserver) === null || _this$intersectionObs2 === void 0 || _this$intersectionObs2.watchAndTag(addedNode, 'mutation:media');
|
|
116
117
|
return;
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
+
var _checkThirdPartySegme = checkThirdPartySegmentWithIgnoreReason(addedNode),
|
|
120
|
+
isWithinThirdPartySegment = _checkThirdPartySegme.isWithinThirdPartySegment,
|
|
121
|
+
ignoredReason = _checkThirdPartySegme.ignoredReason;
|
|
122
|
+
if (isWithinThirdPartySegment) {
|
|
123
|
+
var _this$intersectionObs3;
|
|
124
|
+
var assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
|
|
125
|
+
(_this$intersectionObs3 = _this.intersectionObserver) === null || _this$intersectionObs3 === void 0 || _this$intersectionObs3.watchAndTag(addedNode, assignedReason);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
(_this$intersectionObs4 = _this.intersectionObserver) === null || _this$intersectionObs4 === void 0 || _this$intersectionObs4.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
|
|
119
129
|
});
|
|
120
130
|
});
|
|
121
131
|
_defineProperty(this, "handleAttributeMutation", function (_ref5) {
|
|
122
|
-
var _this$
|
|
132
|
+
var _this$intersectionObs5;
|
|
123
133
|
var target = _ref5.target,
|
|
124
134
|
attributeName = _ref5.attributeName,
|
|
125
135
|
oldValue = _ref5.oldValue,
|
|
126
136
|
newValue = _ref5.newValue;
|
|
127
|
-
(_this$
|
|
137
|
+
(_this$intersectionObs5 = _this.intersectionObserver) === null || _this$intersectionObs5 === void 0 || _this$intersectionObs5.watchAndTag(target, function (_ref6) {
|
|
128
138
|
var target = _ref6.target,
|
|
129
139
|
rect = _ref6.rect;
|
|
130
140
|
if (isContainedWithinMediaWrapper(target)) {
|
|
@@ -162,6 +172,20 @@ var ViewportObserver = /*#__PURE__*/function () {
|
|
|
162
172
|
}
|
|
163
173
|
};
|
|
164
174
|
}
|
|
175
|
+
var _checkThirdPartySegme2 = checkThirdPartySegmentWithIgnoreReason(target),
|
|
176
|
+
isWithinThirdPartySegment = _checkThirdPartySegme2.isWithinThirdPartySegment,
|
|
177
|
+
ignoredReason = _checkThirdPartySegme2.ignoredReason;
|
|
178
|
+
if (isWithinThirdPartySegment) {
|
|
179
|
+
var assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
|
|
180
|
+
return {
|
|
181
|
+
type: assignedReason,
|
|
182
|
+
mutationData: {
|
|
183
|
+
attributeName: attributeName,
|
|
184
|
+
oldValue: oldValue,
|
|
185
|
+
newValue: newValue
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
165
189
|
var lastElementRect = _this.mapVisibleNodeRects.get(target);
|
|
166
190
|
if (lastElementRect && sameRectSize(rect, lastElementRect)) {
|
|
167
191
|
return {
|
|
@@ -258,12 +282,12 @@ var ViewportObserver = /*#__PURE__*/function () {
|
|
|
258
282
|
}, {
|
|
259
283
|
key: "stop",
|
|
260
284
|
value: function stop() {
|
|
261
|
-
var _this$mutationObserve2, _this$
|
|
285
|
+
var _this$mutationObserve2, _this$intersectionObs6, _this$performanceObse2;
|
|
262
286
|
if (!this.isStarted) {
|
|
263
287
|
return;
|
|
264
288
|
}
|
|
265
289
|
(_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 || _this$mutationObserve2.disconnect();
|
|
266
|
-
(_this$
|
|
290
|
+
(_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 || _this$intersectionObs6.disconnect();
|
|
267
291
|
(_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 || _this$performanceObse2.disconnect();
|
|
268
292
|
this.isStarted = false;
|
|
269
293
|
}
|
package/dist/esm/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _typeof from "@babel/runtime/helpers/typeof";
|
|
3
|
+
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; }
|
|
4
|
+
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) { _defineProperty(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; }
|
|
5
|
+
// Using the React Fiber tree to traverse up the DOM and check if a node is within a specific component
|
|
6
|
+
// and extract child component props if needed.
|
|
7
|
+
export function checkWithinComponentAndExtractChildProps(node, targetComponentName, childComponentConfig) {
|
|
8
|
+
// Get the React fiber from the DOM node
|
|
9
|
+
var key = Object.keys(node).find(function (key) {
|
|
10
|
+
return key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$');
|
|
11
|
+
});
|
|
12
|
+
if (!key) {
|
|
13
|
+
return {
|
|
14
|
+
isWithin: false
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
var fiber = node[key];
|
|
18
|
+
if (!fiber) {
|
|
19
|
+
return {
|
|
20
|
+
isWithin: false
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Traverse up the fiber tree
|
|
25
|
+
var currentFiber = fiber;
|
|
26
|
+
var childProp;
|
|
27
|
+
while (currentFiber) {
|
|
28
|
+
var componentName = void 0;
|
|
29
|
+
if (currentFiber.type) {
|
|
30
|
+
if (typeof currentFiber.type === 'function') {
|
|
31
|
+
componentName = currentFiber.type.displayName || currentFiber.type.name;
|
|
32
|
+
} else if (_typeof(currentFiber.type) === 'object' && (currentFiber.type.displayName || currentFiber.type.name)) {
|
|
33
|
+
componentName = currentFiber.type.displayName || currentFiber.type.name;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check if this is a child component we're looking for
|
|
38
|
+
if (childComponentConfig && componentName === childComponentConfig.componentName) {
|
|
39
|
+
var props = currentFiber.memoizedProps || currentFiber.pendingProps;
|
|
40
|
+
if (props && props[childComponentConfig.propName] !== undefined) {
|
|
41
|
+
// Overwrite with the nearest child prop (closest to the target component)
|
|
42
|
+
childProp = childComponentConfig.extractValue ? childComponentConfig.extractValue(props) : props[childComponentConfig.propName];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check if we found the target component
|
|
47
|
+
if (componentName === targetComponentName) {
|
|
48
|
+
return _objectSpread({
|
|
49
|
+
isWithin: true
|
|
50
|
+
}, childComponentConfig && {
|
|
51
|
+
childProp: childProp
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
currentFiber = currentFiber.return;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
isWithin: false
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check if the node is within a UFOThirdPartySegment and extract any UFOIgnoreHolds reason
|
|
62
|
+
export function checkThirdPartySegmentWithIgnoreReason(node) {
|
|
63
|
+
var result = checkWithinComponentAndExtractChildProps(node, 'UFOThirdPartySegment', {
|
|
64
|
+
componentName: 'UFOIgnoreHolds',
|
|
65
|
+
propName: 'reason'
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
isWithinThirdPartySegment: result.isWithin,
|
|
69
|
+
ignoredReason: result.childProp
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Helper function to create mutation type from UFOIgnoreHoldsReason
|
|
74
|
+
export function createMutationTypeWithIgnoredReason(reason) {
|
|
75
|
+
return "mutation:".concat(reason);
|
|
76
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
export type UFOIgnoreHoldsReason = 'third-party-element';
|
|
3
|
+
export type UFOIgnoreHoldsProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
ignore?: boolean;
|
|
6
|
+
reason?: UFOIgnoreHoldsReason;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Prevent a subtree from holding up an interaction
|
|
10
|
+
* Use this when you have a component which loads in late, but
|
|
11
|
+
* isn't considered to be a breach of SLO
|
|
12
|
+
*
|
|
13
|
+
* ```js
|
|
14
|
+
* <App>
|
|
15
|
+
* <Main />
|
|
16
|
+
* <Sidebar>
|
|
17
|
+
* <UFOIgnoreHolds>
|
|
18
|
+
* <InsightsButton />
|
|
19
|
+
* </UFOIgnoreHolds>
|
|
20
|
+
* </Sidebar>
|
|
21
|
+
* </App>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Has an `ignore` prop, to allow you to use it conditionally
|
|
25
|
+
* Has a `reason` prop, to specify why the hold is being ignored
|
|
26
|
+
*/
|
|
27
|
+
declare function UFOIgnoreHolds({ children, ignore, reason }: UFOIgnoreHoldsProps): React.JSX.Element;
|
|
28
|
+
declare namespace UFOIgnoreHolds {
|
|
29
|
+
var displayName: string;
|
|
30
|
+
}
|
|
31
|
+
export default UFOIgnoreHolds;
|
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { UFOIgnoreHoldsProps } from '../ignore-holds';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Use
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ```js
|
|
8
|
-
* <App>
|
|
9
|
-
* <Main />
|
|
10
|
-
* <Sidebar>
|
|
11
|
-
* <UFOInteractionIgnore>
|
|
12
|
-
* <InsightsButton />
|
|
13
|
-
* </UFOInteractionIgnore>
|
|
14
|
-
* </Sidebar>
|
|
15
|
-
* </App>
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* Has an `ignore` prop, to allow you to use it conditionally
|
|
4
|
+
* Legacy wrapper component that delegates to `UFOIgnoreHolds`.
|
|
5
|
+
* Use `UFOIgnoreHolds` instead for new implementations.
|
|
6
|
+
* This component is maintained for backward compatibility only.
|
|
19
7
|
*/
|
|
20
|
-
export default function UFOInteractionIgnore(
|
|
21
|
-
children?: ReactNode;
|
|
22
|
-
ignore?: boolean;
|
|
23
|
-
}): React.JSX.Element;
|
|
8
|
+
export default function UFOInteractionIgnore(props: UFOIgnoreHoldsProps): React.JSX.Element;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
|
-
type
|
|
2
|
+
export type UFOSegmentType = 'third-party' | 'first-party';
|
|
3
|
+
export type Props = {
|
|
3
4
|
name: string;
|
|
4
5
|
children: ReactNode;
|
|
5
6
|
mode?: 'list' | 'single';
|
|
7
|
+
type?: UFOSegmentType;
|
|
6
8
|
};
|
|
7
9
|
/** A portion of the page we apply measurement to */
|
|
8
|
-
declare function UFOSegment({ name: segmentName, children, mode }: Props): React.JSX.Element;
|
|
10
|
+
declare function UFOSegment({ name: segmentName, children, mode, type, }: Props): React.JSX.Element;
|
|
9
11
|
declare namespace UFOSegment {
|
|
10
12
|
var displayName: string;
|
|
11
13
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ObservedWindowEvent } from './window-event-observer';
|
|
2
|
-
export type VCObserverEntryType = 'mutation:child-element' | 'mutation:remount' | 'mutation:element' | 'mutation:element-replacement' | 'mutation:attribute:no-layout-shift' | 'mutation:attribute:non-visual-style' | 'mutation:attribute' | 'mutation:media' | 'mutation:rll-placeholder' | 'layout-shift' | 'window:event' | 'unknown';
|
|
2
|
+
export type VCObserverEntryType = 'mutation:child-element' | 'mutation:remount' | 'mutation:element' | 'mutation:element-replacement' | 'mutation:attribute:no-layout-shift' | 'mutation:attribute:non-visual-style' | 'mutation:attribute' | 'mutation:media' | 'mutation:rll-placeholder' | 'mutation:third-party-element' | 'layout-shift' | 'window:event' | 'unknown';
|
|
3
3
|
export type ViewportEntryData = {
|
|
4
4
|
readonly type: VCObserverEntryType;
|
|
5
5
|
readonly elementName: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UFOIgnoreHoldsReason } from '../../../../ignore-holds';
|
|
2
|
+
import { VCObserverEntryType } from '../../types';
|
|
3
|
+
export declare function checkWithinComponentAndExtractChildProps<T = string>(node: HTMLElement, targetComponentName: string, childComponentConfig?: {
|
|
4
|
+
componentName: string;
|
|
5
|
+
propName: string;
|
|
6
|
+
extractValue?: (props: any) => T;
|
|
7
|
+
}): {
|
|
8
|
+
isWithin: boolean;
|
|
9
|
+
childProp?: T;
|
|
10
|
+
};
|
|
11
|
+
export declare function checkThirdPartySegmentWithIgnoreReason(node: HTMLElement): {
|
|
12
|
+
isWithinThirdPartySegment: boolean;
|
|
13
|
+
ignoredReason?: UFOIgnoreHoldsReason;
|
|
14
|
+
};
|
|
15
|
+
export declare function createMutationTypeWithIgnoredReason(reason: UFOIgnoreHoldsReason): VCObserverEntryType;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
export type UFOIgnoreHoldsReason = 'third-party-element';
|
|
3
|
+
export type UFOIgnoreHoldsProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
ignore?: boolean;
|
|
6
|
+
reason?: UFOIgnoreHoldsReason;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Prevent a subtree from holding up an interaction
|
|
10
|
+
* Use this when you have a component which loads in late, but
|
|
11
|
+
* isn't considered to be a breach of SLO
|
|
12
|
+
*
|
|
13
|
+
* ```js
|
|
14
|
+
* <App>
|
|
15
|
+
* <Main />
|
|
16
|
+
* <Sidebar>
|
|
17
|
+
* <UFOIgnoreHolds>
|
|
18
|
+
* <InsightsButton />
|
|
19
|
+
* </UFOIgnoreHolds>
|
|
20
|
+
* </Sidebar>
|
|
21
|
+
* </App>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Has an `ignore` prop, to allow you to use it conditionally
|
|
25
|
+
* Has a `reason` prop, to specify why the hold is being ignored
|
|
26
|
+
*/
|
|
27
|
+
declare function UFOIgnoreHolds({ children, ignore, reason }: UFOIgnoreHoldsProps): React.JSX.Element;
|
|
28
|
+
declare namespace UFOIgnoreHolds {
|
|
29
|
+
var displayName: string;
|
|
30
|
+
}
|
|
31
|
+
export default UFOIgnoreHolds;
|