Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .claude/rules/anti-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
- **Never** call `signal(value)` to set — use `signal.set(value)` or `signal.update(fn)`
- **Never** forget to call signal as function to read: use `count()` not `count`

## JSX attribute casing
- **Always** use camelCase for JSX attributes: `onClick`, `onMouseEnter`, `onTouchStart`, `onLoad`
- **Never** use lowercase DOM event names: `onclick`, `onmouseenter`, `ontouchstart`, `onload`
- **Always** use `srcSet` not `srcset`, `fetchPriority` not `fetchpriority`
- **Always** use `className` → `class`, `htmlFor` → `for` (Pyreon uses HTML names, not React names)

## JSX reactive expressions
- **Never** use bare signal reads in JSX text — wrap in arrow: `{() => count()}` not `{count()}`
- **Never** return `undefined` from reactive JSX attributes — return empty string `''` instead
Expand Down
120 changes: 60 additions & 60 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@changesets/cli": "^2.30.0",
"@clack/core": "^1.1.0",
"@clack/prompts": "^1.1.0",
"@pyreon/typescript": "^0.7.5",
"@pyreon/typescript": "^0.7.11",
"@types/bun": "^1.3.11",
"@types/node": "^25.5.0",
"@vitus-labs/tools-lint": "^1.15.4",
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@pyreon/cli": "^0.7.5",
"@pyreon/cli": "^0.7.11",
"@pyreon/create-zero": "workspace:^",
"@pyreon/server": "^0.7.5",
"@pyreon/server": "^0.7.11",
"@pyreon/zero": "workspace:^",
"cac": "^7.0.0",
"vite": "^8.0.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/create-zero/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,12 @@ async function scaffold(config: ProjectConfig) {
function pyreonVersion(pkg: string): string {
// Core packages
const core = ['core', 'reactivity', 'runtime-dom', 'runtime-server', 'server', 'head', 'router', 'vite-plugin', 'compiler', 'cli', 'mcp']
if (core.some((c) => pkg === `@pyreon/${c}`)) return '^0.7.5'
if (core.some((c) => pkg === `@pyreon/${c}`)) return '^0.7.11'
// Zero framework packages
if (pkg === '@pyreon/zero' || pkg === '@pyreon/meta' || pkg === '@pyreon/zero-cli' || pkg === '@pyreon/create-zero') return '^0.3.0'
// Fundamentals
const fundamentals = ['store', 'form', 'validation', 'query', 'table', 'virtual', 'i18n', 'feature', 'machine', 'permissions', 'flow', 'code']
if (fundamentals.some((f) => pkg === `@pyreon/${f}`)) return '^0.9.0'
if (fundamentals.some((f) => pkg === `@pyreon/${f}`)) return '^0.10.0'
// UI system
return '^0.3.0'
}
Expand Down
4 changes: 3 additions & 1 deletion packages/create-zero/templates/default/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ This project uses Pyreon Zero, a signal-based full-stack meta-framework. Do NOT

- Use `class=` not `className`
- Use `for=` not `htmlFor`
- Use camelCase events: `onClick`, `onMouseEnter`, `onLoad` (not `onclick`, `onmouseenter`)
- Use `srcSet` not `srcset`, `fetchPriority` not `fetchpriority`
- Reactive text: `{() => count()}`
- Conditional: `{() => show() ? <A /> : null}`
- Lists: `{() => items().map(item => <Item />)}`
- Events: `onClick={() => ...}` (standard DOM events)
- Events: `onClick={() => ...}`
- JSX import source is `@pyreon/core` (auto-configured, no manual import needed)

## File-Based Routing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default function Dashboard() {
<button
type="button"
class="btn btn-secondary"
onclick={() => {
onClick={() => {
localStorage.removeItem('zero-demo-auth')
window.location.href = '/about'
}}
Expand Down
6 changes: 3 additions & 3 deletions packages/create-zero/templates/default/src/routes/counter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ export default function Counter() {
<button
type="button"
class="btn btn-secondary"
onclick={() => count.update((n) => n - 1)}
onClick={() => count.update((n) => n - 1)}
>
-
</button>
<button
type="button"
class="btn btn-primary"
onclick={() => count.set(0)}
onClick={() => count.set(0)}
>
Reset
</button>
<button
type="button"
class="btn btn-secondary"
onclick={() => count.update((n) => n + 1)}
onClick={() => count.update((n) => n + 1)}
>
+
</button>
Expand Down
34 changes: 17 additions & 17 deletions packages/meta/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@pyreon/charts": "^0.9.0",
"@pyreon/code": "^0.9.0",
"@pyreon/feature": "^0.9.0",
"@pyreon/flow": "^0.9.0",
"@pyreon/form": "^0.9.0",
"@pyreon/hotkeys": "^0.9.0",
"@pyreon/i18n": "^0.9.0",
"@pyreon/machine": "^0.9.0",
"@pyreon/permissions": "^0.9.0",
"@pyreon/query": "^0.9.0",
"@pyreon/state-tree": "^0.9.0",
"@pyreon/storage": "^0.9.0",
"@pyreon/store": "^0.9.0",
"@pyreon/table": "^0.9.0",
"@pyreon/validation": "^0.9.0",
"@pyreon/virtual": "^0.9.0",
"@pyreon/charts": "^0.10.0",
"@pyreon/code": "^0.10.0",
"@pyreon/feature": "^0.10.0",
"@pyreon/flow": "^0.10.0",
"@pyreon/form": "^0.10.0",
"@pyreon/hotkeys": "^0.10.0",
"@pyreon/i18n": "^0.10.0",
"@pyreon/machine": "^0.10.0",
"@pyreon/permissions": "^0.10.0",
"@pyreon/query": "^0.10.0",
"@pyreon/state-tree": "^0.10.0",
"@pyreon/storage": "^0.10.0",
"@pyreon/store": "^0.10.0",
"@pyreon/table": "^0.10.0",
"@pyreon/validation": "^0.10.0",
"@pyreon/virtual": "^0.10.0",
"@pyreon/attrs": "^0.2.0",
"@pyreon/coolgrid": "^0.2.0",
"@pyreon/elements": "^0.2.0",
Expand All @@ -62,6 +62,6 @@
"@pyreon/unistyle": "^0.2.0"
},
"peerDependencies": {
"@pyreon/reactivity": "^0.7.5"
"@pyreon/reactivity": "^0.7.11"
}
}
16 changes: 8 additions & 8 deletions packages/zero/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,17 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@pyreon/core": "^0.7.5",
"@pyreon/head": "^0.7.5",
"@pyreon/core": "^0.7.11",
"@pyreon/head": "^0.7.11",
"@pyreon/meta": "workspace:^",
"@pyreon/router": "^0.7.5",
"@pyreon/runtime-dom": "^0.7.5",
"@pyreon/runtime-server": "^0.7.5",
"@pyreon/server": "^0.7.5",
"@pyreon/vite-plugin": "^0.7.5",
"@pyreon/router": "^0.7.11",
"@pyreon/runtime-dom": "^0.7.11",
"@pyreon/runtime-server": "^0.7.11",
"@pyreon/server": "^0.7.11",
"@pyreon/vite-plugin": "^0.7.11",
"vite": "^8.0.0"
},
"peerDependencies": {
"@pyreon/reactivity": "^0.7.5"
"@pyreon/reactivity": "^0.7.11"
}
}
10 changes: 5 additions & 5 deletions packages/zero/src/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export interface ImageProps {
formats?: FormatSource[]
/** Loading strategy. "lazy" uses IntersectionObserver, "eager" loads immediately. Default: "lazy" */
loading?: 'lazy' | 'eager'
/** Mark as priority (LCP image). Disables lazy loading, adds fetchpriority="high". */
/** Mark as priority (LCP image). Disables lazy loading, adds fetchPriority="high". */
priority?: boolean
/** Low-quality placeholder image URL or base64 data URI for blur-up effect. */
placeholder?: string
Expand Down Expand Up @@ -102,7 +102,7 @@ export function Image(props: ImageProps): VNodeChild {
const imgEl = (
<img
src={() => (inView() ? props.src : '')}
srcset={() =>
srcSet={
!hasFormats && inView() && resolvedSrcset ? resolvedSrcset : ''
}
sizes={resolvedSrcset ? sizes : undefined}
Expand All @@ -111,8 +111,8 @@ export function Image(props: ImageProps): VNodeChild {
height={props.height}
loading={isEager ? 'eager' : 'lazy'}
decoding={props.decoding ?? 'async'}
fetchpriority={props.priority ? 'high' : undefined}
onload={() => loaded.set(true)}
fetchPriority={props.priority ? 'high' : undefined}
onLoad={() => loaded.set(true)}
style={() =>
[
'display: block',
Expand Down Expand Up @@ -154,7 +154,7 @@ export function Image(props: ImageProps): VNodeChild {
{props.formats?.map((fmt) => (
<source
type={fmt.type}
srcset={() => (inView() ? fmt.srcset : undefined)}
srcSet={inView() ? fmt.srcset ?? "" : ""}
sizes={sizes}
/>
))}
Expand Down
16 changes: 8 additions & 8 deletions packages/zero/src/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function doPrefetch(href: string) {
* function MyLink(props: LinkProps) {
* const link = useLink(props)
* return (
* <button ref={link.ref} class={link.classes()} onclick={link.handleClick}>
* <button ref={link.ref} class={link.classes()} onClick={link.handleClick}>
* {props.children}
* </button>
* )
Expand Down Expand Up @@ -191,8 +191,8 @@ export function useLink(props: LinkProps): UseLinkReturn {
* <button
* ref={props.ref}
* class={props.class}
* onclick={props.onClick}
* onmouseenter={props.onMouseEnter}
* onClick={props.onClick}
* onMouseEnter={props.onMouseEnter}
* >
* {props.children}
* </button>
Expand All @@ -203,8 +203,8 @@ export function useLink(props: LinkProps): UseLinkReturn {
* <div
* ref={props.ref}
* class={`card ${props.isActive() ? "card--active" : ""}`}
* onclick={props.onClick}
* onmouseenter={props.onMouseEnter}
* onClick={props.onClick}
* onMouseEnter={props.onMouseEnter}
* >
* {props.children}
* </div>
Expand Down Expand Up @@ -256,9 +256,9 @@ export const Link = createLink((props: LinkRenderProps) => (
{...(props.rel ? { rel: props.rel } : {})}
{...(props['aria-label'] ? { 'aria-label': props['aria-label'] } : {})}
{...(props.isExactActive() ? { 'aria-current': 'page' as const } : {})}
onclick={props.onClick}
onmouseenter={props.onMouseEnter}
ontouchstart={props.onTouchStart}
onClick={props.onClick}
onMouseEnter={props.onMouseEnter}
onTouchStart={props.onTouchStart}
>
{props.children}
</a>
Expand Down
2 changes: 1 addition & 1 deletion packages/zero/src/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export function ThemeToggle(props: { class?: string; style?: string }): VNodeChi
<button
class={props.class}
style={props.style}
onclick={toggleTheme}
onClick={toggleTheme}
aria-label="Toggle theme"
title="Toggle theme"
type="button"
Expand Down
Loading