@awsui/components-react
Version:
On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en
157 lines (155 loc) • 7.45 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __awaiter } from "tslib";
import { useContext } from 'react';
import { nodeBelongs } from '../../utils/node-belongs';
import { FunnelMetrics } from '../';
import { FunnelContext, FunnelNameSelectorContext, FunnelStepContext, FunnelSubStepContext, } from '../context/analytics-context';
import { DATA_ATTR_FUNNEL_INTERACTION_ID, DATA_ATTR_FUNNEL_SUBSTEP, getSubStepAllSelector, getTextFromSelector, } from '../selectors';
/**
* Custom React Hook to manage and interact with FunnelSubStep.
* This hook will provide necessary properties and methods required
* to track and manage interactions with a FunnelSubStep component.
*
* The `onFocus` method is used to track the beginning of interaction with the FunnelSubStep.
* The `onBlur` method is used to track the completion of interaction with the FunnelSubStep.
* The subStepId is a unique identifier for the funnel sub-step.
* The subStepRef is a reference to the DOM element of the funnel sub-step.
*/
export const useFunnelSubStep = () => {
const context = useContext(FunnelSubStepContext);
const { funnelInteractionId, funnelIdentifier, funnelState, latestFocusCleanupFunction } = useFunnel();
const { stepNumber, stepIdentifier, stepNameSelector, subStepConfiguration } = useFunnelStep();
const { subStepIdentifier, subStepId, subStepSelector, subStepNameSelector, subStepRef, isNestedSubStep, mousePressed, isFocusedSubStep, focusCleanupFunction, } = context;
if (isNestedSubStep) {
return context;
}
const onFocus = (event) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c, _d;
const element = event.target;
// Ignore spurious focus events, such as when the browser window is focused again.
yield new Promise(r => setTimeout(r, 1));
if (document.activeElement !== element) {
return;
}
if (isFocusedSubStep.current) {
return;
}
isFocusedSubStep.current = true;
if (funnelInteractionId && subStepId) {
/*
If the previously focused substep has provided a cleanup function, we
call it here on behalf of the previously focused substep.
*/
(_a = latestFocusCleanupFunction.current) === null || _a === void 0 ? void 0 : _a.call(latestFocusCleanupFunction);
const subStepName = getTextFromSelector(subStepNameSelector);
const stepName = getTextFromSelector(stepNameSelector);
const subStepNumber = (_d = (_c = (_b = subStepConfiguration.current) === null || _b === void 0 ? void 0 : _b.get(stepNumber)) === null || _c === void 0 ? void 0 : _c.find(step => step.name === subStepName)) === null || _d === void 0 ? void 0 : _d.number;
FunnelMetrics.funnelSubStepStart({
funnelIdentifier,
funnelInteractionId,
subStepIdentifier,
subStepSelector,
subStepNameSelector,
subStepName,
subStepNumber,
stepIdentifier,
stepNumber,
stepName,
stepNameSelector,
subStepAllSelector: getSubStepAllSelector(),
});
/*
This cleanup function will be called when the user leaves this substep.
The function might be called either:
- by the next focused substep as `latestFocusCleanupFunction`
(through a separate instance of the function we're currently in), or
- by the same substep as `focusCleanupFunction`
(through the `onMouseUp` handler or the `onBlur` handler).
*/
let cleanupFunctionHasBeenRun = false;
focusCleanupFunction.current = () => {
var _a, _b, _c;
if (cleanupFunctionHasBeenRun) {
return;
}
cleanupFunctionHasBeenRun = true;
const subStepNumber = (_c = (_b = (_a = subStepConfiguration.current) === null || _a === void 0 ? void 0 : _a.get(stepNumber)) === null || _b === void 0 ? void 0 : _b.find(s => s.name === subStepName)) === null || _c === void 0 ? void 0 : _c.number;
if (funnelState.current !== 'cancelled') {
FunnelMetrics.funnelSubStepComplete({
funnelIdentifier,
funnelInteractionId,
subStepIdentifier,
subStepSelector,
subStepNameSelector,
subStepName,
subStepNumber,
stepIdentifier,
stepNumber,
stepName,
stepNameSelector,
subStepAllSelector: getSubStepAllSelector(),
});
}
};
latestFocusCleanupFunction.current = focusCleanupFunction.current;
}
});
const onBlur = (event) => {
var _a;
if (mousePressed.current) {
/*
Ignore blur events that are caused by mouse interaction, because these events don't
always reflect user intention. For example, clicking the label of an interactive form
element will briefly blur it.
The mouse-caused events are handled in the global `onMouseUp` handler of the substep
context instead.
*/
return;
}
if (!subStepRef.current || !event.relatedTarget || !nodeBelongs(subStepRef.current, event.relatedTarget)) {
isFocusedSubStep.current = false;
if (funnelInteractionId && subStepId && funnelState.current !== 'cancelled') {
/*
Run this substep's own focus cleanup function if another substep
hasn't already done it for us.
*/
(_a = focusCleanupFunction.current) === null || _a === void 0 ? void 0 : _a.call(focusCleanupFunction);
}
}
};
const funnelSubStepProps = funnelInteractionId
? {
[DATA_ATTR_FUNNEL_SUBSTEP]: subStepId,
onFocus,
onBlur,
}
: {};
return Object.assign({ funnelSubStepProps }, context);
};
/**
* Custom React Hook to manage and interact with FunnelStep.
* This hook will provide necessary properties required to track
* and manage interactions with a FunnelStep component.
*
* The 'data-analytics-funnel-step' property of funnelStepProps is used to track the index of the current step in the funnel.
* The context contains additional properties of the FunnelStep.
*/
export const useFunnelStep = () => {
const context = useContext(FunnelStepContext);
return context;
};
export const useFunnel = () => {
const context = useContext(FunnelContext);
const funnelProps = context.funnelInteractionId
? {
[DATA_ATTR_FUNNEL_INTERACTION_ID]: context.funnelInteractionId,
}
: {};
return Object.assign({ funnelProps }, context);
};
export const useFunnelNameSelector = () => {
const context = useContext(FunnelNameSelectorContext);
return context;
};
//# sourceMappingURL=use-funnel.js.map