@atlaskit/lozenge
Version:
A lozenge is a visual indicator used to highlight an item's status for quick recognition.
294 lines (290 loc) • 16.8 kB
JavaScript
/* lozenge-base.tsx generated by @compiled/babel-plugin v3.0.2 */
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("./lozenge-base.compiled.css");
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _runtime = require("@compiled/react/runtime");
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _badgeNew = _interopRequireDefault(require("@atlaskit/badge/badge-new"));
var _css = require("@atlaskit/css");
var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down"));
var _useResizing = require("@atlaskit/motion/use-resizing");
var _fg = require("@atlaskit/platform-feature-flags/fg");
var _pressable = _interopRequireDefault(require("@atlaskit/primitives/pressable"));
var _spinner = _interopRequireDefault(require("@atlaskit/spinner/spinner"));
var _getThemeStyles2 = require("./get-theme-styles");
var _iconRenderer = _interopRequireDefault(require("./icon-renderer"));
var _utils = require("./utils");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- TODO: migrate to @atlaskit/primitives/compiled
// Get the pressed background color for the selected lozenge dropdown trigger
var pressedBackgroundMapping = {
success: "var(--ds-background-success-subtler-pressed, #B3DF72)",
warning: "var(--ds-background-warning-subtler-pressed, #FBC828)",
danger: "var(--ds-background-danger-subtler-pressed, #FD9891)",
information: "var(--ds-background-information-subtler-pressed, #8FB8F6)",
neutral: "var(--ds-background-neutral-pressed, #080F214A)",
discovery: "var(--ds-background-discovery-subtler-pressed, #D8A0F7)",
'accent-red': "var(--ds-background-accent-red-subtler-pressed, #FD9891)",
'accent-orange': "var(--ds-background-accent-orange-subtler-pressed, #FBC828)",
'accent-yellow': "var(--ds-background-accent-yellow-subtler-pressed, #EED12B)",
'accent-lime': "var(--ds-background-accent-lime-subtler-pressed, #B3DF72)",
'accent-green': "var(--ds-background-accent-green-subtler-pressed, #7EE2B8)",
'accent-teal': "var(--ds-background-accent-teal-subtler-pressed, #9DD9EE)",
'accent-blue': "var(--ds-background-accent-blue-subtler-pressed, #8FB8F6)",
'accent-purple': "var(--ds-background-accent-purple-subtler-pressed, #D8A0F7)",
'accent-magenta': "var(--ds-background-accent-magenta-subtler-pressed, #F797D2)",
'accent-gray': "var(--ds-background-accent-gray-subtlest-pressed, #B7B9BE)"
};
var styles = {
container: "_2rko12b0 _1reo15vq _18m915vq _189ee4h9 _1dqonqa1 _1h6d1j28 _kqswh2mm _1e0c116y _4cvr1h6o _vchhusvi _4t3i1k92 _1q51v77o _85i5v77o _bozg1b66 _y4ti1b66",
motionContainer: "_k8m01rje _1oeci9qs _6fl41d08",
containerSpacious: "_2rko1qi0 _1tkeviql _1q511b66 _85i51b66 _bozgutpp _y4tiutpp",
containerBadgePadding: "_y4ti303w",
text: "_11c8wadc _1reo15vq _18m915vq _o5721q9c",
textEllipsis: "_1bto1l2s",
textClip: "_1btozryt",
textSpacious: "_11c8fhey _k48p1wq8",
textSelected: "_syaz6x5g",
loadingOverlay: "_1reo15vq _18m915vq _1e0c1txw _kqswstnw _4cvr1h6o _1bah1h6o _u7coze3t _152tze3t _rjxpze3t _1e02ze3t _lcxvglyw",
loadingOverlayMotion: "_j7hq1bym _5sag1ign _1pglindk",
metricBadgeWrapper: "_1e0c1txw",
'semantic.success': "_3wu02gvx _bfhk14j0 _syaz1p1e",
'semantic.warning': "_3wu01wfx _bfhk10f4 _syazmgs1",
'semantic.danger': "_3wu01mzp _bfhk18wg _syaz1blx",
'semantic.information': "_3wu0wn4u _bfhk8lbg _syaz1qd9",
'semantic.neutral': "_3wu01l7x _bfhki8nm _syazi7uo",
'semantic.discovery': "_3wu019v3 _bfhke670 _syaz1g72",
'accent.red': "_3wu0n9dc _bfhk1rtt _syazhwvp",
'accent.orange': "_3wu01ip5 _bfhk165s _syaz7i1p",
'accent.yellow': "_3wu01s7j _bfhk1773 _syazekll",
'accent.lime': "_3wu01m7d _bfhkz2ec _syaz1ik3",
'accent.green': "_3wu05d2u _bfhk1wnw _syaz1y78",
'accent.teal': "_3wu0131p _bfhk1a17 _syaz12v7",
'accent.blue': "_3wu018hp _bfhk1dy8 _syaz1kyx",
'accent.purple': "_3wu0luwt _bfhk1nm4 _syaz1mn1",
'accent.magenta': "_3wu0132u _bfhkv9ra _syaz1qur",
'accent.gray': "_3wu01l7x _bfhkysee _syaz1tmo",
'interactive.semantic.success': "_irr31r82 _1di6d6jc",
'interactive.semantic.warning': "_irr31yx4 _1di6bkku",
'interactive.semantic.danger': "_irr370oi _1di6jkmi",
'interactive.semantic.information': "_irr315aw _1di6ar1y",
'interactive.semantic.neutral': "_irr3plhp _1di61gdz",
'interactive.semantic.discovery': "_irr3rumk _1di65usi",
'interactive.accent.red': "_irr3affd _1di61j5a",
'interactive.accent.orange': "_irr31ei0 _1di6dpo3",
'interactive.accent.yellow': "_irr31uw7 _1di61r9w",
'interactive.accent.lime': "_irr31gf0 _1di62kxc",
'interactive.accent.green': "_irr31e2h _1di6ybhx",
'interactive.accent.teal': "_irr3kwwr _1di61jb0",
'interactive.accent.blue': "_irr3815t _1di6rwxf",
'interactive.accent.purple': "_irr3attl _1di63nfk",
'interactive.accent.magenta': "_irr31axx _1di642ri",
'interactive.accent.gray': "_irr3wejn _1di618ut",
iconBorderFilter: "_1h6d74of",
content: "_zulp1b66 _1e0c116y _4cvr1h6o",
maxWidth: "_p12f1osq",
contentSpacious: "_zulp12x7",
loadingContent: "_tzy4idpf",
loadingMotion: "_k8m0brmi _1oec1ign _6fl4indk",
containerBadgePressed: "_1axmtoke _17i7toke",
containerBadgeNeutralAppearance: "_1ftrnkaw _1axmnkaw _17i7nkaw"
};
var interactiveMotionStyles = {
motion: "_v564k6bl _1ggl5xtf"
};
/**
* __New Lozenge__
*
* A lozenge is a visual indicator used to highlight an item's status for quick recognition.
* This is the updated version with the new North Star visual language.
*/
var LozengeBase = /*#__PURE__*/(0, _react.memo)( /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
var children = _ref.children,
testId = _ref.testId,
appearance = _ref.appearance,
iconBefore = _ref.iconBefore,
trailingMetric = _ref.trailingMetric,
trailingMetricAppearance = _ref.trailingMetricAppearance,
_ref$maxWidth = _ref.maxWidth,
maxWidth = _ref$maxWidth === void 0 ? 200 : _ref$maxWidth,
_ref$spacing = _ref.spacing,
spacing = _ref$spacing === void 0 ? 'default' : _ref$spacing,
isSelected = _ref.isSelected,
_ref$isLoading = _ref.isLoading,
isLoading = _ref$isLoading === void 0 ? false : _ref$isLoading,
onClick = _ref.onClick,
style = _ref.style,
analyticsContext = _ref.analyticsContext,
interactionName = _ref.interactionName,
ariaControls = _ref['aria-controls'],
ariaExpanded = _ref['aria-expanded'],
ariaHaspopup = _ref['aria-haspopup'],
ariaLabel = _ref['aria-label'];
var _useState = (0, _react.useState)(false),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
resizing = _useState2[0],
setResizing = _useState2[1];
var onFinishMotion = function onFinishMotion() {
return setResizing(false);
};
var resizingWidth = (0, _useResizing.useResizing)({
dimension: 'width',
duration: "var(--ds-duration-medium, 200ms)",
easing: "var(--ds-easing-inout-bold, cubic-bezier(0.4, 0, 0, 1))",
onFinishMotion: onFinishMotion
});
var isInitialRender = (0, _react.useRef)(true);
var isInteractive = typeof onClick === 'function';
// Determine the effective color, with fallback logic for legacy appearances
var resolvedColor = (0, _utils.resolveLozengeColor)(appearance) || 'neutral';
var _getThemeStyles = (0, _getThemeStyles2.getThemeStyles)(resolvedColor),
category = _getThemeStyles.category,
key = _getThemeStyles.key;
var colorStyleKey = "".concat(category, ".").concat(key);
var interactiveStyleKey = "interactive.".concat(category, ".").concat(key);
var maxWidthValue = typeof maxWidth === 'string' ? maxWidth : "".concat(maxWidth, "px");
var maxWidthIsPc = typeof maxWidth === 'string' && maxWidth.endsWith('%');
var resolvedTrailingMetricAppearance = trailingMetricAppearance ? trailingMetricAppearance === 'inverse' ? 'inverse' : (0, _utils.resolveLozengeColor)(trailingMetricAppearance) : resolvedColor;
// Map the resolved trailing metric appearance to a Badge appearance.
// Semantic colors map to their new bold variants (e.g. successBold),
// which provide sufficient color emphasis on top of the subtler
// lozenge background. Accent colors and unknown values fall back to
// the neutral appearance.
var metricBadgeAppearance = function () {
if (resolvedTrailingMetricAppearance === 'inverse') {
return 'inverse';
}
if (resolvedTrailingMetricAppearance == null) {
return 'neutral';
}
if (resolvedTrailingMetricAppearance.startsWith('accent-')) {
return 'neutral';
}
switch (resolvedTrailingMetricAppearance) {
case 'success':
return 'successBold';
case 'warning':
return 'warningBold';
case 'danger':
return 'dangerBold';
case 'information':
return 'informationBold';
case 'discovery':
return 'discoveryBold';
case 'neutral':
default:
return 'neutral';
}
}();
var commonStyleOverrides = {
backgroundColor: style === null || style === void 0 ? void 0 : style.backgroundColor,
// Constrain the container to the smaller of the explicit maxWidth and 100% of
// the parent. Using min(...) means the lozenge never overflows its parent,
// while still honouring the explicit maxWidth prop when the parent is wider.
maxWidth: maxWidthIsPc ? maxWidth : "min(".concat(maxWidthValue, ", 100%)")
};
var hasTrailingMetric = trailingMetric != null && trailingMetric !== '';
var childrenKey = typeof children === 'string' ? children : undefined;
(0, _react.useLayoutEffect)(function () {
// Ignore initial render
if (isInitialRender.current) {
isInitialRender.current = false;
return;
}
setResizing(true);
}, [childrenKey]);
var enableMotionFG = (0, _fg.fg)('platform-dst-motion-uplift');
var enableButtonMotionFG = (0, _fg.fg)('platform-dst-motion-uplift-button');
var innerContent = /*#__PURE__*/React.createElement("span", (0, _extends2.default)({
"data-testid": testId ? "".concat(testId, "--content") : undefined
}, enableMotionFG ? resizingWidth : undefined, {
className: (0, _runtime.ax)([styles.content, spacing === 'spacious' && styles.contentSpacious, isInteractive && enableButtonMotionFG && styles.loadingMotion, isLoading && styles.loadingContent,
// Constrain the content wrapper to its container so text truncation
// works correctly within the flex layout, regardless of whether maxWidth
// is a percentage, fixed value, or the parent container is narrower than
// the explicit maxWidth.
styles.maxWidth])
}), iconBefore && /*#__PURE__*/React.createElement(_iconRenderer.default, {
size: spacing === 'spacious' ? 'medium' : 'small',
icon: iconBefore,
color: resolvedColor,
testId: testId && "".concat(testId, "--icon")
}), /*#__PURE__*/React.createElement("span", {
style: {
// The text fills 100% of the inner content wrapper. The container's
// own max-width (set on the container via commonStyleOverrides) handles
// the actual size constraint, so the text just needs to fill the available
// space and truncate when it overflows.
maxWidth: maxWidthIsPc ? '100%' : "calc(".concat(maxWidthValue, " - ", "var(--ds-space-100, 8px)", ")"),
color: style === null || style === void 0 ? void 0 : style.color
},
"data-testid": testId && "".concat(testId, "--text"),
className: (0, _runtime.ax)([styles.text, enableMotionFG && resizing && !maxWidth ? styles.textClip : styles.textEllipsis, spacing === 'spacious' && styles.textSpacious])
}, children), hasTrailingMetric && !resolvedColor.startsWith('accent-') && /*#__PURE__*/React.createElement("span", {
"data-lozenge-metric-wrapper": true,
"data-testid": testId && "".concat(testId, "--metric"),
className: (0, _runtime.ax)([styles.metricBadgeWrapper])
}, /*#__PURE__*/React.createElement(_badgeNew.default, {
appearance: metricBadgeAppearance
}, trailingMetric)), isInteractive && /*#__PURE__*/React.createElement(_chevronDown.default, {
label: "",
size: "small",
color: 'currentColor',
testId: testId && "".concat(testId, "--chevron")
}));
if (isInteractive) {
return /*#__PURE__*/React.createElement(_pressable.default, (0, _extends2.default)({
ref: ref,
xcss: (0, _css.cx)(styles.container, !isLoading && enableButtonMotionFG ? interactiveMotionStyles.motion : enableMotionFG && styles.motionContainer, spacing === 'spacious' && styles.containerSpacious, !isSelected && styles.iconBorderFilter, styles[colorStyleKey], !isLoading && styles[interactiveStyleKey], hasTrailingMetric && styles.containerBadgePressed, hasTrailingMetric && resolvedTrailingMetricAppearance === 'neutral' && styles.containerBadgeNeutralAppearance)
}, isLoading && {
'aria-busy': true,
'aria-disabled': true,
isDisabled: true
}, {
"aria-label": isLoading ? 'Loading' : ariaLabel,
"aria-controls": ariaControls,
"aria-expanded": ariaExpanded,
"aria-haspopup": ariaHaspopup,
onClick: isLoading ? undefined : onClick,
style: _objectSpread(_objectSpread({}, commonStyleOverrides), {}, {
// Specified because Pressable has a default border:none which overrides the border specified on the container
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
border: "solid ".concat("var(--ds-border-width, 1px)", " ", isSelected ? 'var(--border-color) !important' : 'transparent'),
backgroundColor: isSelected ? pressedBackgroundMapping[resolvedColor] : undefined,
cursor: isLoading ? 'progress' : 'pointer'
}),
testId: testId,
analyticsContext: analyticsContext,
interactionName: interactionName,
componentName: "LozengeDropdownTrigger"
// `data-selected` mirrors the `isSelected` prop so CSS can target the
// pressed-state badge override via attribute selector.
}, isSelected && {
'data-selected': 'true'
}), innerContent, isLoading && /*#__PURE__*/React.createElement("span", {
"data-testid": testId ? "".concat(testId, "--loading-overlay") : undefined,
className: (0, _runtime.ax)([styles.loadingOverlay, enableButtonMotionFG && styles.loadingOverlayMotion])
}, /*#__PURE__*/React.createElement(_spinner.default, {
size: spacing === 'spacious' ? 'small' : 'xsmall',
label: ", Loading",
testId: testId ? "".concat(testId, "--loading-spinner") : undefined
})));
}
return /*#__PURE__*/React.createElement("span", {
ref: ref,
style: commonStyleOverrides,
"data-testid": testId,
className: (0, _runtime.ax)([styles.container, spacing === 'spacious' && styles.containerSpacious, spacing !== 'spacious' && hasTrailingMetric && styles.containerBadgePadding, styles[colorStyleKey], styles.iconBorderFilter, hasTrailingMetric && resolvedTrailingMetricAppearance === 'neutral' && styles.containerBadgeNeutralAppearance])
}, innerContent);
}));
var _default = exports.default = LozengeBase;