@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
JavaScript
/* 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;