+
+
+ Theme Button
+
+
+
+
diff --git a/apps/landing/src/app/(detail)/components/pagination/page.mdx b/apps/landing/src/app/(detail)/components/pagination/page.mdx
new file mode 100644
index 00000000..4122fb7d
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/pagination/page.mdx
@@ -0,0 +1 @@
+# Pagination
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/progress-bar/page.mdx b/apps/landing/src/app/(detail)/components/progress-bar/page.mdx
new file mode 100644
index 00000000..2d2f5244
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/progress-bar/page.mdx
@@ -0,0 +1 @@
+# Progress Bar
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/radio/page.mdx b/apps/landing/src/app/(detail)/components/radio/page.mdx
new file mode 100644
index 00000000..4f02c541
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/radio/page.mdx
@@ -0,0 +1 @@
+# Radio
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/search/page.mdx b/apps/landing/src/app/(detail)/components/search/page.mdx
new file mode 100644
index 00000000..da070d7f
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/search/page.mdx
@@ -0,0 +1 @@
+# Search
diff --git a/apps/landing/src/app/(detail)/components/select/page.mdx b/apps/landing/src/app/(detail)/components/select/page.mdx
new file mode 100644
index 00000000..c8a42305
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/select/page.mdx
@@ -0,0 +1 @@
+# Select
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/slider/page.mdx b/apps/landing/src/app/(detail)/components/slider/page.mdx
new file mode 100644
index 00000000..b6e8eab4
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/slider/page.mdx
@@ -0,0 +1 @@
+# Slider
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/snackbar/page.mdx b/apps/landing/src/app/(detail)/components/snackbar/page.mdx
new file mode 100644
index 00000000..a4e74fb1
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/snackbar/page.mdx
@@ -0,0 +1 @@
+# Snackbar
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/stepper/page.mdx b/apps/landing/src/app/(detail)/components/stepper/page.mdx
new file mode 100644
index 00000000..dd8d1281
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/stepper/page.mdx
@@ -0,0 +1 @@
+# Stepper
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/tab/page.mdx b/apps/landing/src/app/(detail)/components/tab/page.mdx
new file mode 100644
index 00000000..826dec4f
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/tab/page.mdx
@@ -0,0 +1 @@
+# Tab
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/text-area/page.mdx b/apps/landing/src/app/(detail)/components/text-area/page.mdx
new file mode 100644
index 00000000..b1421398
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/text-area/page.mdx
@@ -0,0 +1 @@
+# Text Area
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/text-box/page.mdx b/apps/landing/src/app/(detail)/components/text-box/page.mdx
new file mode 100644
index 00000000..6291142c
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/text-box/page.mdx
@@ -0,0 +1 @@
+# Text Box
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/theme-button/page.mdx b/apps/landing/src/app/(detail)/components/theme-button/page.mdx
new file mode 100644
index 00000000..a1228e75
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/theme-button/page.mdx
@@ -0,0 +1 @@
+# Theme Button
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/toggle/page.mdx b/apps/landing/src/app/(detail)/components/toggle/page.mdx
new file mode 100644
index 00000000..c27b5496
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/toggle/page.mdx
@@ -0,0 +1 @@
+# Toggle
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/tooltip/page.mdx b/apps/landing/src/app/(detail)/components/tooltip/page.mdx
new file mode 100644
index 00000000..e7f4f198
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/tooltip/page.mdx
@@ -0,0 +1 @@
+# Tooltip
\ No newline at end of file
diff --git a/apps/landing/src/app/(detail)/components/uploader/page.mdx b/apps/landing/src/app/(detail)/components/uploader/page.mdx
new file mode 100644
index 00000000..c8fc04eb
--- /dev/null
+++ b/apps/landing/src/app/(detail)/components/uploader/page.mdx
@@ -0,0 +1 @@
+# Uploader
\ No newline at end of file
diff --git a/apps/landing/src/components/icons/components/IconButtonComponent.tsx b/apps/landing/src/components/icons/components/IconButtonComponent.tsx
index 9419579c..7d0a2b62 100644
--- a/apps/landing/src/components/icons/components/IconButtonComponent.tsx
+++ b/apps/landing/src/components/icons/components/IconButtonComponent.tsx
@@ -52,8 +52,8 @@ export default function IconButtonComponent({
strokeMiterlimit="10"
/>
\n \n {icon && (\n
+
+ >
+ )
+ },
+ ],
+}
+
+export default meta
diff --git a/packages/components/src/components/Button/__tests__/__snapshots__/index.browser.test.tsx.snap b/packages/components/src/components/Button/__tests__/__snapshots__/index.browser.test.tsx.snap
new file mode 100644
index 00000000..fdc1a277
--- /dev/null
+++ b/packages/components/src/components/Button/__tests__/__snapshots__/index.browser.test.tsx.snap
@@ -0,0 +1,346 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Button > color should be white 1`] = `
+
+
+
+`;
+
+exports[`Button > should disable 1`] = `
+
+
+
+`;
+
+exports[`Button > should have class name when className is provided 1`] = `
+
+
+
+`;
+
+exports[`Button > should have font size 14px when size is sm and variant is default 1`] = `
+
+
+
+`;
+
+exports[`Button > should have font size 15px when size is md and variant is primary 1`] = `
+
+
+
+`;
+
+exports[`Button > should have font size 15px when size is sm and variant is primary 1`] = `
+
+
+
+`;
+
+exports[`Button > should have text overflow ellipsis when ellipsis is true 1`] = `
+
+
+
+`;
+
+exports[`Button > should have typography when typography is provided 1`] = `
+
+
+
+`;
+
+exports[`Button > should not have bg when a wrong size variable is provided 1`] = `
+
+
+
+`;
+
+exports[`Button > should not have px when a wrong size variable is provided 1`] = `
+
+
+
+`;
+
+exports[`Button > should not render error color when danger is false and variant is default 1`] = `
+
+`;
+
+exports[`Button > should render 1`] = `
+
+
+
+`;
+
+exports[`Button > should render default style when variant is default 1`] = `
+
+
+
+`;
+
+exports[`Button > should render error style when danger is true and variant is default 1`] = `
+
+
+
+`;
+
+exports[`Button > should render icon when icon is provided 1`] = `
+
+
+
+`;
+
+exports[`Button > should render primary background color when danger is true and variant is primary 1`] = `
+
+
+
+`;
diff --git a/packages/components/src/components/Button/__tests__/index.browser.test.tsx b/packages/components/src/components/Button/__tests__/index.browser.test.tsx
new file mode 100644
index 00000000..87b1f717
--- /dev/null
+++ b/packages/components/src/components/Button/__tests__/index.browser.test.tsx
@@ -0,0 +1,182 @@
+import { css, DevupThemeTypography } from '@devup-ui/react'
+import { render } from '@testing-library/react'
+
+import { Button } from '../index'
+
+describe('Button', () => {
+ it('should render', () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ })
+
+ it('should render default style when variant is default', () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveStyle({
+ color: 'var(--text, #272727)',
+ })
+ })
+
+ it('should disable', () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveAttribute('disabled')
+ })
+
+ it('should render error style when danger is true and variant is default', () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveStyle({
+ color: 'var(--error, #D52B2E)',
+ })
+ })
+
+ it('should render primary background color when danger is true and variant is primary', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveStyle({
+ backgroundColor: 'var(--primary, #8163E1)',
+ })
+ })
+
+ it('should not render error color when danger is false and variant is default', async () => {
+ const { container } = render()
+ const button = container.querySelector('button')
+ expect(button).toHaveStyle({
+ color: 'var(--text, #272727)',
+ })
+ expect(button).toMatchSnapshot()
+ })
+
+ it('should have class name when className is provided', () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveClass('test')
+ })
+
+ it('should not have px when a wrong size variable is provided', () => {
+ const { container } = render(
+ // @ts-expect-error
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).not.toHaveClass('px-0-16px--1')
+ })
+
+ it('should not have bg when a wrong size variable is provided', () => {
+ const { container } = render(
+ // @ts-expect-error
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).not.toHaveClass(
+ 'bg-0-color-mix(in srgb,var(--primary,#8163E1) 10%,#FFF 90%)-8380715471663921674-1',
+ )
+ })
+
+ it('should have text overflow ellipsis when ellipsis is true', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ const button = container.querySelector('button>div>div')
+ expect(button).toHaveClass('textOverflow-0-ellipsis--255')
+ })
+
+ it('should have font size 15px when size is md and variant is primary', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveClass('fontSize-0-15px--1')
+ })
+
+ it('should have font size 15px when size is sm and variant is primary', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveClass('fontSize-0-15px--1')
+ })
+
+ it('should have font size 14px when size is sm and variant is default', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveClass('fontSize-0-14px--1')
+ })
+
+ it('should render icon when icon is provided', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('svg')).toBeInTheDocument()
+ })
+ it('color should be white', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveStyle({
+ color: 'var(--text, #272727)',
+ })
+ })
+
+ it('should have typography when typography is provided', () => {
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ expect(container.querySelector('button')).toHaveClass('typo-inlineLabelS')
+ })
+})
diff --git a/packages/components/src/components/Button/index.tsx b/packages/components/src/components/Button/index.tsx
new file mode 100644
index 00000000..dba686c4
--- /dev/null
+++ b/packages/components/src/components/Button/index.tsx
@@ -0,0 +1,260 @@
+import {
+ Box,
+ Button as DevupButton,
+ Center,
+ css,
+ type DevupThemeTypography,
+} from '@devup-ui/react'
+import { clsx } from 'clsx'
+
+type ButtonProps = React.ButtonHTMLAttributes & {
+ variant?: 'primary' | 'default'
+ colors?: {
+ primary?: string
+ error?: string
+ text?: string
+ border?: string
+ inputBackground?: string
+ primaryFocus?: string
+ }
+ typography?: keyof DevupThemeTypography
+ danger?: boolean
+ size?: 'sm' | 'md' | 'lg'
+ icon?: React.ReactNode
+ ellipsis?: boolean
+}
+
+const buttonTextEllipsis = css({
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+})
+
+export function Button({
+ variant = 'default',
+ type = 'button',
+ colors,
+ danger = false,
+ children,
+ size = 'md',
+ className,
+ icon,
+ ellipsis = false,
+ typography,
+ disabled,
+ ...props
+}: ButtonProps): React.ReactElement {
+ return (
+
+
+ {icon && (
+