UNPKG

@grafana/ui

Version:
301 lines (298 loc) • 8.63 kB
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