@atlaskit/react-ufo 3.10.3 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/config/index.js +51 -5
  3. package/dist/cjs/create-experimental-interaction-metrics-payload/index.js +2 -1
  4. package/dist/cjs/create-payload/utils/get-vc-metrics.js +41 -20
  5. package/dist/cjs/interaction-metrics/index.js +2 -1
  6. package/dist/cjs/interaction-metrics/post-interaction-log.js +4 -2
  7. package/dist/cjs/vc/index.js +123 -35
  8. package/dist/cjs/vc/vc-observer/getVCRevisionsData.js +48 -23
  9. package/dist/cjs/vc/vc-observer/index.js +17 -6
  10. package/dist/cjs/vc/vc-observer-new/entries-timeline/index.js +1 -3
  11. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +25 -7
  12. package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +136 -115
  13. package/dist/es2019/config/index.js +49 -6
  14. package/dist/es2019/create-experimental-interaction-metrics-payload/index.js +2 -1
  15. package/dist/es2019/create-payload/utils/get-vc-metrics.js +36 -19
  16. package/dist/es2019/interaction-metrics/index.js +2 -1
  17. package/dist/es2019/interaction-metrics/post-interaction-log.js +2 -1
  18. package/dist/es2019/vc/index.js +98 -35
  19. package/dist/es2019/vc/vc-observer/getVCRevisionsData.js +52 -25
  20. package/dist/es2019/vc/vc-observer/index.js +18 -6
  21. package/dist/es2019/vc/vc-observer-new/entries-timeline/index.js +1 -3
  22. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +23 -7
  23. package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +122 -103
  24. package/dist/esm/config/index.js +49 -5
  25. package/dist/esm/create-experimental-interaction-metrics-payload/index.js +2 -1
  26. package/dist/esm/create-payload/utils/get-vc-metrics.js +42 -21
  27. package/dist/esm/interaction-metrics/index.js +2 -1
  28. package/dist/esm/interaction-metrics/post-interaction-log.js +4 -2
  29. package/dist/esm/vc/index.js +123 -35
  30. package/dist/esm/vc/vc-observer/getVCRevisionsData.js +48 -23
  31. package/dist/esm/vc/vc-observer/index.js +17 -6
  32. package/dist/esm/vc/vc-observer-new/entries-timeline/index.js +1 -3
  33. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.js +25 -7
  34. package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +136 -115
  35. package/dist/types/config/index.d.ts +14 -3
  36. package/dist/types/create-post-interaction-log-payload/index.d.ts +2 -2
  37. package/dist/types/vc/types.d.ts +3 -1
  38. package/dist/types/vc/vc-observer/getVCRevisionsData.d.ts +5 -3
  39. package/dist/types/vc/vc-observer/index.d.ts +1 -1
  40. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.d.ts +8 -3
  41. package/dist/types/vc/vc-observer-new/viewport-observer/index.d.ts +8 -1
  42. package/dist/types-ts4.5/config/index.d.ts +14 -3
  43. package/dist/types-ts4.5/create-post-interaction-log-payload/index.d.ts +2 -2
  44. package/dist/types-ts4.5/vc/types.d.ts +3 -1
  45. package/dist/types-ts4.5/vc/vc-observer/getVCRevisionsData.d.ts +5 -3
  46. package/dist/types-ts4.5/vc/vc-observer/index.d.ts +1 -1
  47. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/canvas-pixel.d.ts +8 -3
  48. package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/index.d.ts +8 -1
  49. package/package.json +7 -1
@@ -1,5 +1,6 @@
1
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
2
  import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
4
  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; } } }; }
4
5
  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; } }
5
6
  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; }
@@ -54,139 +55,154 @@ var ViewportObserver = /*#__PURE__*/function () {
54
55
  var _this = this;
55
56
  var onChange = _ref2.onChange;
56
57
  _classCallCheck(this, ViewportObserver);
57
- this.mapVisibleNodeRects = new WeakMap();
58
- this.intersectionObserver = createIntersectionObserver({
59
- onEntry: function onEntry(_ref3) {
60
- var target = _ref3.target,
61
- rect = _ref3.rect,
62
- time = _ref3.time,
63
- type = _ref3.type,
64
- mutationData = _ref3.mutationData;
65
- if (!target) {
66
- return;
67
- }
68
- var visible = isElementVisible(target);
69
- var lastElementRect = _this.mapVisibleNodeRects.get(target);
70
- _this.mapVisibleNodeRects.set(target, rect);
71
- onChange({
72
- time: time,
73
- type: type,
74
- elementRef: new WeakRef(target),
75
- visible: visible,
76
- rect: rect,
77
- previousRect: lastElementRect,
78
- mutationData: mutationData
79
- });
58
+ _defineProperty(this, "handleIntersectionEntry", function (_ref3) {
59
+ var target = _ref3.target,
60
+ rect = _ref3.rect,
61
+ time = _ref3.time,
62
+ type = _ref3.type,
63
+ mutationData = _ref3.mutationData;
64
+ if (!target) {
65
+ return;
80
66
  }
67
+ var visible = isElementVisible(target);
68
+ var lastElementRect = _this.mapVisibleNodeRects.get(target);
69
+ _this.mapVisibleNodeRects.set(target, rect);
70
+ _this.onChange({
71
+ time: time,
72
+ type: type,
73
+ elementRef: new WeakRef(target),
74
+ visible: visible,
75
+ rect: rect,
76
+ previousRect: lastElementRect,
77
+ mutationData: mutationData
78
+ });
81
79
  });
82
- this.mutationObserver = createMutationObserver({
83
- onChildListMutation: function onChildListMutation(_ref4) {
84
- var _removedNodes$map;
85
- var addedNodes = _ref4.addedNodes,
86
- removedNodes = _ref4.removedNodes;
87
- var removedNodeRects = (_removedNodes$map = removedNodes === null || removedNodes === void 0 ? void 0 : removedNodes.map(function (n) {
88
- return _this.mapVisibleNodeRects.get(n);
89
- })) !== null && _removedNodes$map !== void 0 ? _removedNodes$map : [];
90
- addedNodes.forEach(function (addedNode) {
91
- var _this$intersectionObs3;
92
- // for (const elem of addedNode.querySelectorAll('*')) {
93
- // this.intersectionObserver?.watchAndTag(elem, 'mutation:child-element');
94
- // }
95
-
96
- var sameDeletedNode = removedNodes.find(function (n) {
97
- return n.isEqualNode(addedNode);
98
- });
99
- if (sameDeletedNode) {
100
- var _this$intersectionObs;
101
- (_this$intersectionObs = _this.intersectionObserver) === null || _this$intersectionObs === void 0 || _this$intersectionObs.watchAndTag(addedNode, 'mutation:remount');
102
- return;
103
- }
104
- if (isContainedWithinMediaWrapper(addedNode)) {
105
- var _this$intersectionObs2;
106
- (_this$intersectionObs2 = _this.intersectionObserver) === null || _this$intersectionObs2 === void 0 || _this$intersectionObs2.watchAndTag(addedNode, 'mutation:media');
107
- return;
108
- }
109
- (_this$intersectionObs3 = _this.intersectionObserver) === null || _this$intersectionObs3 === void 0 || _this$intersectionObs3.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
80
+ _defineProperty(this, "handleChildListMutation", function (_ref4) {
81
+ var addedNodes = _ref4.addedNodes,
82
+ removedNodes = _ref4.removedNodes;
83
+ var removedNodeRects = removedNodes.map(function (n) {
84
+ return _this.mapVisibleNodeRects.get(n);
85
+ });
86
+ addedNodes.forEach(function (addedNode) {
87
+ var _this$intersectionObs3;
88
+ var sameDeletedNode = removedNodes.find(function (n) {
89
+ return n.isEqualNode(addedNode);
110
90
  });
111
- },
112
- onAttributeMutation: function onAttributeMutation(_ref5) {
113
- var _this$intersectionObs4;
114
- var target = _ref5.target,
115
- attributeName = _ref5.attributeName;
116
- (_this$intersectionObs4 = _this.intersectionObserver) === null || _this$intersectionObs4 === void 0 || _this$intersectionObs4.watchAndTag(target, function (_ref6) {
117
- var target = _ref6.target,
118
- rect = _ref6.rect;
119
- if (isContainedWithinMediaWrapper(target)) {
120
- return {
121
- type: 'mutation:media',
122
- mutationData: {
123
- attributeName: attributeName
124
- }
125
- };
126
- }
127
- if (isNonVisualStyleMutation({
128
- target: target,
129
- attributeName: attributeName,
130
- type: 'attributes'
131
- })) {
132
- return {
133
- type: 'mutation:attribute:non-visual-style',
134
- mutationData: {
135
- attributeName: attributeName
136
- }
137
- };
138
- }
139
- var lastElementRect = _this.mapVisibleNodeRects.get(target);
140
- if (lastElementRect && sameRectSize(rect, lastElementRect)) {
141
- return {
142
- type: 'mutation:attribute:no-layout-shift',
143
- mutationData: {
144
- attributeName: attributeName
145
- }
146
- };
147
- }
91
+ if (sameDeletedNode) {
92
+ var _this$intersectionObs;
93
+ (_this$intersectionObs = _this.intersectionObserver) === null || _this$intersectionObs === void 0 || _this$intersectionObs.watchAndTag(addedNode, 'mutation:remount');
94
+ return;
95
+ }
96
+ if (isContainedWithinMediaWrapper(addedNode)) {
97
+ var _this$intersectionObs2;
98
+ (_this$intersectionObs2 = _this.intersectionObserver) === null || _this$intersectionObs2 === void 0 || _this$intersectionObs2.watchAndTag(addedNode, 'mutation:media');
99
+ return;
100
+ }
101
+ (_this$intersectionObs3 = _this.intersectionObserver) === null || _this$intersectionObs3 === void 0 || _this$intersectionObs3.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
102
+ });
103
+ });
104
+ _defineProperty(this, "handleAttributeMutation", function (_ref5) {
105
+ var _this$intersectionObs4;
106
+ var target = _ref5.target,
107
+ attributeName = _ref5.attributeName;
108
+ (_this$intersectionObs4 = _this.intersectionObserver) === null || _this$intersectionObs4 === void 0 || _this$intersectionObs4.watchAndTag(target, function (_ref6) {
109
+ var target = _ref6.target,
110
+ rect = _ref6.rect;
111
+ if (isContainedWithinMediaWrapper(target)) {
148
112
  return {
149
- type: 'mutation:attribute',
113
+ type: 'mutation:media',
150
114
  mutationData: {
151
115
  attributeName: attributeName
152
116
  }
153
117
  };
154
- });
155
- }
156
- });
157
- this.performanceObserver = createPerformanceObserver({
158
- onLayoutShift: function onLayoutShift(_ref7) {
159
- var time = _ref7.time,
160
- changedRects = _ref7.changedRects;
161
- var _iterator = _createForOfIteratorHelper(changedRects),
162
- _step;
163
- try {
164
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
165
- var changedRect = _step.value;
166
- var target = changedRect.node;
167
- if (target) {
168
- onChange({
169
- time: time,
170
- elementRef: new WeakRef(target),
171
- visible: true,
172
- rect: changedRect.rect,
173
- previousRect: changedRect.previousRect,
174
- type: 'layout-shift'
175
- });
118
+ }
119
+ if (isNonVisualStyleMutation({
120
+ target: target,
121
+ attributeName: attributeName,
122
+ type: 'attributes'
123
+ })) {
124
+ return {
125
+ type: 'mutation:attribute:non-visual-style',
126
+ mutationData: {
127
+ attributeName: attributeName
128
+ }
129
+ };
130
+ }
131
+ var lastElementRect = _this.mapVisibleNodeRects.get(target);
132
+ if (lastElementRect && sameRectSize(rect, lastElementRect)) {
133
+ return {
134
+ type: 'mutation:attribute:no-layout-shift',
135
+ mutationData: {
136
+ attributeName: attributeName
176
137
  }
138
+ };
139
+ }
140
+ return {
141
+ type: 'mutation:attribute',
142
+ mutationData: {
143
+ attributeName: attributeName
144
+ }
145
+ };
146
+ });
147
+ });
148
+ _defineProperty(this, "handleLayoutShift", function (_ref7) {
149
+ var time = _ref7.time,
150
+ changedRects = _ref7.changedRects;
151
+ var _iterator = _createForOfIteratorHelper(changedRects),
152
+ _step;
153
+ try {
154
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
155
+ var changedRect = _step.value;
156
+ var target = changedRect.node;
157
+ if (target) {
158
+ _this.onChange({
159
+ time: time,
160
+ elementRef: new WeakRef(target),
161
+ visible: true,
162
+ rect: changedRect.rect,
163
+ previousRect: changedRect.previousRect,
164
+ type: 'layout-shift'
165
+ });
177
166
  }
178
- } catch (err) {
179
- _iterator.e(err);
180
- } finally {
181
- _iterator.f();
182
167
  }
168
+ } catch (err) {
169
+ _iterator.e(err);
170
+ } finally {
171
+ _iterator.f();
183
172
  }
184
173
  });
174
+ this.mapVisibleNodeRects = new WeakMap();
175
+ this.onChange = onChange;
176
+ this.isStarted = false;
177
+ this.intersectionObserver = null;
178
+ this.mutationObserver = null;
179
+ this.performanceObserver = null;
185
180
  }
186
181
  return _createClass(ViewportObserver, [{
182
+ key: "initializeObservers",
183
+ value: function initializeObservers() {
184
+ if (this.isStarted) {
185
+ return;
186
+ }
187
+ this.intersectionObserver = createIntersectionObserver({
188
+ onEntry: this.handleIntersectionEntry
189
+ });
190
+ this.mutationObserver = createMutationObserver({
191
+ onChildListMutation: this.handleChildListMutation,
192
+ onAttributeMutation: this.handleAttributeMutation
193
+ });
194
+ this.performanceObserver = createPerformanceObserver({
195
+ onLayoutShift: this.handleLayoutShift
196
+ });
197
+ }
198
+ }, {
187
199
  key: "start",
188
200
  value: function start() {
189
201
  var _this$mutationObserve, _this$performanceObse;
202
+ if (this.isStarted) {
203
+ return;
204
+ }
205
+ this.initializeObservers();
190
206
  (_this$mutationObserve = this.mutationObserver) === null || _this$mutationObserve === void 0 || _this$mutationObserve.observe(document.body, {
191
207
  attributeOldValue: true,
192
208
  attributes: true,
@@ -199,14 +215,19 @@ var ViewportObserver = /*#__PURE__*/function () {
199
215
  // @ts-ignore-error
200
216
  durationThreshold: 30
201
217
  });
218
+ this.isStarted = true;
202
219
  }
203
220
  }, {
204
221
  key: "stop",
205
222
  value: function stop() {
206
223
  var _this$mutationObserve2, _this$intersectionObs5, _this$performanceObse2;
224
+ if (!this.isStarted) {
225
+ return;
226
+ }
207
227
  (_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 || _this$mutationObserve2.disconnect();
208
228
  (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 || _this$intersectionObs5.disconnect();
209
229
  (_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 || _this$performanceObse2.disconnect();
230
+ this.isStarted = false;
210
231
  }
211
232
  }]);
212
233
  }();
@@ -74,7 +74,17 @@ export type Config = {
74
74
  readonly ssr?: boolean;
75
75
  readonly ssrWhitelist?: string[];
76
76
  readonly stopVCAtInteractionFinish?: boolean;
77
- readonly enabledVCRevisions?: readonly TTVCRevisions[];
77
+ /**
78
+ * The revisions of TTVC that will be calculated
79
+ * - `all` is the TTVC revisions that are used on a product level
80
+ * - `byExperience` is the version that is used on an experience level.
81
+ * Note that an entry in the `byExperience` config should only be a SUBSET of the `all` config,
82
+ * i.e. every element for all `byExperience` entry configs should exist in the `all` config
83
+ */
84
+ readonly enabledVCRevisions?: {
85
+ all: readonly TTVCRevisions[];
86
+ byExperience?: Record<string, readonly TTVCRevisions[]>;
87
+ };
78
88
  };
79
89
  readonly postInteractionLog?: {
80
90
  readonly enabled?: boolean;
@@ -99,8 +109,9 @@ export type Config = {
99
109
  };
100
110
  export declare function setUFOConfig(newConfig: Config): void;
101
111
  export declare function getConfig(): Config | undefined;
102
- export declare function getEnabledVCRevisions(): TTVCRevisions[];
103
- export declare function isVCRevisionEnabled(revision: TTVCRevisions): boolean;
112
+ export declare function getEnabledVCRevisions(experienceKey?: string): readonly TTVCRevisions[];
113
+ export declare function isVCRevisionEnabled(revision: TTVCRevisions, experienceKey?: string): boolean;
114
+ export declare function getMostRecentVCRevision(experienceKey?: string): TTVCRevisions;
104
115
  export declare function getInteractionRate(name: string, interactionKind: InteractionKind): number;
105
116
  export declare function getExperimentalInteractionRate(name: string, interactionType: InteractionType): number;
106
117
  export declare function getPostInteractionRate(name: string, interactionType: InteractionType): number;
@@ -26,12 +26,12 @@ declare function createPostInteractionLogPayload({ lastInteractionFinish, reactP
26
26
  vc90: number | null;
27
27
  vcClean: boolean;
28
28
  type: import("../common").InteractionType;
29
- id: string;
30
29
  abortReason?: import("../common").AbortReasonType | undefined;
30
+ id: string;
31
31
  abortedByInteractionName?: string | undefined;
32
32
  routeName: string | null;
33
- experimentalTTAI?: number | undefined;
34
33
  experimentalVC90?: number | undefined;
34
+ experimentalTTAI?: number | undefined;
35
35
  };
36
36
  revisedEndTime: number;
37
37
  revisedTtai: number;
@@ -7,6 +7,7 @@ export type GetVCResultType = {
7
7
  prefix?: string;
8
8
  ssr?: number;
9
9
  vc?: VCRawDataType | null;
10
+ experienceKey: string;
10
11
  };
11
12
  export type SelectorConfig = {
12
13
  id: boolean;
@@ -25,8 +26,9 @@ export type VCObserverOptions = {
25
26
  export interface VCObserverInterface {
26
27
  start(startArg: {
27
28
  startTime: number;
29
+ experienceKey?: string;
28
30
  }): void;
29
- stop(): void;
31
+ stop(experienceKey?: string): void;
30
32
  getVCRawData(): VCRawDataType | null;
31
33
  getVCResult(param: GetVCResultType): Promise<VCResult>;
32
34
  setSSRElement(element: HTMLElement): void;
@@ -1,4 +1,5 @@
1
1
  import { InteractionMetrics } from '../../common/common/types';
2
+ import { RevisionPayload } from '../../common/vc/types';
2
3
  import type { MultiRevisionHeatmap } from './heatmap/heatmap';
3
4
  type CalculatedVC = {
4
5
  VC: {
@@ -8,7 +9,7 @@ type CalculatedVC = {
8
9
  [key: string]: string[] | null;
9
10
  };
10
11
  };
11
- export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean, isEventAborted, multiHeatmap, ssr, calculatedVC, calculatedVCNext, }: {
12
+ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean, isEventAborted, multiHeatmap, ssr, calculatedVC, calculatedVCNext, experienceKey, }: {
12
13
  fullPrefix?: string;
13
14
  interaction: Pick<InteractionMetrics, 'start' | 'end'>;
14
15
  isVCClean: boolean;
@@ -16,9 +17,10 @@ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean,
16
17
  multiHeatmap: MultiRevisionHeatmap | null;
17
18
  calculatedVC: CalculatedVC;
18
19
  calculatedVCNext: CalculatedVC;
20
+ experienceKey: string;
19
21
  ssr?: number;
20
22
  }): {
21
- [x: string]: import("../../common").RevisionPayload;
23
+ [x: string]: RevisionPayload;
22
24
  } | {
23
25
  [x: string]: {
24
26
  revision: string;
@@ -26,7 +28,7 @@ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean,
26
28
  'metric:vc90': number | null;
27
29
  vcDetails: {
28
30
  [key: string]: {
29
- t: number | null | undefined;
31
+ t: number;
30
32
  e: string[];
31
33
  };
32
34
  };
@@ -41,7 +41,7 @@ export declare class VCObserver implements VCObserverInterface {
41
41
  targetName: string;
42
42
  ignoreReason: VCIgnoreReason | undefined;
43
43
  }[];
44
- getVCResult: ({ start, stop, tti, prefix, ssr, vc, isEventAborted, }: GetVCResultType) => Promise<VCResult>;
44
+ getVCResult: ({ start, stop, tti, prefix, ssr, vc, isEventAborted, experienceKey, }: GetVCResultType) => Promise<VCResult>;
45
45
  static calculateVC({ heatmap, ssr, componentsLog, viewport, }: {
46
46
  heatmap: number[][];
47
47
  ssr?: number;
@@ -5,11 +5,11 @@ type Viewport = {
5
5
  };
6
6
  /**
7
7
  * Class responsible for managing a scaled canvas and tracking pixel drawing operations.
8
- * It uses an OffscreenCanvas for better performance and maintains a mapping between
9
- * colors and timestamps for pixel counting purposes.
8
+ * It uses either an OffscreenCanvas (if available) or a regular HTML Canvas for better performance
9
+ * and maintains a mapping between colors and timestamps for pixel counting purposes.
10
10
  */
11
11
  export declare class ViewportCanvas {
12
- /** The underlying OffscreenCanvas instance */
12
+ /** The underlying Canvas instance (either OffscreenCanvas or HTMLCanvasElement) */
13
13
  private readonly canvas;
14
14
  /** The 2D rendering context of the canvas */
15
15
  private readonly ctx;
@@ -30,6 +30,11 @@ export declare class ViewportCanvas {
30
30
  * @throws {Error} If canvas context cannot be obtained
31
31
  */
32
32
  constructor(viewport: Viewport, scaleFactor?: number);
33
+ /**
34
+ * Creates a canvas instance, falling back to HTMLCanvasElement if OffscreenCanvas is not available
35
+ * or if the feature flag is disabled
36
+ */
37
+ private createCanvas;
33
38
  getScaledDimensions(): {
34
39
  width: number;
35
40
  height: number;
@@ -16,7 +16,14 @@ export default class ViewportObserver {
16
16
  private mutationObserver;
17
17
  private performanceObserver;
18
18
  private mapVisibleNodeRects;
19
- constructor({ onChange: onChange }: ViewPortObserverConstructorArgs);
19
+ private onChange;
20
+ private isStarted;
21
+ constructor({ onChange }: ViewPortObserverConstructorArgs);
22
+ private handleIntersectionEntry;
23
+ private handleChildListMutation;
24
+ private handleAttributeMutation;
25
+ private handleLayoutShift;
26
+ private initializeObservers;
20
27
  start(): void;
21
28
  stop(): void;
22
29
  }
@@ -74,7 +74,17 @@ export type Config = {
74
74
  readonly ssr?: boolean;
75
75
  readonly ssrWhitelist?: string[];
76
76
  readonly stopVCAtInteractionFinish?: boolean;
77
- readonly enabledVCRevisions?: readonly TTVCRevisions[];
77
+ /**
78
+ * The revisions of TTVC that will be calculated
79
+ * - `all` is the TTVC revisions that are used on a product level
80
+ * - `byExperience` is the version that is used on an experience level.
81
+ * Note that an entry in the `byExperience` config should only be a SUBSET of the `all` config,
82
+ * i.e. every element for all `byExperience` entry configs should exist in the `all` config
83
+ */
84
+ readonly enabledVCRevisions?: {
85
+ all: readonly TTVCRevisions[];
86
+ byExperience?: Record<string, readonly TTVCRevisions[]>;
87
+ };
78
88
  };
79
89
  readonly postInteractionLog?: {
80
90
  readonly enabled?: boolean;
@@ -99,8 +109,9 @@ export type Config = {
99
109
  };
100
110
  export declare function setUFOConfig(newConfig: Config): void;
101
111
  export declare function getConfig(): Config | undefined;
102
- export declare function getEnabledVCRevisions(): TTVCRevisions[];
103
- export declare function isVCRevisionEnabled(revision: TTVCRevisions): boolean;
112
+ export declare function getEnabledVCRevisions(experienceKey?: string): readonly TTVCRevisions[];
113
+ export declare function isVCRevisionEnabled(revision: TTVCRevisions, experienceKey?: string): boolean;
114
+ export declare function getMostRecentVCRevision(experienceKey?: string): TTVCRevisions;
104
115
  export declare function getInteractionRate(name: string, interactionKind: InteractionKind): number;
105
116
  export declare function getExperimentalInteractionRate(name: string, interactionType: InteractionType): number;
106
117
  export declare function getPostInteractionRate(name: string, interactionType: InteractionType): number;
@@ -26,12 +26,12 @@ declare function createPostInteractionLogPayload({ lastInteractionFinish, reactP
26
26
  vc90: number | null;
27
27
  vcClean: boolean;
28
28
  type: import("../common").InteractionType;
29
- id: string;
30
29
  abortReason?: import("../common").AbortReasonType | undefined;
30
+ id: string;
31
31
  abortedByInteractionName?: string | undefined;
32
32
  routeName: string | null;
33
- experimentalTTAI?: number | undefined;
34
33
  experimentalVC90?: number | undefined;
34
+ experimentalTTAI?: number | undefined;
35
35
  };
36
36
  revisedEndTime: number;
37
37
  revisedTtai: number;
@@ -7,6 +7,7 @@ export type GetVCResultType = {
7
7
  prefix?: string;
8
8
  ssr?: number;
9
9
  vc?: VCRawDataType | null;
10
+ experienceKey: string;
10
11
  };
11
12
  export type SelectorConfig = {
12
13
  id: boolean;
@@ -25,8 +26,9 @@ export type VCObserverOptions = {
25
26
  export interface VCObserverInterface {
26
27
  start(startArg: {
27
28
  startTime: number;
29
+ experienceKey?: string;
28
30
  }): void;
29
- stop(): void;
31
+ stop(experienceKey?: string): void;
30
32
  getVCRawData(): VCRawDataType | null;
31
33
  getVCResult(param: GetVCResultType): Promise<VCResult>;
32
34
  setSSRElement(element: HTMLElement): void;
@@ -1,4 +1,5 @@
1
1
  import { InteractionMetrics } from '../../common/common/types';
2
+ import { RevisionPayload } from '../../common/vc/types';
2
3
  import type { MultiRevisionHeatmap } from './heatmap/heatmap';
3
4
  type CalculatedVC = {
4
5
  VC: {
@@ -8,7 +9,7 @@ type CalculatedVC = {
8
9
  [key: string]: string[] | null;
9
10
  };
10
11
  };
11
- export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean, isEventAborted, multiHeatmap, ssr, calculatedVC, calculatedVCNext, }: {
12
+ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean, isEventAborted, multiHeatmap, ssr, calculatedVC, calculatedVCNext, experienceKey, }: {
12
13
  fullPrefix?: string;
13
14
  interaction: Pick<InteractionMetrics, 'start' | 'end'>;
14
15
  isVCClean: boolean;
@@ -16,9 +17,10 @@ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean,
16
17
  multiHeatmap: MultiRevisionHeatmap | null;
17
18
  calculatedVC: CalculatedVC;
18
19
  calculatedVCNext: CalculatedVC;
20
+ experienceKey: string;
19
21
  ssr?: number;
20
22
  }): {
21
- [x: string]: import("../../common").RevisionPayload;
23
+ [x: string]: RevisionPayload;
22
24
  } | {
23
25
  [x: string]: {
24
26
  revision: string;
@@ -26,7 +28,7 @@ export declare function getVCRevisionsData({ fullPrefix, interaction, isVCClean,
26
28
  'metric:vc90': number | null;
27
29
  vcDetails: {
28
30
  [key: string]: {
29
- t: number | null | undefined;
31
+ t: number;
30
32
  e: string[];
31
33
  };
32
34
  };
@@ -51,7 +51,7 @@ export declare class VCObserver implements VCObserverInterface {
51
51
  targetName: string;
52
52
  ignoreReason: VCIgnoreReason | undefined;
53
53
  }[];
54
- getVCResult: ({ start, stop, tti, prefix, ssr, vc, isEventAborted, }: GetVCResultType) => Promise<VCResult>;
54
+ getVCResult: ({ start, stop, tti, prefix, ssr, vc, isEventAborted, experienceKey, }: GetVCResultType) => Promise<VCResult>;
55
55
  static calculateVC({ heatmap, ssr, componentsLog, viewport, }: {
56
56
  heatmap: number[][];
57
57
  ssr?: number;
@@ -5,11 +5,11 @@ type Viewport = {
5
5
  };
6
6
  /**
7
7
  * Class responsible for managing a scaled canvas and tracking pixel drawing operations.
8
- * It uses an OffscreenCanvas for better performance and maintains a mapping between
9
- * colors and timestamps for pixel counting purposes.
8
+ * It uses either an OffscreenCanvas (if available) or a regular HTML Canvas for better performance
9
+ * and maintains a mapping between colors and timestamps for pixel counting purposes.
10
10
  */
11
11
  export declare class ViewportCanvas {
12
- /** The underlying OffscreenCanvas instance */
12
+ /** The underlying Canvas instance (either OffscreenCanvas or HTMLCanvasElement) */
13
13
  private readonly canvas;
14
14
  /** The 2D rendering context of the canvas */
15
15
  private readonly ctx;
@@ -30,6 +30,11 @@ export declare class ViewportCanvas {
30
30
  * @throws {Error} If canvas context cannot be obtained
31
31
  */
32
32
  constructor(viewport: Viewport, scaleFactor?: number);
33
+ /**
34
+ * Creates a canvas instance, falling back to HTMLCanvasElement if OffscreenCanvas is not available
35
+ * or if the feature flag is disabled
36
+ */
37
+ private createCanvas;
33
38
  getScaledDimensions(): {
34
39
  width: number;
35
40
  height: number;
@@ -16,7 +16,14 @@ export default class ViewportObserver {
16
16
  private mutationObserver;
17
17
  private performanceObserver;
18
18
  private mapVisibleNodeRects;
19
- constructor({ onChange: onChange }: ViewPortObserverConstructorArgs);
19
+ private onChange;
20
+ private isStarted;
21
+ constructor({ onChange }: ViewPortObserverConstructorArgs);
22
+ private handleIntersectionEntry;
23
+ private handleChildListMutation;
24
+ private handleAttributeMutation;
25
+ private handleLayoutShift;
26
+ private initializeObservers;
20
27
  start(): void;
21
28
  stop(): void;
22
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/react-ufo",
3
- "version": "3.10.3",
3
+ "version": "3.11.0",
4
4
  "description": "Parts of React UFO that are publicly available",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -127,9 +127,15 @@
127
127
  }
128
128
  },
129
129
  "platform-feature-flags": {
130
+ "platform_ufo_use_offscreen_canvas": {
131
+ "type": "boolean"
132
+ },
130
133
  "platform_ufo_canvas_heatmap_full_precision": {
131
134
  "type": "boolean"
132
135
  },
136
+ "platform_ufo_vc_enable_revisions_by_experience": {
137
+ "type": "boolean"
138
+ },
133
139
  "ufo_return_relative_request_start": {
134
140
  "type": "boolean"
135
141
  },