@close-by/clay 0.2.24 → 0.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/docs/README.md +13 -8
- package/docs/api.md +11 -7
- package/docs/boot.md +1 -1
- package/docs/compatibility.md +79 -0
- package/docs/duckdb.md +1 -3
- package/docs/elements.md +7 -1
- package/docs/examples.md +18 -18
- package/docs/getting-started.md +23 -45
- package/docs/kibana.md +2 -0
- package/docs/llms.txt +9 -2
- package/docs/mobile.md +111 -0
- package/docs/ops-patterns.md +1 -1
- package/docs/reactive-let.md +7 -5
- package/package.json +5 -5
- package/src/index.ts +3 -0
package/README.md
CHANGED
|
@@ -18,4 +18,6 @@ export default function () {
|
|
|
18
18
|
bunx clay hello.ts
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Live demo: [clay.close-by.org](https://clay.close-by.org/).
|
|
22
|
+
|
|
23
|
+
Docs: shipped with the package at `node_modules/@close-by/clay/docs/`. Agent skill: `node_modules/@close-by/clay/SKILL.md` (or `@close-by/clay/skill`). See [getting-started.md](https://github.com/closeby-corp/clay/blob/main/docs/getting-started.md) after install.
|
package/docs/README.md
CHANGED
|
@@ -6,11 +6,14 @@ You write imperative `ui.*` code on the server. Clay owns a per-client element t
|
|
|
6
6
|
|
|
7
7
|
For coding agents: the repo-root [llms.txt](../llms.txt) is a short map of these guides. The [agent skill](./SKILL.md) ships with `@close-by/clay` at package root (`SKILL.md`).
|
|
8
8
|
|
|
9
|
+
[Live demo](https://clay.close-by.org/) · [Examples catalog](./examples.md)
|
|
10
|
+
|
|
9
11
|
## Guides
|
|
10
12
|
|
|
11
13
|
| Doc | Description |
|
|
12
14
|
|-----|-------------|
|
|
13
15
|
| [Getting started](./getting-started.md) | Install, `clay` CLI, create a page |
|
|
16
|
+
| [Mobile and installable apps](./mobile.md) | Phone tab bar (`mobileNav`), installable app (`pwa`, `--pwa`) |
|
|
14
17
|
| [Boot: CLI vs library](./boot.md) | Production `ui.run` path, `clientDir`, `_run.ts`, reload stubs |
|
|
15
18
|
| [Tailwind](./tailwind.md) | Zero-config utilities from page modules; optional tokens |
|
|
16
19
|
| [Sample app](./tutorial.md) | Step-by-step tasks list, then two pages + shell |
|
|
@@ -24,6 +27,7 @@ For coding agents: the repo-root [llms.txt](../llms.txt) is a short map of these
|
|
|
24
27
|
| [Elements](./elements.md) | All element types and props |
|
|
25
28
|
| [Maps](./maps.md) | `ui.map`: MapLibre markers, routes, arcs, GeoJSON, clusters; palette theming and in-place updates |
|
|
26
29
|
| [WebSocket protocol](./protocol.md) | Client ↔ server message formats |
|
|
30
|
+
| [Compatibility](./compatibility.md) | Public API promise, aliases, and compatibility checks |
|
|
27
31
|
| [Architecture](./architecture.md) | Packages, data flow, and ownership |
|
|
28
32
|
| [Examples](./examples.md) | Demo apps and patterns |
|
|
29
33
|
| [Reactive `let`](./reactive-let.md) | NiceGUI-style `let` transform (opt-in `--reactive-let`) |
|
|
@@ -34,20 +38,19 @@ For coding agents: the repo-root [llms.txt](../llms.txt) is a short map of these
|
|
|
34
38
|
|
|
35
39
|
## Quick start
|
|
36
40
|
|
|
41
|
+
The runtime packages are published to npm. The CLI includes prebuilt client assets.
|
|
42
|
+
|
|
37
43
|
```bash
|
|
38
|
-
bun
|
|
39
|
-
|
|
40
|
-
bun run clay hello.ts
|
|
44
|
+
bun add @close-by/clay-cli @close-by/clay
|
|
45
|
+
bunx clay hello.ts
|
|
41
46
|
# → http://localhost:3000
|
|
42
47
|
```
|
|
43
48
|
|
|
44
|
-
Outside the monorepo: `bun run pack:publishable` then install the `dist-pack/*.tgz` set (see [Getting started](./getting-started.md)), or `bun add @close-by/clay-cli @close-by/clay` once published. Maintainers: `bun run publish:dry` / `publish:npm` (order core → … → cli). Shipped CLI includes prebuilt client assets — no separate `build:client` after install.
|
|
45
|
-
|
|
46
49
|
```typescript
|
|
47
50
|
// hello.ts
|
|
48
51
|
import { ui } from '@close-by/clay';
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
export default function () {
|
|
51
54
|
let count = 0;
|
|
52
55
|
const label = ui.label(`Count: ${count}`);
|
|
53
56
|
|
|
@@ -65,15 +68,17 @@ ui.run(() => {
|
|
|
65
68
|
},
|
|
66
69
|
});
|
|
67
70
|
});
|
|
68
|
-
}
|
|
71
|
+
}
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
Multi-page with shell:
|
|
72
75
|
|
|
73
76
|
```bash
|
|
74
|
-
|
|
77
|
+
bunx clay ./pages --app --title "My App"
|
|
75
78
|
```
|
|
76
79
|
|
|
80
|
+
`ui.run` is library mode; see [Boot](./boot.md).
|
|
81
|
+
|
|
77
82
|
Or library-style entry (`loadPages` + `ui.run({ app })`) — see [Getting started](./getting-started.md).
|
|
78
83
|
|
|
79
84
|
## Naming
|
package/docs/api.md
CHANGED
|
@@ -93,6 +93,7 @@ ui.run({
|
|
|
93
93
|
| `css` | `string \| string[]` | | Extra CSS file path(s) served after the client bundle (absolute or cwd-relative). Override theme tokens without rebuilding the client. |
|
|
94
94
|
| `sound` | `boolean` | | Play short synthesized interface sounds by default (`false`). See [Sound](#sound). |
|
|
95
95
|
| `app` | `AppProps` | | Global dashboard shell; client keeps chrome sticky across navigate |
|
|
96
|
+
| `pwa` | `boolean \| ClayPwaConfig` | | Installable app: web manifest, icons, and a service worker that caches the app shell. See [Mobile and installable apps](./mobile.md#installable-app-pwa) |
|
|
96
97
|
| `authSecret` | `string` | | Enables signed auth cookies (`POST`/`DELETE /auth/session`), `ui.establishAuthSession` / `ui.clearAuthSession`, and default `resolveUserId` from the cookie |
|
|
97
98
|
| `authCookieMaxAgeSec` | `number` | `43200` (12h) | Auth cookie Max-Age |
|
|
98
99
|
| `sessionIdleMs` | `number` | | Optional: clear auth + redirect after this idle time |
|
|
@@ -999,7 +1000,7 @@ registerFlowEdgeTypes({ labeled: BaduiLabeledEdge });
|
|
|
999
1000
|
|
|
1000
1001
|
Then reference those keys from the server: `flow.node({ nodeType: 'fancy', … })` / edge `type: 'labeled'`, and optionally list them on the flow as `customNodeTypes` / `customEdgeTypes`.
|
|
1001
1002
|
|
|
1002
|
-
See Flow
|
|
1003
|
+
See the Flow demos (`/examples/flow` for 1–2, `/examples/flow-editing` for 3–4) for richer patterns:
|
|
1003
1004
|
|
|
1004
1005
|
1. **ETL pipeline** — select/switch/progress/buttons inside nodes; labeled smoothstep edges + dagre auto-layout
|
|
1005
1006
|
2. **Branching approval** — multi-handle triage (`yes` / `no` sources), rating + badges
|
|
@@ -1822,7 +1823,7 @@ onClick: async () => {
|
|
|
1822
1823
|
| `ui.redirect(url)` | `void` | Full-page navigation in the current tab (`location.assign`) — for sign-in routes / external pages; use `ui.navigate` for app pages |
|
|
1823
1824
|
| `ui.theme.set(mode)` | `void` | Push `light` \| `dark` \| `system` to this client |
|
|
1824
1825
|
| `ui.theme.get()` | `ThemeMode \| null` | Last value set on this session |
|
|
1825
|
-
| `ui.theme.palette(name)` | `void` | Switch colour palette for this client (`kiln`, `cobalt`, `ocean`, `forest`, `orchid`, `citrus`, `graphite`, `neon`, `sky`, `navy`, `indigo`, `denim`, `midnight`, or a custom one); remembered across reloads |
|
|
1826
|
+
| `ui.theme.palette(name)` | `void` | Switch colour palette for this client (`kiln`, `cobalt`, `ocean`, `forest`, `orchid`, `citrus`, `graphite`, `chalk`, `brutal`, `terminal`, `editorial`, `bubble`, `soothe`, `nebula`, `studio`, `iris`, `ledger`, `contrast`, `dim`, `neon`, `sky`, `navy`, `indigo`, `denim`, `midnight`, or a custom one); remembered across reloads |
|
|
1826
1827
|
| `ui.theme.getPalette()` | `ThemePalette \| null` | Last palette set, else the one the client reported on connect |
|
|
1827
1828
|
| `ui.theme.palettes` | `readonly string[]` | Built-in palette names |
|
|
1828
1829
|
| `ui.sound.set(on)` | `void` | Turn automatic interface sounds on/off for this client; remembered across reloads. See [Sound](#sound) |
|
|
@@ -1832,6 +1833,7 @@ onClick: async () => {
|
|
|
1832
1833
|
| `ui.runJavaScript(code)` | `void` | Eval trusted snippet in the browser |
|
|
1833
1834
|
| `ui.scroll.to(opts)` | `void` | Scroll window (`top` / `bottom` / px) |
|
|
1834
1835
|
| `ui.scroll.intoView(selector, opts?)` | `void` | `Element.scrollIntoView` via selector |
|
|
1836
|
+
| `ui.onDispose(callback)` | `void` | Register synchronous cleanup during a page build or event; runs once on disconnect, navigation, or reconnect page replacement. Requires an active session, so call it synchronously during the build or at the start of a handler (not after an `await`); callbacks run in registration order and errors are logged without stopping other cleanup. |
|
|
1835
1837
|
| `ui.timer(interval, callback, options?)` | `TimerHandle` | Session-scoped timer; `interval` in **seconds**; `{ once? }`; `.activate()` / `.deactivate()` / `.cancel()` |
|
|
1836
1838
|
| `ui.upload(props?)` | `Element` | Multipart HTTP upload; see below |
|
|
1837
1839
|
| `ui.storage.tab` | | Per-browser-tab map (sessionStorage mirror) |
|
|
@@ -1893,9 +1895,10 @@ User storage requires a `userId` on the session. The built-in client sends an an
|
|
|
1893
1895
|
const messages = ui.storage.app.create<Message[]>('chatMessages', []);
|
|
1894
1896
|
const online = ui.storage.app.create<string[]>('onlineUsers', [], { persist: false });
|
|
1895
1897
|
|
|
1896
|
-
|
|
1898
|
+
// Inside a page builder, unsubscribe when this page is disposed.
|
|
1899
|
+
ui.onDispose(messages.subscribe((list) => {
|
|
1897
1900
|
// update UI for this session
|
|
1898
|
-
});
|
|
1901
|
+
}));
|
|
1899
1902
|
|
|
1900
1903
|
await messages.set([...(await messages.get()), newMessage]);
|
|
1901
1904
|
await messages.update((prev) => [...prev, newMessage]);
|
|
@@ -1909,12 +1912,12 @@ await messages.update((prev) => [...prev, newMessage]);
|
|
|
1909
1912
|
| `storage.app.create(key, initial, options?)` | Get or create named store; `{ persist?: boolean }` |
|
|
1910
1913
|
| `.get()` | `Promise<T>` — load from adapter when persisted |
|
|
1911
1914
|
| `.set(v)` / `.update(fn)` | `Promise<void>` — save when persisted |
|
|
1912
|
-
| `.subscribe(listener)` | Listen for changes |
|
|
1915
|
+
| `.subscribe(listener)` | Listen for changes; returns an unsubscribe function. Pass it to `ui.onDispose` for page-scoped listeners; subscriptions created outside a session remain process-wide. |
|
|
1913
1916
|
| `storage.app.clearAll()` | Test helper (clears app stores only) |
|
|
1914
1917
|
| `storage.clearAll()` | Test helper (clears app stores + user bags + both adapters) |
|
|
1915
1918
|
| `createMemoryPersistence()` | In-memory adapter for tests (`@close-by/clay-core`) |
|
|
1916
1919
|
| `createFilePersistence({ dir })` | File-backed adapter (`@close-by/clay-persistence-file`) |
|
|
1917
|
-
| `createRedisPersistence({ client, keyPrefix? })` | Redis adapter (`@close-by/clay-persistence-redis
|
|
1920
|
+
| `createRedisPersistence({ client, keyPrefix? })` | Redis adapter (`@close-by/clay-persistence-redis`; monorepo only — not published to npm yet) — multi-process app/user bags; keep WS sticky |
|
|
1918
1921
|
|
|
1919
1922
|
`PersistenceAdapter`:
|
|
1920
1923
|
|
|
@@ -1960,6 +1963,7 @@ Sidebar layout for multi-page apps. Prefer `ui.run({ app })` so every page inher
|
|
|
1960
1963
|
| `user` | `AppUser` | Optional user menu (`name`, `email`, `avatar?`) |
|
|
1961
1964
|
| `variant` | `'sidebar' \| 'inset'` | Shell layout variant |
|
|
1962
1965
|
| `collapsible` | `'offcanvas' \| 'icon' \| 'none'` | Sidebar collapse behavior |
|
|
1966
|
+
| `mobileNav` | `'tabs' \| 'menu'` | Phone navigation. Default `'tabs'` (bottom tab bar); `'menu'` keeps only the sidebar sheet. See [Mobile](./mobile.md#keep-only-the-menu) |
|
|
1963
1967
|
| `className` | `string` | Extra classes on the shell |
|
|
1964
1968
|
|
|
1965
1969
|
`AppNavItem`: `{ label, href, icon?, description?, items? }` — `icon` is a Lucide kebab-case name (full set; e.g. `home`, `gauge`, `sparkles`). Nested `items` render as collapsible sub-links in the sidebar.
|
|
@@ -2114,7 +2118,7 @@ form.name = 'Ada'; // persisted
|
|
|
2114
2118
|
ui.draft.clear('formDemo'); // drop storage key; reset the object yourself if needed
|
|
2115
2119
|
```
|
|
2116
2120
|
|
|
2117
|
-
See
|
|
2121
|
+
See Forms (`/examples/forms`).
|
|
2118
2122
|
|
|
2119
2123
|
### `ui.auto(fn)`
|
|
2120
2124
|
|
package/docs/boot.md
CHANGED
|
@@ -98,7 +98,7 @@ If you run **`tsc --noEmit`** (or IDE typecheck) on the app repo, exclude reload
|
|
|
98
98
|
|
|
99
99
|
Without that exclude, a leftover stub from a crashed dev session can produce spurious TS errors until you delete `.clay-reload/`. Clay apps that only typecheck `pages/` and `src/` rarely need more; monorepos should exclude `.clay-reload` at the app root `tsconfig.json`.
|
|
100
100
|
|
|
101
|
-
Legacy `_clay-reload-*.ts` files under `pages/` (pre-0.2.5) should be deleted; modern Clay writes
|
|
101
|
+
Legacy `_clay-reload-*.ts` files under `pages/` (pre-0.2.5) should be deleted; modern Clay writes to `<cwd>/.clay-reload/`, inside the project tree but outside `pages/`.
|
|
102
102
|
|
|
103
103
|
## Reactive-let
|
|
104
104
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Compatibility
|
|
2
|
+
|
|
3
|
+
An app written for a Clay release keeps working on later releases unchanged.
|
|
4
|
+
If an app breaks after a Clay update, that is a bug in Clay unless the release
|
|
5
|
+
notes list the change under **Breaking**.
|
|
6
|
+
|
|
7
|
+
## What this covers
|
|
8
|
+
|
|
9
|
+
The promise covers the public surface apps use:
|
|
10
|
+
|
|
11
|
+
- `ui.*` functions and namespaces, including `ui.ai`, `ui.storage`, and `ui.theme`.
|
|
12
|
+
- Element methods such as `setText`, `classes`, and `bindValue`.
|
|
13
|
+
- Package exports, including exports moved to another module.
|
|
14
|
+
- Factory option names and element prop names.
|
|
15
|
+
- Event names and their payloads.
|
|
16
|
+
- Element wire types and protocol operations.
|
|
17
|
+
- CLI flags, defaults, and behavior.
|
|
18
|
+
|
|
19
|
+
The client and server ship together, but the wire format still matters.
|
|
20
|
+
Apps use `ui.runJavaScript` and custom clients, and old browser tabs reconnect
|
|
21
|
+
to new servers. Updating the server must account for those callers too.
|
|
22
|
+
|
|
23
|
+
## Rules for changes
|
|
24
|
+
|
|
25
|
+
1. What a release shipped stays available in later releases, unless its removal
|
|
26
|
+
is explicitly listed under Breaking in the release notes.
|
|
27
|
+
2. A rename keeps the old name as an alias of the same implementation.
|
|
28
|
+
Mark the old name with JSDoc `@deprecated Use newName.` so editors can guide
|
|
29
|
+
callers to the replacement. Moving an export keeps it in the old module too.
|
|
30
|
+
3. Types only widen: options gain optional members, unions gain cases, and
|
|
31
|
+
functions gain optional trailing parameters or overloads. Apps should handle
|
|
32
|
+
values they do not know, for example with a default branch in a switch.
|
|
33
|
+
4. Behavior does not change silently. Defaults, units, payload shapes, and
|
|
34
|
+
callback order are part of the contract even when the names stay the same.
|
|
35
|
+
|
|
36
|
+
For example, a renamed helper keeps a direct alias:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
export function newName(text: string) {
|
|
40
|
+
return ui.label(text);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** @deprecated Use newName. */
|
|
44
|
+
export const oldName = newName;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## How we check it
|
|
48
|
+
|
|
49
|
+
[compat/surface.json](../compat/surface.json) records the public names.
|
|
50
|
+
[packages/ui/src/compat.test.ts](../packages/ui/src/compat.test.ts) compares that
|
|
51
|
+
record with the current source as part of `bun run test`.
|
|
52
|
+
Missing names fail the test; new names also fail until the record is updated.
|
|
53
|
+
|
|
54
|
+
The record contains:
|
|
55
|
+
|
|
56
|
+
- `ui.<path>`: functions and plain-object namespaces, up to three levels deep.
|
|
57
|
+
Session-created values and getters requiring a session are excluded.
|
|
58
|
+
- `export:<package-name>:<name>`: runtime exports from Clay, core, components,
|
|
59
|
+
server, auth, and file persistence. Type-only exports are absent at runtime.
|
|
60
|
+
- `element.<method>`: methods on the core Element prototype chain.
|
|
61
|
+
- `class.<ExportName>.<method>`: own methods of other Element classes exported
|
|
62
|
+
by `@close-by/clay`.
|
|
63
|
+
- `wire.<type>`: element types handled by the client renderer.
|
|
64
|
+
- `op.server.<op>`, `op.client.<op>`, and `op.patch.<op>`: protocol operations.
|
|
65
|
+
- `cli.<flag>`: CLI flags, including short aliases.
|
|
66
|
+
|
|
67
|
+
After adding public API, run `bun scripts/compat-surface.ts --write` and commit
|
|
68
|
+
`compat/surface.json` with the implementation. Review its diff before committing.
|
|
69
|
+
For a rename, restore the old alias before updating the record.
|
|
70
|
+
For an intentional removal, list it under Breaking in the release notes and
|
|
71
|
+
regenerate the record. Run `bun test packages/ui` to check it.
|
|
72
|
+
Run `bun scripts/compat-surface.ts` for counts without changing the record.
|
|
73
|
+
|
|
74
|
+
This check records names, not full signatures or behavior. Option and prop names,
|
|
75
|
+
event payload shapes, defaults, units, and callback order are not checked
|
|
76
|
+
automatically yet. Reviewers check these, along with type compatibility.
|
|
77
|
+
Native and network adapter packages are outside the mechanical record.
|
|
78
|
+
|
|
79
|
+
Practice adapted from [Native Shell's compatibility policy](https://nsh.dev/docs/compatibility).
|
package/docs/duckdb.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Multi-database DuckDB wrapper: named instances, `ATTACH` for DuckDB/SQLite/Postgres/MySQL, and insert/update/delete helpers.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
bun add @close-by/clay-duckdb # or depend on workspace:* inside this monorepo
|
|
7
|
-
```
|
|
5
|
+
**Monorepo only — not published to npm yet.** Depend on `@close-by/clay-duckdb` with `workspace:*` inside this monorepo.
|
|
8
6
|
|
|
9
7
|
## Connect multiple databases
|
|
10
8
|
|
package/docs/elements.md
CHANGED
|
@@ -201,6 +201,12 @@ Server patches still reconcile when `props.value` changes (e.g. `draft.text = ''
|
|
|
201
201
|
|
|
202
202
|
Field `error` is **server-owned** (via initial props, `.setError`, or `ui.validate`). It is not optimistic — the client shows `props.error` after `updateProps` patches.
|
|
203
203
|
|
|
204
|
+
## On phones
|
|
205
|
+
|
|
206
|
+
On phone-sized touch screens (max-width 767px and coarse pointer), `select` uses the native picker
|
|
207
|
+
and `date` uses the native date picker. `dropdownmenu` and `combobox` open bottom sheets.
|
|
208
|
+
Props and events stay the same. Desktop rendering is unchanged.
|
|
209
|
+
|
|
204
210
|
## Styling
|
|
205
211
|
|
|
206
212
|
Prefer Tailwind utility classes via `.classes(...)`:
|
|
@@ -213,4 +219,4 @@ Layout `gap` uses a small numeric scale mapped to `gap-0` … `gap-8` in the cli
|
|
|
213
219
|
|
|
214
220
|
The client ships the "kiln" theme — warm neutrals, a fired-clay primary, vivid chart colours, light + dark (ShadCN-style CSS variables in `packages/client/src/index.css`, Plus Jakarta Sans bundled). Override tokens at runtime with `ui.run({ css: './globals.css' })`; Clay extras include `--clay-brand-from` / `--clay-brand-to` and the `clay-brand-gradient`, `clay-brand-text`, `clay-ambient` classes.
|
|
215
221
|
|
|
216
|
-
|
|
222
|
+
Twenty-four more palettes ship alongside kiln — `cobalt`, `ocean`, `forest`, `orchid`, `citrus`, `graphite`, `chalk`, `brutal`, `terminal`, `editorial`, `bubble`, `soothe`, `nebula`, `studio`, `iris`, `ledger`, `contrast`, `dim`, `neon`, plus the blues `sky`, `navy`, `indigo`, `denim`, `midnight` (each light + dark, in `packages/client/src/palettes.css`). Pick the app default with `ui.run({ palette: 'ocean' })` or switch per session with `ui.theme.palette('neon')`. `chalk`, `brutal`, `terminal`, `editorial`, `bubble`, `soothe`, `nebula`, `studio`, `iris`, `ledger`, `contrast`, and `dim` also change font, radius and shadows. `contrast` is the accessibility option, with high-contrast colours and explicit focus indicators. Custom palettes: define `:root[data-palette="mine"] { … }` and `:root.dark[data-palette="mine"] { … }` in your `css` file, then `ui.theme.palette('mine')`.
|
package/docs/examples.md
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
Demo entry: [`apps/demo/src/main.ts`](../apps/demo/src/main.ts)
|
|
4
4
|
Pages: [`apps/demo/src/examples/`](../apps/demo/src/examples/) (auto-loaded via `ui.loadPages`)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Live: https://clay.close-by.org/ · locally in this repo: `bun run build:client && bun run demo` (or `bun run demo:cli`), then open http://localhost:4000.
|
|
7
|
+
|
|
8
|
+
## Standalone apps
|
|
9
|
+
|
|
10
|
+
- [`examples/tailwind-app/`](../examples/tailwind-app/): Standalone app with Tailwind utilities.
|
|
7
11
|
|
|
8
12
|
## Sidebar groups
|
|
9
13
|
|
|
10
|
-
Each page sets `group` / `groupIcon` in its `pageMeta`, so the sidebar and the home page's catalog share one structure: **Start here** (themes, fill layout, counter, todo, kitchen sink) → **Reactivity** → **Data** → **Maps** (gallery, delivery tracker, store locator, globe, uptime monitor) → **Forms & controls** → **
|
|
14
|
+
Each page sets `group` / `groupIcon` in its `pageMeta`, so the sidebar and the home page's catalog share one structure: **Start here** (themes, fill layout, counter, todo, kitchen sink) → **Reactivity** → **Data** → **Maps** (map gallery, delivery tracker, store locator, globe, uptime monitor) → **Forms & controls** → **Components** → **Apps** (including List, Kanban, Gantt, Flow, and Ops console) → **Account**. Order within a group is `pageMeta.order`.
|
|
11
15
|
|
|
12
16
|
## Catalog
|
|
13
17
|
|
|
@@ -16,34 +20,30 @@ Each page sets `group` / `groupIcon` in its `pageMeta`, so the sidebar and the h
|
|
|
16
20
|
| `/` | `Home.ts` | Landing page: hero, live counter + source side by side (`ui.codeBlock`), feature grid, catalog grouped via `ui.navFromPages()` (same as sidebar) |
|
|
17
21
|
| `/examples/counter` | `Counter.ts` | `setText`, `refreshable`, button variants |
|
|
18
22
|
| `/examples/todo` | `Todo.ts` | `reactive`, `bindValue`, list `refreshable`, filters |
|
|
23
|
+
| `/examples/reactive-let-orders` | `ReactiveLetOrders.ts` | Order filters and master–detail views with `ui.state` / `ui.auto`, plus the equivalent reactive `let` source (runnable copy: `examples/reactive-let-orders.ts` with the Clay CLI) |
|
|
19
24
|
| `/examples/chat` | `Chat.ts` | `ui.storage.app` (persisted messages + ephemeral presence), async `get`/`set` |
|
|
20
25
|
| `/examples/ai` | `AiDemo.ts` | `ui.ai.*` gallery — chat, prompt bar, loader/thinking, agent cards, diff/insights/fine-tune (static props; no model runtime) |
|
|
21
26
|
| `/examples/upload` | `FileUpload.ts` | `ui.upload` button + dropzone (progress/abort/size), `ui.storage.tab` / `user`, `ui.download`, `ui.clipboard` |
|
|
22
27
|
| `/examples/dashboard` | `Dashboard.ts` | `stat`, `areaChart`, full-chrome `dataTable` (views, editors, detail drawer) |
|
|
23
28
|
| `/examples/datatable` | `DataTableDemo.ts` | Multi-sort (Shift+click / badges), footer aggregates + a11y hints, column pin, remote filter/sort + pagination; density/zebra, editors (Enter/Esc + focus restore), resize, virtualization (≥40, coexists with reorder via windowed drop targets); facets, bulk, collapse/expand, loading/empty; `ui.table` sugar |
|
|
24
|
-
| `/examples/
|
|
25
|
-
| `/examples/
|
|
26
|
-
| `/examples/
|
|
27
|
-
| `/examples/reui-batch-7` | `ReuiBatch7Demo.ts` | ReUI batch 7: `inputGroup`, `toggle`, `descriptionList`, `staticTable`, `aspectRatio`, `itemList`, `checkboxGroup` |
|
|
28
|
-
| `/examples/charts` | `ChartDemo.ts` | `ui.chart.*`, `ui.sparkline`, composed/scatter charts |
|
|
29
|
+
| `/examples/ops-console` | `OpsConsoleDemo.ts` | Order triage: `filterBar` → `feedList` → `descriptionList` / `staticTable` |
|
|
30
|
+
| `/examples/charts` | `ChartDemo.ts` | `ui.chart.*`, `ui.sparkline`, composed/scatter charts, `stat` + sparkline |
|
|
31
|
+
| `/examples/live-table` | `LiveTableStress.ts` | High-frequency table updates, configurable row count, and live price changes |
|
|
29
32
|
| `/examples/live-charts` | `LiveCharts.ts` | Live charts: `appendData` sliding windows, `setData` tweens, `upsertData` buckets, live gauge and sparklines |
|
|
30
|
-
| `/examples/slider-demo` | `SliderDemo.ts` | Slider, checkbox, select + bindings |
|
|
31
33
|
| `/examples/themes` | `ThemesDemo.ts` | Palette gallery: `ui.theme.palette`, light/dark, component preview |
|
|
32
34
|
| `/examples/layout` | `LayoutDemo.ts` | Fill layout: `fillViewport`, `grow`, `scroll`, `ui.grid` |
|
|
33
|
-
| `/examples/feedback` | `FeedbackDemo.ts` |
|
|
34
|
-
| `/examples/
|
|
35
|
+
| `/examples/feedback` | `FeedbackDemo.ts` | Feedback & status: alert, spinner, progress, `runJavaScript` / scroll, live timer clock, notice, empty, timeline |
|
|
36
|
+
| `/examples/forms` | `FormDemo.ts` | Forms: validation, `ui.draft`, slider, checkbox, select, rating, color picker, tags, field, numberField, phoneInput, nativeSelect, inputGroup, toggle, checkboxGroup, dateRange, stepper |
|
|
35
37
|
| `/examples/auth` | `Auth.ts` (+ login/admin/change-password) | Signed cookie session, hashed passwords, login lockout, role-gated admin + audit log |
|
|
36
|
-
| `/examples/
|
|
37
|
-
| `/examples/
|
|
38
|
-
| `/examples/
|
|
39
|
-
| `/examples/controls` | `ControlsDemo.ts` | Menubar (submenu/checkbox/radio), command dialog + inline, carousel, resizable, scroll-area, `ui.state` / `ui.auto` |
|
|
40
|
-
| `/examples/controls-extra` | `ControlsExtra.ts` | `ui.codeBlock` (Shiki), `ui.tree` |
|
|
41
|
-
| `/examples/media-extra` | `MediaExtra.ts` | `ui.relativeTime`, `ui.qrCode`, `ui.imageZoom`, `ui.imageCrop` |
|
|
38
|
+
| `/examples/overlays` | `OverlaysDemo.ts` | Breadcrumb, dropdown/context menu, hover card, popover, dialog/sheet/drawer, `dialogStack` multi-step stacked modal |
|
|
39
|
+
| `/examples/navigation` | `NavigationDemo.ts` | Navigation & layout: menubar, command, carousel, resizable, scrollArea, keybind, viewportEnter, navigationMenu, buttonGroup, pagination, aspectRatio |
|
|
40
|
+
| `/examples/content` | `ContentDemo.ts` | Content & media: markdown, html, codeBlock, descriptionList, staticTable, itemList, tree, image, imageZoom, imageCrop, qrCode, iframe, relativeTime, eventCalendar |
|
|
42
41
|
| `/examples/editor` | `EditorDemo.ts` | `ui.editor` HTML + Markdown side-by-side, bindValue |
|
|
43
42
|
| `/examples/kanban` | `KanbanDemo.ts` | `ui.kanban` swimlanes, card detail drawer, element-owned `cardMove`/`cardSelect`, reset via APIs |
|
|
44
|
-
| `/examples/list` | `ListDemo.ts` | `ui.list`
|
|
43
|
+
| `/examples/list` | `ListDemo.ts` | Apps: `ui.list` groups, drag to reorder, reset via `setGroups` |
|
|
45
44
|
| `/examples/gantt` | `GanttDemo.ts` | `ui.gantt` owned rows/dates/markers/deps, cross-row drag, header double-click markers, `itemMove` / `markerAdd` settle |
|
|
46
|
-
| `/examples/flow` | `FlowDemo.ts` |
|
|
45
|
+
| `/examples/flow` | `FlowDemo.ts` | `ui.flow` ETL pipeline with in-node controls, labeled edges and dagre auto-layout; multi-handle approval branches |
|
|
46
|
+
| `/examples/flow-editing` | `FlowEditingDemo.ts` | Fan-in/out with `addNode` dynamic stages; group/`parentId` nesting |
|
|
47
47
|
| `/examples/data-clients` | `DataClientsDemo.ts` | DuckDB / Kibana / ClickHouse integration story (mock-friendly) |
|
|
48
48
|
| `/examples/maps` | `MapsGallery.ts` | `ui.map` gallery: markers and popups, routes, arcs, choropleth, clusters, compact analytics map |
|
|
49
49
|
| `/examples/delivery-tracker` | `DeliveryTracker.ts` | `ui.map` route progress and courier marker: `updateRoute` / `upsertMarker` on a timer, `fill` layout |
|
package/docs/getting-started.md
CHANGED
|
@@ -6,13 +6,21 @@
|
|
|
6
6
|
- Node-compatible OS (macOS / Linux / WSL)
|
|
7
7
|
- For local tarball installs: npm (links co-installed `file:` packages; Bun may try the registry for rewritten versions)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Install from npm
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun add @close-by/clay-cli @close-by/clay
|
|
13
|
+
# transitive: core, components, server, persistence-file
|
|
14
|
+
# optional: bun add @close-by/clay-auth
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `bun init`’s tsconfig or set `"extends": "@close-by/clay/page-tsconfig"` in your `tsconfig.json`.
|
|
10
18
|
|
|
11
19
|
Consumers import `@close-by/clay` and run apps with the `clay` binary from `@close-by/clay-cli`. The CLI ships prebuilt Vite assets (`client-dist`); you do **not** need `@close-by/clay-client` or a monorepo `build:client`.
|
|
12
20
|
|
|
13
21
|
Walkthrough (tasks list → two pages + `--app`): [Sample app](./tutorial.md).
|
|
14
22
|
|
|
15
|
-
###
|
|
23
|
+
### Contributors: local packs
|
|
16
24
|
|
|
17
25
|
```bash
|
|
18
26
|
# In the Clay checkout:
|
|
@@ -22,38 +30,21 @@ bun run pack:publishable # build:client + bun pm pack → dist-pack/*.tgz
|
|
|
22
30
|
|
|
23
31
|
# In your app directory:
|
|
24
32
|
npm install \
|
|
25
|
-
/path/to/clay/dist-pack/close-by-clay-core
|
|
26
|
-
/path/to/clay/dist-pack/close-by-clay-auth
|
|
27
|
-
/path/to/clay/dist-pack/close-by-clay-compiler
|
|
28
|
-
/path/to/clay/dist-pack/close-by-clay-persistence-file
|
|
29
|
-
/path/to/clay/dist-pack/close-by-clay-components
|
|
30
|
-
/path/to/clay/dist-pack/close-by-clay-server
|
|
31
|
-
/path/to/clay/dist-pack/close-by-clay
|
|
32
|
-
/path/to/clay/dist-pack/close-by-clay-cli
|
|
33
|
+
'/path/to/clay/dist-pack/close-by-clay-core-<version>.tgz' \
|
|
34
|
+
'/path/to/clay/dist-pack/close-by-clay-auth-<version>.tgz' \
|
|
35
|
+
'/path/to/clay/dist-pack/close-by-clay-compiler-<version>.tgz' \
|
|
36
|
+
'/path/to/clay/dist-pack/close-by-clay-persistence-file-<version>.tgz' \
|
|
37
|
+
'/path/to/clay/dist-pack/close-by-clay-components-<version>.tgz' \
|
|
38
|
+
'/path/to/clay/dist-pack/close-by-clay-server-<version>.tgz' \
|
|
39
|
+
'/path/to/clay/dist-pack/close-by-clay-<version>.tgz' \
|
|
40
|
+
'/path/to/clay/dist-pack/close-by-clay-cli-<version>.tgz'
|
|
33
41
|
```
|
|
34
42
|
|
|
35
|
-
Install **all** runtime tarballs together so `@close-by/clay` and `@close-by/clay
|
|
36
|
-
|
|
37
|
-
### When published to npm
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
bun add @close-by/clay-cli @close-by/clay
|
|
41
|
-
# transitive: core, components, server, persistence-file
|
|
42
|
-
# optional: bun add @close-by/clay-auth
|
|
43
|
-
```
|
|
43
|
+
Replace `<version>` with the packed version. Install **all** runtime tarballs together so `@close-by/clay` and `@close-by/clay-*@<version>` resolve from the co-installed packs.
|
|
44
44
|
|
|
45
45
|
### Publishing to npm (maintainers)
|
|
46
46
|
|
|
47
|
-
Runtime packages are scoped
|
|
48
|
-
|
|
49
|
-
1. `@close-by/clay-core`
|
|
50
|
-
2. `@close-by/clay-auth`
|
|
51
|
-
3. `@close-by/clay-compiler`
|
|
52
|
-
4. `@close-by/clay-persistence-file`
|
|
53
|
-
5. `@close-by/clay-components`
|
|
54
|
-
6. `@close-by/clay-server`
|
|
55
|
-
7. `@close-by/clay`
|
|
56
|
-
8. `@close-by/clay-cli`
|
|
47
|
+
Runtime packages are scoped and public. The canonical package list and dependency publish order are in [`scripts/publishable.ts`](../scripts/publishable.ts).
|
|
57
48
|
|
|
58
49
|
```bash
|
|
59
50
|
# In the Clay checkout:
|
|
@@ -65,20 +56,6 @@ bun run publish:npm # pack + validate + real npm publish (same or
|
|
|
65
56
|
# Re-run is safe: versions already on npm are skipped.
|
|
66
57
|
```
|
|
67
58
|
|
|
68
|
-
Equivalent manual flow from packed tarballs:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
bun run pack:publishable
|
|
72
|
-
npm publish ./dist-pack/close-by-clay-core-0.1.0.tgz --access public
|
|
73
|
-
npm publish ./dist-pack/close-by-clay-auth-0.1.0.tgz --access public
|
|
74
|
-
npm publish ./dist-pack/close-by-clay-compiler-0.1.0.tgz --access public
|
|
75
|
-
npm publish ./dist-pack/close-by-clay-persistence-file-0.1.0.tgz --access public
|
|
76
|
-
npm publish ./dist-pack/close-by-clay-components-0.1.0.tgz --access public
|
|
77
|
-
npm publish ./dist-pack/close-by-clay-server-0.1.0.tgz --access public
|
|
78
|
-
npm publish ./dist-pack/close-by-clay-0.1.0.tgz --access public
|
|
79
|
-
npm publish ./dist-pack/close-by-clay-cli-0.1.0.tgz --access public
|
|
80
|
-
```
|
|
81
|
-
|
|
82
59
|
`publish:dry` checks each tarball for rewritten deps (no `workspace:*`), `license` / README / LICENSE, CLI `bin` + `client-dist`, `@close-by/clay` `docs/` (via `prepack` → `scripts/sync-docs.ts`), then runs `npm publish --dry-run`. `publish:npm` looks up each `name@version` on the registry and **skips** if it is already published (resume after a partial failure). Use `--skip-pack` to reuse an existing `dist-pack/`: `bun scripts/publish-from-pack.ts --dry-run --skip-pack`.
|
|
83
60
|
|
|
84
61
|
After install, version-matched docs live at `node_modules/@close-by/clay/docs/` (import paths like `@close-by/clay/docs/api.md` with Bun, or `resolveClayDocsDir` from `@close-by/clay/docs-dir`).
|
|
@@ -149,6 +126,7 @@ bun run clay ./pages --app --title "My App"
|
|
|
149
126
|
| `-p, --port` | Port (default `3000`) |
|
|
150
127
|
| `-t, --title` | HTML / shell title |
|
|
151
128
|
| `--app` | Dashboard shell + nav from discovered pages |
|
|
129
|
+
| `--pwa` | Installable app: manifest + service worker ([Mobile and installable apps](./mobile.md)) |
|
|
152
130
|
| `--no-open` | Do not open the browser |
|
|
153
131
|
| `--reload` | Restart on file changes (`bun --watch`); opens the browser once; prints `↻ clay: reloading…` and re-imports pages (clears `require.cache`) |
|
|
154
132
|
| `--reactive-let` | Enable compile-time reactive `let` Bun loader (**off** by default; still needs `// @clay-reactive` or `"use reactive";` in source) |
|
|
@@ -181,7 +159,7 @@ Open:
|
|
|
181
159
|
- http://localhost:4000 — home with links to examples
|
|
182
160
|
- http://localhost:4000/examples/counter
|
|
183
161
|
- http://localhost:4000/examples/todo
|
|
184
|
-
- http://localhost:4000/examples/
|
|
162
|
+
- http://localhost:4000/examples/forms
|
|
185
163
|
- http://localhost:4000/examples/auth
|
|
186
164
|
|
|
187
165
|
| Script | What it does |
|
|
@@ -201,7 +179,7 @@ Open:
|
|
|
201
179
|
- Source packages keep `workspace:*` for the monorepo; `bun pm pack` / publish rewrites them to the package version.
|
|
202
180
|
- `@close-by/clay-client` is **private**; only its Vite `dist` is copied into `@close-by/clay-cli` (`copy-client` / CLI `prepack`, also invoked by `build:client`).
|
|
203
181
|
- Root stays `private: true`. Each runtime package ships `license`, `README.md`, `LICENSE`, and `publishConfig.access: public`.
|
|
204
|
-
-
|
|
182
|
+
- Publishable packages and dependency order: [`scripts/publishable.ts`](../scripts/publishable.ts).
|
|
205
183
|
|
|
206
184
|
## Library mode (multi-page entrypoint)
|
|
207
185
|
|
package/docs/kibana.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Authenticated (or internal) Kibana REST client: arbitrary API calls, Elasticsearch via console proxy or `/elasticsearch`, and `search_after` pagination for walking every matching log line.
|
|
4
4
|
|
|
5
|
+
**Monorepo only — not published to npm yet.** Depend on `@close-by/clay-kibana` with `workspace:*` inside this monorepo.
|
|
6
|
+
|
|
5
7
|
```typescript
|
|
6
8
|
import { Kibana } from '@close-by/clay-kibana';
|
|
7
9
|
|
package/docs/llms.txt
CHANGED
|
@@ -11,6 +11,8 @@ Notes for agents:
|
|
|
11
11
|
- Update existing nodes with `setText` / `setValue` / bindings. Prefer `ui.state` + `ui.auto` (+ `ui.timer`) for async/live UIs; `ui.refreshable` for simple one-shot rebuilds. Shared or persisted state: `ui.storage` (`tab` / `user` / `app`).
|
|
12
12
|
- Never use `window` / `navigator` in page code — use `ui.clipboard`, `ui.setUrlHash`, `ui.getUrlSearch` / `ui.updateUrlSearch`, `ui.openExternal`.
|
|
13
13
|
- Runtime is Bun. In this repo: `bun run build:client`, then `bun run demo` (http://localhost:4000) or `bun run clay hello.ts`.
|
|
14
|
+
- Installable app is opt-in: `ui.run({ pwa: true })` or `clay ./pages --app --pwa` adds a manifest and an app-shell service worker (see docs/mobile.md).
|
|
15
|
+
- On phones the `app` nav becomes a bottom tab bar; `app: { mobileNav: 'menu' }` keeps only the sidebar sheet.
|
|
14
16
|
- `ui.ai.*` is visual primitives only — no model or streaming runtime.
|
|
15
17
|
- Agent skill (Cursor / compatible tools): `@close-by/clay/SKILL.md` — copy to `.cursor/skills/clay/SKILL.md` or read from `node_modules` when installed.
|
|
16
18
|
|
|
@@ -20,6 +22,7 @@ Notes for agents:
|
|
|
20
22
|
- [Getting started](docs/getting-started.md): Install, `clay` CLI, first app, publishing
|
|
21
23
|
- [Boot](docs/boot.md): CLI vs library, `clientDir`, `_run.ts`, reload stubs
|
|
22
24
|
- [Tailwind](docs/tailwind.md): Scanned utilities + `ui.run({ css })`
|
|
25
|
+
- [Mobile and installable apps](docs/mobile.md): Phone tab bar (`mobileNav`), installable PWA (`ui.run({ pwa })`, `--pwa`)
|
|
23
26
|
- [Sample app](docs/tutorial.md): Step-by-step tasks list, then two pages + shell
|
|
24
27
|
- [Concepts](docs/concepts.md): Sessions, element tree, patches, refreshable, bindings, storage
|
|
25
28
|
- [Browser APIs](docs/browser-apis.md): `ui.clipboard` / hash / `openExternal` — no `window` in page code
|
|
@@ -30,6 +33,8 @@ Notes for agents:
|
|
|
30
33
|
|
|
31
34
|
## Examples
|
|
32
35
|
|
|
36
|
+
- [Live demo](https://clay.close-by.org/): Browse the running examples
|
|
37
|
+
|
|
33
38
|
- [Examples catalog](docs/examples.md): Demo routes and patterns
|
|
34
39
|
- [Demo pages](apps/demo/src/examples/): Runnable `ui.page` modules
|
|
35
40
|
|
|
@@ -37,9 +42,11 @@ Notes for agents:
|
|
|
37
42
|
|
|
38
43
|
- [Architecture](docs/architecture.md): Packages and data flow
|
|
39
44
|
- [WebSocket protocol](docs/protocol.md): Message formats
|
|
45
|
+
- [Compatibility](docs/compatibility.md): Public API promise, aliases, and compatibility checks
|
|
40
46
|
- [AI UI](docs/ai.md): `ui.ai.*` visual primitives
|
|
41
47
|
- [Reactive let](docs/reactive-let.md): `ui.state` / `ui.auto` and the compile-time `let` transform
|
|
42
|
-
- [DuckDB](docs/duckdb.md): `@close-by/clay-duckdb`
|
|
48
|
+
- [DuckDB](docs/duckdb.md): `@close-by/clay-duckdb` — monorepo only — not published to npm yet
|
|
49
|
+
- Redis persistence: `@close-by/clay-persistence-redis` — monorepo only — not published to npm yet (see [storage API](docs/api.md))
|
|
43
50
|
- [ClickHouse](docs/clickhouse.md): `@close-by/clay-clickhouse`
|
|
44
|
-
- [Kibana](docs/kibana.md): `@close-by/clay-kibana`
|
|
51
|
+
- [Kibana](docs/kibana.md): `@close-by/clay-kibana` — monorepo only — not published to npm yet
|
|
45
52
|
- [NiceGUI](https://nicegui.io/documentation): Inspiration for the `ui.*` style
|
package/docs/mobile.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Mobile and installable apps
|
|
2
|
+
|
|
3
|
+
Apps built with the `app` shell work on phones without changes. You can also make an app installable to the home screen, which is opt-in.
|
|
4
|
+
|
|
5
|
+
## Phone layout
|
|
6
|
+
|
|
7
|
+
On phone-sized screens (narrow, with a touch pointer) the shell changes on its own:
|
|
8
|
+
|
|
9
|
+
- **Bottom tab bar.** Up to 4 top-level `nav` items become tabs. When there are more items, or `navSecondary`, `documents` or `user` is set, a **More** tab opens the sidebar sheet. A tab is highlighted when its page, or one of its child pages, is active.
|
|
10
|
+
- **Bottom sheets.** Dialogs open as bottom sheets.
|
|
11
|
+
- **Safe areas.** Content clears the iPhone notch and home indicator.
|
|
12
|
+
- **Toasts and the connection chip** sit above the tab bar.
|
|
13
|
+
- **16px form text.** iOS doesn't zoom when a field is focused.
|
|
14
|
+
|
|
15
|
+
`select`, `combobox`, `date` and `dropdownMenu` also use native pickers or bottom drawers on phones. See [Elements](./elements.md#on-phones).
|
|
16
|
+
|
|
17
|
+
### Keep only the menu
|
|
18
|
+
|
|
19
|
+
Set `mobileNav: 'menu'` to keep the hamburger sheet and skip the tab bar:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
ui.run({
|
|
23
|
+
app: {
|
|
24
|
+
title: 'My App',
|
|
25
|
+
nav: ui.navFromPages(),
|
|
26
|
+
mobileNav: 'menu', // default: 'tabs'
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`mobileNav` is also a [`ui.app()`](./api.md#uiappprops-fn) prop.
|
|
32
|
+
|
|
33
|
+
## Installable app (PWA)
|
|
34
|
+
|
|
35
|
+
Opt in with the CLI flag or the `pwa` option:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
clay ./pages --app --pwa
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
ui.run({ pwa: true }); // defaults
|
|
43
|
+
|
|
44
|
+
ui.run({
|
|
45
|
+
title: 'My App',
|
|
46
|
+
pwa: {
|
|
47
|
+
shortName: 'App',
|
|
48
|
+
description: 'Track my work',
|
|
49
|
+
themeColor: '#1d4ed8',
|
|
50
|
+
backgroundColor: '#ffffff',
|
|
51
|
+
display: 'standalone',
|
|
52
|
+
startUrl: '/',
|
|
53
|
+
icon: './assets/icon-512.png',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`ClayPwaConfig` is exported from `@close-by/clay-server`.
|
|
59
|
+
|
|
60
|
+
| Option | Default | Description |
|
|
61
|
+
|--------|---------|-------------|
|
|
62
|
+
| `name` | `title` | App name in the install prompt and splash screen |
|
|
63
|
+
| `shortName` | `name` | Label under the home-screen icon |
|
|
64
|
+
| `description` | | Manifest description |
|
|
65
|
+
| `themeColor` | Clay light/dark background | Browser and OS chrome color |
|
|
66
|
+
| `backgroundColor` | Clay light background | Splash screen background |
|
|
67
|
+
| `display` | `'standalone'` | `'standalone' \| 'fullscreen' \| 'minimal-ui' \| 'browser'` |
|
|
68
|
+
| `startUrl` | `'/'` | URL opened from the home screen |
|
|
69
|
+
| `icon` | Clay's bundled icons | Square PNG (512px+ recommended) or SVG, relative to the working directory |
|
|
70
|
+
|
|
71
|
+
It adds:
|
|
72
|
+
|
|
73
|
+
- `/manifest.webmanifest`, with name, icons, colors and display mode.
|
|
74
|
+
- `theme-color` and Apple meta tags, plus `viewport-fit=cover` so content can use the full screen.
|
|
75
|
+
- `/sw.js`, a service worker that caches the app shell (HTML, JS, CSS and icons). It uses network-first, so online users always get the latest build.
|
|
76
|
+
|
|
77
|
+
### Icons
|
|
78
|
+
|
|
79
|
+
- Without `icon`, Clay's bundled icons are used.
|
|
80
|
+
- `icon` must be a `.png` or `.svg` file. A missing or unsupported file throws at startup.
|
|
81
|
+
- iOS home-screen icons need a PNG. SVG gets no apple-touch-icon, so use a PNG if the app will be installed on iOS.
|
|
82
|
+
|
|
83
|
+
### Offline
|
|
84
|
+
|
|
85
|
+
The installed app still opens without a connection and shows Clay's reconnecting state. There is no offline mode for pages, since every screen runs on the server.
|
|
86
|
+
|
|
87
|
+
### HTTPS
|
|
88
|
+
|
|
89
|
+
Service workers require HTTPS. `localhost` is exempt, so you can test locally. Serve the app over HTTPS before asking people to install it.
|
|
90
|
+
|
|
91
|
+
### Install
|
|
92
|
+
|
|
93
|
+
- **Android and desktop Chrome:** an install prompt or menu item appears when the app is installable.
|
|
94
|
+
- **iOS Safari:** Share → Add to Home Screen.
|
|
95
|
+
|
|
96
|
+
### Turn it off
|
|
97
|
+
|
|
98
|
+
Remove `pwa` (or the `--pwa` flag). Clay then serves a `/sw.js` that clears the app cache and unregisters itself. Browsers that installed the app earlier clean up the next time they load it.
|
|
99
|
+
|
|
100
|
+
### Override the worker or manifest
|
|
101
|
+
|
|
102
|
+
`/sw.js` and `/manifest.webmanifest` can be replaced with `routes`, which match by exact path before pages:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
ui.run({
|
|
106
|
+
pwa: true,
|
|
107
|
+
routes: {
|
|
108
|
+
'/sw.js': () => new Response(mySource, { headers: { 'Content-Type': 'text/javascript' } }),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
```
|
package/docs/ops-patterns.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Dense internal tools (live feeds, master–detail, logs/traces) push Clay past card dashboards. Prefer Phase 1 reactivity ([Concepts](./concepts.md#canonical-recipe-state--auto--timer)) and the helpers below.
|
|
4
4
|
|
|
5
|
-
**Runnable
|
|
5
|
+
**Runnable example:** `/examples/ops-console` (`OpsConsoleDemo.ts`) — one Orders-shaped surface using `filterBar`, `inputGroup`, `feedList`/`feedRow`, `descriptionList`, `staticTable`, `pagination`, `empty`, `notice`, and `toggle`. Use that page to find API friction before adding more wire types.
|
|
6
6
|
|
|
7
7
|
## Status chips
|
|
8
8
|
|
package/docs/reactive-let.md
CHANGED
|
@@ -66,7 +66,7 @@ Clay lifts `count` into `ui.state`, turns the label into `bindText`, and leaves
|
|
|
66
66
|
| When to use `let` + pragma | When to stay on Phase 1 |
|
|
67
67
|
|-----------------------------|-------------------------|
|
|
68
68
|
| Counters, toggles, filters on demo pages | Async fetch before first paint, heavy CJS imports |
|
|
69
|
-
| Orders-shaped proof pages (`
|
|
69
|
+
| Orders-shaped proof pages (`examples/reactive-let-orders.ts`) | Per-row mutable state without stable row keys |
|
|
70
70
|
| Teaching / prototyping NiceGUI-style UX | You want zero Bun loader / compiler in the path |
|
|
71
71
|
|
|
72
72
|
Phase 1 remains the **escape hatch** — copy patterns from [`ReactiveLetOrders.ts`](../apps/demo/src/examples/ReactiveLetOrders.ts) when Phase 2 limits bite.
|
|
@@ -206,13 +206,15 @@ Tests: `packages/compiler/src/transform.test.ts`, `packages/core/src/auto.test.t
|
|
|
206
206
|
| Page | Syntax | Run |
|
|
207
207
|
|------|--------|-----|
|
|
208
208
|
| [`ReactiveLetOrders.ts`](../apps/demo/src/examples/ReactiveLetOrders.ts) | Phase 1 `state` / `auto` | `bun run cli` |
|
|
209
|
-
| [`
|
|
209
|
+
| [`examples/reactive-let-orders.ts`](../examples/reactive-let-orders.ts) | `let` + `// @clay-reactive` | `bun run clay examples/reactive-let-orders.ts --reactive-let` (from repo root) |
|
|
210
210
|
|
|
211
211
|
```bash
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
bun run demo:cli # Orders at /examples/reactive-let-orders, always interactive
|
|
213
|
+
bun run clay examples/reactive-let-orders.ts --reactive-let # standalone let proof, same route
|
|
214
214
|
```
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
The demo Orders page includes the let source as a code block. The standalone copy stays outside the auto-loaded demo pages.
|
|
217
|
+
|
|
218
|
+
Compiler coverage: `packages/compiler/src/orders-proof.test.ts` transforms the standalone let example and asserts separate list/detail regions (no mega-`auto`).
|
|
217
219
|
|
|
218
220
|
Without `--reactive-let`, `let` assignments are silent no-ops (no error).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@close-by/clay",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.26",
|
|
4
4
|
"description": "NiceGUI-like ui.* facade for Clay apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@close-by/clay-compiler": "0.2.
|
|
41
|
-
"@close-by/clay-core": "0.2.
|
|
42
|
-
"@close-by/clay-components": "0.2.
|
|
43
|
-
"@close-by/clay-server": "0.2.
|
|
40
|
+
"@close-by/clay-compiler": "0.2.26",
|
|
41
|
+
"@close-by/clay-core": "0.2.26",
|
|
42
|
+
"@close-by/clay-components": "0.2.26",
|
|
43
|
+
"@close-by/clay-server": "0.2.26",
|
|
44
44
|
"@tailwindcss/cli": "^4.3.3",
|
|
45
45
|
"tailwindcss": "^4.3.3"
|
|
46
46
|
}
|
package/src/index.ts
CHANGED
|
@@ -501,10 +501,12 @@ import {
|
|
|
501
501
|
} from '@close-by/clay-core';
|
|
502
502
|
import {
|
|
503
503
|
ClayServer,
|
|
504
|
+
onDispose,
|
|
504
505
|
type ClayServerConfig,
|
|
505
506
|
establishAuthSession as establishAuthSessionCore,
|
|
506
507
|
clearAuthSession as clearAuthSessionCore,
|
|
507
508
|
} from '@close-by/clay-server';
|
|
509
|
+
export { onDispose };
|
|
508
510
|
import {
|
|
509
511
|
loadPages,
|
|
510
512
|
navFromPages,
|
|
@@ -2075,6 +2077,7 @@ export const ui = {
|
|
|
2075
2077
|
runJavaScript,
|
|
2076
2078
|
scroll,
|
|
2077
2079
|
timer,
|
|
2080
|
+
onDispose,
|
|
2078
2081
|
storage,
|
|
2079
2082
|
theme,
|
|
2080
2083
|
sound,
|