@adukiorg/anza 0.2.0 → 0.2.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/CHANGELOG.md +81 -4
- package/README.md +97 -133
- package/bin/anza/anza +0 -0
- package/bin/anza/anza.exe +0 -0
- package/bin/anza/find.js +35 -0
- package/bin/anza/index.js +34 -0
- package/bin/anza/launch.js +19 -0
- package/bin/common/index.js +7 -0
- package/bin/common/logs.js +62 -0
- package/bin/create/copy.js +18 -0
- package/bin/create/index.js +45 -0
- package/bin/create/run.js +210 -0
- package/bin/create/write.js +19 -0
- package/importmap.json +4 -0
- package/package.json +16 -10
- package/src/core/offline/{usage.md → notes/usage.md} +11 -1
- package/src/core/router/boot.js +82 -0
- package/src/core/router/cascade.js +76 -0
- package/src/core/router/container.js +63 -72
- package/src/core/router/graph.js +144 -0
- package/src/core/router/index.js +12 -2
- package/src/core/router/intercept.js +26 -7
- package/src/core/router/lca.js +58 -0
- package/src/core/router/match.js +49 -36
- package/src/core/router/notes/audit-old.md +887 -0
- package/src/core/router/notes/audti.md +773 -0
- package/src/core/router/notes/tasks.md +473 -0
- package/src/core/router/{usage.md → notes/usage.md} +57 -35
- package/src/core/router/sync/tab.js +6 -4
- package/src/core/router/transitions.js +35 -8
- package/src/core/router/trie.js +130 -0
- package/src/core/security/{usage.md → notes/usage.md} +1 -2
- package/src/core/storage/{usage.md → notes/usage.md} +6 -6
- package/src/core/theme/index.js +78 -0
- package/src/core/ui/define/index.js +2 -1
- package/src/core/ui/define/orchestrator.js +10 -4
- package/src/core/ui/defs/dock.js +134 -0
- package/src/core/ui/defs/index.js +20 -0
- package/src/core/ui/defs/page.js +89 -0
- package/src/core/ui/defs/part.js +28 -0
- package/src/core/ui/defs/spec.js +96 -0
- package/src/core/ui/defs/view.js +23 -0
- package/src/core/ui/index.js +16 -3
- package/src/core/ui/notes/definations.md +979 -0
- package/src/tokens/index.css +1 -0
- package/src/tokens/semantic/contrast.css +18 -0
- package/src/tokens/semantic/transitions.css +32 -0
- package/types/core/platform/index.d.ts +39 -10
- package/types/core/router/index.d.ts +9 -0
- package/types/core/theme/index.d.ts +18 -0
- package/types/core/ui/index.d.ts +11 -0
- package/types/index.d.ts +1 -0
- package/bin/anza.js +0 -63
- package/bin/create.js +0 -150
- package/src/core/api/plan.md +0 -209
- package/src/core/events/missing.md +0 -103
- package/src/core/events/plan.md +0 -177
- package/src/core/offline/missing.md +0 -89
- package/src/core/offline/plan.md +0 -143
- package/src/core/platform/missing.md +0 -119
- package/src/core/platform/platform.d.ts +0 -88
- package/src/core/router/missing.md +0 -716
- package/src/core/router/outlet.js +0 -139
- package/src/core/router/plan.md +0 -370
- package/src/core/security/missing.md +0 -97
- package/src/core/state/missing.md +0 -165
- package/src/core/storage/missing.md +0 -165
- package/src/core/storage/plan.md +0 -69
- package/src/core/ui/implementation.md +0 -170
- package/src/core/ui/plan.md +0 -510
- package/src/core/ui/ui.types.md +0 -890
- /package/src/core/animations/{usage.md → notes/usage.md} +0 -0
- /package/src/core/api/{usage.md → notes/usage.md} +0 -0
- /package/src/core/events/{usage.md → notes/usage.md} +0 -0
- /package/src/core/platform/{usage.md → notes/usage.md} +0 -0
- /package/src/core/state/{usage.md → notes/usage.md} +0 -0
- /package/src/core/ui/{usage.md → notes/usage.md} +0 -0
- /package/src/core/ui/{watch.md → notes/watch.md} +0 -0
- /package/src/core/workers/{plan.md → notes/plan.md} +0 -0
- /package/src/core/workers/{usage.md → notes/usage.md} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@adukiorg/anza` will be documented here.
|
|
4
4
|
|
|
5
|
-
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
Versioning follows [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -16,11 +16,85 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
+
## [0.2.2] — 2026-06-09
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- CI/CD workflows for GitHub Actions (build, typecheck, verify scaffolding, cross-platform release)
|
|
24
|
+
- Comprehensive documentation for all modules (animations, api, events, platform, router, security, state, storage, sw, ui, workers)
|
|
25
|
+
- `library/bin/` CLI wrappers for Node.js distribution
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## [0.2.1] — 2026-06-09
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
#### Service Worker Toolkit — `@adukiorg/anza/sw`
|
|
34
|
+
|
|
35
|
+
- **New subpath export** `@adukiorg/anza/sw` — caching strategies, route interception, background sync, and push notifications
|
|
36
|
+
- **Seven caching strategies**: CacheFirst, NetworkFirst, StaleRevalidate, CacheThenNetwork, NetworkOnly, CacheOnly, OfflineFallback
|
|
37
|
+
- **URLPattern routing** inside the Service Worker via `router()` and `Router`
|
|
38
|
+
- **Install/activate helpers**: `precache()`, `pruneStale()`, `claim()`, `enableNavPreload()`
|
|
39
|
+
- **TTL expiry**: `pruneExpired()`, `setupAutoPrune()` with `x-expires-at` headers
|
|
40
|
+
- **Background sync**: `replayQueue()`, `requeueFailed()` with dead-letter queue
|
|
41
|
+
- **Request serialization**: `serializeRequest()`, `deserializeRequest()` for IndexedDB storage
|
|
42
|
+
- **Push notifications**: `subscribe()`, `notify()` with VAPID support
|
|
43
|
+
- **Scaffolded `src/sw.js`** generated by both `anza create` and `anza-create`
|
|
44
|
+
|
|
45
|
+
#### Theme Switching — `@adukiorg/anza/theme`
|
|
46
|
+
|
|
47
|
+
- **New subpath export** `@adukiorg/anza/theme`
|
|
48
|
+
- **Auto-init on import** — reads saved preference from `localStorage` or respects `prefers-color-scheme`
|
|
49
|
+
- **Attaches to `window.theme`** via `Object.defineProperty` (non-enumerable, non-configurable)
|
|
50
|
+
- **API**: `theme.get()`, `theme.set()`, `theme.toggle()` — all update the same global instance
|
|
51
|
+
- **No manual init required** — importing `@adukiorg/anza/ui` triggers it automatically
|
|
52
|
+
|
|
53
|
+
#### View Transition Tokens — `tokens/semantic/transitions.css`
|
|
54
|
+
|
|
55
|
+
- **New semantic token layer** connecting the CSS View Transitions API to the design token system
|
|
56
|
+
- **Tokens**: `--transition-bg`, `--transition-duration`, `--transition-easing`, `--transition-push`, `--transition-pop`, `--transition-replace`
|
|
57
|
+
- **Router `transitions.run()`** injects a token-aware stylesheet on first use
|
|
58
|
+
- **Dock `swap()`** reads directional easing from tokens (`--transition-push` vs `--transition-pop`) for physically different forward/back feel
|
|
59
|
+
- **High-contrast theme morphing** — `contrast.css` now declares `transition:` for smooth token interpolation
|
|
60
|
+
|
|
61
|
+
#### Documentation
|
|
62
|
+
|
|
63
|
+
- **Comprehensive `docs/index.md`** — master docs entry with all modules listed by usefulness
|
|
64
|
+
- **`docs/sw/`** — complete SW documentation: `index.md`, `start.md`, `strategies.md`, `routes.md`, `sync.md`, `api.md`
|
|
65
|
+
- **Updated `docs/intro/`** — SW toolkit in feature list, build output includes `dist/sw.js`
|
|
66
|
+
- **View Transition token docs** added to `docs/ui/transitions.md`, `docs/router/transitions.md`, `docs/animations/tokens.md`
|
|
67
|
+
|
|
68
|
+
#### Tooling
|
|
69
|
+
|
|
70
|
+
- **`tools/src/build/graph.rs` split** into focused modules:
|
|
71
|
+
- `cache.rs` — incremental build cache (`.anzacache.json`)
|
|
72
|
+
- `parse.rs` — ESM AST parsing with swc
|
|
73
|
+
- `entries.rs` — entry point discovery from HTML and `src/sw.js`
|
|
74
|
+
- `resolve.rs` — import map and filesystem resolution
|
|
75
|
+
- `html.rs` — HTML injection (importmap link, HMR script)
|
|
76
|
+
- `sw.rs` — Service Worker bare-specifier rewriting
|
|
77
|
+
- **Auto-discovery of `src/sw.js`** as a build entry point
|
|
78
|
+
- **Bare specifier rewriting in `dist/sw.js`** — `@adukiorg/anza/sw` → `./sw/index.js` (SW does not support import maps)
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
|
|
82
|
+
- **Cache file renamed** from `.anza-build-cache.json` to `.anzacache.json`
|
|
83
|
+
- **Scaffolded `src/app.js`** now imports and auto-registers the Service Worker
|
|
84
|
+
- **Scaffolded `src/sw.js`** included in both Node.js and Rust `create` commands
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- High-contrast theme (`contrast.css`) now animates token changes instead of snapping instantly
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
19
92
|
## [0.2.0] — 2026-06-07
|
|
20
93
|
|
|
21
94
|
### Added
|
|
22
95
|
|
|
23
96
|
#### Compiler — `anza`
|
|
97
|
+
|
|
24
98
|
- **Dependency Graph Walking**: Automated dependency resolution of ESM imports/exports.
|
|
25
99
|
- **Tree-Shaking**: Outputs only referenced files to `dist/`, excluding unused code.
|
|
26
100
|
- **Automatic Inline Importmaps**: Optimal `<script type="importmap">` generated and injected inline into HTML entry points.
|
|
@@ -30,9 +104,11 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
30
104
|
- **Nested /dist Routing**: Added router nested service mapping in Axum dev server for development path parity.
|
|
31
105
|
|
|
32
106
|
#### Structure
|
|
107
|
+
|
|
33
108
|
- **Monorepo Split**: Reorganized files into `/library` (NPM package), `/sample` (demo application), and `/tools` (Rust compiler).
|
|
34
109
|
|
|
35
110
|
#### Sample
|
|
111
|
+
|
|
36
112
|
- **Cyberpunk Blog SPA**: Features reactive store, category filters, instant search, likes count persistence, details page with lightweight custom markdown renderer, post publishing, and post deletion.
|
|
37
113
|
|
|
38
114
|
---
|
|
@@ -132,6 +208,7 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
132
208
|
- `blog/` — sample SPA demonstrating state, storage, offline queue, and animations
|
|
133
209
|
- Import map mirrors the published `@adukiorg/anza/*` subpath exports exactly
|
|
134
210
|
|
|
135
|
-
[Unreleased]: https://github.com/aduki-org/
|
|
136
|
-
[0.2.
|
|
137
|
-
[0.
|
|
211
|
+
[Unreleased]: https://github.com/aduki-org/anza/compare/v0.2.1...HEAD
|
|
212
|
+
[0.2.1]: https://github.com/aduki-org/anza/compare/v0.2.0...v0.2.1
|
|
213
|
+
[0.2.0]: https://github.com/aduki-org/anza/compare/v0.1.0...v0.2.0
|
|
214
|
+
[0.1.0]: https://github.com/aduki-org/anza/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @adukiorg/anza
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> The browser already knows how to render, route, cache, and animate. We just stopped getting in its way.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@adukiorg/anza)
|
|
6
6
|
[](./LICENSE)
|
|
@@ -8,206 +8,170 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## What
|
|
11
|
+
## What This Is (and What It Is Not)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
**This is** a web platform library that treats the browser as the runtime. It gives you reactive state, client-side routing, custom elements, offline sync, and animations — all as plain ES modules the browser resolves directly. No bundler. No virtual DOM. No framework lock-in.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
| --- | --- |
|
|
17
|
-
| `/api` | `fetch`, Streams API, `scheduler.postTask` |
|
|
18
|
-
| `/state` | ES Proxy, `queueMicrotask`, `BroadcastChannel` |
|
|
19
|
-
| `/events` | Custom pub/sub with AbortSignal cleanup |
|
|
20
|
-
| `/router` | Navigation API, History API |
|
|
21
|
-
| `/storage` | IndexedDB, Cache API, OPFS, LRU memory |
|
|
22
|
-
| `/offline` | IDB-backed operation queue, `navigator.onLine` |
|
|
23
|
-
| `/animations` | WAAPI (`element.animate`), stagger groups |
|
|
24
|
-
| `/workers` | Web Locks API, Web Workers pool |
|
|
25
|
-
| `/security` | Web Crypto API, `DOMParser` XSS sanitizer |
|
|
26
|
-
| `/platform` | Feature detection for 30+ browser APIs |
|
|
27
|
-
| `/ui` | Shadow DOM base element, design token cascade |
|
|
28
|
-
| `/elements` | Custom element library |
|
|
15
|
+
**This is NOT** another React competitor. If you love JSX, useEffect cleanup races, and wondering why your bundle is 400KB, Anza is not for you. We are not trying to replace React. React is fine. React is great. React is for people who enjoy debugging `useMemo` dependency arrays at 2am. We are for people who want to write `.js` files and let the browser do what it was built to do.
|
|
29
16
|
|
|
30
|
-
|
|
17
|
+
**This is NOT** Angular. We do not have a CLI that generates fourteen files to render a button. We have `element('my-button', { template: '<button>Click me</button>' })`. That is the whole API.
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## Installation
|
|
35
|
-
|
|
36
|
-
To install `@adukiorg/anza` in your project:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm install @adukiorg/anza
|
|
40
|
-
```
|
|
19
|
+
**This is NOT** Vue. We do not have a template compiler. We do not have a virtual DOM diffing algorithm that runs in JavaScript to figure out what the browser should have already figured out. We write HTML. The browser parses HTML. It has been doing this since 1993. It is pretty good at it.
|
|
41
20
|
|
|
42
21
|
---
|
|
43
22
|
|
|
44
|
-
##
|
|
23
|
+
## The Pitch
|
|
45
24
|
|
|
46
|
-
|
|
25
|
+
Anza is built on browser-native APIs. Every module wraps something the browser already ships:
|
|
47
26
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
27
|
+
| Module | What it wraps | What we did to it |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `/api` | `fetch`, Streams API, `scheduler.postTask` | Added retries, caching, and a pipeline. The browser did the hard part. |
|
|
30
|
+
| `/state` | ES Proxy, `queueMicrotask`, `BroadcastChannel` | Reactive stores with batched updates. No getters/setters boilerplate. |
|
|
31
|
+
| `/events` | `CustomEvent`, `AbortSignal` | Pub/sub with cleanup that actually works. |
|
|
32
|
+
| `/router` | Navigation API, History API, `URLPattern` | Routes that match URLs and render views. Shocking, we know. |
|
|
33
|
+
| `/storage` | IndexedDB, Cache API, OPFS | Tiered persistence: memory → IDB → disk. You pick the tier. |
|
|
34
|
+
| `/offline` | `navigator.onLine`, IndexedDB | Queue failed requests, replay them later. Like a polite retry system. |
|
|
35
|
+
| `/animations` | WAAPI (`element.animate`) | Stagger groups and scroll-driven animations. The GPU does the work. |
|
|
36
|
+
| `/workers` | Web Locks API, Web Workers | A worker pool with concurrency limits. Because tabs deserve boundaries. |
|
|
37
|
+
| `/security` | Web Crypto API, `DOMParser` | Encrypt, hash, sanitize. The browser has a crypto lab. We use it. |
|
|
38
|
+
| `/platform` | 30+ browser APIs | Feature detection so you know what you are working with. |
|
|
39
|
+
| `/ui` | Custom Elements, Shadow DOM, CSS Layers | Declarative components with reactive props and lifecycle hooks. No classes. |
|
|
40
|
+
| `/sw` | Service Worker, Cache API, Background Sync | Caching strategies, route interception, and push notifications. |
|
|
41
|
+
| `/theme` | `data-theme`, `localStorage`, `matchMedia` | Auto theme switching with persistence. Light, dark, or high-contrast. |
|
|
52
42
|
|
|
53
|
-
|
|
43
|
+
The Rust CLI (`anza`) resolves your ESM import graph and copies only the modules you actually use into `dist/`. It generates type declarations, serves with HMR, and gets out of your way.
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
---
|
|
56
46
|
|
|
57
|
-
|
|
47
|
+
## Quick Start
|
|
58
48
|
|
|
59
|
-
### 1. Build the compiler
|
|
60
|
-
From the workspace root directory:
|
|
61
49
|
```bash
|
|
62
|
-
|
|
50
|
+
npx anza-create myapp
|
|
51
|
+
cd myapp
|
|
52
|
+
npm install
|
|
53
|
+
npm run dev
|
|
63
54
|
```
|
|
64
|
-
This builds the release binary into `tools/target/release/anza`.
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
Navigate into the sample project:
|
|
68
|
-
```bash
|
|
69
|
-
cd sample
|
|
70
|
-
npm install # Links to the local library package
|
|
71
|
-
npm run build # Performs graph resolution and emits output to dist/
|
|
72
|
-
npm run dev # Starts dev server on port 8080 with HMR and routing fallbacks
|
|
73
|
-
```
|
|
56
|
+
That is it. Your browser loads `dist/app.js` natively. No webpack. No vite. No `npm run build` that takes forty seconds.
|
|
74
57
|
|
|
75
58
|
---
|
|
76
59
|
|
|
77
|
-
## What
|
|
60
|
+
## What You Actually Write
|
|
78
61
|
|
|
79
|
-
|
|
80
|
-
- **Tree-Shaking**: Copies only the reached modules into `dist/`. Unreferenced files and assets are completely excluded.
|
|
81
|
-
- **Automatic Inline Importmap**: Analyzes import references and automatically generates/injects an optimal `<script type="importmap">` tag inline in your HTML files.
|
|
82
|
-
- **Static Asset Copying**: Automatically copies templates (`.html`) and stylesheets (`.css`) referenced by your components.
|
|
83
|
-
- **Strict Validation**: Fails the build on unresolved imports, syntax errors, or invalid component prop declarations.
|
|
84
|
-
- **HMR Dev Server**: Serves your files with a SSE live-reload listener. Modifying a CSS file hot-swaps it in place; HTML/JS modifications trigger a fast page reload.
|
|
62
|
+
### A Component
|
|
85
63
|
|
|
86
|
-
|
|
64
|
+
```javascript
|
|
65
|
+
import { view } from '@adukiorg/anza/defs';
|
|
87
66
|
|
|
88
|
-
|
|
67
|
+
view('user-card', {
|
|
68
|
+
props: {
|
|
69
|
+
name: { type: String, default: 'Guest' },
|
|
70
|
+
active: { type: Boolean }
|
|
71
|
+
},
|
|
72
|
+
template: `
|
|
73
|
+
<div class="card">
|
|
74
|
+
<h2 ref="title">{{ name }}</h2>
|
|
75
|
+
<span class="badge" hidden="">{{ active }}</span>
|
|
76
|
+
</div>
|
|
77
|
+
`,
|
|
78
|
+
on: {
|
|
79
|
+
connect({ refs }) {
|
|
80
|
+
refs.title.textContent = this.name;
|
|
81
|
+
},
|
|
82
|
+
change({ name, val, refs }) {
|
|
83
|
+
if (name === 'name') refs.title.textContent = val;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
```
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
Use it:
|
|
91
90
|
|
|
92
|
-
### `ui-button/template.html`
|
|
93
91
|
```html
|
|
94
|
-
<
|
|
95
|
-
<slot></slot>
|
|
96
|
-
</button>
|
|
92
|
+
<user-card name="Alice" active></user-card>
|
|
97
93
|
```
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
```css
|
|
101
|
-
:host { display: inline-block; }
|
|
102
|
-
.btn { background: var(--color-primary); color: white; border: none; }
|
|
103
|
-
```
|
|
95
|
+
No build step. No JSX transform. No virtual DOM reconciliation. The browser parses the template, creates the DOM, and updates it when props change. Because that is literally what browsers are for.
|
|
104
96
|
|
|
105
|
-
###
|
|
106
|
-
```js
|
|
107
|
-
import { ui } from '@adukiorg/anza/ui';
|
|
97
|
+
### A Route
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
}
|
|
99
|
+
```javascript
|
|
100
|
+
import { page, dock } from '@adukiorg/anza/defs';
|
|
101
|
+
|
|
102
|
+
dock('main', { parent: 'body' });
|
|
103
|
+
|
|
104
|
+
page('/', {
|
|
105
|
+
tag: 'page-home',
|
|
106
|
+
via: ['main'],
|
|
107
|
+
template: { html: './home.html', css: './home.css' }
|
|
120
108
|
}, import.meta.url);
|
|
121
109
|
```
|
|
122
110
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
## Quick Examples
|
|
111
|
+
Click `<a href="/about">`. The router intercepts it. The view transitions. No full page reload. The Navigation API has been in Chrome since 2022. We use it.
|
|
126
112
|
|
|
127
113
|
### Reactive State
|
|
128
114
|
|
|
129
|
-
```
|
|
115
|
+
```javascript
|
|
130
116
|
import { state } from '@adukiorg/anza/state';
|
|
131
117
|
|
|
132
|
-
const store = state.create({ count: 0
|
|
118
|
+
const store = state.create({ count: 0 });
|
|
133
119
|
|
|
134
120
|
store.subscribe('count', () => {
|
|
135
121
|
console.log('count changed to', store.get('count'));
|
|
136
122
|
});
|
|
137
123
|
|
|
138
|
-
store.set('count', 1);
|
|
139
|
-
store.set('count', 2); // batched — only one notification fires
|
|
124
|
+
store.set('count', 1);
|
|
140
125
|
```
|
|
141
126
|
|
|
142
|
-
|
|
127
|
+
Proxy-based reactivity. Batched updates. Cross-tab sync via `BroadcastChannel`. No reducers. No actions. No sagas. Just a store that notifies subscribers when data changes. Revolutionary, we know.
|
|
143
128
|
|
|
144
|
-
|
|
145
|
-
import { api, PlatformError } from '@adukiorg/anza/api';
|
|
129
|
+
### Theme Switching (Automatic)
|
|
146
130
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
console.log(data);
|
|
150
|
-
} catch (err) {
|
|
151
|
-
if (err instanceof PlatformError) {
|
|
152
|
-
console.error(err.code, err.message); // 'NETWORK_TIMEOUT', 'HTTP_ERROR', etc.
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
131
|
+
```javascript
|
|
132
|
+
import { theme } from '@adukiorg/anza/theme';
|
|
156
133
|
|
|
157
|
-
|
|
134
|
+
theme.toggle(); // light ↔ dark
|
|
135
|
+
theme.set('contrast'); // high-contrast mode
|
|
136
|
+
```
|
|
158
137
|
|
|
159
|
-
|
|
160
|
-
import { Database } from '@adukiorg/anza/storage';
|
|
138
|
+
No init call needed. It auto-restores from `localStorage` on import. Respects `prefers-color-scheme` if no saved preference exists. Attaches to `window.theme` for devtools access. Because theme toggles are not rocket science.
|
|
161
139
|
|
|
162
|
-
|
|
163
|
-
(db) => db.createObjectStore('posts')
|
|
164
|
-
]);
|
|
140
|
+
---
|
|
165
141
|
|
|
166
|
-
|
|
167
|
-
await db.set('posts', 'post-1', { title: 'Hello', content: '...' });
|
|
168
|
-
const post = await db.get('posts', 'post-1');
|
|
169
|
-
```
|
|
142
|
+
## The Token System
|
|
170
143
|
|
|
171
|
-
|
|
144
|
+
Anza ships with a complete design token layer:
|
|
172
145
|
|
|
173
|
-
|
|
174
|
-
|
|
146
|
+
- **Primitives** — OKLCH color scales, spacing, motion, radius, shadow, z-index
|
|
147
|
+
- **Semantic** — light, dark, high-contrast themes with GPU-accelerated token morphing
|
|
148
|
+
- **Components** — form controls, feedback, overlays, layout tokens
|
|
149
|
+
- **Transitions** — View Transition timing and backdrop tokens
|
|
175
150
|
|
|
176
|
-
|
|
177
|
-
animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 300 });
|
|
151
|
+
You own `src/tokens/` after scaffolding. Change a primitive, every component updates. Change a semantic mapping, the whole theme shifts. Override anything in `@layer overrides`. The cascade handles the rest.
|
|
178
152
|
|
|
179
|
-
|
|
180
|
-
const cards = document.querySelectorAll('.card');
|
|
181
|
-
stagger(Array.from(cards), [
|
|
182
|
-
{ transform: 'translateY(20px)', opacity: 0 },
|
|
183
|
-
{ transform: 'translateY(0)', opacity: 1 }
|
|
184
|
-
], { duration: 250, staggerDelay: 60 });
|
|
185
|
-
```
|
|
153
|
+
---
|
|
186
154
|
|
|
187
|
-
|
|
155
|
+
## Philosophy
|
|
188
156
|
|
|
189
|
-
|
|
190
|
-
import { register, navigate } from '@adukiorg/anza/router';
|
|
157
|
+
**Native first.** If the browser has an API for it, we use it. If it doesn't, we build the smallest possible wrapper. We do not reimplement the browser inside JavaScript.
|
|
191
158
|
|
|
192
|
-
|
|
193
|
-
const post = await fetchPost(params.id);
|
|
194
|
-
renderPost(post);
|
|
195
|
-
});
|
|
159
|
+
**Zero build.** The browser resolves ESM imports natively. Our Rust CLI copies the files you use into `dist/`. That is the whole build step. No bundling. No tree-shaking algorithms. The browser is single-threaded anyway.
|
|
196
160
|
|
|
197
|
-
|
|
198
|
-
```
|
|
161
|
+
**You own your code.** Scaffolding copies starter files into `src/`. The library never touches them again. No hidden configs. No magic globals. No runtime injection of framework internals.
|
|
199
162
|
|
|
200
163
|
---
|
|
201
164
|
|
|
202
165
|
## Testing
|
|
203
166
|
|
|
204
|
-
Tests run in **real Chromium** via `@web/test-runner` — no jsdom
|
|
167
|
+
Tests run in **real Chromium** via `@web/test-runner` — no jsdom, no node mocks, no pretend browser.
|
|
205
168
|
|
|
206
169
|
```bash
|
|
207
|
-
cd library
|
|
208
170
|
npm test
|
|
209
171
|
```
|
|
210
172
|
|
|
173
|
+
If it passes in Chromium, it passes in Chrome. If it passes in Chrome, it probably works everywhere else. (We said probably. Safari is Safari.)
|
|
174
|
+
|
|
211
175
|
---
|
|
212
176
|
|
|
213
177
|
## License
|
package/bin/anza/anza
ADDED
|
Binary file
|
|
Binary file
|
package/bin/anza/find.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bin/anza/find.js
|
|
3
|
+
*
|
|
4
|
+
* Resolves the anza Rust binary path for the current platform.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
|
|
10
|
+
const PLATFORMS = {
|
|
11
|
+
darwin: { x64: 'anza-macos-x64', arm64: 'anza-macos-arm64' },
|
|
12
|
+
linux: { x64: 'anza-linux-x64', arm64: 'anza-linux-arm64' },
|
|
13
|
+
win32: { x64: 'anza-windows-x64.exe', arm64: 'anza-windows-arm64.exe' },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function resolve(root, here) {
|
|
17
|
+
const dev = join(root, 'tools', 'target', 'release', 'anza');
|
|
18
|
+
if (existsSync(dev)) return dev;
|
|
19
|
+
|
|
20
|
+
const platform = process.platform;
|
|
21
|
+
const arch = process.arch;
|
|
22
|
+
const name = PLATFORMS[platform]?.[arch];
|
|
23
|
+
|
|
24
|
+
if (!name) {
|
|
25
|
+
throw new Error(`Unsupported platform: ${platform} ${arch}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const prebuilt = join(here, name);
|
|
29
|
+
if (existsSync(prebuilt)) return prebuilt;
|
|
30
|
+
|
|
31
|
+
throw new Error(
|
|
32
|
+
'anza binary not found.\n' +
|
|
33
|
+
'Run: node tasks/build.js (from the repo root)'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bin/anza/index.js
|
|
4
|
+
*
|
|
5
|
+
* Node.js wrapper for the anza Rust binary.
|
|
6
|
+
* Re-exports find and launch for programmatic use.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname, join } from 'path';
|
|
11
|
+
import { resolve } from './find.js';
|
|
12
|
+
import { start } from './launch.js';
|
|
13
|
+
|
|
14
|
+
export { resolve } from './find.js';
|
|
15
|
+
export { start } from './launch.js';
|
|
16
|
+
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = dirname(__filename);
|
|
19
|
+
|
|
20
|
+
const library = join(__dirname, '..', '..');
|
|
21
|
+
const root = join(library, '..');
|
|
22
|
+
|
|
23
|
+
// CLI entry only when executed directly
|
|
24
|
+
const isCli = process.argv[1] === __filename;
|
|
25
|
+
|
|
26
|
+
if (isCli) {
|
|
27
|
+
try {
|
|
28
|
+
const path = resolve(root, __dirname);
|
|
29
|
+
start(path, process.argv.slice(2));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error(err.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bin/anza/launch.js
|
|
3
|
+
*
|
|
4
|
+
* Spawns the anza Rust binary with forwarded args.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import * as logs from '../common/index.js';
|
|
9
|
+
|
|
10
|
+
export function start(path, args) {
|
|
11
|
+
const child = spawn(path, args, { stdio: 'inherit' });
|
|
12
|
+
|
|
13
|
+
child.on('error', (err) => {
|
|
14
|
+
logs.error(`Failed to spawn anza: ${err.message}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
19
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bin/common/logs.js
|
|
3
|
+
*
|
|
4
|
+
* Colored category logger matching the Rust logs crate.
|
|
5
|
+
* Categories: info, debug, success, error, warn, compiler, server, hmr, watcher, sync.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const RESET = '\x1b[0m';
|
|
9
|
+
const GRAY = '\x1b[90m';
|
|
10
|
+
const BLUE = '\x1b[34m';
|
|
11
|
+
const CYAN = '\x1b[36m';
|
|
12
|
+
const GREEN = '\x1b[1m\x1b[32m';
|
|
13
|
+
const RED = '\x1b[1m\x1b[31m';
|
|
14
|
+
const YELLOW = '\x1b[1m\x1b[33m';
|
|
15
|
+
const BYELLOW = '\x1b[93m';
|
|
16
|
+
const BBLUE = '\x1b[94m';
|
|
17
|
+
const BGREEN = '\x1b[92m';
|
|
18
|
+
|
|
19
|
+
function stamp() {
|
|
20
|
+
const d = new Date();
|
|
21
|
+
return `${GRAY}[${d.toISOString().slice(0, 19).replace('T', ' ')}]${RESET} `;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function info(msg) {
|
|
25
|
+
console.log(`${stamp()}${BLUE}INFO:${RESET} ${msg}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function debug(msg) {
|
|
29
|
+
console.log(`${stamp()}${GRAY}DEBUG:${RESET} ${msg}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function success(msg) {
|
|
33
|
+
console.log(`${stamp()}${GREEN}SUCCESS:${RESET} ${msg}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function error(msg) {
|
|
37
|
+
console.error(`${stamp()}${RED}ERROR:${RESET} ${msg}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function warn(msg) {
|
|
41
|
+
console.warn(`${stamp()}${YELLOW}WARN:${RESET} ${msg}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function compiler(msg) {
|
|
45
|
+
console.log(`${stamp()}${CYAN}COMPILER:${RESET} ${msg}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function server(msg) {
|
|
49
|
+
console.log(`${stamp()}${BBLUE}SERVER:${RESET} ${msg}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function hmr(msg) {
|
|
53
|
+
console.log(`${stamp()}${BGREEN}HMR:${RESET} ${msg}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function watcher(msg) {
|
|
57
|
+
console.log(`${stamp()}${BYELLOW}WATCHER:${RESET} ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function sync(msg) {
|
|
61
|
+
console.log(`${stamp()}${GRAY}SYNC:${RESET} ${msg}`);
|
|
62
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bin/create/copy.js
|
|
3
|
+
*
|
|
4
|
+
* Recursively copies a directory tree.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { cpSync } from 'fs';
|
|
8
|
+
import * as logs from '../common/index.js';
|
|
9
|
+
|
|
10
|
+
export function copy(src, dst) {
|
|
11
|
+
try {
|
|
12
|
+
cpSync(src, dst, { recursive: true });
|
|
13
|
+
return true;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
logs.warn(`Could not copy ${src} -> ${dst}: ${e.message}`);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bin/create/index.js
|
|
4
|
+
*
|
|
5
|
+
* Scaffolds a new anza app project in the given directory.
|
|
6
|
+
* Re-exports run, copy, and write for programmatic use.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { resolve, basename, dirname, join } from 'path';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import * as logs from '../common/index.js';
|
|
13
|
+
import { run } from './run.js';
|
|
14
|
+
|
|
15
|
+
export { run } from './run.js';
|
|
16
|
+
export { copy } from './copy.js';
|
|
17
|
+
export { write } from './write.js';
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = dirname(__filename);
|
|
21
|
+
|
|
22
|
+
const arg = process.argv[2];
|
|
23
|
+
|
|
24
|
+
// CLI entry only when executed directly
|
|
25
|
+
const isCli = process.argv[1] === __filename;
|
|
26
|
+
|
|
27
|
+
if (isCli) {
|
|
28
|
+
if (!arg || arg === '--help' || arg === '-h') {
|
|
29
|
+
console.log('Usage: npx anza-create <name>');
|
|
30
|
+
console.log(' npx anza-create . (scaffold in current dir)');
|
|
31
|
+
process.exit(arg ? 0 : 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const target = resolve(arg);
|
|
35
|
+
const name = arg === '.' ? basename(process.cwd()) : basename(target);
|
|
36
|
+
|
|
37
|
+
if (existsSync(target) && arg !== '.') {
|
|
38
|
+
logs.error(`'${target}' already exists.`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const library = join(__dirname, '..', '..');
|
|
43
|
+
|
|
44
|
+
run(target, name, library);
|
|
45
|
+
}
|