release: WRNexusJS 0.6.0
This commit is contained in:
@@ -303,3 +303,103 @@ wrnexus eject <component> # copy a Wire UI component's .wrn into app/compone
|
||||
3. For data, add an `app/api/*.ts` route and `getDb()`; for forms, add an `app/schemas/*.ts` and `data-schema`.
|
||||
4. Style with Tailwind utility classes in the view, or theme tokens (`var(--wire-*)`), or `style { }`.
|
||||
5. Never emit React/JSX, a manual router, or client-side island JS — the framework handles hydration.
|
||||
|
||||
## WRNexusJS v0.6 canonical language
|
||||
|
||||
|
||||
Use normal imports, TypeScript contracts, typed state, callable outputs, runtime-specific functions, typed server calls, and framework stores:
|
||||
|
||||
```wrn
|
||||
import type { PublicUser, ConfirmPayload, ConfirmResult } from "@/types/user.ts"
|
||||
import PublicLayout from "@/layouts/PublicLayout.wrn"
|
||||
import userStore from "@/stores/global/user.wrn"
|
||||
import { Button, Modal } from "@wrnexus/ui"
|
||||
|
||||
page ProfilePage {
|
||||
layout = PublicLayout
|
||||
|
||||
props {
|
||||
title: string
|
||||
user?: PublicUser
|
||||
}
|
||||
|
||||
state {
|
||||
loading: boolean = false
|
||||
}
|
||||
|
||||
client state {
|
||||
modalOpen: boolean = false
|
||||
}
|
||||
|
||||
server state {
|
||||
internalSessionId: string | null = null
|
||||
}
|
||||
|
||||
outputs {
|
||||
success(payload: ConfirmResult)
|
||||
cancel()
|
||||
}
|
||||
|
||||
functions {
|
||||
client async function confirm(payload: ConfirmPayload): Promise<void> {
|
||||
loading = true
|
||||
try {
|
||||
const result = await server.confirm(payload)
|
||||
output.success(result)
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
server async function confirm(payload: ConfirmPayload): Promise<ConfirmResult> {
|
||||
return await confirmationService.save(payload)
|
||||
}
|
||||
|
||||
shared function normalize(value: string): string {
|
||||
return value.trim()
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
<Modal open='{modalOpen}' @confirm='confirm(payload)'>
|
||||
<Button disabled='{loading}'>Save</Button>
|
||||
</Modal>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Canonical function modifier order is `runtime -> async -> function -> name`.
|
||||
- Use `output.name(payload)` for component outputs; `$emit` is compatibility-only.
|
||||
- Native DOM handlers receive `event`; component-output handlers receive `payload`.
|
||||
- `server.name(...)` performs a typed same-origin RPC call from browser code.
|
||||
- `app/types/global.d.ts` is ambient; other `app/types/*.ts` files require `import type`.
|
||||
- `state` is shared/hydrated, `client state` is browser-only, and `server state` is never serialized.
|
||||
- Global stores are request-scoped in SSR and survive CSR navigation. Page stores are disposed on route leave.
|
||||
- Existing projects default to compatible import/event/layout behavior; new code should use explicit imports and typed contracts.
|
||||
|
||||
Store example:
|
||||
|
||||
```wrn
|
||||
global store UserStore {
|
||||
state {
|
||||
user: PublicUser | null = null
|
||||
}
|
||||
|
||||
computed {
|
||||
authenticated: boolean = user !== null
|
||||
}
|
||||
|
||||
persist {
|
||||
storage = "local"
|
||||
include = ["user"]
|
||||
version = 1
|
||||
}
|
||||
|
||||
functions {
|
||||
client function clear(): void {
|
||||
user = null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user