Skip to content

Commit cb532f1

Browse files
yangshuncursoragent
andcommitted
docs: show Pages examples for every framework
Component samples were Vue-only or JSX-only, so the guides now tab React, Vue, Svelte, and Solid where the syntax differs. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 10a9b9c commit cb532f1

4 files changed

Lines changed: 281 additions & 14 deletions

File tree

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Deploy hosted production before publishing the npm packages: the CLI checks the
1919

2020
- **Do not use Python for repository scripts or automation**, including inline CI scripts and ad-hoc maintenance commands. Use Node.js with TypeScript/JavaScript, or shell/PowerShell where appropriate.
2121
- **Keep user-facing documentation focused on using Void.** Explain public APIs, configuration, observable behavior, and actions users need to take. Do not add implementation details, internal workarounds, defensive checks, normalization rules, or bug-fix history unless they help users make a decision or resolve an actionable problem. Maintainer-only knowledge belongs in source comments, repository/package `AGENTS.md`, or contributor guides. This applies to app guides, API/CLI references, consumer-facing READMEs, and shipped app-development skills. Code examples should type-check. When an API does not infer a route, param, or path type, annotate the example with the public type that checks it, such as `PageParams`, `RouteUrl`, or `routeUrl()`.
22+
- **Keep Pages examples framework-agnostic.** Void Pages supports React, Vue, Svelte, and Solid. When a docs example uses an adapter API and the syntax differs, show all four in a `::: code-group` with those tab labels. When the code is the same, write it once; if only the import path differs, name the other packages in a comment (`@void/react`, `@void/vue`, `@void/svelte`, `@void/solid`). Do not use one framework's component syntax, import, or file extension as the only example. Keep a single framework when the section is that framework's own API, a labeled custom SSR renderer, a JSX route handler, or an integration guide. Do not wrap a one-snippet example in a code group.
2223
- **Keep native Cloudflare deploys Workers Free-compatible by default.** New public Void SDK/runtime features must work with `void deploy --platform cloudflare` on Workers Free unless the underlying Cloudflare product has no Free offering. Paid-only functionality must be explicitly opt-in, inferred and emitted only when the app uses it, and checked before provisioning or building. Its documentation and deploy error must name the required Cloudflare product/plan, link to enable it, and explain any API-token permissions. Platform-internal paid services must never become requirements of a single-app native Cloudflare deploy. Add regression coverage proving that an app which does not use the paid feature emits no paid binding and performs no entitlement probe.
2324
- Every implementation plan should include the following:
2425
- During plan generation: ask clarifying questions when necessary, especially around developer-experience defining design decisions.

‎docs/guide/pages-routing/markdown.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,13 @@ Welcome to Void. Here's an interactive demo:
136136
<Counter />
137137
```
138138

139-
- **`<script>` block:** extracted before markdown compilation. Island imports use `with { island: "..." }` syntax (see [islands](./islands)). Any other code in the block becomes a [client script](#client-scripts) that runs in the browser.
139+
- **`<script>` block:** extracted before markdown compilation. Island imports use `with { island: "..." }` syntax (see [islands](./islands)). The component file uses your framework's extension (`.vue`, `.tsx`, or `.svelte`). Any other code in the block becomes a [client script](#client-scripts) that runs in the browser.
140140
- **Frontmatter:** YAML metadata between `---` fences. Layouts and islands can read it through [`useFrontmatter()`](#frontmatter-access).
141141
- **Body:** standard markdown plus GFM. Uppercase tags such as `<Counter />` reference imported components and render as islands.
142142

143143
## Client Scripts
144144

145-
Use the `<script>` block for island imports and JavaScript that runs when the page loads:
145+
Use the `<script>` block for island imports and JavaScript that runs when the page loads. Import the component with your framework's extension (`.vue`, `.tsx`, or `.svelte`):
146146

147147
```md
148148
<script>

‎docs/guide/pages-routing/overview.md‎

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,80 @@ With [`routing.typedRoutes`](../type-safety.md#checked-url-strings), which apps
203203

204204
`Link` also supports query data, history replacement, full-page navigation, and cancellation:
205205

206-
```tsx
206+
::: code-group
207+
208+
```tsx [React]
209+
import { Link } from '@void/react';
210+
211+
<Link href="/users" data={{ page: 2, tag: ['active', 'new'] }}>
212+
Filtered users
213+
</Link>
214+
215+
<Link href="/users" replace>
216+
Users
217+
</Link>
218+
219+
<Link href="/logout" reloadDocument>
220+
Sign out
221+
</Link>
222+
223+
<Link
224+
href="/settings"
225+
onNavigate={(event) => {
226+
if (!confirm('Leave this page?')) {
227+
event.preventDefault();
228+
}
229+
}}
230+
>
231+
Settings
232+
</Link>
233+
```
234+
235+
```vue [Vue]
236+
<script setup lang="ts">
237+
import { Link } from '@void/vue';
238+
239+
function onNavigate(event: { preventDefault(): void }) {
240+
if (!confirm('Leave this page?')) {
241+
event.preventDefault();
242+
}
243+
}
244+
</script>
245+
246+
<template>
247+
<Link href="/users" :data="{ page: 2, tag: ['active', 'new'] }">Filtered users</Link>
248+
<Link href="/users" replace>Users</Link>
249+
<Link href="/logout" reload-document>Sign out</Link>
250+
<Link href="/settings" :on-navigate="onNavigate">Settings</Link>
251+
</template>
252+
```
253+
254+
```svelte [Svelte]
255+
<script lang="ts">
256+
import { Link } from '@void/svelte';
257+
</script>
258+
259+
<Link href="/users" data={{ page: 2, tag: ['active', 'new'] }}>Filtered users</Link>
260+
261+
<Link href="/users" replace>Users</Link>
262+
263+
<Link href="/logout" reloadDocument>Sign out</Link>
264+
265+
<Link
266+
href="/settings"
267+
onNavigate={(event) => {
268+
if (!confirm('Leave this page?')) {
269+
event.preventDefault();
270+
}
271+
}}
272+
>
273+
Settings
274+
</Link>
275+
```
276+
277+
```tsx [Solid]
278+
import { Link } from '@void/solid';
279+
207280
<Link href="/users" data={{ page: 2, tag: ['active', 'new'] }}>
208281
Filtered users
209282
</Link>
@@ -228,6 +301,8 @@ With [`routing.typedRoutes`](../type-safety.md#checked-url-strings), which apps
228301
</Link>
229302
```
230303

304+
:::
305+
231306
`prefetch` and `reloadDocument` work only with GET links. GET `data` becomes query parameters; use scalar values or arrays.
232307

233308
For programmatic navigation, use `useRouter()`. Pass a typed destination object to `visit()`, `prefetch()`, or `flush()`:
@@ -256,7 +331,9 @@ You can also pass URL strings or `URL` instances to these router methods. See [T
256331

257332
For dynamic route params, use `useParams()` from the same adapter package. Pass the page's URL pattern as the type argument to type the result:
258333

259-
```tsx
334+
::: code-group
335+
336+
```tsx [React]
260337
// pages/posts/[id].tsx
261338
import { useParams } from '@void/react';
262339

@@ -266,6 +343,42 @@ export default function PostPage() {
266343
}
267344
```
268345

346+
```vue [Vue]
347+
<!-- pages/posts/[id].vue -->
348+
<script setup lang="ts">
349+
import { useParams } from '@void/vue';
350+
351+
const params = useParams<'/posts/:id'>(); // { id: string }
352+
</script>
353+
354+
<template>
355+
<h1>Post {{ params.id }}</h1>
356+
</template>
357+
```
358+
359+
```svelte [Svelte]
360+
<!-- pages/posts/[id].svelte -->
361+
<script lang="ts">
362+
import { useParams } from '@void/svelte';
363+
364+
const params = useParams<'/posts/:id'>(); // { id: string }
365+
</script>
366+
367+
<h1>Post {params.id}</h1>
368+
```
369+
370+
```tsx [Solid]
371+
// pages/posts/[id].tsx
372+
import { useParams } from '@void/solid';
373+
374+
export default function PostPage() {
375+
const params = useParams<'/posts/:id'>(); // { id: string }
376+
return <h1>Post {params.id}</h1>;
377+
}
378+
```
379+
380+
:::
381+
269382
See [Page params](../type-safety.md#page-params) for how patterns are checked.
270383

271384
### Active links

0 commit comments

Comments
 (0)