create-hozu 0.4.0 → 0.4.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/skill/reference.md +27 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-hozu",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Create a Hozu app, set up for Claude Code or for agents that read AGENTS.md",
5
5
  "keywords": [
6
6
  "hozu",
@@ -21,9 +21,32 @@ export const docs = route({ path: '/docs/:path+', params: z.object({ path: z.arr
21
21
  literal option values are all members, so one submit carries a title and a priority.
22
22
  - `ui.dom.valueAsNumber` (number | null), `ui.dom.checked`, `ui.dom.key`, and similar event fields.
23
23
  - Also: `ui.html(value)` (trusted HTML from query data only, HZ030), `ui.asset(new URL('./x.png', import.meta.url))`,
24
- `ui.window({ on })` / `ui.document({ on })` for global listeners, widgets (`ui.widget` / `ui.use`) for
24
+ `ui.window({ on })` / `ui.document({ on })` for global listeners, widgets (see Widgets) for browser APIs and
25
25
  third-party DOM libraries.
26
26
 
27
+ ## Widgets (browser APIs, DOM libraries)
28
+ There is no `widget` export: declare with `ui.widget`, place with `ui.use`, list the declaration in the feature's
29
+ `declarations`, and implement it in a client module.
30
+ ```ts
31
+ export const Copy = ui.widget({ tag: 'button', props: z.object({ text: z.string() }),
32
+ events: { copied: z.object({}) }, client: new URL('./copy.client.ts', import.meta.url), load: 'visible', wraps: true })
33
+ ui.use(Copy, { props: { text: block.code }, on: { copied: () => ui.send(Copied, {}) }, class: 'btn' }, ['Copy'])
34
+ ```
35
+ ```ts
36
+ // copy.client.ts: a type-only import of the declaration
37
+ import { implement } from '@hozu/core/widget'
38
+ import type { Copy } from './widgets.ts'
39
+ export default implement<typeof Copy>(({ el, props, emit, signal }) => {
40
+ el.addEventListener('click', () => navigator.clipboard.writeText(props.text).then(() => emit('copied', {})), { signal })
41
+ return { update(next) { props = next } }
42
+ })
43
+ ```
44
+ `load`: `'eager' | 'visible' | 'idle'`; `wraps: true` keeps the children as server HTML.
45
+ **Serving them is a separate step.** Run `npm install @hozu/bundle`, then pass `widgets: await bundleWidgets(build)`
46
+ to `createServer` in `serve.ts` (and to `exportStatic`). Without it the server refuses to start; `hozu build` bundles
47
+ widgets itself. HZ029 is a client module that does not bundle. A library's own CSS goes in `app.css`
48
+ (`@import "leaflet/dist/leaflet.css";`), and a map or chart host needs a height class (`h-96`).
49
+
27
50
  ## Forms without JavaScript
28
51
  A submit whose payload reads only `ui.dom.form('name')`, literals, context, params and search also works without JS
29
52
  (otherwise HZ036 warns). The server runs the same machine and mutation, then redirects (on `navigate`, or when the
@@ -49,6 +72,9 @@ Every mutation also has the framework error `Invalid` = `{ message, fields }`: o
49
72
  - `project({ notFound: route, error: route })` renders those pages for 404 / 500.
50
73
  - A view listed with a machine on several pages, in the same order, stays mounted when links move between them
51
74
  (see `patterns.md`).
75
+ - **JS per page is derived:** a page loads the client only when a machine-bound node renders on it. An island
76
+ inside `ui.each`, `ui.if`, `when` or a query branch loads it only on pages where it renders; `hozu plan <route>`
77
+ says `always` or `only when rendered`. Do not add views or flags to avoid JS.
52
78
 
53
79
  ## Sessions
54
80
  - **Start from the scaffold:** `hozu add feature notes --page / --with auth` writes `features/account`