-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathindex.ts
119 lines (98 loc) · 3.43 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { useEffect, useState } from 'react';
import { useModalContext } from '../../context/modal-context';
import { useDOMAttribute } from '../use-dom-attribute';
import { useEffectOnUpdate } from '../use-effect-on-update';
import { useRandomId } from '../use-unique-id';
import { isInViewport } from './is-in-viewport';
const EVALUATE_COMPONENT_VISIBILITY_EVENT = 'awsui-evaluate-component-visibility';
/**
* This hook manages a boolean state (`evaluateComponentVisibility`) that toggles
* whenever a custom DOM event (`EVALUATE_COMPONENT_VISIBILITY_EVENT`) is triggered.
*
* @returns
*/
const useEvaluateComponentVisibility = () => {
const [evaluateComponentVisibility, setEvaluateComponentVisibility] = useState(false);
useEffect(() => {
const handleEvaluateComponentVisibility = () => {
setEvaluateComponentVisibility(prev => !prev);
};
document.addEventListener(EVALUATE_COMPONENT_VISIBILITY_EVENT, handleEvaluateComponentVisibility);
return () => {
document.removeEventListener(EVALUATE_COMPONENT_VISIBILITY_EVENT, handleEvaluateComponentVisibility);
};
}, []);
return evaluateComponentVisibility;
};
/**
* This function returns an object that needs to be spread onto the same
* element as the `elementRef`, so that the data attribute is applied
* correctly.
*/
export function usePerformanceMarks(
name: string,
enabled: () => boolean,
elementRef: React.RefObject<HTMLElement>,
getDetails: () => Record<string, string | boolean | number | undefined>,
dependencies: React.DependencyList
) {
const id = useRandomId();
const { isInModal } = useModalContext();
const attributes = useDOMAttribute(elementRef, 'data-analytics-performance-mark', id);
const evaluateComponentVisibility = useEvaluateComponentVisibility();
useEffect(() => {
if (!enabled() || !elementRef.current || isInModal) {
return;
}
const elementVisible =
elementRef.current.offsetWidth > 0 &&
elementRef.current.offsetHeight > 0 &&
getComputedStyle(elementRef.current).visibility !== 'hidden';
if (!elementVisible) {
return;
}
const timestamp = performance.now();
const cleanup = isInViewport(elementRef.current, inViewport => {
performance.mark(`${name}Rendered`, {
startTime: timestamp,
detail: {
source: 'awsui',
instanceIdentifier: id,
inViewport,
...getDetails(),
},
});
});
return cleanup;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffectOnUpdate(() => {
if (!enabled() || !elementRef.current || isInModal) {
return;
}
const elementVisible =
elementRef.current.offsetWidth > 0 &&
elementRef.current.offsetHeight > 0 &&
getComputedStyle(elementRef.current).visibility !== 'hidden';
if (!elementVisible) {
return;
}
const timestamp = performance.now();
const cleanup = isInViewport(elementRef.current, inViewport => {
performance.mark(`${name}Updated`, {
startTime: timestamp,
detail: {
source: 'awsui',
instanceIdentifier: id,
inViewport,
...getDetails(),
},
});
});
return cleanup;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [evaluateComponentVisibility, ...dependencies]);
return attributes;
}