Host IO
Apps and the JavaScript host can talk both ways: Nix calls JavaScript through effects, and JavaScript dispatches actions to the app. Both are optional.
Define effects#
Effects are functions, by name. They can return promises:
export default { copy: (text) => navigator.clipboard.writeText(text), paste: () => navigator.clipboard.readText(), };
Name the module in a page's client, in the Vite plugin's pages:
client: { type: "nix", path: "./src/app", effects: "./src/effects.js" },
Or pass them to mount, when embedding an app:
import app from "./app?cursery:app"; import effects from "./effects.js"; app.mount(document.getElementById("app"), { effects });
Call effects#
Handlers call an effect with io.call, given its name and input. In io.pipe, each step gets the output of the last:
let inherit (import <web/dom>) html; io = import <web/io>; in { init = ""; update = state: action: action.payload; render = text: [ (html.button { on.click = event: io.call "copy" "Hello"; } "Copy") (html.button { on.click = event: io.pipe null [ (_: io.call "paste" null) # What the promise resolved to. (text: io.dispatch "pasted" text) ]; } "Paste") (html.p text) ]; }
Inputs and outputs must be JSON-compatible.
Dispatch from JavaScript#
dispatch sends an action to the app mounted into an element, as io.dispatch does from a handler:
import { dispatch } from "cursery"; import app from "./app?cursery:app"; const container = document.getElementById("app"); app.mount(container); setInterval(() => { // The action's type and payload. The app renders before this returns. dispatch(container, "tick", Date.now()); }, 1000);
The payload must be JSON-compatible.