@octopusdeploy/design-system-components
Version:
The design systems component library.
159 lines (158 loc) • 7.28 kB
JavaScript
;
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",
},
});