UNPKG

@atlaskit/spotlight

Version:

A spotlight introduces users to points of interest, from focused messages to multi-step tours.

133 lines (131 loc) 4.53 kB
/* top-layer.tsx generated by @compiled/babel-plugin v3.0.2 */ import * as React from 'react'; import { ax, ix } from "@compiled/react/runtime"; import { useContext, useEffect, useLayoutEffect, useRef } from 'react'; import Motion from '@atlaskit/motion/entering/motion'; import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event'; import { Popover } from '@atlaskit/top-layer/popover/popover'; import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover'; import { useSimpleLightDismiss } from '@atlaskit/top-layer/use-simple-light-dismiss'; import { SpotlightContext } from '../../controllers/context'; import { usePositionArea } from '../../utils/use-position-area'; import { getPlacementWithOffset } from './get-placement-with-offset'; const noopUpdate = () => Promise.resolve(); 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 => { /** * This composes the low-level `@atlaskit/top-layer` `Popover` primitive directly * (rather than `@atlaskit/popup` or a higher-level wrapper) for two reasons: * * 1. Spotlight has bespoke positioning, dismiss, and motion requirements that * are coupled to the surrounding `SpotlightContext` (heading id, card * placement, primary/secondary actions, etc.). Building on the primitive * keeps that wiring local to spotlight without leaking into a shared popup. * 2. Spotlight's public API exposes a `dismiss(event)` callback that takes a * `KeyboardEvent` / `MouseEvent`, while the top-layer primitive surfaces a * structured `{ reason }`. Bridging that contract here (via * `createPopoverCloseEvent`) preserves backwards compatibility for existing * consumers as we migrate behind the `platform-dst-top-layer-spotlight` gate. */ const { children, placement, motion = DefaultMotion, isVisible = true, shouldDismissOnClickOutside = true, dismiss, back, testId, offset } = props; const done = 'done' in props ? props.done : undefined; const next = 'next' in props ? props.next : undefined; const popoverRef = useRef(null); const { heading, popoverContent, card, primaryAction, secondaryAction, target } = useContext(SpotlightContext); useAnchoredPopover({ anchorRef: target.ref, popoverRef, placement: getPlacementWithOffset({ placement, offset }), isOpen: isVisible }); useSimpleLightDismiss({ popoverRef, isOpen: isVisible, onClose: ({ reason }) => { if (reason === 'light-dismiss' && !shouldDismissOnClickOutside) { return; } // `createPopoverCloseEvent` is typed as `KeyboardEvent | MouseEvent | Event` // for forward-compatibility, but only `escape` / `light-dismiss` are // possible here, so the result is always a Keyboard/MouseEvent. dismiss(createPopoverCloseEvent({ reason })); } }); useEffect(() => { popoverContent.setRef(popoverRef); popoverContent.setUpdate(() => noopUpdate); }, [popoverContent]); const positionArea = usePositionArea(popoverRef); useEffect(() => { popoverContent.setPositionArea(positionArea); }, [popoverContent, positionArea]); 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]); return /*#__PURE__*/React.createElement(Popover, { ref: popoverRef, isOpen: isVisible, mode: "manual", role: "dialog", labelledBy: heading.id, testId: testId }, children); };