aeon-ui-engine 1.4.0 → 1.8.0
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 +139 -0
- package/CONSUMER.md +67 -27
- package/INTEGRATION.md +1 -1
- package/README.md +17 -8
- package/package.json +5 -2
- package/packages/cli/dist/bin.js +29 -3
- package/packages/cli/dist/{chunk-5L47SLNV.js → chunk-JMNRJCWF.js} +63 -9
- package/packages/cli/dist/index.d.ts +15 -1
- package/packages/cli/dist/index.js +3 -1
- package/packages/cli/node_modules/.bin/vitest +2 -2
- package/packages/cli/src/bin.ts +30 -2
- package/packages/cli/src/index.ts +1 -0
- package/packages/cli/src/init.ts +10 -4
- package/packages/cli/src/link.ts +61 -0
- package/packages/core/node_modules/.bin/vitest +2 -2
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/panda/styled-system/styles.css +0 -4
- package/packages/primitives/dist/{chunk-PB3LFHXU.js → chunk-VUPWYBGU.js} +14 -0
- package/packages/primitives/dist/index.js +1 -1
- package/packages/primitives/dist/machines/range-slider.d.ts +3 -3
- package/packages/primitives/dist/machines/slider.d.ts +22 -0
- package/packages/primitives/dist/machines/slider.js +1 -1
- package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/primitives/src/machines/slider.ts +17 -0
- package/packages/react/dist/index.d.ts +44 -5
- package/packages/react/dist/index.js +173 -48
- package/packages/react/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/react/src/dialog/dialog.test.tsx +27 -0
- package/packages/react/src/dialog/index.tsx +11 -3
- package/packages/react/src/floating/FloatingPositioner.tsx +19 -1
- package/packages/react/src/hooks/use-anchor-position.ts +88 -17
- package/packages/react/src/menu/index.tsx +45 -6
- package/packages/react/src/popover/index.tsx +31 -4
- package/packages/react/src/slider/index.tsx +66 -19
- package/packages/react/src/tooltip/index.tsx +7 -1
- package/packages/schemas/dist/index.js +3 -1
- package/packages/schemas/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/schemas/prompts/cursorrules.md +3 -1
- package/packages/schemas/registry/machines/slider.json +18 -1
- package/packages/schemas/src/prompts.ts +3 -1
- package/packages/tree/README.md +29 -0
- package/packages/tree/dist/index.d.ts +97 -0
- package/packages/tree/dist/index.js +107 -0
- package/packages/tree/node_modules/.bin/esbuild +21 -0
- package/packages/tree/node_modules/.bin/jiti +21 -0
- package/packages/tree/node_modules/.bin/tsc +21 -0
- package/packages/tree/node_modules/.bin/tsserver +21 -0
- package/packages/tree/node_modules/.bin/tsup +21 -0
- package/packages/tree/node_modules/.bin/tsup-node +21 -0
- package/packages/tree/node_modules/.bin/tsx +21 -0
- package/packages/tree/node_modules/.bin/vite +21 -0
- package/packages/tree/node_modules/.bin/vitest +21 -0
- package/packages/tree/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/tree/package.json +42 -0
- package/packages/tree/src/exclusive-action.test.ts +54 -0
- package/packages/tree/src/exclusive-action.ts +104 -0
- package/packages/tree/src/index.ts +7 -0
- package/packages/tree/src/interpret.tsx +45 -0
- package/packages/tree/src/totality.ts +20 -0
- package/packages/tree/src/widget.ts +31 -0
- package/packages/tree/tsconfig.json +8 -0
- package/packages/tree/vitest.config.ts +8 -0
- package/scripts/link-scoped-packages.mjs +206 -0
- package/scripts/vite-aliases.mjs +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,143 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.0] - 2026-09-27
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`Popover.Positioner` / `FloatingPositioner` `anchorRef` + `matchAnchorWidth`.** Position a surface against the region it belongs to instead of the small trigger pinned to its edge, so a wide panel lands where the eye already is rather than being clamped back from the viewport edge.
|
|
8
|
+
- **Optional philosophy note:** [docs/ANALOGY.md](./docs/ANALOGY.md) — Aeon as metaphor for formless truth and sensory projection (not product doctrine). Linked from [PHILOSOPHY.md](./PHILOSOPHY.md) and the docs index.
|
|
9
|
+
- `@aeon-ui/tree` — widget trees. A widget is immutable data describing one face
|
|
10
|
+
of a chart, interpreted into DOM with `data-aeon-scope|part|state`. Flutter's
|
|
11
|
+
Widget and Element layers only: no RenderObject (layout stays CSS), no
|
|
12
|
+
`StatefulWidget` (the chart is the only state).
|
|
13
|
+
- `exclusiveActionWidget` — the shared face for "confirm, then await" regions
|
|
14
|
+
(`idle → confirming → busy → idle | failure`): pending label, disabled set,
|
|
15
|
+
failure copy and confirm slot are functions of the snapshot.
|
|
16
|
+
- `uncoveredStates(states, project)` — totality as a test: every state the chart
|
|
17
|
+
names must appear on the tree projected for it.
|
|
18
|
+
- `interpret(tree, hosts)` — element layer; hosts slot existing compounds
|
|
19
|
+
(`Prompt`, fields) into names the tree declares.
|
|
20
|
+
- Vite aliases, optimizeDeps exclude and tsconfig paths include `@aeon-ui/tree`.
|
|
21
|
+
|
|
22
|
+
## [1.7.7] - 2026-08-18
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Three more primitives in the live section, chosen for chart complexity.** `Slider` is hierarchical — the snapshot reports `interaction.dragging`, so the chart lights the region *and* the leaf inside it while you drag, and an arrow key shows `SET_VALUE` writing context without leaving the state. `FileUpload` runs a real drag-and-drop lifecycle (`idle` / `dragging` / `rejected`), driveable by dragging a file or by sending the same events from buttons. `Toast` is the one chart that moves without you: `visible` carries a delayed `TIMEOUT` that retires it on the machine's own clock.
|
|
27
|
+
- **`useSliderContext`** exported from `@aeon-ui/react`, so a slider's live machine state (including the nested `interaction` value) is readable from inside `Slider.Root` — matching `useAsyncContext` / `useFieldContext` / `useStickyBarContext`.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **The live chart never highlighted a component's *initial* state.** A late SVG swap replaced the diagram after the highlight was painted, so the first snapshot silently went dark until you interacted. The explorer now repaints when the rendered chart changes.
|
|
32
|
+
- **`valid` also lit up `invalid`.** Node matching compared id substrings, so any state whose name contained another's was highlighted too. Matching is now segment-aware, and a region's `[*]` marker no longer inherits its parent's highlight.
|
|
33
|
+
- **Nested snapshot values are highlighted properly.** A dotted path such as `interaction.dragging` now lights every node on the path, since the ancestors are genuinely active.
|
|
34
|
+
- **Live charts are readable.** The explorer box was short enough that parallel and nested diagrams auto-fit to ~30%; it now has room, and the slider's nested region lays out left-to-right.
|
|
35
|
+
|
|
36
|
+
## [1.7.6] - 2026-08-18
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **Hero video: resolved an apparent contradiction in the narration.** "Nothing else exists" (about the async machine) could read as conflicting with the later child-machine states (broadcasting, seen, mined). The closed-world line is now scoped — "that's this machine's entire world" — and the hierarchy scene opens with the bridge: "Need more states? Charts nest." Transcript re-aligned (61s).
|
|
41
|
+
|
|
42
|
+
## [1.7.5] - 2026-08-18
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- **Hero video narration re-recorded for clarity.** "Statechart" is now fed to TTS as "state chart" so it isn't mispronounced (the on-screen subtitle keeps the correct spelling — `speak` overrides audio only, the same mechanism the closing URL already used). The parallel-regions explanation is rebuilt around three plain questions — "Has it been edited? Does it pass? Is it sending?" — and each chart lane now prints its question next to the region name, so the words and the diagram agree. Also clearer: "no in-between states" replaces "no half states", "your CSS targets that attribute" replaces "your styles key off it", and the child machine's middle state is spoken as "seen on the network" rather than a bare "seen". Transcript re-aligned (59s).
|
|
47
|
+
|
|
48
|
+
## [1.7.4] - 2026-08-18
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **Hero video intro now shows the pain, and the ending is de-branded.** The opening scene names the actual symptoms of boolean soup — a mystery spinner with no context, two buttons wired to the same job (`Retry` / `Reload`), and "state is a mess" — instead of an abstract truth count. The narration no longer says the word "dirty" (the state node still shows it, since that's the real machine state). The hierarchy scene presents the nested send flow as "a real example / wallet · send" without naming the product. Transcript re-aligned (57s).
|
|
53
|
+
|
|
54
|
+
## [1.7.3] - 2026-08-18
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- **Hero video: plainer intro, glossed jargon, and a real hierarchical chart from a shipping product.** The intro now shows three plain `loading` / `empty` / `error` toggles with what each means in English, instead of prop-name jargon. The parallel-regions scene explains `dirty` outright ("dirty just means the user typed") and prints a plain-English gloss under the composite value. The machine catalog scene is replaced with the send flow from HandCash Desktop: the `sendPayment` chart (`editing → confirming → handoff`) with the `txLifecycle` child machine (`broadcasting → seenInMempool → mined`) nested inside `handoff` — the wallet surface and the breadcrumb (`handoff › broadcasting`) stay in lockstep with the chart. Also fixed a renderer bug where PIL ignored text alpha, so every text fade-in had been popping at full opacity (visible as floating state labels before their nodes appeared). Transcript re-aligned (55s).
|
|
59
|
+
|
|
60
|
+
## [1.7.2] - 2026-08-18
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- **New hero video, built from scratch to teach statecharts — not one animated state.** Seven scenes: three booleans producing a screen with a spinner and an error at once; the async machine with every state named and every edge labelled with its event; an event with no matching edge blocked at the door; the field machine's three parallel regions all true at once beside the surface that projects them; `state → data-aeon-state → pixels`; and four components each running their own machine on their own clock. Real system typography (SF / SF Mono), a poster frame from the chart scene, faststart streaming, and re-aligned transcript cues (52s).
|
|
65
|
+
|
|
66
|
+
## [1.7.1] - 2026-08-18
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- **Hero video now shows the actual thesis.** Previously the statechart node swept on its own float while the phone face animated separately, so the chart and the screen never agreed. The centrepiece is now one coupled demo: the component face and the highlighted chart node are the same state, driven by a single step timeline, with the causing event (`FETCH`, `RESOLVE`, `REJECT`, `REFRESH`) labelled on the transition edge — the same idea as the live section. The closing card points at "See it live" instead of the removed builder; transcript cues re-aligned.
|
|
71
|
+
|
|
72
|
+
## [1.7.0] - 2026-08-18
|
|
73
|
+
|
|
74
|
+
### Added
|
|
75
|
+
|
|
76
|
+
- **Live section: real components beside the chart that tracks them.** Async, Button, Field, and Dialog run their shipped machines; the Mermaid chart highlights the state the component is actually in and names the event that caused the move. Field reports all three regions at once, because a field has no single state.
|
|
77
|
+
- Machine-accurate diagrams for `buttonLifecycleMachine`, `dialogMachine`, and `fieldMachine`; the async chart now shows its `REFRESH` and re-fetch edges. `aeonDiagrams.test.ts` fails if a chart misses a machine state or invents one.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- **A controlled `Dialog`, `Popover`, or `Menu` could never be opened by its own trigger.** `onOpenChange` reported the resolved prop, so an owner holding `open` never heard the machine's intent — the trigger, escape key, and outside click were all dead. Each root now reports the machine's own transition (and no longer fires on mount).
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
- **The generative app builder is gone** — sandbox, chart→schema compiler, live composer, model client, cost meter, and the `/api/aeon-generate` and `/api/aeon-scrape` endpoints, plus the OpenRouter proxy plugin and its env keys (~6,000 lines). Landing nav, hero, and header CTAs point at the live section.
|
|
86
|
+
- The static "Determinism" diagram section, now that the live charts replace it. `expandActiveStates` lost its builder-specific token aliases.
|
|
87
|
+
|
|
88
|
+
## [1.6.1] - 2026-08-18
|
|
89
|
+
|
|
90
|
+
### Changed
|
|
91
|
+
|
|
92
|
+
- **Builder previews read like designs, not state dumps.** The first screen now leads with the site's own hero headline and description (scraped, never invented); other screens are titled by their state once. Actions promote one primary button and group the rest instead of stacking equal buttons. The app bar no longer repeats the state label the dock already shows.
|
|
93
|
+
- **Device selector is back** — phone / tablet / desktop toggle above the preview, with the desktop frame showing the scraped host in its address bar.
|
|
94
|
+
|
|
95
|
+
## [1.6.0] - 2026-08-18
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- **Redesign any site from its URL** — paste a domain into the builder and `/api/aeon-scrape` reads the page for its name, description, nav, actions, logo, and `theme-color`. The brand becomes chrome (logo in the app bar, accent palette scoped to the preview) and the page content becomes the prompt. Private and non-HTTP hosts are refused.
|
|
100
|
+
- `builder/projectFaces.ts` — generic chart projection: states become screens, transitions become actions, `collect` demos add a field, `async` demos add an async region.
|
|
101
|
+
- Demo tests now run in CI (`pnpm test`), covering projection, scraping, palette derivation, and a server render of the builder output.
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- **App builder rebuilt around one input.** Prompt or URL, Build, preview. The starter chips, engine bar, cost meter, inspector tabs, device picker, and build loader are gone.
|
|
106
|
+
- **The model returns a chart and nothing else; the UI is projected from it.** Previously ~1,900 lines of prompt keyword matching decided that "match" meant a dating app, "faq" meant an accordion, and "pong" meant paddles, then filled screens with seeded catalogs, listings, and test stimuli. All of it is deleted, along with the preset app schemas it produced.
|
|
107
|
+
- Empty nav tabs are dropped instead of being filled with placeholder screens, and the offline fallback chart is deliberately shapeless rather than a product guess.
|
|
108
|
+
|
|
109
|
+
## [1.5.2] - 2026-08-18
|
|
110
|
+
|
|
111
|
+
### Changed
|
|
112
|
+
|
|
113
|
+
- **Landing page trimmed to essentials** — removed the pillars grid, the numbered setup box, and the full rule-file dump; the Cursor section is now one command plus a copy button. Hero shows a single install line, the why section keeps only the same-prompt contrast, specs show one chart, and the FAQ is four questions.
|
|
114
|
+
|
|
115
|
+
## [1.5.1] - 2026-08-18
|
|
116
|
+
|
|
117
|
+
### Added
|
|
118
|
+
|
|
119
|
+
- **Scoped package linking (Next.js works without aliases)** — `postinstall` and `npx aeon-ui link` symlink `node_modules/@aeon-ui/*` → `aeon-ui-engine/packages/*`. Next.js consumers now need only `transpilePackages` plus `"use client"`; the Vite plugin is optional (optimizeDeps convenience).
|
|
120
|
+
- **`aeon-ui link` CLI command** — `--cwd`, `--force`, `--quiet`; also runs at the end of `npx aeon-ui init`. Exported as `aeon-ui-engine/link`.
|
|
121
|
+
|
|
122
|
+
### Changed
|
|
123
|
+
|
|
124
|
+
- CONSUMER.md, README, INTEGRATION, VITE_CONSUMER, MIGRATION_FROM_ARK, PUBLISHING: install once, link automatically, Vite plugin optional; `file:` link workaround for Next.js removed.
|
|
125
|
+
- Landing FAQ and Cursor rules snippet state that Aeon is React-first with Next.js supported, and that Vue / Solid / Svelte are thin adapters rather than the main catalog.
|
|
126
|
+
|
|
127
|
+
## [1.4.1] - 2026-08-17
|
|
128
|
+
|
|
129
|
+
### Fixed
|
|
130
|
+
|
|
131
|
+
- **Floating surfaces are collision aware** — `Menu` / `Popover` / `Tooltip` / `Select` positioners now accept `bottom-end` / `top-end` / `*-center` placements, flip when the preferred side has no room, and clamp inside the viewport. Right-aligned triggers (avatar menus in a sticky header) no longer render offscreen.
|
|
132
|
+
- **Positioner stacking is configurable** — `gutter` and `zIndex` props on `Menu.Positioner`, `Popover.Positioner`, `Tooltip.Positioner` replace the hardcoded 4px gap and `z-index: 50`, so menus can sit above app chrome.
|
|
133
|
+
- **Menu keyboard behavior** — `Menu.Content` takes focus while open, restores focus to the trigger on dismiss, and closes on Escape from anywhere on the page (previously only when focus was already inside the surface).
|
|
134
|
+
- **Controlled `Slider` reports interaction** — pointer and keyboard input now call `onValueChange` even when `value` is set, so a controlled thumb (audio seek bar) follows its prop instead of Aeon's internal value. `onValueChange` no longer fires on mount or echoes the controlled prop.
|
|
135
|
+
- **`sliderMachine` bounds follow the host** — new `SET_BOUNDS` / `SET_DISABLED` events, sent by `Slider.Root` on prop change, so a range that grows later (track duration arriving) stops clamping to the initial `max`.
|
|
136
|
+
|
|
137
|
+
### Added
|
|
138
|
+
|
|
139
|
+
- Positioners publish `data-side`, `data-align`, `--aeon-available-height`, and `--aeon-anchor-width` for recipes that cap their own scroll area.
|
|
140
|
+
|
|
3
141
|
## [1.4.0] - 2026-08-17
|
|
4
142
|
|
|
5
143
|
### Added
|
|
@@ -13,6 +151,7 @@
|
|
|
13
151
|
### Changed
|
|
14
152
|
|
|
15
153
|
- COMPONENTS / MACHINES / PRIMITIVE_COVERAGE / API_PATTERNS updated for 1.4 primitives.
|
|
154
|
+
- **aeon-ui.com** hero, FAQ, Cursor docs, CONSUMER, and README now lead with `npx aeon-ui migrate` for existing apps.
|
|
16
155
|
|
|
17
156
|
## [1.3.6] - 2026-07-31
|
|
18
157
|
|
package/CONSUMER.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Using `aeon-ui-engine` from npm
|
|
2
2
|
|
|
3
|
-
One package.
|
|
3
|
+
One package. Install once. `@aeon-ui/*` resolves automatically.
|
|
4
|
+
|
|
5
|
+
Aeon is **React-first** (Next.js included). Vue / Solid / Svelte adapters are thin — not the main product.
|
|
6
|
+
|
|
7
|
+
## 0. Existing app? Migrate first
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx aeon-ui migrate
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Scans for known local workarounds (custom dropzones, range sliders, toast bridges, hand-rolled link buttons) and writes `AEON_MIGRATION_CHECKLIST.md`. Use `--check` to print findings only. New projects can skip straight to install + `npx aeon-ui init`.
|
|
4
14
|
|
|
5
15
|
## 1. Install
|
|
6
16
|
|
|
@@ -8,51 +18,81 @@ One package. One plugin. Done.
|
|
|
8
18
|
npm install aeon-ui-engine react react-dom xstate @xstate/react
|
|
9
19
|
```
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
**Postinstall** runs `scripts/link-scoped-packages.mjs`, which symlinks:
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
// vite.config.ts
|
|
15
|
-
import react from '@vitejs/plugin-react'
|
|
16
|
-
import { defineConfig } from 'vite'
|
|
17
|
-
import { aeonUiVitePlugin } from 'aeon-ui-engine/vite'
|
|
23
|
+
`node_modules/@aeon-ui/*` → `node_modules/aeon-ui-engine/packages/*`
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
Re-run manually anytime:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx aeon-ui link
|
|
29
|
+
# or
|
|
30
|
+
node node_modules/aeon-ui-engine/scripts/link-scoped-packages.mjs
|
|
22
31
|
```
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
No bundler aliases are required for `@aeon-ui/ui` / `@aeon-ui/react` imports.
|
|
34
|
+
|
|
35
|
+
## 2. Import CSS (one line)
|
|
25
36
|
|
|
26
37
|
```tsx
|
|
27
|
-
//
|
|
38
|
+
// app/layout.tsx (Next.js) or main.tsx (Vite)
|
|
28
39
|
import 'aeon-ui-engine/aeon.css'
|
|
29
40
|
```
|
|
30
41
|
|
|
31
|
-
##
|
|
42
|
+
## 3. Use components
|
|
32
43
|
|
|
33
44
|
```tsx
|
|
34
45
|
import { Button, Dialog, Menu, Toast } from '@aeon-ui/ui'
|
|
35
46
|
```
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Next.js
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// next.config.mjs
|
|
54
|
+
export default {
|
|
55
|
+
transpilePackages: [
|
|
56
|
+
'@aeon-ui/ui',
|
|
57
|
+
'@aeon-ui/react',
|
|
58
|
+
'@aeon-ui/core',
|
|
59
|
+
'@aeon-ui/primitives',
|
|
60
|
+
'@aeon-ui/panda',
|
|
61
|
+
],
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Mark interactive surfaces as Client Components:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
'use client'
|
|
69
|
+
import { Button } from '@aeon-ui/ui'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
No `resolve.alias` / webpack alias block. If Turbopack mis-resolves after install, run `npx aeon-ui link` and prefer `next dev --webpack` while evaluating.
|
|
38
73
|
|
|
39
74
|
---
|
|
40
75
|
|
|
41
|
-
##
|
|
76
|
+
## Vite (optional plugin)
|
|
42
77
|
|
|
43
|
-
|
|
78
|
+
Scoped imports already work via the link step. The Vite plugin is optional — it still helps with `optimizeDeps` and monorepo `packagesRoot`:
|
|
44
79
|
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
```ts
|
|
81
|
+
// vite.config.ts
|
|
82
|
+
import react from '@vitejs/plugin-react'
|
|
83
|
+
import { defineConfig } from 'vite'
|
|
84
|
+
import { aeonUiVitePlugin } from 'aeon-ui-engine/vite'
|
|
85
|
+
|
|
86
|
+
export default defineConfig({
|
|
87
|
+
plugins: [react(), aeonUiVitePlugin()],
|
|
88
|
+
})
|
|
53
89
|
```
|
|
54
90
|
|
|
55
|
-
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Optional: TypeScript
|
|
94
|
+
|
|
95
|
+
Linked packages usually typecheck via each package’s `types` field. If needed:
|
|
56
96
|
|
|
57
97
|
```json
|
|
58
98
|
{
|
|
@@ -117,7 +157,7 @@ Style with any CSS system using `data-aeon-scope`, `data-aeon-part`, `data-aeon-
|
|
|
117
157
|
|
|
118
158
|
## Optional: Local monorepo
|
|
119
159
|
|
|
120
|
-
Point the plugin at a local checkout:
|
|
160
|
+
Point the Vite plugin at a local checkout (or set `AEON_UI_ROOT` before `aeon-ui link`):
|
|
121
161
|
|
|
122
162
|
```ts
|
|
123
163
|
aeonUiVitePlugin({ packagesRoot: '/path/to/aeon-ui/packages' })
|
|
@@ -125,4 +165,4 @@ aeonUiVitePlugin({ packagesRoot: '/path/to/aeon-ui/packages' })
|
|
|
125
165
|
|
|
126
166
|
## Reference consumer
|
|
127
167
|
|
|
128
|
-
[Casino-games](https://github.com/GenericCPU/Casino-games) uses
|
|
168
|
+
[Casino-games](https://github.com/GenericCPU/Casino-games) uses the engine install pattern. Next.js consumers: install + link + `transpilePackages` (see above).
|
package/INTEGRATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Agents:** [AGENTS.md](./AGENTS.md) · [docs/API_PATTERNS.md](./docs/API_PATTERNS.md)
|
|
4
4
|
|
|
5
|
-
**npm consumers:** start with **[CONSUMER.md](./CONSUMER.md)** — install `aeon-ui-engine
|
|
5
|
+
**npm consumers:** start with **[CONSUMER.md](./CONSUMER.md)** — install `aeon-ui-engine` (postinstall links `@aeon-ui/*`), peer deps, then import. Vite plugin is optional; Next.js needs `transpilePackages` only.
|
|
6
6
|
|
|
7
7
|
Aeon UI is **three layers**. You can use one or all.
|
|
8
8
|
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Aeon UI models interactive behavior as executable [statecharts](https://www.thes
|
|
|
16
16
|
| `@aeon-ui/primitives` | XState machines (toggle, dialog, tabs, accordion, async, button lifecycle, field) |
|
|
17
17
|
| `@aeon-ui/react` | React headless bindings |
|
|
18
18
|
| `@aeon-ui/schemas` | JSON Schema catalog + agent system prompts |
|
|
19
|
-
| `@aeon-ui/cli` | `npx aeon-ui init` — Cursor rules,
|
|
19
|
+
| `@aeon-ui/cli` | `npx aeon-ui init` · `link` · `migrate` — Cursor rules, scoped package link, migration checklist |
|
|
20
20
|
| `@aeon-ui/panda` | Design tokens, `defineSlotRecipe` styles, generated `styled-system` |
|
|
21
21
|
| `@aeon-ui/ui` | Styled components (`aeonButton`, `aeonAccordion`, …) |
|
|
22
22
|
| `@aeon-ui/vue` | Vue 3 headless adapter (v0.1: Switch + `useAeonMachine`) |
|
|
@@ -33,13 +33,27 @@ Teach an AI agent first (optional but recommended):
|
|
|
33
33
|
npx aeon-ui init
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Migrating an existing app? Scan for known workarounds and write a checklist:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx aeon-ui migrate
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The monorepo is published on npm as **`aeon-ui-engine`** (bundles all `@aeon-ui/*` workspace packages). Postinstall links `node_modules/@aeon-ui/*` so **Next.js and Vite** resolve imports without aliases:
|
|
37
43
|
|
|
38
44
|
```bash
|
|
39
45
|
npm install aeon-ui-engine react react-dom xstate @xstate/react
|
|
46
|
+
# re-link if needed: npx aeon-ui link
|
|
40
47
|
```
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
```tsx
|
|
50
|
+
// app/layout.tsx or main.tsx
|
|
51
|
+
import 'aeon-ui-engine/aeon.css'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Next.js** — add `transpilePackages` for `@aeon-ui/ui`, `@aeon-ui/react`, `@aeon-ui/core`, `@aeon-ui/primitives`, `@aeon-ui/panda`, and use `"use client"` for interactive components.
|
|
55
|
+
|
|
56
|
+
**Vite (optional)** — `aeonUiVitePlugin()` still helps with optimizeDeps; linking alone is enough for `@aeon-ui/*` resolution:
|
|
43
57
|
|
|
44
58
|
```ts
|
|
45
59
|
// vite.config.ts
|
|
@@ -49,11 +63,6 @@ export default defineConfig({
|
|
|
49
63
|
})
|
|
50
64
|
```
|
|
51
65
|
|
|
52
|
-
```tsx
|
|
53
|
-
// main.tsx
|
|
54
|
-
import 'aeon-ui-engine/aeon.css'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
66
|
Full setup guide: **[CONSUMER.md](./CONSUMER.md)**.
|
|
58
67
|
|
|
59
68
|
Open [https://github.com/GenericCPU/aeon-ui](https://github.com/GenericCPU/aeon-ui) for the repo. The marketing demo lives at [https://aeon-ui.com](https://aeon-ui.com) — set `VITE_SITE_ORIGIN` to that origin in Vercel so Open Graph previews resolve the social image in `apps/demo/public/` correctly.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aeon-ui-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
"./vite": "./scripts/vite-aliases.mjs",
|
|
11
|
+
"./link": "./scripts/link-scoped-packages.mjs",
|
|
11
12
|
"./aeon.css": "./packages/panda/aeon.css",
|
|
12
13
|
"./tsconfig.base.json": "./tsconfig.base.json",
|
|
13
14
|
"./CONSUMER.md": "./CONSUMER.md",
|
|
@@ -25,13 +26,15 @@
|
|
|
25
26
|
"CHANGELOG.md"
|
|
26
27
|
],
|
|
27
28
|
"scripts": {
|
|
29
|
+
"postinstall": "node ./scripts/link-scoped-packages.mjs",
|
|
30
|
+
"link:scoped": "node ./scripts/link-scoped-packages.mjs",
|
|
28
31
|
"build": "pnpm --filter @aeon-ui/panda run codegen && pnpm -r run build",
|
|
29
32
|
"build:headless": "pnpm --filter @aeon-ui/core --filter @aeon-ui/primitives --filter @aeon-ui/react run build",
|
|
30
33
|
"codegen": "pnpm --filter @aeon-ui/panda codegen",
|
|
31
34
|
"dev": "pnpm --filter @aeon-ui/demo dev",
|
|
32
35
|
"examples": "pnpm --filter @aeon-ui/examples dev",
|
|
33
36
|
"typecheck": "pnpm -r run typecheck",
|
|
34
|
-
"test": "pnpm run test:headless",
|
|
37
|
+
"test": "pnpm run test:headless && pnpm --filter @aeon-ui/demo run test",
|
|
35
38
|
"test:headless": "pnpm run build:headless && pnpm --filter @aeon-ui/core --filter @aeon-ui/primitives --filter @aeon-ui/react run test",
|
|
36
39
|
"changeset": "changeset",
|
|
37
40
|
"version-packages": "changeset version",
|
package/packages/cli/dist/bin.js
CHANGED
|
@@ -1,37 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
initAeon,
|
|
4
|
+
linkAeon,
|
|
4
5
|
migrateAeon
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JMNRJCWF.js";
|
|
6
7
|
|
|
7
8
|
// src/bin.ts
|
|
8
9
|
var args = process.argv.slice(2);
|
|
9
10
|
var cmd = args[0] ?? "help";
|
|
10
11
|
var force = args.includes("--force") || args.includes("-f");
|
|
11
12
|
var checkOnly = args.includes("--check");
|
|
13
|
+
var quiet = args.includes("--quiet") || args.includes("-q");
|
|
14
|
+
function argValue(flag) {
|
|
15
|
+
const i = args.indexOf(flag);
|
|
16
|
+
if (i >= 0 && args[i + 1] && !args[i + 1].startsWith("-")) return args[i + 1];
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
var cwdArg = argValue("--cwd");
|
|
12
20
|
function help() {
|
|
13
21
|
console.log(`aeon-ui \u2014 AI-optimized CLI for Aeon UI
|
|
14
22
|
|
|
15
23
|
Usage:
|
|
16
24
|
npx aeon-ui init [--force]
|
|
25
|
+
npx aeon-ui link [--quiet] [--force] [--cwd <dir>]
|
|
17
26
|
npx aeon-ui migrate [--check]
|
|
18
27
|
|
|
19
28
|
Commands:
|
|
20
29
|
init Inject Cursor rules, JSON schemas, system prompt, and a starter component
|
|
30
|
+
link Symlink node_modules/@aeon-ui/* \u2192 aeon-ui-engine/packages/* (also runs on postinstall)
|
|
21
31
|
migrate Scan for known workarounds and write AEON_MIGRATION_CHECKLIST.md
|
|
22
32
|
help Show this message
|
|
23
33
|
|
|
24
34
|
Options:
|
|
25
|
-
--force, -f Overwrite existing generated files (init)
|
|
35
|
+
--force, -f Overwrite existing generated files (init); replace existing @aeon-ui links (link)
|
|
26
36
|
--check Report findings only; do not write checklist (migrate)
|
|
37
|
+
--quiet, -q Suppress link output (link)
|
|
38
|
+
--cwd <dir> Project root for link (defaults to process.cwd())
|
|
27
39
|
`);
|
|
28
40
|
}
|
|
29
41
|
if (cmd === "init") {
|
|
30
|
-
const result = initAeon({ force });
|
|
42
|
+
const result = initAeon({ force, cwd: cwdArg });
|
|
31
43
|
console.log(`Aeon UI init \u2192 ${result.cwd}`);
|
|
32
44
|
for (const line of result.written) console.log(` ${line}`);
|
|
45
|
+
try {
|
|
46
|
+
linkAeon({ cwd: result.cwd, quiet: true });
|
|
47
|
+
console.log(" link @aeon-ui/* (scoped packages)");
|
|
48
|
+
} catch {
|
|
49
|
+
console.log(" link skipped (install aeon-ui-engine first, then: npx aeon-ui link)");
|
|
50
|
+
}
|
|
33
51
|
console.log("\nNext: npm install aeon-ui-engine react react-dom xstate @xstate/react");
|
|
34
52
|
console.log("Docs: AEON_AI.md \xB7 paste aeon.cursorrules.md into your agent system prompt");
|
|
53
|
+
} else if (cmd === "link") {
|
|
54
|
+
try {
|
|
55
|
+
const result = linkAeon({ quiet, force, cwd: cwdArg });
|
|
56
|
+
if (quiet) console.log(`Aeon UI link \u2192 ${result.cwd}`);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(err instanceof Error ? err.message : err);
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
}
|
|
35
61
|
} else if (cmd === "migrate") {
|
|
36
62
|
const result = migrateAeon({ write: !checkOnly });
|
|
37
63
|
console.log(`Aeon UI migrate \u2192 ${result.cwd}`);
|
|
@@ -85,10 +85,16 @@ Generated by \`npx aeon-ui init\`.
|
|
|
85
85
|
## Next steps
|
|
86
86
|
|
|
87
87
|
1. Install: \`npm install aeon-ui-engine react react-dom xstate @xstate/react\`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
- Postinstall links \`@aeon-ui/*\` into \`node_modules\` (re-run with \`npx aeon-ui link\` if needed).
|
|
89
|
+
2. CSS: \`import 'aeon-ui-engine/aeon.css'\` (e.g. root layout).
|
|
90
|
+
3. **Next.js:** add \`transpilePackages\` for \`@aeon-ui/ui\`, \`@aeon-ui/react\`, \`@aeon-ui/core\`, \`@aeon-ui/primitives\`, \`@aeon-ui/panda\`. Use \`"use client"\` for interactive components. No webpack aliases required.
|
|
91
|
+
4. **Vite (optional):** \`aeonUiVitePlugin()\` from \`aeon-ui-engine/vite\` still helps with optimizeDeps; scoped imports resolve via the link step alone.
|
|
92
|
+
5. Paste \`aeon.cursorrules.md\` into Cursor rules / system prompt (already mirrored to \`.cursor/rules/aeon-ui.mdc\`)
|
|
93
|
+
6. Constrain generation with JSON under \`aeon.schemas/\`
|
|
94
|
+
|
|
95
|
+
## Frameworks
|
|
96
|
+
|
|
97
|
+
Aeon is **React-first** (full catalog + styled layer). Next.js is supported. Vue / Solid / Svelte adapters exist but are thin \u2014 not the main product.
|
|
92
98
|
|
|
93
99
|
## Principle
|
|
94
100
|
|
|
@@ -98,9 +104,56 @@ Generated by \`npx aeon-ui init\`.
|
|
|
98
104
|
return { cwd, written };
|
|
99
105
|
}
|
|
100
106
|
|
|
107
|
+
// src/link.ts
|
|
108
|
+
import { spawnSync } from "child_process";
|
|
109
|
+
import { createRequire } from "module";
|
|
110
|
+
import { existsSync as existsSync2 } from "fs";
|
|
111
|
+
import { dirname, join as join2 } from "path";
|
|
112
|
+
import { fileURLToPath } from "url";
|
|
113
|
+
function resolveLinkScript() {
|
|
114
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
115
|
+
const fromMonorepo = join2(here, "../../../scripts/link-scoped-packages.mjs");
|
|
116
|
+
if (existsSync2(fromMonorepo)) return fromMonorepo;
|
|
117
|
+
try {
|
|
118
|
+
const require2 = createRequire(import.meta.url);
|
|
119
|
+
const engineRoot = dirname(require2.resolve("aeon-ui-engine/package.json"));
|
|
120
|
+
return join2(engineRoot, "scripts/link-scoped-packages.mjs");
|
|
121
|
+
} catch {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"Could not find scripts/link-scoped-packages.mjs (aeon-ui-engine not installed?)"
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function linkAeon(options = {}) {
|
|
128
|
+
const script = resolveLinkScript();
|
|
129
|
+
const args = [script];
|
|
130
|
+
if (options.cwd) {
|
|
131
|
+
args.push("--cwd", options.cwd);
|
|
132
|
+
}
|
|
133
|
+
if (options.quiet) {
|
|
134
|
+
args.push("--quiet");
|
|
135
|
+
}
|
|
136
|
+
if (options.force) {
|
|
137
|
+
args.push("--force");
|
|
138
|
+
}
|
|
139
|
+
const result = spawnSync(process.execPath, args, {
|
|
140
|
+
stdio: options.quiet ? "pipe" : "inherit",
|
|
141
|
+
env: process.env,
|
|
142
|
+
cwd: options.cwd ?? process.cwd()
|
|
143
|
+
});
|
|
144
|
+
if (result.status !== 0 && result.status !== null) {
|
|
145
|
+
const err = result.stderr?.toString() || `link exited with code ${result.status}`;
|
|
146
|
+
throw new Error(err);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
cwd: options.cwd ?? process.cwd(),
|
|
150
|
+
status: result.status ?? 0
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
101
154
|
// src/migrate.ts
|
|
102
|
-
import { existsSync as
|
|
103
|
-
import { join as
|
|
155
|
+
import { existsSync as existsSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
156
|
+
import { join as join3 } from "path";
|
|
104
157
|
var FINDINGS = [
|
|
105
158
|
{
|
|
106
159
|
id: "preview-window-machine",
|
|
@@ -156,8 +209,8 @@ function walkHints(cwd) {
|
|
|
156
209
|
const hits = [];
|
|
157
210
|
let corpus = "";
|
|
158
211
|
for (const rel of CANDIDATES) {
|
|
159
|
-
const abs =
|
|
160
|
-
if (!
|
|
212
|
+
const abs = join3(cwd, rel);
|
|
213
|
+
if (!existsSync3(abs)) continue;
|
|
161
214
|
try {
|
|
162
215
|
corpus += `
|
|
163
216
|
${rel}
|
|
@@ -228,7 +281,7 @@ function migrateAeon(options = {}) {
|
|
|
228
281
|
const findings = walkHints(cwd);
|
|
229
282
|
const written = [];
|
|
230
283
|
if (write) {
|
|
231
|
-
const path =
|
|
284
|
+
const path = join3(cwd, "AEON_MIGRATION_CHECKLIST.md");
|
|
232
285
|
const findingsBlock = findings.length === 0 ? "\n## Scan results\n\nNo known local workarounds detected in the quick scan.\n" : `
|
|
233
286
|
## Scan results
|
|
234
287
|
|
|
@@ -243,5 +296,6 @@ ${findingsBlock}`);
|
|
|
243
296
|
|
|
244
297
|
export {
|
|
245
298
|
initAeon,
|
|
299
|
+
linkAeon,
|
|
246
300
|
migrateAeon
|
|
247
301
|
};
|
|
@@ -7,6 +7,20 @@ declare function initAeon(options?: InitOptions): {
|
|
|
7
7
|
written: string[];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
type LinkOptions = {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
quiet?: boolean;
|
|
13
|
+
force?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Symlink `node_modules/@aeon-ui/*` → `aeon-ui-engine/packages/*`.
|
|
17
|
+
* Prefer the postinstall hook; this command re-runs linking manually.
|
|
18
|
+
*/
|
|
19
|
+
declare function linkAeon(options?: LinkOptions): {
|
|
20
|
+
cwd: string;
|
|
21
|
+
status: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
10
24
|
type MigrateOptions = {
|
|
11
25
|
cwd?: string;
|
|
12
26
|
write?: boolean;
|
|
@@ -23,4 +37,4 @@ declare function migrateAeon(options?: MigrateOptions): {
|
|
|
23
37
|
findings: Finding[];
|
|
24
38
|
};
|
|
25
39
|
|
|
26
|
-
export { type InitOptions, type MigrateOptions, initAeon, migrateAeon };
|
|
40
|
+
export { type InitOptions, type LinkOptions, type MigrateOptions, initAeon, linkAeon, migrateAeon };
|
|
@@ -10,9 +10,9 @@ case `uname` in
|
|
|
10
10
|
esac
|
|
11
11
|
|
|
12
12
|
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.
|
|
13
|
+
export NODE_PATH="/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.27.7_jiti@2.7.0_tsx@4.22.3_/node_modules/vitest/node_modules:/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.27.7_jiti@2.7.0_tsx@4.22.3_/node_modules:/Users/brandoncryderman/AeonUI/node_modules/.pnpm/node_modules"
|
|
14
14
|
else
|
|
15
|
-
export NODE_PATH="/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.
|
|
15
|
+
export NODE_PATH="/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.27.7_jiti@2.7.0_tsx@4.22.3_/node_modules/vitest/node_modules:/Users/brandoncryderman/AeonUI/node_modules/.pnpm/vitest@4.1.8_@types+node@22.19.19_jsdom@29.1.1_vite@8.0.16_@types+node@22.19.19_esbuild@0.27.7_jiti@2.7.0_tsx@4.22.3_/node_modules:/Users/brandoncryderman/AeonUI/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
16
|
fi
|
|
17
17
|
if [ -x "$basedir/node" ]; then
|
|
18
18
|
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|