UNPKG

@octopusdeploy/design-system-components

Version:
159 lines (158 loc) • 7.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InlineMessage = exports.inlineMessageTypes = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const css_1 = require("@emotion/css"); const design_system_icons_1 = require("@octopusdeploy/design-system-icons"); const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens"); const routing_1 = require("../../routing"); const Link_1 = require("../Link"); exports.inlineMessageTypes = ["information", "warning", "danger", "feature", "upsell"]; /** * The inline message component is used to display a short, non-urgent contextual message that * attracts the user's attention without interrupting their task. It can be used to display information, * warnings, or other messages that are not critical to the user's task. * * @param props - The component props * @returns A React element representing the inline message * * @example * ```tsx * // Basic information message * <InlineMessage * type="information" * description="Your changes have been saved successfully." * /> * * // With action button * <InlineMessage * type="warning" * title="Deprecated Feature" * description="This feature will be removed in the next version." * action={{ label: "Learn More", onClick: onClick }} * /> * ``` */ /** * Type guard to check if action is ActionButtonProps */ function isActionButton(action) { return "onClick" in action; } /** * Type guard to check if action is ActionLinkProps */ function isActionLink(action) { return "href" in action; } /** * Type guard to check if action is ActionLinkPropsExternal */ function isActionLinkExternal(action) { return "external" in action && action.external === true; } function ActionElement(action) { const Link = (0, routing_1.useOctopusLinkComponent)(); if (action && isActionLink(action)) { if (isActionLinkExternal(action) && typeof action.href === "string") { return ((0, jsx_runtime_1.jsx)("div", { className: actionExternalStyles, children: (0, jsx_runtime_1.jsx)(Link_1.ExternalLink, { href: action.href, size: "medium", trackAnalytics: action.trackAnalytics, children: action.label }) })); } const openInNewTab = action.openInSelf === false; return ((0, jsx_runtime_1.jsxs)(Link, { className: (0, css_1.cx)(actionStyles, interactionStyles, { [newTabActionStyles]: openInNewTab }), target: openInNewTab ? "_blank" : "_self", rel: openInNewTab ? "noreferrer noopener" : undefined, href: action.href, children: [action.label, openInNewTab && (0, jsx_runtime_1.jsx)(design_system_icons_1.ArrowUpRightFromSquareIcon, { size: 16 })] })); } if (action && isActionButton(action)) { return ((0, jsx_runtime_1.jsx)("button", { type: "button", className: (0, css_1.cx)(buttonStyles, actionStyles, interactionStyles), onClick: action.onClick, children: action.label })); } } const InlineMessage = (props) => { const { type, title, description, action } = props; const iconElement = getIconForType(type); return ((0, jsx_runtime_1.jsxs)("div", { className: containerStyles, children: [(0, jsx_runtime_1.jsx)("span", { className: iconContainerStyles, children: iconElement }), (0, jsx_runtime_1.jsxs)("div", { className: contentContainerStyles, children: [title && (0, jsx_runtime_1.jsx)("p", { className: titleStyles, children: title }), (0, jsx_runtime_1.jsx)("p", { className: messageStyles, children: description }), action && ActionElement(action)] })] })); }; exports.InlineMessage = InlineMessage; exports.InlineMessage.displayName = "InlineMessage"; const iconsByType = { information: (0, jsx_runtime_1.jsx)(design_system_icons_1.InfoCircleIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.icon.info }), warning: (0, jsx_runtime_1.jsx)(design_system_icons_1.ExclamationCircleIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.icon.warning }), danger: (0, jsx_runtime_1.jsx)(design_system_icons_1.ExclamationDiamondIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.icon.danger }), feature: (0, jsx_runtime_1.jsx)(design_system_icons_1.RocketIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.icon.feature }), upsell: (0, jsx_runtime_1.jsx)(design_system_icons_1.GemIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.icon.feature }), }; function getIconForType(type) { return iconsByType[type] || null; } const containerStyles = (0, css_1.css)({ display: "flex", alignItems: "center", gap: design_system_tokens_1.space[4], // Fixing the line height here to prevent alignment issues when a parent container has a line height set lineHeight: design_system_tokens_1.lineHeight.xSmall, }); const iconContainerStyles = (0, css_1.css)({ flexShrink: 0, }); const contentContainerStyles = (0, css_1.css)({ display: "inline", whiteSpace: "normal", textWrap: "pretty", }); const titleStyles = (0, css_1.css)({ font: design_system_tokens_1.text.body.bold.medium, color: design_system_tokens_1.themeTokens.color.text.primary, display: "inline", margin: 0, marginRight: design_system_tokens_1.space[4], }); const messageStyles = (0, css_1.css)({ font: design_system_tokens_1.text.body.regular.medium, color: design_system_tokens_1.themeTokens.color.text.primary, display: "inline", margin: 0, }); const actionStyles = (0, css_1.css)({ font: design_system_tokens_1.text.body.regular.medium, color: design_system_tokens_1.themeTokens.color.text.link.default, marginLeft: design_system_tokens_1.space[4], textDecoration: "none", }); const newTabActionStyles = (0, css_1.css)({ display: "inline-flex", alignItems: "center", gap: design_system_tokens_1.space[4], }); const actionExternalStyles = (0, css_1.css)({ display: "inline-flex", alignItems: "center", gap: design_system_tokens_1.space[2], marginLeft: design_system_tokens_1.space[4], // TODO: Ideally i want to apply this to the Link/ExternalLink component but that has // wider flow on effects, so this is temporary until we consolidate the Linking components // at a later date. "&:hover a": { color: design_system_tokens_1.themeTokens.color.text.link.hover, textDecoration: "underline", }, "&:focus-visible a": { borderRadius: design_system_tokens_1.borderRadius.extraSmall, outline: `${design_system_tokens_1.borderWidth[2]} solid ${design_system_tokens_1.themeTokens.color.border.selected}`, outlineOffset: "2px", }, }); const buttonStyles = (0, css_1.css)({ background: "none", padding: "0", border: "none", cursor: "pointer", }); const interactionStyles = (0, css_1.css)({ "&:hover": { color: design_system_tokens_1.themeTokens.color.text.link.hover, textDecoration: "underline", textDecorationColor: design_system_tokens_1.themeTokens.color.text.link.hover, }, "&:focus-visible": { borderRadius: design_system_tokens_1.borderRadius.extraSmall, outline: `${design_system_tokens_1.borderWidth[2]} solid ${design_system_tokens_1.themeTokens.color.border.selected}`, outlineOffset: "2px", }, });