-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(primitive): add button component
- Loading branch information
1 parent
81ccb72
commit 6d4d267
Showing
5 changed files
with
221 additions
and
0 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
src/components/primitives/button/__tests__/button.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { createRef } from "react"; | ||
import { describe, it } from "@jest/globals"; | ||
import { fireEvent, render } from "@testing-library/react"; | ||
|
||
import { Button } from "../button"; | ||
|
||
describe("Primitives / Button", () => { | ||
it("Correct rendering and unmount", () => { | ||
const screen = render(<Button />); | ||
|
||
expect(() => screen.unmount()).not.toThrow(); | ||
}); | ||
|
||
it("Successful ref forwarding", () => { | ||
const ref = createRef<HTMLButtonElement>(); | ||
|
||
render(<Button ref={ref} />); | ||
|
||
expect(ref.current).not.toBeUndefined(); | ||
}); | ||
|
||
it("Verify that it is disabled", () => { | ||
const screen = render(<Button disabled />); | ||
const button = screen.getByRole("button") as HTMLInputElement; | ||
|
||
expect(button).toBeDisabled(); | ||
}); | ||
|
||
it("Should trigger onClick function", () => { | ||
const mockHandler = jest.fn(); | ||
const screen = render(<Button onClick={mockHandler} />); | ||
const button = screen.getByRole("button"); | ||
|
||
fireEvent.click(button); | ||
|
||
expect(mockHandler).toHaveBeenCalled(); | ||
}); | ||
|
||
it("Verify that you have the correct type attribute", () => { | ||
const screen = render(<Button type="submit" />); | ||
const button = screen.getByRole("button"); | ||
|
||
expect(button).toHaveAttribute("type", "submit"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import type { StoryObj, Meta } from "@storybook/react"; | ||
|
||
import { css } from "@root/styled-system/css"; | ||
import { stack } from "@root/styled-system/patterns"; | ||
|
||
import { Button } from "./button"; | ||
|
||
export default { | ||
title: "Primitives/Button", | ||
tags: ["autodocs"], | ||
decorators: [ | ||
(Story) => ( | ||
<div className={css({ p: "4" })}> | ||
<Story /> | ||
</div> | ||
), | ||
], | ||
} satisfies Meta<typeof Button>; | ||
|
||
type Story = StoryObj<typeof Button>; | ||
|
||
export const Preview: Story = { | ||
name: "Default Preview", | ||
args: { | ||
children: "Sample Text", | ||
}, | ||
render: (args) => <Button {...args} />, | ||
}; | ||
|
||
export const Sizes: Story = { | ||
render: () => ( | ||
<div className={stack({ gap: "3", direction: "row", flexWrap: "wrap" })}> | ||
<Button size="sm">Small</Button> | ||
<Button>Medium</Button> | ||
</div> | ||
), | ||
}; | ||
|
||
export const RecipeVariantProps: Story = { | ||
render: () => ( | ||
<div className={stack({ gap: "3", direction: "row", flexWrap: "wrap" })}> | ||
<Button>Outline</Button> | ||
<Button variant="solid">Solid</Button> | ||
<div className={css({ backgroundColor: "bg-primary-solid", p: "2" })}> | ||
<Button variant="solid-white">Solid White</Button> | ||
</div> | ||
</div> | ||
), | ||
}; | ||
|
||
export const OnlyIcon: Story = { | ||
render: () => ( | ||
<div className={stack({ gap: "3", direction: "row", flexWrap: "wrap" })}> | ||
<Button isIconOnly size="sm"> | ||
<svg height="20" viewBox="0 0 24 24" width="20"> | ||
<g fill="none" fillRule="nonzero"> | ||
<path d="M24 0v24H0V0h24ZM12.593 23.258l-.011.002-.071.035-.02.004-.014-.004-.071-.035c-.01-.004-.019-.001-.024.005l-.004.01-.017.428.005.02.01.013.104.074.015.004.012-.004.104-.074.012-.016.004-.017-.017-.427c-.002-.01-.009-.017-.017-.018Zm.265-.113-.013.002-.185.093-.01.01-.003.011.018.43.005.012.008.007.201.093c.012.004.023 0 .029-.008l.004-.014-.034-.614c-.003-.012-.01-.02-.02-.022Zm-.715.002a.023.023 0 0 0-.027.006l-.006.014-.034.614c0 .012.007.02.017.024l.015-.002.201-.093.01-.008.004-.011.017-.43-.003-.012-.01-.01-.184-.092Z" /> | ||
<path | ||
d="M21 5.18V17a4 4 0 1 1-2-3.465V9.181L9 10.847V18c0 .06-.005.117-.015.174A3.5 3.5 0 1 1 7 15.337v-8.49a2 2 0 0 1 1.671-1.973l10-1.666A2 2 0 0 1 21 5.18ZM5.5 17a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3ZM17 15a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm2-9.82L9 6.847V8.82l10-1.667V5.18Z" | ||
fill="#09244BFF" | ||
/> | ||
</g> | ||
</svg> | ||
</Button> | ||
<Button isIconOnly> | ||
<svg height="24" viewBox="0 0 24 24" width="24"> | ||
<g fill="none" fillRule="nonzero"> | ||
<path d="M24 0v24H0V0h24ZM12.593 23.258l-.011.002-.071.035-.02.004-.014-.004-.071-.035c-.01-.004-.019-.001-.024.005l-.004.01-.017.428.005.02.01.013.104.074.015.004.012-.004.104-.074.012-.016.004-.017-.017-.427c-.002-.01-.009-.017-.017-.018Zm.265-.113-.013.002-.185.093-.01.01-.003.011.018.43.005.012.008.007.201.093c.012.004.023 0 .029-.008l.004-.014-.034-.614c-.003-.012-.01-.02-.02-.022Zm-.715.002a.023.023 0 0 0-.027.006l-.006.014-.034.614c0 .012.007.02.017.024l.015-.002.201-.093.01-.008.004-.011.017-.43-.003-.012-.01-.01-.184-.092Z" /> | ||
<path | ||
d="M21 5.18V17a4 4 0 1 1-2-3.465V9.181L9 10.847V18c0 .06-.005.117-.015.174A3.5 3.5 0 1 1 7 15.337v-8.49a2 2 0 0 1 1.671-1.973l10-1.666A2 2 0 0 1 21 5.18ZM5.5 17a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3ZM17 15a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm2-9.82L9 6.847V8.82l10-1.667V5.18Z" | ||
fill="#09244BFF" | ||
/> | ||
</g> | ||
</svg> | ||
</Button> | ||
</div> | ||
), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { ButtonHTMLAttributes } from "react"; | ||
|
||
import { forwardRef } from "react"; | ||
import { button } from "@root/styled-system/recipes"; | ||
|
||
import type { RecipeVariantProps } from "@root/styled-system/css"; | ||
|
||
type ButtonElementProps = ButtonHTMLAttributes<HTMLButtonElement>; | ||
type RecipeProps = RecipeVariantProps<typeof button>; | ||
type Props = RecipeProps & Omit<ButtonElementProps, keyof RecipeProps>; | ||
|
||
export const Button = forwardRef<HTMLButtonElement, Props>( | ||
({ children, size, variant, className, isIconOnly, ...props }, ref) => { | ||
const classes = button({ size, variant, isIconOnly }); | ||
|
||
return ( | ||
// eslint-disable-next-line react/button-has-type | ||
<button ref={ref} className={`${classes} ${className ?? ""}`} {...props}> | ||
{children} | ||
</button> | ||
); | ||
}, | ||
); | ||
|
||
Button.displayName = "Button"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { defineRecipe } from "@pandacss/dev"; | ||
|
||
export default defineRecipe({ | ||
className: "button", | ||
base: { | ||
display: "inline-flex", | ||
alignItems: "center", | ||
justifyContent: "center", | ||
fontWeight: "700", | ||
cursor: "pointer", | ||
}, | ||
variants: { | ||
size: { | ||
sm: { | ||
height: "8", | ||
textStyle: "body-sm", | ||
px: "3", | ||
rounded: "md", | ||
}, | ||
md: { | ||
height: "10", | ||
textStyle: "body-base", | ||
px: "4", | ||
rounded: "lg", | ||
}, | ||
}, | ||
variant: { | ||
outline: { | ||
borderWidth: "1px", | ||
borderColor: "border-primary", | ||
borderStyle: "solid", | ||
backgroundColor: "transparent", | ||
color: "text-primary", | ||
}, | ||
solid: { | ||
backgroundColor: "bg-primary-solid", | ||
color: "white", | ||
}, | ||
"solid-white": { | ||
backgroundColor: "white", | ||
color: "text-primary", | ||
}, | ||
}, | ||
isIconOnly: { | ||
true: { | ||
rounded: "999px!", | ||
px: "0!", | ||
}, | ||
}, | ||
}, | ||
compoundVariants: [ | ||
{ | ||
isIconOnly: true, | ||
size: "md", | ||
css: { | ||
width: "10!", | ||
}, | ||
}, | ||
{ | ||
isIconOnly: true, | ||
size: "sm", | ||
css: { | ||
width: "8!", | ||
}, | ||
}, | ||
], | ||
defaultVariants: { | ||
size: "md", | ||
variant: "outline", | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters