@grafana/ui
Version:
Grafana Components Library
262 lines (259 loc) • 8.18 kB
JavaScript
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { cx, css } from '@emotion/css';
import * as React from 'react';
import { useMemo, useContext, memo, cloneElement } from 'react';
import { t } from '@grafana/i18n';
import { useStyles2 } from '../../themes/ThemeContext.mjs';
import { getFocusStyles } from '../../themes/mixins.mjs';
import { getCardContainerStyles, CardContainer } from './CardContainer.mjs';
"use strict";
const CardContext = React.createContext(null);
const Card = ({
disabled,
href,
onClick,
children,
isSelected,
isCompact,
className,
noMargin,
...htmlProps
}) => {
const hasHeadingComponent = useMemo(
() => React.Children.toArray(children).some((c) => React.isValidElement(c) && c.type === Heading),
[children]
);
const disableHover = disabled || !onClick && !href;
const onCardClick = onClick && !disabled ? onClick : void 0;
const styles = useStyles2(getCardContainerStyles, disabled, disableHover, isSelected, isCompact, noMargin);
return /* @__PURE__ */ jsx(
CardContainer,
{
disableEvents: disabled,
disableHover,
isSelected,
className: cx(styles.container, className),
noMargin,
...htmlProps,
children: /* @__PURE__ */ jsxs(CardContext.Provider, { value: { href, onClick: onCardClick, disabled, isSelected }, children: [
!hasHeadingComponent && /* @__PURE__ */ jsx(Heading, {}),
children
] })
}
);
};
Card.displayName = "Card";
const Heading = ({ children, className, "aria-label": ariaLabel }) => {
const context = useContext(CardContext);
const styles = useStyles2(getHeadingStyles);
const { href, onClick, isSelected } = context != null ? context : {
href: void 0,
onClick: void 0,
isSelected: void 0
};
const optionLabel = t("grafana-ui.card.option", "option");
return /* @__PURE__ */ jsxs("h2", { className: cx(styles.heading, className), children: [
href ? /* @__PURE__ */ jsx("a", { href, className: styles.linkHack, "aria-label": ariaLabel, onClick, children }) : onClick ? /* @__PURE__ */ jsx("button", { onClick, className: styles.linkHack, "aria-label": ariaLabel, type: "button", children }) : /* @__PURE__ */ jsx(Fragment, { children }),
isSelected !== void 0 && /* @__PURE__ */ jsx("input", { "aria-label": optionLabel, type: "radio", checked: isSelected, readOnly: true })
] });
};
Heading.displayName = "Heading";
const getHeadingStyles = (theme) => ({
heading: css({
gridArea: "Heading",
justifySelf: "start",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
marginBottom: 0,
fontSize: theme.typography.size.md,
letterSpacing: "inherit",
lineHeight: theme.typography.body.lineHeight,
color: theme.colors.text.primary,
fontWeight: theme.typography.fontWeightMedium,
"& input[readonly]": {
cursor: "inherit"
}
}),
linkHack: css({
all: "unset",
"&::after": {
position: "absolute",
content: '""',
top: 0,
bottom: 0,
left: 0,
right: 0,
borderRadius: theme.shape.radius.default
},
"&:focus-visible": {
outline: "none",
outlineOffset: 0,
boxShadow: "none",
"&::after": {
...getFocusStyles(theme),
zIndex: 1
}
}
})
});
const Tags = ({ children, className }) => {
const styles = useStyles2(getTagStyles);
return /* @__PURE__ */ jsx("div", { className: cx(styles.tagList, className), children });
};
Tags.displayName = "Tags";
const getTagStyles = (theme) => ({
tagList: css({
position: "relative",
gridArea: "Tags",
alignSelf: "center"
})
});
const Description = ({ children, className }) => {
const styles = useStyles2(getDescriptionStyles);
const Element = typeof children === "string" ? "p" : "div";
return /* @__PURE__ */ jsx(Element, { className: cx(styles.description, className), children });
};
Description.displayName = "Description";
const getDescriptionStyles = (theme) => ({
description: css({
width: "100%",
gridArea: "Description",
margin: theme.spacing(1, 0, 0),
color: theme.colors.text.secondary,
lineHeight: theme.typography.body.lineHeight
})
});
const Figure = ({ children, align = "start", className }) => {
const styles = useStyles2(getFigureStyles);
return /* @__PURE__ */ jsx(
"div",
{
className: cx(
styles.media,
className,
css({
alignSelf: align
})
),
children
}
);
};
Figure.displayName = "Figure";
const getFigureStyles = (theme) => ({
media: css({
position: "relative",
gridArea: "Figure",
marginRight: theme.spacing(2),
width: "40px",
"> img": {
width: "100%"
},
"&:empty": {
display: "none"
}
})
});
const Meta = memo(({ children, className, separator = "|" }) => {
const styles = useStyles2(getMetaStyles);
let meta = children;
const filtered = React.Children.toArray(children).filter(Boolean);
if (!filtered.length) {
return null;
}
meta = filtered.map((element, i) => /* @__PURE__ */ jsx("div", { className: styles.metadataItem, children: element }, `element_${i}`));
if (filtered.length > 1 && separator) {
meta = filtered.reduce((prev, curr, i) => [
prev,
/* @__PURE__ */ jsx("span", { className: styles.separator, children: separator }, `separator_${i}`),
curr
]);
}
return /* @__PURE__ */ jsx("div", { className: cx(styles.metadata, className), children: meta });
});
Meta.displayName = "Meta";
const getMetaStyles = (theme) => ({
metadata: css({
gridArea: "Meta",
display: "flex",
alignItems: "center",
width: "100%",
fontSize: theme.typography.size.sm,
color: theme.colors.text.secondary,
margin: theme.spacing(0.5, 0, 0),
lineHeight: theme.typography.bodySmall.lineHeight,
overflowWrap: "anywhere"
}),
metadataItem: css({
// Needed to allow for clickable children in metadata
zIndex: 0
}),
separator: css({
margin: `0 ${theme.spacing(1)}`
})
});
const BaseActions = ({ children, disabled, variant, className }) => {
const styles = useStyles2(getActionStyles);
const context = useContext(CardContext);
const isDisabled = (context == null ? void 0 : context.disabled) || disabled;
const css2 = variant === "primary" ? styles.actions : styles.secondaryActions;
return /* @__PURE__ */ jsx("div", { className: cx(css2, className), children: React.Children.map(children, (child) => {
return React.isValidElement(child) ? cloneElement(child, { disabled: isDisabled, ...child.props }) : null;
}) });
};
const getActionStyles = (theme) => ({
actions: css({
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
gap: theme.spacing(1),
gridArea: "Actions",
marginTop: theme.spacing(2)
}),
secondaryActions: css({
alignSelf: "center",
color: theme.colors.text.secondary,
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
gap: theme.spacing(1),
gridArea: "Secondary",
marginTop: theme.spacing(2)
})
});
const Actions = ({ children, disabled, className }) => {
return /* @__PURE__ */ jsx(BaseActions, { variant: "primary", disabled, className, children });
};
Actions.displayName = "Actions";
const SecondaryActions = ({ children, disabled, className }) => {
return /* @__PURE__ */ jsx(BaseActions, { variant: "secondary", disabled, className, children });
};
SecondaryActions.displayName = "SecondaryActions";
const getCardStyles = (theme) => {
return {
inner: css({
display: "flex",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
flexWrap: "wrap"
}),
...getHeadingStyles(theme),
...getMetaStyles(theme),
...getDescriptionStyles(theme),
...getFigureStyles(theme),
...getActionStyles(theme),
...getTagStyles(theme)
};
};
Card.Heading = Heading;
Card.Tags = Tags;
Card.Figure = Figure;
Card.Meta = Meta;
Card.Actions = Actions;
Card.SecondaryActions = SecondaryActions;
Card.Description = Description;
export { Card, getCardStyles };
//# sourceMappingURL=Card.mjs.map