Skip to content

Commit

Permalink
feat(ButtonIcon): adding support for labelLeft
Browse files Browse the repository at this point in the history
  • Loading branch information
aversini committed Feb 18, 2024
1 parent a59fbab commit 29b657e
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 60 deletions.
60 changes: 45 additions & 15 deletions packages/documentation/src/Components/ButtonIcon.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { Story } from "@ladle/react";
import { ButtonIcon, IconEdit, IconSettings } from "@versini/ui-components";
import {
ButtonIcon,
IconEdit,
IconNext,
IconPrevious,
IconSettings,
} from "@versini/ui-components";

export const Basic: Story<any> = (args) => (
<div className="flex flex-wrap">
Expand All @@ -19,20 +25,44 @@ export const Basic: Story<any> = (args) => (
);

export const WithLabel: Story<any> = (args) => (
<div className="flex flex-wrap">
<ButtonIcon labelRight="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelRight="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelRight="Edit" {...args}>
<IconEdit decorative className="h-3 w-3" />
</ButtonIcon>
<ButtonIcon labelRight="Edit" {...args}>
<IconEdit decorative />
</ButtonIcon>
</div>
<>
<div className="flex flex-wrap">
<ButtonIcon labelRight="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelRight="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelRight="Edit" {...args}>
<IconEdit decorative className="h-3 w-3" />
</ButtonIcon>
<ButtonIcon labelRight="Edit" {...args}>
<IconEdit decorative />
</ButtonIcon>
</div>
<div className="mt-2 flex flex-wrap">
<ButtonIcon labelLeft="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelLeft="Settings" {...args}>
<IconSettings decorative />
</ButtonIcon>
<ButtonIcon labelLeft="Edit" {...args}>
<IconEdit decorative className="h-3 w-3" />
</ButtonIcon>
<ButtonIcon labelLeft="Edit" {...args}>
<IconEdit decorative />
</ButtonIcon>
</div>
<div className="mt-2 flex flex-wrap">
<ButtonIcon labelRight="Previous page" {...args}>
<IconPrevious decorative monotone />
</ButtonIcon>
<ButtonIcon labelLeft="Next page" {...args}>
<IconNext decorative monotone />
</ButtonIcon>
</div>
</>
);

export default {
Expand Down
3 changes: 3 additions & 0 deletions packages/ui-components/src/components/Button/ButtonIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ButtonIcon = React.forwardRef<HTMLButtonElement, ButtonIconProps>(
label,
size = "medium",
labelRight,
labelLeft,
spacing,

...otherProps
Expand All @@ -36,6 +37,7 @@ export const ButtonIcon = React.forwardRef<HTMLButtonElement, ButtonIconProps>(
noBorder,
size,
labelRight,
labelLeft,
spacing,
});

Expand All @@ -48,6 +50,7 @@ export const ButtonIcon = React.forwardRef<HTMLButtonElement, ButtonIconProps>(
aria-label={ariaLabel || label}
{...otherProps}
>
{labelLeft && <span className="pr-2">{labelLeft}</span>}
{children}
{labelRight && <span className="pl-2">{labelRight}</span>}
</button>
Expand Down
4 changes: 4 additions & 0 deletions packages/ui-components/src/components/Button/ButtonTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export type ButtonIconProps = {
* The label to show next to the icon.
*/
label?: string;
/**
* The label to show to the left of the icon.
*/
labelLeft?: string;
/**
* The label to show to the right of the icon.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("ButtonIcon (exceptions)", () => {
});

describe("ButtonIcon modifiers", () => {
it("should render a default button", async () => {
it("should render a default button icon", async () => {
render(
<ButtonIcon>
<IconSettings />
Expand All @@ -28,7 +28,7 @@ describe("ButtonIcon modifiers", () => {
]);
});

it("should render a dark button", async () => {
it("should render a dark button icon", async () => {
render(
<ButtonIcon kind="dark">
<IconSettings />
Expand All @@ -40,7 +40,7 @@ describe("ButtonIcon modifiers", () => {
expect(buttonClass).toContain("bg-action-dark");
});

it("should render a light button", async () => {
it("should render a light button icon", async () => {
render(
<ButtonIcon kind="light">
<IconSettings />
Expand All @@ -52,7 +52,7 @@ describe("ButtonIcon modifiers", () => {
expect(buttonClass).toContain("bg-action-light");
});

it("should render a disabled dark button", async () => {
it("should render a disabled dark button icon", async () => {
render(
<ButtonIcon kind="dark" disabled>
<IconSettings />
Expand All @@ -64,7 +64,7 @@ describe("ButtonIcon modifiers", () => {
expect(buttonClass).toContain("disabled:cursor-not-allowed");
});

it("should render a disabled light button", async () => {
it("should render a disabled light button icon", async () => {
render(
<ButtonIcon kind="light" disabled>
<IconSettings />
Expand All @@ -76,7 +76,7 @@ describe("ButtonIcon modifiers", () => {
expect(buttonClass).toContain("disabled:cursor-not-allowed");
});

it("should render a fullWidth button", async () => {
it("should render a fullWidth button icon", async () => {
render(
<ButtonIcon fullWidth>
<IconSettings />
Expand All @@ -86,7 +86,7 @@ describe("ButtonIcon modifiers", () => {
expect(button.className).toContain("w-full");
});

it("should render a size small button", async () => {
it("should render a size small button icon", async () => {
render(
<ButtonIcon size="small">
<IconSettings />
Expand All @@ -96,7 +96,7 @@ describe("ButtonIcon modifiers", () => {
expectToHaveClasses(button, ["h-6", "w-6", "p-0"]);
});

it("should render a size small button with a label on the right", async () => {
it("should render a size small button icon with a label on the right", async () => {
render(
<ButtonIcon size="small" labelRight="Settings">
<IconSettings decorative />
Expand All @@ -105,16 +105,22 @@ describe("ButtonIcon modifiers", () => {
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, [
"h-6",
"pl-2",
"pr-4",
"text-sm",
"font-medium",
]);
expectToHaveClasses(button, ["h-6", "px-4", "text-sm", "font-medium"]);
});

it("should render a size medium button", async () => {
it("should render a size small button icon with a label on the left", async () => {
render(
<ButtonIcon size="small" labelLeft="Settings">
<IconSettings decorative />
</ButtonIcon>,
);
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, ["h-6", "px-4", "text-sm", "font-medium"]);
});

it("should render a size medium button icon", async () => {
render(
<ButtonIcon size="medium">
<IconSettings />
Expand All @@ -124,7 +130,7 @@ describe("ButtonIcon modifiers", () => {
expectToHaveClasses(button, ["h-8", "w-8", "p-1"]);
});

it("should render a size medium button with a label on the right", async () => {
it("should render a size medium button icon with a label on the right", async () => {
render(
<ButtonIcon size="medium" labelRight="Settings">
<IconSettings decorative />
Expand All @@ -133,16 +139,22 @@ describe("ButtonIcon modifiers", () => {
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, [
"h-8",
"pl-2",
"pr-4",
"text-base",
"font-medium",
]);
expectToHaveClasses(button, ["h-8", "px-4", "text-base", "font-medium"]);
});

it("should render a size large button", async () => {
it("should render a size medium button icon with a label on the left", async () => {
render(
<ButtonIcon size="medium" labelLeft="Settings">
<IconSettings decorative />
</ButtonIcon>,
);
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, ["h-8", "px-4", "text-base", "font-medium"]);
});

it("should render a size large button icon", async () => {
render(
<ButtonIcon size="large">
<IconSettings />
Expand All @@ -152,7 +164,7 @@ describe("ButtonIcon modifiers", () => {
expectToHaveClasses(button, ["h-12", "w-12", "p-2"]);
});

it("should render a size large button with a label on the right", async () => {
it("should render a size large button icon with a label on the right", async () => {
render(
<ButtonIcon size="large" labelRight="Settings">
<IconSettings decorative />
Expand All @@ -161,12 +173,18 @@ describe("ButtonIcon modifiers", () => {
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, [
"h-12",
"pl-2",
"pr-4",
"text-lg",
"font-medium",
]);
expectToHaveClasses(button, ["h-12", "px-4", "text-lg", "font-medium"]);
});

it("should render a size large button icon with a label on the left", async () => {
render(
<ButtonIcon size="large" labelLeft="Settings">
<IconSettings decorative />
</ButtonIcon>,
);
const button = await screen.findByRole("button");
const label = await screen.findByText("Settings");
expect(label).toBeDefined();
expectToHaveClasses(button, ["h-12", "px-4", "text-lg", "font-medium"]);
});
});
27 changes: 15 additions & 12 deletions packages/ui-components/src/components/Button/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type getButtonClassesProps = {
type: typeof TYPE_BUTTON | typeof TYPE_ICON | typeof TYPE_LINK;

className?: string;
labelLeft?: string;
labelRight?: string;
slim?: boolean;
} & SpacingProps;
Expand All @@ -28,9 +29,11 @@ const getButtonSizesClasses = ({
slim,
size,
labelRight,
labelLeft,
}: {
size: string;
type: string;
labelLeft?: string;
labelRight?: string;
slim?: boolean;
}) => {
Expand All @@ -55,17 +58,16 @@ const getButtonSizesClasses = ({

case TYPE_ICON:
return clsx("inline-flex items-center justify-center", {
"h-6 w-6 p-0": (size === "small" || slim) && !labelRight,
"h-6 pl-2 pr-4 text-sm font-medium":
(size === "small" || slim) && labelRight,

"h-8 w-8 p-1": size === "medium" && !slim && !labelRight,
"h-8 pl-2 pr-4 text-base font-medium":
size === "medium" && !slim && labelRight,

"h-12 w-12 p-2": size === "large" && !slim && !labelRight,
"h-12 pl-2 pr-4 text-lg font-medium":
size === "large" && !slim && labelRight,
"h-6 w-6 p-0": (size === "small" || slim) && !(labelRight || labelLeft),
"h-6 px-4 text-sm font-medium":
(size === "small" || slim) && (labelRight || labelLeft),
"h-8 w-8 p-1": size === "medium" && !slim && !(labelRight || labelLeft),
"h-8 px-4 text-base font-medium":
size === "medium" && !slim && (labelRight || labelLeft),
"h-12 w-12 p-2":
size === "large" && !slim && !(labelRight || labelLeft),
"h-12 px-4 text-lg font-medium":
size === "large" && !slim && (labelRight || labelLeft),
});
}
};
Expand Down Expand Up @@ -128,6 +130,7 @@ export const getButtonClasses = ({
size,
noBorder,
labelRight,
labelLeft,
spacing,
}: getButtonClassesProps) => {
return raw
Expand All @@ -137,7 +140,7 @@ export const getButtonClasses = ({
className,
getSpacing(spacing),
getButtonBaseClasses({ kind }),
getButtonSizesClasses({ type, slim, size, labelRight }),
getButtonSizesClasses({ type, slim, size, labelRight, labelLeft }),
getButtonBorderClasses({ kind, noBorder }),
getButtonFocusClasses({ focus }),
getButtonHoverClasses({ kind, disabled }),
Expand Down

0 comments on commit 29b657e

Please sign in to comment.