Skip to content

Commit

Permalink
Button / IconButton / LinkButton: add Cambio variants
Browse files Browse the repository at this point in the history
  • Loading branch information
christianvuerings committed Feb 26, 2024
1 parent 8920a56 commit a0e32a6
Show file tree
Hide file tree
Showing 18 changed files with 736 additions and 78 deletions.
7 changes: 7 additions & 0 deletions .changeset/dull-pandas-build.md
@@ -0,0 +1,7 @@
---
"@cambly/syntax-design-tokens": minor
"@cambly/syntax-core": minor
"@syntax/storybook": minor
---

Add ThemeProvider & styles for Button / IconButton & LinkButton
14 changes: 13 additions & 1 deletion apps/storybook/stories/Colors.tsx
Expand Up @@ -4,7 +4,10 @@ import variables from "../../../packages/syntax-design-tokens/dist/json/variable
export default function Colors() {
const groupColors = Object.entries(variables).reduce(
(acc, [key, value]) => {
if (
if (key.includes("cambio")) {
// @ts-expect-error
acc["Cambio"].push({ key, value });
} else if (
key.includes("black") ||
key.includes("white") ||
key.includes("gray")
Expand All @@ -25,6 +28,7 @@ export default function Colors() {
return acc;
},
{
Cambio: [],
Grayscale: [],
Primary: [],
Destructive: [],
Expand All @@ -46,6 +50,14 @@ export default function Colors() {
style={{
color:
[
"color-cambio-white",
"color-cambio-gray-88",
"color-cambio-gray-96",
"color-cambio-cream",
"color-cambio-pink",
"color-cambio-sky",
"color-cambio-yellow",
"color-cambio-transparent-full",
"color-base-gray-10",
"color-base-gray-30",
"color-base-white",
Expand Down
18 changes: 18 additions & 0 deletions packages/syntax-core/src/Button/Button.module.css
Expand Up @@ -90,6 +90,12 @@
border-radius: 100px;
}

.xlCambio {
height: 80px;
padding: 0 40px;
border-radius: 100px;
}

.icon {
color: inherit;
}
Expand Down Expand Up @@ -123,6 +129,18 @@
border: 1px solid var(--color-base-destructive-300);
}

.cambioSecondaryBorder {
border: 1px solid var(--color-cambio-black);
}

.cambioSecondaryDestructiveBorder {
border: 1px solid var(--color-cambio-destructive);
}

.cambioSecondarySuccessBorder {
border: 1px solid var(--color-cambio-success);
}

@keyframes syntaxButtonLoadingRotate {
0% {
transform-origin: 50% 50%;
Expand Down
5 changes: 4 additions & 1 deletion packages/syntax-core/src/Button/Button.stories.tsx
Expand Up @@ -17,17 +17,20 @@ export default {
"primary",
"secondary",
"tertiary",
"quaternary",
"destructive-primary",
"destructive-secondary",
"destructive-tertiary",
"success",
"success-primary",
"success-secondary",
"branded",
"inverse",
],
control: { type: "radio" },
},
size: {
options: ["sm", "md", "lg"],
options: ["sm", "md", "lg", "xl"],
control: { type: "radio" },
},
disabled: {
Expand Down
101 changes: 78 additions & 23 deletions packages/syntax-core/src/Button/Button.tsx
@@ -1,19 +1,24 @@
import React, { forwardRef } from "react";
import classNames from "classnames";

import backgroundColor from "../colors//backgroundColor";
import foregroundColor from "../colors/foregroundColor";
import foregroundTypographyColor from "../colors/foregroundTypographyColor";
import { type Size } from "../constants";
import Typography from "../Typography/Typography";
import Box from "../Box/Box";

import iconSize from "./constants/iconSize";
import textVariant from "./constants/textVariant";
import loadingIconSize from "./constants/loadingIconSize";
import styles from "./Button.module.css";
import useIsHydrated from "../useIsHydrated";
import { useTheme } from "../ThemeProvider/ThemeProvider";
import { classicColor, cambioColor } from "./constants/color";
import {
classicBackgroundColor,
cambioBackgroundColor,
} from "../colors/backgroundColor";
import {
classicForegroundColor,
cambioForegroundColor,
} from "../colors/foregroundColor";
import classicSize from "./constants/classicSize";

type ButtonProps = {
/**
Expand All @@ -31,25 +36,46 @@ type ButtonProps = {
/**
* The color of the button
*
* Classic only:
* * `success-primary`
* * `success-secondary`
* * `inverse`
*
* Cambio only:
* * `quaternary`
* * `destructive-tertiary`
* * `success-primary`
* * `success-secondary`
*
* @defaultValue "primary"
*/
color?:
| "primary"
| "secondary"
| "tertiary"
| "quaternary"
| "destructive-primary"
| "destructive-secondary"
| "destructive-tertiary"
| "branded"
| "success"
| "success-primary"
| "success-secondary"
| "inverse";
/**
* The size of the button
*
* Classic:
* * `sm`: 32px
* * `md`: 40px
* * `lg`: 48px
*
* Cambio:
* * `sm`: 32px
* * `md`: 48px
* * `lg`: 64px
* * `xl`: 80px
*
* @defaultValue "md"
*/
size?: (typeof Size)[number];
Expand Down Expand Up @@ -77,10 +103,12 @@ type ButtonProps = {
fullWidth?: boolean;
/**
* The icon to be displayed at the start of the button. Please use a [Rounded Material Icon](https://material.io/resources/icons/?style=round)
* Note: startIcon is not supported in the Cambio theme
*/
startIcon?: React.ComponentType<{ className?: string }>;
/**
* The icon to be displayed at the end of the button. Please use a [Rounded Material Icon](https://material.io/resources/icons/?style=round)
* Note: endIcon is not supported in the Cambio theme
*/
endIcon?: React.ComponentType<{ className?: string }>;
/**
Expand Down Expand Up @@ -123,6 +151,16 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
const isHydrated = useIsHydrated();
const { themeName } = useTheme();

const foregroundColorClass =
themeName === "classic"
? classicForegroundColor(classicColor(color))
: cambioForegroundColor(cambioColor(color));

const backgroundColorClass =
themeName === "classic"
? classicBackgroundColor(classicColor(color))
: cambioBackgroundColor(cambioColor(color));

return (
<button
data-testid={dataTestId}
Expand All @@ -134,42 +172,59 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
onClick={onClick}
className={classNames(
styles.button,
foregroundColor(color),
backgroundColor(color),
themeName === "classic" ? styles[size] : styles[`${size}Cambio`],
foregroundColorClass,
backgroundColorClass,
themeName === "classic"
? styles[classicSize(size)]
: styles[`${size}Cambio`],
{
[styles.fullWidth]: fullWidth,
[styles.buttonGap]: size === "lg" || size === "md",
[styles.secondaryBorder]: color === "secondary",
[styles.buttonGap]:
themeName === "classic" && (size === "lg" || size === "md"),
[styles.secondaryBorder]:
themeName === "classic" && color === "secondary",
[styles.secondaryDestructiveBorder]:
color === "destructive-secondary",
themeName === "classic" && color === "destructive-secondary",
[styles.cambioSecondaryBorder]:
themeName === "cambio" && color === "secondary",
[styles.cambioSecondaryDestructiveBorder]:
themeName === "cambio" &&
(color === "destructive-secondary" ||
color === "destructive-tertiary"),
[styles.cambioSecondarySuccessBorder]:
themeName === "cambio" && color === "success-secondary",
},
)}
>
{!loading && StartIcon && (
<StartIcon className={classNames(styles.icon, iconSize[size])} />
{!loading && StartIcon && themeName === "classic" && (
<StartIcon
className={classNames(styles.icon, iconSize[classicSize(size)])}
/>
)}
{((loading && loadingText) || (!loading && text)) && (
<Box paddingX={1}>
<Typography
size={textVariant[size]}
color={foregroundTypographyColor(color)}
>
<span style={{ fontWeight: 500 }}>
<Typography size={textVariant[classicSize(size)]}>
<span
// Temporary - until we have cambio colors on Typogrphay
className={foregroundColorClass}
style={{ fontWeight: 500 }}
>
{loading ? loadingText : text}
</span>
</Typography>
</Box>
)}
{!loading && EndIcon && (
<EndIcon className={classNames(styles.icon, iconSize[size])} />
{!loading && EndIcon && themeName === "classic" && (
<EndIcon
className={classNames(styles.icon, iconSize[classicSize(size)])}
/>
)}
{loading && (
<svg
className={classNames(styles.loading, foregroundColor(color))}
className={classNames(styles.loading, foregroundColorClass)}
viewBox="22 22 44 44"
width={loadingIconSize[size]}
height={loadingIconSize[size]}
width={loadingIconSize[classicSize(size)]}
height={loadingIconSize[classicSize(size)]}
>
<circle
className={styles.loadingCircle}
Expand Down
5 changes: 5 additions & 0 deletions packages/syntax-core/src/Button/constants/classicSize.ts
@@ -0,0 +1,5 @@
export default function classicSize(
size: "sm" | "md" | "lg" | "xl",
): "sm" | "md" | "lg" {
return size === "xl" ? "lg" : size;
}
66 changes: 66 additions & 0 deletions packages/syntax-core/src/Button/constants/color.ts
@@ -0,0 +1,66 @@
export function classicColor(
color:
| "primary"
| "secondary"
| "tertiary"
| "quaternary"
| "destructive-primary"
| "destructive-secondary"
| "destructive-tertiary"
| "branded"
| "success"
| "success-primary"
| "success-secondary"
| "inverse",
):
| "primary"
| "secondary"
| "tertiary"
| "destructive-primary"
| "destructive-secondary"
| "branded"
| "success"
| "inverse" {
if (color === "quaternary") {
return "inverse";
} else if (color === "destructive-tertiary") {
return "destructive-secondary";
} else if (color === "success-primary" || color === "success-secondary") {
return "success";
}
return color;
}

export function cambioColor(
color:
| "primary"
| "secondary"
| "tertiary"
| "quaternary"
| "destructive-primary"
| "destructive-secondary"
| "destructive-tertiary"
| "branded"
| "success"
| "success-primary"
| "success-secondary"
| "inverse",
):
| "primary"
| "secondary"
| "tertiary"
| "quaternary"
| "destructive-primary"
| "destructive-secondary"
| "branded"
| "success-primary"
| "success-secondary" {
if (color === "success") {
return "success-primary";
} else if (color === "destructive-tertiary") {
return "destructive-secondary";
} else if (color === "inverse") {
return "quaternary";
}
return color;
}
6 changes: 3 additions & 3 deletions packages/syntax-core/src/Button/constants/loadingIconSize.ts
@@ -1,7 +1,7 @@
const loadingIconSize = {
["sm"]: 16,
["md"]: 20,
["lg"]: 24,
sm: 16,
md: 20,
lg: 24,
};

export default loadingIconSize;
7 changes: 4 additions & 3 deletions packages/syntax-core/src/Button/constants/textVariant.ts
@@ -1,7 +1,8 @@
const textVariant = {
["sm"]: 100,
["md"]: 200,
["lg"]: 300,
sm: 100,
md: 200,
lg: 300,
xl: 500,
} as const;

export default textVariant;

0 comments on commit a0e32a6

Please sign in to comment.