mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-15 20:12:11 +01:00
Implement new Icon Button component
Co-authored-by: René Pfeuffer<rene.pfeuffer@cloudogu.com>
This commit is contained in:
2
gradle/changelog/added_iconbutton.yaml
Normal file
2
gradle/changelog/added_iconbutton.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: added
|
||||
description: New component "icon button" in ui library
|
||||
@@ -30,7 +30,9 @@ import {
|
||||
ButtonVariants,
|
||||
ExternalLinkButton as ExternalLinkButtonComponent,
|
||||
LinkButton as LinkButtonComponent,
|
||||
IconButton as IconButtonComponent,
|
||||
} from "./Button";
|
||||
import Icon from "./Icon";
|
||||
import StoryRouter from "storybook-react-router";
|
||||
import { StoryFn } from "@storybook/react";
|
||||
|
||||
@@ -42,6 +44,7 @@ export default {
|
||||
Button: ButtonComponent,
|
||||
LinkButton: LinkButtonComponent,
|
||||
ExternalLinkButton: ExternalLinkButtonComponent,
|
||||
IconButton: IconButtonComponent,
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
@@ -64,6 +67,10 @@ const ExternalLinkButtonTemplate: StoryFn<ComponentProps<typeof ExternalLinkButt
|
||||
<ExternalLinkButtonComponent {...args} />
|
||||
);
|
||||
|
||||
const IconButtonTemplate: StoryFn<ComponentProps<typeof IconButtonComponent>> = (args) => (
|
||||
<IconButtonComponent {...args} />
|
||||
);
|
||||
|
||||
export const Button = ButtonTemplate.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
Button.args = {
|
||||
@@ -87,3 +94,41 @@ ExternalLinkButton.args = {
|
||||
href: "https://scm-manager.org",
|
||||
variant: ButtonVariants.PRIMARY,
|
||||
};
|
||||
|
||||
const smallIcon = <Icon className="is-small">trash</Icon>;
|
||||
const mediumIcon = <Icon className="is-medium">trash</Icon>;
|
||||
|
||||
/*
|
||||
|
||||
Variant and size are defaulted to medium and colored and do not have to be explicitly added as parameters.
|
||||
However for the sake of documentation here they are still passed in
|
||||
|
||||
*/
|
||||
export const IconButtonBorder = IconButtonTemplate.bind({});
|
||||
IconButtonBorder.args = {
|
||||
children: mediumIcon,
|
||||
variant: "colored",
|
||||
size: "medium",
|
||||
};
|
||||
|
||||
|
||||
export const IconButtonBorderDefault = IconButtonTemplate.bind({});
|
||||
IconButtonBorderDefault.args = {
|
||||
children: mediumIcon,
|
||||
variant: "default",
|
||||
size: "medium",
|
||||
};
|
||||
|
||||
export const IconButtonBorderlessSmall = IconButtonTemplate.bind({});
|
||||
IconButtonBorderlessSmall.args = {
|
||||
children: smallIcon,
|
||||
variant: "colored",
|
||||
size: "small",
|
||||
};
|
||||
|
||||
export const IconButtonBorderlessSmallDefault = IconButtonTemplate.bind({});
|
||||
IconButtonBorderlessSmallDefault.args = {
|
||||
children: smallIcon,
|
||||
variant: "default",
|
||||
size: "small",
|
||||
};
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from "react";
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from "react";
|
||||
import { Link as ReactRouterLink, LinkProps as ReactRouterLinkProps } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { createAttributesForTesting } from "../helpers";
|
||||
import styled from "styled-components";
|
||||
|
||||
/**
|
||||
* @beta
|
||||
@@ -141,3 +142,85 @@ export const ExternalLinkButton = React.forwardRef<HTMLAnchorElement, ExternalLi
|
||||
</ExternalLink>
|
||||
)
|
||||
);
|
||||
|
||||
const StyledIconButton = styled.button`
|
||||
border-radius: 6px !important;
|
||||
min-width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
padding: 0.5em;
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
background-color: color-mix(in srgb, currentColor 10%, transparent);
|
||||
}
|
||||
&:active {
|
||||
background-color: color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledIconButtonCircle = styled.button`
|
||||
border-radius: 50% !important;
|
||||
border: None;
|
||||
min-width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
padding: 0.5em;
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
background-color: color-mix(in srgb, currentColor 10%, transparent);
|
||||
}
|
||||
&:active {
|
||||
background-color: color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const IconButtonVariants = {
|
||||
COLORED: "colored",
|
||||
DEFAULT: "default",
|
||||
} as const;
|
||||
|
||||
export const IconSizes = {
|
||||
SMALL: "small",
|
||||
MEDIUM: "medium",
|
||||
} as const;
|
||||
|
||||
type IconButtonSize = typeof IconSizes[keyof typeof IconSizes];
|
||||
|
||||
type IconButtonVariant = typeof IconButtonVariants[keyof typeof IconButtonVariants];
|
||||
|
||||
const createIconButtonClasses = (variant?: IconButtonVariant) =>
|
||||
classNames("button", {
|
||||
"is-primary is-outlined": variant === "colored",
|
||||
});
|
||||
|
||||
type IconButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
testId?: string;
|
||||
variant?: IconButtonVariant;
|
||||
children: ReactNode;
|
||||
size?: IconButtonSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Styled html button.
|
||||
*
|
||||
* An icon button has to declare an `aria-label`.
|
||||
*
|
||||
* @beta
|
||||
* @since 3.2.0
|
||||
*/
|
||||
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
({ className, variant = "default", size = "medium", testId, type, children, ...props }, ref) => {
|
||||
const elementAttributes = {
|
||||
type: type ?? "button",
|
||||
...props,
|
||||
className: classNames(createIconButtonClasses(variant), "button", "has-background-transparent"),
|
||||
ref: ref,
|
||||
...createAttributesForTesting(testId),
|
||||
};
|
||||
return size === "small" ? (
|
||||
<StyledIconButtonCircle {...elementAttributes}>{children}</StyledIconButtonCircle>
|
||||
) : (
|
||||
<StyledIconButton {...elementAttributes}>{children}</StyledIconButton>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user