El Framework que Hace Magia ✨

ScopeJS es ese amigo desarrollador que siempre quisiste tener: confiable, ligero y que nunca te complica la vida. Perfecto para cuando quieres crear algo genial sin dramas.

✨ Componentes que no dan guerra 🚀 Modales con clase 🛣️ Router que funciona de verdad ⚡ Solo 15KB (¡como debe ser!)

Instalación Súper Fácil

No necesitas ser un ninja del desarrollo. Con ScopeJS, en 2 minutos ya estás creando maravillas 🎯

1

El Clásico (Copy & Paste)

Para los que prefieren lo sencillo: copia, pega y a volar 🚀

<!-- En el <head> de tu HTML -->
<script src="https://unpkg.com/@pablotheblink/scopejs@2.0.4/js/ScopeJS.js"></script>

<script>
  // Las funciones están disponibles globalmente
  const MiComponente = ScopeJS.Component({
    controller: class {
      constructor() {
        this.mensaje = "¡Hola Mundo!";
      }
    },
    render() {
      return `<h1>${this.mensaje}</h1>`;
    }
  });

  // Renderizar cuando la página cargue
  window.addEventListener('load', () => {
    const container = document.getElementById('app');
    MiComponente.render(container);
  });
</script>
✅ Cero configuración ✅ Sin complicaciones ✅ Funciona hasta en el navegador de tu abuela
2

El Moderno (Para los cool kids)

Para los que les gusta presumir con ES6 modules y bundlers 😎

<!-- En el <head> de tu HTML -->
<script type="module">
  import { Component, Modal, Router } from 'https://unpkg.com/@pablotheblink/scopejs@2.0.4/js/ScopeJS.js';

  const MiComponente = Component({
    controller: class {
      constructor() {
        this.mensaje = "¡Hola Mundo!";
      }
    },
    render() {
      return `<h1>${this.mensaje}</h1>`;
    }
  });

  // Renderizar cuando la página cargue
  window.addEventListener('load', () => {
    const container = document.getElementById('app');
    MiComponente.render(container);
  });
</script>
🚀 Tree shaking (suena fancy) 🚀 Imports selectivos 🚀 Perfecto para proyectos grandes

Más Formas de Conseguirlo

🌐 CDN (El Rápido)

Directo desde la nube, más rápido que tu café matutino:

<script src="https://unpkg.com/@pablotheblink/scopejs@2.0.4/js/ScopeJS.js"></script>

📦 NPM (El Profesional)

Para los proyectos serios que merecen lo mejor:

npm install @pablotheblink/scopejs

Estructura HTML Básica

Aquí tienes un ejemplo completo de cómo estructurar tu página HTML:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Mi App con ScopeJS</title>
  
  <!-- Opción 1: Script normal -->
  <script src="js/ScopeJS.js"></script>
  
  <!-- Opción 2: ES6 Module -->
  <!-- <script type="module" src="js/app.js"></script> -->
</head>
<body>
  <div id="app">
    <!-- Tu aplicación se renderizará aquí -->
  </div>

  <script>
    // Tu código de la aplicación aquí
    const App = ScopeJS.Component({
      controller: class {
        constructor() {
          this.titulo = "Mi Primera App ScopeJS";
          this.contador = 0;
        }
        
        incrementar() {
          this.contador++;
          this.apply();
        }
      },
      
      render() {
        return `
          <div style="text-align: center; padding: 2rem;">
            <h1>${this.titulo}</h1>
            <p>Contador: ${this.contador}</p>
            <button onclick="incrementar()">
              Incrementar
            </button>
          </div>
        `;
      }
    });

    // Inicializar cuando la página cargue
    window.addEventListener('load', () => {
      const container = document.getElementById('app');
      App.render(container);
    });
  </script>
</body>
</html>

💡 Consejos de la Casa

  • ¿Eres nuevo? Empieza con el método clásico, no te compliques la vida
  • ¿Ya tienes experiencia? Dale caña a los ES6 modules
  • ¿Va a producción? Minifica el archivo para que vuele
  • Compatibilidad: Funciona en todos los navegadores modernos (si tienes IE6, tenemos que hablar)
  • Tamaño: Solo ~15KB minificado (más pequeño que una foto de Instagram)

Componentes Inteligentes

Crea piezas de código que funcionan como un reloj suizo: precisas, elegantes y reutilizables. Porque la vida es muy corta para escribir código repetitivo 🕰️

¿Qué Magia Tienen los Componentes?

Los componentes en ScopeJS son como ladrillos LEGO inteligentes que encapsulan todo lo que necesitas:

  • Cerebro: Controladores con lógica que realmente funciona
  • Cara bonita: Templates HTML que enamoran
  • Estilo: CSS que no se pelea con el resto
  • Personalidad: Eventos que responden como deben
  • Memoria: Estado que se actualiza automágicamente

Para Qué Sirven (Spoiler: Para Todo)

🧩

Widgets Chulos

Botones, tarjetas, formularios... Todo lo que necesitas para impresionar.

📊

Dashboards Épicos

Gráficos, métricas y paneles que hacen que los datos cobren vida.

🎨

Interfaces de Lujo

Layouts complejos que se comunican entre sí como por arte de magia.

Ejemplo Básico: Contador

Código del Componente

import { Component } from './js/ScopeJS.js';

// Definir el componente
const Counter = Component({
    // Lógica del controlador
    controller: class {
        constructor() {
            this.count = 0;
            this.step = 1;
        }
        
        increment() {
            this.count += this.step;
            this.apply(); // Re-renderizar
        }
        
        decrement() {
            this.count -= this.step;
            this.apply();
        }
        
        reset() {
            this.count = 0;
            this.apply();
        }
    },
    
    // Template HTML
    render() {
        return `
            <div class="counter-widget">
                <h3>Contador: ${this.count}</h3>
                <div class="controls">
                    <button onclick="decrement()">-</button>
                    <button onclick="increment()">+</button>
                </div>
                <button onclick="reset()">Reset</button>
            </div>
        `;
    },
    
    // Estilos CSS scoped
    style: `
        padding: 1rem;
        border: 2px solid #9333ea;
        border-radius: 0.5rem;
        text-align: center;
        background: white;
    `,
    
    // Tag personalizado
    tagName: 'my-counter'
});

// Usar el componente
const container = document.getElementById('app');
Counter.render(container);

Vista Previa

Contador: 0

Ejemplo Avanzado: Lista de Tareas

Lista Interactiva

import { Component } from './js/ScopeJS.js';

const TodoList = Component({
    controller: class {
        constructor() {
            this.todos = [];
            this.newTodo = '';
            this.filter = 'all';
        }
        
        addTodo() {
            if (this.newTodo.trim()) {
                this.todos.push({
                    id: Date.now(),
                    text: this.newTodo,
                    completed: false
                });
                this.newTodo = '';
                this.apply();
            }
        }
        
        toggleTodo(id) {
            const todo = this.todos.find(t => t.id == id);
            if (todo) {
                todo.completed = !todo.completed;
                this.apply();
            }
        }
        
        deleteTodo(id) {
            this.todos = this.todos.filter(t => t.id != id);
            this.apply();
        }
        
        get filteredTodos() {
            if (this.filter === 'completed') {
                return this.todos.filter(t => t.completed);
            }
            if (this.filter === 'active') {
                return this.todos.filter(t => !t.completed);
            }
            return this.todos;
        }
    },
    
    render() {
        return `
            <div class="todo-app">
                <h3>Lista de Tareas</h3>
                
                <div class="add-todo">
                    <input type="text" model="newTodo" 
                           placeholder="Nueva tarea...">
                    <button onclick="addTodo()">Agregar</button>
                </div>
                
                <div class="filters">
                    <button onclick="filter='all'; apply()" 
                            class="${this.filter === 'all' ? 'active' : ''}">
                        Todas
                    </button>
                    <button onclick="filter='active'; apply()" 
                            class="${this.filter === 'active' ? 'active' : ''}">
                        Activas
                    </button>
                    <button onclick="filter='completed'; apply()" 
                            class="${this.filter === 'completed' ? 'active' : ''}">
                        Completadas
                    </button>
                </div>
                
                <ul class="todo-list">
                    ${this.filteredTodos.map(todo => `
                        <li class="todo-item ${todo.completed ? 'completed' : ''}">
                            <input type="checkbox" 
                                   ${todo.completed ? 'checked' : ''} 
                                   onclick="toggleTodo(${todo.id})">
                            <span>${todo.text}</span>
                            <button onclick="deleteTodo(${todo.id})">❌</button>
                        </li>
                    `).join('')}
                </ul>
            </div>
        `;
    },
    
    style: `
        padding: 1rem;
        border: 2px solid #9333ea;
        border-radius: 0.5rem;
        background: white;
    `,
    
    tagName: 'todo-list'
});

Demo Interactivo

Lista de Tareas

    Lo Que Te Va a Volar la Cabeza

    🎯

    ⚡ Renderizado Quirúrgico (Sí, es tan genial como suena)

    ScopeJS no es de esos frameworks pesados que actualizan toda la página cada vez que cambias una coma. Nosotros somos más listos: solo tocamos lo que realmente ha cambiado. Como un cirujano del DOM.

    Precisión ninja: Si cambias un texto, solo se actualiza ese texto. Nada más.

    Eficiencia máxima: Si cambias una clase CSS, solo se modifica esa clase. Punto.

    ✨ Resultado: Animaciones fluidas, formularios que no se resetean y una experiencia de usuario que enamora

    🔄

    Data Binding Automático

    Con el atributo model los datos se sincronizan solos. ¡Magia pura!

    🎯

    Eventos Inteligentes

    Manejo de eventos que funciona como esperas, con parámetros y todo

    🎨

    CSS Encapsulado

    Estilos que se portan bien y no molestan al resto

    Súper Reactivo

    Re-renderizado eficiente solo cuando hace falta. Ni más, ni menos

    Router que No Te Decepciona

    Sistema de navegación para SPAs que funciona como debe: sin dramas, sin bugs raros y con todas las funciones que necesitas. El router que siempre quisiste 🗺️

    Configuración del Router

    Configuración Básica

    import { Router, Component } from './js/ScopeJS.js';
    
    // Definir las vistas/componentes
    const HomePage = Component({
        controller: class {
            constructor() {
                this.title = "Página de Inicio";
                this.message = "¡Bienvenido a ScopeJS!";
            }
        },
        
        render() {
            return `
                <div class="p-6 text-center">
                    <h1 class="text-3xl font-bold text-purple-800 mb-4">
                        ${this.title}
                    </h1>
                    <p class="text-gray-600">${this.message}</p>
                    <a href="/usuario/123" class="text-purple-600 hover:underline">
                        Ver perfil de usuario
                    </a>
                </div>
            `;
        }
    });
    
    const UserProfile = Component({
        controller: class {
            constructor() {
                this.userId = null;
                this.userName = "";
            }
            
            init(params) {
                this.userId = params.id;
                this.userName = `Usuario ${params.id}`;
                this.apply();
            }
        },
        
        render() {
            return `
                <div class="p-6">
                    <h1 class="text-2xl font-bold text-purple-800 mb-4">
                        Perfil de ${this.userName}
                    </h1>
                    <p class="text-gray-600 mb-4">ID: ${this.userId}</p>
                    <button onclick="history.back()" 
                            class="bg-purple-600 text-white px-4 py-2 rounded">
                        Volver
                    </button>
                </div>
            `;
        }
    });
    
    // Configurar el router
    const AppRouter = Router([
        {
            path: "/",
            component: HomePage,
            alias: "inicio"
        },
        {
            path: "/inicio",
            component: HomePage,
            alias: "home"
        },
        {
            path: "/usuario/:id",
            component: UserProfile,
            alias: "perfil-usuario",
            middleware: (params, next) => {
                // Validar que el ID sea un número
                if (isNaN(params.id)) {
                    alert("ID de usuario inválido");
                    return false;
                }
                next();
            }
        },
        {
            path: "/productos",
            alias: "catalogo-productos",
            component: Component({
                render() {
                    return `
                        <div class="p-6">
                            <h1 class="text-2xl font-bold text-purple-800 mb-4">
                                Catálogo de Productos
                            </h1>
                            <div class="grid grid-cols-2 gap-4">
                                <div class="border p-4 rounded">Producto 1</div>
                                <div class="border p-4 rounded">Producto 2</div>
                            </div>
                        </div>
                    `;
                }
            })
        }
    ]);
    
    // Renderizar el router en el DOM
    const container = document.getElementById('app');
    AppRouter.render(container);
    
    // Navegación programática
    function navigateToUser(userId) {
        AppRouter.navigate(`/usuario/${userId}`);
    }
    
    function navigateToProducts() {
        AppRouter.navigate('/productos');
    }
    
    // Escuchar cambios de ruta
    AppRouter.listen((route, params) => {
        console.log('Navegando a:', route, 'Parámetros:', params);
    });

    Navegación Programática

    Selecciona una ruta para ver la navegación

    Por Qué Este Router Mola

    🔗

    URLs Dinámicas

    Parámetros en las rutas que funcionan de verdad

    🛡️

    Middleware Inteligente

    Control de acceso y validación sin complicaciones

    📱

    SPA de Verdad

    Navegación fluida sin recargas molestas

    🎭

    Transiciones Smooth

    Cambios de vista que enamoran

    La Biblia de la API

    Todo lo que necesitas saber para dominar ScopeJS como un ninja del código. Aquí está la documentación que realmente vas a leer 📚

    Component API

    Propiedad Tipo Descripción
    controller Class Clase controladora del componente
    render Function Función que retorna el HTML del componente
    style String CSS scoped para el componente
    tagName String Nombre del elemento personalizado
    postRender Function Callback ejecutado después del render

    Modal API

    Propiedad Tipo Descripción
    controller Class Controlador del modal
    render Function Función de renderizado
    hideWhenClickOverlay Boolean Cerrar al hacer clic fuera
    className String Clase CSS adicional
    referrer Element Elemento de referencia para posición

    Router API

    Método Parámetros Descripción
    navigate path, body Navegar a una ruta específica
    render container Renderizar el router en un contenedor
    listen callback Escuchar cambios de ruta
    unlisten uuid Remover listener de cambios

    Utilidades

    Función Parámetros Descripción
    enableDebugger boolean Activar/desactivar modo debug
    apply - Re-renderizar componente
    close ...args Cerrar modal (disponible en modales)

    Playground de los Dioses

    Tu sandbox personal para experimentar con ScopeJS. Aquí puedes romper cosas, crear maravillas y aprender sin miedo. ¡Es tu momento de brillar! ⚡

    Tu Editor Personal

    Aquí Pasa la Magia

    ¡Vamos! Escribe algo genial y verás cómo cobra vida aquí ✨

    💡 Trucos de Pro:

    • • Usa this.apply() después de cambiar datos
    • • El atributo model es tu mejor amigo para formularios
    • • Los eventos son tan fáciles como onclick="miMetodo()"
    • • Los estilos CSS se aplican automágicamente (sí, es magia)

    Sobre el Autor

    Pablo Martínez
    😎

    Pablo Martínez

    Desarrollador Full Stack con un poquito de locura 🤪 por crear herramientas que hagan que los usuarios digan "¡WOW!" Creé ScopeJS porque estaba cansado de frameworks pesados que convierten proyectos simples en monstruos complicados 🐉

    Si este proyecto te ha robado el corazón ❤️ (y algunos cafés ☕), considera invitarme a una pizza 🍕 para seguir creando cositas geniales

    💖 Apóyame con una donación

    Tu apoyo me ayuda a seguir desarrollando herramientas útiles y gratuitas para la comunidad