@atlaskit/react-ufo 3.12.4 → 3.13.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 (109) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/create-experimental-interaction-metrics-payload/index.js +2 -1
  3. package/dist/cjs/create-payload/utils/get-vc-metrics.js +2 -1
  4. package/dist/cjs/vc/index.js +4 -2
  5. package/dist/cjs/vc/vc-observer/getVCRevisionDebugDetails.js +41 -0
  6. package/dist/cjs/vc/vc-observer/index.js +63 -33
  7. package/dist/cjs/vc/vc-observer/observers/index.js +3 -2
  8. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +38 -12
  9. package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +9 -0
  10. package/dist/cjs/vc/vc-observer-new/index.js +13 -7
  11. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +211 -36
  12. package/dist/cjs/vc/vc-observer-new/metric-calculator/fy25_03/index.js +4 -4
  13. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +94 -4
  14. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/test-with-debug-info.js +108 -0
  15. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/index.js +16 -57
  16. package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +15 -5
  17. package/dist/cjs/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +3 -1
  18. package/dist/es2019/create-experimental-interaction-metrics-payload/index.js +2 -1
  19. package/dist/es2019/create-payload/utils/get-vc-metrics.js +1 -0
  20. package/dist/es2019/vc/index.js +4 -2
  21. package/dist/es2019/vc/vc-observer/getVCRevisionDebugDetails.js +32 -0
  22. package/dist/es2019/vc/vc-observer/index.js +36 -1
  23. package/dist/es2019/vc/vc-observer/observers/index.js +2 -1
  24. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +38 -13
  25. package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +9 -1
  26. package/dist/es2019/vc/vc-observer-new/index.js +12 -6
  27. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +115 -17
  28. package/dist/es2019/vc/vc-observer-new/metric-calculator/fy25_03/index.js +4 -4
  29. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +44 -1
  30. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/test-with-debug-info.js +75 -0
  31. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/index.js +2 -20
  32. package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +15 -5
  33. package/dist/es2019/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +3 -1
  34. package/dist/esm/create-experimental-interaction-metrics-payload/index.js +2 -1
  35. package/dist/esm/create-payload/utils/get-vc-metrics.js +2 -1
  36. package/dist/esm/vc/index.js +4 -2
  37. package/dist/esm/vc/vc-observer/getVCRevisionDebugDetails.js +35 -0
  38. package/dist/esm/vc/vc-observer/index.js +63 -33
  39. package/dist/esm/vc/vc-observer/observers/index.js +3 -2
  40. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +38 -12
  41. package/dist/esm/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.js +9 -0
  42. package/dist/esm/vc/vc-observer-new/index.js +13 -7
  43. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +211 -36
  44. package/dist/esm/vc/vc-observer-new/metric-calculator/fy25_03/index.js +4 -4
  45. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.js +94 -5
  46. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/test-with-debug-info.js +106 -0
  47. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/index.js +2 -55
  48. package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +15 -5
  49. package/dist/esm/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +3 -1
  50. package/dist/types/config/index.d.ts +1 -0
  51. package/dist/types/vc/types.d.ts +2 -0
  52. package/dist/types/vc/vc-observer/getVCRevisionDebugDetails.d.ts +30 -0
  53. package/dist/types/vc/vc-observer/index.d.ts +1 -1
  54. package/dist/types/vc/vc-observer/observers/index.d.ts +3 -0
  55. package/dist/types/vc/vc-observer/observers/ssr-placeholders/index.d.ts +4 -1
  56. package/dist/types/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.d.ts +1 -1
  57. package/dist/types/vc/vc-observer-new/index.d.ts +2 -0
  58. package/dist/types/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +4 -1
  59. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +5 -1
  60. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/test-with-debug-info.d.ts +1 -0
  61. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/index.d.ts +2 -4
  62. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +20 -2
  63. package/dist/types/vc/vc-observer-new/metric-calculator/types.d.ts +2 -0
  64. package/dist/types/vc/vc-observer-new/types.d.ts +5 -1
  65. package/dist/types/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
  66. package/dist/types/vc/vc-observer-new/viewport-observer/types.d.ts +2 -0
  67. package/dist/types-ts4.5/config/index.d.ts +1 -0
  68. package/dist/types-ts4.5/vc/types.d.ts +2 -0
  69. package/dist/types-ts4.5/vc/vc-observer/getVCRevisionDebugDetails.d.ts +30 -0
  70. package/dist/types-ts4.5/vc/vc-observer/index.d.ts +1 -1
  71. package/dist/types-ts4.5/vc/vc-observer/observers/index.d.ts +3 -0
  72. package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/index.d.ts +4 -1
  73. package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/ssr-scripts/collectSSRPlaceholderDimensions.d.ts +1 -1
  74. package/dist/types-ts4.5/vc/vc-observer-new/index.d.ts +2 -0
  75. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +4 -1
  76. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/index.d.ts +5 -1
  77. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/canvas-heatmap/test-with-debug-info.d.ts +1 -0
  78. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/index.d.ts +2 -4
  79. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/types.d.ts +20 -2
  80. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/types.d.ts +2 -0
  81. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +5 -1
  82. package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
  83. package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/types.d.ts +2 -0
  84. package/package.json +4 -1
  85. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/heatmap.js +0 -367
  86. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +0 -398
  87. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/types.js +0 -5
  88. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/calc-union-area.js +0 -152
  89. package/dist/cjs/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +0 -108
  90. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/heatmap.js +0 -248
  91. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +0 -263
  92. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/types.js +0 -1
  93. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/calc-union-area.js +0 -99
  94. package/dist/es2019/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +0 -60
  95. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/heatmap.js +0 -361
  96. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.js +0 -391
  97. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/types.js +0 -1
  98. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/calc-union-area.js +0 -145
  99. package/dist/esm/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.js +0 -101
  100. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/heatmap.d.ts +0 -39
  101. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.d.ts +0 -10
  102. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/types.d.ts +0 -43
  103. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/calc-union-area.d.ts +0 -12
  104. package/dist/types/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.d.ts +0 -25
  105. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/heatmap.d.ts +0 -39
  106. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/index.d.ts +0 -10
  107. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/heatmap/types.d.ts +0 -43
  108. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/calc-union-area.d.ts +0 -12
  109. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/percentile-calc/rect-sweeping-line/index.d.ts +0 -25
@@ -123,7 +123,9 @@ var ViewportObserver = exports.default = /*#__PURE__*/function () {
123
123
  (0, _defineProperty2.default)(this, "handleAttributeMutation", function (_ref5) {
124
124
  var _this$intersectionObs4;
125
125
  var target = _ref5.target,
126
- attributeName = _ref5.attributeName;
126
+ attributeName = _ref5.attributeName,
127
+ oldValue = _ref5.oldValue,
128
+ newValue = _ref5.newValue;
127
129
  (_this$intersectionObs4 = _this.intersectionObserver) === null || _this$intersectionObs4 === void 0 || _this$intersectionObs4.watchAndTag(target, function (_ref6) {
128
130
  var target = _ref6.target,
129
131
  rect = _ref6.rect;
@@ -131,7 +133,9 @@ var ViewportObserver = exports.default = /*#__PURE__*/function () {
131
133
  return {
132
134
  type: 'mutation:media',
133
135
  mutationData: {
134
- attributeName: attributeName
136
+ attributeName: attributeName,
137
+ oldValue: oldValue,
138
+ newValue: newValue
135
139
  }
136
140
  };
137
141
  }
@@ -143,7 +147,9 @@ var ViewportObserver = exports.default = /*#__PURE__*/function () {
143
147
  return {
144
148
  type: 'mutation:attribute:non-visual-style',
145
149
  mutationData: {
146
- attributeName: attributeName
150
+ attributeName: attributeName,
151
+ oldValue: oldValue,
152
+ newValue: newValue
147
153
  }
148
154
  };
149
155
  }
@@ -152,14 +158,18 @@ var ViewportObserver = exports.default = /*#__PURE__*/function () {
152
158
  return {
153
159
  type: 'mutation:attribute:no-layout-shift',
154
160
  mutationData: {
155
- attributeName: attributeName
161
+ attributeName: attributeName,
162
+ oldValue: oldValue,
163
+ newValue: newValue
156
164
  }
157
165
  };
158
166
  }
159
167
  return {
160
168
  type: 'mutation:attribute',
161
169
  mutationData: {
162
- attributeName: attributeName
170
+ attributeName: attributeName,
171
+ oldValue: oldValue,
172
+ newValue: newValue
163
173
  }
164
174
  };
165
175
  });
@@ -42,7 +42,9 @@ function createMutationObserver(_ref) {
42
42
  var _mut$attributeName;
43
43
  onAttributeMutation({
44
44
  target: mut.target,
45
- attributeName: (_mut$attributeName = mut.attributeName) !== null && _mut$attributeName !== void 0 ? _mut$attributeName : 'unknown'
45
+ attributeName: (_mut$attributeName = mut.attributeName) !== null && _mut$attributeName !== void 0 ? _mut$attributeName : 'unknown',
46
+ oldValue: oldValue,
47
+ newValue: newValue
46
48
  });
47
49
  }
48
50
  continue;
@@ -68,7 +68,8 @@ export async function getExperimentalVCMetrics(interaction) {
68
68
  isEventAborted: !!interaction.abortReason,
69
69
  prefix,
70
70
  vc: interaction.vc,
71
- experienceKey: interaction.ufoName
71
+ experienceKey: interaction.ufoName,
72
+ interactionId: interaction.id
72
73
  });
73
74
  const VC = result === null || result === void 0 ? void 0 : result['metrics:vc'];
74
75
  if (!VC || !(result !== null && result !== void 0 && result[`${prefix}:vc:clean`])) {
@@ -36,6 +36,7 @@ async function getVCMetrics(interaction) {
36
36
  vc: interaction.vc,
37
37
  isEventAborted: interactionStatus.originalInteractionStatus !== 'SUCCEEDED',
38
38
  experienceKey: interaction.ufoName,
39
+ interactionId: interaction.id,
39
40
  ...ssr
40
41
  });
41
42
  if ((_config$experimentalI = config.experimentalInteractionMetrics) !== null && _config$experimentalI !== void 0 && _config$experimentalI.enabled) {
@@ -82,7 +82,8 @@ export class VCObserverWrapper {
82
82
  const v1v2Result = isVCRevisionEnabled('fy25.01', experienceKey) || isVCRevisionEnabled('fy25.02', experienceKey) ? await ((_this$oldVCObserver6 = this.oldVCObserver) === null || _this$oldVCObserver6 === void 0 ? void 0 : _this$oldVCObserver6.getVCResult(param)) : {};
83
83
  const v3Result = isVCRevisionEnabled('fy25.03', experienceKey) ? await ((_this$newVCObserver5 = this.newVCObserver) === null || _this$newVCObserver5 === void 0 ? void 0 : _this$newVCObserver5.getVCResult({
84
84
  start: param.start,
85
- stop: param.stop
85
+ stop: param.stop,
86
+ interactionId: param.interactionId
86
87
  })) : [];
87
88
  if (!v3Result) {
88
89
  return v1v2Result !== null && v1v2Result !== void 0 ? v1v2Result : {};
@@ -96,7 +97,8 @@ export class VCObserverWrapper {
96
97
  const oldResult = await ((_this$oldVCObserver7 = this.oldVCObserver) === null || _this$oldVCObserver7 === void 0 ? void 0 : _this$oldVCObserver7.getVCResult(param));
97
98
  const newResult = await ((_this$newVCObserver6 = this.newVCObserver) === null || _this$newVCObserver6 === void 0 ? void 0 : _this$newVCObserver6.getVCResult({
98
99
  start: param.start,
99
- stop: param.stop
100
+ stop: param.stop,
101
+ interactionId: param.interactionId
100
102
  }));
101
103
  if (oldResult && !newResult) {
102
104
  return oldResult;
@@ -0,0 +1,32 @@
1
+ export function getVCRevisionDebugDetails({
2
+ revision,
3
+ isClean,
4
+ abortReason,
5
+ VCEntries,
6
+ componentsLog,
7
+ interactionId
8
+ }) {
9
+ return {
10
+ revision,
11
+ isClean,
12
+ abortReason,
13
+ vcLogs: VCEntries.map(entry => ({
14
+ time: entry.time,
15
+ viewportPercentage: entry.vc,
16
+ entries: entry.elements.map(element => {
17
+ var _componentsLog$entry$;
18
+ const logEntry = (_componentsLog$entry$ = componentsLog[entry.time]) === null || _componentsLog$entry$ === void 0 ? void 0 : _componentsLog$entry$.find(log => log.targetName === element);
19
+ return {
20
+ elementName: element,
21
+ type: logEntry === null || logEntry === void 0 ? void 0 : logEntry.type,
22
+ rect: logEntry === null || logEntry === void 0 ? void 0 : logEntry.intersectionRect,
23
+ visible: true,
24
+ attributeName: logEntry === null || logEntry === void 0 ? void 0 : logEntry.attributeName,
25
+ oldValue: logEntry === null || logEntry === void 0 ? void 0 : logEntry.oldValue,
26
+ newValue: logEntry === null || logEntry === void 0 ? void 0 : logEntry.newValue
27
+ };
28
+ })
29
+ })),
30
+ interactionId
31
+ };
32
+ }
@@ -3,6 +3,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
3
3
  import { isVCRevisionEnabled } from '../../config';
4
4
  import { getActiveInteraction } from '../../interaction-metrics';
5
5
  import { attachAbortListeners } from './attachAbortListeners';
6
+ import { getVCRevisionDebugDetails } from './getVCRevisionDebugDetails';
6
7
  import { getVCRevisionsData } from './getVCRevisionsData';
7
8
  import { getViewportHeight, getViewportWidth } from './getViewport';
8
9
  import { MultiRevisionHeatmap } from './heatmap/heatmap';
@@ -96,7 +97,8 @@ export class VCObserver {
96
97
  ssr,
97
98
  vc,
98
99
  isEventAborted,
99
- experienceKey
100
+ experienceKey,
101
+ interactionId
100
102
  }) => {
101
103
  const startTime = performance.now();
102
104
  // add local measurement
@@ -298,6 +300,33 @@ export class VCObserver {
298
300
  entries: isTTVCv1Disabled ? vcNext.VCEntries.rel : VCEntries.rel
299
301
  }
300
302
  }));
303
+
304
+ // Add devtool callback for both v1 and v2
305
+ if (typeof window.__ufo_devtool_onVCRevisionReady__ === 'function' && fg('platform_ufo_ttvc_v3_devtool')) {
306
+ var _ufo_devtool_onVCRev2, _ref2;
307
+ // Handle v1 if not disabled
308
+ if (!isTTVCv1Disabled) {
309
+ var _ufo_devtool_onVCRev, _ref;
310
+ (_ufo_devtool_onVCRev = (_ref = window).__ufo_devtool_onVCRevisionReady__) === null || _ufo_devtool_onVCRev === void 0 ? void 0 : _ufo_devtool_onVCRev.call(_ref, getVCRevisionDebugDetails({
311
+ revision: 'fy25.01',
312
+ isClean: !abortReasonInfo,
313
+ abortReason: abortReason.reason,
314
+ VCEntries: VCEntries.rel,
315
+ componentsLog,
316
+ interactionId
317
+ }));
318
+ }
319
+
320
+ // Handle v2
321
+ (_ufo_devtool_onVCRev2 = (_ref2 = window).__ufo_devtool_onVCRevisionReady__) === null || _ufo_devtool_onVCRev2 === void 0 ? void 0 : _ufo_devtool_onVCRev2.call(_ref2, getVCRevisionDebugDetails({
322
+ revision: 'fy25.02',
323
+ isClean: !abortReasonInfo,
324
+ abortReason: abortReason.reason,
325
+ VCEntries: vcNext.VCEntries.rel,
326
+ componentsLog,
327
+ interactionId
328
+ }));
329
+ }
301
330
  }
302
331
  } catch (e) {
303
332
  /* do nothing */
@@ -525,6 +554,9 @@ export class VCObserver {
525
554
  this.arraySize = options.heatmapSize || 200;
526
555
  this.devToolsEnabled = options.devToolsEnabled || false;
527
556
  this.oldDomUpdatesEnabled = options.oldDomUpdates || false;
557
+ const {
558
+ ssrEnablePageLayoutPlaceholder
559
+ } = options;
528
560
  this.observers = new Observers({
529
561
  selectorConfig: options.selectorConfig || {
530
562
  id: false,
@@ -532,6 +564,9 @@ export class VCObserver {
532
564
  role: false,
533
565
  className: true,
534
566
  dataVC: true
567
+ },
568
+ SSRConfig: {
569
+ enablePageLayoutPlaceholder: ssrEnablePageLayoutPlaceholder || false
535
570
  }
536
571
  });
537
572
  this.heatmap = !isVCRevisionEnabled('fy25.01') ? [] : this.getCleanHeatmap();
@@ -20,6 +20,7 @@ function isElementVisible(target) {
20
20
  }
21
21
  export class Observers {
22
22
  constructor(opts) {
23
+ var _opts$SSRConfig;
23
24
  _defineProperty(this, "observedMutations", new WeakMap());
24
25
  _defineProperty(this, "elementsInView", new Set());
25
26
  _defineProperty(this, "callbacks", new Set());
@@ -59,7 +60,7 @@ export class Observers {
59
60
  };
60
61
  this.intersectionObserver = this.getIntersectionObserver();
61
62
  this.mutationObserver = this.getMutationObserver();
62
- this.ssrPlaceholderHandler = new SSRPlaceholderHandlers();
63
+ this.ssrPlaceholderHandler = new SSRPlaceholderHandlers((_opts$SSRConfig = opts.SSRConfig) === null || _opts$SSRConfig === void 0 ? void 0 : _opts$SSRConfig.enablePageLayoutPlaceholder);
63
64
  }
64
65
  isBrowserSupported() {
65
66
  return typeof window.IntersectionObserver === 'function' && typeof window.MutationObserver === 'function';
@@ -1,12 +1,35 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  const ANCESTOR_LOOKUP_LIMIT = 10;
3
+ const PAGE_LAYOUT_ID = 'page-layout.root';
3
4
  export class SSRPlaceholderHandlers {
4
- constructor() {
5
+ constructor(enablePageLayoutPlaceholder = false) {
5
6
  _defineProperty(this, "staticPlaceholders", new Map());
6
7
  _defineProperty(this, "callbacks", new Map());
7
8
  _defineProperty(this, "getSizeCallbacks", new Map());
8
9
  _defineProperty(this, "reactValidateCallbacks", new Map());
9
10
  _defineProperty(this, "EQUALITY_THRESHOLD", 1);
11
+ _defineProperty(this, "getPlaceholderId", el => {
12
+ var _el$dataset;
13
+ const ssrPlaceholderId = el === null || el === void 0 ? void 0 : (_el$dataset = el.dataset) === null || _el$dataset === void 0 ? void 0 : _el$dataset.ssrPlaceholder;
14
+ if (!!ssrPlaceholderId) {
15
+ return ssrPlaceholderId;
16
+ }
17
+ if (this.enablePageLayoutPlaceholder && (el === null || el === void 0 ? void 0 : el.dataset.testid) === PAGE_LAYOUT_ID) {
18
+ return PAGE_LAYOUT_ID;
19
+ }
20
+ return '';
21
+ });
22
+ _defineProperty(this, "getPlaceholderReplacementId", el => {
23
+ var _el$dataset2;
24
+ const ssrPlaceholderReplaceId = el === null || el === void 0 ? void 0 : (_el$dataset2 = el.dataset) === null || _el$dataset2 === void 0 ? void 0 : _el$dataset2.ssrPlaceholderReplace;
25
+ if (!!ssrPlaceholderReplaceId) {
26
+ return ssrPlaceholderReplaceId;
27
+ }
28
+ if (this.enablePageLayoutPlaceholder && (el === null || el === void 0 ? void 0 : el.dataset.testid) === PAGE_LAYOUT_ID) {
29
+ return PAGE_LAYOUT_ID;
30
+ }
31
+ return '';
32
+ });
10
33
  _defineProperty(this, "intersectionObserverCallback", ({
11
34
  target,
12
35
  boundingClientRect
@@ -17,7 +40,7 @@ export class SSRPlaceholderHandlers {
17
40
  // impossible case - keep typescript healthy
18
41
  return;
19
42
  }
20
- const staticKey = target.dataset.ssrPlaceholder || '';
43
+ const staticKey = this.getPlaceholderId(target);
21
44
  if (staticKey) {
22
45
  if (this.staticPlaceholders.has(staticKey) && this.callbacks.has(staticKey)) {
23
46
  // validation
@@ -39,7 +62,7 @@ export class SSRPlaceholderHandlers {
39
62
  this.callbacks.delete(staticKey);
40
63
  }
41
64
  } else {
42
- const key = target.dataset.ssrPlaceholderReplace || '';
65
+ const key = this.getPlaceholderReplacementId(target);
43
66
  const resolve = this.reactValidateCallbacks.get(key);
44
67
  if (!resolve) {
45
68
  return;
@@ -63,25 +86,27 @@ export class SSRPlaceholderHandlers {
63
86
  // Only instantiate the IntersectionObserver if it's supported
64
87
  this.intersectionObserver = new IntersectionObserver(entries => entries.filter(entry => entry.intersectionRatio > 0).forEach(this.intersectionObserverCallback));
65
88
  }
89
+ this.enablePageLayoutPlaceholder = enablePageLayoutPlaceholder;
66
90
  if (window.document) {
67
91
  try {
68
- const existingElements = document.querySelectorAll('[data-ssr-placeholder]');
92
+ const selector = this.enablePageLayoutPlaceholder ? '[data-ssr-placeholder],[data-testid="page-layout.root"]' : '[data-ssr-placeholder]';
93
+ const existingElements = document.querySelectorAll(selector);
69
94
  existingElements.forEach(el => {
70
- var _el$dataset;
71
- if (el instanceof HTMLElement && el !== null && el !== void 0 && (_el$dataset = el.dataset) !== null && _el$dataset !== void 0 && _el$dataset.ssrPlaceholder) {
95
+ const placeholderId = el instanceof HTMLElement && this.getPlaceholderId(el);
96
+ if (placeholderId) {
72
97
  var _window$__SSR_PLACEHO, _this$intersectionObs2;
73
98
  let width = -1;
74
99
  let height = -1;
75
100
  let x = -1;
76
101
  let y = -1;
77
- const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[el.dataset.ssrPlaceholder];
102
+ const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[placeholderId];
78
103
  if (boundingClientRect) {
79
104
  width = boundingClientRect.width;
80
105
  height = boundingClientRect.height;
81
106
  x = boundingClientRect.x;
82
107
  y = boundingClientRect.y;
83
108
  }
84
- this.staticPlaceholders.set(el.dataset.ssrPlaceholder, {
109
+ this.staticPlaceholders.set(placeholderId, {
85
110
  width,
86
111
  height,
87
112
  x,
@@ -102,10 +127,10 @@ export class SSRPlaceholderHandlers {
102
127
  this.reactValidateCallbacks = new Map();
103
128
  }
104
129
  isPlaceholder(element) {
105
- return Boolean(element.dataset.ssrPlaceholder);
130
+ return Boolean(this.getPlaceholderId(element));
106
131
  }
107
132
  isPlaceholderReplacement(element) {
108
- return Boolean(element.dataset.ssrPlaceholderReplace);
133
+ return Boolean(this.getPlaceholderReplacementId(element));
109
134
  }
110
135
  isPlaceholderIgnored(element) {
111
136
  // data-ssr-placeholder-ignored doesn't have a value.
@@ -128,7 +153,7 @@ export class SSRPlaceholderHandlers {
128
153
  }
129
154
  checkIfExistedAndSizeMatching(el) {
130
155
  el = this.findNearestPlaceholderContainerIfIgnored(el);
131
- const id = el.dataset.ssrPlaceholder || '';
156
+ const id = this.getPlaceholderId(el);
132
157
  return new Promise(resolve => {
133
158
  if (!this.staticPlaceholders.has(id)) {
134
159
  resolve(false);
@@ -143,13 +168,13 @@ export class SSRPlaceholderHandlers {
143
168
  getSize(el) {
144
169
  return new Promise(resolve => {
145
170
  var _this$intersectionObs4;
146
- this.getSizeCallbacks.set(el.dataset.ssrPlaceholder || '', resolve);
171
+ this.getSizeCallbacks.set(this.getPlaceholderId(el), resolve);
147
172
  (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.observe(el);
148
173
  });
149
174
  }
150
175
  validateReactComponentMatchToPlaceholder(el) {
151
176
  el = this.findNearestPlaceholderContainerIfIgnored(el);
152
- const id = el.dataset.ssrPlaceholderReplace || '';
177
+ const id = this.getPlaceholderReplacementId(el);
153
178
  return new Promise(resolve => {
154
179
  if (!this.staticPlaceholders.has(id)) {
155
180
  resolve(false);
@@ -1,7 +1,7 @@
1
1
  // lightweight script to scan the SSR response and collect all elements with data-ssr-placeholder attribute
2
2
  // and save their size/positions in a map __SSR_PLACEHOLDERS_DIMENSIONS__ on the Window object. Each placeholderId is
3
3
  // unique and maps to its corresponding elements bounding client rectangle dimensions.
4
- export function collectSSRPlaceholderDimensions(document, window) {
4
+ export function collectSSRPlaceholderDimensions(document, window, enablePageLayoutPlaceholder = false) {
5
5
  const ssrPlaceholders = document === null || document === void 0 ? void 0 : document.querySelectorAll('[data-ssr-placeholder]');
6
6
  ssrPlaceholders.forEach(elem => {
7
7
  const placeholderId = elem.getAttribute('data-ssr-placeholder');
@@ -11,4 +11,12 @@ export function collectSSRPlaceholderDimensions(document, window) {
11
11
  window.__SSR_PLACEHOLDERS_DIMENSIONS__[placeholderId] = boundingClient;
12
12
  }
13
13
  });
14
+ if (enablePageLayoutPlaceholder) {
15
+ const pageLayoutRoot = document === null || document === void 0 ? void 0 : document.getElementById('unsafe-design-system-page-layout-root');
16
+ if (pageLayoutRoot) {
17
+ const boundingClient = pageLayoutRoot.getBoundingClientRect();
18
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__ = window.__SSR_PLACEHOLDERS_DIMENSIONS__ || {};
19
+ window.__SSR_PLACEHOLDERS_DIMENSIONS__['page-layout.root'] = boundingClient;
20
+ }
21
+ }
14
22
  }
@@ -13,10 +13,11 @@ const DEFAULT_SELECTOR_CONFIG = {
13
13
  };
14
14
  export default class VCObserverNew {
15
15
  constructor(config) {
16
- var _config$selectorConfi;
16
+ var _config$isPostInterac, _config$selectorConfi;
17
17
  _defineProperty(this, "viewportObserver", null);
18
18
  _defineProperty(this, "windowEventObserver", null);
19
19
  this.entriesTimeline = new EntriesTimeline();
20
+ this.isPostInteraction = (_config$isPostInterac = config.isPostInteraction) !== null && _config$isPostInterac !== void 0 ? _config$isPostInterac : false;
20
21
  this.selectorConfig = (_config$selectorConfi = config.selectorConfig) !== null && _config$selectorConfi !== void 0 ? _config$selectorConfi : DEFAULT_SELECTOR_CONFIG;
21
22
  this.viewportObserver = new ViewportObserver({
22
23
  onChange: onChangeArg => {
@@ -36,13 +37,15 @@ export default class VCObserverNew {
36
37
  }
37
38
  this.entriesTimeline.push({
38
39
  time,
39
- type,
40
40
  data: {
41
+ type,
41
42
  elementName,
42
43
  rect,
43
44
  previousRect,
44
45
  visible,
45
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName
46
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
47
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
48
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
46
49
  }
47
50
  });
48
51
  }
@@ -54,8 +57,8 @@ export default class VCObserverNew {
54
57
  }) => {
55
58
  this.entriesTimeline.push({
56
59
  time,
57
- type: 'window:event',
58
60
  data: {
61
+ type: 'window:event',
59
62
  eventType: type
60
63
  }
61
64
  });
@@ -78,7 +81,8 @@ export default class VCObserverNew {
78
81
  async getVCResult(param) {
79
82
  const {
80
83
  start,
81
- stop
84
+ stop,
85
+ interactionId
82
86
  } = param;
83
87
  const results = [];
84
88
  const calculator_fy25_03 = new VCCalculator_FY25_03();
@@ -89,7 +93,9 @@ export default class VCObserverNew {
89
93
  const fy25_03 = await calculator_fy25_03.calculate({
90
94
  orderedEntries,
91
95
  startTime: start,
92
- stopTime: stop
96
+ stopTime: stop,
97
+ interactionId,
98
+ isPostInteraction: this.isPostInteraction
93
99
  });
94
100
  if (fy25_03) {
95
101
  results.push(fy25_03);
@@ -1,25 +1,131 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
- import calculateTTVCPercentiles from './percentile-calc';
2
+ import { calculateTTVCPercentiles, calculateTTVCPercentilesWithDebugInfo } from './percentile-calc';
3
3
  import getViewportHeight from './utils/get-viewport-height';
4
4
  import getViewportWidth from './utils/get-viewport-width';
5
5
  export default class AbstractVCCalculatorBase {
6
6
  constructor(revisionNo) {
7
7
  this.revisionNo = revisionNo;
8
8
  }
9
+ filterViewportEntries(entries) {
10
+ return entries.filter(entry => {
11
+ return 'rect' in entry.data;
12
+ });
13
+ }
14
+ async calculateBasic(filteredEntries, startTime, stopTime) {
15
+ const percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99];
16
+ const viewportEntries = this.filterViewportEntries(filteredEntries);
17
+ const vcLogs = await calculateTTVCPercentiles({
18
+ viewport: {
19
+ width: getViewportWidth(),
20
+ height: getViewportHeight()
21
+ },
22
+ startTime,
23
+ stopTime,
24
+ orderedEntries: viewportEntries,
25
+ percentiles
26
+ });
27
+ return vcLogs;
28
+ }
29
+ async calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason) {
30
+ const percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99];
31
+ const viewportEntries = this.filterViewportEntries(filteredEntries);
32
+ const vcLogs = await calculateTTVCPercentilesWithDebugInfo({
33
+ viewport: {
34
+ width: getViewportWidth(),
35
+ height: getViewportHeight()
36
+ },
37
+ startTime,
38
+ stopTime,
39
+ orderedEntries: viewportEntries
40
+ });
41
+ const vcDetails = {};
42
+ let percentileIndex = 0;
43
+ const entryDataBuffer = new Set();
44
+ if (vcLogs) {
45
+ for (const entry of vcLogs) {
46
+ const {
47
+ time,
48
+ viewportPercentage,
49
+ entries
50
+ } = entry;
51
+
52
+ // Only process entries if we haven't reached all percentiles
53
+ if (percentileIndex >= percentiles.length) {
54
+ break;
55
+ }
56
+
57
+ // Check if this entry matches any checkpoint percentiles
58
+ if (viewportPercentage >= percentiles[percentileIndex]) {
59
+ const elementNames = entries.map(e => e.elementName);
60
+
61
+ // Process all matching percentiles in one go
62
+ while (percentileIndex < percentiles.length && viewportPercentage >= percentiles[percentileIndex]) {
63
+ vcDetails[`${percentiles[percentileIndex]}`] = {
64
+ t: Math.round(time),
65
+ e: elementNames
66
+ };
67
+ percentileIndex++;
68
+ }
69
+
70
+ // Clear buffer after processing all matching percentiles
71
+ entryDataBuffer.clear();
72
+ } else {
73
+ // Only add to buffer if we haven't reached all percentiles
74
+ entries.forEach(e => entryDataBuffer.add(e));
75
+ }
76
+ }
77
+ }
78
+
79
+ // Fill in any missing percentiles with the last known values
80
+ let previousResult = {
81
+ t: 0,
82
+ e: []
83
+ };
84
+ for (let i = 0; i < percentiles.length; i++) {
85
+ const percentile = percentiles[i];
86
+ if (!(percentile in vcDetails)) {
87
+ vcDetails[`${percentile}`] = previousResult;
88
+ } else {
89
+ previousResult = vcDetails[`${percentile}`];
90
+ }
91
+ }
92
+
93
+ // Handle devtool callback
94
+ if (!isPostInteraction && typeof window !== 'undefined' && typeof window.__ufo_devtool_onVCRevisionReady__ === 'function' && fg('platform_ufo_ttvc_v3_devtool')) {
95
+ try {
96
+ var _ufo_devtool_onVCRev, _ref;
97
+ (_ufo_devtool_onVCRev = (_ref = window).__ufo_devtool_onVCRevisionReady__) === null || _ufo_devtool_onVCRev === void 0 ? void 0 : _ufo_devtool_onVCRev.call(_ref, {
98
+ revision: this.revisionNo,
99
+ isClean: isVCClean,
100
+ abortReason: dirtyReason,
101
+ vcLogs,
102
+ interactionId
103
+ });
104
+ } catch (e) {
105
+ // if any error communicating with devtool, we don't want to break the app
106
+ // eslint-disable-next-line no-console
107
+ console.error('Error in onVCRevisionReady', e);
108
+ }
109
+ }
110
+ return vcDetails;
111
+ }
9
112
  async calculate({
10
113
  startTime,
11
114
  stopTime,
12
- orderedEntries
115
+ orderedEntries,
116
+ interactionId,
117
+ isPostInteraction
13
118
  }) {
14
119
  var _vcDetails$90$t, _vcDetails$;
15
120
  const filteredEntries = orderedEntries.filter(entry => {
16
121
  return this.isEntryIncluded(entry);
17
122
  });
123
+ let isVCClean;
124
+ let dirtyReason;
18
125
  if (fg('platform_ufo_add_vc_abort_reason_by_revisions')) {
19
- const {
20
- isVCClean,
21
- dirtyReason
22
- } = this.getVCCleanStatus(filteredEntries);
126
+ const getVCCleanStatusResult = this.getVCCleanStatus(filteredEntries);
127
+ isVCClean = getVCCleanStatusResult.isVCClean;
128
+ dirtyReason = getVCCleanStatusResult.dirtyReason;
23
129
  if (!isVCClean) {
24
130
  return {
25
131
  revision: this.revisionNo,
@@ -29,7 +135,7 @@ export default class AbstractVCCalculatorBase {
29
135
  };
30
136
  }
31
137
  } else {
32
- const isVCClean = this.isVCClean(filteredEntries);
138
+ isVCClean = this.isVCClean(filteredEntries);
33
139
  if (!isVCClean) {
34
140
  return {
35
141
  revision: this.revisionNo,
@@ -38,16 +144,8 @@ export default class AbstractVCCalculatorBase {
38
144
  };
39
145
  }
40
146
  }
41
- const vcDetails = await calculateTTVCPercentiles({
42
- viewport: {
43
- width: getViewportWidth(),
44
- height: getViewportHeight()
45
- },
46
- startTime,
47
- stopTime,
48
- orderedEntries: filteredEntries,
49
- percentiles: [25, 50, 75, 80, 85, 90, 95, 98, 99]
50
- });
147
+ const useDebugInfo = fg('platform_ufo_ttvc_v3_devtool');
148
+ const vcDetails = useDebugInfo ? await this.calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason) : await this.calculateBasic(filteredEntries, startTime, stopTime);
51
149
  return {
52
150
  revision: this.revisionNo,
53
151
  clean: true,
@@ -13,10 +13,10 @@ export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
13
13
  super(REVISION_NO);
14
14
  }
15
15
  isEntryIncluded(entry) {
16
- if (!CONSIDERED_ENTRY_TYPE.includes(entry.type)) {
16
+ if (!CONSIDERED_ENTRY_TYPE.includes(entry.data.type)) {
17
17
  return false;
18
18
  }
19
- if (entry.type === 'mutation:attribute') {
19
+ if (entry.data.type === 'mutation:attribute') {
20
20
  const entryData = entry.data;
21
21
  const attributeName = entryData.attributeName;
22
22
  if (!attributeName || KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS.includes(attributeName)) {
@@ -31,7 +31,7 @@ export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
31
31
  }
32
32
  isVCClean(filteredEntries) {
33
33
  const hasAbortEvent = filteredEntries.some(entry => {
34
- if (entry.type === 'window:event') {
34
+ if (entry.data.type === 'window:event') {
35
35
  const data = entry.data;
36
36
  if (ABORTING_WINDOW_EVENT.includes(data.eventType)) {
37
37
  return true;
@@ -44,7 +44,7 @@ export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
44
44
  getVCCleanStatus(filteredEntries) {
45
45
  let dirtyReason = '';
46
46
  const hasAbortEvent = filteredEntries.some(entry => {
47
- if (entry.type === 'window:event') {
47
+ if (entry.data.type === 'window:event') {
48
48
  const data = entry.data;
49
49
  if (ABORTING_WINDOW_EVENT.includes(data.eventType)) {
50
50
  dirtyReason = data.eventType === 'keydown' ? 'keypress' : data.eventType;