UNPKG

@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
/* lozenge-base.tsx generated by @compiled/babel-plugin v3.0.2 */ "use strict"; 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;