aeon-ui-engine 1.0.1 → 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 (227) hide show
  1. package/CHANGELOG.md +51 -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/panda/src/recipes/button.ts +4 -4
  28. package/packages/panda/src/recipes/combobox.ts +1 -1
  29. package/packages/panda/src/recipes/select.ts +1 -1
  30. package/packages/panda/src/theme/tokens.ts +5 -0
  31. package/packages/panda/styled-system/styles.css +10 -6
  32. package/packages/panda/styled-system/tokens/index.mjs +32 -0
  33. package/packages/panda/styled-system/tokens/tokens.d.ts +2 -2
  34. package/packages/primitives/dist/chunk-5S4DIRL4.js +42 -0
  35. package/packages/primitives/dist/chunk-H4KOEPYC.js +52 -0
  36. package/packages/primitives/dist/chunk-HONROWUG.js +41 -0
  37. package/packages/primitives/dist/chunk-J6JHKMVM.js +90 -0
  38. package/packages/primitives/dist/chunk-JBAG5E6W.js +46 -0
  39. package/packages/primitives/dist/chunk-LVNCD5F2.js +43 -0
  40. package/packages/primitives/dist/chunk-PB3LFHXU.js +72 -0
  41. package/packages/primitives/dist/chunk-SZV6KGXN.js +49 -0
  42. package/packages/primitives/dist/chunk-WVICCOQH.js +56 -0
  43. package/packages/primitives/dist/chunk-ZMGRX64G.js +74 -0
  44. package/packages/primitives/dist/index.d.ts +11 -0
  45. package/packages/primitives/dist/index.js +60 -0
  46. package/packages/primitives/dist/machines/accordion.d.ts +34 -0
  47. package/packages/primitives/dist/machines/accordion.js +6 -0
  48. package/packages/primitives/dist/machines/async.d.ts +111 -0
  49. package/packages/primitives/dist/machines/async.js +12 -0
  50. package/packages/primitives/dist/machines/button.d.ts +45 -0
  51. package/packages/primitives/dist/machines/button.js +8 -0
  52. package/packages/primitives/dist/machines/dialog.d.ts +57 -0
  53. package/packages/primitives/dist/machines/dialog.js +6 -0
  54. package/packages/primitives/dist/machines/field.d.ts +72 -0
  55. package/packages/primitives/dist/machines/field.js +12 -0
  56. package/packages/primitives/dist/machines/popover.d.ts +54 -0
  57. package/packages/primitives/dist/machines/popover.js +6 -0
  58. package/packages/primitives/dist/machines/slider.d.ts +71 -0
  59. package/packages/primitives/dist/machines/slider.js +10 -0
  60. package/packages/primitives/dist/machines/tabs.d.ts +39 -0
  61. package/packages/primitives/dist/machines/tabs.js +6 -0
  62. package/packages/primitives/dist/machines/toast.d.ts +31 -0
  63. package/packages/primitives/dist/machines/toast.js +6 -0
  64. package/packages/primitives/dist/machines/toggle.d.ts +54 -0
  65. package/packages/primitives/dist/machines/toggle.js +6 -0
  66. package/packages/primitives/node_modules/.bin/jiti +21 -0
  67. package/packages/primitives/node_modules/.bin/tsc +21 -0
  68. package/packages/primitives/node_modules/.bin/tsserver +21 -0
  69. package/packages/primitives/node_modules/.bin/tsup +21 -0
  70. package/packages/primitives/node_modules/.bin/tsup-node +21 -0
  71. package/packages/primitives/node_modules/.bin/tsx +21 -0
  72. package/packages/primitives/node_modules/.bin/vitest +21 -0
  73. package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  74. package/packages/react/dist/index.d.ts +564 -0
  75. package/packages/react/dist/index.js +3461 -0
  76. package/packages/react/node_modules/.bin/jiti +21 -0
  77. package/packages/react/node_modules/.bin/tsc +21 -0
  78. package/packages/react/node_modules/.bin/tsserver +21 -0
  79. package/packages/react/node_modules/.bin/tsup +21 -0
  80. package/packages/react/node_modules/.bin/tsup-node +21 -0
  81. package/packages/react/node_modules/.bin/tsx +21 -0
  82. package/packages/react/node_modules/.bin/vitest +21 -0
  83. package/packages/react/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  84. package/packages/react-scene/dist/index.d.ts +121 -0
  85. package/packages/react-scene/dist/index.js +430 -0
  86. package/packages/react-scene/node_modules/.bin/jiti +21 -0
  87. package/packages/react-scene/node_modules/.bin/tsc +21 -0
  88. package/packages/react-scene/node_modules/.bin/tsserver +21 -0
  89. package/packages/react-scene/node_modules/.bin/tsup +21 -0
  90. package/packages/react-scene/node_modules/.bin/tsup-node +21 -0
  91. package/packages/react-scene/node_modules/.bin/tsx +21 -0
  92. package/packages/scene/dist/index.d.ts +46 -0
  93. package/packages/scene/dist/index.js +54 -0
  94. package/packages/scene/node_modules/.bin/jiti +21 -0
  95. package/packages/scene/node_modules/.bin/tsc +21 -0
  96. package/packages/scene/node_modules/.bin/tsserver +21 -0
  97. package/packages/scene/node_modules/.bin/tsup +21 -0
  98. package/packages/scene/node_modules/.bin/tsup-node +21 -0
  99. package/packages/scene/node_modules/.bin/tsx +21 -0
  100. package/packages/signal/dist/index.d.ts +54 -0
  101. package/packages/signal/dist/index.js +169 -0
  102. package/packages/signal/node_modules/.bin/jiti +21 -0
  103. package/packages/signal/node_modules/.bin/tsc +21 -0
  104. package/packages/signal/node_modules/.bin/tsserver +21 -0
  105. package/packages/signal/node_modules/.bin/tsup +21 -0
  106. package/packages/signal/node_modules/.bin/tsup-node +21 -0
  107. package/packages/signal/node_modules/.bin/tsx +21 -0
  108. package/packages/site/dist/index.d.ts +31 -0
  109. package/packages/site/dist/index.js +62 -0
  110. package/packages/site/node_modules/.bin/jiti +21 -0
  111. package/packages/site/node_modules/.bin/tsc +21 -0
  112. package/packages/site/node_modules/.bin/tsserver +21 -0
  113. package/packages/site/node_modules/.bin/tsup +21 -0
  114. package/packages/site/node_modules/.bin/tsup-node +21 -0
  115. package/packages/site/node_modules/.bin/tsx +21 -0
  116. package/packages/solid/dist/index.d.ts +30 -0
  117. package/packages/solid/dist/index.js +174 -0
  118. package/packages/solid/node_modules/.bin/jiti +21 -0
  119. package/packages/solid/node_modules/.bin/tsc +21 -0
  120. package/packages/solid/node_modules/.bin/tsserver +21 -0
  121. package/packages/solid/node_modules/.bin/tsup +21 -0
  122. package/packages/solid/node_modules/.bin/tsup-node +21 -0
  123. package/packages/solid/node_modules/.bin/tsx +21 -0
  124. package/packages/surface/dist/index.d.ts +8 -0
  125. package/packages/surface/dist/index.js +14 -0
  126. package/packages/surface/node_modules/.bin/jiti +21 -0
  127. package/packages/surface/node_modules/.bin/tsc +21 -0
  128. package/packages/surface/node_modules/.bin/tsserver +21 -0
  129. package/packages/surface/node_modules/.bin/tsup +21 -0
  130. package/packages/surface/node_modules/.bin/tsup-node +21 -0
  131. package/packages/surface/node_modules/.bin/tsx +21 -0
  132. package/packages/svelte/dist/index.d.ts +12 -0
  133. package/packages/svelte/dist/index.js +15 -0
  134. package/packages/svelte/node_modules/.bin/acorn +21 -0
  135. package/packages/svelte/node_modules/.bin/jiti +21 -0
  136. package/packages/svelte/node_modules/.bin/svelte-check +21 -0
  137. package/packages/svelte/node_modules/.bin/tsc +21 -0
  138. package/packages/svelte/node_modules/.bin/tsserver +21 -0
  139. package/packages/svelte/node_modules/.bin/tsup +21 -0
  140. package/packages/svelte/node_modules/.bin/tsup-node +21 -0
  141. package/packages/svelte/node_modules/.bin/tsx +21 -0
  142. package/packages/svelte/node_modules/.bin/vite +21 -0
  143. package/packages/ui/dist/index.d.ts +200 -0
  144. package/packages/ui/dist/index.js +429 -0
  145. package/packages/ui/node_modules/.bin/jiti +21 -0
  146. package/packages/ui/node_modules/.bin/tsc +21 -0
  147. package/packages/ui/node_modules/.bin/tsserver +21 -0
  148. package/packages/ui/node_modules/.bin/tsup +21 -0
  149. package/packages/ui/node_modules/.bin/tsup-node +21 -0
  150. package/packages/ui/node_modules/.bin/tsx +21 -0
  151. package/packages/ui/src/select.tsx +3 -4
  152. package/packages/vue/dist/index.d.ts +71 -0
  153. package/packages/vue/dist/index.js +193 -0
  154. package/packages/vue/node_modules/.bin/jiti +21 -0
  155. package/packages/vue/node_modules/.bin/tsc +21 -0
  156. package/packages/vue/node_modules/.bin/tsserver +21 -0
  157. package/packages/vue/node_modules/.bin/tsup +21 -0
  158. package/packages/vue/node_modules/.bin/tsup-node +21 -0
  159. package/packages/vue/node_modules/.bin/tsx +21 -0
  160. package/scripts/vite-aliases.mjs +125 -0
  161. package/.changeset/README.md +0 -23
  162. package/.changeset/combobox-and-changesets.md +0 -9
  163. package/.changeset/config.json +0 -30
  164. package/.changeset/framework-adapters.md +0 -12
  165. package/.changeset/scene-3d.md +0 -6
  166. package/.changeset/scene-plane.md +0 -8
  167. package/.changeset/site-og.md +0 -5
  168. package/.cursor/rules/aeon-ui.mdc +0 -22
  169. package/ACCESSIBILITY.md +0 -32
  170. package/AGENTS.md +0 -226
  171. package/COMPONENTS.md +0 -41
  172. package/FRAMEWORKS.md +0 -57
  173. package/PHILOSOPHY.md +0 -71
  174. package/PUBLISHING.md +0 -85
  175. package/SCENE.md +0 -113
  176. package/STATES.md +0 -243
  177. package/apps/demo/index.html +0 -31
  178. package/apps/demo/og.config.mjs +0 -20
  179. package/apps/demo/package.json +0 -41
  180. package/apps/demo/public/favicon.svg +0 -16
  181. package/apps/demo/public/og-aeon-ui-engine.png +0 -0
  182. package/apps/demo/public/og.svg +0 -35
  183. package/apps/demo/scripts/generate-og-png.mjs +0 -62
  184. package/apps/demo/src/App.tsx +0 -31
  185. package/apps/demo/src/aeonDiagrams.ts +0 -42
  186. package/apps/demo/src/app.css +0 -16
  187. package/apps/demo/src/components/ActionCluster.tsx +0 -20
  188. package/apps/demo/src/components/AsyncMachineDemo.tsx +0 -97
  189. package/apps/demo/src/components/ButtonLifecycleDemo.tsx +0 -63
  190. package/apps/demo/src/components/CodeExample.tsx +0 -7
  191. package/apps/demo/src/components/ComboboxDemo.tsx +0 -30
  192. package/apps/demo/src/components/DiagramsSection.tsx +0 -37
  193. package/apps/demo/src/components/FieldStateDemo.tsx +0 -51
  194. package/apps/demo/src/components/GridMesh.tsx +0 -8
  195. package/apps/demo/src/components/HeroInstall.tsx +0 -13
  196. package/apps/demo/src/components/LandingFaq.tsx +0 -29
  197. package/apps/demo/src/components/LandingFooter.tsx +0 -30
  198. package/apps/demo/src/components/LandingHeader.tsx +0 -62
  199. package/apps/demo/src/components/LandingHero.tsx +0 -55
  200. package/apps/demo/src/components/LayersSection.tsx +0 -47
  201. package/apps/demo/src/components/MermaidDiagram.tsx +0 -86
  202. package/apps/demo/src/components/PhilosophySection.tsx +0 -31
  203. package/apps/demo/src/components/PlaygroundBlock.tsx +0 -18
  204. package/apps/demo/src/components/PlaygroundControlsDemo.tsx +0 -63
  205. package/apps/demo/src/components/PlaygroundSection.tsx +0 -120
  206. package/apps/demo/src/components/ScrollRegionDemo.tsx +0 -74
  207. package/apps/demo/src/components/ThemeSwitcher.tsx +0 -79
  208. package/apps/demo/src/demo-layout.css +0 -293
  209. package/apps/demo/src/landing.css +0 -1151
  210. package/apps/demo/src/main.tsx +0 -14
  211. package/apps/demo/src/nav.ts +0 -9
  212. package/apps/demo/src/site.ts +0 -218
  213. package/apps/demo/tsconfig.json +0 -17
  214. package/apps/demo/vite-plugins/og-meta.ts +0 -30
  215. package/apps/demo/vite.config.ts +0 -69
  216. package/docs/API_PATTERNS.md +0 -234
  217. package/docs/ARCHITECTURE.md +0 -125
  218. package/docs/COMPONENT_CHECKLIST.md +0 -103
  219. package/docs/FILE_MAP.md +0 -122
  220. package/docs/GLOSSARY.md +0 -125
  221. package/docs/INDEX.md +0 -53
  222. package/docs/LAYOUT_COORDINATES.md +0 -178
  223. package/docs/MACHINES.md +0 -171
  224. package/docs/MIGRATION_FROM_ARK.md +0 -295
  225. package/docs/VITE_CONSUMER.md +0 -114
  226. package/pnpm-workspace.yaml +0 -3
  227. package/vercel.json +0 -12
package/STATES.md DELETED
@@ -1,243 +0,0 @@
1
- # States traditional UI forgets — and how Aeon models them
2
-
3
- **Agents:** start at [AGENTS.md](./AGENTS.md) and [docs/MACHINES.md](./docs/MACHINES.md) for which components use machines vs props.
4
-
5
- Aeon’s north star: **[state is defined first; UI expresses the totality of that definition](./PHILOSOPHY.md)** (`UI = f(snapshot)`).
6
-
7
- Traditional interfaces collapse rich behavior into a few booleans (`disabled`, `loading`, `open`) or hide conditions entirely. This document catalogs common gaps, how Aeon addresses them today, and how to extend the library.
8
-
9
- ---
10
-
11
- ## The attribute contract
12
-
13
- Every styled surface should be targetable consistently:
14
-
15
- | Attribute | Purpose |
16
- |-----------|---------|
17
- | `data-aeon-scope` | Component family (`button`, `async`, `field`, …) |
18
- | `data-aeon-part` | Compound part (`root`, `track`, `control`, …) |
19
- | `data-aeon-state` | Active condition(s) from the machine snapshot |
20
-
21
- Nested parallel regions flatten with `stateToAttr` from `@aeon-ui/core`:
22
-
23
- ```ts
24
- import { stateToAttr } from '@aeon-ui/core'
25
- // e.g. "interaction:dirty validation:invalid submission:idle"
26
- ```
27
-
28
- Panda recipes and `globalCss` in `@aeon-ui/panda` key off these attributes — not ad hoc class names in product code.
29
-
30
- ---
31
-
32
- ## 1. Async data regions
33
-
34
- ### What traditional UI skips
35
-
36
- | Condition | Typical mistake |
37
- |-----------|-----------------|
38
- | **Idle** (never fetched) | Looks like “empty” |
39
- | **Loading** | Spinner with no named state |
40
- | **Success** | Only happy path styled |
41
- | **Failure** | Toast only, easy to miss |
42
- | **Empty** (success, zero results) | Same UI as idle |
43
- | **Stale** (success + background refresh) | Silent flicker |
44
-
45
- ### Aeon model
46
-
47
- Machine: `createAsyncMachine()` in `@aeon-ui/primitives`
48
- States: `idle` · `loading` · `success` · `failure` · `empty`
49
- Context flag: `stale` on success → readout uses `data-aeon-state="success stale"`
50
-
51
- Constants: `ASYNC_LIFECYCLE_STATES`, `isEmptyAsyncData()`
52
-
53
- ### UI kit (totality pattern)
54
-
55
- ```tsx
56
- import { Async, Button } from '@aeon-ui/ui'
57
-
58
- <Async.Root>
59
- <Async.Track /> {/* every lifecycle state visible on the rail */}
60
- <Async.Readout>…</Async.Readout>
61
- <Async.Actions>
62
- <Button.Root>Fetch</Button.Root>
63
- </Async.Actions>
64
- </Async.Root>
65
- ```
66
-
67
- Headless: `@aeon-ui/react` → `Async`, `useAsyncContext`
68
- Anatomy: `asyncAnatomy` (`track`, `segment`, `readout`, `actions`, …)
69
- Styles: `aeonAsync` slot recipe
70
-
71
- **Rule:** If the chart lists five states, the track lists five segments — one active, none implicit.
72
-
73
- ---
74
-
75
- ## 2. Action button lifecycle
76
-
77
- ### What traditional UI skips
78
-
79
- `disabled` is used for: in-flight submit, success, permission denied, validation blocked, and “busy”.
80
-
81
- Missing named states: **pending**, **success**, **failure**, distinct from **disabled**.
82
-
83
- ### Aeon model
84
-
85
- Machine: `buttonLifecycleMachine`
86
- States: `idle` · `pending` · `success` · `failure` · `disabled`
87
-
88
- ### Component API
89
-
90
- ```tsx
91
- <Button.Root status="pending" aria-busy>
92
- Submitting…
93
- </Button.Root>
94
- ```
95
-
96
- `status` maps to `data-aeon-state`. Global styles adjust cursor/opacity/border per state.
97
-
98
- For full chart-driven flows, run `buttonLifecycleMachine` with `useAeonMachine` and drive `status` from `snapshot.value` (see playground **Button lifecycle**).
99
-
100
- ---
101
-
102
- ## 3. Form field (orthogonal regions)
103
-
104
- ### What traditional UI skips
105
-
106
- Interaction, validation, and submission are merged into one visual “error state.”
107
-
108
- ### Aeon model
109
-
110
- Machine: `fieldMachine` (parallel)
111
-
112
- | Region | States |
113
- |--------|--------|
114
- | `interaction` | `pristine` · `dirty` |
115
- | `validation` | `valid` · `invalid` |
116
- | `submission` | `idle` · `pending` |
117
-
118
- Root: `data-aeon-state="interaction:dirty validation:invalid submission:idle"`
119
-
120
- ### Component API
121
-
122
- ```tsx
123
- import { Field } from '@aeon-ui/ui'
124
-
125
- <Field.Root>
126
- <Field.Label htmlFor="email">Email</Field.Label>
127
- <Field.Control id="email" validate={(v) => isValidEmail(v)} />
128
- <Field.Message>Enter a valid email.</Field.Message>
129
- <Field.Hint>Shown when pristine.</Field.Hint>
130
- </Field.Root>
131
- ```
132
-
133
- `Field.Control` sends `INPUT`, `BLUR`, and `VALIDATE` events.
134
- `Field.Message` renders only when `validation:invalid`.
135
- Pending submission dims the control via `[data-aeon-state*="submission:pending"]` in global CSS.
136
-
137
- ---
138
-
139
- ## 4. Primitives already chart-backed
140
-
141
- | Primitive | Stable states (high level) |
142
- |-----------|----------------------------|
143
- | **Dialog** | `closed` · `open` |
144
- | **Toggle / Switch** | `checked` / `unchecked` + interaction `idle` · `pressed` |
145
- | **Tabs** | single active value |
146
- | **Accordion** | per-item open/closed |
147
-
148
- Future optional substates (documented, not all implemented): dialog `entering` / `exiting`, accordion `expanding` / `collapsing`.
149
-
150
- ---
151
-
152
- ## 5. Scroll regions
153
-
154
- ### What traditional UI skips
155
-
156
- Scroll position is implicit. Overflow axis (vertical, horizontal, or both) and whether the user is at the start, middle, or end of each axis are rarely reflected in the DOM — so edge fades, scrollbar styling, and assistive hints stay out of sync.
157
-
158
- ### Aeon model
159
-
160
- No XState machine — `getScrollSnapshot()` in `@aeon-ui/core` derives state from the viewport element on scroll and resize.
161
-
162
- | `data-aeon-state` token | Meaning |
163
- |-------------------------|---------|
164
- | `idle` | No overflow on either axis |
165
- | `overflow-y` · `overflow-x` · `overflow-both` | Which axes scroll |
166
- | `at-start-y` · `between-y` · `at-end-y` | Vertical edge position |
167
- | `at-start-x` · `between-x` · `at-end-x` | Horizontal edge position |
168
-
169
- ### Component API
170
-
171
- ```tsx
172
- import { Scroll } from '@aeon-ui/ui'
173
-
174
- <Scroll.Root axis="both" maxH="md">
175
- <Scroll.Viewport>
176
- <Scroll.Content>{children}</Scroll.Content>
177
- </Scroll.Viewport>
178
- <Scroll.StateReadout />
179
- </Scroll.Root>
180
- ```
181
-
182
- Import `@aeon-ui/panda/scrollbars.css` after `theme-runtime.css` for WebKit + Firefox scrollbar styling on `html`, `[data-aeon-scroll]`, and `.code-example`.
183
-
184
- ---
185
-
186
- ## 6. States to model in product code
187
-
188
- Aeon does not ship every domain machine, but the same rules apply:
189
-
190
- | Concern | Suggested states |
191
- |---------|------------------|
192
- | **Offline** | `online` · `offline` · `reconnecting` |
193
- | **Permissions** | `allowed` · `denied` (not `disabled`) |
194
- | **Optimistic UI** | `optimistic` · `confirmed` · `rolledBack` |
195
- | **Rate limit** | `ok` · `throttled` |
196
- | **Selection** | add `indeterminate` on checkboxes |
197
-
198
- Use **orthogonal regions** when concerns are independent (Nguyen / Harel statecharts).
199
-
200
- ---
201
-
202
- ## 7. Styling checklist
203
-
204
- Full ordered steps: **[docs/COMPONENT_CHECKLIST.md](./docs/COMPONENT_CHECKLIST.md)**.
205
-
206
- 1. Model the chart in `@aeon-ui/primitives` (or app-level XState).
207
- 2. Add anatomy in `@aeon-ui/core` if new scope.
208
- 3. Project snapshot in `@aeon-ui/react` with `partAttrs` / `stateToAttr`.
209
- 4. Add slot recipe or `globalCss` keyed on `data-aeon-state` in `@aeon-ui/panda`.
210
- 5. Export styled compound from `@aeon-ui/ui`.
211
- 6. Demo the **full rail** — track + readout + actions.
212
-
213
- ---
214
-
215
- ## 8. Play-surface layout (spatial, not XState)
216
-
217
- Games and spatial UIs need **desktop vs mobile composition** without breaking pointer math. Aeon models this separately from behavior:
218
-
219
- - **Layout mode** — `compact` | `wide` on `data-aeon-layout-mode`
220
- - **Composition** — `split` | `stack` | `overlay` on `data-aeon-layout-composition`
221
- - **Normalized coordinates** — `normFromClient` / `clientFromNorm` in `@aeon-ui/core` (0–100 plane per measured region)
222
-
223
- Full guide: **[docs/LAYOUT_COORDINATES.md](./docs/LAYOUT_COORDINATES.md)** · Anatomy: `playSurfaceAnatomy` · Hook: `useLayoutMode`.
224
-
225
- ---
226
-
227
- ## 9. Package map
228
-
229
- | Package | Role |
230
- |---------|------|
231
- | `@aeon-ui/primitives` | Machines: `async`, `buttonLifecycle`, `field`, … |
232
- | `@aeon-ui/core` | `asyncAnatomy`, `fieldAnatomy`, `scrollAnatomy`, `getScrollSnapshot` |
233
- | `@aeon-ui/react` | `Async.*`, `Field.*`, `Scroll.*`, `Button` + `status` |
234
- | `@aeon-ui/panda` | `aeonAsync`, `aeonField`, `aeonScroll`, `scrollbars.css` |
235
- | `@aeon-ui/ui` | Styled exports |
236
-
237
- ---
238
-
239
- ## References
240
-
241
- - [PHILOSOPHY.md](./PHILOSOPHY.md) — north star and tenets
242
- - [Thanh Nguyen (2020) — Statecharts for modern web application state management](https://www.theseus.fi/bitstream/handle/10024/334118/Thanh_Nguyen.pdf?sequence=2&isAllowed=y)
243
- - Live examples: `apps/demo` playground (**Async region**, **Button lifecycle**, **Field regions**, **Scroll regions**)
@@ -1,31 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Aeon UI — Future-proof UI infrastructure</title>
7
- <!-- OG_META -->
8
- <link rel="preconnect" href="https://fonts.googleapis.com" />
9
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
- <link
11
- href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Instrument+Sans:wght@400;500;600;700&family=Syne:wght@600;700;800&display=swap"
12
- rel="stylesheet"
13
- />
14
- </head>
15
- <body>
16
- <div id="root"></div>
17
- <script>
18
- (function () {
19
- var t = localStorage.getItem('aeon-theme') || 'default';
20
- var m = localStorage.getItem('aeon-mode');
21
- if (m !== 'light' && m !== 'dark') {
22
- m = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
23
- }
24
- document.documentElement.dataset.aeonTheme = t;
25
- document.documentElement.dataset.aeonMode = m;
26
- document.documentElement.style.colorScheme = m;
27
- })();
28
- </script>
29
- <script type="module" src="/src/main.tsx"></script>
30
- </body>
31
- </html>
@@ -1,20 +0,0 @@
1
- /** Shared OG / canonical URLs — override in CI with VITE_SITE_ORIGIN. */
2
- export const siteOrigin = (process.env.VITE_SITE_ORIGIN ?? 'https://aeon-ui.com').replace(
3
- /\/$/,
4
- '',
5
- )
6
-
7
- /** Published npm package — keep in sync with apps/demo/src/site.ts */
8
- export const npmPackage = 'aeon-ui-engine'
9
- export const npmInstallCommand = `npm install ${npmPackage}`
10
-
11
- export const og = {
12
- title: 'Aeon UI — Future-proof UI infrastructure',
13
- description:
14
- 'Statechart-driven primitives and a styled layer you control — dependable behavior today, room to grow tomorrow. Built to last.',
15
- siteName: 'Aeon UI',
16
- imagePath: '/og-aeon-ui-engine.png',
17
- imageAlt: `Aeon UI — Future-proof UI infrastructure (${npmInstallCommand})`,
18
- themeColor: '#0c0e12',
19
- npmInstallCommand,
20
- }
@@ -1,41 +0,0 @@
1
- {
2
- "name": "@aeon-ui/demo",
3
- "private": true,
4
- "type": "module",
5
- "scripts": {
6
- "dev": "vite",
7
- "generate:og": "node scripts/generate-og-png.mjs",
8
- "build": "pnpm --filter @aeon-ui/panda codegen && pnpm --filter @aeon-ui/site build && node scripts/generate-og-png.mjs && vite build",
9
- "preview": "vite preview",
10
- "typecheck": "tsc --noEmit"
11
- },
12
- "dependencies": {
13
- "@aeon-ui/geometry": "workspace:*",
14
- "@aeon-ui/panda": "workspace:*",
15
- "@aeon-ui/primitives": "workspace:*",
16
- "@aeon-ui/react": "workspace:*",
17
- "@aeon-ui/react-scene": "workspace:*",
18
- "@aeon-ui/signal": "workspace:*",
19
- "@aeon-ui/surface": "workspace:*",
20
- "@aeon-ui/ui": "workspace:*",
21
- "@xstate/react": "^5.0.3",
22
- "mermaid": "^11.15.0",
23
- "react": "^19.1.0",
24
- "react-dom": "^19.1.0",
25
- "xstate": "^5.19.2"
26
- },
27
- "devDependencies": {
28
- "@aeon-ui/site": "workspace:*",
29
- "@fontsource/ibm-plex-mono": "^5.2.7",
30
- "@fontsource/instrument-sans": "^5.2.8",
31
- "@fontsource/syne": "^5.2.7",
32
- "@resvg/resvg-js": "^2.6.2",
33
- "@types/node": "^22.15.3",
34
- "@types/react": "^19.1.2",
35
- "@types/react-dom": "^19.1.2",
36
- "@vitejs/plugin-react": "^4.4.1",
37
- "typescript": "^5.8.3",
38
- "vite": "^6.3.5",
39
- "wawoff2": "^2.0.1"
40
- }
41
- }
@@ -1,16 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Aeon UI">
2
- <rect width="32" height="32" rx="8" fill="#0a0c10"/>
3
- <rect
4
- x="6.5"
5
- y="6.5"
6
- width="15"
7
- height="15"
8
- rx="3.5"
9
- fill="none"
10
- stroke="#5eead4"
11
- stroke-width="1.75"
12
- opacity="0.9"
13
- />
14
- <rect x="10.5" y="10.5" width="15" height="15" rx="3.5" fill="#e8ecf4"/>
15
- <circle cx="21" cy="21" r="2.5" fill="#5eead4"/>
16
- </svg>
@@ -1,35 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630" role="img" aria-label="Aeon UI - Future-proof UI infrastructure">
2
- <defs>
3
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#121820"/>
5
- <stop offset="55%" stop-color="#0c0e12"/>
6
- <stop offset="100%" stop-color="#080a0e"/>
7
- </linearGradient>
8
- <linearGradient id="accent" x1="0%" y1="0%" x2="100%" y2="0%">
9
- <stop offset="0%" stop-color="#2dd4bf" stop-opacity="0"/>
10
- <stop offset="45%" stop-color="#5eead4"/>
11
- <stop offset="100%" stop-color="#2dd4bf" stop-opacity="0"/>
12
- </linearGradient>
13
- <pattern id="grid" width="48" height="48" patternUnits="userSpaceOnUse">
14
- <path d="M 48 0 L 0 0 0 48" fill="none" stroke="#5eead4" stroke-width="0.5" opacity="0.08"/>
15
- </pattern>
16
- <radialGradient id="glow" cx="72%" cy="28%" r="45%">
17
- <stop offset="0%" stop-color="#5eead4" stop-opacity="0.14"/>
18
- <stop offset="100%" stop-color="#5eead4" stop-opacity="0"/>
19
- </radialGradient>
20
- </defs>
21
- <rect width="1200" height="630" fill="url(#bg)"/>
22
- <rect width="1200" height="630" fill="url(#grid)"/>
23
- <rect width="1200" height="630" fill="url(#glow)"/>
24
-
25
- <text x="80" y="268" fill="#f0f4e8" font-family="Syne" font-size="88" font-weight="700" letter-spacing="-0.04em">Aeon UI</text>
26
- <text x="80" y="340" fill="#94a3b8" font-family="Instrument Sans" font-size="36" font-weight="500">Future-proof UI infrastructure</text>
27
- <text x="80" y="400" fill="#64748b" font-family="IBM Plex Mono" font-size="22" font-weight="400">Statecharts / Headless primitives / Panda CSS</text>
28
-
29
- <rect x="80" y="428" width="404" height="40" rx="6" fill="rgba(94, 234, 212, 0.12)" stroke="rgba(94, 234, 212, 0.35)" stroke-width="1"/>
30
- <text x="104" y="454" fill="#5eead4" font-family="IBM Plex Mono" font-size="14" font-weight="500">{{NPM_INSTALL_COMMAND}}</text>
31
-
32
- <text x="80" y="548" fill="#94a3b8" font-family="Instrument Sans" font-size="17" font-weight="500">A project by</text>
33
- <text x="228" y="548" fill="#5eead4" font-family="Syne" font-size="22" font-weight="700">SpiderCorp</text>
34
- <text x="80" y="578" fill="#64748b" font-family="IBM Plex Mono" font-size="14" font-weight="400">spidercorp.xyz</text>
35
- </svg>
@@ -1,62 +0,0 @@
1
- import { createRequire } from 'node:module'
2
- import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
3
- import { tmpdir } from 'node:os'
4
- import { dirname, join } from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
- import { Resvg } from '@resvg/resvg-js'
7
- import wawoff2 from 'wawoff2'
8
- import { og } from '../og.config.mjs'
9
-
10
- const require = createRequire(import.meta.url)
11
- const root = join(dirname(fileURLToPath(import.meta.url)), '..')
12
- const svgPath = join(root, 'public', 'og.svg')
13
- const outPath = join(root, 'public', og.imagePath.replace(/^\//, ''))
14
-
15
- /** @type {Array<[slug: string, pkg: string, file: string]>} */
16
- const FONT_SOURCES = [
17
- ['Syne-700', '@fontsource/syne', 'syne-latin-700-normal.woff2'],
18
- ['InstrumentSans-500', '@fontsource/instrument-sans', 'instrument-sans-latin-500-normal.woff2'],
19
- ['InstrumentSans-400', '@fontsource/instrument-sans', 'instrument-sans-latin-400-normal.woff2'],
20
- ['IBMPlexMono-500', '@fontsource/ibm-plex-mono', 'ibm-plex-mono-latin-500-normal.woff2'],
21
- ['IBMPlexMono-400', '@fontsource/ibm-plex-mono', 'ibm-plex-mono-latin-400-normal.woff2'],
22
- ]
23
-
24
- function woff2Path(pkg, filename) {
25
- return join(dirname(require.resolve(`${pkg}/package.json`)), 'files', filename)
26
- }
27
-
28
- /** resvg `fontFiles` only loads SFNT/TTF — convert @fontsource WOFF2 first. */
29
- async function loadFontFiles() {
30
- const dir = mkdtempSync(join(tmpdir(), 'aeon-og-fonts-'))
31
- const fontFiles = []
32
-
33
- for (const [slug, pkg, file] of FONT_SOURCES) {
34
- const woff2 = readFileSync(woff2Path(pkg, file))
35
- const sfnt = await wawoff2.decompress(woff2)
36
- const ttfPath = join(dir, `${slug}.ttf`)
37
- writeFileSync(ttfPath, Buffer.from(sfnt))
38
- fontFiles.push(ttfPath)
39
- }
40
-
41
- return fontFiles
42
- }
43
-
44
- const svgTemplate = readFileSync(svgPath, 'utf8')
45
- const svg = svgTemplate.replaceAll('{{NPM_INSTALL_COMMAND}}', og.npmInstallCommand)
46
- const fontFiles = await loadFontFiles()
47
-
48
- const resvg = new Resvg(svg, {
49
- fitTo: { mode: 'width', value: 1200 },
50
- font: {
51
- loadSystemFonts: false,
52
- fontFiles,
53
- defaultFontFamily: 'Instrument Sans',
54
- sansSerifFamily: 'Instrument Sans',
55
- serifFamily: 'Syne',
56
- monospaceFamily: 'IBM Plex Mono',
57
- },
58
- })
59
-
60
- const png = resvg.render().asPng()
61
- writeFileSync(outPath, png)
62
- console.log(`Wrote ${outPath} (${png.length} bytes)`)
@@ -1,31 +0,0 @@
1
- import { Toast } from '@aeon-ui/ui'
2
- import { GridMesh } from './components/GridMesh.js'
3
- import { LandingFaq } from './components/LandingFaq.js'
4
- import { LandingFooter } from './components/LandingFooter.js'
5
- import { LandingHeader } from './components/LandingHeader.js'
6
- import { LandingHero } from './components/LandingHero.js'
7
- import { DiagramsSection } from './components/DiagramsSection.js'
8
- import { LayersSection } from './components/LayersSection.js'
9
- import { PhilosophySection } from './components/PhilosophySection.js'
10
- import { PlaygroundSection } from './components/PlaygroundSection.js'
11
-
12
- export function App() {
13
- return (
14
- <Toast.Provider>
15
- <GridMesh />
16
- <div className="landing">
17
- <LandingHeader />
18
- <main>
19
- <LandingHero />
20
- <PhilosophySection />
21
- <PlaygroundSection />
22
- <LayersSection />
23
- <DiagramsSection />
24
- <LandingFaq />
25
- </main>
26
- <LandingFooter />
27
- </div>
28
- <Toast.Viewport placement="bottom-end" />
29
- </Toast.Provider>
30
- )
31
- }
@@ -1,42 +0,0 @@
1
- /** Mermaid sources — kept in sync with aeon-ui-engine machines (STATES.md). */
2
-
3
- export type AeonDiagram = {
4
- id: string
5
- title: string
6
- caption: string
7
- source: string
8
- }
9
-
10
- /** Model → snapshot → DOM. The north-star flow. */
11
- export const aeonNorthStarDiagram = `flowchart LR
12
- chart["Statechart"]
13
- snap["Snapshot"]
14
- ui["UI"]
15
- chart --> snap --> ui`
16
-
17
- /** Main async path — full machine has reset/re-fetch edges in STATES.md. */
18
- export const asyncLifecycleDiagram = `stateDiagram-v2
19
- direction LR
20
- [*] --> idle
21
- idle --> loading: fetch
22
- loading --> success: ok
23
- loading --> failure: err
24
- loading --> empty: empty
25
- success --> idle: reset
26
- failure --> idle: reset
27
- empty --> idle: reset`
28
-
29
- export const aeonDiagrams: AeonDiagram[] = [
30
- {
31
- id: 'north-star',
32
- title: 'Model → UI',
33
- caption: 'Behavior is defined once; the interface is its projection — structure, copy, and state attributes in agreement.',
34
- source: aeonNorthStarDiagram,
35
- },
36
- {
37
- id: 'async',
38
- title: 'Async region',
39
- caption: 'A named lifecycle teams can reason about together — not an unnamed spinner behind a boolean.',
40
- source: asyncLifecycleDiagram,
41
- },
42
- ]
@@ -1,16 +0,0 @@
1
- @import './landing.css';
2
- @import './demo-layout.css';
3
-
4
- html {
5
- scroll-behavior: smooth;
6
- }
7
-
8
- @media (prefers-reduced-motion: reduce) {
9
- html {
10
- scroll-behavior: auto;
11
- }
12
- }
13
-
14
- a {
15
- color: inherit;
16
- }
@@ -1,20 +0,0 @@
1
- import { Button, cn } from '@aeon-ui/ui'
2
- import type { ReactNode } from 'react'
3
-
4
- export interface ActionClusterProps {
5
- children: ReactNode
6
- className?: string
7
- }
8
-
9
- /** Machine console actions — spaced buttons by default. */
10
- export function ActionCluster({ children, className }: ActionClusterProps) {
11
- return (
12
- <Button.Group
13
- className={cn('machine-console__actions', className)}
14
- data-aeon-scope="machine"
15
- data-aeon-part="actions"
16
- >
17
- {children}
18
- </Button.Group>
19
- )
20
- }
@@ -1,97 +0,0 @@
1
- import { useAsyncContext } from '@aeon-ui/react'
2
- import { Async, Button } from '@aeon-ui/ui'
3
- import { ActionCluster } from './ActionCluster.js'
4
-
5
- export interface AsyncMachineDemoProps {
6
- /** Playground shows failure and empty paths; hero always succeeds for a crisp preview. */
7
- variant?: 'hero' | 'playground'
8
- }
9
-
10
- const readouts: Record<string, Record<'hero' | 'playground', string>> = {
11
- idle: {
12
- hero: 'Idle — ready to fetch',
13
- playground: 'Idle — press Simulate fetch when ready',
14
- },
15
- loading: {
16
- hero: 'Loading…',
17
- playground: 'Loading…',
18
- },
19
- success: {
20
- hero: 'Success',
21
- playground: 'Success — data on context',
22
- },
23
- failure: {
24
- hero: 'Failure',
25
- playground: 'Failure — error on context',
26
- },
27
- empty: {
28
- hero: 'Empty',
29
- playground: 'Empty — resolved with no rows',
30
- },
31
- }
32
-
33
- function AsyncMachineControls({ variant }: { variant: 'hero' | 'playground' }) {
34
- const { status, send } = useAsyncContext()
35
- const runFetch = () => {
36
- send({ type: 'FETCH' })
37
- const delay = variant === 'hero' ? 700 : 900
38
- setTimeout(() => {
39
- if (variant === 'hero') {
40
- send({ type: 'RESOLVE', data: 'Payload OK' })
41
- return
42
- }
43
- const roll = Math.random()
44
- if (roll < 0.25) {
45
- send({ type: 'REJECT', error: 'Network unreachable' })
46
- } else if (roll < 0.4) {
47
- send({ type: 'RESOLVE', data: [] })
48
- } else {
49
- send({ type: 'RESOLVE', data: 'Aeon payload received' })
50
- }
51
- }, delay)
52
- }
53
-
54
- return (
55
- <ActionCluster className="machine-console__actions">
56
- <Button.Root size="sm" onClick={runFetch} disabled={status === 'loading'}>
57
- {variant === 'hero' ? 'Run' : 'Simulate fetch'}
58
- </Button.Root>
59
- <Button.Root size="sm" variant="outline" onClick={() => send({ type: 'RESET' })}>
60
- Reset
61
- </Button.Root>
62
- {variant === 'playground' && status === 'success' && (
63
- <Button.Root size="sm" variant="ghost" onClick={() => send({ type: 'STALE' })}>
64
- Mark stale
65
- </Button.Root>
66
- )}
67
- </ActionCluster>
68
- )
69
- }
70
-
71
- function AsyncMachineReadout({ variant }: { variant: 'hero' | 'playground' }) {
72
- const { status, data, error, stale } = useAsyncContext()
73
- const readout =
74
- status === 'success'
75
- ? String(data ?? (variant === 'hero' ? 'Payload OK' : 'Aeon payload received'))
76
- : status === 'failure'
77
- ? String(error ?? 'Network unreachable')
78
- : (readouts[status]?.[variant] ?? readouts.idle[variant])
79
-
80
- return (
81
- <p className="live-status__text">
82
- {stale && status === 'success' ? `${readout} (stale — refresh recommended)` : readout}
83
- </p>
84
- )
85
- }
86
-
87
- export function AsyncMachineDemo({ variant = 'playground' }: AsyncMachineDemoProps) {
88
- return (
89
- <Async.Root data-aeon-scope="machine" data-aeon-part="console">
90
- <Async.Track />
91
- <Async.Readout>
92
- <AsyncMachineReadout variant={variant} />
93
- </Async.Readout>
94
- <AsyncMachineControls variant={variant} />
95
- </Async.Root>
96
- )
97
- }