2021-09-13 18:12:45 +00:00
|
|
|
# Skooma
|
|
|
|
|
2023-12-11 09:52:49 +00:00
|
|
|
```js
|
2024-08-02 07:24:50 +00:00
|
|
|
import {html} from "skooma/render.js"
|
|
|
|
|
|
|
|
document.body.append(
|
|
|
|
html.p(
|
|
|
|
"This is a paragraph with some text ",
|
|
|
|
html.b("and some bold text "),
|
|
|
|
html.img({
|
|
|
|
alt: "And an image",
|
|
|
|
href: "http://picsum.photos/200/200"
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)
|
2023-12-11 09:52:49 +00:00
|
|
|
```
|
|
|
|
|
2024-08-02 07:24:50 +00:00
|
|
|
## Goals
|
|
|
|
|
|
|
|
1. `skooma/render` should stay small enough to use it as just a helper library
|
|
|
|
to generate some dom nodes in any sort of web environment.
|
|
|
|
1. `skooma/observable` should likewise function as a standalone reactive state
|
|
|
|
management library to be used with or without a framework
|
|
|
|
1. A developer who doesn't use skooma should be able to read any code using it
|
|
|
|
and piece together what it does based on structure and function names
|
|
|
|
1. Skooma should be easy to gradually introduce into an application that uses
|
|
|
|
a different framework or no framework at all
|
|
|
|
1. Skooma should make it easy to gradually replace it with a different solution
|
|
|
|
should it prove unfit for a project it is being used in
|
|
|
|
1. The library should be hackable so that developers can tweak it for different
|
|
|
|
environments like SSR or frameworks
|
|
|
|
|
2024-08-01 12:57:13 +00:00
|
|
|
## Warning
|
|
|
|
|
|
|
|
**This branch is in the process of being aggressively refactored and improved.
|
|
|
|
This readme file may not reflect the latest state of the interface.**
|
|
|
|
|
2023-09-29 15:16:24 +00:00
|
|
|
## Overview
|
|
|
|
|
|
|
|
```js
|
2023-12-22 17:43:47 +00:00
|
|
|
const text = new State({value: "Skooma is cool"})
|
|
|
|
setTimeout(() => {text.value = "Skooma is awesome!"}, 1e5)
|
|
|
|
|
2023-09-29 15:16:24 +00:00
|
|
|
document.body.append(html.div(
|
|
|
|
html.h1("Hello, World!"),
|
2023-12-22 17:43:47 +00:00
|
|
|
html.p(text, {class: "amazing"}),
|
|
|
|
html.button("Show Proof", {click: event => { alert("It's true!") }})
|
2023-09-29 15:16:24 +00:00
|
|
|
))
|
|
|
|
```
|
2021-09-13 18:12:45 +00:00
|
|
|
|
|
|
|
## Interface / Examples
|
|
|
|
|
2024-08-01 12:57:13 +00:00
|
|
|
### Basic DOM generatio
|
2023-12-22 17:43:47 +00:00
|
|
|
|
|
|
|
Accessing the `html` proxy with any string key returns a new node generator
|
|
|
|
function:
|
|
|
|
|
|
|
|
```js
|
|
|
|
html.div("Hello, World!")
|
|
|
|
```
|
|
|
|
|
|
|
|
Attributes can be set by passing objects to the generator:
|
|
|
|
|
|
|
|
```js
|
|
|
|
html.div("Big Text", {style: "font-size: 1.4em"})
|
|
|
|
```
|
|
|
|
|
|
|
|
Complex structures can easily achieved by nesting generator functions:
|
2023-09-29 15:16:24 +00:00
|
|
|
|
2021-09-13 18:12:45 +00:00
|
|
|
```js
|
2023-12-22 17:43:47 +00:00
|
|
|
html.div(
|
|
|
|
html.p(
|
|
|
|
html.b("Bold Text")
|
|
|
|
)
|
|
|
|
)
|
2021-09-13 18:12:45 +00:00
|
|
|
```
|
|
|
|
|
2023-12-22 17:43:47 +00:00
|
|
|
For convenience, arrays assigned as attributes will be joined with spaces:
|
|
|
|
|
|
|
|
```js
|
|
|
|
html.a({class: ["button", "important"]})
|
|
|
|
```
|
|
|
|
|
|
|
|
Assigning a function as an attribute will instead attach it as an event
|
|
|
|
listener:
|
|
|
|
|
|
|
|
```js
|
|
|
|
html.button("Click me!", {click: event => {
|
|
|
|
alert("You clicked the button.")
|
|
|
|
}})
|
|
|
|
```
|
|
|
|
|
|
|
|
<!-- TODO: Document special keys -->
|
|
|
|
|
2021-11-25 09:08:59 +00:00
|
|
|
Generators can be called with many arguments. Arrays get iterated recursively as
|
|
|
|
if they were part of a flat argument list.
|
|
|
|
|
2023-09-29 15:16:24 +00:00
|
|
|
### Generating Text Nodes
|
|
|
|
|
2021-11-23 15:27:25 +00:00
|
|
|
```js
|
|
|
|
text("Hello, World")
|
|
|
|
// Wraps document.createTextNode
|
|
|
|
text()
|
2021-11-25 09:08:59 +00:00
|
|
|
// Defaults to empty string instead of erroring
|
|
|
|
text(null)
|
|
|
|
// Non-string arguments still error
|
2021-12-26 16:54:04 +00:00
|
|
|
|
|
|
|
text`Hello, World!`
|
|
|
|
// returns a new document fragment containing the text node "Hello, World!"
|
|
|
|
text`Hello, ${user}!`
|
|
|
|
// returns a document fragment containing 3 nodes:
|
|
|
|
// "Hello, ", the interpolated value of `user` and "!"
|
2023-09-29 15:16:24 +00:00
|
|
|
text`Hello, ${html.b(user)}!`
|
|
|
|
// Text node for Hello, the <b> tag with the user's name, and a text node for !
|
2021-11-23 15:27:25 +00:00
|
|
|
```
|
|
|
|
|
2021-10-05 17:28:36 +00:00
|
|
|
## handle
|
|
|
|
|
2023-12-11 09:52:49 +00:00
|
|
|
```js
|
2024-08-01 12:57:13 +00:00
|
|
|
import {handle} from 'skooma/state.js'
|
2023-12-11 09:52:49 +00:00
|
|
|
```
|
|
|
|
|
2021-10-05 17:28:36 +00:00
|
|
|
Since it is common for event handlers to call `preventDefault()`, skooma
|
|
|
|
provides a helper function called `handle` with the following definition:
|
|
|
|
|
|
|
|
```js
|
|
|
|
fn => event => { event.preventDefault(); return fn(event) }
|
|
|
|
```
|
|
|
|
|
2021-09-13 20:38:25 +00:00
|
|
|
## A few more examples:
|
|
|
|
|
|
|
|
Create a Button that deletes itself:
|
|
|
|
|
|
|
|
```js
|
|
|
|
document.body.append(
|
|
|
|
html.button("Delete Me", {click: event => event.target.remove()})
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Turn a two-dimensional array into an HTML table:
|
|
|
|
```js
|
|
|
|
const table = rows =>
|
|
|
|
html.table(html.tbody(rows.map(
|
|
|
|
row => html.tr(row.map(
|
|
|
|
cell => html.rd(cell, {dataset: {
|
|
|
|
content: cell.toLowerCase(),
|
|
|
|
}})
|
|
|
|
))
|
|
|
|
)))
|
|
|
|
```
|
|
|
|
|
|
|
|
A list that you can add items to
|
|
|
|
```js
|
|
|
|
let list, input = ""
|
|
|
|
document.body.append(html.div([
|
|
|
|
list=html.ul(),
|
|
|
|
html.input({type: 'text', input: e => input = e.target.value}),
|
|
|
|
html.button({click: event => list.append(html.li(input))}, "Add"),
|
|
|
|
]))
|
|
|
|
```
|
|
|
|
|
|
|
|
A list that you can also delete items from
|
|
|
|
```js
|
|
|
|
const listItem = content => html.li(
|
|
|
|
html.span(content), " ", html.a("[remove]", {
|
|
|
|
click: event => event.target.closest("li").remove(),
|
|
|
|
style: { cursor: 'pointer', color: 'red' },
|
|
|
|
})
|
|
|
|
)
|
|
|
|
let list, input = ""
|
|
|
|
document.body.append(html.div([
|
|
|
|
list=html.ul(),
|
|
|
|
html.input({type: 'text', input: e => input = e.target.value}),
|
|
|
|
html.button({click: event => list.append(listItem(input))}, "Add"),
|
|
|
|
]))
|
|
|
|
```
|