├── .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(Click me );
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 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from "@eslint/js";
2 | import globals from "globals";
3 | import reactHooks from "eslint-plugin-react-hooks";
4 | import reactRefresh from "eslint-plugin-react-refresh";
5 | import tseslint from "typescript-eslint";
6 | import eslintConfigPrettier from "eslint-config-prettier";
7 |
8 | export default tseslint.config(
9 | { ignores: ["dist"] },
10 | {
11 | extends: [js.configs.recommended, ...tseslint.configs.recommended, eslintConfigPrettier],
12 | files: ["**/*.{ts,tsx}"],
13 | languageOptions: {
14 | ecmaVersion: 2020,
15 | globals: globals.browser,
16 | },
17 | plugins: {
18 | "react-hooks": reactHooks,
19 | "react-refresh": reactRefresh,
20 | },
21 | rules: {
22 | ...reactHooks.configs.recommended.rules,
23 | "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
24 | },
25 | },
26 | );
27 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { defineConfig } from "vite";
3 | import react from "@vitejs/plugin-react";
4 | import { resolve } from "path";
5 | import { libInjectCss } from "vite-plugin-lib-inject-css";
6 | import dts from "vite-plugin-dts";
7 |
8 | // https://vitejs.dev/config/
9 | export default defineConfig({
10 | plugins: [
11 | react(),
12 | libInjectCss(),
13 | dts({
14 | tsconfigPath: "./tsconfig.app.json",
15 | exclude: ["**/*.test.tsx", "src/setup-tests.ts", "**/*.stories.ts"],
16 | }),
17 | ],
18 | build: {
19 | lib: {
20 | entry: resolve(__dirname, "src/main.ts"),
21 | formats: ["es"],
22 | },
23 | copyPublicDir: false,
24 | rollupOptions: {
25 | external: ["react", "react-dom", "react/jsx-runtime", "tailwindcss"],
26 | },
27 | },
28 | test: {
29 | globals: true,
30 | environment: "jsdom",
31 | setupFiles: "./src/setup-tests.ts",
32 | css: false,
33 | coverage: {
34 | include: ["src/components"],
35 | },
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactjs-component-library",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "build": "tsc -b && vite build",
8 | "lint": "eslint .",
9 | "format": "prettier --check .",
10 | "format:fix": "prettier --write .",
11 | "test": "vitest",
12 | "prepare": "husky",
13 | "storybook": "storybook dev -p 6006",
14 | "build-storybook": "storybook build"
15 | },
16 | "devDependencies": {
17 | "@chromatic-com/storybook": "^1.8.0",
18 | "@commitlint/cli": "^19.4.1",
19 | "@commitlint/config-conventional": "^19.4.1",
20 | "@eslint/js": "^9.9.0",
21 | "@storybook/addon-essentials": "^8.2.9",
22 | "@storybook/addon-interactions": "^8.2.9",
23 | "@storybook/addon-links": "^8.2.9",
24 | "@storybook/addon-onboarding": "^8.2.9",
25 | "@storybook/blocks": "^8.2.9",
26 | "@storybook/react": "^8.2.9",
27 | "@storybook/react-vite": "^8.2.9",
28 | "@storybook/test": "^8.2.9",
29 | "@testing-library/jest-dom": "^6.5.0",
30 | "@testing-library/react": "^16.0.1",
31 | "@types/node": "^22.5.2",
32 | "@types/react": "^18.3.3",
33 | "@types/react-dom": "^18.3.0",
34 | "@vitejs/plugin-react": "^4.3.1",
35 | "autoprefixer": "^10.4.20",
36 | "eslint": "^9.9.0",
37 | "eslint-config-prettier": "^9.1.0",
38 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
39 | "eslint-plugin-react-refresh": "^0.4.9",
40 | "eslint-plugin-storybook": "^0.8.0",
41 | "globals": "^15.9.0",
42 | "husky": "^9.1.5",
43 | "jsdom": "^25.0.0",
44 | "lint-staged": "^15.2.10",
45 | "postcss": "^8.4.44",
46 | "prettier": "^3.3.3",
47 | "react": "^18.3.1",
48 | "react-dom": "^18.3.1",
49 | "storybook": "^8.2.9",
50 | "tailwindcss": "^3.4.10",
51 | "typescript": "^5.5.3",
52 | "typescript-eslint": "^8.0.1",
53 | "vite": "^5.4.1",
54 | "vite-plugin-dts": "^4.1.0",
55 | "vite-plugin-lib-inject-css": "^2.1.1",
56 | "vitest": "^2.0.5"
57 | },
58 | "peerDependencies": {
59 | "react": "^18.3.1",
60 | "react-dom": "^18.3.1"
61 | },
62 | "packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e",
63 | "eslintConfig": {
64 | "extends": [
65 | "plugin:storybook/recommended"
66 | ]
67 | },
68 | "dependencies": {
69 | "react": "^18.3.1",
70 | "react-dom": "^18.3.1"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Reactjs Component Library Template
2 |
3 | Esta plantilla es un punto de partida para crear tu propia biblioteca de componentes en React con TypeScript. Incluye todas las herramientas modernas necesarias para desarrollar, probar y documentar tus componentes de manera eficiente.
4 |
5 | ## Características
6 |
7 | - **⚛️ Biblioteca de componentes en React 18.3 con TypeScript 5.5**
8 |
9 | - Desarrolla componentes reutilizables y tipados con TypeScript.
10 |
11 | - **🏗️ Vite 5.4 como entorno de desarrollo (basado en Rollup)**
12 |
13 | - Vite proporciona un entorno rápido y optimizado para el desarrollo de tus componentes.
14 |
15 | - **🌳 Tree shaking**
16 |
17 | - Distribuye solo el código que necesitas; elimina el código muerto automáticamente.
18 |
19 | - **📚 Storybook 8 para la visualización de componentes**
20 |
21 | - Visualiza y documenta tus componentes en vivo con Storybook.
22 |
23 | - **🖌️ TailwindCSS 3.4**
24 |
25 | - Incorpora TailwindCSS para un desarrollo de interfaces rápido y eficiente.
26 |
27 | - **🎨 PostCSS para procesar tu CSS**
28 |
29 | - Utiliza PostCSS para transformar y optimizar tu CSS.
30 |
31 | - **🧪 Pruebas con Vitest y React Testing Library**
32 |
33 | - Garantiza la calidad de tus componentes con pruebas automáticas utilizando Vitest y React Testing Library.
34 |
35 | - **✅ Herramientas de calidad de código con ESLint, Prettier y Stylelint**
36 |
37 | - Mantén un código limpio y consistente utilizando estas herramientas.
38 |
39 | - **🔧 NPM como gestor de paquetes**
40 |
41 | - Administra tus dependencias y scripts de manera segura con NPM.
42 |
43 | - **🚀 TODO: GitHub Actions**
44 | - Planeado: Automatización de lint, pruebas automatizadas, generación de changelog y publicación usando CI/CD con GitHub Actions.
45 | - Dale estrellita ⭐️ al proyecto para que no te pierdas la actualización.
46 |
47 | ## Scripts disponibles
48 |
49 | | **Script** | **Descripción** |
50 | | ----------------- | ---------------------------------------------------------------- |
51 | | `build` | Compila el proyecto utilizando TypeScript y Vite. |
52 | | `lint` | Analiza el código con ESLint para asegurar la calidad. |
53 | | `format` | Verifica el formato del código con Prettier. |
54 | | `format:fix` | Corrige automáticamente el formato del código con Prettier. |
55 | | `test` | Ejecuta las pruebas con Vitest. |
56 | | `prepare` | Configura Husky para manejar hooks de Git. |
57 | | `storybook` | Inicia el servidor de Storybook para visualizar los componentes. |
58 | | `build-storybook` | Compila y genera una versión estática de Storybook. |
59 |
60 | ## 🛠️ Cómo Empezar Paso a Paso
61 |
62 | ### 1. Crea un Nuevo Repositorio desde el Template
63 |
64 | Haz clic en el botón "Use this template" en la parte superior de la página para crear tu propio repositorio basado en esta plantilla.
65 |
66 | ### 2. Clona tu Nuevo Repositorio
67 |
68 | Clona el repositorio que acabas de crear en tu máquina local:
69 |
70 | ```bash
71 | git clone https://github.com/tu-usuario/tu-nuevo-repositorio.git
72 | cd tu-nuevo-repositorio
73 | ```
74 |
75 | ### 3. Instala las Dependencias
76 |
77 | Instala todas las dependencias necesarias utilizando npm:
78 |
79 | ```bash
80 | npm ci
81 | ```
82 |
83 | > [!NOTE]
84 | > Usar `npm ci` en lugar de `npm install` instalará las dependencias exactamente como están especificadas en el archivo `package-lock.json`, lo que garantiza una instalación más rápida y consistente.
85 |
86 | ### 4. Visualiza los Componentes con Storybook
87 |
88 | Inicia Storybook para visualizar y documentar tus componentes en tiempo real:
89 |
90 | ```bash
91 | npm run storybook
92 | ```
93 |
94 | ### 5. Ejecuta las Pruebas
95 |
96 | Asegúrate de que todos los componentes funcionan correctamente ejecutando las pruebas:
97 |
98 | ```bash
99 | npm test
100 | ```
101 |
102 | ### 6. Compila la Biblioteca
103 |
104 | Cuando estés listo para distribuir tu biblioteca, compílala utilizando el siguiente comando:
105 |
106 | ```bash
107 | npm run build
108 | ```
109 |
110 | ### 7. Haz pruebas locales de la Biblioteca
111 |
112 | Utiliza `npm link` para probar tu biblioteca en una aplicación local antes de publicarla en npm:
113 |
114 | 1. En la carpeta de tu biblioteca, ejecuta:
115 |
116 | ```bash
117 | npm link
118 | ```
119 |
120 | > [!NOTE]
121 | > npm link crea un enlace simbólico en la carpeta global de npm para tu biblioteca. Puedes ver más información sobre npm link [aquí](https://docs.npmjs.com/cli/v10/commands/npm-link).
122 |
123 | 2. En la carpeta de tu aplicación local, ejecuta:
124 |
125 | ```bash
126 | npm link tu-biblioteca
127 | ```
128 |
129 | > [!NOTE]
130 | > Puedes revisar la carpeta node_modules de tu aplicación local para asegurarte de que tu biblioteca está vinculada correctamente.
131 |
132 | Importa un componente directamente de tu biblioteca y úsalo en tu aplicación local para asegurarte de que todo funcione correctamente.
133 |
134 | ```jsx
135 | import { Button } from "tu-biblioteca";
136 | ```
137 |
138 | ### 8. Publica tu Biblioteca en npm
139 |
140 | Cuando estés listo para publicar tu biblioteca en npm, sigue estos pasos:
141 |
142 | 1. Crea una cuenta en [npm](https://www.npmjs.com/signup) si aún no tienes una.
143 | 2. Inicia sesión en tu cuenta de npm en tu terminal:
144 |
145 | ```bash
146 | npm login
147 | ```
148 |
149 | 3. Actualiza el campo `name` en tu archivo `package.json` con el nombre de tu biblioteca.
150 | 4. Incrementa el número de versión en tu archivo `package.json`:
151 |
152 | ```bash
153 | npm version patch
154 | ```
155 |
156 | 5. Publica tu biblioteca en npm:
157 |
158 | ```bash
159 | npm publish
160 | ```
161 |
162 | > [!NOTE]
163 | > Puedes encontrar más información sobre cómo publicar paquetes en npm [aquí](https://docs.npmjs.com/cli/v10/commands/npm-publish).
164 |
165 | ### 9. Comparte tu Biblioteca con el Mundo
166 |
167 | ¡Felicidades! Has creado tu propia biblioteca de componentes en React. Ahora puedes compartirla con el mundo y permitir que otros la utilicen en sus proyectos.
168 |
169 | ## ¿Qué sigue?
170 |
171 | Seguramente te estás preguntando cómo llevar este proyecto al siguiente nivel. Por ejemplo:
172 |
173 | - ¿Cómo puedes asegurarte de que tu biblioteca sea funcional, fácil de mantener y escalar a medida que tu proyecto crece?
174 | - ¿Cómo puedes crear componentes que sean reutilizables?
175 | - ¿Qué pasos puedes seguir para integrar un sistema de diseño sólido?
176 | - ¿Cómo puedes manejar los tokens de diseño para mantener la coherencia en todas tus aplicaciones?
177 |
178 | Y eso no es todo...
179 |
180 | > [!NOTE]
181 | > A medida que avanzas, pueden surgir otras preguntas, como garantizar la accesibilidad de tus componentes, facilitar la colaboración efectiva en tu equipo, o incluso cómo desplegar Storybook para que todos puedan ver el trabajo que has hecho.
182 |
183 | Para ayudarte a responder a estas preguntas, he creado una guía detallada que te llevará a través de los pasos necesarios para llevar tu biblioteca de componentes al siguiente nivel.
184 |
185 |
186 |
187 | 📘 Descarga la Guía Completa Aquí
188 |
189 |
190 |
191 | ## ⭐️ Apoya el Proyecto
192 |
193 | Si encuentras útil esta plantilla, por favor considera darle una estrella ⭐️ en GitHub. Esto ayuda a que más personas descubran el proyecto y mantiene a la comunidad comprometida.
194 |
--------------------------------------------------------------------------------