aeon-ui-engine 1.0.2 → 1.0.3

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.
Files changed (219) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/CONSUMER.md +86 -0
  3. package/INTEGRATION.md +2 -0
  4. package/README.md +15 -4
  5. package/package.json +17 -1
  6. package/packages/core/dist/index.d.ts +257 -0
  7. package/packages/core/dist/index.js +378 -0
  8. package/packages/core/node_modules/.bin/esbuild +21 -0
  9. package/packages/core/node_modules/.bin/jiti +21 -0
  10. package/packages/core/node_modules/.bin/tsc +21 -0
  11. package/packages/core/node_modules/.bin/tsserver +21 -0
  12. package/packages/core/node_modules/.bin/tsup +21 -0
  13. package/packages/core/node_modules/.bin/tsup-node +21 -0
  14. package/packages/core/node_modules/.bin/tsx +21 -0
  15. package/packages/core/node_modules/.bin/vite +21 -0
  16. package/packages/core/node_modules/.bin/vitest +21 -0
  17. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  18. package/packages/geometry/dist/index.d.ts +50 -0
  19. package/packages/geometry/dist/index.js +88 -0
  20. package/packages/geometry/node_modules/.bin/esbuild +21 -0
  21. package/packages/geometry/node_modules/.bin/jiti +21 -0
  22. package/packages/geometry/node_modules/.bin/tsc +21 -0
  23. package/packages/geometry/node_modules/.bin/tsserver +21 -0
  24. package/packages/geometry/node_modules/.bin/tsup +21 -0
  25. package/packages/geometry/node_modules/.bin/tsup-node +21 -0
  26. package/packages/geometry/node_modules/.bin/tsx +21 -0
  27. package/packages/primitives/dist/chunk-5S4DIRL4.js +42 -0
  28. package/packages/primitives/dist/chunk-H4KOEPYC.js +52 -0
  29. package/packages/primitives/dist/chunk-HONROWUG.js +41 -0
  30. package/packages/primitives/dist/chunk-J6JHKMVM.js +90 -0
  31. package/packages/primitives/dist/chunk-JBAG5E6W.js +46 -0
  32. package/packages/primitives/dist/chunk-LVNCD5F2.js +43 -0
  33. package/packages/primitives/dist/chunk-PB3LFHXU.js +72 -0
  34. package/packages/primitives/dist/chunk-SZV6KGXN.js +49 -0
  35. package/packages/primitives/dist/chunk-WVICCOQH.js +56 -0
  36. package/packages/primitives/dist/chunk-ZMGRX64G.js +74 -0
  37. package/packages/primitives/dist/index.d.ts +11 -0
  38. package/packages/primitives/dist/index.js +60 -0
  39. package/packages/primitives/dist/machines/accordion.d.ts +34 -0
  40. package/packages/primitives/dist/machines/accordion.js +6 -0
  41. package/packages/primitives/dist/machines/async.d.ts +111 -0
  42. package/packages/primitives/dist/machines/async.js +12 -0
  43. package/packages/primitives/dist/machines/button.d.ts +45 -0
  44. package/packages/primitives/dist/machines/button.js +8 -0
  45. package/packages/primitives/dist/machines/dialog.d.ts +57 -0
  46. package/packages/primitives/dist/machines/dialog.js +6 -0
  47. package/packages/primitives/dist/machines/field.d.ts +72 -0
  48. package/packages/primitives/dist/machines/field.js +12 -0
  49. package/packages/primitives/dist/machines/popover.d.ts +54 -0
  50. package/packages/primitives/dist/machines/popover.js +6 -0
  51. package/packages/primitives/dist/machines/slider.d.ts +71 -0
  52. package/packages/primitives/dist/machines/slider.js +10 -0
  53. package/packages/primitives/dist/machines/tabs.d.ts +39 -0
  54. package/packages/primitives/dist/machines/tabs.js +6 -0
  55. package/packages/primitives/dist/machines/toast.d.ts +31 -0
  56. package/packages/primitives/dist/machines/toast.js +6 -0
  57. package/packages/primitives/dist/machines/toggle.d.ts +54 -0
  58. package/packages/primitives/dist/machines/toggle.js +6 -0
  59. package/packages/primitives/node_modules/.bin/jiti +21 -0
  60. package/packages/primitives/node_modules/.bin/tsc +21 -0
  61. package/packages/primitives/node_modules/.bin/tsserver +21 -0
  62. package/packages/primitives/node_modules/.bin/tsup +21 -0
  63. package/packages/primitives/node_modules/.bin/tsup-node +21 -0
  64. package/packages/primitives/node_modules/.bin/tsx +21 -0
  65. package/packages/primitives/node_modules/.bin/vitest +21 -0
  66. package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  67. package/packages/react/dist/index.d.ts +564 -0
  68. package/packages/react/dist/index.js +3461 -0
  69. package/packages/react/node_modules/.bin/jiti +21 -0
  70. package/packages/react/node_modules/.bin/tsc +21 -0
  71. package/packages/react/node_modules/.bin/tsserver +21 -0
  72. package/packages/react/node_modules/.bin/tsup +21 -0
  73. package/packages/react/node_modules/.bin/tsup-node +21 -0
  74. package/packages/react/node_modules/.bin/tsx +21 -0
  75. package/packages/react/node_modules/.bin/vitest +21 -0
  76. package/packages/react/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  77. package/packages/react-scene/dist/index.d.ts +121 -0
  78. package/packages/react-scene/dist/index.js +430 -0
  79. package/packages/react-scene/node_modules/.bin/jiti +21 -0
  80. package/packages/react-scene/node_modules/.bin/tsc +21 -0
  81. package/packages/react-scene/node_modules/.bin/tsserver +21 -0
  82. package/packages/react-scene/node_modules/.bin/tsup +21 -0
  83. package/packages/react-scene/node_modules/.bin/tsup-node +21 -0
  84. package/packages/react-scene/node_modules/.bin/tsx +21 -0
  85. package/packages/scene/dist/index.d.ts +46 -0
  86. package/packages/scene/dist/index.js +54 -0
  87. package/packages/scene/node_modules/.bin/jiti +21 -0
  88. package/packages/scene/node_modules/.bin/tsc +21 -0
  89. package/packages/scene/node_modules/.bin/tsserver +21 -0
  90. package/packages/scene/node_modules/.bin/tsup +21 -0
  91. package/packages/scene/node_modules/.bin/tsup-node +21 -0
  92. package/packages/scene/node_modules/.bin/tsx +21 -0
  93. package/packages/signal/dist/index.d.ts +54 -0
  94. package/packages/signal/dist/index.js +169 -0
  95. package/packages/signal/node_modules/.bin/jiti +21 -0
  96. package/packages/signal/node_modules/.bin/tsc +21 -0
  97. package/packages/signal/node_modules/.bin/tsserver +21 -0
  98. package/packages/signal/node_modules/.bin/tsup +21 -0
  99. package/packages/signal/node_modules/.bin/tsup-node +21 -0
  100. package/packages/signal/node_modules/.bin/tsx +21 -0
  101. package/packages/site/dist/index.d.ts +31 -0
  102. package/packages/site/dist/index.js +62 -0
  103. package/packages/site/node_modules/.bin/jiti +21 -0
  104. package/packages/site/node_modules/.bin/tsc +21 -0
  105. package/packages/site/node_modules/.bin/tsserver +21 -0
  106. package/packages/site/node_modules/.bin/tsup +21 -0
  107. package/packages/site/node_modules/.bin/tsup-node +21 -0
  108. package/packages/site/node_modules/.bin/tsx +21 -0
  109. package/packages/solid/dist/index.d.ts +30 -0
  110. package/packages/solid/dist/index.js +174 -0
  111. package/packages/solid/node_modules/.bin/jiti +21 -0
  112. package/packages/solid/node_modules/.bin/tsc +21 -0
  113. package/packages/solid/node_modules/.bin/tsserver +21 -0
  114. package/packages/solid/node_modules/.bin/tsup +21 -0
  115. package/packages/solid/node_modules/.bin/tsup-node +21 -0
  116. package/packages/solid/node_modules/.bin/tsx +21 -0
  117. package/packages/surface/dist/index.d.ts +8 -0
  118. package/packages/surface/dist/index.js +14 -0
  119. package/packages/surface/node_modules/.bin/jiti +21 -0
  120. package/packages/surface/node_modules/.bin/tsc +21 -0
  121. package/packages/surface/node_modules/.bin/tsserver +21 -0
  122. package/packages/surface/node_modules/.bin/tsup +21 -0
  123. package/packages/surface/node_modules/.bin/tsup-node +21 -0
  124. package/packages/surface/node_modules/.bin/tsx +21 -0
  125. package/packages/svelte/dist/index.d.ts +12 -0
  126. package/packages/svelte/dist/index.js +15 -0
  127. package/packages/svelte/node_modules/.bin/acorn +21 -0
  128. package/packages/svelte/node_modules/.bin/jiti +21 -0
  129. package/packages/svelte/node_modules/.bin/svelte-check +21 -0
  130. package/packages/svelte/node_modules/.bin/tsc +21 -0
  131. package/packages/svelte/node_modules/.bin/tsserver +21 -0
  132. package/packages/svelte/node_modules/.bin/tsup +21 -0
  133. package/packages/svelte/node_modules/.bin/tsup-node +21 -0
  134. package/packages/svelte/node_modules/.bin/tsx +21 -0
  135. package/packages/svelte/node_modules/.bin/vite +21 -0
  136. package/packages/ui/dist/index.d.ts +200 -0
  137. package/packages/ui/dist/index.js +429 -0
  138. package/packages/ui/node_modules/.bin/jiti +21 -0
  139. package/packages/ui/node_modules/.bin/tsc +21 -0
  140. package/packages/ui/node_modules/.bin/tsserver +21 -0
  141. package/packages/ui/node_modules/.bin/tsup +21 -0
  142. package/packages/ui/node_modules/.bin/tsup-node +21 -0
  143. package/packages/ui/node_modules/.bin/tsx +21 -0
  144. package/packages/vue/dist/index.d.ts +71 -0
  145. package/packages/vue/dist/index.js +193 -0
  146. package/packages/vue/node_modules/.bin/jiti +21 -0
  147. package/packages/vue/node_modules/.bin/tsc +21 -0
  148. package/packages/vue/node_modules/.bin/tsserver +21 -0
  149. package/packages/vue/node_modules/.bin/tsup +21 -0
  150. package/packages/vue/node_modules/.bin/tsup-node +21 -0
  151. package/packages/vue/node_modules/.bin/tsx +21 -0
  152. package/scripts/vite-aliases.mjs +125 -0
  153. package/.changeset/README.md +0 -23
  154. package/.changeset/combobox-and-changesets.md +0 -9
  155. package/.changeset/config.json +0 -31
  156. package/.changeset/framework-adapters.md +0 -12
  157. package/.changeset/scene-3d.md +0 -6
  158. package/.changeset/scene-plane.md +0 -8
  159. package/.changeset/site-og.md +0 -5
  160. package/.cursor/rules/aeon-ui.mdc +0 -22
  161. package/ACCESSIBILITY.md +0 -32
  162. package/AGENTS.md +0 -226
  163. package/COMPONENTS.md +0 -41
  164. package/FRAMEWORKS.md +0 -57
  165. package/PHILOSOPHY.md +0 -71
  166. package/PUBLISHING.md +0 -105
  167. package/SCENE.md +0 -113
  168. package/STATES.md +0 -243
  169. package/apps/demo/index.html +0 -31
  170. package/apps/demo/og.config.mjs +0 -20
  171. package/apps/demo/package.json +0 -41
  172. package/apps/demo/public/favicon.svg +0 -16
  173. package/apps/demo/public/og-aeon-ui-engine.png +0 -0
  174. package/apps/demo/public/og.svg +0 -35
  175. package/apps/demo/scripts/generate-og-png.mjs +0 -62
  176. package/apps/demo/src/App.tsx +0 -31
  177. package/apps/demo/src/aeonDiagrams.ts +0 -42
  178. package/apps/demo/src/app.css +0 -16
  179. package/apps/demo/src/components/ActionCluster.tsx +0 -20
  180. package/apps/demo/src/components/AsyncMachineDemo.tsx +0 -97
  181. package/apps/demo/src/components/ButtonLifecycleDemo.tsx +0 -63
  182. package/apps/demo/src/components/CodeExample.tsx +0 -7
  183. package/apps/demo/src/components/ComboboxDemo.tsx +0 -30
  184. package/apps/demo/src/components/DiagramsSection.tsx +0 -37
  185. package/apps/demo/src/components/FieldStateDemo.tsx +0 -51
  186. package/apps/demo/src/components/GridMesh.tsx +0 -8
  187. package/apps/demo/src/components/HeroInstall.tsx +0 -13
  188. package/apps/demo/src/components/LandingFaq.tsx +0 -29
  189. package/apps/demo/src/components/LandingFooter.tsx +0 -30
  190. package/apps/demo/src/components/LandingHeader.tsx +0 -62
  191. package/apps/demo/src/components/LandingHero.tsx +0 -55
  192. package/apps/demo/src/components/LayersSection.tsx +0 -47
  193. package/apps/demo/src/components/MermaidDiagram.tsx +0 -86
  194. package/apps/demo/src/components/PhilosophySection.tsx +0 -31
  195. package/apps/demo/src/components/PlaygroundBlock.tsx +0 -18
  196. package/apps/demo/src/components/PlaygroundControlsDemo.tsx +0 -63
  197. package/apps/demo/src/components/PlaygroundSection.tsx +0 -120
  198. package/apps/demo/src/components/ScrollRegionDemo.tsx +0 -74
  199. package/apps/demo/src/components/ThemeSwitcher.tsx +0 -79
  200. package/apps/demo/src/demo-layout.css +0 -293
  201. package/apps/demo/src/landing.css +0 -1143
  202. package/apps/demo/src/main.tsx +0 -14
  203. package/apps/demo/src/nav.ts +0 -9
  204. package/apps/demo/src/site.ts +0 -218
  205. package/apps/demo/tsconfig.json +0 -17
  206. package/apps/demo/vite-plugins/og-meta.ts +0 -30
  207. package/apps/demo/vite.config.ts +0 -69
  208. package/docs/API_PATTERNS.md +0 -234
  209. package/docs/ARCHITECTURE.md +0 -125
  210. package/docs/COMPONENT_CHECKLIST.md +0 -103
  211. package/docs/FILE_MAP.md +0 -122
  212. package/docs/GLOSSARY.md +0 -125
  213. package/docs/INDEX.md +0 -53
  214. package/docs/LAYOUT_COORDINATES.md +0 -178
  215. package/docs/MACHINES.md +0 -171
  216. package/docs/MIGRATION_FROM_ARK.md +0 -295
  217. package/docs/VITE_CONSUMER.md +0 -114
  218. package/pnpm-workspace.yaml +0 -3
  219. package/vercel.json +0 -12
@@ -1,178 +0,0 @@
1
- # Layout coordinates (responsive play surfaces)
2
-
3
- **Problem:** Games and rich apps need the same **logical** interaction space on desktop (split columns) and mobile (stacked lanes or overlays). CSS alone does not give you stable pointer math when regions move.
4
-
5
- **Aeon answer:** Separate three concerns — same pattern as `UI = f(state)`:
6
-
7
- | Layer | Owns | Package |
8
- |-------|------|---------|
9
- | **Behavior** | Statecharts, rounds, bets | `@aeon-ui/primitives` + app |
10
- | **Composition** | *Where* regions sit (split / stack / overlay) | CSS + `ResponsiveLayoutSpec` |
11
- | **Coordinates** | *Where* the user points inside a region | `@aeon-ui/core` `layout` module |
12
-
13
- Pointer logic uses a **normalized plane** (0–100 per axis) inside a measured `DOMRect`, not raw pixels.
14
-
15
- ---
16
-
17
- ## North star
18
-
19
- **Layout mode is explicit. Coordinates are normalized. CSS projects mode to pixels.**
20
-
21
- - `data-aeon-layout-mode="compact" | "wide"`
22
- - `data-aeon-layout-composition="split" | "stack" | "overlay"`
23
- - Anatomy: `playSurfaceAnatomy` → `mat`, `table`, `dice`, `bank`
24
-
25
- Agents: [AGENTS.md](../AGENTS.md) · API: `packages/core/src/layout.ts`
26
-
27
- ---
28
-
29
- ## Normalized plane
30
-
31
- ```ts
32
- import {
33
- normFromClient,
34
- clientFromNorm,
35
- clampNorm,
36
- NORM_PLANE,
37
- } from '@aeon-ui/core'
38
-
39
- const rect = bowlEl.getBoundingClientRect()
40
- const aim = normFromClient(rect, e.clientX, e.clientY, {
41
- origin: NORM_PLANE.bottomLeft, // y up — throws, dice
42
- bounds: { xMin: 10, xMax: 90, yMin: 26, yMax: 74 },
43
- })
44
- ```
45
-
46
- | Origin | Y direction | Use |
47
- |--------|-------------|-----|
48
- | `bottom-left` | Up | Dice throw, spatial games, scene aim |
49
- | `top-left` | Down | HUD-aligned hit targets (optional) |
50
-
51
- **Rule:** Pick one origin per region and keep it in the spec. Do not mix origins in one gesture pipeline.
52
-
53
- ---
54
-
55
- ## Responsive layout spec
56
-
57
- Declare **composition per mode**, not ad hoc media queries in TS:
58
-
59
- ```ts
60
- import type { ResponsiveLayoutSpec } from '@aeon-ui/core'
61
-
62
- export const ceeLoPlayLayout: ResponsiveLayoutSpec = {
63
- compactMq: '(max-width: 39.99rem)',
64
- modes: {
65
- wide: {
66
- id: 'ceelo-wide',
67
- composition: 'split',
68
- regions: [
69
- { region: 'dice', slot: 'bowl', zIndex: 1 },
70
- { region: 'table', slot: 'felt', zIndex: 1 },
71
- ],
72
- bounds: {
73
- dice: { xMin: 8, xMax: 40, yMin: 8, yMax: 92 },
74
- table: { xMin: 0, xMax: 100, yMin: 0, yMax: 100 },
75
- },
76
- },
77
- compact: {
78
- id: 'ceelo-compact',
79
- composition: 'stack',
80
- regions: [
81
- { region: 'table', slot: 'felt', zIndex: 2 },
82
- { region: 'dice', slot: 'dice', zIndex: 4 },
83
- ],
84
- bounds: {
85
- dice: { xMin: 10, xMax: 90, yMin: 26, yMax: 74 },
86
- },
87
- },
88
- },
89
- }
90
- ```
91
-
92
- | Composition | Meaning | CSS strategy |
93
- |-------------|---------|--------------|
94
- | `split` | Regions side by side | `grid-template-columns: col + 1fr` |
95
- | `stack` | Regions in rows | `grid-template-rows: auto + lane` |
96
- | `overlay` | Same cell, z-index | Single `mat` area + absolute children |
97
-
98
- **Do not** encode `overlay` until stack/split is stable — Casino-games reverted overlay for this reason.
99
-
100
- ---
101
-
102
- ## React
103
-
104
- ```ts
105
- import { useLayoutMode } from '@aeon-ui/react'
106
- import { layoutModeAttrs, regionBoundsForMode } from '@aeon-ui/core'
107
-
108
- const { mode, composition } = useLayoutMode(ceeLoPlayLayout)
109
- const diceBounds = regionBoundsForMode(ceeLoPlayLayout, mode, 'dice')
110
-
111
- <div
112
- data-aeon-scope="play"
113
- data-aeon-part="mat"
114
- {...layoutModeAttrs(mode, composition.composition)}
115
- >
116
- ```
117
-
118
- Measure the **dice region** element for `normFromClient`, not the full mat, when bounds are defined per region.
119
-
120
- ```ts
121
- import { measureElement, resolveRegionRect, normFromClient } from '@aeon-ui/core'
122
-
123
- const diceRect = resolveRegionRect(
124
- measureElement(bowlRef.current),
125
- measureElement(matRef.current),
126
- )
127
- ```
128
-
129
- ---
130
-
131
- ## CSS contract
132
-
133
- 1. Map `composition.regions[].slot` → `grid-template-areas` per `data-aeon-layout-mode`.
134
- 2. Never drive throw math from `grid-template-columns` percentages — measure DOM.
135
- 3. Optional Panda conditions:
136
-
137
- ```css
138
- [data-aeon-scope='play'][data-aeon-layout-mode='compact'][data-aeon-layout-composition='stack'] {
139
- /* stack rules */
140
- }
141
- ```
142
-
143
- ---
144
-
145
- ## Checklist (new game surface)
146
-
147
- - [ ] List logical regions (`table`, `dice`, `bank`, …).
148
- - [ ] Add `ResponsiveLayoutSpec` with `wide` + `compact` compositions.
149
- - [ ] Add per-mode `bounds` for any region that receives drag/aim.
150
- - [ ] CSS: two layouts keyed on `data-aeon-layout-mode` (no overlay until tested).
151
- - [ ] TS: `useLayoutMode` + `normFromClient` on measured region rects.
152
- - [ ] Demo or story: resize across breakpoint; aim stays inside bounds.
153
-
154
- ---
155
-
156
- ## Relation to scene plane
157
-
158
- | Package | Role |
159
- |---------|------|
160
- | `@aeon-ui/core` `layout` | App/play surface, pointer norm, breakpoints |
161
- | `@aeon-ui/geometry` | Decorative scene grids, SVG, `sceneAttrs` |
162
- | `@aeon-ui/scene` | CSS 3D presentation |
163
-
164
- Scene coordinates are visual; **layout coordinates** are for input and game logic.
165
-
166
- ---
167
-
168
- ## Reference implementation
169
-
170
- [Casino-games](https://github.com/GenericCPU/Casino-games) `shared/game/dicePlayLayout.ts` and `diceAim.ts` already use this model informally (`AimBounds` = `NormRect`). Migrating to `@aeon-ui/core` keeps one API across products.
171
-
172
- ---
173
-
174
- ## See also
175
-
176
- - [STATES.md](../STATES.md) — scroll snapshot (derived spatial state, same idea)
177
- - [docs/ARCHITECTURE.md](./ARCHITECTURE.md)
178
- - [packages/core/README.md](../packages/core/README.md)
package/docs/MACHINES.md DELETED
@@ -1,171 +0,0 @@
1
- # Machines truth table
2
-
3
- **Purpose:** Prevent agents from wiring the wrong state layer. This table reflects **current implementation**, not aspirational catalog rows.
4
-
5
- ---
6
-
7
- ## Summary table
8
-
9
- | Component | `@aeon-ui/primitives` machine | Headless runtime | `data-aeon-state` source |
10
- |-----------|------------------------------|------------------|--------------------------|
11
- | **Async** | `createAsyncMachine()` | `useAeonMachine` in `Async` context | Snapshot value (+ `stale` flag on readout) |
12
- | **Field** | `fieldMachine` (parallel) | `useAeonMachine` | `stateToAttr(snapshot.value)` |
13
- | **Button** | `buttonLifecycleMachine` | **`status` prop** on `Button.Root` | Prop string, not machine by default |
14
- | **Switch** | `toggleMachine` | `useAeonMachine` | Snapshot |
15
- | **Checkbox** | `toggleMachine` | `useAeonMachine` | Snapshot |
16
- | **Dialog** | `dialogMachine` | `useAeonMachine` | `open` / `closed` |
17
- | **Tabs** | `tabsMachine` | `useAeonMachine` | Selected tab value |
18
- | **Accordion** | `accordionMachine` | `useAeonMachine` | Per-item open |
19
- | **Menu** | `popoverMachine` | `useAeonMachine` | `open` / `closed` |
20
- | **Popover** | `popoverMachine` | `useAeonMachine` | `open` / `closed` |
21
- | **Toast** (item) | `toastMachine` | `useAeonMachine` | visible / hidden |
22
- | **Select** | `popoverMachine` | `useAeonMachine` | `open` / `closed`; highlight in React |
23
- | **Combobox** | — | **`useState`** (open, query, highlight) | `open` / `closed` + highlight attrs |
24
- | **Tooltip** | — | **`useState(open)`** | `open` / `closed`; touch tap toggle |
25
- | **Scroll** | — | **`getScrollSnapshot()`** | Derived overflow/edge tokens |
26
- | **Separator** | — | **static orientation prop** | horizontal / vertical |
27
- | **Progress** | — | **props** (`value`, `indeterminate`) | idle / loading / complete |
28
- | **RadioGroup** | `tabsMachine` | `useAeonMachine` | selected value |
29
- | **Slider** | `sliderMachine` | `useAeonMachine` | idle / dragging + numeric value |
30
- | **PinInput** | — | **`useState`** | idle / complete |
31
-
32
- ---
33
-
34
- ## Button: prop vs machine (critical)
35
-
36
- Two valid patterns — **do not conflate them**:
37
-
38
- ### Pattern A — Headless / styled (default)
39
-
40
- ```tsx
41
- <Button.Root status="pending" aria-busy>
42
- Saving…
43
- </Button.Root>
44
- ```
45
-
46
- - File: `packages/react/src/button/index.tsx`
47
- - `status` ∈ `idle` | `pending` | `success` | `failure` | `disabled`
48
- - Sets `data-aeon-state` via `partAttrs`
49
- - **No** `useAeonMachine` inside Button
50
-
51
- ### Pattern B — Chart-driven (app / demo)
52
-
53
- ```tsx
54
- const [snapshot, send] = useAeonMachine(buttonLifecycleMachine)
55
- const status = snapshot.value as ButtonStatus
56
- <Button.Root status={status} onClick={() => send({ type: 'PRESS' })} />
57
- ```
58
-
59
- - Machine: `packages/primitives/src/machines/button.ts`
60
- - Demo: playground **Button lifecycle**
61
-
62
- ---
63
-
64
- ## Async events
65
-
66
- Machine: `packages/primitives/src/machines/async.ts`
67
- Factory: `createAsyncMachine<T>()` — use per-region instance in context.
68
-
69
- | Event | Effect |
70
- |-------|--------|
71
- | `FETCH` | → `loading` |
72
- | `RESOLVE` `{ data }` | → `success` or `empty` if `isEmptyAsyncData(data)` |
73
- | `REJECT` `{ error }` | → `failure` |
74
- | `RESET` | → `idle`, clear context |
75
- | `STALE` | Context flag while staying in `success` |
76
- | `REFRESH` | Re-fetch from success/empty/failure |
77
-
78
- Constants: `ASYNC_LIFECYCLE_STATES`, `isEmptyAsyncData()`.
79
-
80
- React: `Async.Root` provides context; children call `send` via `useAsyncContext()`.
81
-
82
- ---
83
-
84
- ## Field events (orthogonal)
85
-
86
- Machine: `packages/primitives/src/machines/field.ts` — **parallel** regions.
87
-
88
- | Region | States |
89
- |--------|--------|
90
- | `interaction` | `pristine` · `dirty` |
91
- | `validation` | `valid` · `invalid` |
92
- | `submission` | `idle` · `pending` |
93
-
94
- | Event | Typical use |
95
- |-------|-------------|
96
- | `INPUT` | User typed |
97
- | `BLUR` | Left control |
98
- | `VALIDATE` `{ valid: boolean }` | After rule run |
99
- | `SUBMIT` | Form submit started |
100
- | `SUBMIT_DONE` / `SUBMIT_FAIL` | End pending |
101
- | `RESET` | Clear field |
102
-
103
- Flatten for DOM:
104
-
105
- ```ts
106
- import { stateToAttr } from '@aeon-ui/core'
107
- stateToAttr(snapshot.value) // "interaction:dirty validation:invalid submission:idle"
108
- ```
109
-
110
- ---
111
-
112
- ## Button lifecycle events
113
-
114
- Machine: `buttonLifecycleMachine` in `packages/primitives/src/machines/button.ts`
115
-
116
- | Event | From → To (simplified) |
117
- |-------|------------------------|
118
- | `PRESS` | idle → pending |
119
- | `SUCCEED` | pending → success |
120
- | `FAIL` | pending → failure |
121
- | `DISABLE` / `ENABLE` | ↔ disabled |
122
- | `RESET` | → idle |
123
-
124
- ---
125
-
126
- ## Dialog / toggle / tabs / accordion
127
-
128
- | Machine | File | Notes |
129
- |---------|------|-------|
130
- | `dialogMachine` | `machines/dialog.ts` | open/closed; Escape handled in React |
131
- | `toggleMachine` | `machines/toggle.ts` | Switch + Checkbox |
132
- | `tabsMachine` | `machines/tabs.ts` | Single active value |
133
- | `accordionMachine` | `machines/accordion.ts` | Multiple items |
134
- | `popoverMachine` | `machines/popover.ts` | Menu, Popover, Select |
135
- | `toastMachine` | `machines/toast.ts` | Auto-dismiss input |
136
-
137
- Inspect each file for full transition tables. Diagrams: `apps/demo/src/aeonDiagrams.ts`.
138
-
139
- ---
140
-
141
- ## Combobox / Tooltip
142
-
143
- **No primitives machine.** Open/query/highlight live in:
144
-
145
- - `packages/react/src/combobox/index.tsx` (item registry for filtering)
146
- - `packages/react/src/tooltip/index.tsx`
147
-
148
- **Select** reuses `popoverMachine` for open/closed; option order comes from DOM (`role="option"` ids), not a registry.
149
-
150
- ---
151
-
152
- ## Scroll
153
-
154
- ```ts
155
- import { getScrollSnapshot } from '@aeon-ui/core'
156
- ```
157
-
158
- Hook: `packages/react/src/scroll/use-scroll-state.ts` — listens to scroll/resize on viewport.
159
-
160
- States: `idle`, `overflow-y`, `overflow-x`, `overflow-both`, `at-start-y`, `between-y`, `at-end-y`, … (see [STATES.md](../STATES.md) §5).
161
-
162
- ---
163
-
164
- ## Diagram sync
165
-
166
- When you change transitions in `packages/primitives/src/machines/`:
167
-
168
- 1. Update matching diagram string in `apps/demo/src/aeonDiagrams.ts`
169
- 2. Mention in PR / commit that diagrams were synced
170
-
171
- No automated test enforces sync yet — **manual discipline required**.
@@ -1,295 +0,0 @@
1
- # Migrating from Ark UI to Aeon UI
2
-
3
- Step-by-step guide for apps that use **`@ark-ui/react`** headless primitives with your own CSS (Tailwind, CSS modules, etc.). Chakra-wrapped Ark recipes are out of scope here—migrate the headless boundary first, then revisit styling.
4
-
5
- **Reference consumers**
6
-
7
- | App | Stack | Notes |
8
- |-----|-------|--------|
9
- | [spidercorp.xyz](https://github.com/GenericCPU/spydercorp.xyz) | Vite + React | Field, Select, Dialog, Toast |
10
- | [soundbase.click](https://github.com/GenericCPU/soundbase) | Next.js + React | Avatar (Chakra remains for other widgets) |
11
-
12
- ---
13
-
14
- ## 1. Inventory Ark usage
15
-
16
- ```bash
17
- rg "@ark-ui" --glob '*.{ts,tsx}' .
18
- ```
19
-
20
- Group imports by component (`dialog`, `select`, `field`, `avatar`, `toast`, `portal`, `collection`, …). Migrate in this order when possible:
21
-
22
- 1. **Leaf primitives** with a direct Aeon equivalent (Avatar, Switch, Checkbox).
23
- 2. **Forms** — Field, Select, Combobox.
24
- 3. **Overlays** — Dialog, Menu, Popover, Tooltip.
25
- 4. **Toasts** — replace `createToaster` with `Toast.Provider` + `useToast()`.
26
-
27
- Components with **no** Aeon headless yet (Slider, Number Input, Steps, …): keep Ark for that file until Aeon ships them, or replace with a minimal local implementation.
28
-
29
- ---
30
-
31
- ## 2. Install Aeon runtime deps
32
-
33
- Aeon headless peers:
34
-
35
- ```bash
36
- npm install @xstate/react xstate
37
- ```
38
-
39
- When `@aeon-ui/*` is on npm:
40
-
41
- ```bash
42
- npm install @aeon-ui/react @aeon-ui/core @aeon-ui/primitives
43
- ```
44
-
45
- Until publish, point the bundler at a built clone (sections 3–4).
46
-
47
- ---
48
-
49
- ## 3. Build Aeon once
50
-
51
- From the Aeon UI repo:
52
-
53
- ```bash
54
- pnpm run build:headless
55
- ```
56
-
57
- In the consumer `package.json`:
58
-
59
- ```json
60
- {
61
- "scripts": {
62
- "aeon:ensure": "node <path-to-AeonUI>/scripts/ensure-headless-built.mjs",
63
- "prebuild": "npm run aeon:ensure"
64
- }
65
- }
66
- ```
67
-
68
- CI: set `AEON_UI_ROOT` to the checkout path.
69
-
70
- ---
71
-
72
- ## 4. Wire the bundler
73
-
74
- ### Vite
75
-
76
- See [VITE_CONSUMER.md](./VITE_CONSUMER.md) for full `resolve.alias`, `optimizeDeps.include`, and TypeScript `paths`.
77
-
78
- ### Next.js (recommended: `file:` links)
79
-
80
- Turbopack often **cannot** import files outside the app root via `resolveAlias`. Link the built packages into `node_modules` instead:
81
-
82
- ```json
83
- {
84
- "dependencies": {
85
- "@aeon-ui/core": "file:../../../AeonUI/packages/core",
86
- "@aeon-ui/primitives": "file:../../../AeonUI/packages/primitives",
87
- "@aeon-ui/react": "file:../../../AeonUI/packages/react",
88
- "@xstate/react": "^5.0.3",
89
- "xstate": "^5.19.2"
90
- }
91
- }
92
- ```
93
-
94
- Run `npm install` after `pnpm run build:headless` in Aeon UI (or `npm run aeon:ensure` in the consumer).
95
-
96
- `next.config.mjs`:
97
-
98
- ```js
99
- export default {
100
- transpilePackages: ['@aeon-ui/react', '@aeon-ui/core', '@aeon-ui/primitives'],
101
- }
102
- ```
103
-
104
- Optional: `next build --webpack` if you hit Turbopack edge cases.
105
-
106
- `tsconfig.json` paths (optional; `file:` installs usually typecheck via package `types`):
107
-
108
- ```json
109
- {
110
- "compilerOptions": {
111
- "paths": {
112
- "@aeon-ui/core": ["../../../AeonUI/packages/core/dist/index.d.ts"],
113
- "@aeon-ui/primitives": ["../../../AeonUI/packages/primitives/dist/index.d.ts"],
114
- "@aeon-ui/react": ["../../../AeonUI/packages/react/dist/index.d.ts"]
115
- }
116
- }
117
- }
118
- ```
119
-
120
- Mark client boundaries: `'use client'` on files that import `@aeon-ui/react`.
121
-
122
- ---
123
-
124
- ## 5. API mapping (Ark → Aeon)
125
-
126
- | Ark | Aeon |
127
- |-----|------|
128
- | `data-scope` / `data-part` | `data-aeon-scope` / `data-aeon-part` |
129
- | `data-state` | `data-aeon-state` |
130
- | `Field.Input` | `Field.Control` |
131
- | `Field.Textarea` | `Field.Textarea` |
132
- | `createListCollection` + `Select.*` | `Select.Root` → `Trigger` + `ValueText` → `Positioner` → `Content` → `Item` |
133
- | `Portal` + `Dialog.*` | `Dialog.Portal` wraps `Backdrop`, `Positioner`, `Content` |
134
- | `Avatar.Root` / `Image` / `Fallback` | Same part names under `@aeon-ui/react` |
135
- | `createToaster` + `Toaster` | `Toast.Provider`, `Toast.Viewport`, `useToast().publish()` |
136
-
137
- ### Select (required structure)
138
-
139
- ```tsx
140
- import { Select } from '@aeon-ui/react'
141
-
142
- <Select.Root value={value} onValueChange={setValue}>
143
- <Select.Trigger>
144
- <Select.ValueText>{label}</Select.ValueText>
145
- </Select.Trigger>
146
- <Select.Positioner>
147
- <Select.Content>
148
- <Select.Item value="a">Option A</Select.Item>
149
- </Select.Content>
150
- </Select.Positioner>
151
- </Select.Root>
152
- ```
153
-
154
- Use `portalled={false}` in tests or fixed-height containers.
155
-
156
- ### Dialog
157
-
158
- ```tsx
159
- <Dialog.Root open={open} onOpenChange={setOpen}>
160
- <Dialog.Trigger>Open</Dialog.Trigger>
161
- <Dialog.Portal>
162
- <Dialog.Backdrop />
163
- <Dialog.Positioner>
164
- <Dialog.Content>
165
- <Dialog.Title>Title</Dialog.Title>
166
- <Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
167
- </Dialog.Content>
168
- </Dialog.Positioner>
169
- </Dialog.Portal>
170
- </Dialog.Root>
171
- ```
172
-
173
- ### Avatar (shadcn-style wrapper)
174
-
175
- Keep your `components/ui/avatar.tsx` as a thin Tailwind wrapper over Aeon parts so call sites stay unchanged:
176
-
177
- ```tsx
178
- import { Avatar as AeonAvatar } from '@aeon-ui/react'
179
-
180
- function Avatar({ className, ...props }) {
181
- return <AeonAvatar.Root className={cn('relative flex size-8 ...', className)} {...props} />
182
- }
183
- ```
184
-
185
- Aeon does not force width/height recipes—Tailwind `size-*` on `Root` works.
186
-
187
- ### Toasts
188
-
189
- ```tsx
190
- // layout.tsx
191
- import { Toast } from '@aeon-ui/react'
192
-
193
- <Toast.Provider>
194
- {children}
195
- <Toast.Viewport placement="bottom-end" />
196
- </Toast.Provider>
197
-
198
- // anywhere
199
- const { publish } = useToast()
200
- publish({ title: 'Saved' })
201
- ```
202
-
203
- ---
204
-
205
- ## 6. Restyle with `data-aeon-*`
206
-
207
- Ark CSS often targets `[data-part=trigger]`. Rename selectors:
208
-
209
- ```css
210
- /* was: [data-scope='select'][data-part='content'] */
211
- [data-aeon-scope='select'][data-aeon-part='content'] {
212
- /* ... */
213
- }
214
- ```
215
-
216
- State:
217
-
218
- ```css
219
- [data-aeon-scope='select'][data-aeon-part='item'][data-aeon-state='highlighted'] {
220
- background: var(--accent);
221
- }
222
- ```
223
-
224
- See [STATES.md](../STATES.md) and [INTEGRATION.md](../INTEGRATION.md).
225
-
226
- ---
227
-
228
- ## 7. Remove Ark
229
-
230
- ```bash
231
- npm uninstall @ark-ui/react
232
- ```
233
-
234
- Re-run build and grep for stragglers:
235
-
236
- ```bash
237
- rg "@ark-ui" .
238
- ```
239
-
240
- ---
241
-
242
- ## 8. Verify
243
-
244
- | Check | Command / action |
245
- |-------|------------------|
246
- | Aeon tests | `cd AeonUI && pnpm test:headless` |
247
- | Consumer build | `npm run build` / `vite build` |
248
- | Select | Open list, keyboard, pick option, Escape |
249
- | Dialog | Open, focus trap, Escape, scroll lock |
250
- | Avatar | Image load, fallback when missing/broken |
251
- | Toasts | `publish` after provider mount |
252
-
253
- ---
254
-
255
- ## 9. Chakra + Ark stacks
256
-
257
- Many HandCash templates use **Chakra v3 recipes** built on Ark. Migrating “off Ark” does not require removing Chakra in one pass:
258
-
259
- 1. Replace **direct** `@ark-ui/react` imports (e.g. `components/ui/avatar.tsx`).
260
- 2. Later, swap Chakra widgets for `@aeon-ui/react` or `@aeon-ui/ui` per component.
261
-
262
- soundbase.click keeps Chakra for Button, Dialog, Select, etc.; only Avatar uses Aeon headless today.
263
-
264
- ---
265
-
266
- ## Light / dark transitions (Tailwind + next-themes)
267
-
268
- Import Aeon’s transition stylesheet and bridge `data-aeon-mode` to your existing theme toggle:
269
-
270
- ```css
271
- /* globals.css */
272
- @import '@aeon-ui/core/theme-transition.css';
273
- ```
274
-
275
- ```tsx
276
- import { AeonThemeBridge } from '@/components/aeon-theme-bridge' // syncs next-themes → data-aeon-mode
277
- import { runAeonThemeTransition } from '@aeon-ui/core'
278
-
279
- // layout: inside <ThemeProvider>
280
- <AeonThemeBridge />
281
-
282
- // theme menu
283
- runAeonThemeTransition(() => setTheme('dark'))
284
- ```
285
-
286
- Reference: **soundbase.click** (`components/aeon-theme-bridge.tsx`).
287
-
288
- ---
289
-
290
- ## Related docs
291
-
292
- - [VITE_CONSUMER.md](./VITE_CONSUMER.md) — Vite-specific aliases
293
- - [MACHINES.md](./MACHINES.md) — which components use XState
294
- - [ACCESSIBILITY.md](../ACCESSIBILITY.md) — roles and keyboard
295
- - [API_PATTERNS.md](./API_PATTERNS.md) — copy-paste snippets