Update html-proxy somewhat

This commit is contained in:
Talia 2024-07-17 10:54:59 +02:00
parent d9d761a8ed
commit 9f326f4cbb

View file

@ -6,45 +6,60 @@ import {html} from "skooma.js"
A functional-friendly helper library for procedural DOM generation and templating, with support for reactive state objects.
## Overview
## Summary
```js
const text = new State({value: "Skooma is cool"})
setTimeout(() => {text.value = "Skooma is awesome!"}, 1e5)
document.body.append(html.div(
html.h1("Hello, World!"),
html.p(text, {class: "amazing"}),
html.button("Show Proof", {click: event => { alert("It's true!") }})
))
html.button(
"Clicki Me!",
{
class: "primary",
click({target}) {
console.log("User clicked", target)
}
},
button => { console.log("Created", button) }
)
```
* elements as functions `content -> element`
* content as arguments or in arrays
* attributes in object arguments
* style, dataset, shadow root, etc. as magic attributes
* events as function attributes
* initialisers as `void -> void` functions
## Interface / Examples
### Basic DOM generation
Accessing the `html` proxy with any string key returns a new node generator function. When called this function will generate a DOM node (HTML Tag). The name of the function becomes the tag name of the node.
Accessing the `html` proxy with any string key returns a new node generator function.
When called this function will generate a DOM node (HTML Tag).
The name of the function becomes the tag name of the node.
```js
html.div()
```
Content and attributes can be set via the function arguments: Strings and DOM nodes are inserted as children, while other objects (except for some special cases) have their key-value pairs turned into attribute-value pairs on the
Content and attributes can be set via the function arguments:
Strings and DOM nodes are inserted as children, while other objects (except for some special cases) have their key-value pairs turned into attribute-value pairs on the
```js
html.div("Big Text", {style: "font-size: 1.4em"})
```
Arrays, including nested ones, are iterated, and their values treated as arguments. This works both for inserting children and setting attributes.
Arrays are iterated and their values treated as arguments.
This works both for inserting children and setting attributes.
```js
const content = [" ps: hi", {class: "title"}]
html.h1({id: "main-heading"}, "Heading", content)
```
Function arguments are treated differently depending on their length: Functions with **no** named parameters are called, and their return value is then evaluated just like an argument to the generator.
Function arguments are treated differently depending on their length:]
Functions with **no** named parameters are called, and their return value is then evaluated just like an argument to the generator.
All other functions are (immediately) called with the newly created node as their first and only argument. These can be used to initialise the new node in a point-free style.
All other functions are (immediately) called with the newly created node as their first and only argument.
These can be used to initialise the new node in a point-free style.
```js
const hello = () => html.bold("Hello, World!")
@ -52,7 +67,8 @@ const init = node => console.log("Initialising", node)
html.div(hello, init)
```
Nested tags can be generated with nested function calls. When properly formatted, this means simpler templates will have the same structure as if written in HTML (sans those pesky closing tags).
Nested tags can be generated with nested function calls.
When properly formatted, this means simpler templates will have the same structure as if written in HTML (sans those pesky closing tags).
```js
html.div(
@ -85,7 +101,8 @@ const style = { color: "salmon" }
html.span("Salmon", { style })
```
The special property `shadowRoot` will attach a shadow-DOM to the element if none is present and append its content to the shadow root. Arrays are iterated over and their elements appended individually.
The special property `shadowRoot` will attach a shadow-DOM to the element if none is present and append its content to the shadow root.
Arrays are iterated over and their elements appended individually.
```js
html.div({
@ -104,11 +121,14 @@ console.log(div.getAttribute("data-foo") === "bar")
### Reactivity
Skooma generator functions have a simple concept of reactive state: Any value that
Skooma supports reactivity through a simple protocol:
1. Is not an `HTMLElement`
2. Is an `EventTarget`
3. Has a `value` attribute
Observable objects identify themselves with the `observable` attribute, which
must return a truthy value.
When such a value is found where an attribute value or a child element would be expected, then its `value` is used instead, and a "change" event listener is added to the reactive state that either updates the property or replaces the child element respectively.
Observables are expected to expose a `value` attribute that is both readable and
writeable, and to emit a "change" event whenever its vale has changed.
Observables can be used both as attribute values as well as for child elements.
TODO: Explain what actually happens