diff --git a/docs/404.html b/docs/404.html index 53d9921..4ef9478 100644 --- a/docs/404.html +++ b/docs/404.html @@ -17,7 +17,7 @@
- + \ No newline at end of file diff --git a/docs/api/$.html b/docs/api/$.html index 6816a9b..8fe094d 100644 --- a/docs/api/$.html +++ b/docs/api/$.html @@ -13,35 +13,72 @@ - + -
Skip to content

The Reactive Core: $( )

The $ function is the heart of SigPro. It is a Unified Reactive Constructor that handles state, derivations, and automatic persistence through a single, consistent interface.

1. The Constructor: $( input, [key] )

Depending on the arguments you pass, SigPro creates different reactive primitives:

ArgumentTypeRequiredDescription
inputValue / FunctionYesInitial state or reactive logic.
keystringNoIf provided, the signal persists in localStorage.

2. Signal (State & Persistence)

A Signal is a reactive "box" for data. SigPro now supports Native Persistence: if you provide a second argument (the key), the signal will automatically sync with localStorage.

  • Standard: const $count = $(0);
  • Persistent: const $theme = $("light", "app-theme"); (Restores value on page reload).

Example:

javascript
const $user = $("Guest", "session-user"); // Automatically saved/loaded
+    
Skip to content

The Reactive Core: $( )

The $ function is a Unified Reactive Constructor. It detects the type of input you provide and returns the appropriate reactive primitive.


1. Signals (Atomic State)

A Signal is the simplest form of reactivity. It holds a single value (string, number, boolean, null).

Option A: Standard Signal (RAM)

Ideal for volatile state that shouldn't persist after a page refresh.

javascript
const $count = $(0); 
 
-// Read (Getter)
-console.log($user()); 
+// Usage:
+$count();           // Getter: returns 0
+$count(10);         // Setter: updates to 10
+$count(c => c + 1); // Functional update: updates to 11

Option B: Persistent Signal (Disk)

By adding a key, SigPro links the signal to localStorage.

javascript
// Syntax: $(initialValue, "storage-key")
+const $theme = $("light", "app-theme"); 
 
-// Update (Setter + Auto-save to Disk)
-$user("Alice"); 
+// It restores the value from disk automatically on load.
+// When you update it, it saves to disk instantly:
+$theme("dark"); // localStorage.getItem("app-theme") is now "dark"

2. Stores (Reactive Objects)

A Store is a proxy that wraps an Object. SigPro makes every property reactive recursively. You access and set properties as if they were individual signals.

Option A: Standard Store (RAM)

javascript
const user = $({ 
+  name: "Alice", 
+  profile: { bio: "Developer" } 
+});
 
-// Functional Update
-$user(prev => prev.toUpperCase());

3. Computed (Derived State)

When you pass a function that returns a value, SigPro creates a Computed Signal. It tracks dependencies and recalculates only when necessary.

  • Syntax: const $derived = $(() => logic);

Example:

javascript
const $price = $(100);
-const $qty = $(2);
+// Getter: Call the property as a function
+console.log(user.name()); // "Alice"
 
-// Auto-tracks $price and $qty
-const $total = $(() => $price() * $qty());
+// Setter: Pass the value to the property function
+user.name("Bob"); 
 
-$qty(3); // $total updates to 300 automatically

4. Effects (Reactive Actions)

An Effect is a function that does not return a value. It performs an action (side effect) whenever the signals it "touches" change.

  • When to use: Logging, manual DOM tweaks, or syncing with external APIs.
  • Syntax: $(() => { action });

Example:

javascript
const $status = $("online");
+// Nested updates work exactly the same:
+user.profile.bio("Architect");

Option B: Persistent Store (Disk)

The most powerful way to save complex state. The entire object tree is serialized to JSON and kept in sync with the disk.

javascript
const settings = $({ 
+  volume: 50, 
+  notifications: true 
+}, "user-settings");
 
-// Runs every time $status changes
+// Any change in the object triggers a disk sync:
+settings.volume(100); // The whole JSON is updated in localStorage

3. Stores (Reactive Arrays)

When you pass an Array, SigPro tracks changes to the list. You can use standard methods or access indexes as reactive getters.

javascript
const $list = $(["Item 1", "Item 2"]);
+
+// Get by index
+console.log($list[0]()); // "Item 1"
+
+// Update by index
+$list[0]("Updated Item");
+
+// Note: For adding/removing items, use standard array methods 
+// which SigPro makes reactive (push, pop, splice, etc.)

4. Computed (Derived Logic)

A Computed Signal is a read-only value that depends on other signals. It is defined by passing a function that returns a value.

javascript
const $price = $(100);
+const $tax = $(0.21);
+
+// This function HAS a return statement
+const $total = $(() => {
+  return $price() * (1 + $tax());
+});
+
+// Usage (Read-only):
+console.log($total()); // 121
+
+$price(200);
+console.log($total()); // 242 (Auto-updated)

5. Effects (Reactive Actions)

An Effect is used for side-effects. It is defined by passing a function that does NOT return a value. It runs once immediately and then re-runs whenever its dependencies change.

javascript
const $name = $("Alice");
+
+// This function has NO return statement (Side-effect)
 $(() => {
-  console.log("System status is now:", $status());
-});

5. Summary Table: Usage Guide

PrimitiveLogic TypePersistence?Typical Use Case
SignalMutable StateYes (Optional)$(0, 'counter')
ComputedDerived / Read-onlyNo$(() => $a() + $b())
EffectImperative ActionNo$(() => alert($msg()))

💡 Pro Tip: The Power of Native Persistence

In SigPro, you don't need external plugins for basic storage. By using the key parameter in a Signal, you gain:

  1. Zero Boilerplate: No more JSON.parse(localStorage.getItem(...)).
  2. Instant Hydration: The value is restored before the UI renders, preventing "flicker".
  3. Atomic Safety: Data is saved to disk exactly when the signal changes, ensuring your app state is always safe.

Naming Convention

We use the $ prefix (e.g., $count) for reactive functions to distinguish them from static variables at a glance:

javascript
let count = 0;       // Static
-const $count = $(0); // Reactive Signal
- + console.log("The name changed to:", $name()); + document.title = `Profile: ${$name()}`; +}); + +$name("Bob"); // Triggers the console.log and updates document.title

6. Summary: Input Mapping

If you pass...SigPro creates a...Access Method
A ValueSignal$var() / $var(val)
An ObjectStoreobj.prop() / obj.prop(val)
An ArrayArray Storearr[i]() / arr.push()
Function (returns)Computed$comp() (Read-only)
Function (no return)EffectAutomatically executed

💡 Naming Convention: The $ Prefix

To keep your code clean, always prefix your reactive variables with $. This tells you at a glance that you need to call it as a function to get its value.

javascript
const name = "Static";   // Just a string
+const $name = $("Alice"); // A Reactive Signal
+ \ No newline at end of file diff --git a/docs/api/html.html b/docs/api/html.html index cf8d50c..15b0257 100644 --- a/docs/api/html.html +++ b/docs/api/html.html @@ -19,7 +19,7 @@ -
Skip to content

Rendering Engine: $.html

The $.html function is the architect of your UI. It creates standard HTML elements and wires them directly to your signals without the need for a Virtual DOM.

1. Syntax: $.html(tag, [props], [content])

ParameterTypeRequiredDescription
tagstringYesAny valid HTML5 tag (e.g., 'div', 'button', 'input').
propsObjectNoAttributes, event listeners, and reactive bindings.
contentanyNoText, Nodes, Arrays, or Reactive Functions.

Example:

javascript
const myButton = $.html('button', { class: 'btn-primary' }, 'Click me');

2. Global Tag Helpers

To avoid repetitive $.html calls, SigPro automatically exposes common tags to the global window object. This allows for a clean, declarative syntax.

javascript
// Instead of $.html('div', ...), just use:
+    
Skip to content

Rendering Engine: $.html

The $.html function is the architect of your UI. It creates standard HTML elements and wires them directly to your signals without the need for a Virtual DOM.

1. Syntax: $.html(tag, [props], [content])

ParameterTypeRequiredDescription
tagstringYesAny valid HTML5 tag (e.g., 'div', 'button', 'input').
propsObjectNoAttributes, event listeners, and reactive bindings.
contentanyNoText, Nodes, Arrays, or Reactive Functions.

Example:

javascript
const myButton = $.html('button', { class: 'btn-primary' }, 'Click me');

2. Global Tag Helpers

To avoid repetitive $.html calls, SigPro automatically exposes common tags to the global window object. This allows for a clean, declarative syntax.

javascript
// Instead of $.html('div', ...), just use:
 div({ id: 'wrapper' }, [
   h1("Welcome"),
   p("This is SigPro.")
@@ -41,7 +41,7 @@
     ? h1("High Score!") 
     : p("Keep going...");
 });

The "Guillotine" (Performance Tip)

When a reactive function in the content returns a new Node, SigPro uses replaceWith() to swap the old node for the new one. This ensures that:

  1. The update is nearly instantaneous.
  2. The old node is correctly garbage-collected.

6. Summary: Content Types

InputBehavior
String / NumberAppended as a TextNode.
HTMLElementAppended directly to the parent.
ArrayEach item is processed and appended in order.
Function () => ...Creates a live reactive zone that updates automatically.
- + \ No newline at end of file diff --git a/docs/api/mount.html b/docs/api/mount.html index 6e520a7..92b6b20 100644 --- a/docs/api/mount.html +++ b/docs/api/mount.html @@ -3,7 +3,7 @@ - Application Mounter: $.router.mount (Core) | SigPro + Application Mounter: $.mount | SigPro @@ -13,13 +13,13 @@ - + -
Skip to content

Application Mounter: $.router.mount (Core)

The $.mount function is the entry point of your reactive world. It takes a SigPro component (or a plain DOM node) and injects it into the real document, bridging the gap between your logic and the browser.

1. Syntax: $.mount(node, [target])

ParameterTypeDefaultDescription
nodeHTMLElement or FunctionRequiredThe component or element to render.
targetstring or HTMLElementdocument.bodyWhere to mount the app (CSS selector or Element).

2. Usage Scenarios

A. The "Clean Slate" (Main Entry)

In a modern app, you usually want to control the entire page. By default, $.mount clears the target's existing HTML before mounting your application.

javascript
// src/main.js
+    
Skip to content

Application Mounter: $.mount

The $.mount function is the entry point of your reactive world. It takes a SigPro component (or a plain DOM node) and injects it into the real document, bridging the gap between your logic and the browser.

1. Syntax: $.mount(node, [target])

ParameterTypeDefaultDescription
nodeHTMLElement or FunctionRequiredThe component or element to render.
targetstring or HTMLElementdocument.bodyWhere to mount the app (CSS selector or Element).

2. Usage Scenarios

A. The "Clean Slate" (Main Entry)

In a modern app, you usually want to control the entire page. By default, $.mount clears the target's existing HTML before mounting your application.

javascript
// src/main.js
 import { $ } from 'sigpro';
 import App from './App.js';
 
@@ -48,7 +48,7 @@
 
 const myNode = $.html('div', 'Local Widget');
 $.mount(myNode, '#widget-target');

6. Summary Cheat Sheet

GoalCode
Mount to body$.mount(App)
Mount to ID$.mount(App, '#id')
Mount to Element$.mount(App, myElement)
Direct Function$.mount(() => div("Hi"), '#widget')
- + \ No newline at end of file diff --git a/docs/api/quick.html b/docs/api/quick.html index 1892e97..0d42c06 100644 --- a/docs/api/quick.html +++ b/docs/api/quick.html @@ -3,7 +3,7 @@ - Quick API Reference ⚡ | SigPro + Quick API Reference | SigPro @@ -13,20 +13,81 @@ - + -
Skip to content

Quick API Reference ⚡

This is a high-level summary of the SigPro core API. For detailed guides and edge cases, please refer to the specific documentation for each module.

1. Core Reactivity: $( )

The $ function is a polymorphic constructor. It creates Signals (state) or Computed Effects (logic) based on the input type.

UsageInput TypeReturnsDescription
SignalanyFunctionA getter/setter for reactive state.
ComputedFunctionFunctionA read-only signal that auto-updates when its dependencies change.

Example:

javascript
const $count = $(0);             // Signal
-const $double = $(() => $count() * 2); // Computed

2. Rendering Engine: $.html

SigPro uses a hyperscript-style engine to create live DOM nodes.

ArgumentTypeRequiredDescription
tagstringYesStandard HTML tag (e.g., 'div', 'button').
propsObjectNoAttributes (id), Events (onclick), or Reactive Props ($value).
contentanyNoString, Node, Array, or Reactive Function.

Example:

javascript
$.html('button', { onclick: () => alert('Hi!') }, 'Click Me');

3. Global Helpers (Tag Proxies)

To keep your code clean, SigPro automatically exposes common HTML tags to the global scope.

CategoryAvailable Tags
Layoutdiv, section, main, nav, header, footer, span
Typographyh1, h2, h3, p, label, a, li, ul, ol
Formsinput, button, form, select, option
Mediaimg, video, audio, canvas

Example:

javascript
// No imports needed!
-div([ 
-  h1("Title"), 
-  button("Ok") 
-]);

4. Mounting & Plugins

Methods to initialize your application and extend the engine.

MethodSignatureDescription
$.mount(node, target)Wipes the target (default: body) and renders the component.
$.plugin(source)Registers a function or loads external .js scripts as plugins.

Example:

javascript
$.plugin([UI, Router]);
-$.mount(App, '#root');

5. Reactive Syntax Cheat Sheet

FeatureSyntaxDescription
Text Bindingp(["Value: ", $sig])Updates text content automatically.
Attributesdiv({ id: $sig })Static attribute assignment.
Reactive Attrdiv({ $class: $sig })Attribute updates when $sig changes.
Two-way Bindinginput({ $value: $sig })Syncs input value and signal automatically.
Conditionaldiv(() => $sig() > 0 ? "Yes" : "No")Re-renders only the content when the condition changes.

Summary Table

FeatureSigPro ApproachBenefit
Update LogicFine-grained (Surgical)Blazing fast updates.
DOMNative NodesZero abstraction cost.
SyntaxPure JavaScriptNo build-tool lock-in.
FootprintModularLoad only what you use.
- +
Skip to content

Quick API Reference

SigPro is a minimal yet powerful engine. Here is a complete overview of its capabilities.

1. Core API Summary

FunctionDescriptionExample
$(val, key?)Creates a Signal, Computed, or Store (with optional persistence).const $n = $(0)
$.html()The base engine to create reactive HTMLElements.$.html('div', {}, 'Hi')
TagsGlobal helpers (div, span, button, etc.) built on top of $.html.div("Hello SigPro")
$.mount()Mounts a component into a target element (clears target first).$.mount(App, '#app')
$.router()Hash-based router with dynamic params and lazy loading.$.router(routes)
$.plugin()Extends SigPro or loads external scripts/plugins.$.plugin(MyPlugin)

2. The Power of $ (Reactivity)

The $ function adapts to whatever you pass to it:

Signals & Persistent State

Reactive values in RAM or synced with localStorage.

javascript
const $count = $(0);                      // Simple Signal
+const $theme = $('dark', 'app-theme');    // Persistent Signal (Disk)
+
+$count(10);             // Update value
+console.log($count());  // Get value: 10

Computed Signals

Read-only signals that update automatically when their dependencies change.

javascript
const $double = $(() => $count() * 2);

Reactive Stores (Objects + Disk)

Transforms an object into a reactive tree. If a key is provided, the entire structure persists.

javascript
// Store in RAM + Disk (Auto-syncs nested properties)
+const state = $({ 
+  user: { name: 'Natxo' }, 
+  settings: { dark: true } 
+}, 'my-app-state');
+
+// Accessing properties (they become signals)
+state.user.name();         // Get: 'Natxo'
+state.user.name('Guest');  // Set & Sync to Disk: 'my-app-state_user_name'

3. UI Creation: Constructor vs. Direct Tags

SigPro provides the $.html engine for defining any element and global "Sugar Tags" for rapid development.

javascript
// 1. DEFINE: Create a custom piece of UI
+// This returns a real DOM element ready to be used.
+const MyHero = $.html('section', { class: 'hero' }, [
+  h1("Internal Title")
+]);
+
+// 2. USE: Nest it inside other elements like a standard tag
+const Page = () => div([
+  MyHero, // We just drop the variable here
+  p("This paragraph is outside the Hero section.")
+]);
+
+$.mount(Page, '#app');
javascript
// Use pre-defined global tags to compose layouts instantly.
+// No need to define them, just call them.
+
+const Page = () => div({ id: 'main' }, [
+  section({ class: 'hero' }, [
+    h1("Direct Global Tag"),
+    p("Building UI without boilerplate.")
+  ]),
+  button({ onclick: () => alert('Hi!') }, "Click Me")
+]);
+
+$.mount(Page, '#app');

Technical Breakdown

  • $.html(tag, props, children): This is the core factory. Use it when you need to create an element dynamically or when working with Custom Elements / Web Components.
  • Global Tags (div, p, etc.): These are shortcut functions that SigPro injects into the window object. They internally call $.html for you, making your component code much cleaner and easier to read.

Key Difference

  • $.html: Acts as a constructor. Use it when you want to "bake" a specific structure (like a Section that always contains an H1) into a single variable.
  • Global Tags: Act as scaffolding. Use them to wrap different contents dynamically as you build your views.

Global Tags (Standard Syntax)

SigPro declares standard tags in the global scope so you don't have to import them.

javascript
const Card = (title, $val) => div({ class: 'card' }, [
+  h2(title),
+  p("Reactive content below:"),
+  input({ 
+    type: 'number', 
+    $value: $val, // Automatic Two-way binding
+    $style: () => $val() > 10 ? 'color: red' : 'color: green' 
+  })
+]);

4. Mounting: $.mount

The entry point of your application. It links your JavaScript logic to a specific DOM element.

html
<div id="app"></div>
javascript
// In your main.js
+const App = () => main([ 
+  h1("Welcome to SigPro"),
+  p("Everything here is reactive.")
+]);
+
+// Usage: $.mount(component, selectorOrElement)
+$.mount(App, '#app');

5. Navigation: $.router

A robust hash-based router (#/path) that handles view switching automatically.

javascript
const routes = [
+  { path: '/', component: Home },
+  { path: '/user/:id', component: (params) => h1(`User ID: ${params.id}`) },
+  { path: '/admin', component: () => import('./Admin.js') }, // Native Lazy Loading
+  { path: '*', component: () => p("404 - Not Found") }
+];
+
+// Initialize and mount the router
+$.mount($.router(routes), '#app');
+
+// Programmatic navigation
+$.router.go('/user/42');

6. Plugins: $.plugin

Extend the engine or load external dependencies.

javascript
// 1. Function-based plugin
+$.plugin(($) => {
+  $.myHelper = () => console.log("Plugin active!");
+});
+
+// 2. Load external scripts
+await $.plugin('https://cdn.example.com/library.js');
+ \ No newline at end of file diff --git a/docs/api/router.html b/docs/api/router.html index dda62bd..34432de 100644 --- a/docs/api/router.html +++ b/docs/api/router.html @@ -19,7 +19,7 @@ -
Skip to content

Routing Engine: $.router

The $.router is SigPro's high-performance, hash-based navigation system. It connects the browser's URL directly to your reactive signals, enabling seamless page transitions without full reloads.

1. Core Features

  • Hash-based: Works everywhere without special server configuration (using #/path).
  • Lazy Loading: Pages are only downloaded when the user visits the route, keeping the initial bundle under 2KB.
  • Reactive: The view updates automatically and surgically when the hash changes.
  • Dynamic Routes: Built-in support for parameters like /user/:id.

2. Syntax: $.router(routes)

ParameterTypeRequiredDescription
routesArray<Object>YesAn array of route definitions { path, component }.

3. Setting Up Routes

In your App.js (or a dedicated routes file), define your navigation map and inject it into your layout.

javascript
const routes = [
+    
Skip to content

Routing Engine: $.router

The $.router is SigPro's high-performance, hash-based navigation system. It connects the browser's URL directly to your reactive signals, enabling seamless page transitions without full reloads.

1. Core Features

  • Hash-based: Works everywhere without special server configuration (using #/path).
  • Lazy Loading: Pages are only downloaded when the user visits the route, keeping the initial bundle under 2KB.
  • Reactive: The view updates automatically and surgically when the hash changes.
  • Dynamic Routes: Built-in support for parameters like /user/:id.

2. Syntax: $.router(routes)

ParameterTypeRequiredDescription
routesArray<Object>YesAn array of route definitions { path, component }.

3. Setting Up Routes

In your App.js (or a dedicated routes file), define your navigation map and inject it into your layout.

javascript
const routes = [
   { path: '/', component: () => h1("Home Page") },
   { 
     path: '/admin', 
@@ -56,7 +56,7 @@
   NavLink('/', 'Home'),
   NavLink('/settings', 'Settings')
 ]);

7. Summary: Route Component Types

Component TypeBehavior
HTMLElementRendered immediately.
Function (params) => ...Executed with URL parameters and rendered.
Promise / import()Triggers Lazy Loading with a loading state.
String / NumberRendered as simple text inside a span.
- + \ No newline at end of file diff --git a/docs/api/tags.html b/docs/api/tags.html index 636f29b..7cdc861 100644 --- a/docs/api/tags.html +++ b/docs/api/tags.html @@ -13,68 +13,44 @@ - + -
Skip to content

Global Tag Helpers

In SigPro, you don't need to write $.html('div', ...) every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags.

1. How it Works

When SigPro initializes, it runs a proxy loop that creates a function for every common HTML tag and attaches it to the window object.

  • Traditional: $.html('button', { onclick: ... }, 'Click')
  • SigPro Style: button({ onclick: ... }, 'Click')

This approach gives you a "DSL" (Domain Specific Language) that feels like HTML but is actually pure JavaScript.


2. The Global Registry

The following tags are available globally by default:

CategoryAvailable Functions
Layoutdiv, span, section, main, nav, header, footer, article, aside
Typographyh1, h2, h3, p, ul, ol, li, a, label, strong, em
Formsform, input, button, select, option, textarea
Tabletable, thead, tbody, tr, th, td
Mediaimg, video, audio, canvas, svg

3. Usage Patterns

The tag functions are highly flexible and accept arguments in different orders to suit your coding style.

A. Attributes + Content

The most common pattern.

javascript
div({ class: 'card' }, [
-  h1("Title"),
-  p("Description")
-]);

B. Content Only

If you don't need attributes, you can skip the object entirely.

javascript
div([
-  h1("Just Content"),
-  p("No attributes object needed here.")
-]);

C. Simple Text

For elements that only contain a string.

javascript
button("Submit"); // Equivalent to <button>Submit</button>

4. Reactive Tags

Since these helpers are just wrappers around $.html, they support full reactivity out of the box.

javascript
const $loading = $(true);
+    
Skip to content

Global Tag Helpers

In SigPro, you don't need to write $.html('div', ...) every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags upon initialization.

1. How it Works

SigPro iterates through an internal manifest of standard HTML tags and attaches a wrapper function for each one directly to the window object. This creates a native "DSL" (Domain Specific Language) that looks like a template engine but is 100% standard JavaScript.

  • Under the hood: $.html('button', { onclick: ... }, 'Click')
  • SigPro Style: button({ onclick: ... }, 'Click')

2. The Complete Global Registry

The following tags are injected into the global scope and are ready to use as soon as SigPro loads:

CategoryAvailable Global Functions
Structurediv, span, p, section, nav, main, header, footer, article, aside
Typographyh1, h2, h3, h4, h5, h6, ul, ol, li, dl, dt, dd, strong, em, code, pre, small, i, b, u, mark
Interactivebutton, a, label, br, hr, details, summary
Formsform, input, select, option, textarea, fieldset, legend
Tablestable, thead, tbody, tr, th, td, tfoot, caption
Media & Graphicsimg, canvas, video, audio, svg, path, iframe

"In SigPro, tags are not 'magic' strings handled by a compiler. They are functional imitations of HTML elements. Every time you call div(), you are executing a standard JavaScript function that returns a real DOM element. This gives you the speed of a specialized DSL with the transparency of pure JS."

WARNING: GLOBAL NAMING COLLISIONS

Since SigPro injects these helpers directly into the window object, they are regular JavaScript functions. This means they can be overwritten.

If you declare a variable, constant, or function with the same name as an HTML tag (e.g., const div = ... or function p()), you will nullify or shadow the built-in SigPro helper for that tag in your current scope.

Best Practice: To avoid conflicts, always use PascalCase for your custom components (e.g., UserCard, AppHeader) to distinguish them from the lowercase global HTML helpers.


3. Usage Patterns (Argument Flexibility)

The tag functions are "smart". They detect whether you are passing attributes, content, or both.

A. Attributes + Content

The standard way to build complex nodes.

javascript
div({ class: 'container', id: 'main-wrapper' }, [
+  h1("Welcome"),
+  p("This is SigPro.")
+]);

B. Content Only (The "Skipper")

If you don't need attributes, you can pass the content (string, array, or function) as the first and only argument.

javascript
section([
+  h2("No Attributes Needed"),
+  button("Click Me")
+]);

C. Primitive Content

For simple tags, you can just pass a string or a number.

javascript
h1("Hello World"); 
+span(42);

4. Reactive Attributes & Content

These helpers fully support SigPro's reactivity. Attributes starting with $ are automatically tracked.

javascript
const $count = $(0);
 
-div([
-  $loading() ? span("Loading...") : h1("Data Ready!"),
+div({ class: 'counter-app' }, [
+  h2(["Current Count: ", $count]), // Auto-unwrapping text content
+  
   button({ 
-    $disabled: $loading, // Reactive attribute
-    onclick: () => $loading(false) 
-  }, "Stop Loading")
-]);

5. Under the Hood

If you are curious about how this happens without a compiler, here is the logic inside the SigPro core:

javascript
const tags = ['div', 'span', 'p', 'button', ...];
-
-tags.forEach(tag => {
-  window[tag] = (props, content) => $.html(tag, props, content);
-});

Because these are attached to window, they are available in any file in your project as soon as SigPro is loaded, making your components look like this:

javascript
// No imports required for tags!
-export default () => 
-  section({ id: 'hero' }, [
-    h1("Fast. Atomic. Simple."),
-    p("Built with SigPro.")
-  ]);

6. Full Comparison: SigPro vs. Standard HTML

To better understand the translation, here is a complete example of a User Card component. Notice how SigPro attributes with the $ prefix map to reactive behavior, while standard attributes remain static.

javascript
const $online = $(true);
-
-export const UserCard = () => (
-  div({ class: 'user-card' }, [
-    img({ src: 'avatar.png', alt: 'User' }),
-    
-    div({ class: 'info' }, [
-      h2("John Doe"),
-      p({ 
-        $class: () => $online() ? 'status-on' : 'status-off' 
-      }, [
-        "Status: ", 
-        () => $online() ? "Online" : "Offline"
-      ])
-    ]),
-    
-    button({ 
-      onclick: () => $online(!$online()) 
-    }, "Toggle Status")
+    onclick: () => $count(c => c + 1),
+    $style: () => $count() > 5 ? "color: red" : "color: green" // Reactive style
+  }, "Increment")
+]);

5. Technical Implementation

As seen in the SigPro core, the engine registers these tags dynamically. This means zero imports are needed for UI creation in your component files.

javascript
// Internal SigPro loop
+tags.forEach(t => window[t] = (p, c) => $.html(t, p, c));

Because they are real functions, you get full IDE autocompletion and valid JS syntax highlighting without needing special plugins like JSX.


6. Comparison: Logic to UI

Here is how a dynamic Task Item component translates from SigPro logic to the final DOM structure.

javascript
const Task = (title, $done) => (
+  li({ class: 'task-item' }, [
+    input({ 
+      type: 'checkbox', 
+      $checked: $done // Two-way reactive binding
+    }),
+    span({ 
+      $style: () => $done() ? "text-decoration: line-through" : "" 
+    }, title)
   ])
-);
html
<div class="user-card">
-  <img src="avatar.png" alt="User">
-  
-  <div class="info">
-    <h2>John Doe</h2>
-    <p class="status-on">
-      Status: Online
-    </p>
-  </div>
-  
-  <button>Toggle Status</button>
-</div>

What is happening here?

  1. Structure: The hierarchy is identical. div([...]) in JS translates directly to nested tags in HTML.
  2. Attributes: class is set once. $class is "live"; SigPro listens to the $online signal and updates the class name without re-rendering the whole card.
  3. Content: The array [...] in SigPro is the equivalent of the children inside an HTML tag.
  4. Reactivity: The function () => $online() ? ... creates a TextNode in the HTML that changes its text content surgically whenever the signal toggles.

💡 Best Practices

  1. Destructuring: If you prefer not to rely on global variables, you can destructure them from window or $ (though in SigPro, using them globally is the intended "clean" way).
  2. Custom Tags: If you need a tag that isn't in the default list (like a Web Component), you can still use the base engine: $.html('my-custom-element', { ... }).
- +);
html
<li class="task-item">
+  <input type="checkbox" checked>
+  <style="text-decoration: line-through">Buy milk</span>
+</li>
+ \ No newline at end of file diff --git a/docs/assets/api__.md.BV8uIOD5.js b/docs/assets/api__.md.BV8uIOD5.js new file mode 100644 index 0000000..f70a3e5 --- /dev/null +++ b/docs/assets/api__.md.BV8uIOD5.js @@ -0,0 +1,59 @@ +import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"The Reactive Core: $( )","description":"","frontmatter":{},"headers":[],"relativePath":"api/$.md","filePath":"api/$.md"}'),e={name:"api/$.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

The Reactive Core: $( )

The $ function is a Unified Reactive Constructor. It detects the type of input you provide and returns the appropriate reactive primitive.


1. Signals (Atomic State)

A Signal is the simplest form of reactivity. It holds a single value (string, number, boolean, null).

Option A: Standard Signal (RAM)

Ideal for volatile state that shouldn't persist after a page refresh.

javascript
const $count = $(0); 
+
+// Usage:
+$count();           // Getter: returns 0
+$count(10);         // Setter: updates to 10
+$count(c => c + 1); // Functional update: updates to 11

Option B: Persistent Signal (Disk)

By adding a key, SigPro links the signal to localStorage.

javascript
// Syntax: $(initialValue, "storage-key")
+const $theme = $("light", "app-theme"); 
+
+// It restores the value from disk automatically on load.
+// When you update it, it saves to disk instantly:
+$theme("dark"); // localStorage.getItem("app-theme") is now "dark"

2. Stores (Reactive Objects)

A Store is a proxy that wraps an Object. SigPro makes every property reactive recursively. You access and set properties as if they were individual signals.

Option A: Standard Store (RAM)

javascript
const user = $({ 
+  name: "Alice", 
+  profile: { bio: "Developer" } 
+});
+
+// Getter: Call the property as a function
+console.log(user.name()); // "Alice"
+
+// Setter: Pass the value to the property function
+user.name("Bob"); 
+
+// Nested updates work exactly the same:
+user.profile.bio("Architect");

Option B: Persistent Store (Disk)

The most powerful way to save complex state. The entire object tree is serialized to JSON and kept in sync with the disk.

javascript
const settings = $({ 
+  volume: 50, 
+  notifications: true 
+}, "user-settings");
+
+// Any change in the object triggers a disk sync:
+settings.volume(100); // The whole JSON is updated in localStorage

3. Stores (Reactive Arrays)

When you pass an Array, SigPro tracks changes to the list. You can use standard methods or access indexes as reactive getters.

javascript
const $list = $(["Item 1", "Item 2"]);
+
+// Get by index
+console.log($list[0]()); // "Item 1"
+
+// Update by index
+$list[0]("Updated Item");
+
+// Note: For adding/removing items, use standard array methods 
+// which SigPro makes reactive (push, pop, splice, etc.)

4. Computed (Derived Logic)

A Computed Signal is a read-only value that depends on other signals. It is defined by passing a function that returns a value.

javascript
const $price = $(100);
+const $tax = $(0.21);
+
+// This function HAS a return statement
+const $total = $(() => {
+  return $price() * (1 + $tax());
+});
+
+// Usage (Read-only):
+console.log($total()); // 121
+
+$price(200);
+console.log($total()); // 242 (Auto-updated)

5. Effects (Reactive Actions)

An Effect is used for side-effects. It is defined by passing a function that does NOT return a value. It runs once immediately and then re-runs whenever its dependencies change.

javascript
const $name = $("Alice");
+
+// This function has NO return statement (Side-effect)
+$(() => {
+  console.log("The name changed to:", $name());
+  document.title = \`Profile: \${$name()}\`;
+});
+
+$name("Bob"); // Triggers the console.log and updates document.title

6. Summary: Input Mapping

If you pass...SigPro creates a...Access Method
A ValueSignal$var() / $var(val)
An ObjectStoreobj.prop() / obj.prop(val)
An ArrayArray Storearr[i]() / arr.push()
Function (returns)Computed$comp() (Read-only)
Function (no return)EffectAutomatically executed

💡 Naming Convention: The $ Prefix

To keep your code clean, always prefix your reactive variables with $. This tells you at a glance that you need to call it as a function to get its value.

javascript
const name = "Static";   // Just a string
+const $name = $("Alice"); // A Reactive Signal
`,38)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/api__.md.BV8uIOD5.lean.js b/docs/assets/api__.md.BV8uIOD5.lean.js new file mode 100644 index 0000000..d09e3f1 --- /dev/null +++ b/docs/assets/api__.md.BV8uIOD5.lean.js @@ -0,0 +1 @@ +import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"The Reactive Core: $( )","description":"","frontmatter":{},"headers":[],"relativePath":"api/$.md","filePath":"api/$.md"}'),e={name:"api/$.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",38)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/api__.md.CJ6A9esy.js b/docs/assets/api__.md.CJ6A9esy.js deleted file mode 100644 index 0d4f9c5..0000000 --- a/docs/assets/api__.md.CJ6A9esy.js +++ /dev/null @@ -1,22 +0,0 @@ -import{_ as t,o as i,c as a,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"The Reactive Core: $( )","description":"","frontmatter":{},"headers":[],"relativePath":"api/$.md","filePath":"api/$.md"}'),n={name:"api/$.md"};function l(h,s,r,p,o,d){return i(),a("div",null,[...s[0]||(s[0]=[e(`

The Reactive Core: $( )

The $ function is the heart of SigPro. It is a Unified Reactive Constructor that handles state, derivations, and automatic persistence through a single, consistent interface.

1. The Constructor: $( input, [key] )

Depending on the arguments you pass, SigPro creates different reactive primitives:

ArgumentTypeRequiredDescription
inputValue / FunctionYesInitial state or reactive logic.
keystringNoIf provided, the signal persists in localStorage.

2. Signal (State & Persistence)

A Signal is a reactive "box" for data. SigPro now supports Native Persistence: if you provide a second argument (the key), the signal will automatically sync with localStorage.

  • Standard: const $count = $(0);
  • Persistent: const $theme = $("light", "app-theme"); (Restores value on page reload).

Example:

javascript
const $user = $("Guest", "session-user"); // Automatically saved/loaded
-
-// Read (Getter)
-console.log($user()); 
-
-// Update (Setter + Auto-save to Disk)
-$user("Alice"); 
-
-// Functional Update
-$user(prev => prev.toUpperCase());

3. Computed (Derived State)

When you pass a function that returns a value, SigPro creates a Computed Signal. It tracks dependencies and recalculates only when necessary.

  • Syntax: const $derived = $(() => logic);

Example:

javascript
const $price = $(100);
-const $qty = $(2);
-
-// Auto-tracks $price and $qty
-const $total = $(() => $price() * $qty());
-
-$qty(3); // $total updates to 300 automatically

4. Effects (Reactive Actions)

An Effect is a function that does not return a value. It performs an action (side effect) whenever the signals it "touches" change.

  • When to use: Logging, manual DOM tweaks, or syncing with external APIs.
  • Syntax: $(() => { action });

Example:

javascript
const $status = $("online");
-
-// Runs every time $status changes
-$(() => {
-  console.log("System status is now:", $status());
-});

5. Summary Table: Usage Guide

PrimitiveLogic TypePersistence?Typical Use Case
SignalMutable StateYes (Optional)$(0, 'counter')
ComputedDerived / Read-onlyNo$(() => $a() + $b())
EffectImperative ActionNo$(() => alert($msg()))

💡 Pro Tip: The Power of Native Persistence

In SigPro, you don't need external plugins for basic storage. By using the key parameter in a Signal, you gain:

  1. Zero Boilerplate: No more JSON.parse(localStorage.getItem(...)).
  2. Instant Hydration: The value is restored before the UI renders, preventing "flicker".
  3. Atomic Safety: Data is saved to disk exactly when the signal changes, ensuring your app state is always safe.

Naming Convention

We use the $ prefix (e.g., $count) for reactive functions to distinguish them from static variables at a glance:

javascript
let count = 0;       // Static
-const $count = $(0); // Reactive Signal
`,34)])])}const c=t(n,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/api__.md.CJ6A9esy.lean.js b/docs/assets/api__.md.CJ6A9esy.lean.js deleted file mode 100644 index b120fd4..0000000 --- a/docs/assets/api__.md.CJ6A9esy.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as t,o as i,c as a,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"The Reactive Core: $( )","description":"","frontmatter":{},"headers":[],"relativePath":"api/$.md","filePath":"api/$.md"}'),n={name:"api/$.md"};function l(h,s,r,p,o,d){return i(),a("div",null,[...s[0]||(s[0]=[e("",34)])])}const c=t(n,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/api_mount.md.DK1GUmQ8.js b/docs/assets/api_mount.md.B9mWME6o.js similarity index 84% rename from docs/assets/api_mount.md.DK1GUmQ8.js rename to docs/assets/api_mount.md.B9mWME6o.js index 5a969ec..45cf2cb 100644 --- a/docs/assets/api_mount.md.DK1GUmQ8.js +++ b/docs/assets/api_mount.md.B9mWME6o.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Application Mounter: $.router.mount (Core)","description":"","frontmatter":{},"headers":[],"relativePath":"api/mount.md","filePath":"api/mount.md"}'),n={name:"api/mount.md"};function l(h,s,p,r,o,k){return a(),t("div",null,[...s[0]||(s[0]=[e(`

Application Mounter: $.router.mount (Core)

The $.mount function is the entry point of your reactive world. It takes a SigPro component (or a plain DOM node) and injects it into the real document, bridging the gap between your logic and the browser.

1. Syntax: $.mount(node, [target])

ParameterTypeDefaultDescription
nodeHTMLElement or FunctionRequiredThe component or element to render.
targetstring or HTMLElementdocument.bodyWhere to mount the app (CSS selector or Element).

2. Usage Scenarios

A. The "Clean Slate" (Main Entry)

In a modern app, you usually want to control the entire page. By default, $.mount clears the target's existing HTML before mounting your application.

javascript
// src/main.js
+import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Application Mounter: $.mount","description":"","frontmatter":{},"headers":[],"relativePath":"api/mount.md","filePath":"api/mount.md"}'),n={name:"api/mount.md"};function l(h,s,p,o,r,k){return a(),t("div",null,[...s[0]||(s[0]=[e(`

Application Mounter: $.mount

The $.mount function is the entry point of your reactive world. It takes a SigPro component (or a plain DOM node) and injects it into the real document, bridging the gap between your logic and the browser.

1. Syntax: $.mount(node, [target])

ParameterTypeDefaultDescription
nodeHTMLElement or FunctionRequiredThe component or element to render.
targetstring or HTMLElementdocument.bodyWhere to mount the app (CSS selector or Element).

2. Usage Scenarios

A. The "Clean Slate" (Main Entry)

In a modern app, you usually want to control the entire page. By default, $.mount clears the target's existing HTML before mounting your application.

javascript
// src/main.js
 import { $ } from 'sigpro';
 import App from './App.js';
 
diff --git a/docs/assets/api_mount.md.B9mWME6o.lean.js b/docs/assets/api_mount.md.B9mWME6o.lean.js
new file mode 100644
index 0000000..63c3b19
--- /dev/null
+++ b/docs/assets/api_mount.md.B9mWME6o.lean.js
@@ -0,0 +1 @@
+import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Application Mounter: $.mount","description":"","frontmatter":{},"headers":[],"relativePath":"api/mount.md","filePath":"api/mount.md"}'),n={name:"api/mount.md"};function l(h,s,p,o,r,k){return a(),t("div",null,[...s[0]||(s[0]=[e("",32)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default};
diff --git a/docs/assets/api_mount.md.DK1GUmQ8.lean.js b/docs/assets/api_mount.md.DK1GUmQ8.lean.js
deleted file mode 100644
index f7481f1..0000000
--- a/docs/assets/api_mount.md.DK1GUmQ8.lean.js
+++ /dev/null
@@ -1 +0,0 @@
-import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Application Mounter: $.router.mount (Core)","description":"","frontmatter":{},"headers":[],"relativePath":"api/mount.md","filePath":"api/mount.md"}'),n={name:"api/mount.md"};function l(h,s,p,r,o,k){return a(),t("div",null,[...s[0]||(s[0]=[e("",32)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default};
diff --git a/docs/assets/api_quick.md.Cy_XozKR.js b/docs/assets/api_quick.md.Cy_XozKR.js
deleted file mode 100644
index 49fa511..0000000
--- a/docs/assets/api_quick.md.Cy_XozKR.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import{_ as e,o as s,c as i,ae as a}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Quick API Reference ⚡","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),l={name:"api/quick.md"};function n(d,t,o,r,h,g){return s(),i("div",null,[...t[0]||(t[0]=[a(`

Quick API Reference ⚡

This is a high-level summary of the SigPro core API. For detailed guides and edge cases, please refer to the specific documentation for each module.

1. Core Reactivity: $( )

The $ function is a polymorphic constructor. It creates Signals (state) or Computed Effects (logic) based on the input type.

UsageInput TypeReturnsDescription
SignalanyFunctionA getter/setter for reactive state.
ComputedFunctionFunctionA read-only signal that auto-updates when its dependencies change.

Example:

javascript
const $count = $(0);             // Signal
-const $double = $(() => $count() * 2); // Computed

2. Rendering Engine: $.html

SigPro uses a hyperscript-style engine to create live DOM nodes.

ArgumentTypeRequiredDescription
tagstringYesStandard HTML tag (e.g., 'div', 'button').
propsObjectNoAttributes (id), Events (onclick), or Reactive Props ($value).
contentanyNoString, Node, Array, or Reactive Function.

Example:

javascript
$.html('button', { onclick: () => alert('Hi!') }, 'Click Me');

3. Global Helpers (Tag Proxies)

To keep your code clean, SigPro automatically exposes common HTML tags to the global scope.

CategoryAvailable Tags
Layoutdiv, section, main, nav, header, footer, span
Typographyh1, h2, h3, p, label, a, li, ul, ol
Formsinput, button, form, select, option
Mediaimg, video, audio, canvas

Example:

javascript
// No imports needed!
-div([ 
-  h1("Title"), 
-  button("Ok") 
-]);

4. Mounting & Plugins

Methods to initialize your application and extend the engine.

MethodSignatureDescription
$.mount(node, target)Wipes the target (default: body) and renders the component.
$.plugin(source)Registers a function or loads external .js scripts as plugins.

Example:

javascript
$.plugin([UI, Router]);
-$.mount(App, '#root');

5. Reactive Syntax Cheat Sheet

FeatureSyntaxDescription
Text Bindingp(["Value: ", $sig])Updates text content automatically.
Attributesdiv({ id: $sig })Static attribute assignment.
Reactive Attrdiv({ $class: $sig })Attribute updates when $sig changes.
Two-way Bindinginput({ $value: $sig })Syncs input value and signal automatically.
Conditionaldiv(() => $sig() > 0 ? "Yes" : "No")Re-renders only the content when the condition changes.

Summary Table

FeatureSigPro ApproachBenefit
Update LogicFine-grained (Surgical)Blazing fast updates.
DOMNative NodesZero abstraction cost.
SyntaxPure JavaScriptNo build-tool lock-in.
FootprintModularLoad only what you use.
`,31)])])}const k=e(l,[["render",n]]);export{c as __pageData,k as default}; diff --git a/docs/assets/api_quick.md.Cy_XozKR.lean.js b/docs/assets/api_quick.md.Cy_XozKR.lean.js deleted file mode 100644 index 53ba9b5..0000000 --- a/docs/assets/api_quick.md.Cy_XozKR.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as s,c as i,ae as a}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Quick API Reference ⚡","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),l={name:"api/quick.md"};function n(d,t,o,r,h,g){return s(),i("div",null,[...t[0]||(t[0]=[a("",31)])])}const k=e(l,[["render",n]]);export{c as __pageData,k as default}; diff --git a/docs/assets/api_quick.md.OAEBn6rS.js b/docs/assets/api_quick.md.OAEBn6rS.js new file mode 100644 index 0000000..8d175ca --- /dev/null +++ b/docs/assets/api_quick.md.OAEBn6rS.js @@ -0,0 +1,68 @@ +import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Quick API Reference","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),e={name:"api/quick.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Quick API Reference

SigPro is a minimal yet powerful engine. Here is a complete overview of its capabilities.

1. Core API Summary

FunctionDescriptionExample
$(val, key?)Creates a Signal, Computed, or Store (with optional persistence).const $n = $(0)
$.html()The base engine to create reactive HTMLElements.$.html('div', {}, 'Hi')
TagsGlobal helpers (div, span, button, etc.) built on top of $.html.div("Hello SigPro")
$.mount()Mounts a component into a target element (clears target first).$.mount(App, '#app')
$.router()Hash-based router with dynamic params and lazy loading.$.router(routes)
$.plugin()Extends SigPro or loads external scripts/plugins.$.plugin(MyPlugin)

2. The Power of $ (Reactivity)

The $ function adapts to whatever you pass to it:

Signals & Persistent State

Reactive values in RAM or synced with localStorage.

javascript
const $count = $(0);                      // Simple Signal
+const $theme = $('dark', 'app-theme');    // Persistent Signal (Disk)
+
+$count(10);             // Update value
+console.log($count());  // Get value: 10

Computed Signals

Read-only signals that update automatically when their dependencies change.

javascript
const $double = $(() => $count() * 2);

Reactive Stores (Objects + Disk)

Transforms an object into a reactive tree. If a key is provided, the entire structure persists.

javascript
// Store in RAM + Disk (Auto-syncs nested properties)
+const state = $({ 
+  user: { name: 'Natxo' }, 
+  settings: { dark: true } 
+}, 'my-app-state');
+
+// Accessing properties (they become signals)
+state.user.name();         // Get: 'Natxo'
+state.user.name('Guest');  // Set & Sync to Disk: 'my-app-state_user_name'

3. UI Creation: Constructor vs. Direct Tags

SigPro provides the $.html engine for defining any element and global "Sugar Tags" for rapid development.

javascript
// 1. DEFINE: Create a custom piece of UI
+// This returns a real DOM element ready to be used.
+const MyHero = $.html('section', { class: 'hero' }, [
+  h1("Internal Title")
+]);
+
+// 2. USE: Nest it inside other elements like a standard tag
+const Page = () => div([
+  MyHero, // We just drop the variable here
+  p("This paragraph is outside the Hero section.")
+]);
+
+$.mount(Page, '#app');
javascript
// Use pre-defined global tags to compose layouts instantly.
+// No need to define them, just call them.
+
+const Page = () => div({ id: 'main' }, [
+  section({ class: 'hero' }, [
+    h1("Direct Global Tag"),
+    p("Building UI without boilerplate.")
+  ]),
+  button({ onclick: () => alert('Hi!') }, "Click Me")
+]);
+
+$.mount(Page, '#app');

Technical Breakdown

  • $.html(tag, props, children): This is the core factory. Use it when you need to create an element dynamically or when working with Custom Elements / Web Components.
  • Global Tags (div, p, etc.): These are shortcut functions that SigPro injects into the window object. They internally call $.html for you, making your component code much cleaner and easier to read.

Key Difference

  • $.html: Acts as a constructor. Use it when you want to "bake" a specific structure (like a Section that always contains an H1) into a single variable.
  • Global Tags: Act as scaffolding. Use them to wrap different contents dynamically as you build your views.

Global Tags (Standard Syntax)

SigPro declares standard tags in the global scope so you don't have to import them.

javascript
const Card = (title, $val) => div({ class: 'card' }, [
+  h2(title),
+  p("Reactive content below:"),
+  input({ 
+    type: 'number', 
+    $value: $val, // Automatic Two-way binding
+    $style: () => $val() > 10 ? 'color: red' : 'color: green' 
+  })
+]);

4. Mounting: $.mount

The entry point of your application. It links your JavaScript logic to a specific DOM element.

html
<div id="app"></div>
javascript
// In your main.js
+const App = () => main([ 
+  h1("Welcome to SigPro"),
+  p("Everything here is reactive.")
+]);
+
+// Usage: $.mount(component, selectorOrElement)
+$.mount(App, '#app');

5. Navigation: $.router

A robust hash-based router (#/path) that handles view switching automatically.

javascript
const routes = [
+  { path: '/', component: Home },
+  { path: '/user/:id', component: (params) => h1(\`User ID: \${params.id}\`) },
+  { path: '/admin', component: () => import('./Admin.js') }, // Native Lazy Loading
+  { path: '*', component: () => p("404 - Not Found") }
+];
+
+// Initialize and mount the router
+$.mount($.router(routes), '#app');
+
+// Programmatic navigation
+$.router.go('/user/42');

6. Plugins: $.plugin

Extend the engine or load external dependencies.

javascript
// 1. Function-based plugin
+$.plugin(($) => {
+  $.myHelper = () => console.log("Plugin active!");
+});
+
+// 2. Load external scripts
+await $.plugin('https://cdn.example.com/library.js');
`,42)])])}const g=i(e,[["render",l]]);export{o as __pageData,g as default}; diff --git a/docs/assets/api_quick.md.OAEBn6rS.lean.js b/docs/assets/api_quick.md.OAEBn6rS.lean.js new file mode 100644 index 0000000..0d822dc --- /dev/null +++ b/docs/assets/api_quick.md.OAEBn6rS.lean.js @@ -0,0 +1 @@ +import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Quick API Reference","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),e={name:"api/quick.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",42)])])}const g=i(e,[["render",l]]);export{o as __pageData,g as default}; diff --git a/docs/assets/api_tags.md.BAYRMzRh.js b/docs/assets/api_tags.md.BAYRMzRh.js deleted file mode 100644 index f07e963..0000000 --- a/docs/assets/api_tags.md.BAYRMzRh.js +++ /dev/null @@ -1,55 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const E=JSON.parse('{"title":"Global Tag Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/tags.md","filePath":"api/tags.md"}'),e={name:"api/tags.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Global Tag Helpers

In SigPro, you don't need to write $.html('div', ...) every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags.

1. How it Works

When SigPro initializes, it runs a proxy loop that creates a function for every common HTML tag and attaches it to the window object.

  • Traditional: $.html('button', { onclick: ... }, 'Click')
  • SigPro Style: button({ onclick: ... }, 'Click')

This approach gives you a "DSL" (Domain Specific Language) that feels like HTML but is actually pure JavaScript.


2. The Global Registry

The following tags are available globally by default:

CategoryAvailable Functions
Layoutdiv, span, section, main, nav, header, footer, article, aside
Typographyh1, h2, h3, p, ul, ol, li, a, label, strong, em
Formsform, input, button, select, option, textarea
Tabletable, thead, tbody, tr, th, td
Mediaimg, video, audio, canvas, svg

3. Usage Patterns

The tag functions are highly flexible and accept arguments in different orders to suit your coding style.

A. Attributes + Content

The most common pattern.

javascript
div({ class: 'card' }, [
-  h1("Title"),
-  p("Description")
-]);

B. Content Only

If you don't need attributes, you can skip the object entirely.

javascript
div([
-  h1("Just Content"),
-  p("No attributes object needed here.")
-]);

C. Simple Text

For elements that only contain a string.

javascript
button("Submit"); // Equivalent to <button>Submit</button>

4. Reactive Tags

Since these helpers are just wrappers around $.html, they support full reactivity out of the box.

javascript
const $loading = $(true);
-
-div([
-  $loading() ? span("Loading...") : h1("Data Ready!"),
-  button({ 
-    $disabled: $loading, // Reactive attribute
-    onclick: () => $loading(false) 
-  }, "Stop Loading")
-]);

5. Under the Hood

If you are curious about how this happens without a compiler, here is the logic inside the SigPro core:

javascript
const tags = ['div', 'span', 'p', 'button', ...];
-
-tags.forEach(tag => {
-  window[tag] = (props, content) => $.html(tag, props, content);
-});

Because these are attached to window, they are available in any file in your project as soon as SigPro is loaded, making your components look like this:

javascript
// No imports required for tags!
-export default () => 
-  section({ id: 'hero' }, [
-    h1("Fast. Atomic. Simple."),
-    p("Built with SigPro.")
-  ]);

6. Full Comparison: SigPro vs. Standard HTML

To better understand the translation, here is a complete example of a User Card component. Notice how SigPro attributes with the $ prefix map to reactive behavior, while standard attributes remain static.

javascript
const $online = $(true);
-
-export const UserCard = () => (
-  div({ class: 'user-card' }, [
-    img({ src: 'avatar.png', alt: 'User' }),
-    
-    div({ class: 'info' }, [
-      h2("John Doe"),
-      p({ 
-        $class: () => $online() ? 'status-on' : 'status-off' 
-      }, [
-        "Status: ", 
-        () => $online() ? "Online" : "Offline"
-      ])
-    ]),
-    
-    button({ 
-      onclick: () => $online(!$online()) 
-    }, "Toggle Status")
-  ])
-);
html
<div class="user-card">
-  <img src="avatar.png" alt="User">
-  
-  <div class="info">
-    <h2>John Doe</h2>
-    <p class="status-on">
-      Status: Online
-    </p>
-  </div>
-  
-  <button>Toggle Status</button>
-</div>

What is happening here?

  1. Structure: The hierarchy is identical. div([...]) in JS translates directly to nested tags in HTML.
  2. Attributes: class is set once. $class is "live"; SigPro listens to the $online signal and updates the class name without re-rendering the whole card.
  3. Content: The array [...] in SigPro is the equivalent of the children inside an HTML tag.
  4. Reactivity: The function () => $online() ? ... creates a TextNode in the HTML that changes its text content surgically whenever the signal toggles.

💡 Best Practices

  1. Destructuring: If you prefer not to rely on global variables, you can destructure them from window or $ (though in SigPro, using them globally is the intended "clean" way).
  2. Custom Tags: If you need a tag that isn't in the default list (like a Web Component), you can still use the base engine: $.html('my-custom-element', { ... }).
`,41)])])}const g=i(e,[["render",l]]);export{E as __pageData,g as default}; diff --git a/docs/assets/api_tags.md.BAYRMzRh.lean.js b/docs/assets/api_tags.md.BAYRMzRh.lean.js deleted file mode 100644 index e1b1295..0000000 --- a/docs/assets/api_tags.md.BAYRMzRh.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const E=JSON.parse('{"title":"Global Tag Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/tags.md","filePath":"api/tags.md"}'),e={name:"api/tags.md"};function l(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",41)])])}const g=i(e,[["render",l]]);export{E as __pageData,g as default}; diff --git a/docs/assets/api_tags.md.YLRdMyid.js b/docs/assets/api_tags.md.YLRdMyid.js new file mode 100644 index 0000000..0b18c15 --- /dev/null +++ b/docs/assets/api_tags.md.YLRdMyid.js @@ -0,0 +1,31 @@ +import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Global Tag Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/tags.md","filePath":"api/tags.md"}'),n={name:"api/tags.md"};function l(h,s,o,p,d,k){return a(),t("div",null,[...s[0]||(s[0]=[e(`

Global Tag Helpers

In SigPro, you don't need to write $.html('div', ...) every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags upon initialization.

1. How it Works

SigPro iterates through an internal manifest of standard HTML tags and attaches a wrapper function for each one directly to the window object. This creates a native "DSL" (Domain Specific Language) that looks like a template engine but is 100% standard JavaScript.

  • Under the hood: $.html('button', { onclick: ... }, 'Click')
  • SigPro Style: button({ onclick: ... }, 'Click')

2. The Complete Global Registry

The following tags are injected into the global scope and are ready to use as soon as SigPro loads:

CategoryAvailable Global Functions
Structurediv, span, p, section, nav, main, header, footer, article, aside
Typographyh1, h2, h3, h4, h5, h6, ul, ol, li, dl, dt, dd, strong, em, code, pre, small, i, b, u, mark
Interactivebutton, a, label, br, hr, details, summary
Formsform, input, select, option, textarea, fieldset, legend
Tablestable, thead, tbody, tr, th, td, tfoot, caption
Media & Graphicsimg, canvas, video, audio, svg, path, iframe

"In SigPro, tags are not 'magic' strings handled by a compiler. They are functional imitations of HTML elements. Every time you call div(), you are executing a standard JavaScript function that returns a real DOM element. This gives you the speed of a specialized DSL with the transparency of pure JS."

WARNING: GLOBAL NAMING COLLISIONS

Since SigPro injects these helpers directly into the window object, they are regular JavaScript functions. This means they can be overwritten.

If you declare a variable, constant, or function with the same name as an HTML tag (e.g., const div = ... or function p()), you will nullify or shadow the built-in SigPro helper for that tag in your current scope.

Best Practice: To avoid conflicts, always use PascalCase for your custom components (e.g., UserCard, AppHeader) to distinguish them from the lowercase global HTML helpers.


3. Usage Patterns (Argument Flexibility)

The tag functions are "smart". They detect whether you are passing attributes, content, or both.

A. Attributes + Content

The standard way to build complex nodes.

javascript
div({ class: 'container', id: 'main-wrapper' }, [
+  h1("Welcome"),
+  p("This is SigPro.")
+]);

B. Content Only (The "Skipper")

If you don't need attributes, you can pass the content (string, array, or function) as the first and only argument.

javascript
section([
+  h2("No Attributes Needed"),
+  button("Click Me")
+]);

C. Primitive Content

For simple tags, you can just pass a string or a number.

javascript
h1("Hello World"); 
+span(42);

4. Reactive Attributes & Content

These helpers fully support SigPro's reactivity. Attributes starting with $ are automatically tracked.

javascript
const $count = $(0);
+
+div({ class: 'counter-app' }, [
+  h2(["Current Count: ", $count]), // Auto-unwrapping text content
+  
+  button({ 
+    onclick: () => $count(c => c + 1),
+    $style: () => $count() > 5 ? "color: red" : "color: green" // Reactive style
+  }, "Increment")
+]);

5. Technical Implementation

As seen in the SigPro core, the engine registers these tags dynamically. This means zero imports are needed for UI creation in your component files.

javascript
// Internal SigPro loop
+tags.forEach(t => window[t] = (p, c) => $.html(t, p, c));

Because they are real functions, you get full IDE autocompletion and valid JS syntax highlighting without needing special plugins like JSX.


6. Comparison: Logic to UI

Here is how a dynamic Task Item component translates from SigPro logic to the final DOM structure.

javascript
const Task = (title, $done) => (
+  li({ class: 'task-item' }, [
+    input({ 
+      type: 'checkbox', 
+      $checked: $done // Two-way reactive binding
+    }),
+    span({ 
+      $style: () => $done() ? "text-decoration: line-through" : "" 
+    }, title)
+  ])
+);
html
<li class="task-item">
+  <input type="checkbox" checked>
+  <style="text-decoration: line-through">Buy milk</span>
+</li>
`,36)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/docs/assets/api_tags.md.YLRdMyid.lean.js b/docs/assets/api_tags.md.YLRdMyid.lean.js new file mode 100644 index 0000000..2c5cd6a --- /dev/null +++ b/docs/assets/api_tags.md.YLRdMyid.lean.js @@ -0,0 +1 @@ +import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Global Tag Helpers","description":"","frontmatter":{},"headers":[],"relativePath":"api/tags.md","filePath":"api/tags.md"}'),n={name:"api/tags.md"};function l(h,s,o,p,d,k){return a(),t("div",null,[...s[0]||(s[0]=[e("",36)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/docs/assets/examples.md.Cy97nBRw.js b/docs/assets/examples.md.Cy97nBRw.js new file mode 100644 index 0000000..11f1135 --- /dev/null +++ b/docs/assets/examples.md.Cy97nBRw.js @@ -0,0 +1,20 @@ +import{_ as t,o as e,c as n,j as s,a as i,ae as l}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Live Playground","description":"","frontmatter":{},"headers":[],"relativePath":"examples.md","filePath":"examples.md"}'),h={name:"examples.md"};function p(k,a,r,d,o,E){return e(),n("div",null,[...a[0]||(a[0]=[s("h1",{id:"live-playground",tabindex:"-1"},[i("Live Playground "),s("a",{class:"header-anchor",href:"#live-playground","aria-label":'Permalink to "Live Playground"'},"​")],-1),s("p",null,[i("Experience "),s("strong",null,"SigPro's"),i(" fine-grained reactivity in real-time. Feel free to tweak the signal values in the editor!")],-1),s("iframe",{width:"100%",height:"600",src:"//jsfiddle.net/natxocc/spwran02/4/embedded/",frameborder:"0",loading:"lazy",allowtransparency:"true",allowfullscreen:"true"},null,-1),l(` \`\`\`

2. Best Practices for Documentation

  • Tab Selection: You can control which tabs are active by default by changing the URL segment after /embedded/.
    • js,result: Shows the logic and the output.
    • html,js,result: Shows the base structure, the logic, and the output.
  • Height Management: For complex Store examples, increase the height attribute to 500 or 600 so the code is readable without internal scrolling.
  • Responsive Width: Keeping width="100%" ensures the fiddle scales correctly on tablets and mobile devices.

3. Advanced: The "Fiddle" Component (Optional)

If you plan to have 10+ examples, you can create a global Vue component in VitePress. This keeps your Markdown files clean and allows you to change the theme or default height for all fiddles at once.

Create .vitepress/theme/components/Fiddle.vue:

vue
<template>
+  <div class="fiddle-wrapper" style="margin: 20px 0;">
+    <iframe 
+      width="100%" 
+      :height="height" 
+      :src="\`//jsfiddle.net/natxocc/\${id}/embedded/\${tabs}/dark/\`" 
+      frameborder="0"
+      loading="lazy">
+    </iframe>
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  id: String,      // e.g., "spwran02/4"
+  height: { default: '400' },
+  tabs: { default: 'js,result' }
+})
+</script>

Usage in Markdown:

markdown
Check out this store example:
+<Fiddle id="spwran02/4" height="500" />

Why this is perfect for SigPro:

Because SigPro is zero-dependency and runs directly in the browser, your JSFiddle code will be exactly what the user copies into their own index.html. There is no hidden "build step" confusing the learner.

`,14)])])}const y=t(h,[["render",p]]);export{c as __pageData,y as default}; diff --git a/docs/assets/examples.md.Cy97nBRw.lean.js b/docs/assets/examples.md.Cy97nBRw.lean.js new file mode 100644 index 0000000..f4920ee --- /dev/null +++ b/docs/assets/examples.md.Cy97nBRw.lean.js @@ -0,0 +1 @@ +import{_ as t,o as e,c as n,j as s,a as i,ae as l}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Live Playground","description":"","frontmatter":{},"headers":[],"relativePath":"examples.md","filePath":"examples.md"}'),h={name:"examples.md"};function p(k,a,r,d,o,E){return e(),n("div",null,[...a[0]||(a[0]=[s("h1",{id:"live-playground",tabindex:"-1"},[i("Live Playground "),s("a",{class:"header-anchor",href:"#live-playground","aria-label":'Permalink to "Live Playground"'},"​")],-1),s("p",null,[i("Experience "),s("strong",null,"SigPro's"),i(" fine-grained reactivity in real-time. Feel free to tweak the signal values in the editor!")],-1),s("iframe",{width:"100%",height:"600",src:"//jsfiddle.net/natxocc/spwran02/4/embedded/",frameborder:"0",loading:"lazy",allowtransparency:"true",allowfullscreen:"true"},null,-1),l("",14)])])}const y=t(h,[["render",p]]);export{c as __pageData,y as default}; diff --git a/docs/assets/guide_getting-started.md.BJ3Lg3i9.js b/docs/assets/guide_getting-started.md.BJ3Lg3i9.js deleted file mode 100644 index 187149f..0000000 --- a/docs/assets/guide_getting-started.md.BJ3Lg3i9.js +++ /dev/null @@ -1,26 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"guide/getting-started.md","filePath":"guide/getting-started.md"}'),e={name:"guide/getting-started.md"};function l(p,s,h,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Getting Started

SigPro is a lightweight, atomic reactive engine designed to build modern web interfaces with zero overhead. It focuses on high performance through fine-grained reactivity.

1. Installation

You can install SigPro via your favorite package manager:

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

2. Basic Usage

The core of SigPro is the $ function, which creates reactive state (Signals) and computed effects.

Create a main.js file and try this:

javascript
import { $ } from 'SigPro';
-
-// 1. Create a reactive signal
-const $name = $("World");
-
-// 2. Define a reactive component
-const App = () => div({ class: 'container' }, [
-  h1(["Hello, ", $name, "!"]),
-  
-  input({ 
-    type: 'text', 
-    $value: $name, // Two-way binding
-    placeholder: 'Enter your name...' 
-  }),
-  
-  button({ 
-    onclick: () => $name("SigPro") 
-  }, "Set to SigPro")
-]);
-
-// 3. Mount the application
-$.mount(App, '#app');

3. How it Works

SigPro doesn't use a Virtual DOM. Instead, it creates real DOM nodes and binds them directly to your data:

  1. Signals: $(value) creates a getter/setter function.
  2. Reactivity: When you pass a signal or a function to a DOM element, SigPro automatically creates a subscription.
  3. Fine-Grained Updates: Only the specific text node or attribute linked to the signal updates when the value changes.

4. Global Tags

By default, SigPro exports common HTML tags to the global scope (window) when initialized. This allows you to write clean, declarative UI without importing every single tag:

javascript
// Instead of $.html('div', ...), just use:
-div([
-  h1("Clean Syntax"),
-  p("No more boilerplate.")
-]);
`,15)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/guide_getting-started.md.BJ3Lg3i9.lean.js b/docs/assets/guide_getting-started.md.BJ3Lg3i9.lean.js deleted file mode 100644 index 38ed860..0000000 --- a/docs/assets/guide_getting-started.md.BJ3Lg3i9.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"guide/getting-started.md","filePath":"guide/getting-started.md"}'),e={name:"guide/getting-started.md"};function l(p,s,h,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",15)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/guide_why.md.lyU7T5_c.js b/docs/assets/guide_why.md.lyU7T5_c.js deleted file mode 100644 index 7e0cea4..0000000 --- a/docs/assets/guide_why.md.lyU7T5_c.js +++ /dev/null @@ -1,7 +0,0 @@ -import{_ as e,o as i,c as a,ae as s}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Why SigPro?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/why.md","filePath":"guide/why.md"}'),l={name:"guide/why.md"};function n(r,t,o,h,d,g){return i(),a("div",null,[...t[0]||(t[0]=[s(`

Why SigPro?

After years of building applications with React, Vue, and Svelte—investing countless hours mastering unique mental models, proprietary syntaxes, and complex build tools—we reached a realization: the web platform has evolved, but frameworks have become layers of abstraction that often move us further away from the browser.

SigPro is the answer to a simple question: Why fight the platform when we can embrace it?

The Modern Web is Ready

SigPro bypasses the overhead of the Virtual DOM and heavy compilers by using modern browser primitives. It treats the DOM as a first-class citizen, not as a side effect of a state change.

Browser PrimitiveWhat It Enables
Closures & ProxiesAutomatic dependency tracking without heavy overhead.
ES ModulesNative modularity and lazy loading without complex bundlers.
Direct DOM APIsSurgical updates that are faster than any reconciliation algorithm.
Microtask QueuesBatching updates efficiently to ensure 60fps performance.

The SigPro Philosophy

SigPro strips away the complexity, delivering a reactive programming model that feels like a framework but stays remarkably close to Vanilla JS:

  • No JSX transformations – Pure JavaScript functions.
  • No Virtual DOM – Direct, fine-grained DOM manipulation.
  • No proprietary syntax – If you know JS, you know SigPro.
  • Zero Build Step Required – It can run directly in the browser via ESM.
javascript
// Pure, Atomic, Reactive.
-const $count = $(0);
-
-const Counter = () => div([
-  p(["Count: ", $count]),
-  button({ onclick: () => $count(c => c + 1) }, "Increment")
-]);

Performance Comparison

SigPro isn't just lighter; it's architecturally faster because it skips the "diffing" phase entirely.

MetricSigProSolidJSSvelteVueReact
Bundle Size (gzip)🥇 < 2KB🥈 7KB🥉 16KB20KB45KB
ArchitectureAtomicAtomicCompiledV-DOMV-DOM
Initial Render🥇 Fastest🥈 Fast🥉 FastAverageSlow
Update Perf🥇 Surgical🥇 Surgical🥈 Fast🥉 AverageSlow
Dependencies🥇 0🥇 0🥇 0🥈 2🥉 5+
Build Step🥇 Optional🥈 Required🥈 Required🥇 Optional🥈 Required

🔑 Core Principles

SigPro is built on four fundamental pillars:

📡 Atomic Reactivity

Automatic dependency tracking with no manual subscriptions. When a signal changes, only the exact text nodes or attributes that depend on it update—instantly and surgically.

⚡ Surgical DOM Updates

No Virtual DOM diffing. No tree reconciliation. We don't guess what changed; we know exactly where the update needs to happen. Performance scales with your data, not the size of your component tree.

🧩 Plugin-First Architecture

The core is a tiny, powerful engine. Need Routing? Fetching? Global UI? Just plug it in. This keeps your production bundles "pay-only-for-what-you-use."

🔬 Predictable & Transparent

There is no "magic" hidden in a black-box compiler. What you write is what the browser executes. Debugging is straightforward because there is no framework layer between your code and the DevTools.


"SigPro returns the joy of web development by making the browser the hero again."

`,28)])])}const y=e(l,[["render",n]]);export{c as __pageData,y as default}; diff --git a/docs/assets/guide_why.md.lyU7T5_c.lean.js b/docs/assets/guide_why.md.lyU7T5_c.lean.js deleted file mode 100644 index cd2cec3..0000000 --- a/docs/assets/guide_why.md.lyU7T5_c.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as i,c as a,ae as s}from"./chunks/framework.C8AWLET_.js";const c=JSON.parse('{"title":"Why SigPro?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/why.md","filePath":"guide/why.md"}'),l={name:"guide/why.md"};function n(r,t,o,h,d,g){return i(),a("div",null,[...t[0]||(t[0]=[s("",28)])])}const y=e(l,[["render",n]]);export{c as __pageData,y as default}; diff --git a/docs/assets/index.md.By6smViD.js b/docs/assets/index.md.By6smViD.js new file mode 100644 index 0000000..b257b71 --- /dev/null +++ b/docs/assets/index.md.By6smViD.js @@ -0,0 +1 @@ +import{_ as t,o as i,c as a,ae as o}from"./chunks/framework.C8AWLET_.js";const p=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"SigPro","text":"Atomic Unified Reactive Engine","tagline":"High-precision atomic reactivity. No Virtual DOM. No compiler. No dependencies.","image":{"src":"/logo.svg","alt":"SigPro Logo"},"actions":[{"theme":"brand","text":"Get Started","link":"/install"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/natxocc/sigpro"}]},"features":[{"title":"⚛️ Atomic Reactivity","details":"Powered by fine-grained Signals. Forget about whole-component re-renders; SigPro updates only the specific text node or attribute that changed."},{"title":"🚀 Zero Virtual DOM","details":"By eliminating the V-DOM diffing layer, SigPro performs surgical, direct manipulations on the real DOM, removing memory and CPU overhead."},{"title":"🛠️ No Compiler Required","details":"Pure Vanilla JS. No Babel, no JSX, no complex build steps. Standard JavaScript that runs natively in the browser with maximum performance."},{"title":"📦 Ultra-Lightweight","details":"The core engine—including reactivity, DOM creation, persistence, and routing—is under 2KB. Perfect for performance-critical applications."}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function r(s,e,l,c,h,d){return i(),a("div",null,[...e[0]||(e[0]=[o('

Redefining Modern Reactivity

SigPro is not just another framework; it is a high-performance engine. While other libraries add layers of abstraction that slow down execution, SigPro returns to the essence of the web, leveraging the power of modern browser engines.

Why SigPro?

⚡️ Surgical DOM Efficiency

Unlike React or Vue, SigPro doesn't compare element trees. When a signal changes, SigPro knows exactly which DOM node depends on it and updates it instantly. It is reactive precision at its finest.

🔌 Modular Plugin System

The core is sacred. Any extra functionality—Routing, UI Helpers, or State Persistence—is integrated through a polymorphic plugin system. Load only what your application truly needs.

💾 Native Persistence

SigPro features first-class support for localStorage. Synchronizing your application state with persistent storage is as simple as providing a key when initializing your Signal.

🚦 Built-in Hash Routing

A robust routing system that supports Native Lazy Loading out of the box. Load your components only when the user navigates to them, keeping initial load times near zero.


The "No-Build" Philosophy

In an ecosystem obsessed with compilers, SigPro bets on standardization. Write code today that will still run 10 years from now, without depending on build tools that will eventually become obsolete.

"The best way to optimize code is to not have to process it at all."


Community & Vision

SigPro is an open-source project focused on simplicity and extreme speed. Designed for developers who love the web platform and hate unnecessary "bloatware".

text
Built with ❤️ by NatxoCC for the Modern Web.
',19)])])}const g=t(n,[["render",r]]);export{p as __pageData,g as default}; diff --git a/docs/assets/index.md.By6smViD.lean.js b/docs/assets/index.md.By6smViD.lean.js new file mode 100644 index 0000000..55cb1d9 --- /dev/null +++ b/docs/assets/index.md.By6smViD.lean.js @@ -0,0 +1 @@ +import{_ as t,o as i,c as a,ae as o}from"./chunks/framework.C8AWLET_.js";const p=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"SigPro","text":"Atomic Unified Reactive Engine","tagline":"High-precision atomic reactivity. No Virtual DOM. No compiler. No dependencies.","image":{"src":"/logo.svg","alt":"SigPro Logo"},"actions":[{"theme":"brand","text":"Get Started","link":"/install"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/natxocc/sigpro"}]},"features":[{"title":"⚛️ Atomic Reactivity","details":"Powered by fine-grained Signals. Forget about whole-component re-renders; SigPro updates only the specific text node or attribute that changed."},{"title":"🚀 Zero Virtual DOM","details":"By eliminating the V-DOM diffing layer, SigPro performs surgical, direct manipulations on the real DOM, removing memory and CPU overhead."},{"title":"🛠️ No Compiler Required","details":"Pure Vanilla JS. No Babel, no JSX, no complex build steps. Standard JavaScript that runs natively in the browser with maximum performance."},{"title":"📦 Ultra-Lightweight","details":"The core engine—including reactivity, DOM creation, persistence, and routing—is under 2KB. Perfect for performance-critical applications."}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function r(s,e,l,c,h,d){return i(),a("div",null,[...e[0]||(e[0]=[o("",19)])])}const g=t(n,[["render",r]]);export{p as __pageData,g as default}; diff --git a/docs/assets/index.md.DTGopCPx.js b/docs/assets/index.md.DTGopCPx.js deleted file mode 100644 index 4697eaf..0000000 --- a/docs/assets/index.md.DTGopCPx.js +++ /dev/null @@ -1,17 +0,0 @@ -import{_ as s,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"SigPro","text":"Atomic Unified Reactive Engine","tagline":"Fine-grained reactivity, built-in routing, and modular plugins. All under 2KB.","image":{"src":"/logo.svg","alt":"SigPro Logo"},"actions":[{"theme":"brand","text":"Get Started","link":"/guide/getting-started"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/natxocc/sigpro"}]},"features":[{"title":"Atomic Reactivity","details":"Powered by Signals. Only updates what changes. No Virtual DOM overhead, no heavy re-renders."},{"title":"Zero Dependencies","details":"Written in pure Vanilla JS. Maximum performance with the smallest footprint possible."},{"title":"Modular Ecosystem","details":"Official plugins for UI components, dynamic Routing, Fetch, and Storage. Load only what you need."}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function l(h,i,p,r,k,o){return a(),t("div",null,[...i[0]||(i[0]=[e(`

Why SigPro?

SigPro isn't just another framework; it's a high-performance engine. It strips away the complexity of massive bundles and returns to the essence of the web, enhanced with reactive superpowers.

The Core in Action

javascript
import { $ } from 'sigpro2';
-
-// A reactive state Signal
-const $count = $(0);
-
-// A Computed signal that updates automatically
-const $double = $(() => $count() * 2);
-
-// UI that breathes with your data
-const Counter = () => div([
-  h1(["Count: ", $count]),
-  p(["Double: ", $double]),
-  button({ onclick: () => $count(c => c + 1) }, "Increment")
-]);
-
-$.mount(Counter);

Key Features

⚡️ Fine-Grained Reactivity

Unlike frameworks that diff complex trees (V-DOM), SigPro binds your signals directly to real DOM text nodes and attributes. If the data changes, the node changes. Period.

🔌 Polymorphic Plugin System

Extend core capabilities in a single line. Add global UI helpers, routing, or state persistence seamlessly.

javascript
import { UI, Router } from 'sigpro/plugins';
-$.plugin([UI, Router]);

📂 File-Based Routing

With our dedicated Vite plugin, manage your routes simply by creating files in src/pages/. It supports native Lazy Loading out of the box for lightning-fast initial loads.


Quick Install

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

Community & Support

SigPro is an open-source project. Whether you want to contribute, report a bug, or just talk about reactivity, join us on our official repository.

Built with ❤️ by NatxoCC
`,20)])])}const c=s(n,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/index.md.DTGopCPx.lean.js b/docs/assets/index.md.DTGopCPx.lean.js deleted file mode 100644 index e7ece58..0000000 --- a/docs/assets/index.md.DTGopCPx.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as s,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"SigPro","text":"Atomic Unified Reactive Engine","tagline":"Fine-grained reactivity, built-in routing, and modular plugins. All under 2KB.","image":{"src":"/logo.svg","alt":"SigPro Logo"},"actions":[{"theme":"brand","text":"Get Started","link":"/guide/getting-started"},{"theme":"alt","text":"View on GitHub","link":"https://github.com/natxocc/sigpro"}]},"features":[{"title":"Atomic Reactivity","details":"Powered by Signals. Only updates what changes. No Virtual DOM overhead, no heavy re-renders."},{"title":"Zero Dependencies","details":"Written in pure Vanilla JS. Maximum performance with the smallest footprint possible."},{"title":"Modular Ecosystem","details":"Official plugins for UI components, dynamic Routing, Fetch, and Storage. Load only what you need."}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function l(h,i,p,r,k,o){return a(),t("div",null,[...i[0]||(i[0]=[e("",20)])])}const c=s(n,[["render",l]]);export{g as __pageData,c as default}; diff --git a/docs/assets/install.md.pJydCe65.js b/docs/assets/install.md.pJydCe65.js new file mode 100644 index 0000000..39df70b --- /dev/null +++ b/docs/assets/install.md.pJydCe65.js @@ -0,0 +1,45 @@ +import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Installation & Setup","description":"","frontmatter":{},"headers":[],"relativePath":"install.md","filePath":"install.md"}'),l={name:"install.md"};function p(h,s,e,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t(`

Installation & Setup

SigPro is designed to be drop-in ready. Whether you are building a complex application with a bundler or a simple reactive widget in a single HTML file, SigPro scales with your needs.

1. Installation

Choose the method that best fits your workflow:

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
html
<script type="module">
+  import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
+</script>

2. Quick Start Examples

Depending on your installation method, here is how you can get SigPro running in seconds.

javascript
// File: App.js
+import { $ } from 'sigpro'; 
+
+export const App = () => {
+  // $ is global, but we import it for better IDE intellisense
+  const $count = $(0);
+  
+  // Tags like div, h1, button are available globally
+  return div({ class: 'card' }, [
+    h1(["Count is: ", $count]),
+    button({ onclick: () => $count(c => c + 1) }, "Increment")
+  ]);
+};
+
+// File: main.js
+import { $ } from 'sigpro';
+import { App } from './App.js';
+
+$.mount(App, '#app');
html
<!DOCTYPE html>
+<html lang="en">
+<body>
+  <div id="app"></div>
+
+  <script type="module">
+    // Import directly from CDN
+    import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
+
+    const $name = $("Developer");
+
+    // No need to import div, section, h2, input... they are global!
+    const App = () => section([
+      h2(["Welcome, ", $name]),
+      input({ 
+        type: 'text', 
+        $value: $name, // Automatic two-way binding
+        placeholder: 'Type your name...' 
+      })
+    ]);
+
+    $.mount(App, '#app');
+  </script>
+</body>
+</html>

3. Global by Design

One of SigPro's core strengths is its Global API.

  • The $ Function: Once loaded, it attaches itself to window.$. While you can use import for better IDE support and type checking, it is accessible everywhere.
  • HTML Tags: Common tags (div, span, button, etc.) are automatically registered in the global scope. This eliminates "Import Hell" and keeps your components clean and readable.

4. Why no build step?

Because SigPro uses native ES Modules and standard JavaScript functions to generate the DOM, you don't actually need a compiler like Babel or a loader for JSX.

  • Development: Just save and refresh. No complex HMR issues.
  • Production: Use any bundler (Vite, esbuild, Rollup) to tree-shake and minify your final code for maximum performance.
`,16)])])}const g=i(l,[["render",p]]);export{o as __pageData,g as default}; diff --git a/docs/assets/install.md.pJydCe65.lean.js b/docs/assets/install.md.pJydCe65.lean.js new file mode 100644 index 0000000..1176be3 --- /dev/null +++ b/docs/assets/install.md.pJydCe65.lean.js @@ -0,0 +1 @@ +import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Installation & Setup","description":"","frontmatter":{},"headers":[],"relativePath":"install.md","filePath":"install.md"}'),l={name:"install.md"};function p(h,s,e,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t("",16)])])}const g=i(l,[["render",p]]);export{o as __pageData,g as default}; diff --git a/docs/assets/plugins_core.debug.md.BKuhgPoj.js b/docs/assets/plugins_core.debug.md.BKuhgPoj.js deleted file mode 100644 index 2600a21..0000000 --- a/docs/assets/plugins_core.debug.md.BKuhgPoj.js +++ /dev/null @@ -1,27 +0,0 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Development Tool: _debug","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.debug.md","filePath":"plugins/core.debug.md"}'),e={name:"plugins/core.debug.md"};function l(h,s,p,k,r,o){return a(),n("div",null,[...s[0]||(s[0]=[t(`

Development Tool: _debug

The Debug Plugin is a lightweight reactive listener. Once attached to a signal or a computed function, it automatically monitors changes, compares values, and formats the output in the browser console.

1. Core Features

  • Reactive Tracking: Automatically logs whenever the tracked signal updates.
  • Visual Grouping: Uses styled console groups to keep your dev tools organized.
  • Object Inspection: Automatically uses console.table() when the signal contains an object or array.
  • Efficient Comparison: Uses Object.is to prevent redundant logging if the value hasn't actually changed.

2. Installation

To use _debug, you only need the SigPro core. Register the plugin in your main.js. You can conditionally load it so it only runs during development.

javascript
import { $ } from 'sigpro';
-import { Debug } from 'sigpro/plugins';
-
-// Only load Debug in development mode
-const plugins = [];
-if (import.meta.env.DEV) plugins.push(Debug);
-
-$.plugin(plugins).then(() => {
-  import('./App.js').then(app => $.mount(app.default));
-});
bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

3. Basic Usage

Call _debug anywhere in your component. It stays active in the background, watching the signal's lifecycle.

javascript
export default () => {
-  const $count = $(0);
-  const $user = $({ name: "Guest", role: "Viewer" });
-
-  // Start tracking
-  _debug($count, "Main Counter");
-  _debug($user, "User Session");
-
-  return div([
-    button({ onclick: () => $count(c => c + 1) }, "Increment"),
-    button({ onclick: () => $user({ name: "Admin", role: "Super" }) }, "Promote")
-  ]);
-};

4. Console Output Breakdown

When a signal changes, the console displays a structured block:

  1. Header: A styled badge with the name (e.g., SigPro Debug: Main Counter).
  2. Previous Value: The value before the update (in red).
  3. Current Value: The new value (in green).
  4. Table View: If the value is an object, a formatted table appears automatically.

5. Debugging Computed Values

You can also debug computed functions to see exactly when derived state is recalculated.

javascript
const $price = $(100);
-const $tax = $(0.21);
-const $total = $(() => $price() * (1 + $tax()));
-
-// Monitor the result of the calculation
-_debug($total, "Final Invoice Total");

6. Why use _debug?

  1. Clean Logic: No need to scatter console.log inside your reactive functions.
  2. State History: Instantly see the "Before" and "After" of any user action.
  3. No-Noise: It only logs when a real change occurs, keeping the console clean.
  4. Deep Inspection: The automatic console.table makes debugging large API responses much faster.
`,24)])])}const E=i(e,[["render",l]]);export{g as __pageData,E as default}; diff --git a/docs/assets/plugins_core.debug.md.BKuhgPoj.lean.js b/docs/assets/plugins_core.debug.md.BKuhgPoj.lean.js deleted file mode 100644 index 83a18f7..0000000 --- a/docs/assets/plugins_core.debug.md.BKuhgPoj.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Development Tool: _debug","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.debug.md","filePath":"plugins/core.debug.md"}'),e={name:"plugins/core.debug.md"};function l(h,s,p,k,r,o){return a(),n("div",null,[...s[0]||(s[0]=[t("",24)])])}const E=i(e,[["render",l]]);export{g as __pageData,E as default}; diff --git a/docs/assets/plugins_core.fetch.md.BIc8aMQh.js b/docs/assets/plugins_core.fetch.md.BIc8aMQh.js deleted file mode 100644 index 43f233f..0000000 --- a/docs/assets/plugins_core.fetch.md.BIc8aMQh.js +++ /dev/null @@ -1,30 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Data Fetching: _fetch","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.fetch.md","filePath":"plugins/core.fetch.md"}'),e={name:"plugins/core.fetch.md"};function h(l,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Data Fetching: _fetch

The Fetch Plugin provides a reactive wrapper around the native browser Fetch API. Instead of managing complex async/await flows within your UI, _fetch returns a "Reactive Tripod" (Data, Loading, and Error) that your components can listen to automatically.

1. Core Concept

When you call _fetch, it returns three signals immediately. Your UI declares how to react to these signals as they change from their initial state to the final response.

  • $data: Initialized as null. Automatically holds the JSON response on success.
  • $loading: Initialized as true. Flips to false once the request settles.
  • $error: Initialized as null. Holds the error message if the request fails.

2. Installation

Register the Fetch plugin in your main.js. By convention, we load it alongside the UI and Router to have the full SigPro ecosystem ready.

javascript
import { $ } from 'sigpro';
-import { Fetch } from 'sigpro/plugins';
-
-$.plugin([Fetch]).then(() => {
-  // Now _fetch() is available globally
-  import('./App.js').then(app => $.mount(app.default));
-});

3. Basic Usage

Use _fetch inside your component to get live updates. The UI updates surgically whenever a signal changes.

javascript
export default () => {
-  const { $data, $loading, $error } = _fetch('https://api.github.com/users/octocat');
-
-  return div({ class: 'p-6 flex flex-col gap-4' }, [
-    h1("Profile Details"),
-    
-    // 1. Loading State (using SigPro UI button)
-    () => $loading() && _button({ $loading: true }, "Fetching..."),
-
-    // 2. Error State
-    () => $error() && div({ class: 'alert alert-error' }, $error()),
-
-    // 3. Success State
-    () => $data() && div({ class: 'card bg-base-200 p-4' }, [
-      img({ src: $data().avatar_url, class: 'w-16 rounded-full' }),
-      h2($data().name),
-      p($data().bio)
-    ])
-  ]);
-};

4. Advanced Configuration

_fetch accepts the same RequestInit options as the standard fetch() (methods, headers, body, etc.).

javascript
const { $data, $loading } = _fetch('/api/v1/update', {
-  method: 'PATCH',
-  headers: { 'Content-Type': 'application/json' },
-  body: JSON.stringify({ status: 'active' })
-});

5. Why use _fetch instead of native Fetch?

  1. Declarative UI: You define the "Loading", "Error", and "Success" templates once, and they swap automatically.
  2. No useEffect required: Since SigPro is natively reactive, you don't need lifecycle hooks to trigger re-renders; the signals handle it.
  3. Consistency: It follows the same _prefix pattern as the rest of the official plugin ecosystem.
  4. Automatic JSON Parsing: It assumes JSON by default and handles 404/500 errors by populating the $error signal.
`,20)])])}const c=i(e,[["render",h]]);export{o as __pageData,c as default}; diff --git a/docs/assets/plugins_core.fetch.md.BIc8aMQh.lean.js b/docs/assets/plugins_core.fetch.md.BIc8aMQh.lean.js deleted file mode 100644 index bf0184a..0000000 --- a/docs/assets/plugins_core.fetch.md.BIc8aMQh.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Data Fetching: _fetch","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.fetch.md","filePath":"plugins/core.fetch.md"}'),e={name:"plugins/core.fetch.md"};function h(l,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",20)])])}const c=i(e,[["render",h]]);export{o as __pageData,c as default}; diff --git a/docs/assets/plugins_core.router.md.Bg_zmVp3.js b/docs/assets/plugins_core.router.md.Bg_zmVp3.js deleted file mode 100644 index 8d4fab9..0000000 --- a/docs/assets/plugins_core.router.md.Bg_zmVp3.js +++ /dev/null @@ -1,31 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const E=JSON.parse('{"title":"Navigation Plugin: Router","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.router.md","filePath":"plugins/core.router.md"}'),e={name:"plugins/core.router.md"};function h(l,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Navigation Plugin: Router

The SigPro Router handles URL changes via hashes (#) and maps them to components. It supports dynamic parameters (like :id) and asynchronous loading for heavy pages.

1. Core Features

  • Hash-based: Works everywhere without special server configuration.
  • Lazy Loading: Pages are only downloaded when the user visits the route.
  • Reactive: The view updates automatically when the hash changes.
  • Dynamic Routes: Supports paths like /user/:id.

2. Installation

The Router is usually included in the official plugins package.

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next
bash
pnpm add -D tailwindcss @tailwindcss/vite daisyui@next
bash
yarn add -D tailwindcss @tailwindcss/vite daisyui@next
bash
bun add -d tailwindcss @tailwindcss/vite daisyui@next

3. Setting Up Routes

In your App.js (or a dedicated routes file), define your navigation map.

javascript
const routes = [
-  { path: '/', component: () => h1("Home Page") },
-  { 
-    path: '/admin', 
-    // Lazy Loading: This file is only fetched when needed
-    component: () => import('./pages/Admin.js') 
-  },
-  { path: '/user/:id', component: (params) => h2(\`User ID: \${params.id}\`) },
-  { path: '*', component: () => div("404 - Page Not Found") }
-];
-
-export default () => div([
-  _navbar({ title: "My App" }),
-  _router(routes) // The router is now a global tag
-]);

4. Navigation (_router.go)

To move between pages programmatically (e.g., inside an onclick event), use the global _router.go helper.

javascript
_button({ 
-  onclick: () => _router.go('/admin') 
-}, "Go to Admin")

5. How it Works (Under the Hood)

The router tracks the window.location.hash and uses a reactive signal to trigger a re-render of the specific area where _router(routes) is placed.

  1. Match: It filters your route array to find the best fit.
  2. Resolve: * If it's a standard function, it executes it immediately.
    • If it's a Promise (via import()), it shows a loading state and swaps the content once the module arrives.
  3. Inject: It replaces the previous DOM node with the new page content surgically.

6. Integration with UI Components

Since you are using the UI Plugin, you can easily create active states in your navigation menus by checking the current hash.

javascript
// Example of a reactive sidebar menu
-_menu({
-  items: [
-    { 
-      label: 'Dashboard', 
-      active: () => window.location.hash === '#/', 
-      onclick: () => _router.go('/') 
-    },
-    { 
-      label: 'Settings', 
-      active: () => window.location.hash === '#/settings', 
-      onclick: () => _router.go('/settings') 
-    }
-  ]
-})
`,24)])])}const g=i(e,[["render",h]]);export{E as __pageData,g as default}; diff --git a/docs/assets/plugins_core.router.md.Bg_zmVp3.lean.js b/docs/assets/plugins_core.router.md.Bg_zmVp3.lean.js deleted file mode 100644 index 121e5fd..0000000 --- a/docs/assets/plugins_core.router.md.Bg_zmVp3.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const E=JSON.parse('{"title":"Navigation Plugin: Router","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.router.md","filePath":"plugins/core.router.md"}'),e={name:"plugins/core.router.md"};function h(l,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",24)])])}const g=i(e,[["render",h]]);export{E as __pageData,g as default}; diff --git a/docs/assets/plugins_core.storage.md.C6UMGg_o.js b/docs/assets/plugins_core.storage.md.C6UMGg_o.js deleted file mode 100644 index 9886b20..0000000 --- a/docs/assets/plugins_core.storage.md.C6UMGg_o.js +++ /dev/null @@ -1,29 +0,0 @@ -import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Persistence Tool: _storage","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.storage.md","filePath":"plugins/core.storage.md"}'),n={name:"plugins/core.storage.md"};function h(l,s,p,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[e(`

Persistence Tool: _storage

The Storage plugin synchronizes a signal with a specific key in your browser's localStorage. It handles both the initial hydration (loading data when the app starts) and automatic saving whenever the signal's value changes.

1. Core Concept

When you "attach" a signal to _storage, two things happen:

  1. Hydration: The plugin checks if the key already exists in localStorage. If it does, it parses the JSON and updates the signal immediately.
  2. Reactive Sync: It creates a reactive watcher that stringifies and saves the signal's value to the disk every time it is updated.

2. Installation

Register the Storage plugin in your main.js. Since this is a logic-only plugin, it doesn't require any CSS or UI dependencies.

javascript
import { $ } from 'sigpro';
-import { Storage } from 'sigpro/plugins';
-
-$.plugin(Storage).then(() => {
-  import('./App.js').then(app => $.mount(app.default));
-});
bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

3. Basic Usage

You can wrap any signal with _storage. It is common practice to do this right after creating the signal.

javascript
export default () => {
-  // 1. Create a signal with a default value
-  const $theme = $( 'light' );
-
-  // 2. Persist it. If 'user_theme' exists in localStorage, 
-  // $theme will be updated to that value instantly.
-  _storage($theme, 'user_theme');
-
-  return div({ class: () => \`app-\${$theme()}\` }, [
-    h1(\`Current Theme: \${$theme()}\`),
-    button({ 
-      onclick: () => $theme(t => t === 'light' ? 'dark' : 'light') 
-    }, "Toggle Theme")
-  ]);
-};

4. Complex Data (Objects & Arrays)

Since the plugin uses JSON.parse and JSON.stringify internally, it works perfectly with complex state structures.

javascript
const $settings = $({ 
-  notifications: true, 
-  fontSize: 16 
-});
-
-// Automatically saves the whole object whenever any property changes
-_storage($settings, 'app_settings');

5. Why use _storage?

  1. Zero Boilerplate: You don't need to manually write localStorage.getItem or setItem logic inside your components.
  2. Chaining: Because _storage returns the signal, you can persist it inline.
  3. Error Resilience: It includes a built-in try/catch block to prevent your app from crashing if the stored JSON is corrupted.
  4. Surgical Persistence: Only the signals you explicitly mark for storage are saved, keeping your localStorage clean.

6. Pro Tip: Combining with Debug

You can chain plugins to create a fully monitored and persistent state:

javascript
const $score = _storage($(0), 'high_score');
-
-// Now it's saved to disk AND logged to console on every change
-_debug($score, "Game Score");
`,25)])])}const c=i(n,[["render",h]]);export{g as __pageData,c as default}; diff --git a/docs/assets/plugins_core.storage.md.C6UMGg_o.lean.js b/docs/assets/plugins_core.storage.md.C6UMGg_o.lean.js deleted file mode 100644 index 00ff4c3..0000000 --- a/docs/assets/plugins_core.storage.md.C6UMGg_o.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Persistence Tool: _storage","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.storage.md","filePath":"plugins/core.storage.md"}'),n={name:"plugins/core.storage.md"};function h(l,s,p,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[e("",25)])])}const c=i(n,[["render",h]]);export{g as __pageData,c as default}; diff --git a/docs/assets/plugins_core.ui.md.C434Uobv.js b/docs/assets/plugins_core.ui.md.C434Uobv.js deleted file mode 100644 index 9433d66..0000000 --- a/docs/assets/plugins_core.ui.md.C434Uobv.js +++ /dev/null @@ -1,452 +0,0 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"SigPro UI Plugin - Complete Documentation","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.ui.md","filePath":"plugins/core.ui.md"}'),h={name:"plugins/core.ui.md"};function l(p,s,k,e,E,d){return a(),n("div",null,[...s[0]||(s[0]=[t(`

SigPro UI Plugin - Complete Documentation

Overview

The SigPro UI plugin is a comprehensive, reactive component library built on SigPro's atomic reactivity system. It seamlessly integrates Tailwind CSS v4 for utility-first styling and daisyUI v5 for semantic, themeable components. Every component is reactive by nature, automatically responding to signal changes without manual DOM updates.

Table of Contents

  1. Installation & Setup
  2. Core Concepts
  3. Form Components
  4. Action Components
  5. Layout Components
  6. Navigation Components
  7. Feedback Components
  8. Container Components
  9. Complete Examples
  10. Styling Guide
  11. Best Practices

Installation & Setup

Step 1: Install Dependencies

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next

Step 2: Configure Tailwind CSS v4

Create src/app.css:

css
/* src/app.css */
-@import "tailwindcss";
-@plugin "daisyui";
-
-/* Optional: Custom themes */
-@theme {
-  --color-primary: oklch(0.65 0.2 250);
-  --color-secondary: oklch(0.7 0.15 150);
-}
-
-/* Dark mode support */
-@custom-variant dark (&:where(.dark, [data-theme="dark"], [data-theme="dark"] *)));

Step 3: Initialize in Your Entry Point

javascript
// main.js
-import './app.css';
-import { $ } from 'sigpro';
-import { UI } from 'sigpro/plugins';
-
-// Load the UI plugin - makes all _components globally available
-$.plugin(UI).then(() => {
-  // All UI components are now registered
-  import('./App.js').then(app => $.mount(app.default));
-});

Core Concepts

Reactive Props

All UI components accept reactive props using the $ prefix. When you pass a signal, the component automatically updates:

javascript
const $username = $('John');
-const $error = $(null);
-
-// Reactive input with two-way binding
-_input({
-  $value: $username,     // Auto-updates when signal changes
-  $error: $error         // Shows error message when signal has value
-})

The parseClass Helper

All components intelligently merge base classes with user-provided classes, supporting both static strings and reactive functions:

javascript
// Static class merging
-_button({ class: 'btn-primary' }, 'Click me')
-// Result: class="btn btn-primary"
-
-// Reactive classes
-const $theme = $('btn-primary');
-_button({ class: () => $theme() }, 'Dynamic Button')
-// Updates when $theme changes

Form Components

_input - Smart Input Field

A complete input wrapper with label, tooltip, error handling, and two-way binding.

Properties:

PropertyTypeDescription
labelstringField label text
tipstringTooltip text shown on hover of a "?" badge
$valuesignalTwo-way bound value signal
$errorsignalError message signal (shows red border + message)
typestringInput type: 'text', 'email', 'password', etc.
placeholderstringPlaceholder text
classstring|functionAdditional CSS classes

Examples:

javascript
// Basic usage
-const $email = $('');
-_input({
-  label: 'Email Address',
-  type: 'email',
-  placeholder: 'user@example.com',
-  $value: $email
-})
-
-// With validation
-const $password = $('');
-const $passwordError = $(null);
-
-_input({
-  label: 'Password',
-  type: 'password',
-  $value: $password,
-  $error: $passwordError,
-  oninput: (e) => {
-    if (e.target.value.length < 6) {
-      $passwordError('Password must be at least 6 characters');
-    } else {
-      $passwordError(null);
-    }
-  }
-})

_select - Dropdown Selector

Reactive select component with options array.

Properties:

PropertyTypeDescription
labelstringField label
optionsArray<{value: any, label: string}>Select options
$valuesignalTwo-way bound selected value

Example:

javascript
const $role = $('user');
-const roles = [
-  { value: 'admin', label: 'Administrator' },
-  { value: 'user', label: 'Standard User' },
-  { value: 'guest', label: 'Guest' }
-];
-
-_select({
-  label: 'User Role',
-  options: roles,
-  $value: $role
-})
-
-// Reactive selection
-console.log($role()); // 'user'

_checkbox - Toggle Checkbox

Styled checkbox with label support.

Properties:

PropertyTypeDescription
labelstringCheckbox label text
$valuesignalBoolean signal for checked state

Example:

javascript
const $remember = $(true);
-
-_checkbox({
-  label: 'Remember me',
-  $value: $remember
-})

_radio - Radio Button Group

Radio button with group value binding.

Properties:

PropertyTypeDescription
labelstringRadio option label
valueanyValue for this radio option
$valuesignalGroup signal holding selected value

Example:

javascript
const $paymentMethod = $('credit');
-
-['credit', 'paypal', 'crypto'].forEach(method => {
-  _radio({
-    name: 'payment',
-    label: method.toUpperCase(),
-    value: method,
-    $value: $paymentMethod
-  })
-})
-
-// Selected: $paymentMethod() === 'credit'

_range - Slider Control

Reactive range slider with optional label.

Properties:

PropertyTypeDescription
labelstringSlider label
minnumberMinimum value
maxnumberMaximum value
stepnumberStep increment
$valuesignalCurrent value signal

Example:

javascript
const $volume = $(50);
-
-_range({
-  label: 'Volume',
-  min: 0,
-  max: 100,
-  step: 1,
-  $value: $volume
-})
-
-// Display current value
-span(() => \`Volume: \${$volume()}%\`)

Action Components

_button - Smart Action Button

Feature-rich button with loading states, icons, and badges.

Properties:

PropertyTypeDescription
$loadingsignalShows spinner + disables when true
$disabledsignalManual disabled state
iconstring|HTMLElementIcon element or emoji/unicode
badgestringBadge text to display
badgeClassstringAdditional badge styling
typestringButton type: 'button', 'submit', etc.
onclickfunctionClick handler

Examples:

javascript
// Basic button
-_button({ onclick: () => alert('Clicked!') }, 'Click Me')
-
-// Loading state
-const $saving = $(false);
-_button({
-  $loading: $saving,
-  icon: '💾',
-  onclick: async () => {
-    $saving(true);
-    await saveData();
-    $saving(false);
-  }
-}, 'Save Changes')
-
-// With badge notification
-_button({
-  badge: '3',
-  badgeClass: 'badge-secondary',
-  icon: '🔔'
-}, 'Notifications')

Layout Components

_fieldset - Form Section Group

Groups related form fields with a legend.

Properties:

PropertyTypeDescription
legendstringFieldset title
classstring|functionAdditional classes

Example:

javascript
_fieldset({ legend: 'Personal Information' }, [
-  _input({ label: 'First Name', $value: $firstName }),
-  _input({ label: 'Last Name', $value: $lastName }),
-  _input({ label: 'Email', type: 'email', $value: $email })
-])

_accordion - Collapsible Section

Expandable/collapsible content panel.

Properties:

PropertyTypeDescription
titlestringAccordion header text
namestringOptional group name (radio behavior)
openbooleanInitially open state

Examples:

javascript
// Single accordion (checkbox behavior)
-_accordion({ title: 'Frequently Asked Questions' }, [
-  p('This is the collapsible content...')
-])
-
-// Grouped accordions (radio behavior - only one open)
-_accordion({ title: 'Section 1', name: 'faq' }, [
-  p('Content for section 1')
-]),
-_accordion({ title: 'Section 2', name: 'faq' }, [
-  p('Content for section 2')
-])

_drawer - Sidebar Drawer

Responsive drawer component that can be toggled programmatically.

Properties:

PropertyTypeDescription
idstringUnique ID for checkbox toggle
$opensignalBoolean signal for drawer state
contentHTMLElementMain content area
sideHTMLElementSidebar content

Example:

javascript
const $drawerOpen = $(false);
-
-_drawer({
-  id: 'main-drawer',
-  $open: $drawerOpen,
-  content: [
-    _button({ onclick: () => $drawerOpen(true) }, 'Open Menu'),
-    div('Main content goes here')
-  ],
-  side: [
-    _menu({ items: [
-      { label: 'Home', onclick: () => $drawerOpen(false) },
-      { label: 'Settings', onclick: () => $drawerOpen(false) }
-    ]})
-  ]
-})

Responsive navigation bar with built-in styling.

Properties:

PropertyTypeDescription
classstring|functionAdditional classes

Example:

javascript
_navbar([
-  div({ class: 'flex-1' }, [
-    a({ class: 'text-xl font-bold' }, 'MyApp')
-  ]),
-  div({ class: 'flex-none' }, [
-    _button({ class: 'btn-ghost btn-sm' }, 'Login'),
-    _button({ class: 'btn-primary btn-sm' }, 'Sign Up')
-  ])
-])

Sidebar or dropdown menu with active state support.

Properties:

PropertyTypeDescription
itemsArray<{label: string, icon?: any, active?: boolean|function, onclick: function}>Menu items

Example:

javascript
const $currentPage = $('home');
-
-_menu({ items: [
-  { 
-    label: 'Dashboard', 
-    icon: '📊',
-    active: () => $currentPage() === 'dashboard',
-    onclick: () => $currentPage('dashboard')
-  },
-  { 
-    label: 'Profile', 
-    icon: '👤',
-    active: () => $currentPage() === 'profile',
-    onclick: () => $currentPage('profile')
-  },
-  { 
-    label: 'Settings', 
-    icon: '⚙️',
-    active: () => $currentPage() === 'settings',
-    onclick: () => $currentPage('settings')
-  }
-]})

_tabs - Tab Navigation

Horizontal tabs with lifted styling.

Properties:

PropertyTypeDescription
itemsArray<{label: string, active: boolean|function, onclick: function}>Tab items

Example:

javascript
const $activeTab = $('profile');
-
-_tabs({ items: [
-  { 
-    label: 'Profile', 
-    active: () => $activeTab() === 'profile',
-    onclick: () => $activeTab('profile')
-  },
-  { 
-    label: 'Settings', 
-    active: () => $activeTab() === 'settings',
-    onclick: () => $activeTab('settings')
-  }
-]})

Feedback Components

_badge - Status Indicator

Small badge for counts, statuses, or labels.

Properties:

PropertyTypeDescription
classstring|functionBadge style (badge-primary, badge-success, etc.)

Example:

javascript
_badge({ class: 'badge-success' }, 'Active')
-_badge({ class: 'badge-error' }, '3 Errors')
-_badge({ class: 'badge-warning' }, 'Pending')

_tooltip - Hover Information

Wrapper that shows tooltip text on hover.

Properties:

PropertyTypeDescription
tipstringTooltip text
positionstringTooltip position (top, bottom, left, right)

Example:

javascript
_tooltip({ tip: 'Click to save changes', class: 'tooltip-primary' }, [
-  _button({}, 'Save')
-])
-
-_tooltip({ tip: 'Your email will not be shared', class: 'tooltip-bottom' }, [
-  span('ⓘ')
-])

Container Components

Programmatically controlled modal dialog.

Properties:

PropertyTypeDescription
$opensignalBoolean signal controlling visibility
titlestringModal title
classstring|functionAdditional styling

Example:

javascript
const $showModal = $(false);
-
-_modal({ 
-  $open: $showModal, 
-  title: 'Confirm Action' 
-}, [
-  p('Are you sure you want to delete this item?'),
-  div({ class: 'flex gap-2 justify-end mt-4' }, [
-    _button({ onclick: () => $showModal(false) }, 'Cancel'),
-    _button({ 
-      class: 'btn-error',
-      onclick: () => {
-        deleteItem();
-        $showModal(false);
-      }
-    }, 'Delete')
-  ])
-])
-
-// Trigger modal
-_button({ onclick: () => $showModal(true) }, 'Delete Item')

Dropdown menu that appears on click.

Properties:

PropertyTypeDescription
labelstringDropdown trigger text
classstring|functionAdditional classes

Example:

javascript
_dropdown({ label: 'Options' }, [
-  li([a({ onclick: () => edit() }, 'Edit')]),
-  li([a({ onclick: () => duplicate() }, 'Duplicate')]),
-  li([a({ class: 'text-error', onclick: () => delete() }, 'Delete')])
-])

Complete Examples

Example 1: User Registration Form

javascript
// Signals
-const $username = $('');
-const $email = $('');
-const $password = $('');
-const $terms = $(false);
-const $loading = $(false);
-
-// Validation signals
-const $usernameError = $(null);
-const $emailError = $(null);
-const $passwordError = $(null);
-
-// Form submission
-const handleSubmit = async () => {
-  $loading(true);
-  
-  // Validate
-  if ($username().length < 3) $usernameError('Username too short');
-  if (!$email().includes('@')) $emailError('Invalid email');
-  if ($password().length < 6) $passwordError('Password too short');
-  if (!$terms()) alert('Accept terms');
-  
-  if (!$usernameError() && !$emailError() && !$passwordError()) {
-    await api.register({
-      username: $username(),
-      email: $email(),
-      password: $password()
-    });
-  }
-  
-  $loading(false);
-};
-
-// Component
-div({ class: 'max-w-md mx-auto p-6' }, [
-  _fieldset({ legend: 'Create Account' }, [
-    _input({
-      label: 'Username',
-      $value: $username,
-      $error: $usernameError,
-      placeholder: 'johndoe'
-    }),
-    _input({
-      label: 'Email',
-      type: 'email',
-      $value: $email,
-      $error: $emailError,
-      placeholder: 'john@example.com'
-    }),
-    _input({
-      label: 'Password',
-      type: 'password',
-      $value: $password,
-      $error: $passwordError
-    }),
-    _checkbox({
-      label: 'I agree to the Terms of Service',
-      $value: $terms
-    }),
-    _button({
-      $loading: $loading,
-      class: 'btn-primary w-full mt-4',
-      onclick: handleSubmit
-    }, 'Sign Up')
-  ])
-])

Example 2: Dashboard with Router Integration

javascript
// App.js
-export default () => {
-  const $activeRoute = $('dashboard');
-  
-  return div({ class: 'min-h-screen' }, [
-    _navbar([
-      div({ class: 'flex-1' }, [
-        a({ class: 'text-xl font-bold' }, 'Dashboard')
-      ]),
-      _button({ 
-        class: 'btn-ghost btn-circle',
-        onclick: () => $.router.go('/settings')
-      }, '⚙️')
-    ]),
-    div({ class: 'flex' }, [
-      // Sidebar
-      div({ class: 'w-64 p-4' }, [
-        _menu({ items: [
-          { 
-            label: 'Dashboard', 
-            icon: '📊',
-            active: () => $activeRoute() === 'dashboard',
-            onclick: () => {
-              $activeRoute('dashboard');
-              $.router.go('/');
-            }
-          },
-          { 
-            label: 'Analytics', 
-            icon: '📈',
-            active: () => $activeRoute() === 'analytics',
-            onclick: () => {
-              $activeRoute('analytics');
-              $.router.go('/analytics');
-            }
-          },
-          { 
-            label: 'Settings', 
-            icon: '⚙️',
-            active: () => $activeRoute() === 'settings',
-            onclick: () => {
-              $activeRoute('settings');
-              $.router.go('/settings');
-            }
-          }
-        ]})
-      ]),
-      
-      // Main content
-      div({ class: 'flex-1 p-6' }, [
-        $.router([
-          { path: '/', component: () => DashboardComponent() },
-          { path: '/analytics', component: () => AnalyticsComponent() },
-          { path: '/settings', component: () => SettingsComponent() }
-        ])
-      ])
-    ])
-  ]);
-};

Example 3: E-commerce Product Card

javascript
const ProductCard = ({ product }) => {
-  const $quantity = $(1);
-  const $inCart = $(false);
-  
-  return div({ class: 'card bg-base-100 shadow-xl' }, [
-    figure([img({ src: product.image, alt: product.name })]),
-    div({ class: 'card-body' }, [
-      h2({ class: 'card-title' }, product.name),
-      p(product.description),
-      div({ class: 'flex justify-between items-center mt-4' }, [
-        span({ class: 'text-2xl font-bold' }, \`$\${product.price}\`),
-        div({ class: 'flex gap-2' }, [
-          _range({
-            min: 1,
-            max: 10,
-            $value: $quantity,
-            class: 'w-32'
-          }),
-          _button({
-            $loading: $inCart,
-            class: 'btn-primary',
-            onclick: async () => {
-              $inCart(true);
-              await addToCart(product.id, $quantity());
-              $inCart(false);
-            }
-          }, 'Add to Cart')
-        ])
-      ])
-    ])
-  ]);
-};

Styling Guide

Theme Configuration

DaisyUI v5 supports extensive theming. Configure in tailwind.config.js or CSS:

css
/* app.css */
-@import "tailwindcss";
-@plugin "daisyui";
-
-/* Custom theme */
-[data-theme="corporate"] {
-  --color-primary: oklch(0.6 0.2 250);
-  --color-secondary: oklch(0.7 0.15 150);
-  --color-accent: oklch(0.8 0.1 50);
-  --color-neutral: oklch(0.3 0.01 260);
-  --color-base-100: oklch(0.98 0.01 260);
-  --color-info: oklch(0.65 0.2 220);
-  --color-success: oklch(0.65 0.2 140);
-  --color-warning: oklch(0.7 0.2 85);
-  --color-error: oklch(0.65 0.25 25);
-}

Component Modifiers

Each component accepts Tailwind/daisyUI classes:

javascript
// Button variants
-_button({ class: 'btn-primary' }, 'Primary')
-_button({ class: 'btn-secondary' }, 'Secondary')
-_button({ class: 'btn-accent' }, 'Accent')
-_button({ class: 'btn-outline' }, 'Outline')
-_button({ class: 'btn-ghost' }, 'Ghost')
-_button({ class: 'btn-sm' }, 'Small')
-_button({ class: 'btn-lg' }, 'Large')
-_button({ class: 'btn-block' }, 'Full Width')

Best Practices

1. Reactive Performance

Always use signals for values that change, not direct variable assignments:

javascript
// ❌ Bad
-let name = 'John';
-_input({ $value: () => name }); // Won't update
-
-// ✅ Good
-const $name = $('John');
-_input({ $value: $name });

2. Error Handling

Use $error signals with validation:

javascript
const $error = $(null);
-
-_input({
-  $error: $error,
-  onchange: (e) => {
-    if (!validate(e.target.value)) {
-      $error('Invalid input');
-    } else {
-      $error(null);
-    }
-  }
-})

3. Modal Management

Keep modals conditionally rendered based on $open:

javascript
// Modal only exists in DOM when open
-_modal({ $open: $showModal }, content)

4. Form Submissions

Combine loading states with error handling:

javascript
const $loading = $(false);
-const $error = $(null);
-
-_button({
-  $loading: $loading,
-  onclick: async () => {
-    $loading(true);
-    try {
-      await submit();
-      $error(null);
-    } catch (err) {
-      $error(err.message);
-    }
-    $loading(false);
-  }
-}, 'Submit')

5. Component Composition

Build reusable components by combining UI primitives:

javascript
const FormField = ({ label, $value, type = 'text' }) => {
-  return _fieldset({ legend: label }, [
-    _input({ type, $value, class: 'w-full' })
-  ]);
-};
-
-// Usage
-FormField({ label: 'Email', $value: $email });

API Reference

All components are globally available after plugin initialization:

ComponentFunction Signature
_button(props, children) => HTMLElement
_input(props) => HTMLElement
_select(props) => HTMLElement
_checkbox(props) => HTMLElement
_radio(props) => HTMLElement
_range(props) => HTMLElement
_fieldset(props, children) => HTMLElement
_accordion(props, children) => HTMLElement
_modal(props, children) => HTMLElement
_drawer(props) => HTMLElement
_navbar(props, children) => HTMLElement
_menu(props) => HTMLElement
_tabs(props) => HTMLElement
_badge(props, children) => HTMLElement
_tooltip(props, children) => HTMLElement
_dropdown(props, children) => HTMLElement

Troubleshooting

Styles Not Applying

Ensure Tailwind CSS is properly configured and imported before your app code:

javascript
import './app.css'; // Must be first
-import { $ } from 'sigpro';

Components Not Found

Verify plugin is loaded before using components:

javascript
$.plugin(UI).then(() => {
-  // Components are ready
-  $.mount(App);
-});

Reactive Updates Not Working

Ensure you're using signals, not primitive values:

javascript
// Wrong
-let count = 0;
-_button({}, () => count)
-
-// Correct
-const $count = $(0);
-_button({}, () => $count())
`,178)])])}const o=i(h,[["render",l]]);export{g as __pageData,o as default}; diff --git a/docs/assets/plugins_core.ui.md.C434Uobv.lean.js b/docs/assets/plugins_core.ui.md.C434Uobv.lean.js deleted file mode 100644 index 058cac5..0000000 --- a/docs/assets/plugins_core.ui.md.C434Uobv.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"SigPro UI Plugin - Complete Documentation","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/core.ui.md","filePath":"plugins/core.ui.md"}'),h={name:"plugins/core.ui.md"};function l(p,s,k,e,E,d){return a(),n("div",null,[...s[0]||(s[0]=[t("",178)])])}const o=i(h,[["render",l]]);export{g as __pageData,o as default}; diff --git a/docs/assets/plugins_custom.md.D6eJnwEa.js b/docs/assets/plugins_custom.md.BuhVOLjH.js similarity index 86% rename from docs/assets/plugins_custom.md.D6eJnwEa.js rename to docs/assets/plugins_custom.md.BuhVOLjH.js index cf4ad7e..ab4b39f 100644 --- a/docs/assets/plugins_custom.md.D6eJnwEa.js +++ b/docs/assets/plugins_custom.md.BuhVOLjH.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Creating Custom Plugins","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/custom.md","filePath":"plugins/custom.md"}'),l={name:"plugins/custom.md"};function h(e,s,p,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t(`

Creating Custom Plugins

There are two main ways to expose a plugin's functionality: Static/Manual Imports (cleaner for large projects) or Global/Automatic Window Injection (easier for quick scripts and global helpers).

1. The Anatomy of a Plugin

A plugin is a standard JavaScript function. By convention, if a plugin adds a global helper or component, it should be prefixed with an underscore (_).

javascript
// plugins/my-utils.js
+import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Creating Custom Plugins","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/custom.md","filePath":"plugins/custom.md"}'),h={name:"plugins/custom.md"};function l(p,s,e,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t(`

Creating Custom Plugins

There are two main ways to expose a plugin's functionality: Static/Manual Imports (cleaner for large projects) or Global/Automatic Window Injection (easier for quick scripts and global helpers).

1. The Anatomy of a Plugin

A plugin is a standard JavaScript function. By convention, if a plugin adds a global helper or component, it should be prefixed with an underscore (_).

javascript
// plugins/my-utils.js
 export const MyUtils = ($) => {
   
   // 1. Attach to the SigPro instance
@@ -45,4 +45,4 @@ import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const o
 $.plugin(ConfigLoader).then(() => {
   console.log("Config loaded:", $.config);
   $.mount(App);
-});

4. Best Practices for Plugin Authors

RuleDescription
PrefixingUse _ for UI components (_modal) and $. for logic ($.fetch).
IdempotencyEnsure calling $.plugin(MyPlugin) twice doesn't break the app.
EncapsulationUse the $ instance passed as an argument rather than importing it again inside the plugin.
ReactivityAlways use $(...) for internal state so the app stays reactive.

5. Installation

Custom plugins don't require extra packages, but ensure your build tool (Vite/Bun) is configured to handle the module imports.

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
`,24)])])}const E=i(l,[["render",h]]);export{o as __pageData,E as default}; +});

4. Best Practices for Plugin Authors

RuleDescription
PrefixingUse _ for UI components (_modal) and $. for logic ($.fetch).
IdempotencyEnsure calling $.plugin(MyPlugin) twice doesn't break the app.
EncapsulationUse the $ instance passed as an argument rather than importing it again inside the plugin.
ReactivityAlways use $(...) for internal state so the app stays reactive.
`,20)])])}const o=i(h,[["render",l]]);export{g as __pageData,o as default}; diff --git a/docs/assets/plugins_custom.md.BuhVOLjH.lean.js b/docs/assets/plugins_custom.md.BuhVOLjH.lean.js new file mode 100644 index 0000000..eed5e50 --- /dev/null +++ b/docs/assets/plugins_custom.md.BuhVOLjH.lean.js @@ -0,0 +1 @@ +import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Creating Custom Plugins","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/custom.md","filePath":"plugins/custom.md"}'),h={name:"plugins/custom.md"};function l(p,s,e,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t("",20)])])}const o=i(h,[["render",l]]);export{g as __pageData,o as default}; diff --git a/docs/assets/plugins_custom.md.D6eJnwEa.lean.js b/docs/assets/plugins_custom.md.D6eJnwEa.lean.js deleted file mode 100644 index 6535180..0000000 --- a/docs/assets/plugins_custom.md.D6eJnwEa.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,o as a,c as n,ae as t}from"./chunks/framework.C8AWLET_.js";const o=JSON.parse('{"title":"Creating Custom Plugins","description":"","frontmatter":{},"headers":[],"relativePath":"plugins/custom.md","filePath":"plugins/custom.md"}'),l={name:"plugins/custom.md"};function h(e,s,p,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t("",24)])])}const E=i(l,[["render",h]]);export{o as __pageData,E as default}; diff --git a/docs/assets/plugins_quick.md.BBIL_nLZ.js b/docs/assets/plugins_quick.md.DOyIUaNj.js similarity index 97% rename from docs/assets/plugins_quick.md.BBIL_nLZ.js rename to docs/assets/plugins_quick.md.DOyIUaNj.js index c87fad4..5f0253b 100644 --- a/docs/assets/plugins_quick.md.BBIL_nLZ.js +++ b/docs/assets/plugins_quick.md.DOyIUaNj.js @@ -10,11 +10,11 @@ import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g const $count = $(0); $.watch($count, "Counter"); // Now available globally via $

2. Initialization Patterns (SigPro)

Thanks to the Synchronous Tag Engine, you no longer need complex import() nesting. Global tags like div(), span(), and button() are ready the moment you import the Core.

This is the standard way to build apps. It's clean, readable, and supports standard ESM imports.

javascript
// main.js
 import { $ } from 'sigpro';
-import { UI } from 'sigpro/plugins';
+import { Fetch } from 'sigpro/plugins';
 import App from './App.js'; // Static import works perfectly!
 
 // 1. Register plugins
-$.plugin(UI);
+$.plugin(Fetch);
 
 // 2. Mount your app directly
 $.mount(App, '#app');

3. Resource Plugins (External Scripts)

You can pass a URL or an Array of URLs. SigPro will inject them as <script> tags and return a Promise that resolves when the scripts are fully loaded. This is perfect for integrating heavy third-party libraries only when needed.

javascript
// Loading external libraries as plugins
diff --git a/docs/assets/plugins_quick.md.BBIL_nLZ.lean.js b/docs/assets/plugins_quick.md.DOyIUaNj.lean.js
similarity index 100%
rename from docs/assets/plugins_quick.md.BBIL_nLZ.lean.js
rename to docs/assets/plugins_quick.md.DOyIUaNj.lean.js
diff --git a/docs/assets/vite_plugin.md.BxGCvKkk.js b/docs/assets/vite_plugin.md.CTs8LDIL.js
similarity index 86%
rename from docs/assets/vite_plugin.md.BxGCvKkk.js
rename to docs/assets/vite_plugin.md.CTs8LDIL.js
index 2229591..166ba5a 100644
--- a/docs/assets/vite_plugin.md.BxGCvKkk.js
+++ b/docs/assets/vite_plugin.md.CTs8LDIL.js
@@ -1,4 +1,4 @@
-import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Vite Plugin: File-based Routing","description":"","frontmatter":{},"headers":[],"relativePath":"vite/plugin.md","filePath":"vite/plugin.md"}'),e={name:"vite/plugin.md"};function l(p,s,h,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Vite Plugin: File-based Routing

The sigproRouter plugin for Vite automates route generation by scanning your pages directory. It creates a virtual module that you can import directly into your code, eliminating the need to maintain a manual routes array.

1. Project Structure

To use the plugin, organize your files within the src/pages directory. The folder hierarchy directly determines your application's URL structure. SigPro uses brackets [param] for dynamic segments.

text
my-sigpro-app/
+import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Vite Plugin: File-based Routing","description":"","frontmatter":{},"headers":[],"relativePath":"vite/plugin.md","filePath":"vite/plugin.md"}'),e={name:"vite/plugin.md"};function p(l,s,h,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[n(`

Vite Plugin: File-based Routing

The sigproRouter plugin for Vite automates route generation by scanning your pages directory. It creates a virtual module that you can import directly into your code, eliminating the need to maintain a manual routes array.

1. Project Structure

To use the plugin, organize your files within the src/pages directory. The folder hierarchy directly determines your application's URL structure. SigPro uses brackets [param] for dynamic segments.

text
my-sigpro-app/
 ├── src/
 │   ├── pages/
 │   │   ├── index.js          →  #/
@@ -46,4 +46,4 @@ import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g
   { path: '/', component: () => import('/src/pages/index.js') },
   { path: '/users/:id', component: () => import('/src/pages/users/[id].js') },
   // ...
-];

Because it uses dynamic import(), Vite automatically performs Code Splitting, meaning each page is its own small JS file that only loads when the user navigates to it.


6. Installation

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
`,30)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; +];

Because it uses dynamic import(), Vite automatically performs Code Splitting, meaning each page is its own small JS file that only loads when the user navigates to it.

`,27)])])}const E=i(e,[["render",p]]);export{g as __pageData,E as default}; diff --git a/docs/assets/vite_plugin.md.BxGCvKkk.lean.js b/docs/assets/vite_plugin.md.CTs8LDIL.lean.js similarity index 61% rename from docs/assets/vite_plugin.md.BxGCvKkk.lean.js rename to docs/assets/vite_plugin.md.CTs8LDIL.lean.js index 72fd347..8f3c678 100644 --- a/docs/assets/vite_plugin.md.BxGCvKkk.lean.js +++ b/docs/assets/vite_plugin.md.CTs8LDIL.lean.js @@ -1 +1 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Vite Plugin: File-based Routing","description":"","frontmatter":{},"headers":[],"relativePath":"vite/plugin.md","filePath":"vite/plugin.md"}'),e={name:"vite/plugin.md"};function l(p,s,h,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n("",30)])])}const c=i(e,[["render",l]]);export{g as __pageData,c as default}; +import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Vite Plugin: File-based Routing","description":"","frontmatter":{},"headers":[],"relativePath":"vite/plugin.md","filePath":"vite/plugin.md"}'),e={name:"vite/plugin.md"};function p(l,s,h,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[n("",27)])])}const E=i(e,[["render",p]]);export{g as __pageData,E as default}; diff --git a/docs/examples.html b/docs/examples.html new file mode 100644 index 0000000..4c5d7a9 --- /dev/null +++ b/docs/examples.html @@ -0,0 +1,45 @@ + + + + + + Live Playground | SigPro + + + + + + + + + + + + + + + +
Skip to content

Live Playground

Experience SigPro's fine-grained reactivity in real-time. Feel free to tweak the signal values in the editor!

```

2. Best Practices for Documentation

  • Tab Selection: You can control which tabs are active by default by changing the URL segment after /embedded/.
    • js,result: Shows the logic and the output.
    • html,js,result: Shows the base structure, the logic, and the output.
  • Height Management: For complex Store examples, increase the height attribute to 500 or 600 so the code is readable without internal scrolling.
  • Responsive Width: Keeping width="100%" ensures the fiddle scales correctly on tablets and mobile devices.

3. Advanced: The "Fiddle" Component (Optional)

If you plan to have 10+ examples, you can create a global Vue component in VitePress. This keeps your Markdown files clean and allows you to change the theme or default height for all fiddles at once.

Create .vitepress/theme/components/Fiddle.vue:

vue
<template>
+  <div class="fiddle-wrapper" style="margin: 20px 0;">
+    <iframe 
+      width="100%" 
+      :height="height" 
+      :src="`//jsfiddle.net/natxocc/${id}/embedded/${tabs}/dark/`" 
+      frameborder="0"
+      loading="lazy">
+    </iframe>
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  id: String,      // e.g., "spwran02/4"
+  height: { default: '400' },
+  tabs: { default: 'js,result' }
+})
+</script>

Usage in Markdown:

markdown
Check out this store example:
+<Fiddle id="spwran02/4" height="500" />

Why this is perfect for SigPro:

Because SigPro is zero-dependency and runs directly in the browser, your JSFiddle code will be exactly what the user copies into their own index.html. There is no hidden "build step" confusing the learner.

+ + + + \ No newline at end of file diff --git a/docs/guide/getting-started.html b/docs/guide/getting-started.html deleted file mode 100644 index cdf0e15..0000000 --- a/docs/guide/getting-started.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - Getting Started | SigPro - - - - - - - - - - - - - - - -
Skip to content

Getting Started

SigPro is a lightweight, atomic reactive engine designed to build modern web interfaces with zero overhead. It focuses on high performance through fine-grained reactivity.

1. Installation

You can install SigPro via your favorite package manager:

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

2. Basic Usage

The core of SigPro is the $ function, which creates reactive state (Signals) and computed effects.

Create a main.js file and try this:

javascript
import { $ } from 'SigPro';
-
-// 1. Create a reactive signal
-const $name = $("World");
-
-// 2. Define a reactive component
-const App = () => div({ class: 'container' }, [
-  h1(["Hello, ", $name, "!"]),
-  
-  input({ 
-    type: 'text', 
-    $value: $name, // Two-way binding
-    placeholder: 'Enter your name...' 
-  }),
-  
-  button({ 
-    onclick: () => $name("SigPro") 
-  }, "Set to SigPro")
-]);
-
-// 3. Mount the application
-$.mount(App, '#app');

3. How it Works

SigPro doesn't use a Virtual DOM. Instead, it creates real DOM nodes and binds them directly to your data:

  1. Signals: $(value) creates a getter/setter function.
  2. Reactivity: When you pass a signal or a function to a DOM element, SigPro automatically creates a subscription.
  3. Fine-Grained Updates: Only the specific text node or attribute linked to the signal updates when the value changes.

4. Global Tags

By default, SigPro exports common HTML tags to the global scope (window) when initialized. This allows you to write clean, declarative UI without importing every single tag:

javascript
// Instead of $.html('div', ...), just use:
-div([
-  h1("Clean Syntax"),
-  p("No more boilerplate.")
-]);
- - - - \ No newline at end of file diff --git a/docs/guide/why.html b/docs/guide/why.html deleted file mode 100644 index 6b210e6..0000000 --- a/docs/guide/why.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Why SigPro? | SigPro - - - - - - - - - - - - - - - -
Skip to content

Why SigPro?

After years of building applications with React, Vue, and Svelte—investing countless hours mastering unique mental models, proprietary syntaxes, and complex build tools—we reached a realization: the web platform has evolved, but frameworks have become layers of abstraction that often move us further away from the browser.

SigPro is the answer to a simple question: Why fight the platform when we can embrace it?

The Modern Web is Ready

SigPro bypasses the overhead of the Virtual DOM and heavy compilers by using modern browser primitives. It treats the DOM as a first-class citizen, not as a side effect of a state change.

Browser PrimitiveWhat It Enables
Closures & ProxiesAutomatic dependency tracking without heavy overhead.
ES ModulesNative modularity and lazy loading without complex bundlers.
Direct DOM APIsSurgical updates that are faster than any reconciliation algorithm.
Microtask QueuesBatching updates efficiently to ensure 60fps performance.

The SigPro Philosophy

SigPro strips away the complexity, delivering a reactive programming model that feels like a framework but stays remarkably close to Vanilla JS:

  • No JSX transformations – Pure JavaScript functions.
  • No Virtual DOM – Direct, fine-grained DOM manipulation.
  • No proprietary syntax – If you know JS, you know SigPro.
  • Zero Build Step Required – It can run directly in the browser via ESM.
javascript
// Pure, Atomic, Reactive.
-const $count = $(0);
-
-const Counter = () => div([
-  p(["Count: ", $count]),
-  button({ onclick: () => $count(c => c + 1) }, "Increment")
-]);

Performance Comparison

SigPro isn't just lighter; it's architecturally faster because it skips the "diffing" phase entirely.

MetricSigProSolidJSSvelteVueReact
Bundle Size (gzip)🥇 < 2KB🥈 7KB🥉 16KB20KB45KB
ArchitectureAtomicAtomicCompiledV-DOMV-DOM
Initial Render🥇 Fastest🥈 Fast🥉 FastAverageSlow
Update Perf🥇 Surgical🥇 Surgical🥈 Fast🥉 AverageSlow
Dependencies🥇 0🥇 0🥇 0🥈 2🥉 5+
Build Step🥇 Optional🥈 Required🥈 Required🥇 Optional🥈 Required

🔑 Core Principles

SigPro is built on four fundamental pillars:

📡 Atomic Reactivity

Automatic dependency tracking with no manual subscriptions. When a signal changes, only the exact text nodes or attributes that depend on it update—instantly and surgically.

⚡ Surgical DOM Updates

No Virtual DOM diffing. No tree reconciliation. We don't guess what changed; we know exactly where the update needs to happen. Performance scales with your data, not the size of your component tree.

🧩 Plugin-First Architecture

The core is a tiny, powerful engine. Need Routing? Fetching? Global UI? Just plug it in. This keeps your production bundles "pay-only-for-what-you-use."

🔬 Predictable & Transparent

There is no "magic" hidden in a black-box compiler. What you write is what the browser executes. Debugging is straightforward because there is no framework layer between your code and the DevTools.


"SigPro returns the joy of web development by making the browser the hero again."

- - - - \ No newline at end of file diff --git a/docs/hashmap.json b/docs/hashmap.json index 1b853b5..3165fd7 100644 --- a/docs/hashmap.json +++ b/docs/hashmap.json @@ -1 +1 @@ -{"api__.md":"CJ6A9esy","api_html.md":"-lEpgX-Z","api_mount.md":"DK1GUmQ8","api_quick.md":"Cy_XozKR","api_router.md":"BV6vPWg-","api_tags.md":"BAYRMzRh","guide_getting-started.md":"BJ3Lg3i9","guide_why.md":"lyU7T5_c","index.md":"DTGopCPx","plugins_core.debug.md":"BKuhgPoj","plugins_core.fetch.md":"BIc8aMQh","plugins_core.router.md":"Bg_zmVp3","plugins_core.storage.md":"C6UMGg_o","plugins_core.ui.md":"C434Uobv","plugins_custom.md":"D6eJnwEa","plugins_quick.md":"BBIL_nLZ","ui_button.md":"B087poC6","ui_form.md":"CZVTxszG","ui_input.md":"mJqBxkG3","ui_installation.md":"C7ubLVYa","ui_introduction.md":"CpBz5t8n","ui_layout.md":"DLaYXca7","ui_modal.md":"Hjip_i1A","ui_navigation.md":"CK3sbH-I","vite_plugin.md":"BxGCvKkk"} +{"api__.md":"BV8uIOD5","api_html.md":"-lEpgX-Z","api_mount.md":"B9mWME6o","api_quick.md":"OAEBn6rS","api_router.md":"BV6vPWg-","api_tags.md":"YLRdMyid","examples.md":"Cy97nBRw","index.md":"By6smViD","install.md":"pJydCe65","plugins_custom.md":"BuhVOLjH","plugins_quick.md":"DOyIUaNj","ui_button.md":"B087poC6","ui_form.md":"CZVTxszG","ui_input.md":"mJqBxkG3","ui_installation.md":"C7ubLVYa","ui_introduction.md":"CpBz5t8n","ui_layout.md":"DLaYXca7","ui_modal.md":"Hjip_i1A","ui_navigation.md":"CK3sbH-I","vite_plugin.md":"CTs8LDIL"} diff --git a/docs/index.html b/docs/index.html index 403ce1e..1fb2b6c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -13,30 +13,14 @@ - + -
Skip to content

SigProAtomic Unified Reactive Engine

Fine-grained reactivity, built-in routing, and modular plugins. All under 2KB.

SigPro Logo

Why SigPro?

SigPro isn't just another framework; it's a high-performance engine. It strips away the complexity of massive bundles and returns to the essence of the web, enhanced with reactive superpowers.

The Core in Action

javascript
import { $ } from 'sigpro2';
-
-// A reactive state Signal
-const $count = $(0);
-
-// A Computed signal that updates automatically
-const $double = $(() => $count() * 2);
-
-// UI that breathes with your data
-const Counter = () => div([
-  h1(["Count: ", $count]),
-  p(["Double: ", $double]),
-  button({ onclick: () => $count(c => c + 1) }, "Increment")
-]);
-
-$.mount(Counter);

Key Features

⚡️ Fine-Grained Reactivity

Unlike frameworks that diff complex trees (V-DOM), SigPro binds your signals directly to real DOM text nodes and attributes. If the data changes, the node changes. Period.

🔌 Polymorphic Plugin System

Extend core capabilities in a single line. Add global UI helpers, routing, or state persistence seamlessly.

javascript
import { UI, Router } from 'sigpro/plugins';
-$.plugin([UI, Router]);

📂 File-Based Routing

With our dedicated Vite plugin, manage your routes simply by creating files in src/pages/. It supports native Lazy Loading out of the box for lightning-fast initial loads.


Quick Install

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

Community & Support

SigPro is an open-source project. Whether you want to contribute, report a bug, or just talk about reactivity, join us on our official repository.

Built with ❤️ by NatxoCC
- +
Skip to content

SigProAtomic Unified Reactive Engine

High-precision atomic reactivity. No Virtual DOM. No compiler. No dependencies.

SigPro Logo

Redefining Modern Reactivity

SigPro is not just another framework; it is a high-performance engine. While other libraries add layers of abstraction that slow down execution, SigPro returns to the essence of the web, leveraging the power of modern browser engines.

Why SigPro?

⚡️ Surgical DOM Efficiency

Unlike React or Vue, SigPro doesn't compare element trees. When a signal changes, SigPro knows exactly which DOM node depends on it and updates it instantly. It is reactive precision at its finest.

🔌 Modular Plugin System

The core is sacred. Any extra functionality—Routing, UI Helpers, or State Persistence—is integrated through a polymorphic plugin system. Load only what your application truly needs.

💾 Native Persistence

SigPro features first-class support for localStorage. Synchronizing your application state with persistent storage is as simple as providing a key when initializing your Signal.

🚦 Built-in Hash Routing

A robust routing system that supports Native Lazy Loading out of the box. Load your components only when the user navigates to them, keeping initial load times near zero.


The "No-Build" Philosophy

In an ecosystem obsessed with compilers, SigPro bets on standardization. Write code today that will still run 10 years from now, without depending on build tools that will eventually become obsolete.

"The best way to optimize code is to not have to process it at all."


Community & Vision

SigPro is an open-source project focused on simplicity and extreme speed. Designed for developers who love the web platform and hate unnecessary "bloatware".

text
Built with ❤️ by NatxoCC for the Modern Web.
+ \ No newline at end of file diff --git a/docs/install.html b/docs/install.html new file mode 100644 index 0000000..0553c85 --- /dev/null +++ b/docs/install.html @@ -0,0 +1,70 @@ + + + + + + Installation & Setup | SigPro + + + + + + + + + + + + + + + +
Skip to content

Installation & Setup

SigPro is designed to be drop-in ready. Whether you are building a complex application with a bundler or a simple reactive widget in a single HTML file, SigPro scales with your needs.

1. Installation

Choose the method that best fits your workflow:

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
html
<script type="module">
+  import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
+</script>

2. Quick Start Examples

Depending on your installation method, here is how you can get SigPro running in seconds.

javascript
// File: App.js
+import { $ } from 'sigpro'; 
+
+export const App = () => {
+  // $ is global, but we import it for better IDE intellisense
+  const $count = $(0);
+  
+  // Tags like div, h1, button are available globally
+  return div({ class: 'card' }, [
+    h1(["Count is: ", $count]),
+    button({ onclick: () => $count(c => c + 1) }, "Increment")
+  ]);
+};
+
+// File: main.js
+import { $ } from 'sigpro';
+import { App } from './App.js';
+
+$.mount(App, '#app');
html
<!DOCTYPE html>
+<html lang="en">
+<body>
+  <div id="app"></div>
+
+  <script type="module">
+    // Import directly from CDN
+    import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
+
+    const $name = $("Developer");
+
+    // No need to import div, section, h2, input... they are global!
+    const App = () => section([
+      h2(["Welcome, ", $name]),
+      input({ 
+        type: 'text', 
+        $value: $name, // Automatic two-way binding
+        placeholder: 'Type your name...' 
+      })
+    ]);
+
+    $.mount(App, '#app');
+  </script>
+</body>
+</html>

3. Global by Design

One of SigPro's core strengths is its Global API.

  • The $ Function: Once loaded, it attaches itself to window.$. While you can use import for better IDE support and type checking, it is accessible everywhere.
  • HTML Tags: Common tags (div, span, button, etc.) are automatically registered in the global scope. This eliminates "Import Hell" and keeps your components clean and readable.

4. Why no build step?

Because SigPro uses native ES Modules and standard JavaScript functions to generate the DOM, you don't actually need a compiler like Babel or a loader for JSX.

  • Development: Just save and refresh. No complex HMR issues.
  • Production: Use any bundler (Vite, esbuild, Rollup) to tree-shake and minify your final code for maximum performance.
+ + + + \ No newline at end of file diff --git a/docs/plugins/core.debug.html b/docs/plugins/core.debug.html deleted file mode 100644 index 21bd7ea..0000000 --- a/docs/plugins/core.debug.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - Development Tool: _debug | SigPro - - - - - - - - - - - - - - - -
Skip to content

Development Tool: _debug

The Debug Plugin is a lightweight reactive listener. Once attached to a signal or a computed function, it automatically monitors changes, compares values, and formats the output in the browser console.

1. Core Features

  • Reactive Tracking: Automatically logs whenever the tracked signal updates.
  • Visual Grouping: Uses styled console groups to keep your dev tools organized.
  • Object Inspection: Automatically uses console.table() when the signal contains an object or array.
  • Efficient Comparison: Uses Object.is to prevent redundant logging if the value hasn't actually changed.

2. Installation

To use _debug, you only need the SigPro core. Register the plugin in your main.js. You can conditionally load it so it only runs during development.

javascript
import { $ } from 'sigpro';
-import { Debug } from 'sigpro/plugins';
-
-// Only load Debug in development mode
-const plugins = [];
-if (import.meta.env.DEV) plugins.push(Debug);
-
-$.plugin(plugins).then(() => {
-  import('./App.js').then(app => $.mount(app.default));
-});
bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

3. Basic Usage

Call _debug anywhere in your component. It stays active in the background, watching the signal's lifecycle.

javascript
export default () => {
-  const $count = $(0);
-  const $user = $({ name: "Guest", role: "Viewer" });
-
-  // Start tracking
-  _debug($count, "Main Counter");
-  _debug($user, "User Session");
-
-  return div([
-    button({ onclick: () => $count(c => c + 1) }, "Increment"),
-    button({ onclick: () => $user({ name: "Admin", role: "Super" }) }, "Promote")
-  ]);
-};

4. Console Output Breakdown

When a signal changes, the console displays a structured block:

  1. Header: A styled badge with the name (e.g., SigPro Debug: Main Counter).
  2. Previous Value: The value before the update (in red).
  3. Current Value: The new value (in green).
  4. Table View: If the value is an object, a formatted table appears automatically.

5. Debugging Computed Values

You can also debug computed functions to see exactly when derived state is recalculated.

javascript
const $price = $(100);
-const $tax = $(0.21);
-const $total = $(() => $price() * (1 + $tax()));
-
-// Monitor the result of the calculation
-_debug($total, "Final Invoice Total");

6. Why use _debug?

  1. Clean Logic: No need to scatter console.log inside your reactive functions.
  2. State History: Instantly see the "Before" and "After" of any user action.
  3. No-Noise: It only logs when a real change occurs, keeping the console clean.
  4. Deep Inspection: The automatic console.table makes debugging large API responses much faster.
- - - - \ No newline at end of file diff --git a/docs/plugins/core.fetch.html b/docs/plugins/core.fetch.html deleted file mode 100644 index 7d06003..0000000 --- a/docs/plugins/core.fetch.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - Data Fetching: _fetch | SigPro - - - - - - - - - - - - - - - -
Skip to content

Data Fetching: _fetch

The Fetch Plugin provides a reactive wrapper around the native browser Fetch API. Instead of managing complex async/await flows within your UI, _fetch returns a "Reactive Tripod" (Data, Loading, and Error) that your components can listen to automatically.

1. Core Concept

When you call _fetch, it returns three signals immediately. Your UI declares how to react to these signals as they change from their initial state to the final response.

  • $data: Initialized as null. Automatically holds the JSON response on success.
  • $loading: Initialized as true. Flips to false once the request settles.
  • $error: Initialized as null. Holds the error message if the request fails.

2. Installation

Register the Fetch plugin in your main.js. By convention, we load it alongside the UI and Router to have the full SigPro ecosystem ready.

javascript
import { $ } from 'sigpro';
-import { Fetch } from 'sigpro/plugins';
-
-$.plugin([Fetch]).then(() => {
-  // Now _fetch() is available globally
-  import('./App.js').then(app => $.mount(app.default));
-});

3. Basic Usage

Use _fetch inside your component to get live updates. The UI updates surgically whenever a signal changes.

javascript
export default () => {
-  const { $data, $loading, $error } = _fetch('https://api.github.com/users/octocat');
-
-  return div({ class: 'p-6 flex flex-col gap-4' }, [
-    h1("Profile Details"),
-    
-    // 1. Loading State (using SigPro UI button)
-    () => $loading() && _button({ $loading: true }, "Fetching..."),
-
-    // 2. Error State
-    () => $error() && div({ class: 'alert alert-error' }, $error()),
-
-    // 3. Success State
-    () => $data() && div({ class: 'card bg-base-200 p-4' }, [
-      img({ src: $data().avatar_url, class: 'w-16 rounded-full' }),
-      h2($data().name),
-      p($data().bio)
-    ])
-  ]);
-};

4. Advanced Configuration

_fetch accepts the same RequestInit options as the standard fetch() (methods, headers, body, etc.).

javascript
const { $data, $loading } = _fetch('/api/v1/update', {
-  method: 'PATCH',
-  headers: { 'Content-Type': 'application/json' },
-  body: JSON.stringify({ status: 'active' })
-});

5. Why use _fetch instead of native Fetch?

  1. Declarative UI: You define the "Loading", "Error", and "Success" templates once, and they swap automatically.
  2. No useEffect required: Since SigPro is natively reactive, you don't need lifecycle hooks to trigger re-renders; the signals handle it.
  3. Consistency: It follows the same _prefix pattern as the rest of the official plugin ecosystem.
  4. Automatic JSON Parsing: It assumes JSON by default and handles 404/500 errors by populating the $error signal.
- - - - \ No newline at end of file diff --git a/docs/plugins/core.router.html b/docs/plugins/core.router.html deleted file mode 100644 index c030b88..0000000 --- a/docs/plugins/core.router.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - Navigation Plugin: Router | SigPro - - - - - - - - - - - - - - - -
Skip to content

Navigation Plugin: Router

The SigPro Router handles URL changes via hashes (#) and maps them to components. It supports dynamic parameters (like :id) and asynchronous loading for heavy pages.

1. Core Features

  • Hash-based: Works everywhere without special server configuration.
  • Lazy Loading: Pages are only downloaded when the user visits the route.
  • Reactive: The view updates automatically when the hash changes.
  • Dynamic Routes: Supports paths like /user/:id.

2. Installation

The Router is usually included in the official plugins package.

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next
bash
pnpm add -D tailwindcss @tailwindcss/vite daisyui@next
bash
yarn add -D tailwindcss @tailwindcss/vite daisyui@next
bash
bun add -d tailwindcss @tailwindcss/vite daisyui@next

3. Setting Up Routes

In your App.js (or a dedicated routes file), define your navigation map.

javascript
const routes = [
-  { path: '/', component: () => h1("Home Page") },
-  { 
-    path: '/admin', 
-    // Lazy Loading: This file is only fetched when needed
-    component: () => import('./pages/Admin.js') 
-  },
-  { path: '/user/:id', component: (params) => h2(`User ID: ${params.id}`) },
-  { path: '*', component: () => div("404 - Page Not Found") }
-];
-
-export default () => div([
-  _navbar({ title: "My App" }),
-  _router(routes) // The router is now a global tag
-]);

4. Navigation (_router.go)

To move between pages programmatically (e.g., inside an onclick event), use the global _router.go helper.

javascript
_button({ 
-  onclick: () => _router.go('/admin') 
-}, "Go to Admin")

5. How it Works (Under the Hood)

The router tracks the window.location.hash and uses a reactive signal to trigger a re-render of the specific area where _router(routes) is placed.

  1. Match: It filters your route array to find the best fit.
  2. Resolve: * If it's a standard function, it executes it immediately.
    • If it's a Promise (via import()), it shows a loading state and swaps the content once the module arrives.
  3. Inject: It replaces the previous DOM node with the new page content surgically.

6. Integration with UI Components

Since you are using the UI Plugin, you can easily create active states in your navigation menus by checking the current hash.

javascript
// Example of a reactive sidebar menu
-_menu({
-  items: [
-    { 
-      label: 'Dashboard', 
-      active: () => window.location.hash === '#/', 
-      onclick: () => _router.go('/') 
-    },
-    { 
-      label: 'Settings', 
-      active: () => window.location.hash === '#/settings', 
-      onclick: () => _router.go('/settings') 
-    }
-  ]
-})
- - - - \ No newline at end of file diff --git a/docs/plugins/core.storage.html b/docs/plugins/core.storage.html deleted file mode 100644 index bb2f6ab..0000000 --- a/docs/plugins/core.storage.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - Persistence Tool: _storage | SigPro - - - - - - - - - - - - - - - -
Skip to content

Persistence Tool: _storage

The Storage plugin synchronizes a signal with a specific key in your browser's localStorage. It handles both the initial hydration (loading data when the app starts) and automatic saving whenever the signal's value changes.

1. Core Concept

When you "attach" a signal to _storage, two things happen:

  1. Hydration: The plugin checks if the key already exists in localStorage. If it does, it parses the JSON and updates the signal immediately.
  2. Reactive Sync: It creates a reactive watcher that stringifies and saves the signal's value to the disk every time it is updated.

2. Installation

Register the Storage plugin in your main.js. Since this is a logic-only plugin, it doesn't require any CSS or UI dependencies.

javascript
import { $ } from 'sigpro';
-import { Storage } from 'sigpro/plugins';
-
-$.plugin(Storage).then(() => {
-  import('./App.js').then(app => $.mount(app.default));
-});
bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro

3. Basic Usage

You can wrap any signal with _storage. It is common practice to do this right after creating the signal.

javascript
export default () => {
-  // 1. Create a signal with a default value
-  const $theme = $( 'light' );
-
-  // 2. Persist it. If 'user_theme' exists in localStorage, 
-  // $theme will be updated to that value instantly.
-  _storage($theme, 'user_theme');
-
-  return div({ class: () => `app-${$theme()}` }, [
-    h1(`Current Theme: ${$theme()}`),
-    button({ 
-      onclick: () => $theme(t => t === 'light' ? 'dark' : 'light') 
-    }, "Toggle Theme")
-  ]);
-};

4. Complex Data (Objects & Arrays)

Since the plugin uses JSON.parse and JSON.stringify internally, it works perfectly with complex state structures.

javascript
const $settings = $({ 
-  notifications: true, 
-  fontSize: 16 
-});
-
-// Automatically saves the whole object whenever any property changes
-_storage($settings, 'app_settings');

5. Why use _storage?

  1. Zero Boilerplate: You don't need to manually write localStorage.getItem or setItem logic inside your components.
  2. Chaining: Because _storage returns the signal, you can persist it inline.
  3. Error Resilience: It includes a built-in try/catch block to prevent your app from crashing if the stored JSON is corrupted.
  4. Surgical Persistence: Only the signals you explicitly mark for storage are saved, keeping your localStorage clean.

6. Pro Tip: Combining with Debug

You can chain plugins to create a fully monitored and persistent state:

javascript
const $score = _storage($(0), 'high_score');
-
-// Now it's saved to disk AND logged to console on every change
-_debug($score, "Game Score");
- - - - \ No newline at end of file diff --git a/docs/plugins/core.ui.html b/docs/plugins/core.ui.html deleted file mode 100644 index bb4d510..0000000 --- a/docs/plugins/core.ui.html +++ /dev/null @@ -1,477 +0,0 @@ - - - - - - SigPro UI Plugin - Complete Documentation | SigPro - - - - - - - - - - - - - - - -
Skip to content

SigPro UI Plugin - Complete Documentation

Overview

The SigPro UI plugin is a comprehensive, reactive component library built on SigPro's atomic reactivity system. It seamlessly integrates Tailwind CSS v4 for utility-first styling and daisyUI v5 for semantic, themeable components. Every component is reactive by nature, automatically responding to signal changes without manual DOM updates.

Table of Contents

  1. Installation & Setup
  2. Core Concepts
  3. Form Components
  4. Action Components
  5. Layout Components
  6. Navigation Components
  7. Feedback Components
  8. Container Components
  9. Complete Examples
  10. Styling Guide
  11. Best Practices

Installation & Setup

Step 1: Install Dependencies

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next

Step 2: Configure Tailwind CSS v4

Create src/app.css:

css
/* src/app.css */
-@import "tailwindcss";
-@plugin "daisyui";
-
-/* Optional: Custom themes */
-@theme {
-  --color-primary: oklch(0.65 0.2 250);
-  --color-secondary: oklch(0.7 0.15 150);
-}
-
-/* Dark mode support */
-@custom-variant dark (&:where(.dark, [data-theme="dark"], [data-theme="dark"] *)));

Step 3: Initialize in Your Entry Point

javascript
// main.js
-import './app.css';
-import { $ } from 'sigpro';
-import { UI } from 'sigpro/plugins';
-
-// Load the UI plugin - makes all _components globally available
-$.plugin(UI).then(() => {
-  // All UI components are now registered
-  import('./App.js').then(app => $.mount(app.default));
-});

Core Concepts

Reactive Props

All UI components accept reactive props using the $ prefix. When you pass a signal, the component automatically updates:

javascript
const $username = $('John');
-const $error = $(null);
-
-// Reactive input with two-way binding
-_input({
-  $value: $username,     // Auto-updates when signal changes
-  $error: $error         // Shows error message when signal has value
-})

The parseClass Helper

All components intelligently merge base classes with user-provided classes, supporting both static strings and reactive functions:

javascript
// Static class merging
-_button({ class: 'btn-primary' }, 'Click me')
-// Result: class="btn btn-primary"
-
-// Reactive classes
-const $theme = $('btn-primary');
-_button({ class: () => $theme() }, 'Dynamic Button')
-// Updates when $theme changes

Form Components

_input - Smart Input Field

A complete input wrapper with label, tooltip, error handling, and two-way binding.

Properties:

PropertyTypeDescription
labelstringField label text
tipstringTooltip text shown on hover of a "?" badge
$valuesignalTwo-way bound value signal
$errorsignalError message signal (shows red border + message)
typestringInput type: 'text', 'email', 'password', etc.
placeholderstringPlaceholder text
classstring|functionAdditional CSS classes

Examples:

javascript
// Basic usage
-const $email = $('');
-_input({
-  label: 'Email Address',
-  type: 'email',
-  placeholder: 'user@example.com',
-  $value: $email
-})
-
-// With validation
-const $password = $('');
-const $passwordError = $(null);
-
-_input({
-  label: 'Password',
-  type: 'password',
-  $value: $password,
-  $error: $passwordError,
-  oninput: (e) => {
-    if (e.target.value.length < 6) {
-      $passwordError('Password must be at least 6 characters');
-    } else {
-      $passwordError(null);
-    }
-  }
-})

_select - Dropdown Selector

Reactive select component with options array.

Properties:

PropertyTypeDescription
labelstringField label
optionsArray<{value: any, label: string}>Select options
$valuesignalTwo-way bound selected value

Example:

javascript
const $role = $('user');
-const roles = [
-  { value: 'admin', label: 'Administrator' },
-  { value: 'user', label: 'Standard User' },
-  { value: 'guest', label: 'Guest' }
-];
-
-_select({
-  label: 'User Role',
-  options: roles,
-  $value: $role
-})
-
-// Reactive selection
-console.log($role()); // 'user'

_checkbox - Toggle Checkbox

Styled checkbox with label support.

Properties:

PropertyTypeDescription
labelstringCheckbox label text
$valuesignalBoolean signal for checked state

Example:

javascript
const $remember = $(true);
-
-_checkbox({
-  label: 'Remember me',
-  $value: $remember
-})

_radio - Radio Button Group

Radio button with group value binding.

Properties:

PropertyTypeDescription
labelstringRadio option label
valueanyValue for this radio option
$valuesignalGroup signal holding selected value

Example:

javascript
const $paymentMethod = $('credit');
-
-['credit', 'paypal', 'crypto'].forEach(method => {
-  _radio({
-    name: 'payment',
-    label: method.toUpperCase(),
-    value: method,
-    $value: $paymentMethod
-  })
-})
-
-// Selected: $paymentMethod() === 'credit'

_range - Slider Control

Reactive range slider with optional label.

Properties:

PropertyTypeDescription
labelstringSlider label
minnumberMinimum value
maxnumberMaximum value
stepnumberStep increment
$valuesignalCurrent value signal

Example:

javascript
const $volume = $(50);
-
-_range({
-  label: 'Volume',
-  min: 0,
-  max: 100,
-  step: 1,
-  $value: $volume
-})
-
-// Display current value
-span(() => `Volume: ${$volume()}%`)

Action Components

_button - Smart Action Button

Feature-rich button with loading states, icons, and badges.

Properties:

PropertyTypeDescription
$loadingsignalShows spinner + disables when true
$disabledsignalManual disabled state
iconstring|HTMLElementIcon element or emoji/unicode
badgestringBadge text to display
badgeClassstringAdditional badge styling
typestringButton type: 'button', 'submit', etc.
onclickfunctionClick handler

Examples:

javascript
// Basic button
-_button({ onclick: () => alert('Clicked!') }, 'Click Me')
-
-// Loading state
-const $saving = $(false);
-_button({
-  $loading: $saving,
-  icon: '💾',
-  onclick: async () => {
-    $saving(true);
-    await saveData();
-    $saving(false);
-  }
-}, 'Save Changes')
-
-// With badge notification
-_button({
-  badge: '3',
-  badgeClass: 'badge-secondary',
-  icon: '🔔'
-}, 'Notifications')

Layout Components

_fieldset - Form Section Group

Groups related form fields with a legend.

Properties:

PropertyTypeDescription
legendstringFieldset title
classstring|functionAdditional classes

Example:

javascript
_fieldset({ legend: 'Personal Information' }, [
-  _input({ label: 'First Name', $value: $firstName }),
-  _input({ label: 'Last Name', $value: $lastName }),
-  _input({ label: 'Email', type: 'email', $value: $email })
-])

_accordion - Collapsible Section

Expandable/collapsible content panel.

Properties:

PropertyTypeDescription
titlestringAccordion header text
namestringOptional group name (radio behavior)
openbooleanInitially open state

Examples:

javascript
// Single accordion (checkbox behavior)
-_accordion({ title: 'Frequently Asked Questions' }, [
-  p('This is the collapsible content...')
-])
-
-// Grouped accordions (radio behavior - only one open)
-_accordion({ title: 'Section 1', name: 'faq' }, [
-  p('Content for section 1')
-]),
-_accordion({ title: 'Section 2', name: 'faq' }, [
-  p('Content for section 2')
-])

_drawer - Sidebar Drawer

Responsive drawer component that can be toggled programmatically.

Properties:

PropertyTypeDescription
idstringUnique ID for checkbox toggle
$opensignalBoolean signal for drawer state
contentHTMLElementMain content area
sideHTMLElementSidebar content

Example:

javascript
const $drawerOpen = $(false);
-
-_drawer({
-  id: 'main-drawer',
-  $open: $drawerOpen,
-  content: [
-    _button({ onclick: () => $drawerOpen(true) }, 'Open Menu'),
-    div('Main content goes here')
-  ],
-  side: [
-    _menu({ items: [
-      { label: 'Home', onclick: () => $drawerOpen(false) },
-      { label: 'Settings', onclick: () => $drawerOpen(false) }
-    ]})
-  ]
-})

Responsive navigation bar with built-in styling.

Properties:

PropertyTypeDescription
classstring|functionAdditional classes

Example:

javascript
_navbar([
-  div({ class: 'flex-1' }, [
-    a({ class: 'text-xl font-bold' }, 'MyApp')
-  ]),
-  div({ class: 'flex-none' }, [
-    _button({ class: 'btn-ghost btn-sm' }, 'Login'),
-    _button({ class: 'btn-primary btn-sm' }, 'Sign Up')
-  ])
-])

Sidebar or dropdown menu with active state support.

Properties:

PropertyTypeDescription
itemsArray<{label: string, icon?: any, active?: boolean|function, onclick: function}>Menu items

Example:

javascript
const $currentPage = $('home');
-
-_menu({ items: [
-  { 
-    label: 'Dashboard', 
-    icon: '📊',
-    active: () => $currentPage() === 'dashboard',
-    onclick: () => $currentPage('dashboard')
-  },
-  { 
-    label: 'Profile', 
-    icon: '👤',
-    active: () => $currentPage() === 'profile',
-    onclick: () => $currentPage('profile')
-  },
-  { 
-    label: 'Settings', 
-    icon: '⚙️',
-    active: () => $currentPage() === 'settings',
-    onclick: () => $currentPage('settings')
-  }
-]})

_tabs - Tab Navigation

Horizontal tabs with lifted styling.

Properties:

PropertyTypeDescription
itemsArray<{label: string, active: boolean|function, onclick: function}>Tab items

Example:

javascript
const $activeTab = $('profile');
-
-_tabs({ items: [
-  { 
-    label: 'Profile', 
-    active: () => $activeTab() === 'profile',
-    onclick: () => $activeTab('profile')
-  },
-  { 
-    label: 'Settings', 
-    active: () => $activeTab() === 'settings',
-    onclick: () => $activeTab('settings')
-  }
-]})

Feedback Components

_badge - Status Indicator

Small badge for counts, statuses, or labels.

Properties:

PropertyTypeDescription
classstring|functionBadge style (badge-primary, badge-success, etc.)

Example:

javascript
_badge({ class: 'badge-success' }, 'Active')
-_badge({ class: 'badge-error' }, '3 Errors')
-_badge({ class: 'badge-warning' }, 'Pending')

_tooltip - Hover Information

Wrapper that shows tooltip text on hover.

Properties:

PropertyTypeDescription
tipstringTooltip text
positionstringTooltip position (top, bottom, left, right)

Example:

javascript
_tooltip({ tip: 'Click to save changes', class: 'tooltip-primary' }, [
-  _button({}, 'Save')
-])
-
-_tooltip({ tip: 'Your email will not be shared', class: 'tooltip-bottom' }, [
-  span('ⓘ')
-])

Container Components

Programmatically controlled modal dialog.

Properties:

PropertyTypeDescription
$opensignalBoolean signal controlling visibility
titlestringModal title
classstring|functionAdditional styling

Example:

javascript
const $showModal = $(false);
-
-_modal({ 
-  $open: $showModal, 
-  title: 'Confirm Action' 
-}, [
-  p('Are you sure you want to delete this item?'),
-  div({ class: 'flex gap-2 justify-end mt-4' }, [
-    _button({ onclick: () => $showModal(false) }, 'Cancel'),
-    _button({ 
-      class: 'btn-error',
-      onclick: () => {
-        deleteItem();
-        $showModal(false);
-      }
-    }, 'Delete')
-  ])
-])
-
-// Trigger modal
-_button({ onclick: () => $showModal(true) }, 'Delete Item')

Dropdown menu that appears on click.

Properties:

PropertyTypeDescription
labelstringDropdown trigger text
classstring|functionAdditional classes

Example:

javascript
_dropdown({ label: 'Options' }, [
-  li([a({ onclick: () => edit() }, 'Edit')]),
-  li([a({ onclick: () => duplicate() }, 'Duplicate')]),
-  li([a({ class: 'text-error', onclick: () => delete() }, 'Delete')])
-])

Complete Examples

Example 1: User Registration Form

javascript
// Signals
-const $username = $('');
-const $email = $('');
-const $password = $('');
-const $terms = $(false);
-const $loading = $(false);
-
-// Validation signals
-const $usernameError = $(null);
-const $emailError = $(null);
-const $passwordError = $(null);
-
-// Form submission
-const handleSubmit = async () => {
-  $loading(true);
-  
-  // Validate
-  if ($username().length < 3) $usernameError('Username too short');
-  if (!$email().includes('@')) $emailError('Invalid email');
-  if ($password().length < 6) $passwordError('Password too short');
-  if (!$terms()) alert('Accept terms');
-  
-  if (!$usernameError() && !$emailError() && !$passwordError()) {
-    await api.register({
-      username: $username(),
-      email: $email(),
-      password: $password()
-    });
-  }
-  
-  $loading(false);
-};
-
-// Component
-div({ class: 'max-w-md mx-auto p-6' }, [
-  _fieldset({ legend: 'Create Account' }, [
-    _input({
-      label: 'Username',
-      $value: $username,
-      $error: $usernameError,
-      placeholder: 'johndoe'
-    }),
-    _input({
-      label: 'Email',
-      type: 'email',
-      $value: $email,
-      $error: $emailError,
-      placeholder: 'john@example.com'
-    }),
-    _input({
-      label: 'Password',
-      type: 'password',
-      $value: $password,
-      $error: $passwordError
-    }),
-    _checkbox({
-      label: 'I agree to the Terms of Service',
-      $value: $terms
-    }),
-    _button({
-      $loading: $loading,
-      class: 'btn-primary w-full mt-4',
-      onclick: handleSubmit
-    }, 'Sign Up')
-  ])
-])

Example 2: Dashboard with Router Integration

javascript
// App.js
-export default () => {
-  const $activeRoute = $('dashboard');
-  
-  return div({ class: 'min-h-screen' }, [
-    _navbar([
-      div({ class: 'flex-1' }, [
-        a({ class: 'text-xl font-bold' }, 'Dashboard')
-      ]),
-      _button({ 
-        class: 'btn-ghost btn-circle',
-        onclick: () => $.router.go('/settings')
-      }, '⚙️')
-    ]),
-    div({ class: 'flex' }, [
-      // Sidebar
-      div({ class: 'w-64 p-4' }, [
-        _menu({ items: [
-          { 
-            label: 'Dashboard', 
-            icon: '📊',
-            active: () => $activeRoute() === 'dashboard',
-            onclick: () => {
-              $activeRoute('dashboard');
-              $.router.go('/');
-            }
-          },
-          { 
-            label: 'Analytics', 
-            icon: '📈',
-            active: () => $activeRoute() === 'analytics',
-            onclick: () => {
-              $activeRoute('analytics');
-              $.router.go('/analytics');
-            }
-          },
-          { 
-            label: 'Settings', 
-            icon: '⚙️',
-            active: () => $activeRoute() === 'settings',
-            onclick: () => {
-              $activeRoute('settings');
-              $.router.go('/settings');
-            }
-          }
-        ]})
-      ]),
-      
-      // Main content
-      div({ class: 'flex-1 p-6' }, [
-        $.router([
-          { path: '/', component: () => DashboardComponent() },
-          { path: '/analytics', component: () => AnalyticsComponent() },
-          { path: '/settings', component: () => SettingsComponent() }
-        ])
-      ])
-    ])
-  ]);
-};

Example 3: E-commerce Product Card

javascript
const ProductCard = ({ product }) => {
-  const $quantity = $(1);
-  const $inCart = $(false);
-  
-  return div({ class: 'card bg-base-100 shadow-xl' }, [
-    figure([img({ src: product.image, alt: product.name })]),
-    div({ class: 'card-body' }, [
-      h2({ class: 'card-title' }, product.name),
-      p(product.description),
-      div({ class: 'flex justify-between items-center mt-4' }, [
-        span({ class: 'text-2xl font-bold' }, `$${product.price}`),
-        div({ class: 'flex gap-2' }, [
-          _range({
-            min: 1,
-            max: 10,
-            $value: $quantity,
-            class: 'w-32'
-          }),
-          _button({
-            $loading: $inCart,
-            class: 'btn-primary',
-            onclick: async () => {
-              $inCart(true);
-              await addToCart(product.id, $quantity());
-              $inCart(false);
-            }
-          }, 'Add to Cart')
-        ])
-      ])
-    ])
-  ]);
-};

Styling Guide

Theme Configuration

DaisyUI v5 supports extensive theming. Configure in tailwind.config.js or CSS:

css
/* app.css */
-@import "tailwindcss";
-@plugin "daisyui";
-
-/* Custom theme */
-[data-theme="corporate"] {
-  --color-primary: oklch(0.6 0.2 250);
-  --color-secondary: oklch(0.7 0.15 150);
-  --color-accent: oklch(0.8 0.1 50);
-  --color-neutral: oklch(0.3 0.01 260);
-  --color-base-100: oklch(0.98 0.01 260);
-  --color-info: oklch(0.65 0.2 220);
-  --color-success: oklch(0.65 0.2 140);
-  --color-warning: oklch(0.7 0.2 85);
-  --color-error: oklch(0.65 0.25 25);
-}

Component Modifiers

Each component accepts Tailwind/daisyUI classes:

javascript
// Button variants
-_button({ class: 'btn-primary' }, 'Primary')
-_button({ class: 'btn-secondary' }, 'Secondary')
-_button({ class: 'btn-accent' }, 'Accent')
-_button({ class: 'btn-outline' }, 'Outline')
-_button({ class: 'btn-ghost' }, 'Ghost')
-_button({ class: 'btn-sm' }, 'Small')
-_button({ class: 'btn-lg' }, 'Large')
-_button({ class: 'btn-block' }, 'Full Width')

Best Practices

1. Reactive Performance

Always use signals for values that change, not direct variable assignments:

javascript
// ❌ Bad
-let name = 'John';
-_input({ $value: () => name }); // Won't update
-
-// ✅ Good
-const $name = $('John');
-_input({ $value: $name });

2. Error Handling

Use $error signals with validation:

javascript
const $error = $(null);
-
-_input({
-  $error: $error,
-  onchange: (e) => {
-    if (!validate(e.target.value)) {
-      $error('Invalid input');
-    } else {
-      $error(null);
-    }
-  }
-})

3. Modal Management

Keep modals conditionally rendered based on $open:

javascript
// Modal only exists in DOM when open
-_modal({ $open: $showModal }, content)

4. Form Submissions

Combine loading states with error handling:

javascript
const $loading = $(false);
-const $error = $(null);
-
-_button({
-  $loading: $loading,
-  onclick: async () => {
-    $loading(true);
-    try {
-      await submit();
-      $error(null);
-    } catch (err) {
-      $error(err.message);
-    }
-    $loading(false);
-  }
-}, 'Submit')

5. Component Composition

Build reusable components by combining UI primitives:

javascript
const FormField = ({ label, $value, type = 'text' }) => {
-  return _fieldset({ legend: label }, [
-    _input({ type, $value, class: 'w-full' })
-  ]);
-};
-
-// Usage
-FormField({ label: 'Email', $value: $email });

API Reference

All components are globally available after plugin initialization:

ComponentFunction Signature
_button(props, children) => HTMLElement
_input(props) => HTMLElement
_select(props) => HTMLElement
_checkbox(props) => HTMLElement
_radio(props) => HTMLElement
_range(props) => HTMLElement
_fieldset(props, children) => HTMLElement
_accordion(props, children) => HTMLElement
_modal(props, children) => HTMLElement
_drawer(props) => HTMLElement
_navbar(props, children) => HTMLElement
_menu(props) => HTMLElement
_tabs(props) => HTMLElement
_badge(props, children) => HTMLElement
_tooltip(props, children) => HTMLElement
_dropdown(props, children) => HTMLElement

Troubleshooting

Styles Not Applying

Ensure Tailwind CSS is properly configured and imported before your app code:

javascript
import './app.css'; // Must be first
-import { $ } from 'sigpro';

Components Not Found

Verify plugin is loaded before using components:

javascript
$.plugin(UI).then(() => {
-  // Components are ready
-  $.mount(App);
-});

Reactive Updates Not Working

Ensure you're using signals, not primitive values:

javascript
// Wrong
-let count = 0;
-_button({}, () => count)
-
-// Correct
-const $count = $(0);
-_button({}, () => $count())
- - - - \ No newline at end of file diff --git a/docs/plugins/custom.html b/docs/plugins/custom.html index 8772e5b..8de2a78 100644 --- a/docs/plugins/custom.html +++ b/docs/plugins/custom.html @@ -13,13 +13,13 @@ - + -
Skip to content

Creating Custom Plugins

There are two main ways to expose a plugin's functionality: Static/Manual Imports (cleaner for large projects) or Global/Automatic Window Injection (easier for quick scripts and global helpers).

1. The Anatomy of a Plugin

A plugin is a standard JavaScript function. By convention, if a plugin adds a global helper or component, it should be prefixed with an underscore (_).

javascript
// plugins/my-utils.js
+    
Skip to content

Creating Custom Plugins

There are two main ways to expose a plugin's functionality: Static/Manual Imports (cleaner for large projects) or Global/Automatic Window Injection (easier for quick scripts and global helpers).

1. The Anatomy of a Plugin

A plugin is a standard JavaScript function. By convention, if a plugin adds a global helper or component, it should be prefixed with an underscore (_).

javascript
// plugins/my-utils.js
 export const MyUtils = ($) => {
   
   // 1. Attach to the SigPro instance
@@ -66,8 +66,8 @@
 $.plugin(ConfigLoader).then(() => {
   console.log("Config loaded:", $.config);
   $.mount(App);
-});

4. Best Practices for Plugin Authors

RuleDescription
PrefixingUse _ for UI components (_modal) and $. for logic ($.fetch).
IdempotencyEnsure calling $.plugin(MyPlugin) twice doesn't break the app.
EncapsulationUse the $ instance passed as an argument rather than importing it again inside the plugin.
ReactivityAlways use $(...) for internal state so the app stays reactive.

5. Installation

Custom plugins don't require extra packages, but ensure your build tool (Vite/Bun) is configured to handle the module imports.

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
- +});

4. Best Practices for Plugin Authors

RuleDescription
PrefixingUse _ for UI components (_modal) and $. for logic ($.fetch).
IdempotencyEnsure calling $.plugin(MyPlugin) twice doesn't break the app.
EncapsulationUse the $ instance passed as an argument rather than importing it again inside the plugin.
ReactivityAlways use $(...) for internal state so the app stays reactive.
+ \ No newline at end of file diff --git a/docs/plugins/quick.html b/docs/plugins/quick.html index 4f5a715..cd40972 100644 --- a/docs/plugins/quick.html +++ b/docs/plugins/quick.html @@ -13,13 +13,13 @@ - + -
Skip to content

Extending SigPro: $.plugin

The plugin system is the engine's modular backbone. It allows you to inject new functionality directly into the $ object, register custom global tags, or load external libraries seamlessly.

1. How Plugins Work

A plugin in SigPro is a function that receives the core instance. When you call $.plugin(MyPlugin), the engine hands over the $ object so the plugin can attach new methods or extend the reactive system.

Functional Plugin Example

javascript
// A plugin that adds a simple watcher to any signal
+    
Skip to content

Extending SigPro: $.plugin

The plugin system is the engine's modular backbone. It allows you to inject new functionality directly into the $ object, register custom global tags, or load external libraries seamlessly.

1. How Plugins Work

A plugin in SigPro is a function that receives the core instance. When you call $.plugin(MyPlugin), the engine hands over the $ object so the plugin can attach new methods or extend the reactive system.

Functional Plugin Example

javascript
// A plugin that adds a simple watcher to any signal
 const Logger = ($) => {
   $.watch = (target, label = "Log") => {
     $(() => console.log(`[${label}]:`, target()));
@@ -31,11 +31,11 @@
 const $count = $(0);
 $.watch($count, "Counter"); // Now available globally via $

2. Initialization Patterns (SigPro)

Thanks to the Synchronous Tag Engine, you no longer need complex import() nesting. Global tags like div(), span(), and button() are ready the moment you import the Core.

This is the standard way to build apps. It's clean, readable, and supports standard ESM imports.

javascript
// main.js
 import { $ } from 'sigpro';
-import { UI } from 'sigpro/plugins';
+import { Fetch } from 'sigpro/plugins';
 import App from './App.js'; // Static import works perfectly!
 
 // 1. Register plugins
-$.plugin(UI);
+$.plugin(Fetch);
 
 // 2. Mount your app directly
 $.mount(App, '#app');

3. Resource Plugins (External Scripts)

You can pass a URL or an Array of URLs. SigPro will inject them as <script> tags and return a Promise that resolves when the scripts are fully loaded. This is perfect for integrating heavy third-party libraries only when needed.

javascript
// Loading external libraries as plugins
@@ -45,8 +45,8 @@
 ]).then(() => {
   console.log("External resources are ready to use!");
   $.mount(DashboardApp);
-});

4. Polymorphic Loading Reference

The $.plugin method is smart; it adapts its behavior based on the input type:

Input TypeActionBehavior
FunctionExecutes fn($)Synchronous: Immediate availability.
String (URL)Injects <script src="...">Asynchronous: Returns a Promise.
ArrayProcesses each item in the listReturns a Promise if any item is a URL.

💡 Pro Tip: When to use .then()?

In SigPro, you only need .then() in two specific cases:

  1. External Assets: When loading a plugin via a URL (CDN).
  2. Strict Dependency: If your App.js requires a variable that is strictly defined inside an asynchronous external script (like window.Chart).

For everything else (UI components, Router, Local State), just call $.plugin() and continue with your code. It's that simple.


Summary Cheat Sheet

GoalCode
Local Plugin$.plugin(myPlugin)
Multiple Plugins$.plugin([UI, Router])
External Library$.plugin('https://...').then(...)
Hybrid Load$.plugin([UI, 'https://...']).then(...)
- +});

4. Polymorphic Loading Reference

The $.plugin method is smart; it adapts its behavior based on the input type:

Input TypeActionBehavior
FunctionExecutes fn($)Synchronous: Immediate availability.
String (URL)Injects <script src="...">Asynchronous: Returns a Promise.
ArrayProcesses each item in the listReturns a Promise if any item is a URL.

💡 Pro Tip: When to use .then()?

In SigPro, you only need .then() in two specific cases:

  1. External Assets: When loading a plugin via a URL (CDN).
  2. Strict Dependency: If your App.js requires a variable that is strictly defined inside an asynchronous external script (like window.Chart).

For everything else (UI components, Router, Local State), just call $.plugin() and continue with your code. It's that simple.


Summary Cheat Sheet

GoalCode
Local Plugin$.plugin(myPlugin)
Multiple Plugins$.plugin([UI, Router])
External Library$.plugin('https://...').then(...)
Hybrid Load$.plugin([UI, 'https://...']).then(...)
+ \ No newline at end of file diff --git a/docs/ui/button.html b/docs/ui/button.html index 130d561..d52657e 100644 --- a/docs/ui/button.html +++ b/docs/ui/button.html @@ -19,7 +19,7 @@ -
Skip to content

Button Component

The _button component creates reactive buttons with built-in support for loading states, icons, badges, and disabled states.

Basic Usage

javascript
_button({ onclick: () => alert('Clicked!') }, 'Click Me')

Loading State

The $loading signal automatically shows a spinner and disables the button.

javascript
const $loading = $(false)
+    
Skip to content

Button Component

The _button component creates reactive buttons with built-in support for loading states, icons, badges, and disabled states.

Basic Usage

javascript
_button({ onclick: () => alert('Clicked!') }, 'Click Me')

Loading State

The $loading signal automatically shows a spinner and disables the button.

javascript
const $loading = $(false)
 
 _button({ 
   $loading: $loading,
@@ -52,8 +52,8 @@
     $success(true)
     setTimeout(() => $success(false), 2000)
   }
-}, 'Save')

API Reference

PropTypeDescription
$loadingSignal<boolean>Shows spinner and disables button
$disabledSignal<boolean>Disables the button
iconstring | NodeIcon to display before text
badgestringBadge text to display
badgeClassstringAdditional CSS classes for badge
classstring | functionAdditional CSS classes
onclickfunctionClick event handler
typestringButton type ('button', 'submit', etc.)
- +}, 'Save')

API Reference

PropTypeDescription
$loadingSignal<boolean>Shows spinner and disables button
$disabledSignal<boolean>Disables the button
iconstring | NodeIcon to display before text
badgestringBadge text to display
badgeClassstringAdditional CSS classes for badge
classstring | functionAdditional CSS classes
onclickfunctionClick event handler
typestringButton type ('button', 'submit', etc.)
+ \ No newline at end of file diff --git a/docs/ui/form.html b/docs/ui/form.html index 73ebd62..8ef9b5a 100644 --- a/docs/ui/form.html +++ b/docs/ui/form.html @@ -19,7 +19,7 @@ -
Skip to content

Form Components

SigPro UI provides a complete set of reactive form components including select dropdowns, checkboxes, radio buttons, and range sliders.

Select Dropdown (_select)

Creates a reactive dropdown select with options.

javascript
const $role = $('user')
+    
Skip to content

Form Components

SigPro UI provides a complete set of reactive form components including select dropdowns, checkboxes, radio buttons, and range sliders.

Select Dropdown (_select)

Creates a reactive dropdown select with options.

javascript
const $role = $('user')
 
 _select({
   label: 'User Role',
@@ -46,8 +46,8 @@
   max: 100,
   step: 1,
   $value: $volume
-})

Complete Form Example

API Reference

_select

PropTypeDescription
labelstringField label
optionsArray<{value: any, label: string}>Select options
$valueSignal<any>Selected value signal

_checkbox

PropTypeDescription
labelstringCheckbox label
$valueSignal<boolean>Checked state signal

_radio

PropTypeDescription
namestringRadio group name
labelstringRadio option label
valueanyValue for this option
$valueSignal<any>Group selected value signal

_range

PropTypeDescription
labelstringSlider label
minnumberMinimum value
maxnumberMaximum value
stepnumberStep increment
$valueSignal<number>Current value signal
- +})

Complete Form Example

API Reference

_select

PropTypeDescription
labelstringField label
optionsArray<{value: any, label: string}>Select options
$valueSignal<any>Selected value signal

_checkbox

PropTypeDescription
labelstringCheckbox label
$valueSignal<boolean>Checked state signal

_radio

PropTypeDescription
namestringRadio group name
labelstringRadio option label
valueanyValue for this option
$valueSignal<any>Group selected value signal

_range

PropTypeDescription
labelstringSlider label
minnumberMinimum value
maxnumberMaximum value
stepnumberStep increment
$valueSignal<number>Current value signal
+ \ No newline at end of file diff --git a/docs/ui/input.html b/docs/ui/input.html index 8adac5a..6dd2a16 100644 --- a/docs/ui/input.html +++ b/docs/ui/input.html @@ -19,7 +19,7 @@ -
Skip to content

Input Component

The _input component creates reactive form inputs with built-in support for labels, tooltips, error messages, and two-way binding.

Basic Usage

javascript
const $name = $('')
+    
Skip to content

Input Component

The _input component creates reactive form inputs with built-in support for labels, tooltips, error messages, and two-way binding.

Basic Usage

javascript
const $name = $('')
 
 _input({
   label: 'Name',
@@ -78,8 +78,8 @@
   $value: $email,
   $error: $emailError,
   oninput: (e) => validateEmail(e.target.value)
-})
- +})
+ \ No newline at end of file diff --git a/docs/ui/installation.html b/docs/ui/installation.html index b94bd26..1260cf3 100644 --- a/docs/ui/installation.html +++ b/docs/ui/installation.html @@ -19,7 +19,7 @@ -
Skip to content

Installation

Prerequisites

  • Node.js 18 or higher
  • A project with SigPro already installed

Step 1: Install Dependencies

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next

Step 2: Configure Tailwind CSS v4

Create a CSS file (e.g., src/app.css):

css
@import "tailwindcss";
+    
Skip to content

Installation

Prerequisites

  • Node.js 18 or higher
  • A project with SigPro already installed

Step 1: Install Dependencies

bash
npm install -D tailwindcss @tailwindcss/vite daisyui@next

Step 2: Configure Tailwind CSS v4

Create a CSS file (e.g., src/app.css):

css
@import "tailwindcss";
 @plugin "daisyui";

Step 3: Import CSS in Your Entry Point

javascript
// main.js
 import './app.css';
 import { $ } from 'sigpro';
@@ -28,8 +28,8 @@
 $.plugin(UI).then(() => {
   console.log('✅ UI Components ready');
   import('./App.js').then(app => $.mount(app.default));
-});

Step 4: Verify Installation

Troubleshooting

Styles not applying?

  • Make sure app.css is imported before any other code
  • Check that Tailwind is properly configured in your build tool

Components not found?

  • Ensure $.plugin(UI) has completed before using components
  • Check browser console for any loading errors

Reactive updates not working?

  • Make sure you're passing signals, not primitive values
  • Use $value prop for two-way binding
- +});

Step 4: Verify Installation

Troubleshooting

Styles not applying?

  • Make sure app.css is imported before any other code
  • Check that Tailwind is properly configured in your build tool

Components not found?

  • Ensure $.plugin(UI) has completed before using components
  • Check browser console for any loading errors

Reactive updates not working?

  • Make sure you're passing signals, not primitive values
  • Use $value prop for two-way binding
+ \ No newline at end of file diff --git a/docs/ui/introduction.html b/docs/ui/introduction.html index d0d0205..6882c85 100644 --- a/docs/ui/introduction.html +++ b/docs/ui/introduction.html @@ -19,8 +19,8 @@ -
Skip to content

UI Components

The SigPro UI plugin is a high-level component library built on top of the reactive core. It leverages Tailwind CSS v4 for utility styling and daisyUI v5 for semantic, themeable components.

Features

  • 🚀 Fully Reactive: Every component automatically updates with signals
  • 🎨 Themeable: Supports all daisyUI themes out of the box
  • 📱 Responsive: Designed to work on all devices
  • 🔧 Zero Dependencies: Pure SigPro with no framework overhead

Quick Demo

What's Included

The UI plugin provides a comprehensive set of reactive components:

CategoryComponents
Actions_button
Forms_input, _select, _checkbox, _radio, _range
Layout_fieldset, _accordion, _drawer
Navigation_navbar, _menu, _tabs
Overlays_modal, _dropdown
Feedback_badge, _tooltip

Next Steps

- +
Skip to content

UI Components

The SigPro UI plugin is a high-level component library built on top of the reactive core. It leverages Tailwind CSS v4 for utility styling and daisyUI v5 for semantic, themeable components.

Features

  • 🚀 Fully Reactive: Every component automatically updates with signals
  • 🎨 Themeable: Supports all daisyUI themes out of the box
  • 📱 Responsive: Designed to work on all devices
  • 🔧 Zero Dependencies: Pure SigPro with no framework overhead

Quick Demo

What's Included

The UI plugin provides a comprehensive set of reactive components:

CategoryComponents
Actions_button
Forms_input, _select, _checkbox, _radio, _range
Layout_fieldset, _accordion, _drawer
Navigation_navbar, _menu, _tabs
Overlays_modal, _dropdown
Feedback_badge, _tooltip

Next Steps

+ \ No newline at end of file diff --git a/docs/ui/layout.html b/docs/ui/layout.html index 5b1cde6..b2272ec 100644 --- a/docs/ui/layout.html +++ b/docs/ui/layout.html @@ -19,7 +19,7 @@ -
Skip to content

Layout Components

Layout components for structuring your application with containers, sections, and collapsible panels.

Fieldset (_fieldset)

Groups related form fields with a legend.

javascript
_fieldset({ legend: 'Personal Information' }, [
+    
Skip to content

Layout Components

Layout components for structuring your application with containers, sections, and collapsible panels.

Fieldset (_fieldset)

Groups related form fields with a legend.

javascript
_fieldset({ legend: 'Personal Information' }, [
   _input({ label: 'Full Name', $value: $name }),
   _input({ label: 'Email Address', type: 'email', $value: $email }),
   _select({ label: 'Role', options: [...], $value: $role })
@@ -47,8 +47,8 @@
   _accordion({ title: 'Subsection 2' }, [
     _input({ label: 'Field 2', $value: $field2 })
   ])
-])
- +])
+ \ No newline at end of file diff --git a/docs/ui/modal.html b/docs/ui/modal.html index 1f14255..009db05 100644 --- a/docs/ui/modal.html +++ b/docs/ui/modal.html @@ -19,7 +19,7 @@ -
Skip to content

Modal & Drawer Components

Overlay components for dialogs, side panels, and popups with reactive control.

A dialog component that appears on top of the page. The modal is completely removed from the DOM when closed, optimizing performance.

Basic Modal

javascript
const $open = $(false)
+    
Skip to content

Modal & Drawer Components

Overlay components for dialogs, side panels, and popups with reactive control.

A dialog component that appears on top of the page. The modal is completely removed from the DOM when closed, optimizing performance.

Basic Modal

javascript
const $open = $(false)
 
 _button({ onclick: () => $open(true) }, 'Open Modal')
 
@@ -47,8 +47,8 @@
       $.html('li', {}, [$.html('a', { onclick: () => $open(false) }, 'Close')])
     ])
   ])
-})

Drawer with Navigation Menu

API Reference

PropTypeDescription
$openSignal<boolean>Controls modal visibility
titlestringModal title text

_drawer

PropTypeDescription
idstringUnique identifier for the drawer
$openSignal<boolean>Controls drawer visibility
contentHTMLElementMain content area
sideHTMLElementSidebar content
- +})

Drawer with Navigation Menu

API Reference

PropTypeDescription
$openSignal<boolean>Controls modal visibility
titlestringModal title text

_drawer

PropTypeDescription
idstringUnique identifier for the drawer
$openSignal<boolean>Controls drawer visibility
contentHTMLElementMain content area
sideHTMLElementSidebar content
+ \ No newline at end of file diff --git a/docs/ui/navigation.html b/docs/ui/navigation.html index 807bbdc..afd9cbb 100644 --- a/docs/ui/navigation.html +++ b/docs/ui/navigation.html @@ -19,7 +19,7 @@ -
Skip to content

Navigation Components

Navigation components for building menus, navbars, and tabs with reactive active states.

A responsive navigation bar with built-in styling.

javascript
const $active = $('Home')
+    
Skip to content

Navigation Components

Navigation components for building menus, navbars, and tabs with reactive active states.

A responsive navigation bar with built-in styling.

javascript
const $active = $('Home')
 
 _navbar({ class: 'shadow-md' }, [
   div({ class: 'flex-1' }, [
@@ -69,8 +69,8 @@
   li([a({ onclick: () => $selected('Edit') }, '✏️ Edit')]),
   li([a({ onclick: () => $selected('Duplicate') }, '📋 Duplicate')]),
   li([a({ onclick: () => $selected('Delete') }, '🗑️ Delete')])
-])

Complete Navigation Example

API Reference

PropTypeDescription
classstring | functionAdditional CSS classes
PropTypeDescription
itemsArray<{label: string, icon?: any, active?: boolean|function, onclick: function}>Menu items

_tabs

PropTypeDescription
itemsArray<{label: string, active: boolean|function, onclick: function}>Tab items
PropTypeDescription
labelstringDropdown trigger text
classstring | functionAdditional CSS classes
- +])

Complete Navigation Example

API Reference

PropTypeDescription
classstring | functionAdditional CSS classes
PropTypeDescription
itemsArray<{label: string, icon?: any, active?: boolean|function, onclick: function}>Menu items

_tabs

PropTypeDescription
itemsArray<{label: string, active: boolean|function, onclick: function}>Tab items
PropTypeDescription
labelstringDropdown trigger text
classstring | functionAdditional CSS classes
+ \ No newline at end of file diff --git a/docs/vite/plugin.html b/docs/vite/plugin.html index 3522ae8..7b0b036 100644 --- a/docs/vite/plugin.html +++ b/docs/vite/plugin.html @@ -13,13 +13,13 @@ - + -
Skip to content

Vite Plugin: File-based Routing

The sigproRouter plugin for Vite automates route generation by scanning your pages directory. It creates a virtual module that you can import directly into your code, eliminating the need to maintain a manual routes array.

1. Project Structure

To use the plugin, organize your files within the src/pages directory. The folder hierarchy directly determines your application's URL structure. SigPro uses brackets [param] for dynamic segments.

text
my-sigpro-app/
+    
Skip to content

Vite Plugin: File-based Routing

The sigproRouter plugin for Vite automates route generation by scanning your pages directory. It creates a virtual module that you can import directly into your code, eliminating the need to maintain a manual routes array.

1. Project Structure

To use the plugin, organize your files within the src/pages directory. The folder hierarchy directly determines your application's URL structure. SigPro uses brackets [param] for dynamic segments.

text
my-sigpro-app/
 ├── src/
 │   ├── pages/
 │   │   ├── index.js          →  #/
@@ -67,8 +67,8 @@
   { path: '/', component: () => import('/src/pages/index.js') },
   { path: '/users/:id', component: () => import('/src/pages/users/[id].js') },
   // ...
-];

Because it uses dynamic import(), Vite automatically performs Code Splitting, meaning each page is its own small JS file that only loads when the user navigates to it.


6. Installation

bash
npm install sigpro
bash
pnpm add sigpro
bash
yarn add sigpro
bash
bun add sigpro
- +];

Because it uses dynamic import(), Vite automatically performs Code Splitting, meaning each page is its own small JS file that only loads when the user navigates to it.

+ \ No newline at end of file diff --git a/sigpro/sigpro.js b/sigpro/sigpro.js index 742c92d..4be774f 100644 --- a/sigpro/sigpro.js +++ b/sigpro/sigpro.js @@ -9,15 +9,23 @@ /** @type {Function|null} Internal tracker for the currently executing reactive effect. */ let activeEffect = null; - /** - * Creates a reactive Signal or Computed value - * @param {any|Function} initial - Initial value or computed function +/** + * Creates a reactive Signal, Computed value, or Store (Object of signals) + * @param {any|Function|Object} initial - Initial value, computed function, or state object * @param {string} [key] - Optional localStorage key for persistence - * @returns {Function} Reactive accessor/mutator function + * @returns {Function|Object} Reactive accessor/mutator or Store object */ const $ = (initial, key) => { const subs = new Set(); + if (typeof initial === 'object' && initial !== null && !Array.isArray(initial) && typeof initial !== 'function' && !(initial instanceof Node)) { + const store = {}; + for (let k in initial) { + store[k] = $(initial[k], key ? `${key}_${k}` : null); + } + return store; + } + if (typeof initial === 'function') { let cached; const runner = () => { diff --git a/src/docs/.vitepress/config.js b/src/docs/.vitepress/config.js index 0a4e182..443cb5e 100644 --- a/src/docs/.vitepress/config.js +++ b/src/docs/.vitepress/config.js @@ -7,8 +7,7 @@ export default defineConfig({ description: "Minimalist Reactive Library", outDir: '../../docs', base: isDev ? '/absproxy/5174/sigpro/' : '/sigpro/', - - // AÑADIDO: Head para estilos + head: [ ['link', { rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/daisyui@5/dist/full.css' }] ], @@ -26,18 +25,15 @@ export default defineConfig({ logo: '/logo.svg', nav: [ { text: 'Home', link: '/' }, - { text: 'Guide', link: '/guide/getting-started' }, + { text: 'Install', link: '/install' }, { text: 'Api', link: '/api/quick' }, - // AÑADIDO: UI en nav - { text: 'UI', link: '/ui/introduction' }, ], sidebar: [ { text: 'Introduction', items: [ - { text: 'What is SigPro?', link: '/' }, - { text: 'Why', link: '/guide/why' }, - { text: 'Guide', link: '/guide/getting-started' }, + { text: 'Installation', link: '/install' }, + { text: 'Vite Plugin', link: '/vite/plugin' }, ] }, { @@ -55,28 +51,13 @@ export default defineConfig({ text: 'Plugins', items: [ { text: 'Quick Start', link: '/plugins/quick' }, - { text: '@core UI Plugin', link: '/plugins/core.ui' }, - { text: '@core Debug', link: '/plugins/core.debug' }, { text: 'Custom', link: '/plugins/custom' }, ] }, { - text: 'Vite Router Plugin', + text: 'Examples', items: [ - { text: 'Vite Plugin', link: '/vite/plugin' }, - ] - }, - { - text: 'UI Components', - items: [ - { text: 'Introduction', link: '/ui/introduction' }, - { text: 'Installation', link: '/ui/installation' }, - { text: 'Button', link: '/ui/button' }, - { text: 'Input', link: '/ui/input' }, - { text: 'Form Components', link: '/ui/form' }, - { text: 'Modal & Drawer', link: '/ui/modal' }, - { text: 'Navigation', link: '/ui/navigation' }, - { text: 'Layout', link: '/ui/layout' }, + { text: 'Demo Core', link: '/examples' } ] } ], diff --git a/src/docs/api/$.md b/src/docs/api/$.md index 0088bfd..1b054ef 100644 --- a/src/docs/api/$.md +++ b/src/docs/api/$.md @@ -1,102 +1,142 @@ # The Reactive Core: `$( )` -The `$` function is the heart of **SigPro**. It is a **Unified Reactive Constructor** that handles state, derivations, and automatic persistence through a single, consistent interface. - -## 1. The Constructor: `$( input, [key] )` - -Depending on the arguments you pass, SigPro creates different reactive primitives: - -| Argument | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **input** | `Value` / `Function` | **Yes** | Initial state or reactive logic. | -| **key** | `string` | No | If provided, the signal **persists** in `localStorage`. | +The `$` function is a **Unified Reactive Constructor**. It detects the type of input you provide and returns the appropriate reactive primitive. --- -## 2. Signal (State & Persistence) +## 1. Signals (Atomic State) +A **Signal** is the simplest form of reactivity. It holds a single value (string, number, boolean, null). -A **Signal** is a reactive "box" for data. SigPro now supports **Native Persistence**: if you provide a second argument (the `key`), the signal will automatically sync with `localStorage`. - -* **Standard:** `const $count = $(0);` -* **Persistent:** `const $theme = $("light", "app-theme");` (Restores value on page reload). - -### Example: +### **Option A: Standard Signal (RAM)** +Ideal for volatile state that shouldn't persist after a page refresh. ```javascript -const $user = $("Guest", "session-user"); // Automatically saved/loaded +const $count = $(0); -// Read (Getter) -console.log($user()); +// Usage: +$count(); // Getter: returns 0 +$count(10); // Setter: updates to 10 +$count(c => c + 1); // Functional update: updates to 11 +``` -// Update (Setter + Auto-save to Disk) -$user("Alice"); +### **Option B: Persistent Signal (Disk)** +By adding a `key`, SigPro links the signal to `localStorage`. +```javascript +// Syntax: $(initialValue, "storage-key") +const $theme = $("light", "app-theme"); -// Functional Update -$user(prev => prev.toUpperCase()); +// It restores the value from disk automatically on load. +// When you update it, it saves to disk instantly: +$theme("dark"); // localStorage.getItem("app-theme") is now "dark" ``` --- -## 3. Computed (Derived State) +## 2. Stores (Reactive Objects) +A **Store** is a proxy that wraps an **Object**. SigPro makes every property reactive recursively. You access and set properties as if they were individual signals. -When you pass a **function** that **returns a value**, SigPro creates a **Computed Signal**. It tracks dependencies and recalculates only when necessary. +### **Option A: Standard Store (RAM)** +```javascript +const user = $({ + name: "Alice", + profile: { bio: "Developer" } +}); -* **Syntax:** `const $derived = $(() => logic);` +// Getter: Call the property as a function +console.log(user.name()); // "Alice" + +// Setter: Pass the value to the property function +user.name("Bob"); + +// Nested updates work exactly the same: +user.profile.bio("Architect"); +``` + +### **Option B: Persistent Store (Disk)** +The most powerful way to save complex state. The **entire object tree** is serialized to JSON and kept in sync with the disk. +```javascript +const settings = $({ + volume: 50, + notifications: true +}, "user-settings"); + +// Any change in the object triggers a disk sync: +settings.volume(100); // The whole JSON is updated in localStorage +``` + +--- + +## 3. Stores (Reactive Arrays) +When you pass an **Array**, SigPro tracks changes to the list. You can use standard methods or access indexes as reactive getters. + +```javascript +const $list = $(["Item 1", "Item 2"]); + +// Get by index +console.log($list[0]()); // "Item 1" + +// Update by index +$list[0]("Updated Item"); + +// Note: For adding/removing items, use standard array methods +// which SigPro makes reactive (push, pop, splice, etc.) +``` + +--- + +## 4. Computed (Derived Logic) +A **Computed Signal** is a read-only value that depends on other signals. It is defined by passing a **function that returns a value**. -### Example: ```javascript const $price = $(100); -const $qty = $(2); +const $tax = $(0.21); -// Auto-tracks $price and $qty -const $total = $(() => $price() * $qty()); - -$qty(3); // $total updates to 300 automatically -``` - ---- - -## 4. Effects (Reactive Actions) - -An **Effect** is a function that **does not return a value**. It performs an action (side effect) whenever the signals it "touches" change. - -* **When to use:** Logging, manual DOM tweaks, or syncing with external APIs. -* **Syntax:** `$(() => { action });` - -### Example: -```javascript -const $status = $("online"); - -// Runs every time $status changes -$(() => { - console.log("System status is now:", $status()); +// This function HAS a return statement +const $total = $(() => { + return $price() * (1 + $tax()); }); + +// Usage (Read-only): +console.log($total()); // 121 + +$price(200); +console.log($total()); // 242 (Auto-updated) ``` --- -## 5. Summary Table: Usage Guide - -| Primitive | Logic Type | Persistence? | Typical Use Case | -| :--- | :--- | :--- | :--- | -| **Signal** | Mutable State | **Yes** (Optional) | `$(0, 'counter')` | -| **Computed** | Derived / Read-only | No | `$(() => $a() + $b())` | -| **Effect** | Imperative Action | No | `$(() => alert($msg()))` | - ---- - -## 💡 Pro Tip: The Power of Native Persistence - -In SigPro, you don't need external plugins for basic storage. By using the `key` parameter in a Signal, you gain: -1. **Zero Boilerplate:** No more `JSON.parse(localStorage.getItem(...))`. -2. **Instant Hydration:** The value is restored **before** the UI renders, preventing "flicker". -3. **Atomic Safety:** Data is saved to disk exactly when the signal changes, ensuring your app state is always safe. - ---- - -### Naming Convention -We use the **`$` prefix** (e.g., `$count`) for reactive functions to distinguish them from static variables at a glance: +## 5. Effects (Reactive Actions) +An **Effect** is used for side-effects. It is defined by passing a **function that does NOT return a value**. It runs once immediately and then re-runs whenever its dependencies change. ```javascript -let count = 0; // Static -const $count = $(0); // Reactive Signal +const $name = $("Alice"); + +// This function has NO return statement (Side-effect) +$(() => { + console.log("The name changed to:", $name()); + document.title = `Profile: ${$name()}`; +}); + +$name("Bob"); // Triggers the console.log and updates document.title +``` + +--- + +## 6. Summary: Input Mapping + +| If you pass... | SigPro creates a... | Access Method | +| :--- | :--- | :--- | +| **A Value** | **Signal** | `$var()` / `$var(val)` | +| **An Object** | **Store** | `obj.prop()` / `obj.prop(val)` | +| **An Array** | **Array Store** | `arr[i]()` / `arr.push()` | +| **Function (returns)** | **Computed** | `$comp()` (Read-only) | +| **Function (no return)** | **Effect** | Automatically executed | + +--- + +## 💡 Naming Convention: The `$` Prefix +To keep your code clean, always prefix your reactive variables with `$`. This tells you at a glance that you need to call it as a function to get its value. + +```javascript +const name = "Static"; // Just a string +const $name = $("Alice"); // A Reactive Signal ``` diff --git a/src/docs/api/mount.md b/src/docs/api/mount.md index bd75b08..377e7f5 100644 --- a/src/docs/api/mount.md +++ b/src/docs/api/mount.md @@ -1,4 +1,4 @@ -# Application Mounter: `$.router.mount` (Core) +# Application Mounter: `$.mount` The `$.mount` function is the entry point of your reactive world. It takes a **SigPro component** (or a plain DOM node) and injects it into the real document, bridging the gap between your logic and the browser. diff --git a/src/docs/api/quick.md b/src/docs/api/quick.md index 6984415..5274c4b 100644 --- a/src/docs/api/quick.md +++ b/src/docs/api/quick.md @@ -1,99 +1,176 @@ -# Quick API Reference ⚡ +# Quick API Reference -This is a high-level summary of the **SigPro** core API. For detailed guides and edge cases, please refer to the specific documentation for each module. +SigPro is a minimal yet powerful engine. Here is a complete overview of its capabilities. -## 1. Core Reactivity: `$( )` +## 1. Core API Summary -The `$` function is a polymorphic constructor. It creates **Signals** (state) or **Computed Effects** (logic) based on the input type. +| Function | Description | Example | +| :--- | :--- | :--- | +| **`$(val, key?)`** | Creates a Signal, Computed, or Store (with optional persistence). | `const $n = $(0)` | +| **`$.html()`** | The base engine to create reactive HTMLElements. | `$.html('div', {}, 'Hi')` | +| **`Tags`** | Global helpers (div, span, button, etc.) built on top of `$.html`. | `div("Hello SigPro")` | +| **`$.mount()`** | Mounts a component into a target element (clears target first). | `$.mount(App, '#app')` | +| **`$.router()`** | Hash-based router with dynamic params and lazy loading. | `$.router(routes)` | +| **`$.plugin()`** | Extends SigPro or loads external scripts/plugins. | `$.plugin(MyPlugin)` | -| Usage | Input Type | Returns | Description | -| :--- | :--- | :--- | :--- | -| **Signal** | `any` | `Function` | A getter/setter for reactive state. | -| **Computed** | `Function` | `Function` | A read-only signal that auto-updates when its dependencies change. | +--- -**Example:** +## 2. The Power of `$` (Reactivity) + +The `$` function adapts to whatever you pass to it: + +### **Signals & Persistent State** +Reactive values in RAM or synced with `localStorage`. ```javascript -const $count = $(0); // Signal -const $double = $(() => $count() * 2); // Computed +const $count = $(0); // Simple Signal +const $theme = $('dark', 'app-theme'); // Persistent Signal (Disk) + +$count(10); // Update value +console.log($count()); // Get value: 10 +``` + +### **Computed Signals** +Read-only signals that update automatically when their dependencies change. +```javascript +const $double = $(() => $count() * 2); +``` + +### **Reactive Stores (Objects + Disk)** +Transforms an object into a reactive tree. If a `key` is provided, the **entire structure** persists. +```javascript +// Store in RAM + Disk (Auto-syncs nested properties) +const state = $({ + user: { name: 'Natxo' }, + settings: { dark: true } +}, 'my-app-state'); + +// Accessing properties (they become signals) +state.user.name(); // Get: 'Natxo' +state.user.name('Guest'); // Set & Sync to Disk: 'my-app-state_user_name' ``` --- -## 2. Rendering Engine: `$.html` +### **3. UI Creation: Constructor vs. Direct Tags** -SigPro uses a hyperscript-style engine to create live DOM nodes. +SigPro provides the `$.html` engine for defining any element and global "Sugar Tags" for rapid development. -| Argument | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **tag** | `string` | Yes | Standard HTML tag (e.g., 'div', 'button'). | -| **props** | `Object` | No | Attributes (`id`), Events (`onclick`), or Reactive Props (`$value`). | -| **content** | `any` | No | String, Node, Array, or Reactive Function. | +::: code-group -**Example:** -```javascript -$.html('button', { onclick: () => alert('Hi!') }, 'Click Me'); +```javascript [Engine Constructor ($.html)] +// 1. DEFINE: Create a custom piece of UI +// This returns a real DOM element ready to be used. +const MyHero = $.html('section', { class: 'hero' }, [ + h1("Internal Title") +]); + +// 2. USE: Nest it inside other elements like a standard tag +const Page = () => div([ + MyHero, // We just drop the variable here + p("This paragraph is outside the Hero section.") +]); + +$.mount(Page, '#app'); ``` +```javascript [Global Helpers (Tags)] +// Use pre-defined global tags to compose layouts instantly. +// No need to define them, just call them. + +const Page = () => div({ id: 'main' }, [ + section({ class: 'hero' }, [ + h1("Direct Global Tag"), + p("Building UI without boilerplate.") + ]), + button({ onclick: () => alert('Hi!') }, "Click Me") +]); + +$.mount(Page, '#app'); +``` + +::: + --- -## 3. Global Helpers (Tag Proxies) +### **Technical Breakdown** -To keep your code clean, SigPro automatically exposes common HTML tags to the global scope. +* **`$.html(tag, props, children)`**: This is the core factory. Use it when you need to create an element dynamically or when working with **Custom Elements / Web Components**. +* **`Global Tags (div, p, etc.)`**: These are shortcut functions that SigPro injects into the `window` object. They internally call `$.html` for you, making your component code much cleaner and easier to read. -| Category | Available Tags | -| :--- | :--- | -| **Layout** | `div`, `section`, `main`, `nav`, `header`, `footer`, `span` | -| **Typography** | `h1`, `h2`, `h3`, `p`, `label`, `a`, `li`, `ul`, `ol` | -| **Forms** | `input`, `button`, `form`, `select`, `option` | -| **Media** | `img`, `video`, `audio`, `canvas` | +--- -**Example:** +### **Key Difference** +* **`$.html`**: Acts as a **constructor**. Use it when you want to "bake" a specific structure (like a Section that *always* contains an H1) into a single variable. +* **`Global Tags`**: Act as **scaffolding**. Use them to wrap different contents dynamically as you build your views. + +### **Global Tags (Standard Syntax)** +SigPro declares standard tags in the global scope so you don't have to import them. ```javascript -// No imports needed! -div([ - h1("Title"), - button("Ok") +const Card = (title, $val) => div({ class: 'card' }, [ + h2(title), + p("Reactive content below:"), + input({ + type: 'number', + $value: $val, // Automatic Two-way binding + $style: () => $val() > 10 ? 'color: red' : 'color: green' + }) ]); ``` --- -## 4. Mounting & Plugins +## 4. Mounting: `$.mount` -Methods to initialize your application and extend the engine. +The entry point of your application. It links your JavaScript logic to a specific DOM element. -| Method | Signature | Description | -| :--- | :--- | :--- | -| **`$.mount`** | `(node, target)` | Wipes the target (default: `body`) and renders the component. | -| **`$.plugin`** | `(source)` | Registers a function or loads external `.js` scripts as plugins. | +```html +
+``` -**Example:** ```javascript -$.plugin([UI, Router]); -$.mount(App, '#root'); +// In your main.js +const App = () => main([ + h1("Welcome to SigPro"), + p("Everything here is reactive.") +]); + +// Usage: $.mount(component, selectorOrElement) +$.mount(App, '#app'); ``` --- -## 5. Reactive Syntax Cheat Sheet +## 5. Navigation: `$.router` -| Feature | Syntax | Description | -| :--- | :--- | :--- | -| **Text Binding** | `p(["Value: ", $sig])` | Updates text content automatically. | -| **Attributes** | `div({ id: $sig })` | Static attribute assignment. | -| **Reactive Attr** | `div({ $class: $sig })` | Attribute updates when `$sig` changes. | -| **Two-way Binding**| `input({ $value: $sig })`| Syncs input value and signal automatically. | -| **Conditional** | `div(() => $sig() > 0 ? "Yes" : "No")` | Re-renders only the content when the condition changes. | +A robust hash-based router (`#/path`) that handles view switching automatically. + +```javascript +const routes = [ + { path: '/', component: Home }, + { path: '/user/:id', component: (params) => h1(`User ID: ${params.id}`) }, + { path: '/admin', component: () => import('./Admin.js') }, // Native Lazy Loading + { path: '*', component: () => p("404 - Not Found") } +]; + +// Initialize and mount the router +$.mount($.router(routes), '#app'); + +// Programmatic navigation +$.router.go('/user/42'); +``` --- +## 6. Plugins: `$.plugin` +Extend the engine or load external dependencies. -## Summary Table +```javascript +// 1. Function-based plugin +$.plugin(($) => { + $.myHelper = () => console.log("Plugin active!"); +}); -| Feature | SigPro Approach | Benefit | -| :--- | :--- | :--- | -| **Update Logic** | Fine-grained (Surgical) | Blazing fast updates. | -| **DOM** | Native Nodes | Zero abstraction cost. | -| **Syntax** | Pure JavaScript | No build-tool lock-in. | -| **Footprint** | Modular | Load only what you use. | \ No newline at end of file +// 2. Load external scripts +await $.plugin('https://cdn.example.com/library.js'); +``` diff --git a/src/docs/api/tags.md b/src/docs/api/tags.md index bfa2ccd..b064408 100644 --- a/src/docs/api/tags.md +++ b/src/docs/api/tags.md @@ -1,160 +1,128 @@ # Global Tag Helpers -In **SigPro**, you don't need to write `$.html('div', ...)` every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags. +In **SigPro**, you don't need to write `$.html('div', ...)` every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags upon initialization. ## 1. How it Works -When SigPro initializes, it runs a proxy loop that creates a function for every common HTML tag and attaches it to the `window` object. +SigPro iterates through an internal manifest of standard HTML tags and attaches a wrapper function for each one directly to the `window` object. This creates a native "DSL" (Domain Specific Language) that looks like a template engine but is **100% standard JavaScript**. -* **Traditional:** `$.html('button', { onclick: ... }, 'Click')` +* **Under the hood:** `$.html('button', { onclick: ... }, 'Click')` * **SigPro Style:** `button({ onclick: ... }, 'Click')` -This approach gives you a "DSL" (Domain Specific Language) that feels like HTML but is actually **pure JavaScript**. - --- -## 2. The Global Registry +## 2. The Complete Global Registry -The following tags are available globally by default: +The following tags are injected into the global scope and are ready to use as soon as SigPro loads: -| Category | Available Functions | +| Category | Available Global Functions | | :--- | :--- | -| **Layout** | `div`, `span`, `section`, `main`, `nav`, `header`, `footer`, `article`, `aside` | -| **Typography** | `h1`, `h2`, `h3`, `p`, `ul`, `ol`, `li`, `a`, `label`, `strong`, `em` | -| **Forms** | `form`, `input`, `button`, `select`, `option`, `textarea` | -| **Table** | `table`, `thead`, `tbody`, `tr`, `th`, `td` | -| **Media** | `img`, `video`, `audio`, `canvas`, `svg` | +| **Structure** | `div`, `span`, `p`, `section`, `nav`, `main`, `header`, `footer`, `article`, `aside` | +| **Typography** | `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `ul`, `ol`, `li`, `dl`, `dt`, `dd`, `strong`, `em`, `code`, `pre`, `small`, `i`, `b`, `u`, `mark` | +| **Interactive** | `button`, `a`, `label`, `br`, `hr`, `details`, `summary` | +| **Forms** | `form`, `input`, `select`, `option`, `textarea`, `fieldset`, `legend` | +| **Tables** | `table`, `thead`, `tbody`, `tr`, `th`, `td`, `tfoot`, `caption` | +| **Media & Graphics** | `img`, `canvas`, `video`, `audio`, `svg`, `path`, `iframe` | + +> "In SigPro, tags are not 'magic' strings handled by a compiler. They are **functional imitations** of HTML elements. Every time you call `div()`, you are executing a standard JavaScript function that returns a real DOM element. This gives you the speed of a specialized DSL with the transparency of pure JS." + +::: danger WARNING: GLOBAL NAMING COLLISIONS +Since **SigPro** injects these helpers directly into the `window` object, they are regular JavaScript functions. This means **they can be overwritten**. + +If you declare a variable, constant, or function with the same name as an HTML tag (e.g., `const div = ...` or `function p()`), you will **nullify or shadow** the built-in SigPro helper for that tag in your current scope. + +**Best Practice:** To avoid conflicts, always use **PascalCase** for your custom components (e.g., `UserCard`, `AppHeader`) to distinguish them from the **lowercase** global HTML helpers. +::: --- -## 3. Usage Patterns +## 3. Usage Patterns (Argument Flexibility) -The tag functions are highly flexible and accept arguments in different orders to suit your coding style. +The tag functions are "smart". They detect whether you are passing attributes, content, or both. ### A. Attributes + Content -The most common pattern. +The standard way to build complex nodes. ```javascript -div({ class: 'card' }, [ - h1("Title"), - p("Description") +div({ class: 'container', id: 'main-wrapper' }, [ + h1("Welcome"), + p("This is SigPro.") ]); ``` -### B. Content Only -If you don't need attributes, you can skip the object entirely. +### B. Content Only (The "Skipper") +If you don't need attributes, you can pass the content (string, array, or function) as the **first and only** argument. ```javascript -div([ - h1("Just Content"), - p("No attributes object needed here.") +section([ + h2("No Attributes Needed"), + button("Click Me") ]); ``` -### C. Simple Text -For elements that only contain a string. +### C. Primitive Content +For simple tags, you can just pass a string or a number. ```javascript -button("Submit"); // Equivalent to +h1("Hello World"); +span(42); ``` --- -## 4. Reactive Tags +## 4. Reactive Attributes & Content -Since these helpers are just wrappers around `$.html`, they support full reactivity out of the box. +These helpers fully support SigPro's reactivity. Attributes starting with `$` are automatically tracked. ```javascript -const $loading = $(true); +const $count = $(0); -div([ - $loading() ? span("Loading...") : h1("Data Ready!"), +div({ class: 'counter-app' }, [ + h2(["Current Count: ", $count]), // Auto-unwrapping text content + button({ - $disabled: $loading, // Reactive attribute - onclick: () => $loading(false) - }, "Stop Loading") + onclick: () => $count(c => c + 1), + $style: () => $count() > 5 ? "color: red" : "color: green" // Reactive style + }, "Increment") ]); ``` --- -## 5. Under the Hood +## 5. Technical Implementation -If you are curious about how this happens without a compiler, here is the logic inside the SigPro core: +As seen in the SigPro core, the engine registers these tags dynamically. This means **zero imports** are needed for UI creation in your component files. ```javascript -const tags = ['div', 'span', 'p', 'button', ...]; - -tags.forEach(tag => { - window[tag] = (props, content) => $.html(tag, props, content); -}); +// Internal SigPro loop +tags.forEach(t => window[t] = (p, c) => $.html(t, p, c)); ``` -Because these are attached to `window`, they are available in any file in your project as soon as SigPro is loaded, making your components look like this: - -```javascript -// No imports required for tags! -export default () => - section({ id: 'hero' }, [ - h1("Fast. Atomic. Simple."), - p("Built with SigPro.") - ]); -``` +Because they are real functions, you get full IDE autocompletion and valid JS syntax highlighting without needing special plugins like JSX. --- -## 6. Full Comparison: SigPro vs. Standard HTML +## 6. Comparison: Logic to UI -To better understand the translation, here is a complete example of a **User Card** component. Notice how **SigPro** attributes with the `$` prefix map to reactive behavior, while standard attributes remain static. +Here is how a dynamic **Task Item** component translates from SigPro logic to the final DOM structure. ::: code-group -```javascript [SigPro (JS)] -const $online = $(true); - -export const UserCard = () => ( - div({ class: 'user-card' }, [ - img({ src: 'avatar.png', alt: 'User' }), - - div({ class: 'info' }, [ - h2("John Doe"), - p({ - $class: () => $online() ? 'status-on' : 'status-off' - }, [ - "Status: ", - () => $online() ? "Online" : "Offline" - ]) - ]), - - button({ - onclick: () => $online(!$online()) - }, "Toggle Status") +```javascript [SigPro Component] +const Task = (title, $done) => ( + li({ class: 'task-item' }, [ + input({ + type: 'checkbox', + $checked: $done // Two-way reactive binding + }), + span({ + $style: () => $done() ? "text-decoration: line-through" : "" + }, title) ]) ); ``` -```html [Equivalent HTML Structure] -
- User - -
-

John Doe

-

- Status: Online -

-
- - -
+```html [Rendered HTML] +
  • + + Buy milk +
  • ``` ::: -### What is happening here? - -1. **Structure:** The hierarchy is identical. `div([...])` in JS translates directly to nested tags in HTML. -2. **Attributes:** `class` is set once. `$class` is "live"; SigPro listens to the `$online` signal and updates the class name without re-rendering the whole card. -3. **Content:** The array `[...]` in SigPro is the equivalent of the children inside an HTML tag. -4. **Reactivity:** The function `() => $online() ? ...` creates a **TextNode** in the HTML that changes its text content surgically whenever the signal toggles. - ---- - -## 💡 Best Practices - -1. **Destructuring:** If you prefer not to rely on global variables, you can destructure them from `window` or `$` (though in SigPro, using them globally is the intended "clean" way). -2. **Custom Tags:** If you need a tag that isn't in the default list (like a Web Component), you can still use the base engine: `$.html('my-custom-element', { ... })`. diff --git a/src/docs/examples.md b/src/docs/examples.md new file mode 100644 index 0000000..836fa4a --- /dev/null +++ b/src/docs/examples.md @@ -0,0 +1,55 @@ +# Live Playground + +Experience **SigPro's** fine-grained reactivity in real-time. Feel free to tweak the signal values in the editor! + + +``` + +--- + +### 2. Best Practices for Documentation + +* **Tab Selection:** You can control which tabs are active by default by changing the URL segment after `/embedded/`. + * `js,result`: Shows the logic and the output. + * `html,js,result`: Shows the base structure, the logic, and the output. +* **Height Management:** For complex Store examples, increase the `height` attribute to `500` or `600` so the code is readable without internal scrolling. +* **Responsive Width:** Keeping `width="100%"` ensures the fiddle scales correctly on tablets and mobile devices. + +--- + +### 3. Advanced: The "Fiddle" Component (Optional) +If you plan to have 10+ examples, you can create a global Vue component in VitePress. This keeps your Markdown files clean and allows you to change the theme or default height for all fiddles at once. + +**Create `.vitepress/theme/components/Fiddle.vue`:** +```vue + + + +``` + +**Usage in Markdown:** +```markdown +Check out this store example: + +``` + +--- + +### Why this is perfect for SigPro: +Because SigPro is **zero-dependency** and runs directly in the browser, your JSFiddle code will be exactly what the user copies into their own `index.html`. There is no hidden "build step" confusing the learner. diff --git a/src/docs/guide/getting-started.md b/src/docs/guide/getting-started.md deleted file mode 100644 index e026fde..0000000 --- a/src/docs/guide/getting-started.md +++ /dev/null @@ -1,76 +0,0 @@ -# Getting Started - -**SigPro** is a lightweight, atomic reactive engine designed to build modern web interfaces with zero overhead. It focuses on high performance through fine-grained reactivity. - -## 1. Installation - -You can install SigPro via your favorite package manager: - -::: code-group -```bash [npm] -npm install sigpro -```` - -```bash [pnpm] -pnpm add sigpro -``` - -```bash [yarn] -yarn add sigpro -``` -```bash [bun] -bun add sigpro -``` -::: - -## 2\. Basic Usage - -The core of SigPro is the `$` function, which creates reactive state (Signals) and computed effects. - -Create a `main.js` file and try this: - -```javascript -import { $ } from 'SigPro'; - -// 1. Create a reactive signal -const $name = $("World"); - -// 2. Define a reactive component -const App = () => div({ class: 'container' }, [ - h1(["Hello, ", $name, "!"]), - - input({ - type: 'text', - $value: $name, // Two-way binding - placeholder: 'Enter your name...' - }), - - button({ - onclick: () => $name("SigPro") - }, "Set to SigPro") -]); - -// 3. Mount the application -$.mount(App, '#app'); -``` - -## 3\. How it Works - -SigPro doesn't use a Virtual DOM. Instead, it creates real DOM nodes and binds them directly to your data: - -1. **Signals**: `$(value)` creates a getter/setter function. -2. **Reactivity**: When you pass a signal or a function to a DOM element, SigPro automatically creates a subscription. -3. **Fine-Grained Updates**: Only the specific text node or attribute linked to the signal updates when the value changes. - -## 4\. Global Tags - -By default, SigPro exports common HTML tags to the global scope (`window`) when initialized. This allows you to write clean, declarative UI without importing every single tag: - -```javascript -// Instead of $.html('div', ...), just use: -div([ - h1("Clean Syntax"), - p("No more boilerplate.") -]); -``` - diff --git a/src/docs/guide/why.md b/src/docs/guide/why.md deleted file mode 100644 index 6cd208f..0000000 --- a/src/docs/guide/why.md +++ /dev/null @@ -1,78 +0,0 @@ -# Why SigPro? - -After years of building applications with React, Vue, and Svelte—investing countless hours mastering unique mental models, proprietary syntaxes, and complex build tools—we reached a realization: the web platform has evolved, but frameworks have become layers of abstraction that often move us further away from the browser. - -**SigPro** is the answer to a simple question: **Why fight the platform when we can embrace it?** - -## The Modern Web is Ready - -SigPro bypasses the overhead of the Virtual DOM and heavy compilers by using modern browser primitives. It treats the DOM as a first-class citizen, not as a side effect of a state change. - -| Browser Primitive | What It Enables | -| :--- | :--- | -| **Closures & Proxies** | Automatic dependency tracking without heavy overhead. | -| **ES Modules** | Native modularity and lazy loading without complex bundlers. | -| **Direct DOM APIs** | Surgical updates that are faster than any reconciliation algorithm. | -| **Microtask Queues** | Batching updates efficiently to ensure 60fps performance. | - ---- - -## The SigPro Philosophy - -SigPro strips away the complexity, delivering a reactive programming model that feels like a framework but stays remarkably close to Vanilla JS: - -* **No JSX transformations** – Pure JavaScript functions. -* **No Virtual DOM** – Direct, fine-grained DOM manipulation. -* **No proprietary syntax** – If you know JS, you know SigPro. -* **Zero Build Step Required** – It can run directly in the browser via ESM. - -```javascript -// Pure, Atomic, Reactive. -const $count = $(0); - -const Counter = () => div([ - p(["Count: ", $count]), - button({ onclick: () => $count(c => c + 1) }, "Increment") -]); -``` - ---- - -## Performance Comparison - -SigPro isn't just lighter; it's architecturally faster because it skips the "diffing" phase entirely. - -| Metric | SigPro | SolidJS | Svelte | Vue | React | -| :--- | :--- | :--- | :--- | :--- | :--- | -| **Bundle Size (gzip)** | 🥇 **< 2KB** | 🥈 7KB | 🥉 16KB | 20KB | 45KB | -| **Architecture** | **Atomic** | **Atomic** | **Compiled** | **V-DOM** | **V-DOM** | -| **Initial Render** | 🥇 **Fastest** | 🥈 Fast | 🥉 Fast | Average | Slow | -| **Update Perf** | 🥇 **Surgical** | 🥇 Surgical | 🥈 Fast | 🥉 Average | Slow | -| **Dependencies** | 🥇 **0** | 🥇 0 | 🥇 0 | 🥈 2 | 🥉 5+ | -| **Build Step** | 🥇 **Optional** | 🥈 Required | 🥈 Required | 🥇 Optional | 🥈 Required | - - - ---- - -## 🔑 Core Principles - -SigPro is built on four fundamental pillars: - -### 📡 Atomic Reactivity -Automatic dependency tracking with no manual subscriptions. When a signal changes, only the **exact** text nodes or attributes that depend on it update—instantly and surgically. - -### ⚡ Surgical DOM Updates -No Virtual DOM diffing. No tree reconciliation. We don't guess what changed; we know exactly where the update needs to happen. Performance scales with your data, not the size of your component tree. - -### 🧩 Plugin-First Architecture -The core is a tiny, powerful engine. Need Routing? Fetching? Global UI? Just plug it in. This keeps your production bundles "pay-only-for-what-you-use." - -### 🔬 Predictable & Transparent -There is no "magic" hidden in a black-box compiler. What you write is what the browser executes. Debugging is straightforward because there is no framework layer between your code and the DevTools. - ---- - -> "SigPro returns the joy of web development by making the browser the hero again." - - diff --git a/src/docs/index.md b/src/docs/index.md index 4b64951..2b097ea 100644 --- a/src/docs/index.md +++ b/src/docs/index.md @@ -4,93 +4,58 @@ layout: home hero: name: SigPro text: Atomic Unified Reactive Engine - tagline: Fine-grained reactivity, built-in routing, and modular plugins. All under 2KB. + tagline: High-precision atomic reactivity. No Virtual DOM. No compiler. No dependencies. image: src: /logo.svg alt: SigPro Logo actions: - theme: brand text: Get Started - link: /guide/getting-started + link: /install - theme: alt text: View on GitHub link: https://github.com/natxocc/sigpro features: - - title: Atomic Reactivity - details: Powered by Signals. Only updates what changes. No Virtual DOM overhead, no heavy re-renders. - - title: Zero Dependencies - details: Written in pure Vanilla JS. Maximum performance with the smallest footprint possible. - - title: Modular Ecosystem - details: Official plugins for UI components, dynamic Routing, Fetch, and Storage. Load only what you need. + - title: ⚛️ Atomic Reactivity + details: Powered by fine-grained Signals. Forget about whole-component re-renders; SigPro updates only the specific text node or attribute that changed. + - title: 🚀 Zero Virtual DOM + details: By eliminating the V-DOM diffing layer, SigPro performs surgical, direct manipulations on the real DOM, removing memory and CPU overhead. + - title: 🛠️ No Compiler Required + details: Pure Vanilla JS. No Babel, no JSX, no complex build steps. Standard JavaScript that runs natively in the browser with maximum performance. + - title: 📦 Ultra-Lightweight + details: The core engine—including reactivity, DOM creation, persistence, and routing—is under 2KB. Perfect for performance-critical applications. --- -## Why SigPro? +## Redefining Modern Reactivity -SigPro isn't just another framework; it's a high-performance engine. It strips away the complexity of massive bundles and returns to the essence of the web, enhanced with reactive superpowers. +SigPro is not just another framework; it is a **high-performance engine**. While other libraries add layers of abstraction that slow down execution, SigPro returns to the essence of the web, leveraging the power of modern browser engines. -### The Core in Action +### Why SigPro? -```javascript -import { $ } from 'sigpro2'; +#### ⚡️ Surgical DOM Efficiency +Unlike React or Vue, SigPro doesn't compare element trees. When a signal changes, SigPro knows exactly which DOM node depends on it and updates it instantly. It is **reactive precision** at its finest. -// A reactive state Signal -const $count = $(0); +#### 🔌 Modular Plugin System +The core is sacred. Any extra functionality—Routing, UI Helpers, or State Persistence—is integrated through a polymorphic plugin system. Load only what your application truly needs. -// A Computed signal that updates automatically -const $double = $(() => $count() * 2); +#### 💾 Native Persistence +SigPro features first-class support for `localStorage`. Synchronizing your application state with persistent storage is as simple as providing a key when initializing your Signal. -// UI that breathes with your data -const Counter = () => div([ - h1(["Count: ", $count]), - p(["Double: ", $double]), - button({ onclick: () => $count(c => c + 1) }, "Increment") -]); - -$.mount(Counter); -``` +#### 🚦 Built-in Hash Routing +A robust routing system that supports **Native Lazy Loading** out of the box. Load your components only when the user navigates to them, keeping initial load times near zero. --- -### Key Features +### The "No-Build" Philosophy +In an ecosystem obsessed with compilers, SigPro bets on **standardization**. Write code today that will still run 10 years from now, without depending on build tools that will eventually become obsolete. -#### ⚡️ Fine-Grained Reactivity -Unlike frameworks that diff complex trees (V-DOM), SigPro binds your signals directly to real DOM text nodes and attributes. If the data changes, the node changes. Period. - -#### 🔌 Polymorphic Plugin System -Extend core capabilities in a single line. Add global UI helpers, routing, or state persistence seamlessly. -```javascript -import { UI, Router } from 'sigpro/plugins'; -$.plugin([UI, Router]); -``` - -#### 📂 File-Based Routing -With our dedicated Vite plugin, manage your routes simply by creating files in `src/pages/`. It supports native **Lazy Loading** out of the box for lightning-fast initial loads. +> "The best way to optimize code is to not have to process it at all." --- -### Quick Install +## Community & Vision +SigPro is an open-source project focused on simplicity and extreme speed. Designed for developers who love the web platform and hate unnecessary "bloatware". -::: code-group -```bash [npm] -npm install sigpro -``` -```bash [pnpm] -pnpm add sigpro -``` -```bash [yarn] -yarn add sigpro -``` -```bash [bun] -bun add sigpro -``` -::: - ---- - -## Community & Support -SigPro is an open-source project. Whether you want to contribute, report a bug, or just talk about reactivity, join us on our official repository. - -``` -Built with ❤️ by NatxoCC -``` +```text +Built with ❤️ by NatxoCC for the Modern Web. \ No newline at end of file diff --git a/src/docs/install.md b/src/docs/install.md new file mode 100644 index 0000000..8abbea3 --- /dev/null +++ b/src/docs/install.md @@ -0,0 +1,110 @@ +# Installation & Setup + +SigPro is designed to be drop-in ready. Whether you are building a complex application with a bundler or a simple reactive widget in a single HTML file, SigPro scales with your needs. + +## 1. Installation + +Choose the method that best fits your workflow: + +::: code-group + +```bash [npm] +npm install sigpro +```` + +```bash [pnpm] +pnpm add sigpro +``` + +```bash [yarn] +yarn add sigpro +``` + +```bash [bun] +bun add sigpro +``` + +```html [CDN (ESM)] + +``` + +::: + +----- + +## 2\. Quick Start Examples + +Depending on your installation method, here is how you can get SigPro running in seconds. + +::: code-group + +```javascript [Mainstream (Bundlers)] +// File: App.js +import { $ } from 'sigpro'; + +export const App = () => { + // $ is global, but we import it for better IDE intellisense + const $count = $(0); + + // Tags like div, h1, button are available globally + return div({ class: 'card' }, [ + h1(["Count is: ", $count]), + button({ onclick: () => $count(c => c + 1) }, "Increment") + ]); +}; + +// File: main.js +import { $ } from 'sigpro'; +import { App } from './App.js'; + +$.mount(App, '#app'); +``` + +```html [Classic (Direct CDN)] + + + +
    + + + + +``` + +::: + +----- + +## 3\. Global by Design + +One of SigPro's core strengths is its **Global API**. + + * **The `$` Function:** Once loaded, it attaches itself to `window.$`. While you can use `import` for better IDE support and type checking, it is accessible everywhere. + * **HTML Tags:** Common tags (`div`, `span`, `button`, etc.) are automatically registered in the global scope. This eliminates "Import Hell" and keeps your components clean and readable. + +## 4\. Why no build step? + +Because SigPro uses **native ES Modules** and standard JavaScript functions to generate the DOM, you don't actually *need* a compiler like Babel or a loader for JSX. + + * **Development:** Just save and refresh. No complex HMR issues. + * **Production:** Use any bundler (Vite, esbuild, Rollup) to tree-shake and minify your final code for maximum performance. + diff --git a/src/docs/plugins/core.debug.md b/src/docs/plugins/core.debug.md deleted file mode 100644 index 1079f04..0000000 --- a/src/docs/plugins/core.debug.md +++ /dev/null @@ -1,107 +0,0 @@ -# Development Tool: `_debug` - -The **Debug Plugin** is a lightweight reactive listener. Once attached to a signal or a computed function, it automatically monitors changes, compares values, and formats the output in the browser console. - -## 1. Core Features - -* **Reactive Tracking:** Automatically logs whenever the tracked signal updates. -* **Visual Grouping:** Uses styled console groups to keep your dev tools organized. -* **Object Inspection:** Automatically uses `console.table()` when the signal contains an object or array. -* **Efficient Comparison:** Uses `Object.is` to prevent redundant logging if the value hasn't actually changed. - ---- - -## 2. Installation - -To use `_debug`, you only need the SigPro core. Register the plugin in your `main.js`. You can conditionally load it so it only runs during development. - -```javascript -import { $ } from 'sigpro'; -import { Debug } from 'sigpro/plugins'; - -// Only load Debug in development mode -const plugins = []; -if (import.meta.env.DEV) plugins.push(Debug); - -$.plugin(plugins).then(() => { - import('./App.js').then(app => $.mount(app.default)); -}); -``` - -::: code-group -```bash [NPM] -npm install sigpro -``` - -```bash [PNPM] -pnpm add sigpro -``` - -```bash [Yarn] -yarn add sigpro -``` - -```bash [Bun] -bun add sigpro -``` -::: - ---- - -## 3. Basic Usage - -Call `_debug` anywhere in your component. It stays active in the background, watching the signal's lifecycle. - -```javascript -export default () => { - const $count = $(0); - const $user = $({ name: "Guest", role: "Viewer" }); - - // Start tracking - _debug($count, "Main Counter"); - _debug($user, "User Session"); - - return div([ - button({ onclick: () => $count(c => c + 1) }, "Increment"), - button({ onclick: () => $user({ name: "Admin", role: "Super" }) }, "Promote") - ]); -}; -``` - ---- - -## 4. Console Output Breakdown - -When a signal changes, the console displays a structured block: - -1. **Header:** A styled badge with the name (e.g., `SigPro Debug: Main Counter`). -2. **Previous Value:** The value before the update (in red). -3. **Current Value:** The new value (in green). -4. **Table View:** If the value is an object, a formatted table appears automatically. - - - ---- - -## 5. Debugging Computed Values - -You can also debug **computed functions** to see exactly when derived state is recalculated. - -```javascript -const $price = $(100); -const $tax = $(0.21); -const $total = $(() => $price() * (1 + $tax())); - -// Monitor the result of the calculation -_debug($total, "Final Invoice Total"); -``` - ---- - -## 6. Why use `_debug`? - -1. **Clean Logic:** No need to scatter `console.log` inside your reactive functions. -2. **State History:** Instantly see the "Before" and "After" of any user action. -3. **No-Noise:** It only logs when a real change occurs, keeping the console clean. -4. **Deep Inspection:** The automatic `console.table` makes debugging large API responses much faster. - diff --git a/src/docs/plugins/core.fetch.md b/src/docs/plugins/core.fetch.md deleted file mode 100644 index 999d867..0000000 --- a/src/docs/plugins/core.fetch.md +++ /dev/null @@ -1,80 +0,0 @@ -# Data Fetching: `_fetch` - -The **Fetch Plugin** provides a reactive wrapper around the native browser Fetch API. Instead of managing complex `async/await` flows within your UI, `_fetch` returns a "Reactive Tripod" (Data, Loading, and Error) that your components can listen to automatically. - -## 1. Core Concept - -When you call `_fetch`, it returns three signals immediately. Your UI declares how to react to these signals as they change from their initial state to the final response. - -* **`$data`**: Initialized as `null`. Automatically holds the JSON response on success. -* **`$loading`**: Initialized as `true`. Flips to `false` once the request settles. -* **`$error`**: Initialized as `null`. Holds the error message if the request fails. - ---- - -## 2. Installation - -Register the `Fetch` plugin in your `main.js`. By convention, we load it alongside the UI and Router to have the full SigPro ecosystem ready. - -```javascript -import { $ } from 'sigpro'; -import { Fetch } from 'sigpro/plugins'; - -$.plugin([Fetch]).then(() => { - // Now _fetch() is available globally - import('./App.js').then(app => $.mount(app.default)); -}); -``` - - ---- - -## 3. Basic Usage - -Use `_fetch` inside your component to get live updates. The UI updates surgically whenever a signal changes. - -```javascript -export default () => { - const { $data, $loading, $error } = _fetch('https://api.github.com/users/octocat'); - - return div({ class: 'p-6 flex flex-col gap-4' }, [ - h1("Profile Details"), - - // 1. Loading State (using SigPro UI button) - () => $loading() && _button({ $loading: true }, "Fetching..."), - - // 2. Error State - () => $error() && div({ class: 'alert alert-error' }, $error()), - - // 3. Success State - () => $data() && div({ class: 'card bg-base-200 p-4' }, [ - img({ src: $data().avatar_url, class: 'w-16 rounded-full' }), - h2($data().name), - p($data().bio) - ]) - ]); -}; -``` - ---- - -## 4. Advanced Configuration - -`_fetch` accepts the same `RequestInit` options as the standard `fetch()` (methods, headers, body, etc.). - -```javascript -const { $data, $loading } = _fetch('/api/v1/update', { - method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ status: 'active' }) -}); -``` - ---- - -## 5. Why use `_fetch` instead of native Fetch? - -1. **Declarative UI**: You define the "Loading", "Error", and "Success" templates once, and they swap automatically. -2. **No `useEffect` required**: Since SigPro is natively reactive, you don't need lifecycle hooks to trigger re-renders; the signals handle it. -3. **Consistency**: It follows the same `_prefix` pattern as the rest of the official plugin ecosystem. -4. **Automatic JSON Parsing**: It assumes JSON by default and handles 404/500 errors by populating the `$error` signal. diff --git a/src/docs/plugins/core.router.md b/src/docs/plugins/core.router.md deleted file mode 100644 index 3b0af56..0000000 --- a/src/docs/plugins/core.router.md +++ /dev/null @@ -1,110 +0,0 @@ -# Navigation Plugin: `Router` - -The SigPro Router handles URL changes via hashes (`#`) and maps them to components. It supports dynamic parameters (like `:id`) and asynchronous loading for heavy pages. - -## 1. Core Features - -* **Hash-based:** Works everywhere without special server configuration. -* **Lazy Loading:** Pages are only downloaded when the user visits the route. -* **Reactive:** The view updates automatically when the hash changes. -* **Dynamic Routes:** Supports paths like `/user/:id`. - ---- - -## 2. Installation - -The Router is usually included in the official plugins package. - -::: code-group -```bash [NPM] -npm install -D tailwindcss @tailwindcss/vite daisyui@next -``` - -```bash [PNPM] -pnpm add -D tailwindcss @tailwindcss/vite daisyui@next -``` - -```bash [Yarn] -yarn add -D tailwindcss @tailwindcss/vite daisyui@next -``` - -```bash [Bun] -bun add -d tailwindcss @tailwindcss/vite daisyui@next -``` -::: - ---- - -## 3. Setting Up Routes - -In your `App.js` (or a dedicated routes file), define your navigation map. - -```javascript -const routes = [ - { path: '/', component: () => h1("Home Page") }, - { - path: '/admin', - // Lazy Loading: This file is only fetched when needed - component: () => import('./pages/Admin.js') - }, - { path: '/user/:id', component: (params) => h2(`User ID: ${params.id}`) }, - { path: '*', component: () => div("404 - Page Not Found") } -]; - -export default () => div([ - _navbar({ title: "My App" }), - _router(routes) // The router is now a global tag -]); -``` - ---- - -## 4. Navigation (`_router.go`) - -To move between pages programmatically (e.g., inside an `onclick` event), use the global `_router.go` helper. - -```javascript -_button({ - onclick: () => _router.go('/admin') -}, "Go to Admin") -``` - ---- - -## 5. How it Works (Under the Hood) - -The router tracks the `window.location.hash` and uses a reactive signal to trigger a re-render of the specific area where `_router(routes)` is placed. - -1. **Match:** It filters your route array to find the best fit. -2. **Resolve:** * If it's a standard function, it executes it immediately. - * If it's a **Promise** (via `import()`), it shows a loading state and swaps the content once the module arrives. -3. **Inject:** It replaces the previous DOM node with the new page content surgically. - - - ---- - -## 6. Integration with UI Components - -Since you are using the **UI Plugin**, you can easily create active states in your navigation menus by checking the current hash. - -```javascript -// Example of a reactive sidebar menu -_menu({ - items: [ - { - label: 'Dashboard', - active: () => window.location.hash === '#/', - onclick: () => _router.go('/') - }, - { - label: 'Settings', - active: () => window.location.hash === '#/settings', - onclick: () => _router.go('/settings') - } - ] -}) -``` - - - diff --git a/src/docs/plugins/core.storage.md b/src/docs/plugins/core.storage.md deleted file mode 100644 index 1205bb4..0000000 --- a/src/docs/plugins/core.storage.md +++ /dev/null @@ -1,106 +0,0 @@ -# Persistence Tool: `_storage` - -The Storage plugin synchronizes a signal with a specific key in your browser's `localStorage`. It handles both the **initial hydration** (loading data when the app starts) and **automatic saving** whenever the signal's value changes. - -## 1. Core Concept - -When you "attach" a signal to `_storage`, two things happen: -1. **Hydration:** The plugin checks if the key already exists in `localStorage`. If it does, it parses the JSON and updates the signal immediately. -2. **Reactive Sync:** It creates a reactive watcher that stringifies and saves the signal's value to the disk every time it is updated. - ---- - -## 2. Installation - -Register the `Storage` plugin in your `main.js`. Since this is a logic-only plugin, it doesn't require any CSS or UI dependencies. - -```javascript -import { $ } from 'sigpro'; -import { Storage } from 'sigpro/plugins'; - -$.plugin(Storage).then(() => { - import('./App.js').then(app => $.mount(app.default)); -}); -``` - -::: code-group -```bash [NPM] -npm install sigpro -``` - -```bash [PNPM] -pnpm add sigpro -``` - -```bash [Yarn] -yarn add sigpro -``` - -```bash [Bun] -bun add sigpro -``` -::: - ---- - -## 3. Basic Usage - -You can wrap any signal with `_storage`. It is common practice to do this right after creating the signal. - -```javascript -export default () => { - // 1. Create a signal with a default value - const $theme = $( 'light' ); - - // 2. Persist it. If 'user_theme' exists in localStorage, - // $theme will be updated to that value instantly. - _storage($theme, 'user_theme'); - - return div({ class: () => `app-${$theme()}` }, [ - h1(`Current Theme: ${$theme()}`), - button({ - onclick: () => $theme(t => t === 'light' ? 'dark' : 'light') - }, "Toggle Theme") - ]); -}; -``` - ---- - -## 4. Complex Data (Objects & Arrays) - -Since the plugin uses `JSON.parse` and `JSON.stringify` internally, it works perfectly with complex state structures. - -```javascript -const $settings = $({ - notifications: true, - fontSize: 16 -}); - -// Automatically saves the whole object whenever any property changes -_storage($settings, 'app_settings'); -``` - ---- - -## 5. Why use `_storage`? - -1. **Zero Boilerplate:** You don't need to manually write `localStorage.getItem` or `setItem` logic inside your components. -2. **Chaining:** Because `_storage` returns the signal, you can persist it inline. -3. **Error Resilience:** It includes a built-in `try/catch` block to prevent your app from crashing if the stored JSON is corrupted. -4. **Surgical Persistence:** Only the signals you explicitly mark for storage are saved, keeping your `localStorage` clean. - - - ---- - -## 6. Pro Tip: Combining with Debug - -You can chain plugins to create a fully monitored and persistent state: - -```javascript -const $score = _storage($(0), 'high_score'); - -// Now it's saved to disk AND logged to console on every change -_debug($score, "Game Score"); -``` diff --git a/src/docs/plugins/core.ui.md b/src/docs/plugins/core.ui.md deleted file mode 100644 index c6f2505..0000000 --- a/src/docs/plugins/core.ui.md +++ /dev/null @@ -1,956 +0,0 @@ -# SigPro UI Plugin - Complete Documentation - -## Overview - -The **SigPro UI** plugin is a comprehensive, reactive component library built on SigPro's atomic reactivity system. It seamlessly integrates **Tailwind CSS v4** for utility-first styling and **daisyUI v5** for semantic, themeable components. Every component is reactive by nature, automatically responding to signal changes without manual DOM updates. - -## Table of Contents - -1. [Installation & Setup](#installation--setup) -2. [Core Concepts](#core-concepts) -3. [Form Components](#form-components) -4. [Action Components](#action-components) -5. [Layout Components](#layout-components) -6. [Navigation Components](#navigation-components) -7. [Feedback Components](#feedback-components) -8. [Container Components](#container-components) -9. [Complete Examples](#complete-examples) -10. [Styling Guide](#styling-guide) -11. [Best Practices](#best-practices) - ---- - -## Installation & Setup - -### Step 1: Install Dependencies - -```bash -npm install -D tailwindcss @tailwindcss/vite daisyui@next -``` - -### Step 2: Configure Tailwind CSS v4 - -Create `src/app.css`: - -```css -/* src/app.css */ -@import "tailwindcss"; -@plugin "daisyui"; - -/* Optional: Custom themes */ -@theme { - --color-primary: oklch(0.65 0.2 250); - --color-secondary: oklch(0.7 0.15 150); -} - -/* Dark mode support */ -@custom-variant dark (&:where(.dark, [data-theme="dark"], [data-theme="dark"] *))); -``` - -### Step 3: Initialize in Your Entry Point - -```javascript -// main.js -import './app.css'; -import { $ } from 'sigpro'; -import { UI } from 'sigpro/plugins'; - -// Load the UI plugin - makes all _components globally available -$.plugin(UI).then(() => { - // All UI components are now registered - import('./App.js').then(app => $.mount(app.default)); -}); -``` - ---- - -## Core Concepts - -### Reactive Props - -All UI components accept reactive props using the `$` prefix. When you pass a signal, the component automatically updates: - -```javascript -const $username = $('John'); -const $error = $(null); - -// Reactive input with two-way binding -_input({ - $value: $username, // Auto-updates when signal changes - $error: $error // Shows error message when signal has value -}) -``` - -### The `parseClass` Helper - -All components intelligently merge base classes with user-provided classes, supporting both static strings and reactive functions: - -```javascript -// Static class merging -_button({ class: 'btn-primary' }, 'Click me') -// Result: class="btn btn-primary" - -// Reactive classes -const $theme = $('btn-primary'); -_button({ class: () => $theme() }, 'Dynamic Button') -// Updates when $theme changes -``` - ---- - -## Form Components - -### `_input` - Smart Input Field - -A complete input wrapper with label, tooltip, error handling, and two-way binding. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Field label text | -| `tip` | `string` | Tooltip text shown on hover of a "?" badge | -| `$value` | `signal` | Two-way bound value signal | -| `$error` | `signal` | Error message signal (shows red border + message) | -| `type` | `string` | Input type: 'text', 'email', 'password', etc. | -| `placeholder` | `string` | Placeholder text | -| `class` | `string\|function` | Additional CSS classes | - -**Examples:** - -```javascript -// Basic usage -const $email = $(''); -_input({ - label: 'Email Address', - type: 'email', - placeholder: 'user@example.com', - $value: $email -}) - -// With validation -const $password = $(''); -const $passwordError = $(null); - -_input({ - label: 'Password', - type: 'password', - $value: $password, - $error: $passwordError, - oninput: (e) => { - if (e.target.value.length < 6) { - $passwordError('Password must be at least 6 characters'); - } else { - $passwordError(null); - } - } -}) -``` - -### `_select` - Dropdown Selector - -Reactive select component with options array. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Field label | -| `options` | `Array<{value: any, label: string}>` | Select options | -| `$value` | `signal` | Two-way bound selected value | - -**Example:** - -```javascript -const $role = $('user'); -const roles = [ - { value: 'admin', label: 'Administrator' }, - { value: 'user', label: 'Standard User' }, - { value: 'guest', label: 'Guest' } -]; - -_select({ - label: 'User Role', - options: roles, - $value: $role -}) - -// Reactive selection -console.log($role()); // 'user' -``` - -### `_checkbox` - Toggle Checkbox - -Styled checkbox with label support. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Checkbox label text | -| `$value` | `signal` | Boolean signal for checked state | - -**Example:** - -```javascript -const $remember = $(true); - -_checkbox({ - label: 'Remember me', - $value: $remember -}) -``` - -### `_radio` - Radio Button Group - -Radio button with group value binding. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Radio option label | -| `value` | `any` | Value for this radio option | -| `$value` | `signal` | Group signal holding selected value | - -**Example:** - -```javascript -const $paymentMethod = $('credit'); - -['credit', 'paypal', 'crypto'].forEach(method => { - _radio({ - name: 'payment', - label: method.toUpperCase(), - value: method, - $value: $paymentMethod - }) -}) - -// Selected: $paymentMethod() === 'credit' -``` - -### `_range` - Slider Control - -Reactive range slider with optional label. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Slider label | -| `min` | `number` | Minimum value | -| `max` | `number` | Maximum value | -| `step` | `number` | Step increment | -| `$value` | `signal` | Current value signal | - -**Example:** - -```javascript -const $volume = $(50); - -_range({ - label: 'Volume', - min: 0, - max: 100, - step: 1, - $value: $volume -}) - -// Display current value -span(() => `Volume: ${$volume()}%`) -``` - ---- - -## Action Components - -### `_button` - Smart Action Button - -Feature-rich button with loading states, icons, and badges. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `$loading` | `signal` | Shows spinner + disables when true | -| `$disabled` | `signal` | Manual disabled state | -| `icon` | `string\|HTMLElement` | Icon element or emoji/unicode | -| `badge` | `string` | Badge text to display | -| `badgeClass` | `string` | Additional badge styling | -| `type` | `string` | Button type: 'button', 'submit', etc. | -| `onclick` | `function` | Click handler | - -**Examples:** - -```javascript -// Basic button -_button({ onclick: () => alert('Clicked!') }, 'Click Me') - -// Loading state -const $saving = $(false); -_button({ - $loading: $saving, - icon: '💾', - onclick: async () => { - $saving(true); - await saveData(); - $saving(false); - } -}, 'Save Changes') - -// With badge notification -_button({ - badge: '3', - badgeClass: 'badge-secondary', - icon: '🔔' -}, 'Notifications') -``` - ---- - -## Layout Components - -### `_fieldset` - Form Section Group - -Groups related form fields with a legend. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `legend` | `string` | Fieldset title | -| `class` | `string\|function` | Additional classes | - -**Example:** - -```javascript -_fieldset({ legend: 'Personal Information' }, [ - _input({ label: 'First Name', $value: $firstName }), - _input({ label: 'Last Name', $value: $lastName }), - _input({ label: 'Email', type: 'email', $value: $email }) -]) -``` - -### `_accordion` - Collapsible Section - -Expandable/collapsible content panel. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `title` | `string` | Accordion header text | -| `name` | `string` | Optional group name (radio behavior) | -| `open` | `boolean` | Initially open state | - -**Examples:** - -```javascript -// Single accordion (checkbox behavior) -_accordion({ title: 'Frequently Asked Questions' }, [ - p('This is the collapsible content...') -]) - -// Grouped accordions (radio behavior - only one open) -_accordion({ title: 'Section 1', name: 'faq' }, [ - p('Content for section 1') -]), -_accordion({ title: 'Section 2', name: 'faq' }, [ - p('Content for section 2') -]) -``` - -### `_drawer` - Sidebar Drawer - -Responsive drawer component that can be toggled programmatically. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `id` | `string` | Unique ID for checkbox toggle | -| `$open` | `signal` | Boolean signal for drawer state | -| `content` | `HTMLElement` | Main content area | -| `side` | `HTMLElement` | Sidebar content | - -**Example:** - -```javascript -const $drawerOpen = $(false); - -_drawer({ - id: 'main-drawer', - $open: $drawerOpen, - content: [ - _button({ onclick: () => $drawerOpen(true) }, 'Open Menu'), - div('Main content goes here') - ], - side: [ - _menu({ items: [ - { label: 'Home', onclick: () => $drawerOpen(false) }, - { label: 'Settings', onclick: () => $drawerOpen(false) } - ]}) - ] -}) -``` - ---- - -## Navigation Components - -### `_navbar` - Application Header - -Responsive navigation bar with built-in styling. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `class` | `string\|function` | Additional classes | - -**Example:** - -```javascript -_navbar([ - div({ class: 'flex-1' }, [ - a({ class: 'text-xl font-bold' }, 'MyApp') - ]), - div({ class: 'flex-none' }, [ - _button({ class: 'btn-ghost btn-sm' }, 'Login'), - _button({ class: 'btn-primary btn-sm' }, 'Sign Up') - ]) -]) -``` - -### `_menu` - Vertical Navigation - -Sidebar or dropdown menu with active state support. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `items` | `Array<{label: string, icon?: any, active?: boolean\|function, onclick: function}>` | Menu items | - -**Example:** - -```javascript -const $currentPage = $('home'); - -_menu({ items: [ - { - label: 'Dashboard', - icon: '📊', - active: () => $currentPage() === 'dashboard', - onclick: () => $currentPage('dashboard') - }, - { - label: 'Profile', - icon: '👤', - active: () => $currentPage() === 'profile', - onclick: () => $currentPage('profile') - }, - { - label: 'Settings', - icon: '⚙️', - active: () => $currentPage() === 'settings', - onclick: () => $currentPage('settings') - } -]}) -``` - -### `_tabs` - Tab Navigation - -Horizontal tabs with lifted styling. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `items` | `Array<{label: string, active: boolean\|function, onclick: function}>` | Tab items | - -**Example:** - -```javascript -const $activeTab = $('profile'); - -_tabs({ items: [ - { - label: 'Profile', - active: () => $activeTab() === 'profile', - onclick: () => $activeTab('profile') - }, - { - label: 'Settings', - active: () => $activeTab() === 'settings', - onclick: () => $activeTab('settings') - } -]}) -``` - ---- - -## Feedback Components - -### `_badge` - Status Indicator - -Small badge for counts, statuses, or labels. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `class` | `string\|function` | Badge style (badge-primary, badge-success, etc.) | - -**Example:** - -```javascript -_badge({ class: 'badge-success' }, 'Active') -_badge({ class: 'badge-error' }, '3 Errors') -_badge({ class: 'badge-warning' }, 'Pending') -``` - -### `_tooltip` - Hover Information - -Wrapper that shows tooltip text on hover. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `tip` | `string` | Tooltip text | -| `position` | `string` | Tooltip position (top, bottom, left, right) | - -**Example:** - -```javascript -_tooltip({ tip: 'Click to save changes', class: 'tooltip-primary' }, [ - _button({}, 'Save') -]) - -_tooltip({ tip: 'Your email will not be shared', class: 'tooltip-bottom' }, [ - span('ⓘ') -]) -``` - ---- - -## Container Components - -### `_modal` - Dialog Window - -Programmatically controlled modal dialog. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `$open` | `signal` | Boolean signal controlling visibility | -| `title` | `string` | Modal title | -| `class` | `string\|function` | Additional styling | - -**Example:** - -```javascript -const $showModal = $(false); - -_modal({ - $open: $showModal, - title: 'Confirm Action' -}, [ - p('Are you sure you want to delete this item?'), - div({ class: 'flex gap-2 justify-end mt-4' }, [ - _button({ onclick: () => $showModal(false) }, 'Cancel'), - _button({ - class: 'btn-error', - onclick: () => { - deleteItem(); - $showModal(false); - } - }, 'Delete') - ]) -]) - -// Trigger modal -_button({ onclick: () => $showModal(true) }, 'Delete Item') -``` - -### `_dropdown` - Context Menu - -Dropdown menu that appears on click. - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `label` | `string` | Dropdown trigger text | -| `class` | `string\|function` | Additional classes | - -**Example:** - -```javascript -_dropdown({ label: 'Options' }, [ - li([a({ onclick: () => edit() }, 'Edit')]), - li([a({ onclick: () => duplicate() }, 'Duplicate')]), - li([a({ class: 'text-error', onclick: () => delete() }, 'Delete')]) -]) -``` - ---- - -## Complete Examples - -### Example 1: User Registration Form - -```javascript -// Signals -const $username = $(''); -const $email = $(''); -const $password = $(''); -const $terms = $(false); -const $loading = $(false); - -// Validation signals -const $usernameError = $(null); -const $emailError = $(null); -const $passwordError = $(null); - -// Form submission -const handleSubmit = async () => { - $loading(true); - - // Validate - if ($username().length < 3) $usernameError('Username too short'); - if (!$email().includes('@')) $emailError('Invalid email'); - if ($password().length < 6) $passwordError('Password too short'); - if (!$terms()) alert('Accept terms'); - - if (!$usernameError() && !$emailError() && !$passwordError()) { - await api.register({ - username: $username(), - email: $email(), - password: $password() - }); - } - - $loading(false); -}; - -// Component -div({ class: 'max-w-md mx-auto p-6' }, [ - _fieldset({ legend: 'Create Account' }, [ - _input({ - label: 'Username', - $value: $username, - $error: $usernameError, - placeholder: 'johndoe' - }), - _input({ - label: 'Email', - type: 'email', - $value: $email, - $error: $emailError, - placeholder: 'john@example.com' - }), - _input({ - label: 'Password', - type: 'password', - $value: $password, - $error: $passwordError - }), - _checkbox({ - label: 'I agree to the Terms of Service', - $value: $terms - }), - _button({ - $loading: $loading, - class: 'btn-primary w-full mt-4', - onclick: handleSubmit - }, 'Sign Up') - ]) -]) -``` - -### Example 2: Dashboard with Router Integration - -```javascript -// App.js -export default () => { - const $activeRoute = $('dashboard'); - - return div({ class: 'min-h-screen' }, [ - _navbar([ - div({ class: 'flex-1' }, [ - a({ class: 'text-xl font-bold' }, 'Dashboard') - ]), - _button({ - class: 'btn-ghost btn-circle', - onclick: () => $.router.go('/settings') - }, '⚙️') - ]), - div({ class: 'flex' }, [ - // Sidebar - div({ class: 'w-64 p-4' }, [ - _menu({ items: [ - { - label: 'Dashboard', - icon: '📊', - active: () => $activeRoute() === 'dashboard', - onclick: () => { - $activeRoute('dashboard'); - $.router.go('/'); - } - }, - { - label: 'Analytics', - icon: '📈', - active: () => $activeRoute() === 'analytics', - onclick: () => { - $activeRoute('analytics'); - $.router.go('/analytics'); - } - }, - { - label: 'Settings', - icon: '⚙️', - active: () => $activeRoute() === 'settings', - onclick: () => { - $activeRoute('settings'); - $.router.go('/settings'); - } - } - ]}) - ]), - - // Main content - div({ class: 'flex-1 p-6' }, [ - $.router([ - { path: '/', component: () => DashboardComponent() }, - { path: '/analytics', component: () => AnalyticsComponent() }, - { path: '/settings', component: () => SettingsComponent() } - ]) - ]) - ]) - ]); -}; -``` - -### Example 3: E-commerce Product Card - -```javascript -const ProductCard = ({ product }) => { - const $quantity = $(1); - const $inCart = $(false); - - return div({ class: 'card bg-base-100 shadow-xl' }, [ - figure([img({ src: product.image, alt: product.name })]), - div({ class: 'card-body' }, [ - h2({ class: 'card-title' }, product.name), - p(product.description), - div({ class: 'flex justify-between items-center mt-4' }, [ - span({ class: 'text-2xl font-bold' }, `$${product.price}`), - div({ class: 'flex gap-2' }, [ - _range({ - min: 1, - max: 10, - $value: $quantity, - class: 'w-32' - }), - _button({ - $loading: $inCart, - class: 'btn-primary', - onclick: async () => { - $inCart(true); - await addToCart(product.id, $quantity()); - $inCart(false); - } - }, 'Add to Cart') - ]) - ]) - ]) - ]); -}; -``` - ---- - -## Styling Guide - -### Theme Configuration - -DaisyUI v5 supports extensive theming. Configure in `tailwind.config.js` or CSS: - -```css -/* app.css */ -@import "tailwindcss"; -@plugin "daisyui"; - -/* Custom theme */ -[data-theme="corporate"] { - --color-primary: oklch(0.6 0.2 250); - --color-secondary: oklch(0.7 0.15 150); - --color-accent: oklch(0.8 0.1 50); - --color-neutral: oklch(0.3 0.01 260); - --color-base-100: oklch(0.98 0.01 260); - --color-info: oklch(0.65 0.2 220); - --color-success: oklch(0.65 0.2 140); - --color-warning: oklch(0.7 0.2 85); - --color-error: oklch(0.65 0.25 25); -} -``` - -### Component Modifiers - -Each component accepts Tailwind/daisyUI classes: - -```javascript -// Button variants -_button({ class: 'btn-primary' }, 'Primary') -_button({ class: 'btn-secondary' }, 'Secondary') -_button({ class: 'btn-accent' }, 'Accent') -_button({ class: 'btn-outline' }, 'Outline') -_button({ class: 'btn-ghost' }, 'Ghost') -_button({ class: 'btn-sm' }, 'Small') -_button({ class: 'btn-lg' }, 'Large') -_button({ class: 'btn-block' }, 'Full Width') -``` - ---- - -## Best Practices - -### 1. Reactive Performance -Always use signals for values that change, not direct variable assignments: - -```javascript -// ❌ Bad -let name = 'John'; -_input({ $value: () => name }); // Won't update - -// ✅ Good -const $name = $('John'); -_input({ $value: $name }); -``` - -### 2. Error Handling -Use `$error` signals with validation: - -```javascript -const $error = $(null); - -_input({ - $error: $error, - onchange: (e) => { - if (!validate(e.target.value)) { - $error('Invalid input'); - } else { - $error(null); - } - } -}) -``` - -### 3. Modal Management -Keep modals conditionally rendered based on `$open`: - -```javascript -// Modal only exists in DOM when open -_modal({ $open: $showModal }, content) -``` - -### 4. Form Submissions -Combine loading states with error handling: - -```javascript -const $loading = $(false); -const $error = $(null); - -_button({ - $loading: $loading, - onclick: async () => { - $loading(true); - try { - await submit(); - $error(null); - } catch (err) { - $error(err.message); - } - $loading(false); - } -}, 'Submit') -``` - -### 5. Component Composition -Build reusable components by combining UI primitives: - -```javascript -const FormField = ({ label, $value, type = 'text' }) => { - return _fieldset({ legend: label }, [ - _input({ type, $value, class: 'w-full' }) - ]); -}; - -// Usage -FormField({ label: 'Email', $value: $email }); -``` - ---- - -## API Reference - -All components are globally available after plugin initialization: - -| Component | Function Signature | -|-----------|-------------------| -| `_button` | `(props, children) => HTMLElement` | -| `_input` | `(props) => HTMLElement` | -| `_select` | `(props) => HTMLElement` | -| `_checkbox` | `(props) => HTMLElement` | -| `_radio` | `(props) => HTMLElement` | -| `_range` | `(props) => HTMLElement` | -| `_fieldset` | `(props, children) => HTMLElement` | -| `_accordion` | `(props, children) => HTMLElement` | -| `_modal` | `(props, children) => HTMLElement` | -| `_drawer` | `(props) => HTMLElement` | -| `_navbar` | `(props, children) => HTMLElement` | -| `_menu` | `(props) => HTMLElement` | -| `_tabs` | `(props) => HTMLElement` | -| `_badge` | `(props, children) => HTMLElement` | -| `_tooltip` | `(props, children) => HTMLElement` | -| `_dropdown` | `(props, children) => HTMLElement` | - ---- - -## Troubleshooting - -### Styles Not Applying -Ensure Tailwind CSS is properly configured and imported before your app code: - -```javascript -import './app.css'; // Must be first -import { $ } from 'sigpro'; -``` - -### Components Not Found -Verify plugin is loaded before using components: - -```javascript -$.plugin(UI).then(() => { - // Components are ready - $.mount(App); -}); -``` - -### Reactive Updates Not Working -Ensure you're using signals, not primitive values: - -```javascript -// Wrong -let count = 0; -_button({}, () => count) - -// Correct -const $count = $(0); -_button({}, () => $count()) -``` diff --git a/src/docs/plugins/custom.md b/src/docs/plugins/custom.md index f7198c2..a147ee0 100644 --- a/src/docs/plugins/custom.md +++ b/src/docs/plugins/custom.md @@ -95,29 +95,3 @@ $.plugin(ConfigLoader).then(() => { | **Encapsulation** | Use the `$` instance passed as an argument rather than importing it again inside the plugin. | | **Reactivity** | Always use `$(...)` for internal state so the app stays reactive. | - - ---- - -## 5. Installation - -Custom plugins don't require extra packages, but ensure your build tool (Vite/Bun) is configured to handle the module imports. - -::: code-group -```bash [NPM] -npm install sigpro -``` - -```bash [PNPM] -pnpm add sigpro -``` - -```bash [Yarn] -yarn add sigpro -``` - -```bash [Bun] -bun add sigpro -``` -::: - diff --git a/src/docs/plugins/quick.md b/src/docs/plugins/quick.md index 04e67b2..6909a2e 100644 --- a/src/docs/plugins/quick.md +++ b/src/docs/plugins/quick.md @@ -33,11 +33,11 @@ This is the standard way to build apps. It's clean, readable, and supports stand ```javascript // main.js import { $ } from 'sigpro'; -import { UI } from 'sigpro/plugins'; +import { Fetch } from 'sigpro/plugins'; import App from './App.js'; // Static import works perfectly! // 1. Register plugins -$.plugin(UI); +$.plugin(Fetch); // 2. Mount your app directly $.mount(App, '#app'); diff --git a/src/docs/vite/plugin.md b/src/docs/vite/plugin.md index 4c210b1..dfb96e1 100644 --- a/src/docs/vite/plugin.md +++ b/src/docs/vite/plugin.md @@ -114,24 +114,3 @@ export const routes = [ Because it uses dynamic `import()`, Vite automatically performs **Code Splitting**, meaning each page is its own small JS file that only loads when the user navigates to it. ---- - -## 6. Installation - -::: code-group -```bash [NPM] -npm install sigpro -``` - -```bash [PNPM] -pnpm add sigpro -``` - -```bash [Yarn] -yarn add sigpro -``` - -```bash [Bun] -bun add sigpro -``` -:::