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.
- package/package.json +1 -1
- package/skill/reference.md +27 -1
package/package.json
CHANGED
package/skill/reference.md
CHANGED
|
@@ -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 (
|
|
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`
|