Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit Button styles to those defined in the Comet design guidelines #3065

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changeset/olive-fans-invite.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Add new `Button` with optional responsive behavior to use in favor of MUI's `But

When setting the `responsive` prop, the button will only show the icon on mobile and show the text content in a tooltip.

This works the same as MUI's `Button` component, with the exception of the `variant` and `color` props that are not supported in the same way.
This `Button` only supports values for `variant` that are defined by the Comet design guidelines, the `color` prop cannot be used.

```diff
-import { Button } from "@mui/material";
+import { Button } from "@comet/admin";
Expand Down
22 changes: 19 additions & 3 deletions packages/admin/admin/src/common/buttons/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,37 @@ import { createComponentSlot } from "../../helpers/createComponentSlot";
import { ThemedComponentBaseProps } from "../../helpers/ThemedComponentBaseProps";
import { useWindowSize } from "../../helpers/useWindowSize";

type Variant = "primary" | "secondary" | "outlined" | "destructive" | "success" | "textLight" | "textDark";
type Slot = "root" | "mobileTooltip";
type ComponentState = "usingResponsiveBehavior";
type ComponentState = Variant | "usingResponsiveBehavior";
export type ButtonClassKey = Slot | ComponentState;

export type ButtonProps = MuiButtonProps &
export type ButtonProps = Omit<MuiButtonProps, "variant" | "color"> &
ThemedComponentBaseProps<{
root: typeof MuiButton;
mobileTooltip: typeof Tooltip;
}> & {
variant?: Variant;
responsive?: boolean;
mobileIcon?: "auto" | "startIcon" | "endIcon" | ReactNode;
mobileBreakpoint?: Breakpoint;
};

type OwnerState = {
variant: Variant;
usingResponsiveBehavior: boolean;
};

const variantToMuiProps: Record<Variant, Partial<MuiButtonProps>> = {
primary: { variant: "contained", color: "primary" },
secondary: { variant: "contained", color: "secondary" },
outlined: { variant: "outlined" },
destructive: { variant: "outlined", color: "error" },
success: { variant: "contained", color: "success" },
textLight: { variant: "text", sx: { color: "white" } },
textDark: { variant: "text", sx: { color: "black" } },
};

const getMobileIconNode = ({ mobileIcon, startIcon, endIcon }: Pick<ButtonProps, "mobileIcon" | "startIcon" | "endIcon">) => {
if (mobileIcon === "auto") {
return startIcon || endIcon;
Expand All @@ -52,6 +65,7 @@ const getMobileIconNode = ({ mobileIcon, startIcon, endIcon }: Pick<ButtonProps,
export const Button = (inProps: ButtonProps) => {
const {
slotProps,
variant = "primary",
responsive,
mobileIcon = "auto",
mobileBreakpoint = "sm",
Expand All @@ -71,10 +85,12 @@ export const Button = (inProps: ButtonProps) => {
}

const ownerState: OwnerState = {
variant,
usingResponsiveBehavior: Boolean(responsive) && windowSize.width < theme.breakpoints.values[mobileBreakpoint],
};

const commonButtonProps = {
...variantToMuiProps[variant],
...restProps,
ownerState,
...slotProps?.root,
Expand All @@ -101,7 +117,7 @@ const Root = createComponentSlot(MuiButton)<ButtonClassKey, OwnerState>({
componentName: "Button",
slotName: "root",
classesResolver(ownerState) {
return [ownerState.usingResponsiveBehavior && "usingResponsiveBehavior"];
return [ownerState.usingResponsiveBehavior && "usingResponsiveBehavior", ownerState.variant];
},
})(
({ ownerState }) => css`
Expand Down
87 changes: 83 additions & 4 deletions storybook/src/admin/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,93 @@
import { Button } from "@comet/admin";
import { Button, ButtonProps } from "@comet/admin";
import { Add, Favorite, Wrench } from "@comet/admin-icons";
import { Stack } from "@mui/material";
import { Box, Stack } from "@mui/material";
import { ReactNode } from "react";

export default {
title: "@comet/admin/Button",
};

type DefaultStoryArgs = {
variant: ButtonProps["variant"];
responsive: boolean;
disabled: boolean;
startIcon: boolean;
endIcon: boolean;
};

export const Default = {
parameters: {
layout: "fullscreen",
},
args: {
variant: "primary",
responsive: false,
disabled: false,
startIcon: true,
endIcon: false,
},
argTypes: {
variant: {
name: "Variant",
control: "select",
options: ["primary", "secondary", "outlined", "destructive", "success", "textLight", "textDark"],
},
responsive: {
name: "Responsive",
control: "boolean",
},
disabled: {
name: "Disabled",
control: "boolean",
},
startIcon: {
name: "Start Icon",
control: "boolean",
},
endIcon: {
name: "End Icon",
control: "boolean",
},
},

render: ({ startIcon, endIcon, disabled, variant, responsive }: DefaultStoryArgs) => {
const showDarkBackground = variant === "textLight";

return (
<Box py={10} px={8} bgcolor={showDarkBackground ? "#333" : "transparent"}>
<Button
onClick={() => {
alert("Button clicked");
}}
startIcon={startIcon ? <Wrench /> : undefined}
endIcon={endIcon ? <Favorite /> : undefined}
disabled={disabled}
variant={variant}
responsive={responsive}
>
This is a button
</Button>
</Box>
);
},
};

export const AllVariants = {
render: () => {
return (
<Stack direction="row" spacing={2}>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="success">Success</Button>
<Button variant="textLight">Text Light</Button>
<Button variant="textDark">Text Dark</Button>
</Stack>
);
},
};

type ResponsiveArgs = {
startIcon: boolean;
endIcon: boolean;
Expand Down Expand Up @@ -54,8 +135,6 @@ export const Responsive = {
<Stack direction="row" spacing={2}>
<Button
responsive
variant="contained"
color="primary"
startIcon={startIcon ? <Wrench /> : undefined}
endIcon={endIcon ? <Add /> : undefined}
mobileIcon={mobileIcon === "custom" ? customMobileIcon : mobileIcon}
Expand Down
4 changes: 2 additions & 2 deletions storybook/src/admin/toolbar/Toolbar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ function Story() {
</ToolbarItem>
<FillSpace />
<ToolbarActions>
<Button responsive startIcon={<ArrowRight />}>
<Button responsive startIcon={<ArrowRight />} variant="outlined">
Secondary button
</Button>
<Button responsive startIcon={<Save />} variant="contained">
<Button responsive startIcon={<Save />}>
Primary button
</Button>
</ToolbarActions>
Expand Down
Loading