Literals and stores

There are two ways to store data when working with ceres: literals and stores.

Literals

Any JavaScript variable that can be represented as a string is a literal. Literals can be used to set attributes or as children. When a literal appears as a child of an element, it will be rendered as a text node. It’s important to know that literals are not reactive, so changing the value of a literal after it has rendered has no effect.

const name = "Ceres Fauna";
let graduated = true;

$element("div", {},
    $element("span", {}, name),
    $element("button", { disabled: graduated }, "Watch")
)
.mount(document.body);

// Does nothing.
graduated = false;

Stores

Stores hold a literal and can be subscribed to. Whenever the stored value changes all subscribers will be notified. You can create a store by calling $store with an initial value. Reading and writing to a store is done through the value property. If necessary, you can specify the type of the store at creation.

const graduated = $store(true);
graduated.value = false;
console.log(graduated.value);

const nullable = $store<string | null>(null);

Stores can be used in place of literals, but they are reactive and renderables will update when their values change.

const name = "Ceres Fauna";
const graduated = $store(true);

$element("div", {},
    $element("span", {}, name),
    $element("button", { disabled: graduated }, "Watch")
)
.mount(document.body);

// Now it works!
setTimeout(() => graduated.value = false, 1000);

Embedding stores on strings

Stores may be used to construct reactive strings using the $format tag.

const pi = $store(3.1415926535897932384);

$element("span", {}, $format`PI = ${pi}`)
.mount(document.body);

setTimeout(() => pi.value = 3, 1000);

Derived stores

Stores can be transformed to create a new store that updates whenever the original changes. To create a derived store call derive on the original store, and give it a transformation function. The original store is unaffected.

const pi = $store(3.1415926535897932384);
const tau = pi.derive((pi) => 2 * pi);

$element("span", {}, $format`TAU = ${tau}`)
.mount(document.body);

To combine multiple stores, use the $derive function with the original stores, along with an aggregator function.

const baseDamage = $store(2);
const critMultiplier = $store(1.5);

const critDamage = $derive([baseDamage, critMultiplier], ([base, multi]) => base * multi);

Custom stores

You can write your own stores by extending the Store class, and ceres will know how to make them reactive. It just works.

class Hakos extends Store<number> {
    private stored: number;

    constructor() {
        super();
        setInterval(() => this.value = Math.random(), 1000);
        this.stored = Math.random();
    }

    get value() { return this.stored };
    set value(value) {
        const previous = this.value;
        this.stored = value;
        this.notify(previous);
    }
}

const baelz = new Hakos();
$element("span", {}, baelz).mount(document.body);