diff --git a/README.md b/README.md
index 250c1b6..9e576cc 100644
--- a/README.md
+++ b/README.md
@@ -154,7 +154,7 @@ Sample code:
_Requires Deno `1.35` or later._
```typescript
-import van from "https://deno.land/x/minivan@0.6.0/src/van-plate.js"
+import van from "https://deno.land/x/minivan@0.6.1/src/van-plate.js"
const {a, body, li, p, ul} = van.tags
@@ -195,7 +195,7 @@ _Requires Deno `1.35` or later._
```typescript
import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
-import van from "https://deno.land/x/minivan@0.6.0/src/mini-van.js"
+import van from "https://deno.land/x/minivan@0.6.1/src/mini-van.js"
const document = new DOMParser().parseFromString("", "text/html")!
const {tags, html} = van.vanWithDoc(document)
@@ -235,16 +235,16 @@ Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanj
To get started on the client side, add the line below to your script:
```javascript
-import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.0.min.js"
+import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.1.min.js"
```
To code without ES6 modules, add the following line to your HTML file instead:
```html
-
+
```
-Alternative, you can download the files ([`mini-van-0.6.0.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.min.js), [`mini-van-0.6.0.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.nomodule.min.js)) and serve them locally.
+Alternative, you can download the files ([`mini-van-0.6.1.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.1.min.js), [`mini-van-0.6.1.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.1.nomodule.min.js)) and serve them locally.
You can find all relevant **Mini-Van** files in this [Download Table](https://vanjs.org/minivan#download-table).
diff --git a/package-lock.json b/package-lock.json
index 7f5624a..ddb5fc2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mini-van-plate",
- "version": "0.6.0",
+ "version": "0.6.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mini-van-plate",
- "version": "0.6.0",
+ "version": "0.6.1",
"license": "MIT",
"devDependencies": {
"esbuild": "^0.17.19",
diff --git a/package.json b/package.json
index 383bdc8..731c171 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mini-van-plate",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "A minimalist template engine for DOM generation and manipulation, working for both client-side and server-side rendering",
"files": [
"src/mini-van.js",
diff --git a/public/mini-van-0.6.1.d.ts b/public/mini-van-0.6.1.d.ts
new file mode 100644
index 0000000..2796707
--- /dev/null
+++ b/public/mini-van-0.6.1.d.ts
@@ -0,0 +1,75 @@
+export interface State {
+ val: T
+ readonly oldVal: T
+ readonly rawVal: T
+}
+
+// Defining readonly view of State for covariance.
+// Basically we want StateView to implement StateView
+export type StateView = Readonly>
+
+export type Primitive = string | number | boolean | bigint
+
+export type PropValue = Primitive | ((e: any) => void) | null
+
+export type Props = Record | (() => PropValue)>
+
+interface HasFirstChild {firstChild?: unknown}
+
+type NodeType =
+ Omit
+
+export type ValidChildDomValue =
+ Primitive | ElementType | NodeType | TextNodeType | null | undefined
+
+export type BindingFunc =
+ | ((dom?: ElementType | TextNodeType) => ValidChildDomValue)
+ | ((dom?: ElementType) => ElementType)
+
+export type ChildDom =
+ | ValidChildDomValue
+ | StateView
+ | BindingFunc
+ | readonly ChildDom[]
+
+type AddFunc =
+ (dom: ElementType, ...children: readonly ChildDom[]) => ElementType
+
+export type TagFunc =
+ (first?: Props | ChildDom,
+ ...rest: readonly ChildDom[]) => ResultType
+
+type Tags =
+ Readonly>>
+
+// Tags type in browser context, which contains the signatures to tag functions that return
+// specialized DOM elements.
+type BrowserTags = Tags & {
+ [K in keyof HTMLElementTagNameMap]: TagFunc
+}
+
+declare function state(): State
+declare function state(initVal: T): State
+
+export interface VanObj {
+ readonly state: typeof state
+ readonly derive: (f: () => T) => State
+ readonly add: AddFunc
+ readonly tags: Tags & ((namespaceURI: string) => Tags)
+
+ // Mini-Van specific API
+ html: (first?: Props | ChildDom,
+ ...rest: readonly ChildDom[]) => string
+}
+
+export interface Van extends VanObj {
+ readonly vanWithDoc: (doc: {
+ createElement(s: any): ElementType,
+ createTextNode(s: any): TextNodeType,
+ }) => VanObj
+ readonly tags: BrowserTags & ((namespaceURI: string) => Tags)
+}
+
+declare const van: Van
+
+export default van
diff --git a/public/mini-van-0.6.1.js b/public/mini-van-0.6.1.js
new file mode 100644
index 0000000..ae2613c
--- /dev/null
+++ b/public/mini-van-0.6.1.js
@@ -0,0 +1,48 @@
+///
+
+// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.
+
+// Aliasing some builtin symbols to reduce the bundle size.
+let protoOf = Object.getPrototypeOf, _undefined, funcProto = protoOf(protoOf)
+
+let stateProto = {get oldVal() { return this.val }, get rawVal() { return this.val }}
+let objProto = protoOf(stateProto)
+
+let state = initVal => ({__proto__: stateProto, val: initVal})
+
+let plainValue = (k, v) => {
+ let protoOfV = protoOf(v ?? 0)
+ return protoOfV === stateProto ? v.val :
+ protoOfV !== funcProto || k?.startsWith("on") ? v : v()
+}
+
+let add = (dom, ...children) =>
+ (dom.append(...children.flat(Infinity)
+ .map(plainValue.bind(_undefined, _undefined))
+ .filter(c => c != _undefined)),
+ dom)
+
+let vanWithDoc = doc => {
+ let tag = (ns, name, ...args) => {
+ let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
+ let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name)
+ for (let [k, v] of Object.entries(props)) {
+ let plainV = plainValue(k, v)
+ // Disable setting attribute for function-valued properties (mostly event handlers),
+ // as they're usually not useful for SSR (server-side rendering).
+ protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV)
+ }
+ return add(dom, ...children)
+ }
+
+ let handler = ns => ({get: (_, name) => tag.bind(_undefined, ns, name)})
+ let tags = new Proxy(ns => new Proxy(tag, handler(ns)), handler())
+
+ return {
+ add, tags, state, derive: f => state(f()),
+ html: (...args) => "" + tags.html(...args).outerHTML,
+ }
+}
+
+export default {"vanWithDoc": vanWithDoc,
+ ...vanWithDoc(typeof window !== "undefined" ? window.document : null)}
diff --git a/public/mini-van-0.6.1.min.d.ts b/public/mini-van-0.6.1.min.d.ts
new file mode 100644
index 0000000..2796707
--- /dev/null
+++ b/public/mini-van-0.6.1.min.d.ts
@@ -0,0 +1,75 @@
+export interface State {
+ val: T
+ readonly oldVal: T
+ readonly rawVal: T
+}
+
+// Defining readonly view of State for covariance.
+// Basically we want StateView to implement StateView
+export type StateView = Readonly>
+
+export type Primitive = string | number | boolean | bigint
+
+export type PropValue = Primitive | ((e: any) => void) | null
+
+export type Props = Record | (() => PropValue)>
+
+interface HasFirstChild {firstChild?: unknown}
+
+type NodeType =
+ Omit
+
+export type ValidChildDomValue =
+ Primitive | ElementType | NodeType | TextNodeType | null | undefined
+
+export type BindingFunc =
+ | ((dom?: ElementType | TextNodeType) => ValidChildDomValue)
+ | ((dom?: ElementType) => ElementType)
+
+export type ChildDom =
+ | ValidChildDomValue
+ | StateView
+ | BindingFunc
+ | readonly ChildDom[]
+
+type AddFunc =
+ (dom: ElementType, ...children: readonly ChildDom[]) => ElementType
+
+export type TagFunc =
+ (first?: Props | ChildDom,
+ ...rest: readonly ChildDom[]) => ResultType
+
+type Tags =
+ Readonly>>
+
+// Tags type in browser context, which contains the signatures to tag functions that return
+// specialized DOM elements.
+type BrowserTags = Tags & {
+ [K in keyof HTMLElementTagNameMap]: TagFunc
+}
+
+declare function state(): State
+declare function state(initVal: T): State
+
+export interface VanObj {
+ readonly state: typeof state
+ readonly derive: (f: () => T) => State
+ readonly add: AddFunc
+ readonly tags: Tags & ((namespaceURI: string) => Tags)
+
+ // Mini-Van specific API
+ html: (first?: Props | ChildDom,
+ ...rest: readonly ChildDom[]) => string
+}
+
+export interface Van extends VanObj {
+ readonly vanWithDoc: (doc: {
+ createElement(s: any): ElementType,
+ createTextNode(s: any): TextNodeType,
+ }) => VanObj
+ readonly tags: BrowserTags & ((namespaceURI: string) => Tags)
+}
+
+declare const van: Van
+
+export default van
diff --git a/public/mini-van-0.6.1.min.js b/public/mini-van-0.6.1.min.js
new file mode 100644
index 0000000..ed82d89
--- /dev/null
+++ b/public/mini-van-0.6.1.min.js
@@ -0,0 +1 @@
+let t,e=Object.getPrototypeOf,r=e(e),l={get oldVal(){return this.val},get rawVal(){return this.val}},n=e(l),o=t=>({__proto__:l,val:t}),a=(t,n)=>{let o=e(n??0);return o===l?n.val:o!==r||t?.startsWith("on")?n:n()},d=(e,...r)=>(e.append(...r.flat(1/0).map(a.bind(t,t)).filter(e=>e!=t)),e),u=l=>{let u=(t,o,...u)=>{let[i,...w]=e(u[0]??0)===n?u:[{},...u],f=t?l.createElementNS(t,o):l.createElement(o);for(let[t,l]of Object.entries(i)){let n=a(t,l);e(n)!==r&&f.setAttribute(t,n)}return d(f,...w)},i=e=>({get:(r,l)=>u.bind(t,e,l)}),w=new Proxy(t=>new Proxy(u,i(t)),i());return{add:d,tags:w,state:o,derive:t=>o(t()),html:(...t)=>""+w.html(...t).outerHTML}};export default{vanWithDoc:u,...u("undefined"!=typeof window?window.document:null)};
\ No newline at end of file
diff --git a/public/mini-van-0.6.1.nomodule.js b/public/mini-van-0.6.1.nomodule.js
new file mode 100644
index 0000000..dfaa60a
--- /dev/null
+++ b/public/mini-van-0.6.1.nomodule.js
@@ -0,0 +1,45 @@
+(() => {
+ // mini-van.js
+ var protoOf = Object.getPrototypeOf;
+ var _undefined;
+ var funcProto = protoOf(protoOf);
+ var stateProto = { get oldVal() {
+ return this.val;
+ }, get rawVal() {
+ return this.val;
+ } };
+ var objProto = protoOf(stateProto);
+ var state = (initVal) => ({ __proto__: stateProto, val: initVal });
+ var plainValue = (k, v) => {
+ let protoOfV = protoOf(v ?? 0);
+ return protoOfV === stateProto ? v.val : protoOfV !== funcProto || k?.startsWith("on") ? v : v();
+ };
+ var add = (dom, ...children) => (dom.append(...children.flat(Infinity).map(plainValue.bind(_undefined, _undefined)).filter((c) => c != _undefined)), dom);
+ var vanWithDoc = (doc) => {
+ let tag = (ns, name, ...args) => {
+ let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args];
+ let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name);
+ for (let [k, v] of Object.entries(props)) {
+ let plainV = plainValue(k, v);
+ protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV);
+ }
+ return add(dom, ...children);
+ };
+ let handler = (ns) => ({ get: (_, name) => tag.bind(_undefined, ns, name) });
+ let tags = new Proxy((ns) => new Proxy(tag, handler(ns)), handler());
+ return {
+ add,
+ tags,
+ state,
+ derive: (f) => state(f()),
+ html: (...args) => "" + tags.html(...args).outerHTML
+ };
+ };
+ var mini_van_default = {
+ "vanWithDoc": vanWithDoc,
+ ...vanWithDoc(typeof window !== "undefined" ? window.document : null)
+ };
+
+ // mini-van.forbundle.js
+ window.van = mini_van_default;
+})();
diff --git a/public/mini-van-0.6.1.nomodule.min.js b/public/mini-van-0.6.1.nomodule.min.js
new file mode 100644
index 0000000..c1beea4
--- /dev/null
+++ b/public/mini-van-0.6.1.nomodule.min.js
@@ -0,0 +1 @@
+{let t,e,r,n,l,o,a,d,w,i;e=Object.getPrototypeOf,r=e(e),l=e(n={get oldVal(){return this.val},get rawVal(){return this.val}}),o=t=>({__proto__:n,val:t}),a=(t,l)=>{let o=e(l??0);return o===n?l.val:o!==r||t?.startsWith("on")?l:l()},d=(e,...r)=>(e.append(...r.flat(1/0).map(a.bind(t,t)).filter(e=>e!=t)),e),i={vanWithDoc:w=n=>{let w=(t,o,...w)=>{let[i,...u]=e(w[0]??0)===l?w:[{},...w],h=t?n.createElementNS(t,o):n.createElement(o);for(let[t,n]of Object.entries(i)){let l=a(t,n);e(l)!==r&&h.setAttribute(t,l)}return d(h,...u)},i=e=>({get:(r,n)=>w.bind(t,e,n)}),u=new Proxy(t=>new Proxy(w,i(t)),i());return{add:d,tags:u,state:o,derive:t=>o(t()),html:(...t)=>""+u.html(...t).outerHTML}},...w("undefined"!=typeof window?window.document:null)},window.van=i;}
\ No newline at end of file
diff --git a/public/mini-van.version b/public/mini-van.version
index 09a3acf..7ceb040 100644
--- a/public/mini-van.version
+++ b/public/mini-van.version
@@ -1 +1 @@
-0.6.0
\ No newline at end of file
+0.6.1
\ No newline at end of file
diff --git a/src/van-plate.js b/src/van-plate.js
index e0edfa1..6d82266 100644
--- a/src/van-plate.js
+++ b/src/van-plate.js
@@ -19,6 +19,11 @@ const noChild = {
keygen: 1,
}
+const tagsNoEscape = {
+ "script": 1,
+ "style": 1,
+}
+
const escapeMap = {
'&': '&',
'<': '<',
@@ -48,7 +53,7 @@ const elementProto = {
for (const c of this.children) {
const plainC = plainValue(c)
protoOf(plainC) === elementProto ? plainC.renderToBuf(buf) :
- buf.push((this.name === "script" ? x => x : escape)(plainC.toString()))
+ buf.push((tagsNoEscape[this.name] ? x => x : escape)(plainC.toString()))
}
buf.push(`${this.name}>`)
},
diff --git a/test/deno/van-plate.test.ts b/test/deno/van-plate.test.ts
index c5c5df0..349b013 100644
--- a/test/deno/van-plate.test.ts
+++ b/test/deno/van-plate.test.ts
@@ -1,7 +1,7 @@
import { assertEquals } from "https://deno.land/std@0.184.0/testing/asserts.ts";
import van from "../../src/van-plate.js"
-const {a, body, br, button, div, head, hr, input, li, p, pre, script, span, title, ul} = van.tags
+const {a, body, br, button, div, head, hr, input, li, p, pre, script, span, style, title, ul} = van.tags
Deno.test("tags", () => {
assertEquals(div(
@@ -41,6 +41,10 @@ Deno.test("don't escape script tag", () => {
assertEquals(script("console.log(a < b && c > d)").render(), "")
})
+Deno.test("don't escape style tag", () => {
+ assertEquals(style("ul > li { list-style-type: square; }").render(), "")
+})
+
Deno.test("nested children", () => {
assertEquals(ul([li("Item 1"), li("Item 2"), li("Item 3")]).render(),
"")