responsive-system 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "responsive-system",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "description": "Sistema de layout responsivo con auto-scaling para Tailwind CSS",
5
5
  "type": "module",
6
6
  "main": "./dist/responsive-system.cjs",
@@ -4,14 +4,18 @@
4
4
  * Script postinstall para automatizar la configuración inicial completa
5
5
  * - Instala React, TypeScript, Tailwind automáticamente
6
6
  * - Inicializa proyecto Vite si está vacío
7
- * - Configura Tailwind
8
- * - Crea página de ejemplo con layouts
7
+ * - Pregunta qué layout quiere (interactivo)
8
+ * - Copia solo los componentes necesarios
9
+ * - Copia el hook useResponsive como archivo local
10
+ * - Crea página de ejemplo en pages/
11
+ * - Configura App.tsx con el layout seleccionado
9
12
  */
10
13
 
11
14
  import fs from 'fs'
12
15
  import path from 'path'
13
16
  import { execSync } from 'child_process'
14
17
  import { fileURLToPath } from 'url'
18
+ import readline from 'readline'
15
19
 
16
20
  const __filename = fileURLToPath(import.meta.url)
17
21
  const __dirname = path.dirname(__filename)
@@ -19,8 +23,12 @@ const __dirname = path.dirname(__filename)
19
23
  const projectRoot = process.cwd()
20
24
  const packageJsonPath = path.join(projectRoot, 'package.json')
21
25
 
26
+ // Detectar si se ejecuta como postinstall o manualmente
27
+ const isPostinstall = process.env.npm_lifecycle_event === 'postinstall'
28
+ const isManual = process.argv[1].includes('postinstall.js') && !isPostinstall
29
+
22
30
  console.log('')
23
- console.log('📦 responsive-system: Iniciando postinstall...')
31
+ console.log('📦 responsive-system: Iniciando configuración...')
24
32
  console.log(` Directorio: ${projectRoot}`)
25
33
  console.log('')
26
34
 
@@ -46,27 +54,186 @@ const isProjectEmpty = !packageJson.dependencies ||
46
54
  // Verificar qué está instalado - SOLO en package.json (no en node_modules para evitar conflictos)
47
55
  const hasReactInPackageJson = (packageJson.dependencies && packageJson.dependencies.react) ||
48
56
  (packageJson.devDependencies && packageJson.devDependencies.react)
49
- // NO verificar node_modules porque puede estar como dependencia transitiva y causar conflictos
50
- const hasReact = hasReactInPackageJson
51
-
52
57
  const hasVite = packageJson.devDependencies && packageJson.devDependencies.vite
53
-
54
58
  const tailwindInDevDeps = packageJson.devDependencies && packageJson.devDependencies.tailwindcss
55
59
  const typescriptInDevDeps = packageJson.devDependencies && packageJson.devDependencies.typescript
56
60
 
57
61
  let needsUpdate = false
58
62
 
63
+ // Función para preguntar al usuario qué layout quiere
64
+ async function askLayout() {
65
+ if (isPostinstall && !isManual) {
66
+ // Si es postinstall automático, usar 'default' por defecto
67
+ console.log(' ℹ️ Usando layout "default" por defecto')
68
+ console.log(' 💡 Ejecuta "npx responsive-system-setup" para cambiar el layout')
69
+ return 'default'
70
+ }
71
+
72
+ // Si es ejecución manual, preguntar interactivamente
73
+ const rl = readline.createInterface({
74
+ input: process.stdin,
75
+ output: process.stdout
76
+ })
77
+
78
+ return new Promise((resolve) => {
79
+ console.log('')
80
+ console.log('🎨 Selecciona el layout que quieres usar:')
81
+ console.log(' 1. default - Navigation + Footer')
82
+ console.log(' 2. sidebar - Sidebar lateral')
83
+ console.log(' 3. dashboard - Sidebar + Footer')
84
+ console.log(' 4. minimal - Sin componentes (solo contenido)')
85
+ console.log('')
86
+
87
+ rl.question(' Ingresa el número (1-4) o el nombre del layout: ', (answer) => {
88
+ rl.close()
89
+
90
+ const normalized = answer.trim().toLowerCase()
91
+
92
+ if (normalized === '1' || normalized === 'default') {
93
+ resolve('default')
94
+ } else if (normalized === '2' || normalized === 'sidebar') {
95
+ resolve('sidebar')
96
+ } else if (normalized === '3' || normalized === 'dashboard') {
97
+ resolve('dashboard')
98
+ } else if (normalized === '4' || normalized === 'minimal') {
99
+ resolve('minimal')
100
+ } else {
101
+ console.log(' ⚠️ Opción inválida, usando "default"')
102
+ resolve('default')
103
+ }
104
+ })
105
+ })
106
+ }
107
+
108
+ // Función para copiar archivo desde el paquete al proyecto
109
+ function copyFileFromPackage(relativePath, targetPath, isComponent = false) {
110
+ const sourcePath = path.join(__dirname, '..', relativePath)
111
+ const destPath = path.join(projectRoot, targetPath)
112
+
113
+ if (!fs.existsSync(sourcePath)) {
114
+ console.error(` ❌ No se encontró: ${relativePath}`)
115
+ return false
116
+ }
117
+
118
+ // Crear directorio destino si no existe
119
+ const destDir = path.dirname(destPath)
120
+ if (!fs.existsSync(destDir)) {
121
+ fs.mkdirSync(destDir, { recursive: true })
122
+ }
123
+
124
+ let content = fs.readFileSync(sourcePath, 'utf8')
125
+
126
+ // Si es un componente, reemplazar importaciones relativas por importaciones del paquete
127
+ if (isComponent) {
128
+ // Reemplazar importaciones de hooks
129
+ content = content.replace(
130
+ /from ['"]\.\.\/\.\.\/hooks['"]/g,
131
+ "from 'responsive-system'"
132
+ )
133
+ // Reemplazar importaciones de context
134
+ content = content.replace(
135
+ /from ['"]\.\.\/\.\.\/context['"]/g,
136
+ "from 'responsive-system'"
137
+ )
138
+ // Reemplazar importaciones de componentes/layout
139
+ content = content.replace(
140
+ /from ['"]\.\.\/components\/layout['"]/g,
141
+ "from 'responsive-system'"
142
+ )
143
+ }
144
+
145
+ fs.writeFileSync(destPath, content)
146
+ return true
147
+ }
148
+
149
+ // Función para copiar componentes según el layout seleccionado
150
+ function copyLayoutComponents(selectedLayout) {
151
+ const componentsDir = path.join(projectRoot, 'src', 'components', 'layout')
152
+
153
+ // Crear directorio si no existe
154
+ if (!fs.existsSync(componentsDir)) {
155
+ fs.mkdirSync(componentsDir, { recursive: true })
156
+ }
157
+
158
+ const componentsToCopy = {
159
+ default: ['Navigation', 'Footer'],
160
+ sidebar: ['Sidebar'],
161
+ dashboard: ['Sidebar', 'Footer'],
162
+ minimal: []
163
+ }
164
+
165
+ const components = componentsToCopy[selectedLayout] || []
166
+
167
+ if (components.length === 0) {
168
+ console.log(' ✅ Layout minimal: No se copian componentes')
169
+ return
170
+ }
171
+
172
+ console.log(` 📦 Copiando componentes para layout "${selectedLayout}":`)
173
+
174
+ for (const component of components) {
175
+ const sourceFile = `src/components/layout/${component}.tsx`
176
+ const targetFile = `src/components/layout/${component}.tsx`
177
+
178
+ if (copyFileFromPackage(sourceFile, targetFile, true)) {
179
+ console.log(` ✅ ${component}.tsx`)
180
+ }
181
+ }
182
+
183
+ // Crear index.ts para exportar los componentes
184
+ const indexContent = components.map(c => `export { default as ${c} } from './${c}'`).join('\n')
185
+ fs.writeFileSync(path.join(componentsDir, 'index.ts'), indexContent)
186
+ console.log(' ✅ index.ts')
187
+ }
188
+
189
+ // Función para copiar el hook useResponsive y sus dependencias
190
+ function copyUseResponsiveHook() {
191
+ console.log(' 📦 Copiando hook useResponsive y dependencias...')
192
+
193
+ // Crear directorio hooks
194
+ const hooksDir = path.join(projectRoot, 'src', 'hooks')
195
+ if (!fs.existsSync(hooksDir)) {
196
+ fs.mkdirSync(hooksDir, { recursive: true })
197
+ }
198
+
199
+ // Copiar tipos
200
+ const typesDir = path.join(projectRoot, 'src', 'types')
201
+ if (!fs.existsSync(typesDir)) {
202
+ fs.mkdirSync(typesDir, { recursive: true })
203
+ }
204
+ copyFileFromPackage('src/types/responsive.ts', 'src/types/responsive.ts')
205
+ console.log(' ✅ types/responsive.ts')
206
+
207
+ // Copiar constantes
208
+ const constantsDir = path.join(projectRoot, 'src', 'constants')
209
+ if (!fs.existsSync(constantsDir)) {
210
+ fs.mkdirSync(constantsDir, { recursive: true })
211
+ }
212
+ copyFileFromPackage('src/constants/breakpoints.ts', 'src/constants/breakpoints.ts')
213
+ console.log(' ✅ constants/breakpoints.ts')
214
+
215
+ // Copiar hook useResponsive
216
+ copyFileFromPackage('src/hooks/useResponsive.ts', 'src/hooks/useResponsive.ts')
217
+ console.log(' ✅ hooks/useResponsive.ts')
218
+
219
+ // Crear index.ts para exportar el hook
220
+ const indexContent = `export { useResponsive } from './useResponsive'
221
+ export type { ResponsiveState, Breakpoint, Orientation } from '../types/responsive'
222
+ export { DEFAULT_BREAKPOINTS, getCurrentBreakpoint, getBreakpointIndex, getBreakpointValue } from '../constants/breakpoints'
223
+ `
224
+ fs.writeFileSync(path.join(hooksDir, 'index.ts'), indexContent)
225
+ console.log(' ✅ hooks/index.ts')
226
+ }
227
+
59
228
  // ESTRATEGIA: Modificar directamente el package.json primero, luego instalar
60
229
  console.log('📦 responsive-system: Verificando dependencias...')
61
230
 
62
231
  // Agregar React a dependencies SOLO si NO está en package.json
63
- // NO verificar node_modules para evitar múltiples copias de React
64
232
  if (!hasReactInPackageJson) {
65
233
  console.log(' ➕ Agregando React a dependencies...')
66
234
  if (!packageJson.dependencies) {
67
235
  packageJson.dependencies = {}
68
236
  }
69
- // Usar versión compatible con peerDependencies del paquete
70
237
  packageJson.dependencies['react'] = '^19.1.1'
71
238
  packageJson.dependencies['react-dom'] = '^19.1.1'
72
239
  needsUpdate = true
@@ -85,9 +252,9 @@ if (isProjectEmpty && !hasVite) {
85
252
  needsUpdate = true
86
253
  }
87
254
 
88
- // Agregar TypeScript y Tailwind a devDependencies
255
+ // Agregar Tailwind y sus dependencias a devDependencies
89
256
  if (!tailwindInDevDeps) {
90
- console.log(' ➕ Agregando Tailwind a devDependencies...')
257
+ console.log(' ➕ Agregando Tailwind y PostCSS a devDependencies...')
91
258
  if (!packageJson.devDependencies) {
92
259
  packageJson.devDependencies = {}
93
260
  }
@@ -98,6 +265,7 @@ if (!tailwindInDevDeps) {
98
265
  needsUpdate = true
99
266
  }
100
267
 
268
+ // Agregar TypeScript y sus tipos a devDependencies
101
269
  if (!typescriptInDevDeps) {
102
270
  console.log(' ➕ Agregando TypeScript a devDependencies...')
103
271
  if (!packageJson.devDependencies) {
@@ -144,16 +312,28 @@ if (isProjectEmpty) {
144
312
  console.log('')
145
313
  console.log('📦 responsive-system: Proyecto vacío detectado, creando estructura base...')
146
314
 
315
+ // Preguntar qué layout quiere
316
+ const selectedLayout = await askLayout()
317
+ console.log(` ✅ Layout seleccionado: "${selectedLayout}"`)
318
+ console.log('')
319
+
147
320
  // Crear estructura de directorios
148
- const dirs = ['src', 'src/components', 'src/pages', 'public']
321
+ const dirs = ['src', 'src/components', 'src/components/layout', 'src/pages', 'src/hooks', 'src/types', 'src/constants', 'public']
149
322
  dirs.forEach(dir => {
150
323
  const dirPath = path.join(projectRoot, dir)
151
324
  if (!fs.existsSync(dirPath)) {
152
325
  fs.mkdirSync(dirPath, { recursive: true })
153
- console.log(` ✅ Creado: ${dir}/`)
154
326
  }
155
327
  })
156
328
 
329
+ // Copiar componentes según layout seleccionado
330
+ copyLayoutComponents(selectedLayout)
331
+ console.log('')
332
+
333
+ // Copiar hook useResponsive
334
+ copyUseResponsiveHook()
335
+ console.log('')
336
+
157
337
  // Crear vite.config.ts
158
338
  const viteConfigPath = path.join(projectRoot, 'vite.config.ts')
159
339
  if (!fs.existsSync(viteConfigPath)) {
@@ -303,7 +483,7 @@ import './index.css'
303
483
 
304
484
  ReactDOM.createRoot(document.getElementById('root')!).render(
305
485
  <React.StrictMode>
306
- <ResponsiveLayoutProvider defaultLayout="default">
486
+ <ResponsiveLayoutProvider defaultLayout="${selectedLayout}">
307
487
  <MainLayout>
308
488
  <App />
309
489
  </MainLayout>
@@ -318,20 +498,21 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
318
498
  // Crear src/index.css
319
499
  const indexCssPath = path.join(projectRoot, 'src', 'index.css')
320
500
  if (!fs.existsSync(indexCssPath)) {
321
- // Tailwind CSS v4 usa @import en lugar de @tailwind
322
501
  const indexCss = `@import "tailwindcss";
323
502
  `
324
503
  fs.writeFileSync(indexCssPath, indexCss)
325
504
  console.log(' ✅ Creado: src/index.css')
326
505
  }
327
506
 
328
- // Crear src/App.tsx con página de ejemplo
329
- const appTsxPath = path.join(projectRoot, 'src', 'App.tsx')
330
- if (!fs.existsSync(appTsxPath)) {
331
- const appTsx = `import { useResponsiveLayout, LayoutSwitcher } from 'responsive-system'
507
+ // Crear src/pages/HomePage.tsx con página de ejemplo
508
+ const homePagePath = path.join(projectRoot, 'src', 'pages', 'HomePage.tsx')
509
+ if (!fs.existsSync(homePagePath)) {
510
+ const homePage = `import { useResponsiveLayout, LayoutSwitcher } from 'responsive-system'
511
+ import { useResponsive } from '../hooks'
332
512
 
333
- function App() {
513
+ function HomePage() {
334
514
  const { breakpoint, isMobile, layout } = useResponsiveLayout()
515
+ const responsive = useResponsive()
335
516
 
336
517
  return (
337
518
  <div className="min-h-screen bg-gray-50 p-6">
@@ -374,6 +555,32 @@ function App() {
374
555
  ))}
375
556
  </div>
376
557
 
558
+ {/* Información sobre el hook useResponsive */}
559
+ <div className="bg-white rounded-lg shadow-lg p-6">
560
+ <h2 className="text-2xl font-bold mb-4">Hook useResponsive</h2>
561
+ <p className="text-gray-700 mb-4">
562
+ El hook <code className="bg-gray-100 px-2 py-1 rounded">useResponsive</code> está disponible localmente en <code className="bg-gray-100 px-2 py-1 rounded">src/hooks/useResponsive.ts</code>
563
+ </p>
564
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
565
+ <div className="p-3 bg-gray-50 rounded">
566
+ <p className="text-xs text-gray-600">Ancho</p>
567
+ <p className="text-lg font-bold">{responsive.width}px</p>
568
+ </div>
569
+ <div className="p-3 bg-gray-50 rounded">
570
+ <p className="text-xs text-gray-600">Alto</p>
571
+ <p className="text-lg font-bold">{responsive.height}px</p>
572
+ </div>
573
+ <div className="p-3 bg-gray-50 rounded">
574
+ <p className="text-xs text-gray-600">Orientación</p>
575
+ <p className="text-lg font-bold capitalize">{responsive.orientation}</p>
576
+ </div>
577
+ <div className="p-3 bg-gray-50 rounded">
578
+ <p className="text-xs text-gray-600">Desktop</p>
579
+ <p className="text-lg font-bold">{responsive.isDesktop ? 'Sí' : 'No'}</p>
580
+ </div>
581
+ </div>
582
+ </div>
583
+
377
584
  {/* Información */}
378
585
  <div className="bg-white rounded-lg shadow-lg p-6">
379
586
  <h2 className="text-2xl font-bold mb-4">Cómo funciona</h2>
@@ -381,7 +588,7 @@ function App() {
381
588
  <li>✅ <strong>Auto-scaling:</strong> Todo escala automáticamente (texto, espaciado, sombras)</li>
382
589
  <li>✅ <strong>Layouts:</strong> Cambia entre default, sidebar, dashboard y minimal</li>
383
590
  <li>✅ <strong>Responsive:</strong> Se adapta automáticamente a todos los tamaños de pantalla</li>
384
- <li>✅ <strong>Sin media queries:</strong> Usa el hook useResponsive para lógica condicional</li>
591
+ <li>✅ <strong>Hook useResponsive:</strong> Disponible localmente para configuración manual</li>
385
592
  </ul>
386
593
  </div>
387
594
  </div>
@@ -389,10 +596,25 @@ function App() {
389
596
  )
390
597
  }
391
598
 
599
+ export default HomePage
600
+ `
601
+ fs.writeFileSync(homePagePath, homePage)
602
+ console.log(' ✅ Creado: src/pages/HomePage.tsx')
603
+ }
604
+
605
+ // Crear src/App.tsx que importa la página
606
+ const appTsxPath = path.join(projectRoot, 'src', 'App.tsx')
607
+ if (!fs.existsSync(appTsxPath)) {
608
+ const appTsx = `import HomePage from './pages/HomePage'
609
+
610
+ function App() {
611
+ return <HomePage />
612
+ }
613
+
392
614
  export default App
393
615
  `
394
616
  fs.writeFileSync(appTsxPath, appTsx)
395
- console.log(' ✅ Creado: src/App.tsx con página de ejemplo')
617
+ console.log(' ✅ Creado: src/App.tsx')
396
618
  }
397
619
 
398
620
  // Actualizar package.json con scripts
@@ -419,6 +641,15 @@ export default App
419
641
  console.log(' 1. npm run dev')
420
642
  console.log(' 2. Abre http://localhost:5173')
421
643
  console.log('')
644
+ console.log(`Layout seleccionado: "${selectedLayout}"`)
645
+ console.log(' - Componentes copiados en src/components/layout/')
646
+ console.log(' - Hook useResponsive disponible en src/hooks/useResponsive.ts')
647
+ console.log(' - Página de ejemplo en src/pages/HomePage.tsx')
648
+ console.log('')
649
+ console.log('💡 Para cambiar el layout, ejecuta: npx responsive-system-setup')
650
+ console.log('')
651
+ } else {
652
+ console.log('✅ responsive-system: Proyecto ya inicializado')
422
653
  }
423
654
 
424
655
  console.log('')