@atlaskit/spotlight
Version:
A spotlight introduces users to points of interest, from focused messages to multi-step tours.
169 lines (165 loc) • 5.39 kB
JavaScript
/* legacy.tsx generated by @compiled/babel-plugin v3.0.2 */
import "./legacy.compiled.css";
import * as React from 'react';
import { ax, ix } from "@compiled/react/runtime";
import { useContext, useEffect, useLayoutEffect, useRef } from 'react';
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
import Motion from '@atlaskit/motion/entering/motion';
import { fg } from '@atlaskit/platform-feature-flags/fg';
import { Popper } from '@atlaskit/popper/main';
import { SpotlightContext } from '../../controllers/context';
import { useFocusWithin } from '../../utils/use-focus-within';
import { useOnClickOutside } from '../../utils/use-on-click-outside';
import { useOnEscape } from '../../utils/use-on-escape';
import { ConditionalExitingPersistence } from './conditional-exiting-persistence';
const styles = {
root: "_1pby1fw0"
};
/**
* Taken from `@atlaskit/popper`
*/
/**
* The `transform: rotate(45deg);` styles used to rotate the `Caret` component result in the corners of
* the caret extending beyond the bounding box (by roughly 2px). So, apply an offset to ensure
* the caret points to the very edge of the target element.
*
* Note: `@atlaskit/popper` maps the offset to the placement, so we only need to define `[0, 2]` and
* the offset will get correctly rotated depending on the placement.
*/
const defaultOffset = [0, 2];
/**
* The Spotlight card can be positioned in many different configurations, but the caret should always point to
* the center of the target element. `@atlaskit/popper` uses `'top' | 'right' | 'bottom' | 'left'` values for
* this center alignment along the respective face. So we translate between the Spotlight position, and the
* Popper position using this map.
*/
const popperPlacementMap = {
'top-start': 'top',
'top-center': 'top',
'top-end': 'top',
'bottom-start': 'bottom',
'bottom-center': 'bottom',
'bottom-end': 'bottom',
'right-start': 'right',
'right-end': 'right',
'left-start': 'left',
'left-end': 'left'
};
const DefaultMotion = ({
children
}) => /*#__PURE__*/React.createElement(Motion, {
enteringAnimation: "var(--ds-spotlight-enter, 250ms cubic-bezier(0.4, 0, 0, 1) ScaleIn95to100, 250ms cubic-bezier(0.4, 0, 0, 1) FadeIn0to100)",
exitingAnimation: "var(--ds-spotlight-exit, 200ms cubic-bezier(0.6, 0, 0.8, 0.6) ScaleOut100to95, 200ms cubic-bezier(0.6, 0, 0.8, 0.6) FadeOut100to0)"
}, children);
/**
* __PopoverContent__
*
* A `PopoverContent` is the element that is shown as a popover.
*/
export const PopoverContent = props => {
const {
children,
placement,
motion = DefaultMotion,
isVisible = true,
shouldDismissOnClickOutside = true,
dismiss,
back,
testId,
offset = defaultOffset,
strategy
} = props;
/**
* A user should only be able to pass a `done` or a `next`. Not both.
* The type is set up as a discriminant union. So, we need a typeguard
* here to destructure it properly.
*/
const done = 'done' in props ? props.done : undefined;
const next = 'next' in props ? props.next : undefined;
const updateRef = useRef(() => new Promise(() => undefined));
const ref = useRef(null);
const {
heading,
popoverContent,
card,
primaryAction,
secondaryAction
} = useContext(SpotlightContext);
const focusWithin = useFocusWithin(popoverContent.ref);
useEffect(() => {
popoverContent.setRef(ref);
}, [ref, popoverContent]);
useEffect(() => {
if (!done && !next) {
return;
}
if (done) {
primaryAction.setAction(done);
return;
} else if (next) {
primaryAction.setAction(next);
return;
}
}, [done, next, primaryAction]);
useEffect(() => {
popoverContent.setDismiss(dismiss);
}, [dismiss, popoverContent]);
useEffect(() => {
if (!back) {
return;
}
secondaryAction.setAction(back);
}, [back, secondaryAction]);
useLayoutEffect(() => {
card.setPlacement(placement);
if (motion) {
card.setMotion(() => motion);
}
}, [placement, card, motion]);
useEffect(() => {
if (updateRef.current) {
popoverContent.setUpdate(() => updateRef.current);
}
}, [popoverContent]);
useOnEscape(event => {
if (!focusWithin) {
return;
}
popoverContent.dismiss.current(event);
});
useOnClickOutside(event => {
if (!shouldDismissOnClickOutside) {
return;
}
popoverContent.dismiss.current(event);
});
return /*#__PURE__*/React.createElement(Popper, {
offset: offset,
strategy: strategy,
placement: popperPlacementMap[placement]
}, ({
ref: localRef,
style,
update
}) => {
if (!isVisible && !fg('platform-dst-motion-uplift-spotlight')) {
return;
}
updateRef.current = update;
return fg('platform-dst-motion-uplift-spotlight') ? /*#__PURE__*/React.createElement(ConditionalExitingPersistence, null, isVisible && /*#__PURE__*/React.createElement("div", {
role: "dialog",
"data-testid": testId,
"aria-labelledby": heading.id,
ref: mergeRefs([ref, localRef]),
style: style,
className: ax([styles.root])
}, children)) : /*#__PURE__*/React.createElement("div", {
role: "dialog",
"data-testid": testId,
"aria-labelledby": heading.id,
ref: mergeRefs([ref, localRef]),
style: style,
className: ax([styles.root])
}, children);
});
};