function withRuntime(callback, {
invalidation,
runtime: runtimeInstance,
identifier = () => DOM.uid("cell").id.replace(/-/g, "_"),
Cell = Symbol.for("Cell"),
} = {}) {
const runtime = runtimeInstance ?? new Runtime();
if(!runtimeInstance) invalidation?.then(() => runtime.dispose());
const module = runtime.module();
const names = new WeakMap();
return callback({$name, $cell, $value, $values, $inspect, $raw, $state, $render});
function placeholder(d) {
if(!(d instanceof Promise)) return d;
const node = document.createComment("");
d.then(d => {
if(!node.parentElement) return;
if(!(d instanceof Node)) d = document.createTextNode(String(d));
node.parentElement.replaceChild(d, node);
});
return node;
}
* @returns {string}
*/
function $name(d) {
if(typeof d === "string") return d;
if(!names.has(d)) names.set(d, identifier());
return names.get(d);
}
/**
* Returns a cell's last value.
*
* @param {Cell | string} d
* @returns {Promise}
*/
function $value(d) {
return module.value(String(d));
}
/**
* Subscribes to a view's values.
*
* @param {Cell | string} cell
* @returns
*/
function $values(cell) {
return $cell([String(cell)], view => Generators.input(view));
}
/**
* Defines a new cell.
*/
function $cell(...args) {
const inputs = args.length < 2 ? [] : args[0];
const fn = args.length < 2 ? args[0] : args[1];
const v = module.variable();
const name = $name(v);
v.define($name(v), inputs.map($name), fn);
return Object.defineProperties(v, {
[Cell]: { value: true },
toString: { value: () => name }
});
}
/**
* Returns Inspector output for a cell.
*
* @param {Cell | string} cell
* @returns {HTMLSpanElement}
*/
function $inspect(cell) {
const wrap = htl.html`<span>`;
module.variable(new Inspector(wrap)).define([String(cell)], d => d);
return wrap;
}
/**
*
*
* @param {Cell | string} cell
* @returns {HTMLSpanElement}
*/
function $raw(cell) {
const wrap = htl.html`<span>`;
const update = d => wrap.replaceChildren(d);
module.variable({fulfilled: update, rejected: update}).define([String(cell)], d => d);
return wrap;
}
/**
*
* @param strings
* @param values
* @returns {HTMLElement}
*/
function $render(strings, ...values) {
const resolve = d => d[Cell] ? $inspect(d) : d;
const map = d => d instanceof Promise
? placeholder(d.then(resolve))
: resolve(d);
return htl.html(strings, ...values.map(map));
}
/**
* @typeParam T
* @param {T} initial
* @returns {[Cell, (newState: T) => T]}
*/
function $state(initial) {
const cell = $cell(initial);
return [cell, d => cell.define(String(cell), d)];
}
}