Skip to content

Commit 213c62d

Browse files
committed
add more components
1 parent 254e9e1 commit 213c62d

File tree

13 files changed

+1256
-0
lines changed

13 files changed

+1256
-0
lines changed

pnpm-lock.yaml

Lines changed: 331 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/common/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ tsconfig.tsbuildinfo
44

55
*storybook.log
66
storybook-static
7+
**/__snapshots__/**
8+
**/__screenshots__/**

web/common/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
"devDependencies": {
55
"@eslint/js": "^9.31.0",
66
"@radix-ui/react-slot": "^1.2.3",
7+
"@radix-ui/react-tooltip": "^1.2.8",
78
"@storybook/addon-docs": "^9.1.2",
89
"@storybook/addon-essentials": "^9.0.0-alpha.12",
910
"@storybook/addon-onboarding": "^9.1.2",
1011
"@storybook/react-vite": "^9.1.2",
12+
"@storybook/test": "^8.6.14",
1113
"@tailwindcss/typography": "^0.5.16",
1214
"@testing-library/dom": "^10.4.1",
1315
"@testing-library/jest-dom": "^6.6.3",
@@ -17,20 +19,23 @@
1719
"@types/react-dom": "^18.3.7",
1820
"@vitejs/plugin-react": "^4.7.0",
1921
"@vitest/browser": "^3.2.4",
22+
"@xyflow/react": "^12.8.4",
2023
"autoprefixer": "^10.4.21",
2124
"class-variance-authority": "^0.7.1",
2225
"clsx": "^2.1.1",
2326
"eslint": "^9.31.0",
2427
"eslint-plugin-react-hooks": "^5.2.0",
2528
"eslint-plugin-storybook": "^9.1.2",
2629
"globals": "^16.3.0",
30+
"lucide-react": "^0.542.0",
2731
"playwright": "^1.54.1",
2832
"postcss": "^8.5.6",
2933
"react": "^18.3.1",
3034
"react-dom": "^18.3.1",
3135
"storybook": "^9.1.2",
3236
"syncpack": "^13.0.4",
3337
"tailwind-merge": "^3.3.1",
38+
"tailwind-scrollbar": "^4.0.2",
3439
"tailwindcss": "^3.4.17",
3540
"typescript": "^5.8.3",
3641
"typescript-eslint": "^8.38.0",
@@ -62,9 +67,12 @@
6267
"module": "dist/sqlmesh-common.es.js",
6368
"peerDependencies": {
6469
"@radix-ui/react-slot": "^1.2.3",
70+
"@radix-ui/react-tooltip": "^1.2.8",
6571
"@tailwindcss/typography": "^0.5.16",
72+
"@xyflow/react": "^12.8.4",
6673
"class-variance-authority": "^0.7.1",
6774
"clsx": "^2.1.1",
75+
"lucide-react": "^0.542.0",
6876
"react": "^18.3.1",
6977
"react-dom": "^18.3.1",
7078
"tailwind-merge": "^3.3.1",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
:root {
2+
--color-button-focused: var(--color-gray-100);
3+
4+
--color-button-primary-background: var(--color-gray-100);
5+
--color-button-primary-foreground: var(--color-prose);
6+
--color-button-primary-hover: var(--color-gray-100);
7+
--color-button-primary-active: var(--color-gray-100);
8+
9+
--color-button-secondary-background: var(--color-gray-100);
10+
--color-button-secondary-foreground: var(--color-prose);
11+
--color-button-secondary-hover: var(--color-gray-100);
12+
--color-button-secondary-active: var(--color-gray-100);
13+
14+
--color-button-alternative-background: var(--color-gray-100);
15+
--color-button-alternative-foreground: var(--color-prose);
16+
--color-button-alternative-hover: var(--color-gray-100);
17+
--color-button-alternative-active: var(--color-gray-100);
18+
19+
--color-button-destructive-background: var(--color-gray-100);
20+
--color-button-destructive-foreground: var(--color-prose);
21+
--color-button-destructive-hover: var(--color-gray-100);
22+
--color-button-destructive-active: var(--color-gray-100);
23+
24+
--color-button-danger-background: var(--color-gray-100);
25+
--color-button-danger-foreground: var(--color-prose);
26+
--color-button-danger-hover: var(--color-gray-100);
27+
--color-button-danger-active: var(--color-gray-100);
28+
29+
--color-button-transparent-background: var(--color-gray-100);
30+
--color-button-transparent-foreground: var(--color-prose);
31+
--color-button-transparent-hover: var(--color-gray-100);
32+
--color-button-transparent-active: var(--color-gray-100);
33+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
2+
import { expect, userEvent, within } from 'storybook/test'
3+
4+
import { EnumSize } from '@/types/enums'
5+
import { Button } from './Button'
6+
import { EnumButtonVariant } from './help'
7+
8+
const meta: Meta<typeof Button> = {
9+
title: 'Components/Button',
10+
component: Button,
11+
tags: ['autodocs'],
12+
argTypes: {
13+
onClick: { action: 'clicked' },
14+
variant: {
15+
control: { type: 'select' },
16+
options: Object.values(EnumButtonVariant),
17+
},
18+
size: {
19+
control: { type: 'select' },
20+
options: Object.values(EnumSize),
21+
},
22+
type: {
23+
control: { type: 'select' },
24+
options: ['button', 'submit', 'reset'],
25+
},
26+
disabled: {
27+
control: 'boolean',
28+
},
29+
},
30+
}
31+
32+
export default meta
33+
34+
type Story = StoryObj<typeof Button>
35+
36+
export const Default: Story = {
37+
args: {
38+
children: 'Default Button',
39+
},
40+
play: async ({ canvasElement }) => {
41+
const canvas = within(canvasElement)
42+
await expect(canvas.getByText('Default Button')).toBeInTheDocument()
43+
},
44+
}
45+
46+
export const Variants: Story = {
47+
render: args => (
48+
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
49+
{Object.values(EnumButtonVariant).map(variant => (
50+
<Button
51+
key={variant}
52+
{...args}
53+
variant={variant}
54+
>
55+
{variant}
56+
</Button>
57+
))}
58+
</div>
59+
),
60+
}
61+
62+
export const Sizes: Story = {
63+
render: args => (
64+
<div
65+
style={{
66+
display: 'flex',
67+
gap: 12,
68+
flexWrap: 'wrap',
69+
alignItems: 'center',
70+
}}
71+
>
72+
{Object.values(EnumSize).map(size => (
73+
<Button
74+
key={size}
75+
{...args}
76+
size={size}
77+
>
78+
{size}
79+
</Button>
80+
))}
81+
</div>
82+
),
83+
}
84+
85+
export const Disabled: Story = {
86+
args: {
87+
children: 'Disabled Button',
88+
disabled: true,
89+
},
90+
play: async ({ canvasElement }) => {
91+
const canvas = within(canvasElement)
92+
const button = canvas.getByRole('button')
93+
await expect(button).toBeDisabled()
94+
await expect(button).toHaveTextContent('Disabled Button')
95+
},
96+
}
97+
98+
export const AsChild: Story = {
99+
render: args => (
100+
<Button
101+
asChild
102+
{...args}
103+
>
104+
<a href="#">Link as Button</a>
105+
</Button>
106+
),
107+
play: async ({ canvasElement }) => {
108+
const canvas = within(canvasElement)
109+
const linkElement = canvas.getByText('Link as Button')
110+
await expect(linkElement.tagName).toBe('A')
111+
await expect(linkElement).toHaveAttribute('href', '#')
112+
},
113+
}
114+
115+
export const Types: Story = {
116+
render: args => (
117+
<div style={{ display: 'flex', gap: 12 }}>
118+
<Button
119+
{...args}
120+
type="button"
121+
>
122+
Button
123+
</Button>
124+
<Button
125+
{...args}
126+
type="submit"
127+
>
128+
Submit
129+
</Button>
130+
<Button
131+
{...args}
132+
type="reset"
133+
>
134+
Reset
135+
</Button>
136+
</div>
137+
),
138+
}
139+
140+
export const InteractiveClick: Story = {
141+
args: {
142+
children: 'Click Me',
143+
},
144+
play: async ({ canvasElement, args }) => {
145+
const canvas = within(canvasElement)
146+
const user = userEvent.setup()
147+
148+
const button = canvas.getByRole('button')
149+
await expect(button).toBeInTheDocument()
150+
151+
await user.click(button)
152+
await expect(args.onClick).toHaveBeenCalledTimes(1)
153+
154+
await user.click(button)
155+
await expect(args.onClick).toHaveBeenCalledTimes(2)
156+
},
157+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Slot } from '@radix-ui/react-slot'
2+
import type { VariantProps } from 'class-variance-authority'
3+
import React from 'react'
4+
5+
import { cn } from '@/utils'
6+
import { buttonVariants } from './help'
7+
import type { ButtonType } from './help'
8+
9+
import './Button.css'
10+
11+
const DEFAULT_BUTTON_TYPE = 'button'
12+
13+
export interface ButtonProps
14+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
15+
VariantProps<typeof buttonVariants> {
16+
asChild?: boolean
17+
type?: ButtonType
18+
}
19+
20+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
21+
({ className, variant, size, type, asChild = false, ...props }, ref) => {
22+
const Comp = asChild ? Slot : DEFAULT_BUTTON_TYPE
23+
return (
24+
<Comp
25+
type={type}
26+
className={cn(buttonVariants({ variant, size, className }))}
27+
ref={ref}
28+
{...props}
29+
/>
30+
)
31+
},
32+
)
33+
Button.displayName = 'Button'
34+
35+
export { Button }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { cva } from 'class-variance-authority'
2+
3+
import { EnumSize } from '@/types/enums'
4+
5+
export const EnumButtonType = {
6+
Button: 'button',
7+
Submit: 'submit',
8+
Reset: 'reset',
9+
} as const
10+
11+
export type ButtonType = (typeof EnumButtonType)[keyof typeof EnumButtonType]
12+
13+
export const EnumButtonVariant = {
14+
Primary: 'primary',
15+
Secondary: 'secondary',
16+
Alternative: 'alternative',
17+
Destructive: 'destructive',
18+
Danger: 'danger',
19+
Transparent: 'transparent',
20+
} as const
21+
22+
export type ButtonVariant =
23+
(typeof EnumButtonVariant)[keyof typeof EnumButtonVariant]
24+
25+
export const buttonVariants = cva(
26+
'inline-flex items-center w-fit justify-center gap-1 whitespace-nowrap leading-none font-semibold ring-offset-light transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focused focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 border border-[transparent]',
27+
{
28+
variants: {
29+
variant: {
30+
[EnumButtonVariant.Primary]:
31+
'bg-button-primary-background text-button-primary-foreground hover:bg-button-primary-hover active:bg-button-primary-active',
32+
[EnumButtonVariant.Secondary]:
33+
'bg-button-secondary-background text-button-secondary-foreground hover:bg-button-secondary-hover active:bg-button-secondary-active',
34+
[EnumButtonVariant.Alternative]:
35+
'bg-button-alternative-background text-button-alternative-foreground border-neutral-200 hover:bg-button-alternative-hover active:bg-button-alternative-active',
36+
[EnumButtonVariant.Destructive]:
37+
'bg-button-destructive-background text-button-destructive-foreground hover:bg-button-destructive-hover active:bg-button-destructive-active',
38+
[EnumButtonVariant.Danger]:
39+
'bg-button-danger-background text-button-danger-foreground hover:bg-button-danger-hover active:bg-button-danger-active',
40+
[EnumButtonVariant.Transparent]:
41+
'bg-button-transparent-background text-button-transparent-foreground hover:bg-button-transparent-hover active:bg-button-transparent-active',
42+
},
43+
size: {
44+
[EnumSize.XXS]: 'h-5 px-2 text-2xs leading-none rounded-2xs',
45+
[EnumSize.XS]: 'h-6 px-2 text-2xs rounded-xs',
46+
[EnumSize.S]: 'h-7 px-3 text-xs rounded-sm',
47+
[EnumSize.M]: 'h-8 px-4 rounded-md',
48+
[EnumSize.L]: 'h-9 px-4 rounded-lg',
49+
[EnumSize.XL]: 'h-10 px-4 rounded-xl',
50+
[EnumSize.XXL]: 'h-11 px-6 rounded-2xl',
51+
},
52+
},
53+
defaultVariants: {
54+
variant: EnumButtonVariant.Primary,
55+
size: EnumSize.S,
56+
},
57+
},
58+
)

0 commit comments

Comments
 (0)