Hello World

The traditional "click me" app:

import * as api from '/api.js'
await api.appReady

const $count = api.$(0)
const inc = () => $count.val++

const panel = await api.sys.makePanel({ name: "hello world" },
  <panel size={{ w: 120, h: 70 }}>
    <api.Center>
      <api.GroupY gap={4}>
        <api.Label text='hello world!' />
        <api.GroupX gap={2}>
          <button style='submit' action={inc}>click me</button>
          <api.Label text={$count.adapt(n => `clicked ${n} times`)} />
        </api.GroupX>
      </api.GroupY>
    </api.Center>
  </panel>
)

panel.focusPanel()

Full Breakdown

All API functions are exported from this file.

import * as api from '/api.js'

When the API is imported, the system is initialized, and all prelude scripts of your choosing are run. So we wait for them to finish.

await api.appReady

We create a Ref and a function to modify it.

const $count = api.$(0)
const inc = () => $count.val++

The sys has a method to create panels, which is async since apps run inside web workers, which need to communicate with the host (the GUI thread).

const panel = await api.sys.makePanel({ name: "hello world" },

Panels only require a name and a root view, so they can draw something on screen, and so the shell has a somewhat unique string to manage them by.

Shells are just user-land programs which typically watch the panelevents broadcast channel and manage the size, position, and visibility of panels.

The panel here is the root view, which specifies its initial size, which the shell can use (or ignore).

  <panel size={{ w: 120, h: 70 }}>
    // ...
  </panel>
)

A note on JSX

JSX here is just shorthand for:

import { composites } from '/api.js'

function jsx(tag, data) {
  if (isConstructable(tag))  return new tag(data)
  else if (isFunction(tag))  return tag(data)
  else                       return composites[tag](data)
}

Unlike the classical web browser model, views are just instances of View or a subclass, and devs can create subclasses directly. Functions must ultimately return a view.

JSX strings are here used for Composites, which is a technique for styling and restructuring views and overriding their functionality, as a modern alternative to older, classical models such as HTML, CSS, web-components, and React.js.

We center our main content, which is a group of views stacked vertically, mainly being our greeting and our pair of button and the label that reflects its actions.

    <api.Center>
      <api.GroupY gap={4}>
        <api.Label text='hello world!' />
        <api.GroupX gap={2}>
          // ...
        </api.GroupX>
      </api.GroupY>
    </api.Center>

Above, we used primitive view classes, which can't be styled. Here, we use the button composite, to allow users to override our style, layout, and/or functionality. The default impl uses a padding of 2, switches color based on the given style, and puts the text inside a Label child of the Button.

          <button style='submit' action={inc}>click me</button>

Finally we have the label that shows the number of clicks. We take the $count and adapt it to produce a string. Like most properties on View and its subclasses, you can either pass a value or a ref to a value. (This aids with creating flexible but simple composite APIs like button).

          <api.Label text={$count.adapt(n => `clicked ${n} times`)} />

And that's it! You now have a working app, simple as can be.

Feel free to check out the Todo List for a more in-depth example.