UNPKG

@atlaskit/flag

Version:

A flag is used for confirmations, alerts, and acknowledgments that require minimal user interaction, often displayed using a flag group.

243 lines (234 loc) 11.2 kB
/* flag-group.tsx generated by @compiled/babel-plugin v3.0.2 */ import _typeof from "@babel/runtime/helpers/typeof"; import "./flag-group.compiled.css"; import * as React from 'react'; import { ax, ix } from "@compiled/react/runtime"; import { Children, useEffect, useMemo, useRef } from 'react'; import { bind } from 'bind-event-listener'; import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents'; import { getDocument } from '@atlaskit/browser-apis'; import { cx } from '@atlaskit/css'; import noop from '@atlaskit/ds-lib/noop'; import ExitingPersistence from '@atlaskit/motion/exiting-persistence'; import SlideIn from '@atlaskit/motion/slide-in'; import Motion from '@atlaskit/motion/entering/motion'; import { fg } from '@atlaskit/platform-feature-flags/fg'; import Portal from '@atlaskit/portal/portal'; import { Box } from '@atlaskit/primitives/compiled'; import { layers } from '@atlaskit/theme/constants'; import { Popover } from '@atlaskit/top-layer/popover/popover'; import VisuallyHidden from '@atlaskit/visually-hidden/visually-hidden'; import { defaultFlagGroupContext } from './internal/default-flag-group-context'; import { FlagGroupContext } from './internal/flag-group-context'; /* eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- VOLTC-139 tracks removal of these deprecated re-export shims. */ /** * @deprecated Use `import { FlagGroupContext } from '@atlaskit/flag/flag-group-context'` instead. */ export { FlagGroupContext } from './internal/flag-group-context'; /* eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- VOLTC-139 tracks removal of these deprecated re-export shims. */ /** * @deprecated Use `import { useFlagGroup } from '@atlaskit/flag/use-flag-group'` instead. */ export { useFlagGroup } from './internal/use-flag-group'; /* eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- VOLTC-139 tracks removal of these deprecated re-export shims. */ /** * @deprecated Use `import { flagWidth } from '@atlaskit/flag/constants'` instead. */ export { flagWidth } from './constants'; // transition: none is set on first-of-type to prevent a bug in Firefox // that causes a broken transition var groupStyles = { root: "_v5641b8g _1bsb1kdj _kqswstnw _u7coidpf _1eqkauwl", first: "_v564glyw _t9ec1ygq _1pbyqfx8", second: "_1pbyegat", nth: "_5sag5cps _t9ec1hw2", hidden: "_3um015vq" }; // transition: none is set on first-of-type to prevent a bug in Firefox // that causes a broken transition var groupStylesNew = { root: "_v564t8bh _kqswstnw _u7coidpf _1bsb1kdj _1eqkauwl", first: "_t9ec1ygq _1pbyqfx8", second: "_t9ec1pi4 _1pbyegat", nth: "_t9ec15wd", hidden: "_3um015vq" }; // Transform needed to push up while 1st flag is leaving // Exiting time should match the exiting time of motion so is halved var dismissAllowedStyles = null; var flagGroupContainerStyles = null; // When rendering in top layer, z-index is redundant (top layer stacks above everything). // Override to avoid leaving an explicit z-index on the container. var flagGroupContainerStylesTopLayer = null; // cc_mohiti_flag_anchoring: update left inset from space.1000 (80px) to space.600 (48px) // to match the bottom inset and produce a symmetric 48px × 48px anchor. // The 80px left offset was a legacy artefact from the old left-rail nav sidebar. // The mobile reset is mirrored from the base style so the override is self-contained // and doesn't depend on @compiled's atomic CSS emit order at the ≤560px breakpoint. var flagGroupContainerStylesSymmetric = null; /** * __Flag group__ * * A flag group is used to group a set of related flags, with entry and exit animations. * * - [Examples](https://atlassian.design/components/flag/flag-group/examples) * - [Code](https://atlassian.design/components/flag/flag-group/code) */ export var FlagGroup = function FlagGroup(props) { var id = props.id, _props$label = props.label, label = _props$label === void 0 ? 'Flag notifications' : _props$label, _props$labelTag = props.labelTag, LabelTag = _props$labelTag === void 0 ? 'h2' : _props$labelTag, _props$shouldRenderTo = props.shouldRenderToParent, shouldRenderToParent = _props$shouldRenderTo === void 0 ? false : _props$shouldRenderTo, children = props.children, _props$onDismissed = props.onDismissed, onDismissed = _props$onDismissed === void 0 ? noop : _props$onDismissed; var hasFlags = Array.isArray(children) ? children.length > 0 : Boolean(children); var dismissFlagContext = useMemo(function () { return { onDismissed: onDismissed, isDismissAllowed: true }; }, [onDismissed]); // Keep a stable reference to the latest children, dismiss handler, and // analytics creator so the keydown listener never reads stale closures. var _useAnalyticsEvents = useAnalyticsEvents(), createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent; var latestRef = useRef({ children: children, onDismissed: onDismissed, createAnalyticsEvent: createAnalyticsEvent }); latestRef.current = { children: children, onDismissed: onDismissed, createAnalyticsEvent: createAnalyticsEvent }; // Accessibility (JRACLOUD-97876): allow keyboard-only and assistive // technology users to dismiss the topmost (and only dismissable) flag with // the Escape key, without having to tab through the entire page to reach // the dismiss button. Behaviour is gated behind a feature flag so it can // be rolled out and validated incrementally. useEffect(function () { if (!fg('platform_dst_flag_keyboard_dismiss')) { return; } if (!hasFlags) { return; } var doc = getDocument(); if (!doc) { return; } var timeoutIds = new Set(); var unbind = bind(doc, { type: 'keydown', listener: function listener(event) { var _props; if (event.key !== 'Escape' || event.defaultPrevented) { return; } var currentChildren = latestRef.current.children; var firstFlag = Array.isArray(currentChildren) ? currentChildren.find(Boolean) : currentChildren; if (!firstFlag || _typeof(firstFlag) !== 'object') { return; } var id = (_props = firstFlag.props) === null || _props === void 0 ? void 0 : _props.id; if (id === undefined || id === null || id === '') { return; } var analyticsEvent = latestRef.current.createAnalyticsEvent({ action: 'dismissed', actionSubject: 'flag', attributes: { dismissedVia: 'keyboardShortcut', key: 'Escape' } }); var timeoutId = setTimeout(function () { var _latestRef$current$on, _latestRef$current; timeoutIds.delete(timeoutId); if (event.defaultPrevented) { return; } event.preventDefault(); (_latestRef$current$on = (_latestRef$current = latestRef.current).onDismissed) === null || _latestRef$current$on === void 0 || _latestRef$current$on.call(_latestRef$current, id, analyticsEvent); }); timeoutIds.add(timeoutId); }, options: { capture: true } }); return function () { unbind(); timeoutIds.forEach(clearTimeout); timeoutIds.clear(); }; }, [hasFlags]); var renderChildren = function renderChildren() { return children && _typeof(children) === 'object' ? Children.map(children, function (flag, index) { var isDismissAllowed = index === 0; return fg('platform-dst-motion-uplift') ? /*#__PURE__*/React.createElement(Box, { xcss: cx(groupStylesNew.root, index === 0 && groupStylesNew.first, index === 1 && groupStylesNew.second, index >= 2 && groupStylesNew.nth, index >= 3 && groupStylesNew.hidden), "data-vc-oob": true }, /*#__PURE__*/React.createElement(Motion, { enteringAnimation: "var(--ds-flag-enter, 250ms cubic-bezier(0, 0.4, 0, 1) SlideIn50PercentLeft, 250ms cubic-bezier(0, 0.4, 0, 1) FadeIn0to100)", exitingAnimation: "var(--ds-flag-exit, 200ms cubic-bezier(0.6, 0, 0.8, 0.6) SlideOut15PercentLeft, 200ms cubic-bezier(0.6, 0, 0.8, 0.6) FadeOut100to0)" }, /*#__PURE__*/React.createElement(FlagGroupContext.Provider, { value: // Only the first flag should be able to be dismissed. isDismissAllowed ? dismissFlagContext : defaultFlagGroupContext }, flag))) : /*#__PURE__*/React.createElement(SlideIn, { enterFrom: "left", fade: "inout", duration: "medium", animationTimingFunction: "ease-in" }, function (_ref) { var className = _ref.className, ref = _ref.ref; return /*#__PURE__*/React.createElement("div", { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 className: ax([groupStyles.root, index === 0 && groupStyles.first, index === 1 && groupStyles.second, index >= 1 && groupStyles.nth, index >= 2 && groupStyles.hidden, isDismissAllowed && "_12a7luct", className]), ref: ref, "data-vc-oob": true }, /*#__PURE__*/React.createElement(FlagGroupContext.Provider, { value: // Only the first flag should be able to be dismissed. isDismissAllowed ? dismissFlagContext : defaultFlagGroupContext }, flag)); }); }) : false; }; var useTopLayer = fg('platform-dst-top-layer'); var useSymmetricAnchor = fg('cc_mohiti_flag_anchoring'); var isKeyboardDismissEnabled = fg('platform_dst_flag_keyboard_dismiss'); // When the keyboard dismiss shortcut is available, surface it to assistive // technology users via the existing visually-hidden landmark heading so they // know they can press Escape to dismiss the topmost flag. var screenReaderLabel = isKeyboardDismissEnabled ? "".concat(label, ". Press Escape to dismiss.") : label; var flags = /*#__PURE__*/React.createElement("div", { id: id, "data-vc-oob": true, className: ax(["_kqsw1n9t _1pbyxejw _u7cooahv _1e021epz _1iafidpf _il0widpf", useTopLayer && "_1pby1wug", useSymmetricAnchor && "_1e02oahv _il0widpf"]) }, hasFlags ? /*#__PURE__*/React.createElement(VisuallyHidden, null, /*#__PURE__*/React.createElement(LabelTag, null, screenReaderLabel)) : null, /*#__PURE__*/React.createElement(ExitingPersistence, { appear: false }, renderChildren())); if (useTopLayer) { return /*#__PURE__*/React.createElement(Popover, { mode: "manual", isOpen: true }, flags); } return shouldRenderToParent ? flags : /*#__PURE__*/React.createElement(Portal, { zIndex: layers.flag() }, flags); }; /* eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- VOLTC-139 tracks removal of these deprecated re-export shims. */ /** * @deprecated Use `import { FlagGroup } from '@atlaskit/flag/flag-group'` instead. */ // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports -- VOLTC-139 tracks removal of this deprecated default export shim. export default FlagGroup;