@atlaskit/react-ufo 4.5.12 → 4.6.1

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 (53) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/config/index.js +19 -6
  3. package/dist/cjs/create-payload/index.js +3 -1
  4. package/dist/cjs/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  5. package/dist/cjs/create-post-interaction-log-payload/index.js +2 -1
  6. package/dist/cjs/interaction-metrics/index.js +2 -1
  7. package/dist/cjs/segment/segment.js +19 -2
  8. package/dist/cjs/trace-hover/index.js +12 -0
  9. package/dist/cjs/trace-interaction/internal/trace-ufo-interaction.js +23 -6
  10. package/dist/cjs/vc/vc-observer-new/index.js +74 -11
  11. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +91 -36
  12. package/dist/es2019/config/index.js +13 -0
  13. package/dist/es2019/create-payload/index.js +3 -0
  14. package/dist/es2019/create-post-interaction-log-payload/get-late-mutations.js +12 -3
  15. package/dist/es2019/create-post-interaction-log-payload/index.js +2 -1
  16. package/dist/es2019/interaction-metrics/index.js +2 -1
  17. package/dist/es2019/segment/segment.js +21 -4
  18. package/dist/es2019/trace-hover/index.js +5 -0
  19. package/dist/es2019/trace-interaction/internal/trace-ufo-interaction.js +24 -7
  20. package/dist/es2019/vc/vc-observer-new/index.js +67 -10
  21. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +56 -8
  22. package/dist/esm/config/index.js +18 -6
  23. package/dist/esm/create-payload/index.js +3 -1
  24. package/dist/esm/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  25. package/dist/esm/create-post-interaction-log-payload/index.js +2 -1
  26. package/dist/esm/interaction-metrics/index.js +2 -1
  27. package/dist/esm/segment/segment.js +21 -4
  28. package/dist/esm/trace-hover/index.js +5 -0
  29. package/dist/esm/trace-interaction/internal/trace-ufo-interaction.js +24 -7
  30. package/dist/esm/vc/vc-observer-new/index.js +74 -11
  31. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +91 -36
  32. package/dist/types/common/common/types.d.ts +5 -0
  33. package/dist/types/common/react-ufo-payload-schema.d.ts +4 -1
  34. package/dist/types/common/vc/types.d.ts +7 -0
  35. package/dist/types/config/index.d.ts +2 -0
  36. package/dist/types/create-payload/index.d.ts +512 -0
  37. package/dist/types/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  38. package/dist/types/trace-hover/index.d.ts +2 -0
  39. package/dist/types/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  40. package/dist/types/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  41. package/dist/types/vc/vc-observer-new/types.d.ts +5 -0
  42. package/dist/types-ts4.5/common/common/types.d.ts +5 -0
  43. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +4 -1
  44. package/dist/types-ts4.5/common/vc/types.d.ts +7 -0
  45. package/dist/types-ts4.5/config/index.d.ts +2 -0
  46. package/dist/types-ts4.5/create-payload/index.d.ts +512 -0
  47. package/dist/types-ts4.5/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  48. package/dist/types-ts4.5/trace-hover/index.d.ts +2 -0
  49. package/dist/types-ts4.5/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  50. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  51. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +5 -0
  52. package/package.json +13 -1
  53. package/trace-hover/package.json +15 -0
@@ -1,4 +1,5 @@
1
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ function getLateMutations(vcDetails, labelStacks = {}, lastInteractionFinish, postInteractionFinishVCRatios) {
2
3
  // Map to track which elements are already seen for each timestamp
3
4
  const seen = new Map();
4
5
  const result = [];
@@ -16,11 +17,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
16
17
  continue;
17
18
  }
18
19
  seenElements.add(element);
19
- result.push({
20
+ const lateMutation = {
20
21
  time: details.t,
21
22
  element,
22
23
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
23
- });
24
+ };
25
+ if (labelStacks && fg('platform_ufo_enable_late_mutation_label_stacks')) {
26
+ const labels = labelStacks[element];
27
+ if (labels) {
28
+ lateMutation.segment = labels.segment;
29
+ lateMutation.labelStack = labels.labelStack;
30
+ }
31
+ }
32
+ result.push(lateMutation);
24
33
  }
25
34
  }
26
35
  return result;
@@ -173,8 +173,9 @@ function createPostInteractionLogPayload({
173
173
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
174
174
  }
175
175
  const vcDetails = postInteractionFinishRevision.vcDetails;
176
+ const labelStacks = postInteractionFinishRevision.labelStacks;
176
177
  if (vcDetails) {
177
- lateMutations = getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
178
+ lateMutations = getLateMutations(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
178
179
  }
179
180
  }
180
181
  return {
@@ -979,7 +979,8 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
979
979
  trace,
980
980
  vcObserver,
981
981
  hold3pActive: new Map(),
982
- hold3pInfo: []
982
+ hold3pInfo: [],
983
+ minorInteractions: []
983
984
  };
984
985
  if (addFeatureFlagsToInteraction) {
985
986
  currentFeatureFlagsAccessed.clear();
@@ -1,12 +1,13 @@
1
1
  import React, { lazy, Profiler, Suspense, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
2
2
  import { unstable_NormalPriority as NormalPriority, unstable_scheduleCallback as scheduleCallback } from 'scheduler';
3
3
  import { v4 as createUUID } from 'uuid';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
4
5
  import coinflip from '../coinflip';
5
- import { getConfig, getInteractionRate } from '../config';
6
+ import { getConfig, getDoNotAbortActivePressInteraction, getInteractionRate, getMinorInteractions } from '../config';
6
7
  import { getActiveTrace, setInteractionActiveTrace } from '../experience-trace-id-context';
7
8
  import UFOInteractionContext from '../interaction-context';
8
9
  import UFOInteractionIDContext from '../interaction-id-context';
9
- import { abortByNewInteraction, addApdex, addCustomData, addCustomTiming, addHold, addHoldByID, addMark, addNewInteraction, addProfilerTimings, addRequestInfo, addSegment, addSpan, removeHoldByID, removeSegment, tryComplete } from '../interaction-metrics';
10
+ import { abortByNewInteraction, addApdex, addCustomData, addCustomTiming, addHold, addHoldByID, addMark, addNewInteraction, addProfilerTimings, addRequestInfo, addSegment, addSpan, getActiveInteraction, removeHoldByID, removeSegment, tryComplete } from '../interaction-metrics';
10
11
  import UFORouteName from '../route-name-context';
11
12
  import generateId from '../short-id';
12
13
  import scheduleOnPaint from './schedule-on-paint';
@@ -145,8 +146,24 @@ export default function UFOSegment({
145
146
  this._internalHoldByID(labelStack, id, name, true);
146
147
  },
147
148
  tracePress(name = 'unknown', timestamp) {
148
- if (interactionId.current != null) {
149
- abortByNewInteraction(interactionId.current, name);
149
+ if (fg('platform_ufo_enable_minor_interactions')) {
150
+ var _getDoNotAbortActiveP, _getMinorInteractions;
151
+ const minorInteractions = [...((_getDoNotAbortActiveP = getDoNotAbortActivePressInteraction()) !== null && _getDoNotAbortActiveP !== void 0 ? _getDoNotAbortActiveP : []), ...((_getMinorInteractions = getMinorInteractions()) !== null && _getMinorInteractions !== void 0 ? _getMinorInteractions : [])];
152
+ if (minorInteractions.includes(name)) {
153
+ var _activeInteraction$mi;
154
+ const activeInteraction = getActiveInteraction();
155
+ activeInteraction === null || activeInteraction === void 0 ? void 0 : (_activeInteraction$mi = activeInteraction.minorInteractions) === null || _activeInteraction$mi === void 0 ? void 0 : _activeInteraction$mi.push({
156
+ name,
157
+ startTime: timestamp !== null && timestamp !== void 0 ? timestamp : performance.now()
158
+ });
159
+ return;
160
+ } else if (interactionId.current != null) {
161
+ abortByNewInteraction(interactionId.current, name);
162
+ }
163
+ } else {
164
+ if (interactionId.current != null) {
165
+ abortByNewInteraction(interactionId.current, name);
166
+ }
150
167
  }
151
168
  const rate = getInteractionRate(name, 'press');
152
169
  if (coinflip(rate)) {
@@ -0,0 +1,5 @@
1
+ import { default as internal_traceUFOInteraction } from '../trace-interaction/internal/trace-ufo-interaction';
2
+ function traceUFOHover(name, timestamp) {
3
+ return internal_traceUFOInteraction(name, 'hover', timestamp);
4
+ }
5
+ export default traceUFOHover;
@@ -1,6 +1,7 @@
1
1
  import { v4 as createUUID } from 'uuid';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import coinflip from '../../coinflip';
3
- import { getDoNotAbortActivePressInteraction, getInteractionRate } from '../../config';
4
+ import { getDoNotAbortActivePressInteraction, getInteractionRate, getMinorInteractions } from '../../config';
4
5
  import { getActiveTrace, setInteractionActiveTrace } from '../../experience-trace-id-context';
5
6
  import { DefaultInteractionID } from '../../interaction-id-context';
6
7
  import { abortAll, addNewInteraction, getActiveInteraction } from '../../interaction-metrics';
@@ -8,15 +9,31 @@ import UFORouteName from '../../route-name-context';
8
9
  function traceUFOInteraction(name, interactionType, startTime) {
9
10
  const rate = getInteractionRate(name, interactionType);
10
11
  const pressInteractionsList = getDoNotAbortActivePressInteraction();
11
- if (pressInteractionsList !== null && pressInteractionsList !== void 0 && pressInteractionsList.includes(name)) {
12
- const interaction = getActiveInteraction();
13
- if ((interaction === null || interaction === void 0 ? void 0 : interaction.ufoName) !== 'unknown' && (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
12
+ if (fg('platform_ufo_enable_minor_interactions')) {
13
+ var _getMinorInteractions;
14
+ const minorInteractions = (pressInteractionsList !== null && pressInteractionsList !== void 0 ? pressInteractionsList : []).concat((_getMinorInteractions = getMinorInteractions()) !== null && _getMinorInteractions !== void 0 ? _getMinorInteractions : []);
15
+ if (minorInteractions.includes(name)) {
16
+ var _activeInteraction$mi;
17
+ const activeInteraction = getActiveInteraction();
18
+ activeInteraction === null || activeInteraction === void 0 ? void 0 : (_activeInteraction$mi = activeInteraction.minorInteractions) === null || _activeInteraction$mi === void 0 ? void 0 : _activeInteraction$mi.push({
19
+ name,
20
+ startTime: startTime !== null && startTime !== void 0 ? startTime : performance.now()
21
+ });
14
22
  return;
23
+ } else {
24
+ abortAll('new_interaction', name);
15
25
  }
16
26
  } else {
17
- // Abort any existing interaction regardless of the coinflip outcome
18
- // Ensures measurements are not carried over between distinct interactions
19
- abortAll('new_interaction', name);
27
+ if (pressInteractionsList !== null && pressInteractionsList !== void 0 && pressInteractionsList.includes(name)) {
28
+ const interaction = getActiveInteraction();
29
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.ufoName) !== 'unknown' && (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
30
+ return;
31
+ }
32
+ } else {
33
+ // Abort any existing interaction regardless of the coinflip outcome
34
+ // Ensures measurements are not carried over between distinct interactions
35
+ abortAll('new_interaction', name);
36
+ }
20
37
  }
21
38
  if (coinflip(rate)) {
22
39
  const startTimestamp = startTime !== null && startTime !== void 0 ? startTime : performance.now();
@@ -1,4 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { SSRPlaceholderHandlers } from '../vc-observer/observers/ssr-placeholders';
3
4
  import EntriesTimeline from './entries-timeline';
4
5
  import getElementName from './get-element-name';
@@ -61,18 +62,27 @@ export default class VCObserverNew {
61
62
  if (element) {
62
63
  elementName = this.getElementName(element);
63
64
  }
65
+ const data = {
66
+ type,
67
+ elementName,
68
+ rect,
69
+ previousRect,
70
+ visible,
71
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
72
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
73
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
74
+ };
75
+ if (element && this.isPostInteraction && fg('platform_ufo_enable_late_mutation_label_stacks')) {
76
+ const labelStacks = getLabelStacks(element);
77
+ if (labelStacks) {
78
+ Object.assign(data, {
79
+ labelStacks
80
+ });
81
+ }
82
+ }
64
83
  this.entriesTimeline.push({
65
84
  time,
66
- data: {
67
- type,
68
- elementName,
69
- rect,
70
- previousRect,
71
- visible,
72
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
73
- oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
74
- newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
75
- }
85
+ data
76
86
  });
77
87
  },
78
88
  // Pass SSR context to ViewportObserver
@@ -245,4 +255,51 @@ export default class VCObserverNew {
245
255
  getElementName(element) {
246
256
  return getElementName(this.selectorConfig, element);
247
257
  }
258
+ }
259
+ function labelStackFromFiber(fiber) {
260
+ var _fiber$child, _fiber$child$memoized;
261
+ const value = fiber === null || fiber === void 0 ? void 0 : (_fiber$child = fiber.child) === null || _fiber$child === void 0 ? void 0 : (_fiber$child$memoized = _fiber$child.memoizedProps) === null || _fiber$child$memoized === void 0 ? void 0 : _fiber$child$memoized.value;
262
+ return Array.isArray(value === null || value === void 0 ? void 0 : value.labelStack) ? value.labelStack : [];
263
+ }
264
+ function labelStackToString(labelStack) {
265
+ return labelStack.map(label => label.name).join('/');
266
+ }
267
+ function labelStackToSegment(labelStack) {
268
+ let segmentIndex = -1;
269
+ for (let i = labelStack.length - 1; i >= 0; i--) {
270
+ if (labelStack[i].segmentId) {
271
+ segmentIndex = i;
272
+ break;
273
+ }
274
+ }
275
+ return labelStack.slice(0, segmentIndex + 1).map(label => label.name).join('/');
276
+ }
277
+ function traverseFiber(fiber) {
278
+ let segment = 'unknown';
279
+ let labelStackString = 'unknown';
280
+ let currentFiber = fiber;
281
+ while (currentFiber) {
282
+ if (currentFiber.type) {
283
+ const componentName = currentFiber.type.displayName || currentFiber.type.name;
284
+ if (componentName === 'UFOSegment' || componentName === 'UFOLabel') {
285
+ const labelStack = labelStackFromFiber(currentFiber);
286
+ labelStackString = labelStackToString(labelStack) || 'unknown';
287
+ segment = labelStackToSegment(labelStack) || 'unknown';
288
+ break;
289
+ }
290
+ }
291
+ currentFiber = currentFiber.return;
292
+ }
293
+ return {
294
+ segment,
295
+ labelStack: labelStackString
296
+ };
297
+ }
298
+ function getLabelStacks(element) {
299
+ const reactFiberKey = Object.keys(element).find(key => key.startsWith('__reactFiber$'));
300
+ if (!reactFiberKey) {
301
+ return null;
302
+ }
303
+ const fiber = element[reactFiberKey];
304
+ return fiber ? traverseFiber(fiber) : null;
248
305
  }
@@ -1,4 +1,7 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
+ import getPageVisibilityUpToTTAI from '../../../create-payload/utils/get-page-visibility-up-to-ttai';
3
+ import { getInteractionId } from '../../../interaction-id-context';
4
+ import { interactions } from '../../../interaction-metrics/common/constants';
2
5
  import { cssIssueOccurrence } from '../viewport-observer/utils/track-display-content-occurrence';
3
6
  import { calculateTTVCPercentilesWithDebugInfo } from './percentile-calc';
4
7
  import getViewportHeight from './utils/get-viewport-height';
@@ -40,6 +43,18 @@ export default class AbstractVCCalculatorBase {
40
43
  }
41
44
  return ratios;
42
45
  }
46
+ getLabelStacks(filteredEntries) {
47
+ const labelStacks = {};
48
+ for (const entry of filteredEntries) {
49
+ if ('elementName' in entry.data && entry.data.labelStacks) {
50
+ labelStacks[entry.data.elementName] = {
51
+ segment: entry.data.labelStacks.segment,
52
+ labelStack: entry.data.labelStacks.labelStack
53
+ };
54
+ }
55
+ }
56
+ return labelStacks;
57
+ }
43
58
  async calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries, include3p) {
44
59
  var _window, _window2, _window3, _window5;
45
60
  const percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99];
@@ -109,6 +124,16 @@ export default class AbstractVCCalculatorBase {
109
124
  }
110
125
  let enhancedVcLogs = vcLogs ? vcLogs.map(log => ({
111
126
  ...log,
127
+ ...(fg('platform_ufo_serialise_ttvc_v3_debug_data') && {
128
+ entries: log.entries.map(entry => {
129
+ var _entry$rect, _entry$previousRect;
130
+ return {
131
+ ...entry,
132
+ rect: (_entry$rect = entry.rect) === null || _entry$rect === void 0 ? void 0 : _entry$rect.toJSON(),
133
+ previousRect: (_entry$previousRect = entry.previousRect) === null || _entry$previousRect === void 0 ? void 0 : _entry$previousRect.toJSON()
134
+ };
135
+ })
136
+ }),
112
137
  viewportPercentage: log.viewportPercentage
113
138
  })) : [];
114
139
 
@@ -152,7 +177,7 @@ export default class AbstractVCCalculatorBase {
152
177
  const ignoredEntriesByTime = new Map();
153
178
  for (const entry of allEntries) {
154
179
  if ('rect' in entry.data && !this.isEntryIncluded(entry, include3p)) {
155
- var _ignoredEntriesByTime;
180
+ var _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou;
156
181
  const viewportData = entry.data;
157
182
  const timestamp = Math.round(entry.time);
158
183
  if (!ignoredEntriesByTime.has(timestamp)) {
@@ -160,6 +185,10 @@ export default class AbstractVCCalculatorBase {
160
185
  }
161
186
  (_ignoredEntriesByTime = ignoredEntriesByTime.get(timestamp)) === null || _ignoredEntriesByTime === void 0 ? void 0 : _ignoredEntriesByTime.push({
162
187
  ...viewportData,
188
+ ...(fg('platform_ufo_serialise_ttvc_v3_debug_data') && {
189
+ rect: (_viewportData$rect = viewportData.rect) === null || _viewportData$rect === void 0 ? void 0 : _viewportData$rect.toJSON(),
190
+ previousRect: (_viewportData$previou = viewportData.previousRect) === null || _viewportData$previou === void 0 ? void 0 : _viewportData$previou.toJSON()
191
+ }),
163
192
  ignoreReason: viewportData.visible ? viewportData.type : 'not-visible'
164
193
  });
165
194
  }
@@ -185,13 +214,29 @@ export default class AbstractVCCalculatorBase {
185
214
  // Only create debug details if callbacks exist
186
215
  let v3RevisionDebugDetails = null;
187
216
  if (shouldCalculateDebugDetails) {
188
- v3RevisionDebugDetails = {
189
- revision: this.revisionNo,
190
- isClean: isVCClean,
191
- abortReason: dirtyReason,
192
- vcLogs: enhancedVcLogs,
193
- interactionId
194
- };
217
+ if (fg('platform_ufo_unify_abort_status_in_ttvc_debug_data')) {
218
+ var _activeInteractionId$;
219
+ // NOTE: using this instead of directly calling `getActiveInteraction()` to get around circular dependencies
220
+ const activeInteractionId = getInteractionId();
221
+ const activeInteraction = interactions.get((_activeInteractionId$ = activeInteractionId.current) !== null && _activeInteractionId$ !== void 0 ? _activeInteractionId$ : '');
222
+ const pageVisibilityUpToTTAI = activeInteraction ? getPageVisibilityUpToTTAI(activeInteraction) : null;
223
+ const isBackgrounded = pageVisibilityUpToTTAI !== 'visible';
224
+ v3RevisionDebugDetails = {
225
+ revision: this.revisionNo,
226
+ isClean: isVCClean && !(activeInteraction !== null && activeInteraction !== void 0 && activeInteraction.abortReason) && !isBackgrounded,
227
+ abortReason: isBackgrounded ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.abortReason,
228
+ vcLogs: enhancedVcLogs,
229
+ interactionId
230
+ };
231
+ } else {
232
+ v3RevisionDebugDetails = {
233
+ revision: this.revisionNo,
234
+ isClean: isVCClean,
235
+ abortReason: dirtyReason,
236
+ vcLogs: enhancedVcLogs,
237
+ interactionId
238
+ };
239
+ }
195
240
  }
196
241
 
197
242
  // Handle devtool callback
@@ -261,6 +306,9 @@ export default class AbstractVCCalculatorBase {
261
306
  vcDetails: vcDetails !== null && vcDetails !== void 0 ? vcDetails : undefined
262
307
  };
263
308
  result.ratios = this.calculateRatios(filteredEntries);
309
+ if (isPostInteraction) {
310
+ result.labelStacks = this.getLabelStacks(filteredEntries);
311
+ }
264
312
  if (fg('platform_ufo_display_content_track_occurrence')) {
265
313
  result.displayContentsOccurrence = cssIssueOccurrence;
266
314
  }
@@ -275,6 +275,18 @@ export function getUfoNameOverrides() {
275
275
  return undefined;
276
276
  }
277
277
  }
278
+ export function getMinorInteractions() {
279
+ try {
280
+ if (!config) {
281
+ return undefined;
282
+ }
283
+ var _config8 = config,
284
+ minorInteractions = _config8.minorInteractions;
285
+ return minorInteractions;
286
+ } catch (e) {
287
+ return undefined;
288
+ }
289
+ }
278
290
 
279
291
  // Contains the list of interactions that do not abort existing known interactions
280
292
  export function getDoNotAbortActivePressInteraction() {
@@ -282,8 +294,8 @@ export function getDoNotAbortActivePressInteraction() {
282
294
  if (!config) {
283
295
  return undefined;
284
296
  }
285
- var _config8 = config,
286
- doNotAbortActivePressInteraction = _config8.doNotAbortActivePressInteraction;
297
+ var _config9 = config,
298
+ doNotAbortActivePressInteraction = _config9.doNotAbortActivePressInteraction;
287
299
  return doNotAbortActivePressInteraction;
288
300
  } catch (e) {
289
301
  return undefined;
@@ -296,8 +308,8 @@ export function getDoNotAbortActivePressInteractionOnTransition() {
296
308
  if (!config) {
297
309
  return undefined;
298
310
  }
299
- var _config9 = config,
300
- doNotAbortActivePressInteractionOnTransition = _config9.doNotAbortActivePressInteractionOnTransition;
311
+ var _config0 = config,
312
+ doNotAbortActivePressInteractionOnTransition = _config0.doNotAbortActivePressInteractionOnTransition;
301
313
  return doNotAbortActivePressInteractionOnTransition;
302
314
  } catch (e) {
303
315
  return undefined;
@@ -309,8 +321,8 @@ export function getInteractionTimeout(ufoName) {
309
321
  if (!config) {
310
322
  return CLEANUP_TIMEOUT;
311
323
  }
312
- var _config0 = config,
313
- interactionTimeout = _config0.interactionTimeout;
324
+ var _config1 = config,
325
+ interactionTimeout = _config1.interactionTimeout;
314
326
  if (interactionTimeout != null && interactionTimeout[ufoName] != null) {
315
327
  return interactionTimeout[ufoName];
316
328
  }
@@ -739,7 +739,7 @@ function _createInteractionMetricsPayload() {
739
739
  'ufo:multipayload': true,
740
740
  'ufo:criticalPayloadCount': criticalPayloadCount
741
741
  } : {}), getBrowserMetadataToLegacyFormat()), getSSRProperties(type)), getAssetsMetrics(interaction, pageLoadInteractionMetrics === null || pageLoadInteractionMetrics === void 0 ? void 0 : pageLoadInteractionMetrics.SSRDoneTime)), getPPSMetrics(interaction)), paintMetrics), getNavigationMetricsToLegacyFormat(type)), finalVCMetrics), experimentalMetrics), (_config$additionalPay = config.additionalPayloadData) === null || _config$additionalPay === void 0 ? void 0 : _config$additionalPay.call(config, interaction)), getTracingContextData(interaction)), getStylesheetMetrics()), getErrorCounts(interaction)), getReactHydrationStats()), {}, {
742
- interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
742
+ interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
743
743
  namePrefix: config.namePrefix || '',
744
744
  segmentPrefix: config.segmentPrefix || '',
745
745
  interactionId: interactionId,
@@ -773,6 +773,8 @@ function _createInteractionMetricsPayload() {
773
773
  unknownElementName: unknownElementName
774
774
  } : {}), unknownElementHierarchy ? {
775
775
  unknownElementHierarchy: unknownElementHierarchy
776
+ } : {}), fg('platform_ufo_enable_minor_interactions') ? {
777
+ minorInteractions: interaction.minorInteractions
776
778
  } : {}),
777
779
  'ufo:payloadTime': roundEpsilon(performance.now() - interactionPayloadStart)
778
780
  })
@@ -1,7 +1,11 @@
1
1
  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; } } }; }
2
2
  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; } }
3
3
  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; }
4
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
4
+ import { fg } from '@atlaskit/platform-feature-flags';
5
+ function getLateMutations(vcDetails) {
6
+ var labelStacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7
+ var lastInteractionFinish = arguments.length > 2 ? arguments[2] : undefined;
8
+ var postInteractionFinishVCRatios = arguments.length > 3 ? arguments[3] : undefined;
5
9
  // Map to track which elements are already seen for each timestamp
6
10
  var seen = new Map();
7
11
  var result = [];
@@ -23,11 +27,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
23
27
  continue;
24
28
  }
25
29
  seenElements.add(element);
26
- result.push({
30
+ var lateMutation = {
27
31
  time: details.t,
28
32
  element: element,
29
33
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
30
- });
34
+ };
35
+ if (labelStacks && fg('platform_ufo_enable_late_mutation_label_stacks')) {
36
+ var labels = labelStacks[element];
37
+ if (labels) {
38
+ lateMutation.segment = labels.segment;
39
+ lateMutation.labelStack = labels.labelStack;
40
+ }
41
+ }
42
+ result.push(lateMutation);
31
43
  }
32
44
  } catch (err) {
33
45
  _iterator.e(err);
@@ -183,8 +183,9 @@ function createPostInteractionLogPayload(_ref2) {
183
183
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
184
184
  }
185
185
  var vcDetails = postInteractionFinishRevision.vcDetails;
186
+ var labelStacks = postInteractionFinishRevision.labelStacks;
186
187
  if (vcDetails) {
187
- lateMutations = getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
188
+ lateMutations = getLateMutations(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
188
189
  }
189
190
  }
190
191
  return {
@@ -1055,7 +1055,8 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
1055
1055
  trace: trace,
1056
1056
  vcObserver: vcObserver,
1057
1057
  hold3pActive: new Map(),
1058
- hold3pInfo: []
1058
+ hold3pInfo: [],
1059
+ minorInteractions: []
1059
1060
  };
1060
1061
  if (addFeatureFlagsToInteraction) {
1061
1062
  currentFeatureFlagsAccessed.clear();
@@ -5,12 +5,13 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
5
5
  import React, { lazy, Profiler, Suspense, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
6
6
  import { unstable_NormalPriority as NormalPriority, unstable_scheduleCallback as scheduleCallback } from 'scheduler';
7
7
  import { v4 as createUUID } from 'uuid';
8
+ import { fg } from '@atlaskit/platform-feature-flags';
8
9
  import coinflip from '../coinflip';
9
- import { getConfig, getInteractionRate } from '../config';
10
+ import { getConfig, getDoNotAbortActivePressInteraction, getInteractionRate, getMinorInteractions } from '../config';
10
11
  import { getActiveTrace, setInteractionActiveTrace } from '../experience-trace-id-context';
11
12
  import UFOInteractionContext from '../interaction-context';
12
13
  import UFOInteractionIDContext from '../interaction-id-context';
13
- import { abortByNewInteraction, addApdex as _addApdex, addCustomData as _addCustomData, addCustomTiming, addHold, addHoldByID, addMark as _addMark, addNewInteraction, addProfilerTimings, addRequestInfo, addSegment, addSpan, removeHoldByID, removeSegment, tryComplete } from '../interaction-metrics';
14
+ import { abortByNewInteraction, addApdex as _addApdex, addCustomData as _addCustomData, addCustomTiming, addHold, addHoldByID, addMark as _addMark, addNewInteraction, addProfilerTimings, addRequestInfo, addSegment, addSpan, getActiveInteraction, removeHoldByID, removeSegment, tryComplete } from '../interaction-metrics';
14
15
  import UFORouteName from '../route-name-context';
15
16
  import generateId from '../short-id';
16
17
  import scheduleOnPaint from './schedule-on-paint';
@@ -161,8 +162,24 @@ export default function UFOSegment(_ref) {
161
162
  tracePress: function tracePress() {
162
163
  var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'unknown';
163
164
  var timestamp = arguments.length > 1 ? arguments[1] : undefined;
164
- if (interactionId.current != null) {
165
- abortByNewInteraction(interactionId.current, name);
165
+ if (fg('platform_ufo_enable_minor_interactions')) {
166
+ var _getDoNotAbortActiveP, _getMinorInteractions;
167
+ var minorInteractions = [].concat(_toConsumableArray((_getDoNotAbortActiveP = getDoNotAbortActivePressInteraction()) !== null && _getDoNotAbortActiveP !== void 0 ? _getDoNotAbortActiveP : []), _toConsumableArray((_getMinorInteractions = getMinorInteractions()) !== null && _getMinorInteractions !== void 0 ? _getMinorInteractions : []));
168
+ if (minorInteractions.includes(name)) {
169
+ var _activeInteraction$mi;
170
+ var activeInteraction = getActiveInteraction();
171
+ activeInteraction === null || activeInteraction === void 0 || (_activeInteraction$mi = activeInteraction.minorInteractions) === null || _activeInteraction$mi === void 0 || _activeInteraction$mi.push({
172
+ name: name,
173
+ startTime: timestamp !== null && timestamp !== void 0 ? timestamp : performance.now()
174
+ });
175
+ return;
176
+ } else if (interactionId.current != null) {
177
+ abortByNewInteraction(interactionId.current, name);
178
+ }
179
+ } else {
180
+ if (interactionId.current != null) {
181
+ abortByNewInteraction(interactionId.current, name);
182
+ }
166
183
  }
167
184
  var rate = getInteractionRate(name, 'press');
168
185
  if (coinflip(rate)) {
@@ -0,0 +1,5 @@
1
+ import { default as internal_traceUFOInteraction } from '../trace-interaction/internal/trace-ufo-interaction';
2
+ function traceUFOHover(name, timestamp) {
3
+ return internal_traceUFOInteraction(name, 'hover', timestamp);
4
+ }
5
+ export default traceUFOHover;
@@ -1,6 +1,7 @@
1
1
  import { v4 as createUUID } from 'uuid';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import coinflip from '../../coinflip';
3
- import { getDoNotAbortActivePressInteraction, getInteractionRate } from '../../config';
4
+ import { getDoNotAbortActivePressInteraction, getInteractionRate, getMinorInteractions } from '../../config';
4
5
  import { getActiveTrace, setInteractionActiveTrace } from '../../experience-trace-id-context';
5
6
  import { DefaultInteractionID } from '../../interaction-id-context';
6
7
  import { abortAll, addNewInteraction, getActiveInteraction } from '../../interaction-metrics';
@@ -8,15 +9,31 @@ import UFORouteName from '../../route-name-context';
8
9
  function traceUFOInteraction(name, interactionType, startTime) {
9
10
  var rate = getInteractionRate(name, interactionType);
10
11
  var pressInteractionsList = getDoNotAbortActivePressInteraction();
11
- if (pressInteractionsList !== null && pressInteractionsList !== void 0 && pressInteractionsList.includes(name)) {
12
- var interaction = getActiveInteraction();
13
- if ((interaction === null || interaction === void 0 ? void 0 : interaction.ufoName) !== 'unknown' && (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
12
+ if (fg('platform_ufo_enable_minor_interactions')) {
13
+ var _getMinorInteractions;
14
+ var minorInteractions = (pressInteractionsList !== null && pressInteractionsList !== void 0 ? pressInteractionsList : []).concat((_getMinorInteractions = getMinorInteractions()) !== null && _getMinorInteractions !== void 0 ? _getMinorInteractions : []);
15
+ if (minorInteractions.includes(name)) {
16
+ var _activeInteraction$mi;
17
+ var activeInteraction = getActiveInteraction();
18
+ activeInteraction === null || activeInteraction === void 0 || (_activeInteraction$mi = activeInteraction.minorInteractions) === null || _activeInteraction$mi === void 0 || _activeInteraction$mi.push({
19
+ name: name,
20
+ startTime: startTime !== null && startTime !== void 0 ? startTime : performance.now()
21
+ });
14
22
  return;
23
+ } else {
24
+ abortAll('new_interaction', name);
15
25
  }
16
26
  } else {
17
- // Abort any existing interaction regardless of the coinflip outcome
18
- // Ensures measurements are not carried over between distinct interactions
19
- abortAll('new_interaction', name);
27
+ if (pressInteractionsList !== null && pressInteractionsList !== void 0 && pressInteractionsList.includes(name)) {
28
+ var interaction = getActiveInteraction();
29
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.ufoName) !== 'unknown' && (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
30
+ return;
31
+ }
32
+ } else {
33
+ // Abort any existing interaction regardless of the coinflip outcome
34
+ // Ensures measurements are not carried over between distinct interactions
35
+ abortAll('new_interaction', name);
36
+ }
20
37
  }
21
38
  if (coinflip(rate)) {
22
39
  var startTimestamp = startTime !== null && startTime !== void 0 ? startTime : performance.now();