doc | ||
.editorconfig | ||
domProxy.js | ||
jsconfig.json | ||
license.md | ||
observable.js | ||
package.json | ||
readme.md | ||
ref.js | ||
render.js |
Skooma
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"
})
)
)
Goals
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.skooma/observable
should likewise function as a standalone reactive state management library to be used with or without a framework- 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
- Skooma should be easy to gradually introduce into an application that uses a different framework or no framework at all
- 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
- The library should be hackable so that developers can tweak it for different environments like SSR or frameworks
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.
Overview
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!") }})
))
Interface / Examples
Basic DOM generatio
Accessing the html
proxy with any string key returns a new node generator
function:
html.div("Hello, World!")
Attributes can be set by passing objects to the generator:
html.div("Big Text", {style: "font-size: 1.4em"})
Complex structures can easily achieved by nesting generator functions:
html.div(
html.p(
html.b("Bold Text")
)
)
For convenience, arrays assigned as attributes will be joined with spaces:
html.a({class: ["button", "important"]})
Assigning a function as an attribute will instead attach it as an event listener:
html.button("Click me!", {click: event => {
alert("You clicked the button.")
}})
Generators can be called with many arguments. Arrays get iterated recursively as if they were part of a flat argument list.
Generating Text Nodes
text("Hello, World")
// Wraps document.createTextNode
text()
// Defaults to empty string instead of erroring
text(null)
// Non-string arguments still error
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 "!"
text`Hello, ${html.b(user)}!`
// Text node for Hello, the <b> tag with the user's name, and a text node for !
handle
import {handle} from 'skooma/state.js'
Since it is common for event handlers to call preventDefault()
, skooma
provides a helper function called handle
with the following definition:
fn => event => { event.preventDefault(); return fn(event) }
A few more examples:
Create a Button that deletes itself:
document.body.append(
html.button("Delete Me", {click: event => event.target.remove()})
)
Turn a two-dimensional array into an HTML table:
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
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
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"),
]))