diff --git a/packages/documentation/src/Components/ButtonIcon.stories.tsx b/packages/documentation/src/Components/ButtonIcon.stories.tsx index 7cfabf65..6f04a669 100644 --- a/packages/documentation/src/Components/ButtonIcon.stories.tsx +++ b/packages/documentation/src/Components/ButtonIcon.stories.tsx @@ -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 = (args) => (
@@ -19,20 +25,44 @@ export const Basic: Story = (args) => ( ); export const WithLabel: Story = (args) => ( -
- - - - - - - - - - - - -
+ <> +
+ + + + + + + + + + + + +
+
+ + + + + + + + + + + + +
+
+ + + + + + +
+ ); export default { diff --git a/packages/ui-components/src/components/Button/ButtonIcon.tsx b/packages/ui-components/src/components/Button/ButtonIcon.tsx index 94aa083f..b3fdb1f8 100644 --- a/packages/ui-components/src/components/Button/ButtonIcon.tsx +++ b/packages/ui-components/src/components/Button/ButtonIcon.tsx @@ -19,6 +19,7 @@ export const ButtonIcon = React.forwardRef( label, size = "medium", labelRight, + labelLeft, spacing, ...otherProps @@ -36,6 +37,7 @@ export const ButtonIcon = React.forwardRef( noBorder, size, labelRight, + labelLeft, spacing, }); @@ -48,6 +50,7 @@ export const ButtonIcon = React.forwardRef( aria-label={ariaLabel || label} {...otherProps} > + {labelLeft && {labelLeft}} {children} {labelRight && {labelRight}} diff --git a/packages/ui-components/src/components/Button/ButtonTypes.d.ts b/packages/ui-components/src/components/Button/ButtonTypes.d.ts index 19db3117..2507299d 100644 --- a/packages/ui-components/src/components/Button/ButtonTypes.d.ts +++ b/packages/ui-components/src/components/Button/ButtonTypes.d.ts @@ -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. */ diff --git a/packages/ui-components/src/components/Button/__tests__/ButtonIcon.test.tsx b/packages/ui-components/src/components/Button/__tests__/ButtonIcon.test.tsx index 7dee5386..8cf93504 100644 --- a/packages/ui-components/src/components/Button/__tests__/ButtonIcon.test.tsx +++ b/packages/ui-components/src/components/Button/__tests__/ButtonIcon.test.tsx @@ -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( @@ -28,7 +28,7 @@ describe("ButtonIcon modifiers", () => { ]); }); - it("should render a dark button", async () => { + it("should render a dark button icon", async () => { render( @@ -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( @@ -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( @@ -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( @@ -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( @@ -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( @@ -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( @@ -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( + + + , + ); + 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( @@ -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( @@ -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( + + + , + ); + 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( @@ -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( @@ -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( + + + , + ); + 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"]); }); }); diff --git a/packages/ui-components/src/components/Button/utilities.ts b/packages/ui-components/src/components/Button/utilities.ts index d78df65f..34a39bca 100644 --- a/packages/ui-components/src/components/Button/utilities.ts +++ b/packages/ui-components/src/components/Button/utilities.ts @@ -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; @@ -28,9 +29,11 @@ const getButtonSizesClasses = ({ slim, size, labelRight, + labelLeft, }: { size: string; type: string; + labelLeft?: string; labelRight?: string; slim?: boolean; }) => { @@ -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), }); } }; @@ -128,6 +130,7 @@ export const getButtonClasses = ({ size, noBorder, labelRight, + labelLeft, spacing, }: getButtonClassesProps) => { return raw @@ -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 }),