improve docs

This commit is contained in:
2026-03-22 16:20:26 +01:00
parent 11a6c97cc5
commit e60c1f69b4
9 changed files with 833 additions and 123 deletions

View File

@@ -4,10 +4,34 @@
"type": "module",
"license": "MIT",
"exports": {
".": "./index.js",
"./plugins": "./plugins/index.js",
"./vite/*": "./vite/*.js"
".": {
"import": "./index.js",
"types": "./sigpro/sigpro.d.ts"
},
"./plugins": {
"import": "./plugins/index.js",
"types": "./plugins/index.d.ts"
},
"./vite/*": {
"import": "./vite/*.js",
"types": "./vite/*.d.ts"
}
},
"types": "./sigpro/sigpro.d.ts",
"typesVersions": {
"*": {
"*": ["./sigpro/sigpro.d.ts"],
"plugins": ["./plugins/index.d.ts"]
}
},
"files": [
"index.js",
"sigpro/",
"plugins/",
"vite/",
"README.md",
"LICENSE"
],
"homepage": "https://natxocc.github.io/sigpro/",
"repository": {
"type": "git",

106
plugins/index.d.ts vendored Normal file
View File

@@ -0,0 +1,106 @@
/**
* SigPro Plugins
* Official plugins for SigPro reactive framework
*
* @module sigpro/plugins
*/
import type { SigPro } from '../sigpro/sigpro';
/**
* Plugin context passed to all plugins
*/
export interface PluginContext {
$: SigPro;
}
/**
* Base plugin interface
*/
export interface SigProPlugin {
/** Plugin name for debugging */
name: string;
/** Plugin version */
version?: string;
/** Initialize plugin with SigPro instance */
install: (context: PluginContext) => void | Promise<void>;
}
/**
* UI Plugin - Creates reactive UI components
*
* @example
* ```javascript
* import { UI } from 'sigpro/plugins';
*
* $.plugin(UI);
*
* // Now you can use UI components
* const modal = UI.modal({
* title: 'Hello',
* content: 'This is a modal'
* });
* ```
*/
export const UI: SigProPlugin;
/**
* Fetch Plugin - Reactive data fetching
*
* @example
* ```javascript
* import { Fetch } from 'sigpro/plugins';
*
* $.plugin(Fetch);
*
* // Reactive data fetching
* const users = $.fetch('/api/users');
* const user = $.fetch(() => `/api/users/${userId()}`);
* ```
*/
export const Fetch: SigProPlugin;
/**
* Debug Plugin - Development tools and logging
*
* @example
* ```javascript
* import { Debug } from 'sigpro/plugins';
*
* $.plugin(Debug);
*
* // Debug signals in console
* $.debug(count); // Logs changes to console
* ```
*/
export const Debug: SigProPlugin;
/**
* Plugin options for each plugin
*/
export namespace PluginOptions {
interface UIOptions {
/** Prefix for CSS classes */
classPrefix?: string;
/** Default animation duration */
animationDuration?: number;
}
interface FetchOptions {
/** Base URL for all requests */
baseURL?: string;
/** Default headers */
headers?: Record<string, string>;
/** Timeout in milliseconds */
timeout?: number;
}
interface DebugOptions {
/** Enable verbose logging */
verbose?: boolean;
/** Log to console */
logToConsole?: boolean;
/** Enable time travel debugging */
timeTravel?: boolean;
}
}

View File

@@ -1,6 +1,4 @@
// /plugins/index.js
export { UI } from './ui.js';
export { Fetch } from './fetch.js';
export { Storage } from './storage.js';
export { Debug } from './debug.js';
export { Router } from './router.js';

View File

@@ -1,44 +0,0 @@
// plugins/router.js
export const Router = ($) => {
$.router = (routes) => {
const sPath = $(window.location.hash.replace(/^#/, "") || "/");
window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/"));
return div([
() => {
const current = sPath();
const route = routes.find(r => {
const rP = r.path.split('/').filter(Boolean);
const cP = current.split('/').filter(Boolean);
if (rP.length !== cP.length) return false;
return rP.every((part, i) => part.startsWith(':') || part === cP[i]);
}) || routes.find(r => r.path === "*");
if (!route) return h1("404 - Not Found");
// --- LA MEJORA AQUÍ ---
const result = typeof route.component === 'function' ? route.component() : route.component;
// Si el componente es una Promesa (Lazy Loading de Vite), esperamos
if (result instanceof Promise) {
const $lazyNode = $(span("Cargando página..."));
result.then(m => {
// Si el módulo tiene un .default (export default), lo usamos
const comp = typeof m === 'function' ? m() : (m.default ? m.default() : m);
$lazyNode(comp);
});
return () => $lazyNode();
}
return result instanceof Node ? result : span(String(result));
}
]);
};
$.router.go = (path) => {
window.location.hash = path.startsWith('/') ? path : `/${path}`;
};
window._router = $.router;
};

View File

@@ -1,31 +0,0 @@
/**
* SigPro Storage Plugin
* Automatically synchronizes signals with localStorage.
*/
export const Storage = ($) => {
/**
* Persists a signal's value in localStorage.
* @param {Function} $sig - The signal to persist.
* @param {string} key - The localStorage key name.
* @returns {Function} The same signal for chaining.
*/
_storage = ($sig, key) => {
// 1. Initial Load: If there's data in storage, update the signal immediately
const saved = localStorage.getItem(key);
if (saved !== null) {
try {
$sig(JSON.parse(saved));
} catch (e) {
console.error(`[SigPro Storage] Error parsing key "${key}":`, e);
}
}
// 2. Auto-Save: Every time the signal changes, update localStorage
$(() => {
const val = $sig();
localStorage.setItem(key, JSON.stringify(val));
});
return $sig;
};
};

387
sigpro/sigpro.d.ts vendored Normal file
View File

@@ -0,0 +1,387 @@
/**
* SigPro - Atomic Unified Reactive Engine
* A lightweight, fine-grained reactivity system with built-in routing and plugin support.
*
* @example
* ```typescript
* // Create a reactive signal
* const count = $(0);
*
* // Create a computed value
* const double = $(() => count() * 2);
*
* // Create reactive HTML
* const app = div({ $class: () => count() > 5 ? 'high' : 'low' }, [
* h1("Counter Demo"),
* p("Count: ", () => count()),
* p("Double: ", () => double()),
* button({ onclick: () => count(count() + 1) }, "Increment")
* ]);
*
* // Mount to DOM
* $.mount(app);
* ```
*/
declare global {
interface Window {
/** Main SigPro instance */
$: SigPro;
/** HTML element creators (auto-generated from tags list) */
div: typeof html;
span: typeof html;
p: typeof html;
button: typeof html;
h1: typeof html;
h2: typeof html;
h3: typeof html;
ul: typeof html;
ol: typeof html;
li: typeof html;
a: typeof html;
label: typeof html;
section: typeof html;
nav: typeof html;
main: typeof html;
header: typeof html;
footer: typeof html;
input: typeof html;
form: typeof html;
img: typeof html;
select: typeof html;
option: typeof html;
table: typeof html;
thead: typeof html;
tbody: typeof html;
tr: typeof html;
th: typeof html;
td: typeof html;
canvas: typeof html;
video: typeof html;
audio: typeof html;
}
/**
* Reactive Signal - A reactive state container
* @template T Type of the stored value
*/
interface Signal<T> {
/** Get the current value */
(): T;
/** Set a new value */
(value: T): T;
/** Update value based on previous value */
(updater: (prev: T) => T): T;
}
/**
* Computed Signal - A reactive derived value
* @template T Type of the computed value
*/
interface Computed<T> {
/** Get the current computed value */
(): T;
}
/**
* Reactive Effect - A function that re-runs when dependencies change
*/
type Effect = () => void;
/**
* HTML Content Types
*/
type HtmlContent =
| string
| number
| boolean
| null
| undefined
| Node
| HtmlContent[]
| (() => string | number | Node | null | undefined);
/**
* HTML Attributes and Event Handlers
*/
interface HtmlProps extends Record<string, any> {
/** Two-way binding for input values */
$value?: Signal<any> | ((val: any) => void);
/** Two-way binding for checkbox/radio checked state */
$checked?: Signal<boolean> | ((val: boolean) => void);
/** Reactive class binding */
$class?: string | (() => string);
/** Reactive style binding */
$style?: string | object | (() => string | object);
/** Reactive attribute binding (any attribute can be prefixed with $) */
[key: `$${string}`]: any;
/** Standard event handlers */
onclick?: (event: MouseEvent) => void;
oninput?: (event: Event) => void;
onchange?: (event: Event) => void;
onsubmit?: (event: Event) => void;
onkeydown?: (event: KeyboardEvent) => void;
onkeyup?: (event: KeyboardEvent) => void;
onfocus?: (event: FocusEvent) => void;
onblur?: (event: FocusEvent) => void;
onmouseover?: (event: MouseEvent) => void;
onmouseout?: (event: MouseEvent) => void;
[key: `on${string}`]: ((event: any) => void) | undefined;
}
/**
* Route Configuration
*/
interface Route {
/** URL path pattern (supports :params and * wildcard) */
path: string;
/** Component to render (can be sync, async, or Promise) */
component: ((params: Record<string, string>) => HTMLElement | Promise<HTMLElement>) | Promise<any> | HTMLElement;
}
/**
* Router Instance
*/
interface Router {
/** Router container element */
(routes: Route[]): HTMLElement;
/** Programmatic navigation */
go: (path: string) => void;
}
/**
* Plugin System
*/
interface Plugin {
/**
* Extend SigPro with custom functionality or load external scripts
* @param source - Plugin function, script URL, or array of URLs
* @returns SigPro instance (sync) or Promise (async loading)
*/
(source: ((sigpro: SigPro) => void) | string | string[]): SigPro | Promise<SigPro>;
}
/**
* Main SigPro Interface
*/
interface SigPro {
/**
* Create a reactive Signal or Computed value
* @template T Type of the value
* @param initial - Initial value or computed function
* @param key - Optional localStorage key for persistence
* @returns Reactive signal or computed function
*
* @example
* ```typescript
* // Signal with localStorage persistence
* const count = $(0, 'app.count');
*
* // Computed value
* const double = $(() => count() * 2);
*
* // Reactive effect (runs automatically)
* $(() => console.log('Count changed:', count()));
* ```
*/
<T>(initial: T, key?: string): Signal<T>;
<T>(computed: () => T, key?: string): Computed<T>;
/**
* Create reactive HTML elements with hyperscript syntax
* @param tag - HTML tag name
* @param props - Attributes, events, and reactive bindings
* @param content - Child nodes or content
* @returns Live DOM element with reactivity
*
* @example
* ```typescript
* const name = $('World');
*
* const element = $.html('div',
* { class: 'greeting', $class: () => name().length > 5 ? 'long' : '' },
* [
* $.html('h1', 'Hello'),
* $.html('p', () => `Hello, ${name()}!`),
* $.html('input', {
* $value: name,
* placeholder: 'Enter your name'
* })
* ]
* );
* ```
*/
html: typeof html;
/**
* Mount a component to the DOM
* @param node - Component or element to mount
* @param target - Target element or CSS selector (default: document.body)
*
* @example
* ```typescript
* // Mount to body
* $.mount(app);
*
* // Mount to specific element
* $.mount(app, '#app');
*
* // Mount with component function
* $.mount(() => div("Dynamic component"));
* ```
*/
mount: typeof mount;
/**
* Initialize a hash-based router
* @param routes - Array of route configurations
* @returns Router container element
*
* @example
* ```typescript
* const routes = [
* { path: '/', component: Home },
* { path: '/user/:id', component: UserProfile },
* { path: '*', component: NotFound }
* ];
*
* const router = $.router(routes);
* $.mount(router);
*
* // Navigate programmatically
* $.router.go('/user/42');
* ```
*/
router: Router;
/**
* Extend SigPro with plugins or load external scripts
* @param source - Plugin function, script URL, or array of URLs
* @returns SigPro instance or Promise
*
* @example
* ```typescript
* // Load external library
* await $.plugin('https://cdn.jsdelivr.net/npm/lodash/lodash.min.js');
*
* // Register plugin
* $.plugin(($) => {
* $.customMethod = () => console.log('Custom method');
* });
*
* // Load multiple scripts
* await $.plugin(['lib1.js', 'lib2.js']);
* ```
*/
plugin: Plugin;
}
/**
* Creates a reactive HTML element
* @param tag - HTML tag name
* @param props - Attributes and event handlers
* @param content - Child content
* @returns Live DOM element
*/
function html(tag: string, props?: HtmlProps | HtmlContent, content?: HtmlContent): HTMLElement;
/**
* Mount a component to the DOM
* @param node - Component or element to mount
* @param target - Target element or CSS selector
*/
function mount(node: HTMLElement | (() => HTMLElement), target?: HTMLElement | string): void;
/**
* Type-safe HTML element creators for common tags
*
* @example
* ```typescript
* // Using tag functions directly
* const myDiv = div({ class: 'container' }, [
* h1("Title"),
* p("Paragraph text"),
* button({ onclick: () => alert('Clicked!') }, "Click me")
* ]);
* ```
*/
interface HtmlTagCreator {
/**
* Create HTML element with props and content
* @param props - HTML attributes and event handlers
* @param content - Child nodes or content
* @returns HTMLElement
*/
(props?: HtmlProps | HtmlContent, content?: HtmlContent): HTMLElement;
}
// Type-safe tag creators
const div: HtmlTagCreator;
const span: HtmlTagCreator;
const p: HtmlTagCreator;
const button: HtmlTagCreator;
const h1: HtmlTagCreator;
const h2: HtmlTagCreator;
const h3: HtmlTagCreator;
const ul: HtmlTagCreator;
const ol: HtmlTagCreator;
const li: HtmlTagCreator;
const a: HtmlTagCreator;
const label: HtmlTagCreator;
const section: HtmlTagCreator;
const nav: HtmlTagCreator;
const main: HtmlTagCreator;
const header: HtmlTagCreator;
const footer: HtmlTagCreator;
const input: HtmlTagCreator;
const form: HtmlTagCreator;
const img: HtmlTagCreator;
const select: HtmlTagCreator;
const option: HtmlTagCreator;
const table: HtmlTagCreator;
const thead: HtmlTagCreator;
const tbody: HtmlTagCreator;
const tr: HtmlTagCreator;
const th: HtmlTagCreator;
const td: HtmlTagCreator;
const canvas: HtmlTagCreator;
const video: HtmlTagCreator;
const audio: HtmlTagCreator;
}
/**
* Helper types for common use cases
*/
export namespace SigProTypes {
/**
* Extract the value type from a Signal
*/
type SignalValue<T> = T extends Signal<infer U> ? U : never;
/**
* Extract the return type from a Computed
*/
type ComputedValue<T> = T extends Computed<infer U> ? U : never;
/**
* Props for a component function
*/
interface ComponentProps {
children?: HtmlContent;
[key: string]: any;
}
/**
* Component function type
*/
type Component<P extends ComponentProps = ComponentProps> = (props: P) => HTMLElement;
/**
* Async component type (for lazy loading)
*/
type AsyncComponent = () => Promise<{ default: Component }>;
}
export {};
// Make sure $ is available globally
declare const $: SigPro;

View File

@@ -2,28 +2,19 @@
* SigPro - Atomic Unified Reactive Engine
* A lightweight, fine-grained reactivity system with built-in routing and plugin support.
* @author Gemini & User
*
* Type definitions available in sigpro.d.ts
*/
(() => {
/** @type {Function|null} Internal tracker for the currently executing reactive effect. */
let activeEffect = null;
/**
* @typedef {Object} SigPro
* @property {function(any|function, string=): Function} $ - Creates a Signal or Computed. Optional key for localStorage.
* @property {function(string, Object=, any=): HTMLElement} html - Creates a reactive HTML element.
* @property {function((HTMLElement|function), (HTMLElement|string)=): void} mount - Mounts a component to the DOM.
* @property {function(Array<Object>): HTMLElement} router - Initializes a hash-based router.
* @property {function(string): void} router.go - Programmatic navigation to a hash path.
* @property {function((function|string|Array<string>)): (Promise<SigPro>|SigPro)} plugin - Extends SigPro or loads external scripts.
*/
/**
* Creates a Signal (state) or a Computed/Effect (reaction).
* Supports optional persistence in localStorage.
* * @param {any|function} initial - Initial value or a function for computed logic.
* @param {string} [key] - Optional localStorage key for automatic state persistence.
* @returns {Function} A reactive accessor/mutator function.
*/
* Creates a reactive Signal or Computed value
* @param {any|Function} initial - Initial value or computed function
* @param {string} [key] - Optional localStorage key for persistence
* @returns {Function} Reactive accessor/mutator function
*/
const $ = (initial, key) => {
const subs = new Set();
@@ -69,11 +60,11 @@
};
/**
* Hyperscript engine to render reactive HTML nodes.
* @param {string} tag - The HTML tag name (e.g., 'div', 'button').
* @param {Object} [props] - Attributes, events (onclick), or reactive props ($value, $class).
* @param {any} [content] - String, Node, Array of nodes, or reactive function.
* @returns {HTMLElement} A live DOM element linked to SigPro signals.
* Creates reactive HTML elements
* @param {string} tag - HTML tag name
* @param {Object} [props] - Attributes and event handlers
* @param {any} [content] - Child content
* @returns {HTMLElement}
*/
$.html = (tag, props = {}, content = []) => {
const el = document.createElement(tag);
@@ -87,12 +78,10 @@
el.addEventListener(key.toLowerCase().slice(2), val);
} else if (key.startsWith('$')) {
const attr = key.slice(1);
// Two-way binding for inputs
if ((attr === 'value' || attr === 'checked') && typeof val === 'function') {
const ev = attr === 'checked' ? 'change' : 'input';
el.addEventListener(ev, e => val(attr === 'checked' ? e.target.checked : e.target.value));
}
// Reactive attribute update
$(() => {
const v = typeof val === 'function' ? val() : val;
if (attr === 'value' || attr === 'checked') el[attr] = v;
@@ -126,9 +115,9 @@
tags.forEach(t => window[t] = (p, c) => $.html(t, p, c));
/**
* Application mounter.
* @param {HTMLElement|function} node - Root component or element to mount.
* @param {HTMLElement|string} [target=document.body] - Target element or CSS selector.
* Mounts a component to the DOM
* @param {HTMLElement|Function} node - Component or element to mount
* @param {HTMLElement|string} [target=document.body] - Target element or selector
*/
$.mount = (node, target = document.body) => {
const el = typeof target === 'string' ? document.querySelector(target) : target;
@@ -139,11 +128,10 @@
};
/**
* Initializes a reactive hash-based router.
* Maps URL hash changes to component rendering and supports Vite's dynamic imports.
* * @param {Array<{path: string, component: Function|Promise|HTMLElement}>} routes - Array of route objects.
* @returns {HTMLElement} A reactive div container that swaps content based on the current hash.
*/
* Initializes a hash-based router
* @param {Array<{path: string, component: Function|Promise|HTMLElement}>} routes
* @returns {HTMLElement}
*/
$.router = (routes) => {
const sPath = $(window.location.hash.replace(/^#/, "") || "/");
window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/"));
@@ -185,20 +173,17 @@
};
/**
* Programmatically navigates to a specific path using the hash.
* * @param {string} path - The destination path (e.g., '/home' or 'settings').
* @example
* $.router.go('/profile/42');
* Programmatic navigation
* @param {string} path - Destination path
*/
$.router.go = (path) => {
window.location.hash = path.startsWith('/') ? path : `/${path}`;
};
/**
* Polymorphic Plugin System.
* Registers internal functions or loads external .js files as plugins.
* @param {function|string|Array<string>} source - Plugin function or URL(s).
* @returns {Promise<SigPro>|SigPro} Resolves with the $ instance after loading or registering.
* Plugin system - extends SigPro or loads external scripts
* @param {Function|string|string[]} source - Plugin or script URL(s)
* @returns {Promise<SigPro>|SigPro}
*/
$.plugin = (source) => {
if (typeof source === 'function') {

261
vite/index.d.ts vendored Normal file
View File

@@ -0,0 +1,261 @@
/**
* SigPro Vite Plugin
* Provides file-based routing and development tools for Vite
*
* @example
* ```javascript
* // vite.config.js
* import { defineConfig } from 'vite';
* import sigproRouter from 'sigpro/vite';
*
* export default defineConfig({
* plugins: [sigproRouter()]
* });
* ```
*/
import type { Plugin } from 'vite';
/**
* File-based routing configuration options
*/
export interface SigProRouterOptions {
/**
* Directory where page components are stored
* @default 'src/pages'
* @example
* ```javascript
* sigproRouter({ pagesDir: 'src/views' })
* ```
*/
pagesDir?: string;
/**
* File extensions to consider as pages
* @default ['.js', '.jsx', '.ts', '.tsx']
* @example
* ```javascript
* sigproRouter({ extensions: ['.js', '.jsx'] })
* ```
*/
extensions?: string[];
/**
* Custom route transformation function
* @param filePath - Absolute path to the file
* @returns Custom route path or null to skip
* @example
* ```javascript
* sigproRouter({
* transformRoute: (path) => {
* // Convert 'src/pages/blog/post.js' to '/blog/post'
* return path.replace(/^src\/pages/, '').replace(/\.js$/, '');
* }
* })
* ```
*/
transformRoute?: (filePath: string) => string | null;
/**
* Base path prefix for all routes
* @default ''
* @example
* ```javascript
* sigproRouter({ basePath: '/app' }) // Routes become /app/about, /app/users, etc.
* ```
*/
basePath?: string;
/**
* Custom 404 component path
* @default null (uses default "404 - Not Found")
* @example
* ```javascript
* sigproRouter({ notFoundComponent: 'src/pages/NotFound.js' })
* ```
*/
notFoundComponent?: string;
}
/**
* Route configuration generated by the plugin
*/
export interface GeneratedRoute {
/** URL path pattern (supports :params and * wildcard) */
path: string;
/** Lazy-loaded component */
component: () => Promise<any>;
}
/**
* Virtual module ID for generated routes
* @example
* ```javascript
* import { routes } from 'virtual:sigpro-routes';
* ```
*/
export const virtualModuleId = 'virtual:sigpro-routes';
/**
* Vite plugin for SigPro file-based routing
*
* Features:
* - 📁 File-based routing from `src/pages` directory
* - 🔄 Automatic route generation
* - 🚀 Lazy-loading support with code splitting
* - 📦 Dynamic routes with `[param]` syntax → `/:param`
* - ⭐ Catch-all routes with `[...param]` syntax → `/*`
* - 🎯 Index routes (`index.js` becomes `/`)
* - 🧹 Automatic sorting (static routes first, then dynamic)
* - 🎨 404 fallback generation
*
* @example
* **File Structure:**
* ```
* src/pages/
* ├── index.js → '/'
* ├── about.js → '/about'
* ├── blog/
* │ ├── index.js → '/blog'
* │ ├── [slug].js → '/blog/:slug'
* │ └── [...catch].js → '/blog/*'
* └── user/
* ├── index.js → '/user'
* └── [id].js → '/user/:id'
* ```
*
* @example
* **Generated Routes:**
* ```javascript
* // virtual:sigpro-routes
* export const routes = [
* { path: '/', component: () => import('src/pages/index.js') },
* { path: '/about', component: () => import('src/pages/about.js') },
* { path: '/blog', component: () => import('src/pages/blog/index.js') },
* { path: '/blog/:slug', component: () => import('src/pages/blog/[slug].js') },
* { path: '/blog/*', component: () => import('src/pages/blog/[...catch].js') },
* { path: '/user', component: () => import('src/pages/user/index.js') },
* { path: '/user/:id', component: () => import('src/pages/user/[id].js') },
* { path: '*', component: () => import('src/pages/NotFound.js') } // If exists
* ];
* ```
*
* @example
* **Usage with SigPro:**
* ```javascript
* // main.js
* import { routes } from 'virtual:sigpro-routes';
* import { $ } from 'sigpro';
*
* const router = $.router(routes);
* $.mount(router, '#app');
* ```
*
* @param options - Plugin configuration options
* @returns Vite plugin object
*/
export default function sigproRouter(options?: SigProRouterOptions): Plugin;
/**
* Page component props for route components
* @template Params - Type of route parameters
*/
export interface PageProps<Params = Record<string, string>> {
/** URL parameters from dynamic routes (e.g., :id, :slug) */
params: Params;
/** URL search parameters (query string) */
query: URLSearchParams;
/** Current pathname without query string */
pathname: string;
/** Children components (for nested routes) */
children?: any;
}
/**
* Route component type
* @template Params - Type of route parameters
*/
export type PageComponent<Params = Record<string, string>> = (
props: PageProps<Params>
) => HTMLElement | Promise<HTMLElement>;
/**
* Helper function to create typed route components
* Provides better TypeScript support and autocompletion
*
* @example
* ```javascript
* // pages/user/[id].js
* import { createPage } from 'sigpro/vite';
*
* export default createPage(({ params, query }) => {
* const { id } = params; // TypeScript knows this is a string
* const page = query.get('page') || 1;
*
* return div({ class: 'user-profile' }, [
* h1(`User ${id}`),
* p(`Page: ${page}`),
* button({
* onclick: () => console.log('Viewing user', id)
* }, 'View Profile')
* ]);
* });
* ```
*
* @example
* **With TypeScript:**
* ```typescript
* // pages/user/[id].tsx
* interface UserParams {
* id: string;
* }
*
* export default createPage<UserParams>(({ params, query }) => {
* const userId = params.id; // TypeScript knows this is string
* // ... rest of component
* });
* ```
*/
export function createPage<Params = Record<string, string>>(
component: (props: PageProps<Params>) => HTMLElement | Promise<HTMLElement>
): PageComponent<Params>;
/**
* Type guard to check if a component is lazy-loaded
* @param component - Component to check
* @returns True if component is a lazy-loaded module
*/
export function isLazyComponent(component: any): component is () => Promise<any>;
/**
* Utility to preload routes for better performance
* @example
* ```javascript
* import { preloadRoutes } from 'sigpro/vite';
*
* // Preload routes after initial load
* preloadRoutes(['/about', '/blog']);
* ```
*/
export function preloadRoutes(paths: string[]): Promise<void>;
/**
* Debug helper to inspect generated routes
* @example
* ```javascript
* // Only in development
* if (import.meta.env.DEV) {
* const routes = await import('virtual:sigpro-routes');
* console.table(routes);
* }
* ```
*/
export function inspectRoutes(): void;
/**
* Virtual module declarations for client-side code
* This allows TypeScript to understand the virtual module
*/
declare module 'virtual:sigpro-routes' {
export const routes: GeneratedRoute[];
}

View File

@@ -1,4 +1,28 @@
// src/vite/index.js
import sigproRouterPlugin from './sigproRouter.js';
export const sigproRouter = sigproRouterPlugin;
export default sigproRouterPlugin;
/**
* SigPro Vite Plugin
* @module sigpro/vite
*/
// ✅ Correcto: importas la función y la llamas como quieras
import sigproRouter from './router.js';
/**
* Vite plugin for SigPro file-based routing
*
* @example
* ```javascript
* // vite.config.js
* import sigproRouter from 'sigpro/vite';
*
* export default {
* plugins: [sigproRouter()]
* };
* ```
*
* @param {import('./index.d.ts').SigProRouterOptions} [options] - Plugin configuration options
* @returns {import('vite').Plugin} Vite plugin instance
*/
export default sigproRouter;
// Opcional: también exportar como named export
export { sigproRouter };