├── .nvmrc ├── .husky ├── pre-commit └── commit-msg ├── src ├── vite-env.d.ts ├── main.css ├── components │ └── button │ │ ├── index.ts │ │ ├── button.test.tsx │ │ ├── button.stories.ts │ │ └── button.tsx ├── main.ts └── setup-tests.ts ├── .lintstagedrc ├── commitlint.config.js ├── postcss.config.js ├── tsconfig.json ├── tailwind.config.js ├── .prettierrc ├── .storybook ├── preview.ts └── main.ts ├── .gitignore ├── index.html ├── tsconfig.node.json ├── tsconfig.app.json ├── eslint.config.js ├── vite.config.ts ├── public └── vite.svg ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.13.1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit $1 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.(js|jsx|ts|tsx|css|md)": "prettier --write" 3 | } 4 | -------------------------------------------------------------------------------- /src/main.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | export default { extends: ["@commitlint/config-conventional"] }; 2 | -------------------------------------------------------------------------------- /src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export { Button } from "./button"; 2 | export type { ButtonProps } from "./button"; 3 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] 4 | } 5 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import "./main.css"; 2 | 3 | export { Button } from "./components/button"; 4 | export type { ButtonProps } from "./components/button"; 5 | -------------------------------------------------------------------------------- /src/setup-tests.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | import { afterEach } from "vitest"; 3 | import { cleanup } from "@testing-library/react"; 4 | 5 | afterEach(() => { 6 | cleanup(); 7 | }); 8 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./src/**/*.{ts,tsx,js,jsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsxSingleQuote": false, 3 | "printWidth": 100, 4 | "semi": true, 5 | "singleAttributePerLine": false, 6 | "singleQuote": false, 7 | "tabWidth": 2, 8 | "trailingComma": "all" 9 | } 10 | -------------------------------------------------------------------------------- /src/components/button/button.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | 3 | import { Button } from "./"; 4 | 5 | describe("Button", () => { 6 | it("should render the button", () => { 7 | render(); 8 | expect(screen.getByRole("button")).toBeInTheDocument(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from "@storybook/react"; 2 | 3 | import "../src/main.css"; 4 | 5 | const preview: Preview = { 6 | parameters: { 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/i, 11 | }, 12 | }, 13 | }, 14 | }; 15 | 16 | export default preview; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | *storybook.log 27 | storybook-static -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from "@storybook/react-vite"; 2 | 3 | const config: StorybookConfig = { 4 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], 5 | addons: [ 6 | "@storybook/addon-onboarding", 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@chromatic-com/storybook", 10 | "@storybook/addon-interactions", 11 | ], 12 | framework: { 13 | name: "@storybook/react-vite", 14 | options: {}, 15 | }, 16 | }; 17 | export default config; 18 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["vitest/globals"], 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true 23 | }, 24 | "include": ["src"] 25 | } 26 | -------------------------------------------------------------------------------- /src/components/button/button.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | import { fn } from "@storybook/test"; 3 | 4 | import { Button } from "./button"; 5 | 6 | const meta = { 7 | title: "Components/Button", 8 | component: Button, 9 | parameters: { 10 | layout: "centered", 11 | }, 12 | tags: ["autodocs"], 13 | args: { 14 | onClick: fn(), 15 | }, 16 | } satisfies Meta; 17 | 18 | export default meta; 19 | 20 | type Story = StoryObj; 21 | 22 | // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args 23 | export const Primary: Story = { 24 | args: { 25 | onFocus: fn(), 26 | children: "Button", 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/button/button.tsx: -------------------------------------------------------------------------------- 1 | export interface ButtonProps extends React.ComponentProps<"button"> { 2 | /** 3 | * The size of the button. 4 | * - 'small' for a compact button. 5 | * - 'medium' for a standard button. 6 | * - 'large' for a larger button. 7 | */ 8 | size?: "small" | "medium" | "large"; 9 | } 10 | 11 | export function Button({ size = "medium", ...props }: ButtonProps) { 12 | const sizeClasses = { 13 | small: "text-xs py-1 px-2", 14 | medium: "text-sm py-2 px-4", 15 | large: "text-lg py-3 px-6", 16 | }; 17 | 18 | const sizeClass = sizeClasses[size]; 19 | 20 | return ( 21 |