void-plugin-hono-jsx 0.1.0-alpha.3 → 0.1.0-alpha.4
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/CHANGELOG.md +52 -0
- package/README.md +41 -12
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/dist/browser/client.d.ts +2 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/client.js +76 -22
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/document-head.d.ts +1 -1
- package/dist/browser/document-head.d.ts.map +1 -1
- package/dist/browser/document-head.js +22 -1
- package/dist/browser/document-head.js.map +1 -1
- package/dist/browser/form-view.d.ts +10 -0
- package/dist/browser/form-view.d.ts.map +1 -0
- package/dist/browser/form-view.js +16 -0
- package/dist/browser/form-view.js.map +1 -0
- package/dist/browser/form.d.ts +28 -12
- package/dist/browser/form.d.ts.map +1 -1
- package/dist/browser/form.js +84 -23
- package/dist/browser/form.js.map +1 -1
- package/dist/browser/markdown.d.ts +15 -0
- package/dist/browser/markdown.d.ts.map +1 -0
- package/dist/browser/markdown.js +6 -0
- package/dist/browser/markdown.js.map +1 -0
- package/dist/browser/navigation.d.ts +13 -0
- package/dist/browser/navigation.d.ts.map +1 -0
- package/dist/browser/navigation.js +83 -0
- package/dist/browser/navigation.js.map +1 -0
- package/dist/browser/pages.d.ts +33 -3
- package/dist/browser/pages.d.ts.map +1 -1
- package/dist/browser/pages.js +76 -13
- package/dist/browser/pages.js.map +1 -1
- package/dist/plugins/hono-islands.d.ts +1 -1
- package/dist/plugins/hono-islands.d.ts.map +1 -1
- package/dist/plugins/hono-islands.js +156 -24
- package/dist/plugins/hono-islands.js.map +1 -1
- package/dist/plugins/hono-markdown.d.ts +4 -0
- package/dist/plugins/hono-markdown.d.ts.map +1 -0
- package/dist/plugins/hono-markdown.js +91 -0
- package/dist/plugins/hono-markdown.js.map +1 -0
- package/dist/plugins/hono-pages.d.ts +9 -1
- package/dist/plugins/hono-pages.d.ts.map +1 -1
- package/dist/plugins/hono-pages.js +51 -15
- package/dist/plugins/hono-pages.js.map +1 -1
- package/dist/plugins/markdown-api.d.ts +10 -0
- package/dist/plugins/markdown-api.d.ts.map +1 -0
- package/dist/plugins/markdown-api.js +13 -0
- package/dist/plugins/markdown-api.js.map +1 -0
- package/dist/plugins/markdown-compiler.d.ts +43 -0
- package/dist/plugins/markdown-compiler.d.ts.map +1 -0
- package/dist/plugins/markdown-compiler.js +91 -0
- package/dist/plugins/markdown-compiler.js.map +1 -0
- package/dist/plugins/resolve-component.d.ts +3 -0
- package/dist/plugins/resolve-component.d.ts.map +1 -0
- package/dist/plugins/resolve-component.js +15 -0
- package/dist/plugins/resolve-component.js.map +1 -0
- package/dist/plugins/runtime-paths.d.ts +1 -0
- package/dist/plugins/runtime-paths.d.ts.map +1 -1
- package/dist/plugins/runtime-paths.js +2 -0
- package/dist/plugins/runtime-paths.js.map +1 -1
- package/dist/server/form-view.d.ts +10 -0
- package/dist/server/form-view.d.ts.map +1 -0
- package/dist/server/form-view.js +16 -0
- package/dist/server/form-view.js.map +1 -0
- package/dist/server/form.d.ts +28 -12
- package/dist/server/form.d.ts.map +1 -1
- package/dist/server/form.js +84 -23
- package/dist/server/form.js.map +1 -1
- package/dist/server/markdown.d.ts +15 -0
- package/dist/server/markdown.d.ts.map +1 -0
- package/dist/server/markdown.js +6 -0
- package/dist/server/markdown.js.map +1 -0
- package/dist/server/pages.d.ts +33 -3
- package/dist/server/pages.d.ts.map +1 -1
- package/dist/server/pages.js +76 -13
- package/dist/server/pages.js.map +1 -1
- package/package.json +21 -3
- package/src/plugins/hono-islands.ts +121 -23
- package/src/plugins/hono-markdown.ts +78 -0
- package/src/plugins/hono-pages.ts +50 -14
- package/src/plugins/markdown-api.ts +17 -0
- package/src/plugins/markdown-compiler.ts +77 -0
- package/src/plugins/resolve-component.ts +12 -0
- package/src/plugins/runtime-paths.ts +2 -0
- package/src/runtime/client.tsx +66 -24
- package/src/runtime/document-head.ts +20 -1
- package/src/runtime/form-view.tsx +23 -0
- package/src/runtime/form.ts +82 -41
- package/src/runtime/markdown.ts +7 -0
- package/src/runtime/navigation.ts +72 -0
- package/src/runtime/pages.tsx +77 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-alpha.4](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.3...v0.1.0-alpha.4) (2026-10-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* Rename voidHonoPages to voidHonoJsx and HonoPagesOptions to HonoJsxOptions. The legacy names are removed without compatibility aliases.
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **forms:** add bound forms and action helpers ([22899eb](https://github.com/ts-76/void-plugin-hono-jsx/commit/22899eb8105f626c87fc4dafd19785a9c637bf4c))
|
|
13
|
+
* **forms:** add bound forms and action helpers ([15f7e0d](https://github.com/ts-76/void-plugin-hono-jsx/commit/15f7e0d154ea38134a458385ac0eb65ce215f302))
|
|
14
|
+
* **forms:** support provider-free island actions ([b8020d8](https://github.com/ts-76/void-plugin-hono-jsx/commit/b8020d856bc2d65c8cecdc69c3ce6aa0cca46737))
|
|
15
|
+
* **forms:** support provider-free island actions ([7179d10](https://github.com/ts-76/void-plugin-hono-jsx/commit/7179d102455dcccb50d2bec2e48f284d3f908c29))
|
|
16
|
+
* **islands:** discover static component and layout graphs ([a93bf48](https://github.com/ts-76/void-plugin-hono-jsx/commit/a93bf482678908153722ad28ec117d2fca2cb62d))
|
|
17
|
+
* **islands:** discover static component and layout graphs ([cc5133d](https://github.com/ts-76/void-plugin-hono-jsx/commit/cc5133dd9d3273ebc02143f41fa79cb7e3dacb1d))
|
|
18
|
+
* **islands:** support visible idle and media policies ([3b6b296](https://github.com/ts-76/void-plugin-hono-jsx/commit/3b6b2965ddd5fefef2e16281e3d64083c1c7d42f))
|
|
19
|
+
* **islands:** support visible idle and media policies ([7d7d8f0](https://github.com/ts-76/void-plugin-hono-jsx/commit/7d7d8f00bc8c1d3b029af9e469005f358f866ab5))
|
|
20
|
+
* **markdown:** add optional Hono Markdown pages ([f27a6ab](https://github.com/ts-76/void-plugin-hono-jsx/commit/f27a6abec34afa9dd875de564454ca2bf1a840bc))
|
|
21
|
+
* **markdown:** add optional Hono Markdown pages ([471ed71](https://github.com/ts-76/void-plugin-hono-jsx/commit/471ed717ac31b8ac3192efed43cb34072913b049))
|
|
22
|
+
* **pages:** expose reactive navigation state ([b54476b](https://github.com/ts-76/void-plugin-hono-jsx/commit/b54476b6eb404530738a5d23397e453d468441d0))
|
|
23
|
+
* **pages:** expose reactive navigation state ([d7b1e04](https://github.com/ts-76/void-plugin-hono-jsx/commit/d7b1e041c751943e08eabeb7d5de54f1a8fb3038))
|
|
24
|
+
* **pages:** expose transition and prefetch options ([e3bf353](https://github.com/ts-76/void-plugin-hono-jsx/commit/e3bf353aa9ffbc7e734442af113a98503b5a0c67))
|
|
25
|
+
* **pages:** expose transition and prefetch options ([764c623](https://github.com/ts-76/void-plugin-hono-jsx/commit/764c623472c173bd4fb1485d32add7af07bc00d6))
|
|
26
|
+
* **pages:** integrate Hono Pages APIs and optional Markdown ([07d459b](https://github.com/ts-76/void-plugin-hono-jsx/commit/07d459b703bbff6cd46ea0f6a56eeea6ac9a97cc))
|
|
27
|
+
* **pages:** support Link navigation options and prefetch ([d32664d](https://github.com/ts-76/void-plugin-hono-jsx/commit/d32664d0f1291078aaad7b63807f98e8afb7b24c))
|
|
28
|
+
* **pages:** support Link navigation options and prefetch ([f2c87c0](https://github.com/ts-76/void-plugin-hono-jsx/commit/f2c87c0f2c1908b24fa064fa69630a62dd4bd025))
|
|
29
|
+
* rename plugin to voidHonoJsx and integrate Markdown sample ([4107cd8](https://github.com/ts-76/void-plugin-hono-jsx/commit/4107cd80ff2caac27acb67fd981634b4ac0e708a))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **islands:** resolve directory index imports in static graphs ([17287b3](https://github.com/ts-76/void-plugin-hono-jsx/commit/17287b30d48646246f18c44e94d99387bc9107de))
|
|
35
|
+
* **markdown:** canonicalize symlinked island identities ([14d0fc7](https://github.com/ts-76/void-plugin-hono-jsx/commit/14d0fc7187d3b9c19b1bb29d10736cb79b126532))
|
|
36
|
+
* **markdown:** diagnose the upstream compiler integration gate ([2ac08ba](https://github.com/ts-76/void-plugin-hono-jsx/commit/2ac08ba6a170292c5a3f5d414046b6a7a01774d8))
|
|
37
|
+
* **pages:** own native transition lifecycle over the Void engine ([aae12c3](https://github.com/ts-76/void-plugin-hono-jsx/commit/aae12c3c1e54782db42f7e2839867e055c5dd1bf))
|
|
38
|
+
* **pages:** preserve navigation guards and recover failed renders ([c2ac900](https://github.com/ts-76/void-plugin-hono-jsx/commit/c2ac900d6bccfb53ad505624d12f976caad37e2d))
|
|
39
|
+
* **pages:** resolve relative Link destinations against the document ([1f0da26](https://github.com/ts-76/void-plugin-hono-jsx/commit/1f0da2637680b92606bef66510236624252c18dc))
|
|
40
|
+
* **release:** refresh pnpm publisher to patched rustls ([db2035e](https://github.com/ts-76/void-plugin-hono-jsx/commit/db2035eff876df04dd582b932b485f3a545e3cd1))
|
|
41
|
+
* **release:** refresh pnpm publisher to patched rustls ([38c9bdd](https://github.com/ts-76/void-plugin-hono-jsx/commit/38c9bdd5af42fe2819215340d6ed92284dce2d9c))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Documentation
|
|
45
|
+
|
|
46
|
+
* describe post-alpha.3 APIs without transient publication claims ([0341e4d](https://github.com/ts-76/void-plugin-hono-jsx/commit/0341e4dffcf09657ad564f77551fa4d9c9066a54))
|
|
47
|
+
* distinguish published alpha baseline and upcoming release evidence ([83cca46](https://github.com/ts-76/void-plugin-hono-jsx/commit/83cca464ccf35a0402e00ce6426e63fee5057451))
|
|
48
|
+
* **markdown:** include optional setup in the packed guide ([26e7dd5](https://github.com/ts-76/void-plugin-hono-jsx/commit/26e7dd59ecdef69e16e466c16b2c0bd962d4777b))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Release Automation
|
|
52
|
+
|
|
53
|
+
* accept scoped ZIP findings in the fixed-tarball publisher ([fb08d0b](https://github.com/ts-76/void-plugin-hono-jsx/commit/fb08d0b5c8c2d80f7f5e9072d36bf1f077f8c8f1))
|
|
54
|
+
|
|
3
55
|
## [0.1.0-alpha.3](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.2...v0.1.0-alpha.3) (2026-10-12)
|
|
4
56
|
|
|
5
57
|
|
package/README.md
CHANGED
|
@@ -13,7 +13,9 @@ This experimental package integrates Hono JSX with Void Pages. The package name
|
|
|
13
13
|
| Vite Plus | Host Vite must satisfy the Vite range | 0.1.24 (scaffold), 1.1.0 (latest) |
|
|
14
14
|
| TypeScript | Project tooling | 7.0.2 |
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Published alpha.3 includes these peer ranges, running-Vite diagnostics and packaged source/maps. Alpha.1 and alpha.2 retain their exact-version gate. Stable Vite/Hono updates within the accepted ranges are admitted by compatibility policy; Void 0.28 and later require explicit validation. Prereleases are excluded. The fixture versions above are the 2026-10-12 snapshot; admitting a range does not mean every future version has already been tested. New upstream releases require refreshed fixtures, full checks and dependency audit review.
|
|
17
|
+
|
|
18
|
+
The expanded Link/Form APIs, island forms and graphs, deferred contracts, page options and optional Markdown documented below are additions after alpha.3. Use a later alpha containing the corresponding exports, or a local tarball to validate this source tree. Alpha.3 does not provide these additions.
|
|
17
19
|
|
|
18
20
|
## Install
|
|
19
21
|
|
|
@@ -33,16 +35,18 @@ npm install --save-dev void@0.27.0 vite@8.3.4 typescript@7.0.2
|
|
|
33
35
|
|
|
34
36
|
## Configure
|
|
35
37
|
|
|
38
|
+
`voidHonoJsx()` and `HonoJsxOptions` replace the earlier `voidHonoPages()` and `HonoPagesOptions` names. This is a breaking alpha API change; the old names are not exported. Alpha.3 uses the earlier names. Use a local tarball or a release containing this rename for the configuration below.
|
|
39
|
+
|
|
36
40
|
```ts
|
|
37
41
|
// vite.config.ts
|
|
38
42
|
import { defineConfig } from 'vite';
|
|
39
43
|
import { voidPlugin } from 'void';
|
|
40
|
-
import {
|
|
44
|
+
import { voidHonoJsx } from 'void-plugin-hono-jsx/plugin';
|
|
41
45
|
|
|
42
|
-
export default defineConfig({ plugins: [voidPlugin(),
|
|
46
|
+
export default defineConfig({ plugins: [voidPlugin(), voidHonoJsx()] });
|
|
43
47
|
```
|
|
44
48
|
|
|
45
|
-
Configure project settings in `void.config.ts` using `defineConfig` from `void/config`. Run Vite from that project's root. `
|
|
49
|
+
Configure project settings in `void.config.ts` using `defineConfig` from `void/config`. Run Vite from that project's root. `voidHonoJsx()` includes the Hono JSX transform, so do not register a separate transform. Configure charset, viewport and favicon through Void's `head` settings.
|
|
46
50
|
|
|
47
51
|
Use `jsx: "react-jsx"` and `jsxImportSource: "hono/jsx"` in TypeScript. The plugin chooses the server or DOM factory for application JSX; the plugin resolves package runtime exports using Vite's actual consumer environment. Cloudflare worker environments may enable the browser condition, so that condition alone cannot select the renderer.
|
|
48
52
|
|
|
@@ -59,7 +63,7 @@ If the project version is already correct, inspect the paths in the diagnostic a
|
|
|
59
63
|
Void's init wizard currently offers React, Vue, Svelte and Solid adapters rather than Hono JSX. A React scaffold can be adapted without replacing its Vite Plus scripts:
|
|
60
64
|
|
|
61
65
|
1. Install this adapter and `hono`; use a candidate/new release with the support policy above.
|
|
62
|
-
2. Replace `voidReact()` / `@void/react/plugin` in `vite.config.ts` with `
|
|
66
|
+
2. Replace `voidReact()` / `@void/react/plugin` in `vite.config.ts` with `voidHonoJsx()` / `void-plugin-hono-jsx/plugin`, keeping `voidPlugin()`.
|
|
63
67
|
3. Set TypeScript `jsx` to `react-jsx` and `jsxImportSource` to `hono/jsx`. Change page/component React imports and hooks to Hono JSX APIs.
|
|
64
68
|
4. Once React code is removed, uninstall `@void/react`, `react`, `react-dom`, `@types/react`, `@types/react-dom` and `oxc-transform-react` if they are otherwise unused. The Hono plugin supplies its own JSX transform.
|
|
65
69
|
5. Keep `vp dev`, `vp build`, `vp preview`, or use the plain Vite scaffold. Verify the app's loaders/actions and database migrations locally.
|
|
@@ -68,21 +72,23 @@ The latest consumer fixtures also install React scaffold dependencies (React/DOM
|
|
|
68
72
|
|
|
69
73
|
## Source and debugging files
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
Published alpha.2 and alpha.3 include the original `src/plugins/*.ts` and `src/runtime/*.{ts,tsx}` alongside compiled `dist` entries. Every JavaScript file has a `.js.map` with embedded original source; every declaration has a `.d.ts.map` pointing to the same packaged TypeScript files. Build-time import rewriting composes its map with the compiler map, so generated locations still refer to the original source. Alpha.0 and alpha.1 retain their original dist-only archives.
|
|
72
76
|
|
|
73
77
|
Read source under `node_modules/void-plugin-hono-jsx/src`. Editors supporting declaration maps can navigate from exported types to those files, and debuggers/bundlers supporting source maps can show the original source. Application imports continue to use `/plugin`, `/pages` and `/form`; `src` is supplied for inspection and debugging, not as an additional runtime entry point. Candidate and clean-consumer checks reject missing/stale maps, external source references, changed source bytes and unexpected archive files.
|
|
74
78
|
|
|
75
79
|
## Runtime exports
|
|
76
80
|
|
|
77
81
|
```tsx
|
|
78
|
-
import { Link, useRouter, useShared, useParams, useErrors } from 'void-plugin-hono-jsx/pages';
|
|
79
|
-
import { useForm } from 'void-plugin-hono-jsx/form';
|
|
82
|
+
import { Link, useRouter, useShared, useParams, useErrors, useNavigation } from 'void-plugin-hono-jsx/pages';
|
|
83
|
+
import { Form, useForm, useIslandForm, action } from 'void-plugin-hono-jsx/form';
|
|
80
84
|
```
|
|
81
85
|
|
|
82
|
-
`Link` and `useRouter` use Void's shared navigation protocol. Ordinary GET visits reset page state; refresh preserves it. Root/nested/named layouts retain state while they remain in the active chain. Shared data, route params and field errors are available in SSR and browser components. `useForm` supports all mutation methods, named actions, validation, duplicate suppression and cancellation. Cancellation does not undo server writes.
|
|
86
|
+
`Link` and `useRouter` use Void's shared navigation protocol. Link accepts `method`, `data`, `preserveScroll`, `preserveState`, `replace`, `reloadDocument` and cancellable `onNavigate`. GET data is serialized into its href; mutation links render buttons. Prefetch supports `true` (hover), `hover`, `click`, `mount`, `visible` or an array, with optional `cacheFor`. Prefetch and document reload are GET-only. User event handlers can prevent the adapter's action; external/download/target links retain native behavior. Ordinary GET visits reset page state; refresh preserves it. Root/nested/named layouts retain state while they remain in the active chain. Shared data, route params and field errors are available in SSR and browser components. `useNavigation()` returns Void's reactive `{ state, location, method }` (`idle`, `loading`, `submitting`); SSR starts idle and pending visits clear on completion, failure or cancellation. `useForm` supports all mutation methods, named actions, validation, duplicate suppression and cancellation. Existing `useForm(defaults)` with `post(url)` remains supported. The bound `useForm('/edit?save', defaults, options)` form also supports `post()`/`put()`/`patch()`/`delete()` and `<Form form={form}>`; provide `url` to Form for a legacy unbound model. `setData` accepts a complete object/updater or a typed field/value pair. `hasChanges`, `recentlySuccessful` (two seconds), selective `reset`/`clearErrors`, and `clearError` describe and reset state. A successful bound submission becomes the new defaults. `Form` displays field/action errors (customizable with `renderError`), respects quota retry deadlines, and never automatically resubmits. The typed `action(url, options)` helper performs a single action through the initialized Pages router. Cancellation does not undo server writes.
|
|
83
87
|
|
|
84
88
|
Head resolution and escaping follow Void. The adapter synchronizes document attributes and inert script metadata; navigation does not execute newly inserted scripts. Raw `script.innerHTML` is authored content. Serialize dynamic JSON-LD and escape `<` before assigning it.
|
|
85
89
|
|
|
90
|
+
If a page or layout throws during browser rendering, the visit rejects and navigation returns to idle. The URL and head remain on the last successful page. Recovery rebuilds that page and its layouts, resetting their local component state; a later visit can proceed normally. State preservation during successful navigation is unchanged.
|
|
91
|
+
|
|
86
92
|
## Static output and prerendering
|
|
87
93
|
|
|
88
94
|
Set `output: 'static'` in `void.config.ts`, then run `vite build`. Void collects known page routes and dynamic `getPrerenderPaths()` results and generates HTML plus `/_void/pages/*.json` under `dist/client`. The Hono adapter supplies its renderer and enables the shared router's static-data mode. It adds no route crawler.
|
|
@@ -120,9 +126,9 @@ A resolved value or error updates the current page without resetting page-local
|
|
|
120
126
|
|
|
121
127
|
Void 0.26.1 forwards ordinary deferred resolver error messages in development; production streams use `Internal Server Error`. Deliberate HTTP exception messages may be forwarded in production. The adapter turns the received message into an `Error` and exposes it through `error`; server stack traces are not included. Author deliberate HTTP exception messages suitable for display to users. This follows the verified streaming error behavior of the pinned Void version.
|
|
122
128
|
|
|
123
|
-
The verified contract covers single deferred props during GET document requests and SPA navigation
|
|
129
|
+
The verified contract covers single and grouped deferred props during GET document requests and SPA navigation, successful prefetch followed by a visit, and retention of resolved values after actions. Void preserves these values until the next load/navigation; mutation actions do not rerun the deferred resolver. Failed deferred prefetch currently becomes a resolved `null` because Void does not transmit its error; use document/SPA streaming when error state is required. Grouped resolver projections require explicit prop types with the current Void `defer<T>` declaration. Deferred island pages and static deferred output remain unsupported. The ordinary Pages action APIs remain documented under runtime exports.
|
|
124
130
|
|
|
125
|
-
##
|
|
131
|
+
## Islands
|
|
126
132
|
|
|
127
133
|
Use a `.island.tsx` or `.island.jsx` page for static server content and import an interactive component using Void's import attribute:
|
|
128
134
|
|
|
@@ -138,7 +144,30 @@ Place the counter outside the pages directory. It can use Hono hooks and event h
|
|
|
138
144
|
|
|
139
145
|
A static-only island page emits no client script or module preload tags. Static page modules stay outside the normal Pages browser manifest. A project containing only static island pages builds empty client entry modules with no framework code. Void's own automatic prerender policy still applies to eligible island pages. Full static output and explicit prerender configuration follow the static output contract below.
|
|
140
146
|
|
|
141
|
-
|
|
147
|
+
The `load`, `visible`, `idle` and `media:(query)` policies use Void's shared scheduler. Use a single default relative TSX/JSX import, with attributes directly in the island page. Unknown policies and obvious malformed media queries fail discovery; the browser checks the media query through CSSOM before scheduling. Each island mounts once when its condition is met. Island layouts and attributed imports in their static TSX/JSX component graph are supported, including named layouts and repeated components with independent JSON props. The graph handles cycles and invalidates island entries when a known static component changes. Static chains without interactive imports emit no client script. Interactive components form a boundary: use ordinary imports inside them; another attributed island inside an already interactive component is rejected to avoid overlapping mounts. Full Pages cannot inherit an island layout (Void diagnoses the mixed mode). `useIslandForm(defaults)` provides the same data/dirty/error/submit/reset/clear state without a Pages provider. Submit to an explicit same-origin URL, or use `<Form form={form} url="/blog?save">`. Island success reloads or redirects the document, so state is rebuilt from SSR props. Duplicate submissions are suppressed; cancellation aborts the owned fetch but does not roll back a server write. Fields are sent as JSON. Ordinary `useForm` and the one-shot Pages `action` still require full Pages; use named imports of `useIslandForm`/`Form` in islands. Pages-only form imports (`useForm`, `action`) and ambiguous namespace/default form imports fail with a diagnostic in an island page or component. `useForm` also requires a full Pages provider at runtime. Use ordinary document links in static island pages. Pages navigation falls back to a document request for island routes. Static layouts remain server content and do not retain interactive state.
|
|
148
|
+
|
|
149
|
+
## Optional Markdown
|
|
150
|
+
|
|
151
|
+
Use a later alpha exporting `/markdown/plugin`; alpha.3 predates this API. For source validation, install the adapter using the local tarball steps above. Add parser peers explicitly only when using Markdown:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
npm install markdown-exit@1.3.0 yaml@2.9.1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { defineConfig } from 'vite';
|
|
159
|
+
import { voidPlugin } from 'void';
|
|
160
|
+
import { voidHonoJsx } from 'void-plugin-hono-jsx/plugin';
|
|
161
|
+
import { voidHonoMarkdown } from 'void-plugin-hono-jsx/markdown/plugin';
|
|
162
|
+
|
|
163
|
+
export default defineConfig({
|
|
164
|
+
plugins: [voidPlugin(), voidHonoJsx(), voidHonoMarkdown()],
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Create `.md` files in the Pages directory. Standard Markdown, tables, authored HTML, fenced code, heading anchors, YAML frontmatter, companion server loaders and TSX/JSX layouts are supported. Import `useFrontmatter()`, `useMarkdownHeadings()` and `useMarkdownProps()` from `void-plugin-hono-jsx/markdown` in layouts or islands. A leading `<script>` block before frontmatter may contain page-specific browser code and default relative TSX/JSX island imports. Islands use literal props and the load/visible/idle/media policies, including canonical identities for symlinked components. Frontmatter must be a JSON-serializable mapping; duplicate keys, invalid YAML and cycles fail compilation.
|
|
169
|
+
|
|
170
|
+
Markdown routes use document navigation, and static-only pages emit no executable script. Interactive/script pages reload on development edits; zero-script pages need a normal refresh. Raw HTML is preserved for repository-authored content, without sanitization for untrusted input. Markdown layout files, JSX-expression/tag-child island props, Shiki themes, footnotes, custom containers and a page-catalog virtual module are unsupported. Do not also configure `@void/md/plugin`. Ordinary Pages users do not need these parser peers. See the repository's [Markdown guide](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/markdown.md) for page examples, metadata scoping and the complete contract.
|
|
142
171
|
|
|
143
172
|
## Experimental limitations
|
|
144
173
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
The renderer/client entry conventions and provider integration were adapted from the published `@void/react` 0.26.0 adapter and Void 0.26.0. Both distributions include the following MIT notice. Hono is a peer dependency; its notice is included for reference. The project is separately licensed under MIT; these notices preserve upstream copyright attribution.
|
|
4
4
|
|
|
5
|
-
## Void and @void/
|
|
5
|
+
## Void, @void/react and @void/md
|
|
6
6
|
|
|
7
|
-
Source distributions: `void@0.26.0` and `@void/react@0.26.0`, published npm packages. The adapter imports framework APIs rather than bundling the framework.
|
|
7
|
+
Source distributions: `void@0.26.0` and `@void/react@0.26.0`, published npm packages. Link, prefetch lifecycle and form API behavior also reference the published `@void/react@0.27.0` adapter. Hono's render/navigation integration uses the public `void@0.26.1` / `void@0.27.0` navigation engine and router facade, with lifecycle behavior adapted from Void's router. Markdown script extraction, component-tag splitting and entry conventions reference the published `@void/md@0.27.0` implementation; its MIT attribution is preserved here. Markdown parsing uses the public `markdown-exit` and `yaml` APIs as optional peers. No private `@void/md` module is imported. The adapter imports framework APIs rather than bundling the framework.
|
|
8
8
|
|
|
9
9
|
MIT License
|
|
10
10
|
|
package/dist/browser/client.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type VoidRouterConfig } from 'void/pages-client';
|
|
2
|
+
type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;
|
|
2
3
|
type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
|
|
3
|
-
export declare function startHonoPages(manifest: Manifest): Promise<void>;
|
|
4
|
+
export declare function startHonoPages(manifest: Manifest, options: NavigationOptions): Promise<void>;
|
|
4
5
|
export {};
|
|
5
6
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAMrG,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,yBAAyB,CAAC,CAAC;AAEtH,KAAK,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,wBAAwB,CAAC,CAAC;AAO/I,wBAAsB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,iBA0GlF"}
|
package/dist/browser/client.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/dom/jsx-runtime";
|
|
2
|
-
import { render } from 'hono/jsx/dom';
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "hono/jsx/dom/jsx-runtime";
|
|
2
|
+
import { ErrorBoundary, render } from 'hono/jsx/dom';
|
|
3
3
|
import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
4
4
|
import { useLayoutEffect, useState } from 'hono/jsx';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { idleNavigationState } from 'void/pages-client';
|
|
6
|
+
import { PageContext, RouterContext, NavigationContext, setActionRouter } from "void-plugin-hono-jsx/pages";
|
|
7
|
+
import { createHonoRouter } from './navigation.js';
|
|
8
8
|
import { createDocumentHead } from './document-head.js';
|
|
9
9
|
import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.js';
|
|
10
10
|
function pageComponent(component) {
|
|
@@ -12,16 +12,22 @@ function pageComponent(component) {
|
|
|
12
12
|
throw new Error('Hono Pages: a page must export a component function.');
|
|
13
13
|
return component;
|
|
14
14
|
}
|
|
15
|
-
export async function startHonoPages(manifest) {
|
|
15
|
+
export async function startHonoPages(manifest, options) {
|
|
16
16
|
const root = document.getElementById('app');
|
|
17
17
|
if (!root)
|
|
18
18
|
throw new Error('Hono Pages: app root is missing.');
|
|
19
19
|
let update;
|
|
20
20
|
let revision = 0;
|
|
21
|
+
let commit = 0;
|
|
22
|
+
const pendingCommits = new Map();
|
|
23
|
+
let committedFrame;
|
|
24
|
+
const failedFrames = new Set();
|
|
25
|
+
let navigationState = idleNavigationState();
|
|
26
|
+
let updateNavigation;
|
|
21
27
|
let applyDocumentHead;
|
|
22
28
|
let renderedProps;
|
|
23
29
|
let updateDeferred;
|
|
24
|
-
const initialization =
|
|
30
|
+
const initialization = createHonoRouter({
|
|
25
31
|
...manifest,
|
|
26
32
|
adapter: {
|
|
27
33
|
createDeferred, resolveDeferred, rejectDeferred, isLoading,
|
|
@@ -37,37 +43,85 @@ export async function startHonoPages(manifest) {
|
|
|
37
43
|
if (!options.preserveState)
|
|
38
44
|
revision++;
|
|
39
45
|
renderedProps = page.props;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
const nextCommit = ++commit;
|
|
47
|
+
const committed = new Promise((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));
|
|
48
|
+
update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });
|
|
49
|
+
await committed;
|
|
43
50
|
},
|
|
44
51
|
},
|
|
45
|
-
|
|
46
|
-
prefetchHoverDelay: 75,
|
|
47
|
-
prefetchDefaultCacheFor: parseCacheFor('30s'),
|
|
52
|
+
...options,
|
|
48
53
|
cacheVisitedPageData: false,
|
|
49
|
-
onNavigationChange(state) { root.dataset.navigation = state.state; },
|
|
54
|
+
onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },
|
|
50
55
|
});
|
|
51
56
|
const releaseBuffer = bufferInitialDeferred();
|
|
52
57
|
const navigation = await initialization.finally(releaseBuffer);
|
|
58
|
+
setActionRouter(navigation.router);
|
|
53
59
|
renderedProps = navigation.initialPageData.props;
|
|
54
60
|
applyDocumentHead = createDocumentHead(navigation.initialPageData.head);
|
|
61
|
+
const initialFrame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };
|
|
62
|
+
function PageFrame({ frame }) {
|
|
63
|
+
useLayoutEffect(() => {
|
|
64
|
+
if (failedFrames.has(frame.commit))
|
|
65
|
+
return;
|
|
66
|
+
if (frame.commit > 0)
|
|
67
|
+
applyDocumentHead?.(frame.page.head);
|
|
68
|
+
committedFrame = frame;
|
|
69
|
+
for (const id of failedFrames)
|
|
70
|
+
if (id < frame.commit)
|
|
71
|
+
failedFrames.delete(id);
|
|
72
|
+
for (const [id, pending] of pendingCommits)
|
|
73
|
+
if (id <= frame.commit) {
|
|
74
|
+
pendingCommits.delete(id);
|
|
75
|
+
pending.resolve();
|
|
76
|
+
}
|
|
77
|
+
}, [frame]);
|
|
78
|
+
let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));
|
|
79
|
+
const ids = manifest.layoutTree[frame.page.component] ?? [];
|
|
80
|
+
for (let index = frame.layouts.length - 1; index >= 0; index--) {
|
|
81
|
+
content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);
|
|
82
|
+
}
|
|
83
|
+
return _jsx(PageContext.Provider, { value: frame.page, children: content });
|
|
84
|
+
}
|
|
55
85
|
function App() {
|
|
56
|
-
const [frame, setFrame] = useState(
|
|
86
|
+
const [frame, setFrame] = useState(initialFrame);
|
|
87
|
+
const [pendingNavigation, setNavigation] = useState(navigationState);
|
|
57
88
|
const [failed, setFailed] = useState(false);
|
|
89
|
+
const [recovery, setRecovery] = useState(0);
|
|
58
90
|
useLayoutEffect(() => {
|
|
91
|
+
updateNavigation = setNavigation;
|
|
92
|
+
setNavigation(navigationState);
|
|
59
93
|
updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));
|
|
60
94
|
update = (next) => { setFailed(false); setFrame(next); };
|
|
61
95
|
const onError = () => setFailed(true);
|
|
62
96
|
window.addEventListener('hono-pages:navigation-error', onError);
|
|
63
|
-
return () => {
|
|
97
|
+
return () => { for (const pending of pendingCommits.values())
|
|
98
|
+
pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };
|
|
64
99
|
}, []);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
const renderFailed = (error) => {
|
|
101
|
+
if (failedFrames.has(frame.commit))
|
|
102
|
+
return;
|
|
103
|
+
failedFrames.add(frame.commit);
|
|
104
|
+
queueMicrotask(() => {
|
|
105
|
+
// A rejected child never reaches PageFrame's commit effect. Roll back
|
|
106
|
+
// outside the render traversal, then reject every coalesced waiter.
|
|
107
|
+
if (commit === frame.commit) {
|
|
108
|
+
if (committedFrame) {
|
|
109
|
+
renderedProps = committedFrame.sourceProps;
|
|
110
|
+
setFrame(committedFrame);
|
|
111
|
+
}
|
|
112
|
+
// Discard the partially built Hono tree only after a render failure.
|
|
113
|
+
// Successful navigations keep the same boundary and layout state.
|
|
114
|
+
setRecovery(value => value + 1);
|
|
115
|
+
setFailed(true);
|
|
116
|
+
}
|
|
117
|
+
for (const [id, pending] of pendingCommits)
|
|
118
|
+
if (id <= frame.commit) {
|
|
119
|
+
pendingCommits.delete(id);
|
|
120
|
+
pending.reject(error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
return _jsx(RouterContext.Provider, { value: navigation.router, children: _jsxs(NavigationContext.Provider, { value: pendingNavigation, children: [failed && _jsx("p", { role: "alert", children: "The page could not be loaded. Please try again." }), _jsx(ErrorBoundary, { onError: renderFailed, fallback: _jsx(_Fragment, {}), children: _jsx(PageFrame, { frame: frame }) }, recovery)] }) });
|
|
71
125
|
}
|
|
72
126
|
render(_jsx(App, {}), root);
|
|
73
127
|
navigation.start();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { createVoidRouter, type VoidRouterConfig } from 'void/pages-client';\nimport { parseCacheFor } from 'void/pages-prefetch';\nimport { PageContext, RouterContext } from './pages.tsx';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest) {\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createVoidRouter>>['initialPageData']; component: unknown; layouts: unknown[]; revision: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createVoidRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n update({ page: { ...page, props: { ...page.props } }, component, layouts, revision });\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n applyDocumentHead?.(page.head);\n },\n },\n viewTransitions: false,\n prefetchHoverDelay: 75,\n prefetchDefaultCacheFor: parseCacheFor('30s'),\n cacheVisitedPageData: false,\n onNavigationChange(state) { root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n function App() {\n const [frame, setFrame] = useState<Frame>({ page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision });\n const [failed, setFailed] = useState(false);\n useLayoutEffect(() => {\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <RouterContext.Provider value={navigation.router}>\n <PageContext.Provider value={frame.page}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n {content}\n </PageContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { ErrorBoundary, render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';\nimport { createHonoRouter } from './navigation.ts';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest, options: NavigationOptions) {\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let commit = 0;\n const pendingCommits = new Map<number, { resolve(): void; reject(error: unknown): void }>();\n let committedFrame: Frame | undefined;\n const failedFrames = new Set<number>();\n let navigationState = idleNavigationState();\n let updateNavigation: ((state: NavigationState) => void) | undefined;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createHonoRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n const nextCommit = ++commit;\n const committed = new Promise<void>((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));\n update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });\n await committed;\n },\n },\n ...options,\n cacheVisitedPageData: false,\n onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n setActionRouter(navigation.router);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n const initialFrame: Frame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };\n function PageFrame({ frame }: { frame: Frame }) {\n useLayoutEffect(() => {\n if (failedFrames.has(frame.commit)) return;\n if (frame.commit > 0) applyDocumentHead?.(frame.page.head);\n committedFrame = frame;\n for (const id of failedFrames) if (id < frame.commit) failedFrames.delete(id);\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.resolve(); }\n }, [frame]);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <PageContext.Provider value={frame.page}>{content}</PageContext.Provider>;\n }\n\n function App() {\n const [frame, setFrame] = useState<Frame>(initialFrame);\n const [pendingNavigation, setNavigation] = useState(navigationState);\n const [failed, setFailed] = useState(false);\n const [recovery, setRecovery] = useState(0);\n useLayoutEffect(() => {\n updateNavigation = setNavigation;\n setNavigation(navigationState);\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { for (const pending of pendingCommits.values()) pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n const renderFailed = (error: unknown) => {\n if (failedFrames.has(frame.commit)) return;\n failedFrames.add(frame.commit);\n queueMicrotask(() => {\n // A rejected child never reaches PageFrame's commit effect. Roll back\n // outside the render traversal, then reject every coalesced waiter.\n if (commit === frame.commit) {\n if (committedFrame) { renderedProps = committedFrame.sourceProps; setFrame(committedFrame); }\n // Discard the partially built Hono tree only after a render failure.\n // Successful navigations keep the same boundary and layout state.\n setRecovery(value => value + 1);\n setFailed(true);\n }\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.reject(error); }\n });\n };\n return <RouterContext.Provider value={navigation.router}>\n <NavigationContext.Provider value={pendingNavigation}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>\n <PageFrame frame={frame} />\n </ErrorBoundary>\n </NavigationContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { HeadDescriptor } from 'void';
|
|
2
|
-
/**
|
|
2
|
+
/** Synchronizes the snapshot before Void's idempotent post-render head commit. */
|
|
3
3
|
export declare function createDocumentHead(initial: HeadDescriptor | undefined): (head: HeadDescriptor | undefined) => void;
|
|
4
4
|
//# sourceMappingURL=document-head.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-head.d.ts","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"document-head.d.ts","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAgB3C,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,UAgBtD,cAAc,GAAG,SAAS,UA4BzC"}
|
|
@@ -7,7 +7,10 @@ function scriptElements(head) {
|
|
|
7
7
|
template.innerHTML = renderHeadToString({ script: head?.script });
|
|
8
8
|
return Array.from(template.content.querySelectorAll('script'));
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
function metadataSignature(element) {
|
|
11
|
+
return JSON.stringify([element.tagName, Array.from(element.attributes, ({ name, value }) => [name, value]).filter(([name]) => name !== 'data-void-head').sort()]);
|
|
12
|
+
}
|
|
13
|
+
/** Synchronizes the snapshot before Void's idempotent post-render head commit. */
|
|
11
14
|
export function createDocumentHead(initial) {
|
|
12
15
|
let htmlKeys = Object.keys(initial?.htmlAttrs ?? {});
|
|
13
16
|
let bodyKeys = Object.keys(initial?.bodyAttrs ?? {});
|
|
@@ -27,6 +30,24 @@ export function createDocumentHead(initial) {
|
|
|
27
30
|
return Object.keys(next);
|
|
28
31
|
}
|
|
29
32
|
return (head) => {
|
|
33
|
+
if (head?.title !== undefined)
|
|
34
|
+
document.title = head.title;
|
|
35
|
+
// Use Void's serializer and managed-tag marker so the router's subsequent
|
|
36
|
+
// commit reuses these nodes instead of inserting duplicate meta/link tags.
|
|
37
|
+
const template = document.createElement('template');
|
|
38
|
+
template.innerHTML = renderHeadToString({ meta: head?.meta, link: head?.link });
|
|
39
|
+
const metadata = Array.from(document.head.querySelectorAll('meta[data-void-head],link[data-void-head]'));
|
|
40
|
+
let cursor = document.head.querySelector('meta[data-void-head],link[data-void-head]');
|
|
41
|
+
for (const desired of Array.from(template.content.querySelectorAll('meta,link'))) {
|
|
42
|
+
const index = metadata.findIndex(element => metadataSignature(element) === metadataSignature(desired));
|
|
43
|
+
const element = index >= 0 ? metadata.splice(index, 1)[0] : desired;
|
|
44
|
+
element.setAttribute('data-void-head', '');
|
|
45
|
+
if (element !== cursor)
|
|
46
|
+
document.head.insertBefore(element, cursor);
|
|
47
|
+
cursor = element.nextSibling;
|
|
48
|
+
}
|
|
49
|
+
for (const previous of metadata)
|
|
50
|
+
previous.remove();
|
|
30
51
|
htmlKeys = attributes(document.documentElement, htmlKeys, head?.htmlAttrs);
|
|
31
52
|
bodyKeys = attributes(document.body, bodyKeys, head?.bodyAttrs);
|
|
32
53
|
const remaining = [...scripts];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-head.js","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGrD,SAAS,eAAe,CAAC,MAAyB;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AACxH,CAAC;AAED,SAAS,cAAc,CAAC,IAAgC;IACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IACpD,QAAQ,CAAC,SAAS,GAAG,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"document-head.js","sourceRoot":"","sources":["../../src/runtime/document-head.ts"],"names":[],"mappings":"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","sourcesContent":["import { renderHeadToString } from 'void/pages-head';\nimport type { HeadDescriptor } from 'void';\n\nfunction scriptSignature(script: HTMLScriptElement) {\n return JSON.stringify([Array.from(script.attributes, ({ name, value }) => [name, value]).sort(), script.textContent]);\n}\n\nfunction scriptElements(head: HeadDescriptor | undefined) {\n const template = document.createElement('template');\n template.innerHTML = renderHeadToString({ script: head?.script });\n return Array.from(template.content.querySelectorAll('script'));\n}\n\nfunction metadataSignature(element: Element) {\n return JSON.stringify([element.tagName, Array.from(element.attributes, ({ name, value }) => [name, value]).filter(([name]) => name !== 'data-void-head').sort()]);\n}\n\n/** Synchronizes the snapshot before Void's idempotent post-render head commit. */\nexport function createDocumentHead(initial: HeadDescriptor | undefined) {\n let htmlKeys = Object.keys(initial?.htmlAttrs ?? {});\n let bodyKeys = Object.keys(initial?.bodyAttrs ?? {});\n let scripts: HTMLScriptElement[] = [];\n const existing = Array.from(document.head.querySelectorAll('script'));\n for (const desired of scriptElements(initial)) {\n const index = existing.findIndex((script) => scriptSignature(script) === scriptSignature(desired));\n if (index >= 0) scripts.push(...existing.splice(index, 1));\n }\n\n function attributes(element: HTMLElement, previous: string[], next: Record<string, string> = {}) {\n for (const key of previous) if (!(key in next)) element.removeAttribute(key);\n for (const [key, value] of Object.entries(next)) element.setAttribute(key, value);\n return Object.keys(next);\n }\n\n return (head: HeadDescriptor | undefined) => {\n if (head?.title !== undefined) document.title = head.title;\n // Use Void's serializer and managed-tag marker so the router's subsequent\n // commit reuses these nodes instead of inserting duplicate meta/link tags.\n const template = document.createElement('template');\n template.innerHTML = renderHeadToString({ meta: head?.meta, link: head?.link });\n const metadata = Array.from(document.head.querySelectorAll('meta[data-void-head],link[data-void-head]'));\n let cursor = document.head.querySelector('meta[data-void-head],link[data-void-head]') as Node | null;\n for (const desired of Array.from(template.content.querySelectorAll('meta,link'))) {\n const index = metadata.findIndex(element => metadataSignature(element) === metadataSignature(desired));\n const element = index >= 0 ? metadata.splice(index, 1)[0] : desired;\n element.setAttribute('data-void-head', '');\n if (element !== cursor) document.head.insertBefore(element, cursor);\n cursor = element.nextSibling;\n }\n for (const previous of metadata) previous.remove();\n htmlKeys = attributes(document.documentElement, htmlKeys, head?.htmlAttrs);\n bodyKeys = attributes(document.body, bodyKeys, head?.bodyAttrs);\n const remaining = [...scripts];\n scripts = scriptElements(head).map((desired) => {\n const index = remaining.findIndex((script) => scriptSignature(script) === scriptSignature(desired));\n if (index >= 0) return remaining.splice(index, 1)[0];\n // Template-parsed scripts remain inert when inserted. Head changes are metadata, not script execution.\n document.head.appendChild(desired);\n return desired;\n });\n for (const script of remaining) script.remove();\n };\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type JSX, type Child } from 'hono/jsx';
|
|
2
|
+
import { type FormMethod, type FormModel, type VoidActionError } from 'void/pages-client';
|
|
3
|
+
export type FormProps = Omit<JSX.IntrinsicElements['form'], 'action' | 'method' | 'onSubmit' | 'onError'> & {
|
|
4
|
+
form: FormModel<[string | FormData | undefined]>;
|
|
5
|
+
method?: FormMethod;
|
|
6
|
+
url?: string;
|
|
7
|
+
renderError?: (error: VoidActionError) => Child;
|
|
8
|
+
};
|
|
9
|
+
export declare function Form({ form, method, url, renderError, children, ...props }: FormProps): import("hono/jsx/dom/jsx-dev-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=form-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-view.d.ts","sourceRoot":"","sources":["../../src/runtime/form-view.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EAAgF,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAExK,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC,GAAG;IAC1G,IAAI,EAAE,SAAS,CAAC,CAAC,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;IACjD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,KAAK,CAAC;CACjD,CAAC;AACF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,sDAa9F"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/dom/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'hono/jsx';
|
|
3
|
+
import { formErrorMessage, formRetryMessage, formSubmissionBlocked, scheduleFormRetry } from 'void/pages-client';
|
|
4
|
+
export function Form({ form, method = 'post', url, renderError, children, ...props }) {
|
|
5
|
+
const [now, setNow] = useState(Date.now());
|
|
6
|
+
useEffect(() => scheduleFormRetry(form.error, () => setNow(Date.now())), [form.error]);
|
|
7
|
+
const message = formErrorMessage(form);
|
|
8
|
+
const retry = formRetryMessage(form.error);
|
|
9
|
+
const blocked = formSubmissionBlocked(form, now);
|
|
10
|
+
return _jsxs("form", { ...props, "aria-busy": form.pending, onSubmit: (event) => {
|
|
11
|
+
event.preventDefault();
|
|
12
|
+
if (!blocked)
|
|
13
|
+
void form[method](url ?? new FormData(event.currentTarget));
|
|
14
|
+
}, children: [message && _jsxs("div", { role: "alert", "data-void-form-error": true, children: [form.error && renderError ? renderError(form.error) : message, retry && _jsx("p", { children: retry })] }), children] });
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=form-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-view.js","sourceRoot":"","sources":["../../src/runtime/form-view.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAwB,MAAM,UAAU,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAyD,MAAM,mBAAmB,CAAC;AAQxK,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAa;IAC7F,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,SAAS,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACvF,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,mBAAU,KAAK,eAAa,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAY,EAAE,EAAE;YAC1E,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO;gBAAE,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,aAAgC,CAAC,CAAC,CAAC;QAC/F,CAAC,aACE,OAAO,IAAI,eAAK,IAAI,EAAC,OAAO,2CAAuB,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,IAAI,sBAAI,KAAK,GAAK,IAAO,EAChJ,QAAQ,IACJ,CAAC;AACV,CAAC","sourcesContent":["import { useEffect, useState, type JSX, type Child } from 'hono/jsx';\nimport { formErrorMessage, formRetryMessage, formSubmissionBlocked, scheduleFormRetry, type FormMethod, type FormModel, type VoidActionError } from 'void/pages-client';\n\nexport type FormProps = Omit<JSX.IntrinsicElements['form'], 'action' | 'method' | 'onSubmit' | 'onError'> & {\n form: FormModel<[string | FormData | undefined]>;\n method?: FormMethod;\n url?: string;\n renderError?: (error: VoidActionError) => Child;\n};\nexport function Form({ form, method = 'post', url, renderError, children, ...props }: FormProps) {\n const [now, setNow] = useState(Date.now());\n useEffect(() => scheduleFormRetry(form.error, () => setNow(Date.now())), [form.error]);\n const message = formErrorMessage(form);\n const retry = formRetryMessage(form.error);\n const blocked = formSubmissionBlocked(form, now);\n return <form {...props} aria-busy={form.pending} onSubmit={(event: Event) => {\n event.preventDefault();\n if (!blocked) void form[method](url ?? new FormData(event.currentTarget as HTMLFormElement));\n }}>\n {message && <div role=\"alert\" data-void-form-error>{form.error && renderError ? renderError(form.error) : message}{retry && <p>{retry}</p>}</div>}\n {children}\n </form>;\n}\n"]}
|
package/dist/browser/form.d.ts
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
import { type FormMethod } from 'void/pages-client';
|
|
2
|
-
|
|
1
|
+
import { VoidActionError, type FormMethod } from 'void/pages-client';
|
|
2
|
+
import type { ActionFormOptions, ActionUrl, ResolveActionBody } from 'void/routes';
|
|
3
|
+
import { action } from './pages.tsx';
|
|
4
|
+
export { Form, type FormProps } from './form-view.tsx';
|
|
5
|
+
export { action };
|
|
6
|
+
type Fields = Record<string, unknown>;
|
|
7
|
+
type Body<U extends string> = ResolveActionBody<U> extends Fields ? ResolveActionBody<U> : Fields;
|
|
8
|
+
type SetData<T> = {
|
|
9
|
+
(next: T | ((current: T) => T)): void;
|
|
10
|
+
<K extends keyof T & string>(field: K, value: T[K]): void;
|
|
11
|
+
};
|
|
12
|
+
export type HonoForm<T extends Fields> = {
|
|
3
13
|
data: T;
|
|
4
|
-
setData:
|
|
14
|
+
setData: SetData<T>;
|
|
5
15
|
errors: Record<string, string>;
|
|
6
16
|
pending: boolean;
|
|
17
|
+
error: VoidActionError | null;
|
|
18
|
+
hasChanges: boolean;
|
|
7
19
|
wasSuccessful: boolean;
|
|
8
|
-
|
|
9
|
-
submit
|
|
10
|
-
cancel
|
|
11
|
-
reset
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
recentlySuccessful: boolean;
|
|
21
|
+
submit(method: FormMethod, target?: string | FormData): Promise<void>;
|
|
22
|
+
cancel(): void;
|
|
23
|
+
reset: {
|
|
24
|
+
(): void;
|
|
25
|
+
(...fields: Array<keyof T & string>): void;
|
|
26
|
+
};
|
|
27
|
+
clearErrors(...fields: Array<keyof T & string>): void;
|
|
28
|
+
clearError(): void;
|
|
29
|
+
} & Record<FormMethod, (target?: string | FormData) => Promise<void>>;
|
|
30
|
+
export declare function useForm<T extends Fields>(initialData: T): HonoForm<T>;
|
|
31
|
+
export declare function useForm<U extends ActionUrl & string>(url: U, defaults: Body<U>, options?: ActionFormOptions<U>): HonoForm<Body<U>>;
|
|
32
|
+
export declare function useIslandForm<T extends Fields>(defaults: T): HonoForm<T>;
|
|
17
33
|
//# sourceMappingURL=form.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/runtime/form.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/runtime/form.ts"],"names":[],"mappings":"AACA,OAAO,EAAwE,eAAe,EAAqB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC9J,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAuC,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACtC,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,iBAAiB,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAClG,KAAK,OAAO,CAAC,CAAC,IAAI;IAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;IAAC,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;CAAE,CAAC;AACvH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI;IACvC,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAC/E,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAC;IACxG,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,MAAM,IAAI,IAAI,CAAC;IACtF,KAAK,EAAE;QAAE,IAAI,IAAI,CAAC;QAAC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;IAAC,WAAW,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAAC,UAAU,IAAI,IAAI,CAAC;CAC5I,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAgBtE,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,WAAW,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvE,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,GAAG,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAQpI,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAcxE"}
|