From 5ab08374002c2bb598bad5832de7afd864cb9603 Mon Sep 17 00:00:00 2001 From: natxocc Date: Thu, 26 Mar 2026 14:11:32 +0100 Subject: [PATCH] Update Docs --- docs/404.html | 2 +- docs/api/html.html | 2 +- docs/api/mount.html | 2 +- docs/api/quick.html | 8 +- docs/api/router.html | 2 +- docs/api/signal.html | 2 +- docs/api/tags.html | 2 +- docs/api/watch.html | 2 +- docs/assets/api_quick.md.4axUqmd3.js | 1 - docs/assets/api_quick.md.4axUqmd3.lean.js | 1 - docs/assets/api_quick.md.CVAmBRZF.js | 1 + docs/assets/api_quick.md.CVAmBRZF.lean.js | 1 + docs/assets/examples.md.Cy97nBRw.js | 20 -- docs/assets/examples.md.Cy97nBRw.lean.js | 1 - ....md.C0utklUK.js => install.md.D5NkNmWr.js} | 4 +- ...UK.lean.js => install.md.D5NkNmWr.lean.js} | 0 docs/examples.html | 45 ---- docs/hashmap.json | 2 +- docs/index.html | 2 +- docs/install.html | 8 +- docs/sigpro.js | 223 ------------------ docs/ui/quick.html | 2 +- docs/vite/plugin.html | 2 +- src/docs/api/quick.md | 37 ++- src/docs/examples.md | 55 ----- src/docs/public/sigpro.js | 223 ------------------ 26 files changed, 47 insertions(+), 603 deletions(-) delete mode 100644 docs/assets/api_quick.md.4axUqmd3.js delete mode 100644 docs/assets/api_quick.md.4axUqmd3.lean.js create mode 100644 docs/assets/api_quick.md.CVAmBRZF.js create mode 100644 docs/assets/api_quick.md.CVAmBRZF.lean.js delete mode 100644 docs/assets/examples.md.Cy97nBRw.js delete mode 100644 docs/assets/examples.md.Cy97nBRw.lean.js rename docs/assets/{install.md.C0utklUK.js => install.md.D5NkNmWr.js} (96%) rename docs/assets/{install.md.C0utklUK.lean.js => install.md.D5NkNmWr.lean.js} (100%) delete mode 100644 docs/examples.html delete mode 100644 docs/sigpro.js delete mode 100644 src/docs/examples.md delete mode 100644 src/docs/public/sigpro.js diff --git a/docs/404.html b/docs/404.html index 5c7ad96..576b8c9 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.html b/docs/api/html.html index f77887d..5441540 100644 --- a/docs/api/html.html +++ b/docs/api/html.html @@ -43,7 +43,7 @@ // Is exactly equivalent to: $.html("div", { class: "wrapper" }, [ $.html("span", {}, "Hello") ]) - + \ No newline at end of file diff --git a/docs/api/mount.html b/docs/api/mount.html index 073ad24..f21dab9 100644 --- a/docs/api/mount.html +++ b/docs/api/mount.html @@ -35,7 +35,7 @@ // Later, to remove the toast and kill its reactivity: instance.destroy();

๐Ÿ’ก Summary Cheat Sheet โ€‹

GoalCode Pattern
Mount to body$.mount(App)
Mount to CSS Selector$.mount(App, '#root')
Mount to DOM Node$.mount(App, myElement)
Clean & Re-mountCalling $.mount again on the same target
Total Saneamientoconst app = $.mount(App); app.destroy();
- + \ No newline at end of file diff --git a/docs/api/quick.html b/docs/api/quick.html index ac980b0..080f15c 100644 --- a/docs/api/quick.html +++ b/docs/api/quick.html @@ -3,7 +3,7 @@ - โšก Quick API Reference | SigPro + โšก Quick API Reference (V2) | SigPro @@ -13,14 +13,14 @@ - + -
Skip to content

โšก Quick API Reference โ€‹

SigPro is a high-performance micro-framework that updates the Real DOM surgically. No Virtual DOM, no unnecessary re-renders.

๐ŸŸข Core Functions โ€‹

FunctionSignatureDescription
$(val, key?)(any, string?) => SignalCreates a Signal. If key is provided, it persists in localStorage.
$(fn)(function) => ComputedCreates a Computed Signal that auto-updates when its dependencies change.
$.effect(fn)(function) => stopFnRuns a side-effect that tracks signals. Returns a function to manually stop it.
$.html(tag, props, children)(string, object, any) => HTMLElementThe low-level DOM factory powering all tag constructors.
$.router(routes)(Array) => HTMLElementInitializes the hash-based router for SPAs.
$.go(path)(string) => voidProgrammatic navigation (e.g., $.go('/home')).
$.mount(comp, target)(any, string|Node) => RuntimeMounts the application into the specified DOM element.
$.ignore(fn)(function) => anyExecutes code without tracking any signals inside it.

๐Ÿ—๏ธ Element Constructors (Tags) โ€‹

SigPro provides PascalCase wrappers for all standard HTML5 tags (e.g., Div, Span, Button).

Syntax Pattern โ€‹

javascript
Tag({ attributes }, [children])

Attribute & Content Handling โ€‹

PatternCode ExampleBehavior
Staticclass: "text-red"Standard HTML attribute string.
Reactivedisabled: isLoadingUpdates automatically when isLoading() changes.
Two-way$value: usernameSyncs input with signal both ways (Binding Operator).
TextP({}, () => count())Updates text node whenever count changes.
Booleanhidden: isHiddenToggles the attribute based on signal truthiness.
- +
Skip to content

โšก Quick API Reference (V2) โ€‹

SigPro is a high-performance micro-framework that updates the Real DOM surgically. No Virtual DOM, no unnecessary re-renders, and built-in Saneamiento (memory cleanup).

๐ŸŸข Core Functions โ€‹

FunctionSignatureDescription
$(val, key?)(any, string?) => SignalCreates a Signal. If key is provided, it persists in localStorage.
$(fn)(function) => ComputedCreates a Computed Signal that auto-updates when its dependencies change.
$.watch(fn)(function) => stopFnAutomatic Mode: Tracks any signal touched inside. Returns a stop function.
$.watch(deps, fn)(Array, function) => stopFnExplicit Mode: Only runs when signals in deps change. Used for Saneamiento.
$.html(tag, props, kids)(string, obj, any) => ElementThe low-level DOM factory. Attaches ._cleanups to every element.
$.If(cond, then, else?)(Signal, fn, fn?) => NodeReactive conditional. Automatically destroys the "else" branch memory.
$.For(list, itemFn)(Signal, fn) => NodeOptimized list renderer. Manages individual item lifecycles.
$.router(routes)(Array) => ElementHash-based SPA router. Uses Explicit Watch to prevent memory leaks.
$.mount(node, target)(any, string|Node) => RuntimeEntry point. Creates a root instance with .destroy() capabilities.

๐Ÿ—๏ธ Element Constructors (Tags) โ€‹

SigPro provides PascalCase wrappers for all standard HTML5 tags (e.g., Div, Span, Button).

Syntax Pattern โ€‹

javascript
Tag({ attributes }, [children])

Attribute & Content Handling โ€‹

PatternCode ExampleBehavior
Staticclass: "text-red"Standard HTML attribute string.
Reactivedisabled: isLoadingUpdates automatically via internal $.watch.
Two-way$value: usernameBinding Operator: Syncs input $\leftrightarrow$ signal both ways.
TextP({}, () => count())Updates text node surgically without re-rendering the P.
Booleanhidden: isHiddenToggles the attribute based on signal truthiness.

๐Ÿงน Saneamiento (Memory Management) โ€‹

In SigPro V2, you rarely need to clean up manually, but the tools are there if you build custom components:

  • Automatic: Anything inside $.If, $.For, or $.router is "swept" when it disappears.
  • Manual: Use instance.destroy() for apps or $.cleanup(el) for manual DOM injections.
  • Internal: Every element carries a ._cleanups Set with its own reactive "kill-switches".
+ \ No newline at end of file diff --git a/docs/api/router.html b/docs/api/router.html index 5ff613d..9ae4239 100644 --- a/docs/api/router.html +++ b/docs/api/router.html @@ -41,7 +41,7 @@ padding: 2rem; animation: fadeIn 0.2s ease-in; } - + \ No newline at end of file diff --git a/docs/api/signal.html b/docs/api/signal.html index 7570d9a..0115ed2 100644 --- a/docs/api/signal.html +++ b/docs/api/signal.html @@ -33,7 +33,7 @@ // Adds "C" using the previous state list(prev => [...prev, "C"]); - + \ No newline at end of file diff --git a/docs/api/tags.html b/docs/api/tags.html index 6365825..d1cecda 100644 --- a/docs/api/tags.html +++ b/docs/api/tags.html @@ -55,7 +55,7 @@ }, name) ]) );
State ($online)Rendered HTMLMemory Management
true<div class="flex..."><span class="w-3..."></span><p class="text-bold">John</p></div>Watcher active
false<div class="flex..."><span hidden class="w-3..."></span><p class="text-gray-400">John</p></div>Attribute synced
- + \ No newline at end of file diff --git a/docs/api/watch.html b/docs/api/watch.html index 580c519..176a24b 100644 --- a/docs/api/watch.html +++ b/docs/api/watch.html @@ -52,7 +52,7 @@ // This triggers only ONE re-run. a(1); b(2); - + \ No newline at end of file diff --git a/docs/assets/api_quick.md.4axUqmd3.js b/docs/assets/api_quick.md.4axUqmd3.js deleted file mode 100644 index d93ab24..0000000 --- a/docs/assets/api_quick.md.4axUqmd3.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as a,c as n,ae as l}from"./chunks/framework.C8AWLET_.js";const f=JSON.parse('{"title":"โšก Quick API Reference","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),d={name:"api/quick.md"};function o(i,t,s,r,c,g){return a(),n("div",null,[...t[0]||(t[0]=[l('

โšก Quick API Reference โ€‹

SigPro is a high-performance micro-framework that updates the Real DOM surgically. No Virtual DOM, no unnecessary re-renders.

๐ŸŸข Core Functions โ€‹

FunctionSignatureDescription
$(val, key?)(any, string?) => SignalCreates a Signal. If key is provided, it persists in localStorage.
$(fn)(function) => ComputedCreates a Computed Signal that auto-updates when its dependencies change.
$.effect(fn)(function) => stopFnRuns a side-effect that tracks signals. Returns a function to manually stop it.
$.html(tag, props, children)(string, object, any) => HTMLElementThe low-level DOM factory powering all tag constructors.
$.router(routes)(Array) => HTMLElementInitializes the hash-based router for SPAs.
$.go(path)(string) => voidProgrammatic navigation (e.g., $.go('/home')).
$.mount(comp, target)(any, string|Node) => RuntimeMounts the application into the specified DOM element.
$.ignore(fn)(function) => anyExecutes code without tracking any signals inside it.

๐Ÿ—๏ธ Element Constructors (Tags) โ€‹

SigPro provides PascalCase wrappers for all standard HTML5 tags (e.g., Div, Span, Button).

Syntax Pattern โ€‹

javascript
Tag({ attributes }, [children])

Attribute & Content Handling โ€‹

PatternCode ExampleBehavior
Staticclass: "text-red"Standard HTML attribute string.
Reactivedisabled: isLoadingUpdates automatically when isLoading() changes.
Two-way$value: usernameSyncs input with signal both ways (Binding Operator).
TextP({}, () => count())Updates text node whenever count changes.
Booleanhidden: isHiddenToggles the attribute based on signal truthiness.
',11)])])}const u=e(d,[["render",o]]);export{f as __pageData,u as default}; diff --git a/docs/assets/api_quick.md.4axUqmd3.lean.js b/docs/assets/api_quick.md.4axUqmd3.lean.js deleted file mode 100644 index 3b1b7c5..0000000 --- a/docs/assets/api_quick.md.4axUqmd3.lean.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as a,c as n,ae as l}from"./chunks/framework.C8AWLET_.js";const f=JSON.parse('{"title":"โšก Quick API Reference","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),d={name:"api/quick.md"};function o(i,t,s,r,c,g){return a(),n("div",null,[...t[0]||(t[0]=[l("",11)])])}const u=e(d,[["render",o]]);export{f as __pageData,u as default}; diff --git a/docs/assets/api_quick.md.CVAmBRZF.js b/docs/assets/api_quick.md.CVAmBRZF.js new file mode 100644 index 0000000..bcf988c --- /dev/null +++ b/docs/assets/api_quick.md.CVAmBRZF.js @@ -0,0 +1 @@ +import{_ as e,o as a,c as n,ae as o}from"./chunks/framework.C8AWLET_.js";const h=JSON.parse('{"title":"โšก Quick API Reference (V2)","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),l={name:"api/quick.md"};function d(s,t,r,i,c,g){return a(),n("div",null,[...t[0]||(t[0]=[o('

โšก Quick API Reference (V2) โ€‹

SigPro is a high-performance micro-framework that updates the Real DOM surgically. No Virtual DOM, no unnecessary re-renders, and built-in Saneamiento (memory cleanup).

๐ŸŸข Core Functions โ€‹

FunctionSignatureDescription
$(val, key?)(any, string?) => SignalCreates a Signal. If key is provided, it persists in localStorage.
$(fn)(function) => ComputedCreates a Computed Signal that auto-updates when its dependencies change.
$.watch(fn)(function) => stopFnAutomatic Mode: Tracks any signal touched inside. Returns a stop function.
$.watch(deps, fn)(Array, function) => stopFnExplicit Mode: Only runs when signals in deps change. Used for Saneamiento.
$.html(tag, props, kids)(string, obj, any) => ElementThe low-level DOM factory. Attaches ._cleanups to every element.
$.If(cond, then, else?)(Signal, fn, fn?) => NodeReactive conditional. Automatically destroys the "else" branch memory.
$.For(list, itemFn)(Signal, fn) => NodeOptimized list renderer. Manages individual item lifecycles.
$.router(routes)(Array) => ElementHash-based SPA router. Uses Explicit Watch to prevent memory leaks.
$.mount(node, target)(any, string|Node) => RuntimeEntry point. Creates a root instance with .destroy() capabilities.

๐Ÿ—๏ธ Element Constructors (Tags) โ€‹

SigPro provides PascalCase wrappers for all standard HTML5 tags (e.g., Div, Span, Button).

Syntax Pattern โ€‹

javascript
Tag({ attributes }, [children])

Attribute & Content Handling โ€‹

PatternCode ExampleBehavior
Staticclass: "text-red"Standard HTML attribute string.
Reactivedisabled: isLoadingUpdates automatically via internal $.watch.
Two-way$value: usernameBinding Operator: Syncs input $\\leftrightarrow$ signal both ways.
TextP({}, () => count())Updates text node surgically without re-rendering the P.
Booleanhidden: isHiddenToggles the attribute based on signal truthiness.

๐Ÿงน Saneamiento (Memory Management) โ€‹

In SigPro V2, you rarely need to clean up manually, but the tools are there if you build custom components:

',15)])])}const y=e(l,[["render",d]]);export{h as __pageData,y as default}; diff --git a/docs/assets/api_quick.md.CVAmBRZF.lean.js b/docs/assets/api_quick.md.CVAmBRZF.lean.js new file mode 100644 index 0000000..a0ae42e --- /dev/null +++ b/docs/assets/api_quick.md.CVAmBRZF.lean.js @@ -0,0 +1 @@ +import{_ as e,o as a,c as n,ae as o}from"./chunks/framework.C8AWLET_.js";const h=JSON.parse('{"title":"โšก Quick API Reference (V2)","description":"","frontmatter":{},"headers":[],"relativePath":"api/quick.md","filePath":"api/quick.md"}'),l={name:"api/quick.md"};function d(s,t,r,i,c,g){return a(),n("div",null,[...t[0]||(t[0]=[o("",15)])])}const y=e(l,[["render",d]]);export{h as __pageData,y as default}; diff --git a/docs/assets/examples.md.Cy97nBRw.js b/docs/assets/examples.md.Cy97nBRw.js deleted file mode 100644 index 11f1135..0000000 --- a/docs/assets/examples.md.Cy97nBRw.js +++ /dev/null @@ -1,20 +0,0 @@ -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 โ€‹


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 deleted file mode 100644 index f4920ee..0000000 --- a/docs/assets/examples.md.Cy97nBRw.lean.js +++ /dev/null @@ -1 +0,0 @@ -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/install.md.C0utklUK.js b/docs/assets/install.md.D5NkNmWr.js similarity index 96% rename from docs/assets/install.md.C0utklUK.js rename to docs/assets/install.md.D5NkNmWr.js index 6e502a1..1dc949d 100644 --- a/docs/assets/install.md.C0utklUK.js +++ b/docs/assets/install.md.D5NkNmWr.js @@ -1,11 +1,11 @@ -import{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Installation & Setup","description":"","frontmatter":{},"headers":[],"relativePath":"install.md","filePath":"install.md"}'),l={name:"install.md"};function e(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

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{_ as i,o as a,c as t,ae as n}from"./chunks/framework.C8AWLET_.js";const g=JSON.parse('{"title":"Installation & Setup","description":"","frontmatter":{},"headers":[],"relativePath":"install.md","filePath":"install.md"}'),l={name:"install.md"};function e(h,s,p,k,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

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 the core and UI components
   import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
   import { UI } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/ui/+esm';
   
   // Initialize UI components globally
   UI($);
-</script>

2. Quick Start Examples โ€‹

SigPro uses PascalCase for Tag Helpers (e.g., Div, Button) to provide a clean, component-like syntax without needing JSX.

javascript
// File: App.js
+</script>

2. Quick Start Examples โ€‹

SigPro uses PascalCase for Tag Helpers (e.g., Div, Button) to provide a clean, component-like syntax without needing JSX.

javascript
// File: App.js
 import { $ } from 'sigpro'; 
 
 export const App = () => {
diff --git a/docs/assets/install.md.C0utklUK.lean.js b/docs/assets/install.md.D5NkNmWr.lean.js
similarity index 100%
rename from docs/assets/install.md.C0utklUK.lean.js
rename to docs/assets/install.md.D5NkNmWr.lean.js
diff --git a/docs/examples.html b/docs/examples.html
deleted file mode 100644
index 16424f8..0000000
--- a/docs/examples.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-  
-    
-    
-    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/hashmap.json b/docs/hashmap.json index a7acb7c..ea4463f 100644 --- a/docs/hashmap.json +++ b/docs/hashmap.json @@ -1 +1 @@ -{"api_html.md":"BPbZMZR1","api_mount.md":"BiKjH18I","api_quick.md":"4axUqmd3","api_router.md":"Cn98LjXO","api_signal.md":"BmorvARW","api_tags.md":"CW_zjfl9","api_watch.md":"D7sOEzCX","examples.md":"Cy97nBRw","index.md":"By6smViD","install.md":"C0utklUK","ui_quick.md":"CsppjR8J","vite_plugin.md":"CTs8LDIL"} +{"api_html.md":"BPbZMZR1","api_mount.md":"BiKjH18I","api_quick.md":"CVAmBRZF","api_router.md":"Cn98LjXO","api_signal.md":"BmorvARW","api_tags.md":"CW_zjfl9","api_watch.md":"D7sOEzCX","index.md":"By6smViD","install.md":"D5NkNmWr","ui_quick.md":"CsppjR8J","vite_plugin.md":"CTs8LDIL"} diff --git a/docs/index.html b/docs/index.html index 549ed1d..4f0dda8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -20,7 +20,7 @@
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 index 6452e89..e26fd68 100644 --- a/docs/install.html +++ b/docs/install.html @@ -13,20 +13,20 @@ - + -
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">
+    
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 the core and UI components
   import { $ } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/+esm';
   import { UI } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/ui/+esm';
   
   // Initialize UI components globally
   UI($);
-</script>

2. Quick Start Examples โ€‹

SigPro uses PascalCase for Tag Helpers (e.g., Div, Button) to provide a clean, component-like syntax without needing JSX.

javascript
// File: App.js
+</script>

2. Quick Start Examples โ€‹

SigPro uses PascalCase for Tag Helpers (e.g., Div, Button) to provide a clean, component-like syntax without needing JSX.

javascript
// File: App.js
 import { $ } from 'sigpro'; 
 
 export const App = () => {
@@ -71,7 +71,7 @@
   </script>
 </body>
 </html>

3. Global by Design โ€‹

One of SigPro's core strengths is its Global API, which eliminates "Import Hell".

  • The $ Function: Once loaded, it attaches itself to window.$. It handles state, effects, and DOM mounting.
  • Tag Helpers (PascalCase): Common HTML tags (Div, Span, Button, Input, etc.) are automatically registered in the global scope.
  • Custom Components: We recommend using PascalCase (e.g., UserCard) or prefixes like _Input to keep your code organized and distinguish your logic from standard tags.

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 transformer for JSX.

  • Development: Just save and refresh. Pure JS, no "transpilation" required.
  • Performance: Extremely lightweight. Use any modern bundler (Vite, esbuild) only when you are ready to minify and tree-shake for production.

5. Why SigPro? (The Competitive Edge) โ€‹

SigPro stands out by removing the "Build Step" tax and the "Virtual DOM" overhead. It is the closest you can get to writing raw HTML/JS while maintaining modern reactivity.

FeatureSigProSolidJSSvelteReactVue
Bundle Size~2KB~7KB~4KB~40KB+~30KB
DOM StrategyDirect DOMDirect DOMCompiled DOMVirtual DOMVirtual DOM
ReactivityFine-grainedFine-grainedCompiledRe-rendersProxies
Build StepOptionalRequiredRequiredRequiredOptional
Learning CurveMinimalMediumLowHighMedium
InitializationUltra-FastVery FastFastSlowMedium

6. Key Advantages โ€‹

  • Extreme Performance: No Virtual DOM reconciliation. SigPro updates the specific node or attribute instantly when a Signal changes.
  • Fine-Grained Reactivity: State changes only trigger updates where the data is actually used, not on the entire component.
  • Native Web Standards: Everything is a standard JS function. No custom template syntax to learn.
  • Zero Magic: No hidden compilers. What you write is what runs in the browser.
  • Global by Design: Tag Helpers and the $ function are available globally to eliminate "Import Hell" and keep your code clean.

7. Summary โ€‹

SigPro isn't just another framework; it's a bridge to the native web. By using standard ES Modules and functional DOM generation, you gain the benefits of a modern library with the weight of a utility script.

Because, in the end... why fight the web when we can embrace it?

- + \ No newline at end of file diff --git a/docs/sigpro.js b/docs/sigpro.js deleted file mode 100644 index 995ed40..0000000 --- a/docs/sigpro.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * SigPro - Atomic Unified Reactive Engine - * A lightweight, fine-grained reactivity system with built-in routing and plugin support. - * @author Gemini & User - */ -(() => { - /** @type {Function|null} Internal tracker for the currently executing reactive effect. */ - let activeEffect = null; - - /** - * @typedef {Object} SigPro - * @property {function(any|function, string=): Function} $ - Creates a Signal or Computed. Optional key for localStorage. - * @property {function(string, Object=, any=): HTMLElement} html - Creates a reactive HTML element. - * @property {function((HTMLElement|function), (HTMLElement|string)=): void} mount - Mounts a component to the DOM. - * @property {function(Array): HTMLElement} router - Initializes a hash-based router. - * @property {function(string): void} router.go - Programmatic navigation to a hash path. - * @property {function((function|string|Array)): (Promise|SigPro)} plugin - Extends SigPro or loads external scripts. - */ - - /** - * Creates a Signal (state) or a Computed/Effect (reaction). - * Supports optional persistence in localStorage. - * * @param {any|function} initial - Initial value or a function for computed logic. - * @param {string} [key] - Optional localStorage key for automatic state persistence. - * @returns {Function} A reactive accessor/mutator function. - */ - const $ = (initial, key) => { - const subs = new Set(); - - if (typeof initial === 'function') { - let cached; - const runner = () => { - const prev = activeEffect; - activeEffect = runner; - try { - const next = initial(); - if (!Object.is(cached, next)) { - cached = next; - subs.forEach(s => s()); - } - } finally { activeEffect = prev; } - }; - runner(); - return () => { - if (activeEffect) subs.add(activeEffect); - return cached; - }; - } - - if (key) { - const saved = localStorage.getItem(key); - if (saved !== null) { - try { initial = JSON.parse(saved); } catch (e) { } - } - } - - return (...args) => { - if (args.length) { - const next = typeof args[0] === 'function' ? args[0](initial) : args[0]; - if (!Object.is(initial, next)) { - initial = next; - if (key) localStorage.setItem(key, JSON.stringify(initial)); - subs.forEach(s => s()); - } - } - if (activeEffect) subs.add(activeEffect); - return initial; - }; - }; - - /** - * Hyperscript engine to render reactive HTML nodes. - * @param {string} tag - The HTML tag name (e.g., 'div', 'button'). - * @param {Object} [props] - Attributes, events (onclick), or reactive props ($value, $class). - * @param {any} [content] - String, Node, Array of nodes, or reactive function. - * @returns {HTMLElement} A live DOM element linked to SigPro signals. - */ - $.html = (tag, props = {}, content = []) => { - const el = document.createElement(tag); - if (typeof props !== 'object' || props instanceof Node || Array.isArray(props) || typeof props === 'function') { - content = props; - props = {}; - } - - for (let [key, val] of Object.entries(props)) { - if (key.startsWith('on')) { - el.addEventListener(key.toLowerCase().slice(2), val); - } else if (key.startsWith('$')) { - const attr = key.slice(1); - // Two-way binding for inputs - if ((attr === 'value' || attr === 'checked') && typeof val === 'function') { - const ev = attr === 'checked' ? 'change' : 'input'; - el.addEventListener(ev, e => val(attr === 'checked' ? e.target.checked : e.target.value)); - } - // Reactive attribute update - $(() => { - const v = typeof val === 'function' ? val() : val; - if (attr === 'value' || attr === 'checked') el[attr] = v; - else if (typeof v === 'boolean') el.toggleAttribute(attr, v); - else el.setAttribute(attr, v ?? ''); - }); - } else el.setAttribute(key, val); - } - - const append = (c) => { - if (Array.isArray(c)) return c.forEach(append); - if (typeof c === 'function') { - const node = document.createTextNode(''); - $(() => { - const res = c(); - if (res instanceof Node) { - if (node.parentNode) node.replaceWith(res); - } else { - node.textContent = res ?? ''; - } - }); - return el.appendChild(node); - } - el.appendChild(c instanceof Node ? c : document.createTextNode(c ?? '')); - }; - append(content); - return el; - }; - - const tags = ['div', 'span', 'p', 'button', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'a', 'label', 'section', 'nav', 'main', 'header', 'footer', 'input', 'form', 'img', 'select', 'option', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'canvas', 'video', 'audio']; - tags.forEach(t => window[t] = (p, c) => $.html(t, p, c)); - - /** - * Application mounter. - * @param {HTMLElement|function} node - Root component or element to mount. - * @param {HTMLElement|string} [target=document.body] - Target element or CSS selector. - */ - $.mount = (node, target = document.body) => { - const el = typeof target === 'string' ? document.querySelector(target) : target; - if (el) { - el.innerHTML = ''; - el.appendChild(typeof node === 'function' ? node() : node); - } - }; - - /** - * Initializes a reactive hash-based router. - * Maps URL hash changes to component rendering and supports Vite's dynamic imports. - * * @param {Array<{path: string, component: Function|Promise|HTMLElement}>} routes - Array of route objects. - * @returns {HTMLElement} A reactive div container that swaps content based on the current hash. - */ - $.router = (routes) => { - const sPath = $(window.location.hash.replace(/^#/, "") || "/"); - window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/")); - - return $.html('div', [ - () => { - const current = sPath(); - const cP = current.split('/').filter(Boolean); - - const route = routes.find(r => { - const rP = r.path.split('/').filter(Boolean); - if (rP.length !== cP.length) return false; - return rP.every((part, i) => part.startsWith(':') || part === cP[i]); - }) || routes.find(r => r.path === "*"); - - if (!route) return $.html('h1', "404 - Not Found"); - - const rP = route.path.split('/').filter(Boolean); - const params = {}; - rP.forEach((part, i) => { - if (part.startsWith(':')) params[part.slice(1)] = cP[i]; - }); - - const result = typeof route.component === 'function' ? route.component(params) : route.component; - - if (result instanceof Promise) { - const $lazyNode = $($.html('span', "Loading...")); - result.then(m => { - const content = m.default || m; - const finalView = typeof content === 'function' ? content(params) : content; - $lazyNode(finalView); - }); - return () => $lazyNode(); - } - - return result instanceof Node ? result : $.html('span', String(result)); - } - ]); - }; - - /** - * Programmatically navigates to a specific path using the hash. - * * @param {string} path - The destination path (e.g., '/home' or 'settings'). - * @example - * $.router.go('/profile/42'); - */ - $.router.go = (path) => { - window.location.hash = path.startsWith('/') ? path : `/${path}`; - }; - - /** - * Polymorphic Plugin System. - * Registers internal functions or loads external .js files as plugins. - * @param {function|string|Array} source - Plugin function or URL(s). - * @returns {Promise|SigPro} Resolves with the $ instance after loading or registering. - */ - $.plugin = (source) => { - if (typeof source === 'function') { - source($); - return $; - } - const urls = Array.isArray(source) ? source : [source]; - return Promise.all(urls.map(url => new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.src = url; - script.async = true; - script.onload = () => { - console.log(`%c[SigPro] Plugin Loaded: ${url}`, "color: #51cf66; font-weight: bold;"); - resolve(); - }; - script.onerror = () => reject(new Error(`[SigPro] Failed to load: ${url}`)); - document.head.appendChild(script); - }))).then(() => $); - }; - - window.$ = $; -})(); \ No newline at end of file diff --git a/docs/ui/quick.html b/docs/ui/quick.html index 8eed511..8ed4388 100644 --- a/docs/ui/quick.html +++ b/docs/ui/quick.html @@ -63,7 +63,7 @@ // Access translated strings (Returns a signal that tracks the current locale) const t = tt("confirm");

5. Best Practices โ€‹

  • Use $ for Reactivity: If a property starts with $, the component expects a Signal (e.g., $value: mySignal).
  • Automatic Cleaning: You don't need to manually destroy these components if they are inside a $.If or $.For. SigPro's core will "sweep" their internal watchers automatically.
  • Manual Cleanups: If you build custom components using setInterval or third-party observers, always add the stop functions to the element's ._cleanups Set.
- + \ No newline at end of file diff --git a/docs/vite/plugin.html b/docs/vite/plugin.html index 95d297b..c5dd728 100644 --- a/docs/vite/plugin.html +++ b/docs/vite/plugin.html @@ -68,7 +68,7 @@ { 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.

- + \ No newline at end of file diff --git a/src/docs/api/quick.md b/src/docs/api/quick.md index d555469..9fedfa7 100644 --- a/src/docs/api/quick.md +++ b/src/docs/api/quick.md @@ -1,19 +1,20 @@ -# โšก Quick API Reference +# โšก Quick API Reference (V2) -SigPro is a high-performance micro-framework that updates the **Real DOM** surgically. No Virtual DOM, no unnecessary re-renders. +SigPro is a high-performance micro-framework that updates the **Real DOM** surgically. No Virtual DOM, no unnecessary re-renders, and built-in **Saneamiento** (memory cleanup). ## ๐ŸŸข Core Functions | Function | Signature | Description | | :--- | :--- | :--- | -| `$(val, key?)` | `(any, string?) => Signal` | Creates a **Signal**. If `key` is provided, it persists in `localStorage`. | -| `$(fn)` | `(function) => Computed` | Creates a **Computed Signal** that auto-updates when its dependencies change. | -| `$.effect(fn)` | `(function) => stopFn` | Runs a side-effect that tracks signals. Returns a function to manually stop it. | -| `$.html(tag, props, children)` | `(string, object, any) => HTMLElement` | The low-level DOM factory powering all tag constructors. | -| `$.router(routes)` | `(Array) => HTMLElement` | Initializes the hash-based router for SPAs. | -| `$.go(path)` | `(string) => void` | Programmatic navigation (e.g., `$.go('/home')`). | -| `$.mount(comp, target)` | `(any, string\|Node) => Runtime` | Mounts the application into the specified DOM element. | -| `$.ignore(fn)` | `(function) => any` | Executes code without tracking any signals inside it. | +| **`$(val, key?)`** | `(any, string?) => Signal` | Creates a **Signal**. If `key` is provided, it persists in `localStorage`. | +| **`$(fn)`** | `(function) => Computed` | Creates a **Computed Signal** that auto-updates when its dependencies change. | +| **`$.watch(fn)`** | `(function) => stopFn` | **Automatic Mode:** Tracks any signal touched inside. Returns a stop function. | +| **`$.watch(deps, fn)`** | `(Array, function) => stopFn` | **Explicit Mode:** Only runs when signals in `deps` change. Used for Saneamiento. | +| **`$.html(tag, props, kids)`** | `(string, obj, any) => Element` | The low-level DOM factory. Attaches `._cleanups` to every element. | +| **`$.If(cond, then, else?)`** | `(Signal, fn, fn?) => Node` | Reactive conditional. Automatically destroys the "else" branch memory. | +| **`$.For(list, itemFn)`** | `(Signal, fn) => Node` | Optimized list renderer. Manages individual item lifecycles. | +| **`$.router(routes)`** | `(Array) => Element` | Hash-based SPA router. Uses Explicit Watch to prevent memory leaks. | +| **`$.mount(node, target)`** | `(any, string\|Node) => Runtime` | Entry point. Creates a root instance with `.destroy()` capabilities. | --- @@ -31,8 +32,18 @@ Tag({ attributes }, [children]) | Pattern | Code Example | Behavior | | :--- | :--- | :--- | | **Static** | `class: "text-red"` | Standard HTML attribute string. | -| **Reactive** | `disabled: isLoading` | Updates automatically when `isLoading()` changes. | -| **Two-way** | `$value: username` | Syncs input with signal **both ways** (Binding Operator). | -| **Text** | `P({}, () => count())` | Updates text node whenever `count` changes. | +| **Reactive** | `disabled: isLoading` | Updates automatically via internal `$.watch`. | +| **Two-way** | `$value: username` | **Binding Operator**: Syncs input $\leftrightarrow$ signal both ways. | +| **Text** | `P({}, () => count())` | Updates text node surgically without re-rendering the `P`. | | **Boolean** | `hidden: isHidden` | Toggles the attribute based on signal truthiness. | +--- + +## ๐Ÿงน Saneamiento (Memory Management) + +In SigPro V2, you rarely need to clean up manually, but the tools are there if you build custom components: + +* **Automatic**: Anything inside `$.If`, `$.For`, or `$.router` is "swept" when it disappears. +* **Manual**: Use `instance.destroy()` for apps or `$.cleanup(el)` for manual DOM injections. +* **Internal**: Every element carries a `._cleanups` Set with its own reactive "kill-switches". + diff --git a/src/docs/examples.md b/src/docs/examples.md deleted file mode 100644 index 836fa4a..0000000 --- a/src/docs/examples.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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/public/sigpro.js b/src/docs/public/sigpro.js deleted file mode 100644 index 995ed40..0000000 --- a/src/docs/public/sigpro.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * SigPro - Atomic Unified Reactive Engine - * A lightweight, fine-grained reactivity system with built-in routing and plugin support. - * @author Gemini & User - */ -(() => { - /** @type {Function|null} Internal tracker for the currently executing reactive effect. */ - let activeEffect = null; - - /** - * @typedef {Object} SigPro - * @property {function(any|function, string=): Function} $ - Creates a Signal or Computed. Optional key for localStorage. - * @property {function(string, Object=, any=): HTMLElement} html - Creates a reactive HTML element. - * @property {function((HTMLElement|function), (HTMLElement|string)=): void} mount - Mounts a component to the DOM. - * @property {function(Array): HTMLElement} router - Initializes a hash-based router. - * @property {function(string): void} router.go - Programmatic navigation to a hash path. - * @property {function((function|string|Array)): (Promise|SigPro)} plugin - Extends SigPro or loads external scripts. - */ - - /** - * Creates a Signal (state) or a Computed/Effect (reaction). - * Supports optional persistence in localStorage. - * * @param {any|function} initial - Initial value or a function for computed logic. - * @param {string} [key] - Optional localStorage key for automatic state persistence. - * @returns {Function} A reactive accessor/mutator function. - */ - const $ = (initial, key) => { - const subs = new Set(); - - if (typeof initial === 'function') { - let cached; - const runner = () => { - const prev = activeEffect; - activeEffect = runner; - try { - const next = initial(); - if (!Object.is(cached, next)) { - cached = next; - subs.forEach(s => s()); - } - } finally { activeEffect = prev; } - }; - runner(); - return () => { - if (activeEffect) subs.add(activeEffect); - return cached; - }; - } - - if (key) { - const saved = localStorage.getItem(key); - if (saved !== null) { - try { initial = JSON.parse(saved); } catch (e) { } - } - } - - return (...args) => { - if (args.length) { - const next = typeof args[0] === 'function' ? args[0](initial) : args[0]; - if (!Object.is(initial, next)) { - initial = next; - if (key) localStorage.setItem(key, JSON.stringify(initial)); - subs.forEach(s => s()); - } - } - if (activeEffect) subs.add(activeEffect); - return initial; - }; - }; - - /** - * Hyperscript engine to render reactive HTML nodes. - * @param {string} tag - The HTML tag name (e.g., 'div', 'button'). - * @param {Object} [props] - Attributes, events (onclick), or reactive props ($value, $class). - * @param {any} [content] - String, Node, Array of nodes, or reactive function. - * @returns {HTMLElement} A live DOM element linked to SigPro signals. - */ - $.html = (tag, props = {}, content = []) => { - const el = document.createElement(tag); - if (typeof props !== 'object' || props instanceof Node || Array.isArray(props) || typeof props === 'function') { - content = props; - props = {}; - } - - for (let [key, val] of Object.entries(props)) { - if (key.startsWith('on')) { - el.addEventListener(key.toLowerCase().slice(2), val); - } else if (key.startsWith('$')) { - const attr = key.slice(1); - // Two-way binding for inputs - if ((attr === 'value' || attr === 'checked') && typeof val === 'function') { - const ev = attr === 'checked' ? 'change' : 'input'; - el.addEventListener(ev, e => val(attr === 'checked' ? e.target.checked : e.target.value)); - } - // Reactive attribute update - $(() => { - const v = typeof val === 'function' ? val() : val; - if (attr === 'value' || attr === 'checked') el[attr] = v; - else if (typeof v === 'boolean') el.toggleAttribute(attr, v); - else el.setAttribute(attr, v ?? ''); - }); - } else el.setAttribute(key, val); - } - - const append = (c) => { - if (Array.isArray(c)) return c.forEach(append); - if (typeof c === 'function') { - const node = document.createTextNode(''); - $(() => { - const res = c(); - if (res instanceof Node) { - if (node.parentNode) node.replaceWith(res); - } else { - node.textContent = res ?? ''; - } - }); - return el.appendChild(node); - } - el.appendChild(c instanceof Node ? c : document.createTextNode(c ?? '')); - }; - append(content); - return el; - }; - - const tags = ['div', 'span', 'p', 'button', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'a', 'label', 'section', 'nav', 'main', 'header', 'footer', 'input', 'form', 'img', 'select', 'option', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'canvas', 'video', 'audio']; - tags.forEach(t => window[t] = (p, c) => $.html(t, p, c)); - - /** - * Application mounter. - * @param {HTMLElement|function} node - Root component or element to mount. - * @param {HTMLElement|string} [target=document.body] - Target element or CSS selector. - */ - $.mount = (node, target = document.body) => { - const el = typeof target === 'string' ? document.querySelector(target) : target; - if (el) { - el.innerHTML = ''; - el.appendChild(typeof node === 'function' ? node() : node); - } - }; - - /** - * Initializes a reactive hash-based router. - * Maps URL hash changes to component rendering and supports Vite's dynamic imports. - * * @param {Array<{path: string, component: Function|Promise|HTMLElement}>} routes - Array of route objects. - * @returns {HTMLElement} A reactive div container that swaps content based on the current hash. - */ - $.router = (routes) => { - const sPath = $(window.location.hash.replace(/^#/, "") || "/"); - window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/")); - - return $.html('div', [ - () => { - const current = sPath(); - const cP = current.split('/').filter(Boolean); - - const route = routes.find(r => { - const rP = r.path.split('/').filter(Boolean); - if (rP.length !== cP.length) return false; - return rP.every((part, i) => part.startsWith(':') || part === cP[i]); - }) || routes.find(r => r.path === "*"); - - if (!route) return $.html('h1', "404 - Not Found"); - - const rP = route.path.split('/').filter(Boolean); - const params = {}; - rP.forEach((part, i) => { - if (part.startsWith(':')) params[part.slice(1)] = cP[i]; - }); - - const result = typeof route.component === 'function' ? route.component(params) : route.component; - - if (result instanceof Promise) { - const $lazyNode = $($.html('span', "Loading...")); - result.then(m => { - const content = m.default || m; - const finalView = typeof content === 'function' ? content(params) : content; - $lazyNode(finalView); - }); - return () => $lazyNode(); - } - - return result instanceof Node ? result : $.html('span', String(result)); - } - ]); - }; - - /** - * Programmatically navigates to a specific path using the hash. - * * @param {string} path - The destination path (e.g., '/home' or 'settings'). - * @example - * $.router.go('/profile/42'); - */ - $.router.go = (path) => { - window.location.hash = path.startsWith('/') ? path : `/${path}`; - }; - - /** - * Polymorphic Plugin System. - * Registers internal functions or loads external .js files as plugins. - * @param {function|string|Array} source - Plugin function or URL(s). - * @returns {Promise|SigPro} Resolves with the $ instance after loading or registering. - */ - $.plugin = (source) => { - if (typeof source === 'function') { - source($); - return $; - } - const urls = Array.isArray(source) ? source : [source]; - return Promise.all(urls.map(url => new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.src = url; - script.async = true; - script.onload = () => { - console.log(`%c[SigPro] Plugin Loaded: ${url}`, "color: #51cf66; font-weight: bold;"); - resolve(); - }; - script.onerror = () => reject(new Error(`[SigPro] Failed to load: ${url}`)); - document.head.appendChild(script); - }))).then(() => $); - }; - - window.$ = $; -})(); \ No newline at end of file