Liking cljdoc? Tell your friends :D

co.multiply.tropical.island

Islands: the unit of rendering, caching and patching, written as functions.

defisland defines a function returning hiccup, as a React component does. Calling an island inside another island's hiccup does not render it: it places the island there, with its arguments, for the runtime (co.multiply.tropical.runtime) to reconcile. An island renders again only when its arguments change (=), or when something it read through a hook changed. Otherwise its last output is reused, and so is everything it holds.

Hooks run only during a render. Each takes a key, unique within the island, instead of relying on call order:

  • use-watch read a ref (atom, etc.) or a signal; re-render when the selected value changes.
  • use-state island-local state, kept while the island is mounted.
  • use-hold hold something (a subscription, a token) while renders keep asking for it.
  • use-session the session's {:tab :uid :request}.
  • use-patch-signals a fn patching the page's signals from any thread.

co.multiply.tropical.hooks/observe and co.multiply.tropical.action/use-action build on these.

Ids are scoped by parent, as React keys are. An island's slot is its name, plus .key for a keyed island, and is unique among its siblings. Its id is the path of slots from the root, app/vault-card/vault-panel, so it is unique on the page wherever the island is placed. An island placed by a different parent is a different instance, and so is one under a new key: it starts over, which is how to reset an island, such as a dialog opened again.

The page sees an opaque digest of the id on the island's element (element-id), unless names are readable (co.multiply.tropical.names).

Islands: the unit of rendering, caching and patching, written as functions.

`defisland` defines a function returning hiccup, as a React component does.
Calling an island inside another island's hiccup does not render it: it places
the island there, with its arguments, for the runtime
(`co.multiply.tropical.runtime`) to reconcile. An island renders again only
when its arguments change (`=`), or when something it read through a hook
changed. Otherwise its last output is reused, and so is everything it holds.

Hooks run only during a render. Each takes a key, unique within the island,
instead of relying on call order:

- `use-watch`   read a ref (atom, etc.) or a signal; re-render when the selected value changes.
- `use-state`   island-local state, kept while the island is mounted.
- `use-hold`    hold something (a subscription, a token) while renders keep asking for it.
- `use-session` the session's `{:tab :uid :request}`.
- `use-patch-signals` a fn patching the page's signals from any thread.

`co.multiply.tropical.hooks/observe` and
`co.multiply.tropical.action/use-action` build on these.

Ids are scoped by parent, as React keys are. An island's slot is its name,
plus `.key` for a keyed island, and is unique among its siblings. Its id is
the path of slots from the root, `app/vault-card/vault-panel`, so it is
unique on the page wherever the island is placed. An island placed by a
different parent is a different instance, and so is one under a new key: it
starts over, which is how to reset an island, such as a dialog opened again.

The page sees an opaque digest of the id on the island's element
(`element-id`), unless names are readable (`co.multiply.tropical.names`).
raw docstring

declare-scriptclj

(declare-script url)

Declares the ES module at url, which the island's elements need. The session sends it to the page once, from the first frame in which an island declares it, as a <script type="module"> appended to the page's head, and gives it to the page for its own head when it is in the first frame. Returns nil.

The primitive under co.multiply.tropical.script.

Declares the ES module at `url`, which the island's elements need. The
session sends it to the page once, from the first frame in which an island
declares it, as a `<script type="module">` appended to the page's head, and
gives it to the page for its own head when it is in the first frame. Returns
nil.

The primitive under `co.multiply.tropical.script`.
sourceraw docstring

declare-signalclj

(declare-signal path value)

Declares the Datastar signal at path, a vector of names, as value, unless the client already has it. The island's root carries the declaration, as data-signals__ifmissing, so the signal exists wherever the island is in the page, and neither a later render, a patch, nor the island mounting again resets what the client has made of it. value is data, sent as JSON, or (js expr). Returns nil.

A map is declared per leaf: a key missing from the client's copy is added, and the others are left as they are.

The primitive under co.multiply.tropical.cookie and co.multiply.tropical.storage, for state the browser owns.

Declares the Datastar signal at `path`, a vector of names, as `value`, unless
the client already has it. The island's root carries the declaration, as
`data-signals__ifmissing`, so the signal exists wherever the island is in the
page, and neither a later render, a patch, nor the island mounting again
resets what the client has made of it. `value` is data, sent as JSON, or
`(js expr)`. Returns nil.

A map is declared per leaf: a key missing from the client's copy is added,
and the others are left as they are.

The primitive under `co.multiply.tropical.cookie` and
`co.multiply.tropical.storage`, for state the browser owns.
sourceraw docstring

defislandcljmacro

(defisland island-name & decl)

Defines an island: a function of its arguments returning hiccup, rendered and patched on its own.

The island's element id is the path of slots from the root (see the namespace docstring). It is set on the root element the render returns, so the render must not set an id of its own; a root that isn't an element is wrapped in a :div. Siblings need distinct slots: to place several instances under one parent, give a :key fn of the arguments in an options map, and the slot becomes name.<key>:

(defisland message {:key :n} [msg]
  [:li (:text msg)])
Defines an island: a function of its arguments returning hiccup, rendered and
patched on its own.

The island's element id is the path of slots from the root (see the
namespace docstring). It is set on the root element the render returns, so
the render must not set an id of its own; a root that isn't an element is
wrapped in a `:div`. Siblings need distinct slots: to place several
instances under one parent, give a `:key` fn of the arguments in an options
map, and the slot becomes `name.<key>`:

    (defisland message {:key :n} [msg]
      [:li (:text msg)])
sourceraw docstring

element-idclj

(element-id id)

The id of island id's element in the page: an opaque digest of it, or the id itself while names are readable (co.multiply.tropical.names).

The id of island `id`'s element in the page: an opaque digest of it, or the
id itself while names are readable (`co.multiply.tropical.names`).
sourceraw docstring

error-viewclj

(error-view _id _e)

What renders in place of island id when its render throws e, unless the app gives an :error-view of its own. It says only that the island failed: an exception's message can carry what the user shouldn't see, and the exception is logged.

What renders in place of island `id` when its render throws `e`, unless the
app gives an `:error-view` of its own. It says only that the island failed:
an exception's message can carry what the user shouldn't see, and the
exception is logged.
sourceraw docstring

frame-charsclj

(frame-chars frame)

Length of the HTML frame emits, computed from cached template sizes.

Length of the HTML `frame` emits, computed from cached template sizes.
sourceraw docstring

jsclj

(js expr)

A JavaScript expression, as the value declare-signal declares a signal with, for a value only the browser knows. The browser evaluates it each time it applies the declaration, and keeps it only where the signal is missing.

A JavaScript expression, as the value `declare-signal` declares a signal
with, for a value only the browser knows. The browser evaluates it each time
it applies the declaration, and keeps it only where the signal is missing.
sourceraw docstring

use-holdclj

(use-hold k acquire)
(use-hold k acquire {:keys [idempotent]})

Holds a value under k for as long as the island's renders keep calling (use-hold k ...). acquire runs when the island first asks for k and returns {:value v, :release f}. release runs after the first render that no longer asks for k, or when the island unmounts. Returns v.

A render asks for each k at most once: asking twice throws, since two call sites sharing one hold (two buttons sharing one action token) is a bug. With {:idempotent true}, asking again returns what the first ask got, for a hold whose key is what it holds, such as a read: two hooks reading the same thing in one render share one hold, as observe and co.multiply.tropical.shared/use-shared do.

Holds a value under `k` for as long as the island's renders keep calling
`(use-hold k ...)`. `acquire` runs when the island first asks for `k` and
returns `{:value v, :release f}`. `release` runs after the first render that no
longer asks for `k`, or when the island unmounts. Returns `v`.

A render asks for each `k` at most once: asking twice throws, since two call
sites sharing one hold (two buttons sharing one action token) is a bug.
With `{:idempotent true}`, asking again returns what the first ask got, for
a hold whose key is what it holds, such as a read: two hooks reading the
same thing in one render share one hold, as `observe` and
`co.multiply.tropical.shared/use-shared` do.
sourceraw docstring

use-patch-signalsclj

(use-patch-signals)

A fn that patches signals, a map, into the page's Datastar signals, as an action's answer does, for work that lands after its action answered: a background task's result filling a form's fields. Callable from any thread while the island is mounted, and returns nil:

(let [patch! (use-patch-signals)
      import (use-action :import
               (fn [{text "text"}]
                 (q/compel (q/task (patch! {:draft (convert text)})))
                 nil))]
  ...)

The session sends them after the frame rendering what changed with them, so elements bound to them are in the page by then, or once its tab is connected, if it isn't. Patches sent together are merged where one patch does what they do in turn. A patch from an island since unmounted is dropped, as are those a session closes with.

Signals are the page's, not the island's: a patch overwrites what the user typed into a field bound to one.

A fn that patches `signals`, a map, into the page's Datastar signals, as an
action's answer does, for work that lands after its action answered: a
background task's result filling a form's fields. Callable from any thread
while the island is mounted, and returns nil:

    (let [patch! (use-patch-signals)
          import (use-action :import
                   (fn [{text "text"}]
                     (q/compel (q/task (patch! {:draft (convert text)})))
                     nil))]
      ...)

The session sends them after the frame rendering what changed with them,
so elements bound to them are in the page by then, or once its tab is
connected, if it isn't. Patches sent together are merged where one patch
does what they do in turn. A patch from an island since unmounted is
dropped, as are those a session closes with.

Signals are the page's, not the island's: a patch overwrites what the user
typed into a field bound to one.
sourceraw docstring

use-sessionclj

(use-session)

The session's context: {:tab :uid :request}, its tab, its user, and the Ring request that created it, as its root got them.

The request is the page's, or, for a tab the server rebuilt, as after a restart, its stream's, to the page's own URL: so its path and query are the page's either way, and fixed for the session's life, while its headers depend on which request it was. An action's handler reads its own request with co.multiply.tropical.action/request.

The session's context: `{:tab :uid :request}`, its tab, its user, and the
Ring request that created it, as its root got them.

The request is the page's, or, for a tab the server rebuilt, as after a
restart, its stream's, to the page's own URL: so its path and query are the
page's either way, and fixed for the session's life, while its headers
depend on which request it was. An action's handler reads its own request
with `co.multiply.tropical.action/request`.
sourceraw docstring

use-stateclj

(use-state k init)

Island-local state under k, starting at init. Returns [value set-value!]. set-value! may be called from any thread, typically from an action, and returns nil. The state lives as long as the island is mounted.

Island-local state under `k`, starting at `init`. Returns `[value set-value!]`.
`set-value!` may be called from any thread, typically from an action, and
returns nil. The state lives as long as the island is mounted.
sourceraw docstring

use-watchclj

(use-watch ref)
(use-watch ref select)

The current value of ref (anything supporting add-watch, or a co.multiply.tropical.signal.Signal), through select if given. The island renders again when the selected value changes, compared with =; a change that select maps to an equal value renders nothing.

select runs on the session's thread whenever ref changes, so keep it cheap.

The current value of `ref` (anything supporting `add-watch`, or a
`co.multiply.tropical.signal.Signal`), through `select` if given. The island
renders again when the selected value changes, compared with `=`; a change
that `select` maps to an equal value renders nothing.

`select` runs on the session's thread whenever `ref` changes, so keep it cheap.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close