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 +1 -1
- package/scripts/postinstall.js +253 -22
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -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
|
-
* -
|
|
8
|
-
* -
|
|
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
|
|
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
|
|
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="
|
|
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/
|
|
329
|
-
const
|
|
330
|
-
if (!fs.existsSync(
|
|
331
|
-
const
|
|
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
|
|
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>
|
|
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
|
|
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('')
|