@grafana/ui
Version:
Grafana Components Library
301 lines (298 loc) • 8.63 kB
JavaScript
import { jsx, jsxs } from 'react/jsx-runtime';
import { cx, css } from '@emotion/css';
import * as React from 'react';
import { useTheme2 } from '../../themes/ThemeContext.mjs';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins.mjs';
import { getPropertiesForButtonSize } from '../Forms/commonStyles.mjs';
import { Icon } from '../Icon/Icon.mjs';
import { Tooltip } from '../Tooltip/Tooltip.mjs';
const Button = React.forwardRef(
({
variant = "primary",
size = "md",
fill = "solid",
icon,
fullWidth,
children,
className,
type = "button",
tooltip,
disabled,
tooltipPlacement,
iconPlacement = "left",
onClick,
...otherProps
}, ref) => {
const theme = useTheme2();
const styles = getButtonStyles({
theme,
size,
variant,
fill,
fullWidth,
iconOnly: !children
});
const buttonStyles = cx(
styles.button,
{
[styles.disabled]: disabled
},
className
);
const hasTooltip = Boolean(tooltip);
const iconComponent = icon && /* @__PURE__ */ jsx(IconRenderer, { icon, size, className: styles.icon });
const button = /* @__PURE__ */ jsxs(
"button",
{
className: buttonStyles,
type,
onClick: disabled ? void 0 : onClick,
...otherProps,
"aria-disabled": hasTooltip && disabled,
disabled: !hasTooltip && disabled,
ref: tooltip ? void 0 : ref,
children: [
iconPlacement === "left" && iconComponent,
children && /* @__PURE__ */ jsx("span", { className: styles.content, children }),
iconPlacement === "right" && iconComponent
]
}
);
if (tooltip) {
return /* @__PURE__ */ jsx(Tooltip, { ref, content: tooltip, placement: tooltipPlacement, children: button });
}
return button;
}
);
Button.displayName = "Button";
const LinkButton = React.forwardRef(
({
variant = "primary",
size = "md",
fill = "solid",
icon,
fullWidth,
children,
className,
onBlur,
onFocus,
disabled,
tooltip,
tooltipPlacement,
...otherProps
}, ref) => {
const theme = useTheme2();
const styles = getButtonStyles({
theme,
fullWidth,
size,
variant,
fill,
iconOnly: !children
});
const linkButtonStyles = cx(
styles.button,
{
[css(styles.disabled, {
pointerEvents: "none"
})]: disabled
},
className
);
const button = /* @__PURE__ */ jsxs(
"a",
{
className: linkButtonStyles,
...otherProps,
tabIndex: disabled ? -1 : 0,
"aria-disabled": disabled,
ref: tooltip ? void 0 : ref,
children: [
/* @__PURE__ */ jsx(IconRenderer, { icon, size, className: styles.icon }),
children && /* @__PURE__ */ jsx("span", { className: styles.content, children })
]
}
);
if (tooltip) {
return /* @__PURE__ */ jsx(Tooltip, { ref, content: tooltip, placement: tooltipPlacement, children: button });
}
return button;
}
);
LinkButton.displayName = "LinkButton";
const IconRenderer = ({ icon, size, className, iconType }) => {
if (!icon) {
return null;
}
if (React.isValidElement(icon)) {
return React.cloneElement(icon, {
className,
size
});
}
return /* @__PURE__ */ jsx(Icon, { name: icon, size, className, type: iconType });
};
const getButtonStyles = (props) => {
const { theme, variant, fill = "solid", size, iconOnly, fullWidth } = props;
const { height, padding, fontSize } = getPropertiesForButtonSize(size, theme);
const variantStyles = getPropertiesForVariant(theme, variant, fill);
const disabledStyles = getPropertiesForDisabled(theme, variant, fill);
const focusStyle = getFocusStyles(theme);
const paddingMinusBorder = theme.spacing.gridSize * padding - 1;
return {
button: css({
label: "button",
display: "inline-flex",
alignItems: "center",
gap: theme.spacing(1),
fontSize,
fontWeight: theme.typography.fontWeightMedium,
fontFamily: theme.typography.fontFamily,
padding: `0 ${paddingMinusBorder}px`,
height: theme.spacing(height),
// Deduct border from line-height for perfect vertical centering on windows and linux
lineHeight: `${theme.spacing.gridSize * height - 2}px`,
verticalAlign: "middle",
cursor: "pointer",
borderRadius: theme.shape.radius.default,
"&:focus": focusStyle,
"&:focus-visible": focusStyle,
"&:focus:not(:focus-visible)": getMouseFocusStyles(),
...fullWidth && {
flexGrow: 1,
justifyContent: "center"
},
...variantStyles,
":disabled": disabledStyles,
"&[disabled]": disabledStyles
}),
disabled: css(disabledStyles, {
"&:hover": css(disabledStyles)
}),
img: css({
width: "16px",
height: "16px",
margin: theme.spacing(0, 1, 0, 0.5)
}),
icon: iconOnly ? css({
// Important not to set margin bottom here as it would override internal icon bottom margin
marginRight: theme.spacing(-padding / 2),
marginLeft: theme.spacing(-padding / 2)
}) : void 0,
content: css({
display: "flex",
flexDirection: "row",
alignItems: "center",
whiteSpace: "nowrap",
overflow: "hidden",
height: "100%"
})
};
};
function getButtonVariantStyles(theme, color, fill) {
let outlineBorderColor = color.border;
let borderColor = "transparent";
let hoverBorderColor = "transparent";
if (color.name === "secondary") {
borderColor = color.border;
hoverBorderColor = theme.colors.emphasize(color.border, 0.25);
outlineBorderColor = theme.colors.border.strong;
}
if (fill === "outline") {
return {
background: "transparent",
color: color.text,
border: `1px solid ${outlineBorderColor}`,
transition: theme.transitions.create(["background-color", "border-color", "color"], {
duration: theme.transitions.duration.short
}),
"&:hover": {
background: color.transparent,
borderColor: theme.colors.emphasize(outlineBorderColor, 0.25),
color: color.text
}
};
}
if (fill === "text") {
return {
background: "transparent",
color: color.text,
border: "1px solid transparent",
transition: theme.transitions.create(["background-color", "color"], {
duration: theme.transitions.duration.short
}),
"&:focus": {
outline: "none",
textDecoration: "none"
},
"&:hover": {
background: color.transparent,
textDecoration: "none"
}
};
}
return {
background: color.main,
color: color.contrastText,
border: `1px solid ${borderColor}`,
transition: theme.transitions.create(["background-color", "box-shadow", "border-color", "color"], {
duration: theme.transitions.duration.short
}),
"&:hover": {
background: color.shade,
color: color.contrastText,
boxShadow: theme.shadows.z1,
borderColor: hoverBorderColor
}
};
}
function getPropertiesForDisabled(theme, variant, fill) {
const disabledStyles = {
cursor: "not-allowed",
boxShadow: "none",
color: theme.colors.text.disabled,
transition: "none"
};
if (fill === "text") {
return {
...disabledStyles,
background: "transparent",
border: `1px solid transparent`
};
}
if (fill === "outline") {
return {
...disabledStyles,
background: "transparent",
border: `1px solid ${theme.colors.border.weak}`
};
}
return {
...disabledStyles,
background: theme.colors.action.disabledBackground,
border: `1px solid transparent`
};
}
function getPropertiesForVariant(theme, variant, fill) {
switch (variant) {
case "secondary":
return getButtonVariantStyles(theme, theme.colors.secondary, fill);
case "destructive":
return getButtonVariantStyles(theme, theme.colors.error, fill);
case "success":
return getButtonVariantStyles(theme, theme.colors.success, fill);
case "primary":
default:
return getButtonVariantStyles(theme, theme.colors.primary, fill);
}
}
const clearButtonStyles = (theme) => {
return css({
background: "transparent",
color: theme.colors.text.primary,
border: "none",
padding: 0
});
};
export { Button, IconRenderer, LinkButton, clearButtonStyles, getButtonStyles, getPropertiesForVariant };
//# sourceMappingURL=Button.mjs.map