Returno to inytegrate Tags in Core
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 4s
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 4s
This commit is contained in:
55
dist/sigpro.esm.js
vendored
55
dist/sigpro.esm.js
vendored
@@ -15,10 +15,6 @@ var MOUNTED_NODES = new WeakMap;
|
|||||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
||||||
var attrFilter = null;
|
|
||||||
var filterXSS = (fn) => {
|
|
||||||
attrFilter = fn;
|
|
||||||
};
|
|
||||||
var dispose = (eff) => {
|
var dispose = (eff) => {
|
||||||
if (!eff || eff._disposed)
|
if (!eff || eff._disposed)
|
||||||
return;
|
return;
|
||||||
@@ -247,6 +243,21 @@ var cleanupNode = (node) => {
|
|||||||
if (node.childNodes)
|
if (node.childNodes)
|
||||||
node.childNodes.forEach((n) => cleanupNode(n));
|
node.childNodes.forEach((n) => cleanupNode(n));
|
||||||
};
|
};
|
||||||
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
|
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
||||||
|
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
||||||
|
var validateAttr = (key, val) => {
|
||||||
|
if (val == null || val === false)
|
||||||
|
return null;
|
||||||
|
if (isDangerousAttr(key)) {
|
||||||
|
const sVal = String(val);
|
||||||
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
|
return "#";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
var h = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
@@ -285,38 +296,38 @@ var h = (tag, props = {}, children = []) => {
|
|||||||
isFunc(v) ? v(el) : v.current = el;
|
isFunc(v) ? v(el) : v.current = el;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let val = attrFilter ? attrFilter(k, v) : v;
|
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
val == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), val);
|
const cleanVal = validateAttr(k.slice(6), v);
|
||||||
|
cleanVal == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
const ev = k.slice(2).toLowerCase();
|
const ev = k.slice(2).toLowerCase();
|
||||||
el.addEventListener(ev, val);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, val);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
onUnmount(off);
|
||||||
} else if (isFunc(val)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const raw = val();
|
const val = validateAttr(k, v());
|
||||||
const safeVal = attrFilter ? attrFilter(k, raw) : raw;
|
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = safeVal || "";
|
el.className = val || "";
|
||||||
else if (safeVal == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = safeVal;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, safeVal === true ? "" : safeVal);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => val(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const val = validateAttr(k, v);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val;
|
el[k] = val;
|
||||||
@@ -498,13 +509,23 @@ var mount = (comp, target) => {
|
|||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
|
var sigpro = () => {
|
||||||
|
if (typeof window === "undefined")
|
||||||
|
return;
|
||||||
|
Object.assign(window, { $, $$, watch, h, when, each, router, mount, batch });
|
||||||
|
"a abbr article aside ... video".split(" ").forEach((tag) => {
|
||||||
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (typeof import.meta === "undefined" && typeof window !== "undefined")
|
||||||
|
sigpro();
|
||||||
export {
|
export {
|
||||||
when,
|
when,
|
||||||
watch,
|
watch,
|
||||||
|
sigpro,
|
||||||
router,
|
router,
|
||||||
mount,
|
mount,
|
||||||
h,
|
h,
|
||||||
filterXSS,
|
|
||||||
each,
|
each,
|
||||||
batch,
|
batch,
|
||||||
$$,
|
$$,
|
||||||
|
|||||||
2
dist/sigpro.esm.min.js
vendored
2
dist/sigpro.esm.min.js
vendored
File diff suppressed because one or more lines are too long
91
dist/sigpro.js
vendored
91
dist/sigpro.js
vendored
@@ -37,15 +37,15 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// sigpro-full.js
|
// index.js
|
||||||
var exports_sigpro_full = {};
|
var exports_sigpro = {};
|
||||||
__export(exports_sigpro_full, {
|
__export(exports_sigpro, {
|
||||||
when: () => when,
|
when: () => when,
|
||||||
watch: () => watch,
|
watch: () => watch,
|
||||||
|
sigpro: () => sigpro,
|
||||||
router: () => router,
|
router: () => router,
|
||||||
mount: () => mount,
|
mount: () => mount,
|
||||||
h: () => h,
|
h: () => h,
|
||||||
filterXSS: () => filterXSS,
|
|
||||||
each: () => each,
|
each: () => each,
|
||||||
batch: () => batch,
|
batch: () => batch,
|
||||||
$$: () => $$,
|
$$: () => $$,
|
||||||
@@ -69,10 +69,6 @@
|
|||||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
||||||
var attrFilter = null;
|
|
||||||
var filterXSS = (fn) => {
|
|
||||||
attrFilter = fn;
|
|
||||||
};
|
|
||||||
var dispose = (eff) => {
|
var dispose = (eff) => {
|
||||||
if (!eff || eff._disposed)
|
if (!eff || eff._disposed)
|
||||||
return;
|
return;
|
||||||
@@ -301,6 +297,21 @@
|
|||||||
if (node.childNodes)
|
if (node.childNodes)
|
||||||
node.childNodes.forEach((n) => cleanupNode(n));
|
node.childNodes.forEach((n) => cleanupNode(n));
|
||||||
};
|
};
|
||||||
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
|
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
||||||
|
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
||||||
|
var validateAttr = (key, val) => {
|
||||||
|
if (val == null || val === false)
|
||||||
|
return null;
|
||||||
|
if (isDangerousAttr(key)) {
|
||||||
|
const sVal = String(val);
|
||||||
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
|
return "#";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
var h = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
@@ -339,38 +350,38 @@
|
|||||||
isFunc(v) ? v(el) : v.current = el;
|
isFunc(v) ? v(el) : v.current = el;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let val = attrFilter ? attrFilter(k, v) : v;
|
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
val == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), val);
|
const cleanVal = validateAttr(k.slice(6), v);
|
||||||
|
cleanVal == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
const ev = k.slice(2).toLowerCase();
|
const ev = k.slice(2).toLowerCase();
|
||||||
el.addEventListener(ev, val);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, val);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
onUnmount(off);
|
||||||
} else if (isFunc(val)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const raw = val();
|
const val = validateAttr(k, v());
|
||||||
const safeVal = attrFilter ? attrFilter(k, raw) : raw;
|
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = safeVal || "";
|
el.className = val || "";
|
||||||
else if (safeVal == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = safeVal;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, safeVal === true ? "" : safeVal);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => val(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const val = validateAttr(k, v);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val;
|
el[k] = val;
|
||||||
@@ -552,38 +563,14 @@
|
|||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
// sigpro/tags.js
|
var sigpro = () => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window === "undefined")
|
||||||
"a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video".split(" ").forEach((tag) => {
|
return;
|
||||||
window[tag] = (...args) => h(tag, ...args);
|
Object.assign(window, { $, $$, watch, h, when, each, router, mount, batch });
|
||||||
|
"a abbr article aside ... video".split(" ").forEach((tag) => {
|
||||||
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
});
|
});
|
||||||
console.log("SigPro tags ready");
|
|
||||||
}
|
|
||||||
|
|
||||||
// sigpro/xss.js
|
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
|
||||||
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
|
||||||
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
|
||||||
var validateAttr = (key, val) => {
|
|
||||||
if (val == null || val === false)
|
|
||||||
return null;
|
|
||||||
if (isDangerousAttr(key)) {
|
|
||||||
const sVal = String(val);
|
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
|
||||||
console.warn(`[SigPro XSS] Locked ${key}`);
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
};
|
};
|
||||||
filterXSS(validateAttr);
|
if (typeof import.meta === "undefined" && typeof window !== "undefined")
|
||||||
|
sigpro();
|
||||||
// sigpro-full.js
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
const props = {};
|
|
||||||
for (const fn of [["$", $], ["$$", $$], ["watch", watch], ["h", h], ["when", when], ["each", each], ["router", router], ["mount", mount], ["batch", batch]]) {
|
|
||||||
props[fn[0]] = { value: fn[1], writable: false, configurable: false, enumerable: true };
|
|
||||||
}
|
|
||||||
Object.defineProperties(window, props);
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
2
dist/sigpro.min.js
vendored
2
dist/sigpro.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -111,8 +111,9 @@ export const filteredTodos = $(() => {
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// components/TodoApp.js
|
// components/TodoApp.js
|
||||||
|
import { sigpro } from 'sigpro';
|
||||||
import { todos, filter, addTodo, toggleTodo, filteredTodos } from "../store/todos.js";
|
import { todos, filter, addTodo, toggleTodo, filteredTodos } from "../store/todos.js";
|
||||||
import "sigpro/tags" // tags helpers available in global
|
sigpro(); // tags helpers available in global also core functions
|
||||||
|
|
||||||
const TodoApp = () =>
|
const TodoApp = () =>
|
||||||
div({ class: "todo-app" }, [
|
div({ class: "todo-app" }, [
|
||||||
|
|||||||
@@ -138,7 +138,8 @@ h('svg', { width: 100, height: 100 }, [
|
|||||||
## Complete Example
|
## Complete Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { $, h, mount } from 'sigpro';
|
import { sigpro } from 'sigpro';
|
||||||
|
sigpro(); // tags helpers available in global also core functions
|
||||||
|
|
||||||
const dynamicTag = $('h1');
|
const dynamicTag = $('h1');
|
||||||
|
|
||||||
|
|||||||
@@ -119,8 +119,8 @@ When `destroy()` is called (or when a new mount replaces an old one), everything
|
|||||||
## Complete Example
|
## Complete Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { $, mount, div, h1, button } from 'sigpro';
|
import { sigpro } from 'sigpro';
|
||||||
import "sigpro/tags" // tags helpers available in global
|
sigpro(); // tags helpers available in global also core functions
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const count = $(0);
|
const count = $(0);
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
# SigPro – Complete API Reference
|
# SigPro – Complete API Reference
|
||||||
|
|
||||||
SigPro is a **Real‑DOM first** reactive micro‑framework. No virtual DOM, no diffing overhead – it updates the DOM directly with surgical precision. Built‑in automatic cleanup prevents memory leaks, and the API is designed to be both tiny and powerful.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import { $, $$, watch, h, when, each, router, mount, batch } from 'sigpro'
|
|
||||||
// Optional side‑effects (activate global helpers & security):
|
|
||||||
import 'sigpro/tags' // → window.div, window.span, etc.
|
|
||||||
import 'sigpro/xss' // → attribute sanitisation
|
|
||||||
```
|
|
||||||
|
|
||||||
In a classic IIFE script (`<script src="sigpro.min.js">`), **everything** (core, router, tags, XSS, global functions) is available automatically.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Core Reactivity
|
## Core Reactivity
|
||||||
|
|
||||||
### `$(value, localStorageKey?)` – Signal & Computed
|
### `$(value, localStorageKey?)` – Signal & Computed
|
||||||
@@ -113,7 +100,8 @@ h('div', {}, [
|
|||||||
Tag helpers are **not exported individually** from the core. To use them globally without the `h(...)` wrapper, activate the side‑effect module:
|
Tag helpers are **not exported individually** from the core. To use them globally without the `h(...)` wrapper, activate the side‑effect module:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import 'sigpro/tags' // now window.div, window.span, etc. are available
|
import { sigpro } from "sigpro"
|
||||||
|
sigpro(); // now window.div, window.span, etc. are available
|
||||||
|
|
||||||
// You can now write:
|
// You can now write:
|
||||||
div({ class: 'container' }, [
|
div({ class: 'container' }, [
|
||||||
@@ -128,21 +116,6 @@ Available tags: `a`, `abbr`, `article`, `aside`, `audio`, `b`, `blockquote`, `br
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Built‑in XSS Shield (Optional)
|
|
||||||
|
|
||||||
SigPro includes an optional security layer that sanitises dangerous attributes (`href`, `src`, `formaction`, etc.) and blocks `javascript:` / `data:` / `vbscript:` protocols.
|
|
||||||
To enable it in ESM environments:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import 'sigpro/xss'
|
|
||||||
```
|
|
||||||
|
|
||||||
In the IIFE bundle, the shield is **active by default**.
|
|
||||||
|
|
||||||
When the shield is enabled, trying to set `href="javascript:alert(1)"` will log a warning and replace the value with `'#'`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Flow Control Components
|
## Flow Control Components
|
||||||
|
|
||||||
### `when(condition, thenComponent, elseComponent?)`
|
### `when(condition, thenComponent, elseComponent?)`
|
||||||
@@ -252,9 +225,8 @@ You never need to manually clean up – just write reactive code.
|
|||||||
## Full Example – Counter with Persistence
|
## Full Example – Counter with Persistence
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { $, watch, mount } from 'sigpro'
|
import { sigpro } from 'sigpro';
|
||||||
import 'sigpro/tags' // ← activate global helpers
|
sigpro(); // All in global window
|
||||||
import 'sigpro/xss' // ← activate security (optional)
|
|
||||||
|
|
||||||
const count = $(0, 'counter') // persists in localStorage
|
const count = $(0, 'counter') // persists in localStorage
|
||||||
|
|
||||||
@@ -268,19 +240,3 @@ const App = () =>
|
|||||||
|
|
||||||
mount(App, '#app')
|
mount(App, '#app')
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Customising the API (Renaming)
|
|
||||||
|
|
||||||
You can rename everything in one line:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import { $ as signal, watch as effect, h as element, mount as render } from 'sigpro'
|
|
||||||
```
|
|
||||||
|
|
||||||
In the IIFE bundle, the core functions are already available as both `window.$` and `window.SigPro.$`, so you can alias them globally if needed:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
window.myReactive = $ // or window.SigPro.$
|
|
||||||
```
|
|
||||||
@@ -152,8 +152,8 @@ If you want the router outlet to have no layout impact, you can set `display: co
|
|||||||
## Complete Example
|
## Complete Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { $, router, mount } from "sigpro";
|
import { sigpro } from 'sigpro';
|
||||||
import "sigpro/tags" // tags helpers available in global
|
sigpro(); // tags helpers available in global also core functions
|
||||||
|
|
||||||
const Home = () => div("Welcome home");
|
const Home = () => div("Welcome home");
|
||||||
const About = () => div("About us");
|
const About = () => div("About us");
|
||||||
|
|||||||
@@ -32,21 +32,13 @@ When you use the **IIFE bundle** (`sigpro.js` or `sigpro.min.js`) with a traditi
|
|||||||
When you import the **ES module** (`import { ... } from 'sigpro'`), the core **does not** add helpers to `window` by default. To enable global tags, import the dedicated side‑effect module:
|
When you import the **ES module** (`import { ... } from 'sigpro'`), the core **does not** add helpers to `window` by default. To enable global tags, import the dedicated side‑effect module:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import 'sigpro/tags'; // ← activates window.div, window.span, etc.
|
import { sigpro } from 'sigpro';
|
||||||
|
sigpro(); // tags helpers available in global also core functions
|
||||||
|
|
||||||
// Now you can use helpers globally
|
// Now you can use helpers globally
|
||||||
const App = () => div({ class: "app" }, "Ready!");
|
const App = () => div({ class: "app" }, "Ready!");
|
||||||
```
|
```
|
||||||
|
|
||||||
If you also want built‑in **XSS protection**, enable it once:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import 'sigpro/xss'; // ← add security layer
|
|
||||||
import 'sigpro/tags'; // ← global helpers
|
|
||||||
```
|
|
||||||
|
|
||||||
Both are side‑effect modules, so the order doesn’t matter.
|
|
||||||
|
|
||||||
> **Important:** The tag helpers are **not** exported as individual named exports from the core (`sigpro`). They become available as global functions (`window.div`, etc.) after the side‑effect runs.
|
> **Important:** The tag helpers are **not** exported as individual named exports from the core (`sigpro`). They become available as global functions (`window.div`, etc.) after the side‑effect runs.
|
||||||
> If you prefer to avoid globals, you can always use `h('div', ...)` directly—it’s perfectly fine.
|
> If you prefer to avoid globals, you can always use `h('div', ...)` directly—it’s perfectly fine.
|
||||||
|
|
||||||
@@ -201,12 +193,8 @@ const Timer = () => {
|
|||||||
### ESM (modern projects)
|
### ESM (modern projects)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Enable global helpers + security
|
import { sigpro } from 'sigpro';
|
||||||
import 'sigpro/tags';
|
sigpro(); // tags helpers available in global also core functions
|
||||||
import 'sigpro/xss';
|
|
||||||
|
|
||||||
// Import core functions
|
|
||||||
import { $, mount } from 'sigpro';
|
|
||||||
|
|
||||||
const nameSignal = $('');
|
const nameSignal = $('');
|
||||||
|
|
||||||
@@ -240,26 +228,3 @@ mount(App, '#app');
|
|||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Important Notes
|
|
||||||
|
|
||||||
- **Naming:** All tag helpers are **lowercase**.
|
|
||||||
- **Global availability:**
|
|
||||||
- **IIFE script** – automatically on `window`.
|
|
||||||
- **ESM module** – not global by default; use `import 'sigpro/tags'` to activate them.
|
|
||||||
- **Custom components:** Use **PascalCase** for your own component functions (e.g., `UserCard`) to visually distinguish them from built‑in tags.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Summary
|
|
||||||
|
|
||||||
| Feature | Description |
|
|
||||||
| :--- | :--- |
|
|
||||||
| **Tag helpers** | Lowercase functions for every HTML element (e.g., `div()`, `button()`). |
|
|
||||||
| **Activation** | IIFE: automatic. ESM: `import 'sigpro/tags'`. |
|
|
||||||
| **Reactive attributes** | Pass a function to any attribute to keep it synced. |
|
|
||||||
| **Two‑way binding** | Assign a signal directly to `value` or `checked` on form elements. |
|
|
||||||
| **Dynamic children** | Pass a function as a child for live updating content. |
|
|
||||||
| **Auto‑cleanup** | All effects, events, and children are disposed when the element is removed. |
|
|
||||||
| **Security** | Optional XSS shield: `import 'sigpro/xss'`. |
|
|
||||||
|
|||||||
@@ -48,16 +48,13 @@ bun add sigpro
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<script type="module">
|
<script type="module">
|
||||||
// Import the core – no global helpers or XSS yet
|
// Import the core
|
||||||
import { $, h, mount } from 'https://cdn.jsdelivr.net/npm/sigpro@1.2.23/dist/sigpro.esm.min.js';
|
import { sigpro, $, h, mount } from 'https://cdn.jsdelivr.net/npm/sigpro@latest/dist/sigpro.esm.min.js';
|
||||||
|
sigpro(); // Optional: now div, span, button, etc. become global
|
||||||
|
|
||||||
// Option A: use named imports (no globals, recommended)
|
// Option A: use named imports (no globals, recommended)
|
||||||
const count = $(0);
|
const count = $(0);
|
||||||
mount(() => h('h1', {}, () => `Count: ${count()}`), '#app');
|
mount(() => h('h1', {}, () => `Count: ${count()}`), '#app');
|
||||||
|
|
||||||
// Option B: enable global tag helpers (still optional)
|
|
||||||
import 'https://cdn.jsdelivr.net/npm/sigpro@1.2.23/sigpro/tags.js';
|
|
||||||
// now div, span, button, etc. become global
|
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -68,7 +65,7 @@ bun add sigpro
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Classic script: full kit (core, router, tags, XSS) auto‑installed -->
|
<!-- Classic script: full kit (core, router, tags, XSS) auto‑installed -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.23/dist/sigpro.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sigpro@latest/dist/sigpro.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// $, h, div, button, router, etc. are already global
|
// $, h, div, button, router, etc. are already global
|
||||||
const count = $(0);
|
const count = $(0);
|
||||||
@@ -95,9 +92,8 @@ SigPro uses **lowercase** Tag Helpers (e.g., `div`, `button`) to keep the syntax
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// App.js – Use named imports for the core, activate helpers if needed
|
// App.js – Use named imports for the core, activate helpers if needed
|
||||||
import { $, mount } from 'sigpro';
|
import { sigpro, $, mount } from 'sigpro';
|
||||||
import 'sigpro/tags'; // ← make div, h1, button, etc. global
|
sigpro(); // Optional: now div, span, button, etc. become global
|
||||||
import 'sigpro/xss'; // ← optional: activate XSS shield
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const count = $(0);
|
const count = $(0);
|
||||||
@@ -171,12 +167,8 @@ When you import the **ESM core** (`import { ... } from 'sigpro'`), **only the re
|
|||||||
|
|
||||||
2. **Activate global helpers** (when you want `div`, `span`, etc. without importing each one):
|
2. **Activate global helpers** (when you want `div`, `span`, etc. without importing each one):
|
||||||
```javascript
|
```javascript
|
||||||
import 'sigpro/tags'; // side‑effect: injects all tag helpers into window
|
import { sigpro } from 'sigpro';
|
||||||
```
|
sigpro(); // side‑effect: injects all tag helpers into window
|
||||||
|
|
||||||
3. **Activate XSS shield** (optional):
|
|
||||||
```javascript
|
|
||||||
import 'sigpro/xss'; // side‑effect: enables attribute sanitization
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Why two modes?
|
### Why two modes?
|
||||||
|
|||||||
@@ -42,12 +42,9 @@
|
|||||||
__export(exports_sigpro, {
|
__export(exports_sigpro, {
|
||||||
when: () => when,
|
when: () => when,
|
||||||
watch: () => watch,
|
watch: () => watch,
|
||||||
setAttrFilter: () => setAttrFilter,
|
sigpro: () => sigpro,
|
||||||
router: () => router,
|
router: () => router,
|
||||||
render: () => render,
|
|
||||||
onUnmount: () => onUnmount,
|
|
||||||
mount: () => mount,
|
mount: () => mount,
|
||||||
isFunc: () => isFunc,
|
|
||||||
h: () => h,
|
h: () => h,
|
||||||
each: () => each,
|
each: () => each,
|
||||||
batch: () => batch,
|
batch: () => batch,
|
||||||
@@ -72,10 +69,6 @@
|
|||||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
||||||
var attrFilter = null;
|
|
||||||
var setAttrFilter = (fn) => {
|
|
||||||
attrFilter = fn;
|
|
||||||
};
|
|
||||||
var dispose = (eff) => {
|
var dispose = (eff) => {
|
||||||
if (!eff || eff._disposed)
|
if (!eff || eff._disposed)
|
||||||
return;
|
return;
|
||||||
@@ -304,6 +297,21 @@
|
|||||||
if (node.childNodes)
|
if (node.childNodes)
|
||||||
node.childNodes.forEach((n) => cleanupNode(n));
|
node.childNodes.forEach((n) => cleanupNode(n));
|
||||||
};
|
};
|
||||||
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
|
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
||||||
|
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
||||||
|
var validateAttr = (key, val) => {
|
||||||
|
if (val == null || val === false)
|
||||||
|
return null;
|
||||||
|
if (isDangerousAttr(key)) {
|
||||||
|
const sVal = String(val);
|
||||||
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
|
return "#";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
var h = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
@@ -342,38 +350,38 @@
|
|||||||
isFunc(v) ? v(el) : v.current = el;
|
isFunc(v) ? v(el) : v.current = el;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let val = attrFilter ? attrFilter(k, v) : v;
|
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
val == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), val);
|
const cleanVal = validateAttr(k.slice(6), v);
|
||||||
|
cleanVal == null ? el.removeAttributeNS(XLINK_NS, k.slice(6)) : el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
const ev = k.slice(2).toLowerCase();
|
const ev = k.slice(2).toLowerCase();
|
||||||
el.addEventListener(ev, val);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, val);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
onUnmount(off);
|
||||||
} else if (isFunc(val)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const raw = val();
|
const val = validateAttr(k, v());
|
||||||
const safeVal = attrFilter ? attrFilter(k, raw) : raw;
|
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = safeVal || "";
|
el.className = val || "";
|
||||||
else if (safeVal == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = safeVal;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, safeVal === true ? "" : safeVal);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => val(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const val = validateAttr(k, v);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val;
|
el[k] = val;
|
||||||
@@ -555,4 +563,14 @@
|
|||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
|
var sigpro = () => {
|
||||||
|
if (typeof window === "undefined")
|
||||||
|
return;
|
||||||
|
Object.assign(window, { $, $$, watch, h, when, each, router, mount, batch });
|
||||||
|
"a abbr article aside ... video".split(" ").forEach((tag) => {
|
||||||
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (typeof import.meta === "undefined" && typeof window !== "undefined")
|
||||||
|
sigpro();
|
||||||
})();
|
})();
|
||||||
|
|||||||
27
package.json
27
package.json
@@ -14,15 +14,12 @@
|
|||||||
"script": "./dist/sigpro.min.js",
|
"script": "./dist/sigpro.min.js",
|
||||||
"types": "./sigpro.d.ts"
|
"types": "./sigpro.d.ts"
|
||||||
},
|
},
|
||||||
"./xss": "./sigpro/xss.js",
|
|
||||||
"./tags": "./sigpro/tags.js",
|
|
||||||
"./vite": "./vite/index.js",
|
"./vite": "./vite/index.js",
|
||||||
"./vite/*": "./vite/*.js"
|
"./vite/*": "./vite/*.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
"sigpro.js",
|
"sigpro.js",
|
||||||
"sigpro/",
|
|
||||||
"dist/",
|
"dist/",
|
||||||
"vite/",
|
"vite/",
|
||||||
"README.md",
|
"README.md",
|
||||||
@@ -36,18 +33,18 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/natxocc/sigpro/issues"
|
"url": "https://github.com/natxocc/sigpro/issues"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"prebuild": "npm run clean",
|
"prebuild": "npm run clean",
|
||||||
"build:esm": "bun build ./index.js --bundle --outfile=./dist/sigpro.esm.js --format=esm",
|
"build:iife": "bun build ./index.js --bundle --outfile=./dist/sigpro.js --format=iife --global-name=SigPro",
|
||||||
"build:esm:min": "bun build ./index.js --bundle --outfile=./dist/sigpro.esm.min.js --format=esm --minify",
|
"build:docs": "bun build ./index.js --bundle --outfile=./docs/sigpro.js --format=iife --global-name=SigPro",
|
||||||
"build:iife": "bun build ./sigpro-full.js --bundle --outfile=./dist/sigpro.js --format=iife --global-name=SigPro",
|
"build:iife:min": "bun build ./index.js --bundle --outfile=./dist/sigpro.min.js --format=iife --global-name=SigPro --minify",
|
||||||
"build:iife:min": "bun build ./sigpro-full.js --bundle --outfile=./dist/sigpro.min.js --format=iife --global-name=SigPro --minify",
|
"build:esm": "bun build ./index.js --bundle --outfile=./dist/sigpro.esm.js --format=esm",
|
||||||
"build:docs": "bun build ./sigpro-full.js --bundle --outfile=./docs/sigpro-full.js --format=iife --global-name=SigPro",
|
"build:esm:min": "bun build ./index.js --bundle --outfile=./dist/sigpro.esm.min.js --format=esm --minify",
|
||||||
"build": "bun run build:esm && bun run build:esm:min && bun run build:iife && bun run build:iife:min && bun run build:docs",
|
"build": "bun run build:iife && bun run build:iife:min && bun run build:esm && bun run build:esm:min && bun run build:docs",
|
||||||
"docs": "bun x serve docs",
|
"docs": "bun x serve docs",
|
||||||
"prepublishOnly": "npm run build"
|
"prepublishOnly": "npm run build"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"signals",
|
"signals",
|
||||||
"reactivity",
|
"reactivity",
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
// sigpro-full.js
|
|
||||||
export * from './sigpro.js';
|
|
||||||
import './sigpro/tags.js';
|
|
||||||
import './sigpro/xss.js';
|
|
||||||
import { $, $$, watch, h, when, each, router, mount, batch } from './sigpro.js';
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
const props = {};
|
|
||||||
for (const fn of [['$', $], ['$$', $$], ['watch', watch], ['h', h], ['when', when], ['each', each], ['router', router], ['mount', mount], ['batch', batch]]) {
|
|
||||||
props[fn[0]] = { value: fn[1], writable: false, configurable: false, enumerable: true };
|
|
||||||
}
|
|
||||||
Object.defineProperties(window, props);
|
|
||||||
}
|
|
||||||
58
sigpro.js
58
sigpro.js
@@ -17,9 +17,6 @@ const SVG_NS = "http://www.w3.org/2000/svg"
|
|||||||
const XLINK_NS = "http://www.w3.org/1999/xlink"
|
const XLINK_NS = "http://www.w3.org/1999/xlink"
|
||||||
const SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","))
|
const SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","))
|
||||||
|
|
||||||
let attrFilter = null
|
|
||||||
const filterXSS = fn => { attrFilter = fn }
|
|
||||||
|
|
||||||
const dispose = eff => {
|
const dispose = eff => {
|
||||||
if (!eff || eff._disposed) return
|
if (!eff || eff._disposed) return
|
||||||
eff._disposed = true
|
eff._disposed = true
|
||||||
@@ -235,6 +232,22 @@ const cleanupNode = (node) => {
|
|||||||
if (node.childNodes) node.childNodes.forEach(n => cleanupNode(n));
|
if (node.childNodes) node.childNodes.forEach(n => cleanupNode(n));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
|
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
||||||
|
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
||||||
|
|
||||||
|
const validateAttr = (key, val) => {
|
||||||
|
if (val == null || val === false) return null
|
||||||
|
if (isDangerousAttr(key)) {
|
||||||
|
const sVal = String(val)
|
||||||
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`)
|
||||||
|
return '#'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
const h = (tag, props = {}, children = []) => {
|
const h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props
|
children = props
|
||||||
@@ -281,37 +294,36 @@ const h = (tag, props = {}, children = []) => {
|
|||||||
isFunc(v) ? v(el) : (v.current = el)
|
isFunc(v) ? v(el) : (v.current = el)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let val = attrFilter ? attrFilter(k, v) : v
|
|
||||||
|
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
val == null
|
const cleanVal = validateAttr(k.slice(6), v)
|
||||||
|
cleanVal == null
|
||||||
? el.removeAttributeNS(XLINK_NS, k.slice(6))
|
? el.removeAttributeNS(XLINK_NS, k.slice(6))
|
||||||
: el.setAttributeNS(XLINK_NS, k.slice(6), val)
|
: el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
const ev = k.slice(2).toLowerCase()
|
const ev = k.slice(2).toLowerCase()
|
||||||
el.addEventListener(ev, val)
|
el.addEventListener(ev, v)
|
||||||
const off = () => el.removeEventListener(ev, val)
|
const off = () => el.removeEventListener(ev, v)
|
||||||
el._cleanups.add(off)
|
el._cleanups.add(off)
|
||||||
onUnmount(off)
|
onUnmount(off)
|
||||||
} else if (isFunc(val)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const raw = val()
|
const val = validateAttr(k, v())
|
||||||
const safeVal = attrFilter ? attrFilter(k, raw) : raw
|
if (k === "class") el.className = val || ""
|
||||||
if (k === "class") el.className = safeVal || ""
|
else if (val == null) el.removeAttribute(k)
|
||||||
else if (safeVal == null) el.removeAttribute(k)
|
else if (k in el && !isSVG) el[k] = val
|
||||||
else if (k in el && !isSVG) el[k] = safeVal
|
else el.setAttribute(k, val === true ? "" : val)
|
||||||
else el.setAttribute(k, safeVal === true ? "" : safeVal)
|
|
||||||
})
|
})
|
||||||
effect()
|
effect()
|
||||||
el._cleanups.add(() => dispose(effect))
|
el._cleanups.add(() => dispose(effect))
|
||||||
onUnmount(() => dispose(effect))
|
onUnmount(() => dispose(effect))
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input"
|
const evType = k === "checked" ? "change" : "input"
|
||||||
el.addEventListener(evType, ev => val(ev.target[k]))
|
el.addEventListener(evType, ev => v(ev.target[k]))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const val = validateAttr(k, v)
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG) el[k] = val
|
if (k in el && !isSVG) el[k] = val
|
||||||
else el.setAttribute(k, val === true ? "" : val)
|
else el.setAttribute(k, val === true ? "" : val)
|
||||||
@@ -493,4 +505,14 @@ const mount = (comp, target) => {
|
|||||||
return inst
|
return inst
|
||||||
}
|
}
|
||||||
|
|
||||||
export { $, $$, watch, h, when, each, router, mount, batch, filterXSS }
|
const sigpro = () => {
|
||||||
|
if (typeof window === "undefined") return
|
||||||
|
Object.assign(window, { $, $$, watch, h, when, each, router, mount, batch })
|
||||||
|
"a abbr article aside ... video"
|
||||||
|
.split(" ")
|
||||||
|
.forEach(tag => { window[tag] = (props, children) => h(tag, props, children) })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof import.meta === 'undefined' && typeof window !== 'undefined') sigpro()
|
||||||
|
|
||||||
|
export { sigpro, $, $$, watch, h, when, each, router, mount, batch }
|
||||||
@@ -3,8 +3,8 @@ import { h } from '../sigpro.js';
|
|||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
'a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video'
|
'a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video'
|
||||||
.split(' ').forEach(tag => {
|
.split(' ').forEach(tag => {
|
||||||
// window[tag] = (props, children) => h(tag, props, children);
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
window[tag] = (...args) => h(tag, ...args);
|
// window[tag] = (...args) => h(tag, ...args);
|
||||||
});
|
});
|
||||||
console.log('SigPro tags ready');
|
console.log('SigPro tags ready');
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user