aeon-ui-engine 1.0.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.
Files changed (430) hide show
  1. package/.changeset/README.md +23 -0
  2. package/.changeset/combobox-and-changesets.md +9 -0
  3. package/.changeset/config.json +30 -0
  4. package/.changeset/framework-adapters.md +12 -0
  5. package/.changeset/scene-3d.md +6 -0
  6. package/.changeset/scene-plane.md +8 -0
  7. package/.changeset/site-og.md +5 -0
  8. package/.cursor/rules/aeon-ui.mdc +22 -0
  9. package/ACCESSIBILITY.md +32 -0
  10. package/AGENTS.md +226 -0
  11. package/COMPONENTS.md +36 -0
  12. package/FRAMEWORKS.md +57 -0
  13. package/INTEGRATION.md +89 -0
  14. package/LICENSE +21 -0
  15. package/PHILOSOPHY.md +71 -0
  16. package/PUBLISHING.md +85 -0
  17. package/README.md +154 -0
  18. package/SCENE.md +113 -0
  19. package/STATES.md +243 -0
  20. package/apps/demo/index.html +31 -0
  21. package/apps/demo/og.config.mjs +15 -0
  22. package/apps/demo/package.json +41 -0
  23. package/apps/demo/public/favicon.svg +16 -0
  24. package/apps/demo/public/og.png +0 -0
  25. package/apps/demo/public/og.svg +35 -0
  26. package/apps/demo/scripts/generate-og-png.mjs +60 -0
  27. package/apps/demo/src/App.tsx +31 -0
  28. package/apps/demo/src/aeonDiagrams.ts +100 -0
  29. package/apps/demo/src/app.css +16 -0
  30. package/apps/demo/src/components/ActionCluster.tsx +20 -0
  31. package/apps/demo/src/components/AsyncMachineDemo.tsx +97 -0
  32. package/apps/demo/src/components/ButtonLifecycleDemo.tsx +63 -0
  33. package/apps/demo/src/components/CodeExample.tsx +7 -0
  34. package/apps/demo/src/components/ComboboxDemo.tsx +30 -0
  35. package/apps/demo/src/components/DiagramsSection.tsx +38 -0
  36. package/apps/demo/src/components/FieldStateDemo.tsx +51 -0
  37. package/apps/demo/src/components/GridMesh.tsx +8 -0
  38. package/apps/demo/src/components/HeroInstall.tsx +10 -0
  39. package/apps/demo/src/components/LandingFaq.tsx +29 -0
  40. package/apps/demo/src/components/LandingFooter.tsx +22 -0
  41. package/apps/demo/src/components/LandingHeader.tsx +60 -0
  42. package/apps/demo/src/components/LandingHero.tsx +55 -0
  43. package/apps/demo/src/components/LayersSection.tsx +51 -0
  44. package/apps/demo/src/components/MermaidDiagram.tsx +84 -0
  45. package/apps/demo/src/components/PhilosophySection.tsx +33 -0
  46. package/apps/demo/src/components/PlaygroundBlock.tsx +23 -0
  47. package/apps/demo/src/components/PlaygroundSection.tsx +204 -0
  48. package/apps/demo/src/components/SceneSection.tsx +157 -0
  49. package/apps/demo/src/components/ScrollRegionDemo.tsx +74 -0
  50. package/apps/demo/src/components/ThemeSwitcher.tsx +76 -0
  51. package/apps/demo/src/demo-layout.css +264 -0
  52. package/apps/demo/src/landing.css +1094 -0
  53. package/apps/demo/src/main.tsx +14 -0
  54. package/apps/demo/src/nav.ts +9 -0
  55. package/apps/demo/src/site.ts +347 -0
  56. package/apps/demo/tsconfig.json +17 -0
  57. package/apps/demo/vite-plugins/og-meta.ts +30 -0
  58. package/apps/demo/vite.config.ts +69 -0
  59. package/docs/API_PATTERNS.md +234 -0
  60. package/docs/ARCHITECTURE.md +125 -0
  61. package/docs/COMPONENT_CHECKLIST.md +103 -0
  62. package/docs/FILE_MAP.md +122 -0
  63. package/docs/GLOSSARY.md +125 -0
  64. package/docs/INDEX.md +53 -0
  65. package/docs/LAYOUT_COORDINATES.md +178 -0
  66. package/docs/MACHINES.md +166 -0
  67. package/docs/MIGRATION_FROM_ARK.md +295 -0
  68. package/docs/VITE_CONSUMER.md +114 -0
  69. package/package.json +25 -0
  70. package/packages/core/README.md +69 -0
  71. package/packages/core/package.json +37 -0
  72. package/packages/core/src/anatomy.ts +144 -0
  73. package/packages/core/src/attrs.ts +47 -0
  74. package/packages/core/src/index.ts +8 -0
  75. package/packages/core/src/layout.ts +176 -0
  76. package/packages/core/src/machine.test.ts +18 -0
  77. package/packages/core/src/machine.ts +15 -0
  78. package/packages/core/src/philosophy.ts +10 -0
  79. package/packages/core/src/scroll.ts +72 -0
  80. package/packages/core/src/theme.test.ts +14 -0
  81. package/packages/core/src/theme.ts +53 -0
  82. package/packages/core/src/types.ts +25 -0
  83. package/packages/core/theme-transition.css +58 -0
  84. package/packages/core/tsconfig.json +8 -0
  85. package/packages/core/vitest.config.ts +8 -0
  86. package/packages/geometry/README.md +7 -0
  87. package/packages/geometry/package.json +35 -0
  88. package/packages/geometry/src/index.ts +3 -0
  89. package/packages/geometry/src/patterns.ts +55 -0
  90. package/packages/geometry/src/scene-attrs.ts +11 -0
  91. package/packages/geometry/src/svg.ts +60 -0
  92. package/packages/geometry/tsconfig.json +8 -0
  93. package/packages/panda/README.md +66 -0
  94. package/packages/panda/package.json +40 -0
  95. package/packages/panda/panda.config.ts +229 -0
  96. package/packages/panda/scripts/emit-theme-runtime.ts +37 -0
  97. package/packages/panda/src/recipes/accordion.ts +95 -0
  98. package/packages/panda/src/recipes/async.ts +76 -0
  99. package/packages/panda/src/recipes/badge.ts +44 -0
  100. package/packages/panda/src/recipes/button-group.ts +33 -0
  101. package/packages/panda/src/recipes/button.ts +91 -0
  102. package/packages/panda/src/recipes/checkbox.ts +41 -0
  103. package/packages/panda/src/recipes/combobox.ts +121 -0
  104. package/packages/panda/src/recipes/dialog.ts +96 -0
  105. package/packages/panda/src/recipes/field-shared.ts +29 -0
  106. package/packages/panda/src/recipes/field.ts +72 -0
  107. package/packages/panda/src/recipes/floating.ts +170 -0
  108. package/packages/panda/src/recipes/index.ts +14 -0
  109. package/packages/panda/src/recipes/scroll-region.ts +55 -0
  110. package/packages/panda/src/recipes/select.ts +111 -0
  111. package/packages/panda/src/recipes/switch.ts +51 -0
  112. package/packages/panda/src/recipes/tabs.ts +50 -0
  113. package/packages/panda/src/theme/catalog-types.ts +24 -0
  114. package/packages/panda/src/theme/catalog.ts +73 -0
  115. package/packages/panda/src/theme/chrome.css +75 -0
  116. package/packages/panda/src/theme/global-theme-css.ts +42 -0
  117. package/packages/panda/src/theme/index.ts +5 -0
  118. package/packages/panda/src/theme/palette.ts +65 -0
  119. package/packages/panda/src/theme/scrollbars.css +96 -0
  120. package/packages/panda/src/theme/semantic-tokens.ts +17 -0
  121. package/packages/panda/src/theme/themes.config.ts +516 -0
  122. package/packages/panda/src/theme/tokens.ts +51 -0
  123. package/packages/panda/styled-system/css/conditions.mjs +36 -0
  124. package/packages/panda/styled-system/css/css.d.ts +22 -0
  125. package/packages/panda/styled-system/css/css.mjs +45 -0
  126. package/packages/panda/styled-system/css/cva.d.ts +6 -0
  127. package/packages/panda/styled-system/css/cva.mjs +87 -0
  128. package/packages/panda/styled-system/css/cx.d.ts +5 -0
  129. package/packages/panda/styled-system/css/cx.mjs +15 -0
  130. package/packages/panda/styled-system/css/index.d.ts +5 -0
  131. package/packages/panda/styled-system/css/index.mjs +4 -0
  132. package/packages/panda/styled-system/css/sva.d.ts +4 -0
  133. package/packages/panda/styled-system/css/sva.mjs +41 -0
  134. package/packages/panda/styled-system/helpers.mjs +339 -0
  135. package/packages/panda/styled-system/jsx/aspect-ratio.d.ts +10 -0
  136. package/packages/panda/styled-system/jsx/aspect-ratio.mjs +14 -0
  137. package/packages/panda/styled-system/jsx/bleed.d.ts +10 -0
  138. package/packages/panda/styled-system/jsx/bleed.mjs +14 -0
  139. package/packages/panda/styled-system/jsx/box.d.ts +10 -0
  140. package/packages/panda/styled-system/jsx/box.mjs +14 -0
  141. package/packages/panda/styled-system/jsx/center.d.ts +10 -0
  142. package/packages/panda/styled-system/jsx/center.mjs +14 -0
  143. package/packages/panda/styled-system/jsx/circle.d.ts +10 -0
  144. package/packages/panda/styled-system/jsx/circle.mjs +14 -0
  145. package/packages/panda/styled-system/jsx/container.d.ts +10 -0
  146. package/packages/panda/styled-system/jsx/container.mjs +14 -0
  147. package/packages/panda/styled-system/jsx/cq.d.ts +10 -0
  148. package/packages/panda/styled-system/jsx/cq.mjs +14 -0
  149. package/packages/panda/styled-system/jsx/divider.d.ts +10 -0
  150. package/packages/panda/styled-system/jsx/divider.mjs +14 -0
  151. package/packages/panda/styled-system/jsx/factory-helper.mjs +22 -0
  152. package/packages/panda/styled-system/jsx/factory.d.ts +3 -0
  153. package/packages/panda/styled-system/jsx/factory.mjs +80 -0
  154. package/packages/panda/styled-system/jsx/flex.d.ts +10 -0
  155. package/packages/panda/styled-system/jsx/flex.mjs +14 -0
  156. package/packages/panda/styled-system/jsx/float.d.ts +10 -0
  157. package/packages/panda/styled-system/jsx/float.mjs +14 -0
  158. package/packages/panda/styled-system/jsx/grid-item.d.ts +10 -0
  159. package/packages/panda/styled-system/jsx/grid-item.mjs +14 -0
  160. package/packages/panda/styled-system/jsx/grid.d.ts +10 -0
  161. package/packages/panda/styled-system/jsx/grid.mjs +14 -0
  162. package/packages/panda/styled-system/jsx/hstack.d.ts +10 -0
  163. package/packages/panda/styled-system/jsx/hstack.mjs +14 -0
  164. package/packages/panda/styled-system/jsx/index.d.ts +24 -0
  165. package/packages/panda/styled-system/jsx/index.mjs +22 -0
  166. package/packages/panda/styled-system/jsx/is-valid-prop.d.ts +11 -0
  167. package/packages/panda/styled-system/jsx/is-valid-prop.mjs +17 -0
  168. package/packages/panda/styled-system/jsx/link-overlay.d.ts +10 -0
  169. package/packages/panda/styled-system/jsx/link-overlay.mjs +14 -0
  170. package/packages/panda/styled-system/jsx/spacer.d.ts +10 -0
  171. package/packages/panda/styled-system/jsx/spacer.mjs +14 -0
  172. package/packages/panda/styled-system/jsx/square.d.ts +10 -0
  173. package/packages/panda/styled-system/jsx/square.mjs +14 -0
  174. package/packages/panda/styled-system/jsx/stack.d.ts +10 -0
  175. package/packages/panda/styled-system/jsx/stack.mjs +14 -0
  176. package/packages/panda/styled-system/jsx/visually-hidden.d.ts +10 -0
  177. package/packages/panda/styled-system/jsx/visually-hidden.mjs +14 -0
  178. package/packages/panda/styled-system/jsx/vstack.d.ts +10 -0
  179. package/packages/panda/styled-system/jsx/vstack.mjs +14 -0
  180. package/packages/panda/styled-system/jsx/wrap.d.ts +10 -0
  181. package/packages/panda/styled-system/jsx/wrap.mjs +14 -0
  182. package/packages/panda/styled-system/patterns/aspect-ratio.d.ts +21 -0
  183. package/packages/panda/styled-system/patterns/aspect-ratio.mjs +38 -0
  184. package/packages/panda/styled-system/patterns/bleed.d.ts +22 -0
  185. package/packages/panda/styled-system/patterns/bleed.mjs +24 -0
  186. package/packages/panda/styled-system/patterns/box.d.ts +21 -0
  187. package/packages/panda/styled-system/patterns/box.mjs +15 -0
  188. package/packages/panda/styled-system/patterns/center.d.ts +21 -0
  189. package/packages/panda/styled-system/patterns/center.mjs +21 -0
  190. package/packages/panda/styled-system/patterns/circle.d.ts +21 -0
  191. package/packages/panda/styled-system/patterns/circle.mjs +25 -0
  192. package/packages/panda/styled-system/patterns/container.d.ts +21 -0
  193. package/packages/panda/styled-system/patterns/container.mjs +21 -0
  194. package/packages/panda/styled-system/patterns/cq.d.ts +22 -0
  195. package/packages/panda/styled-system/patterns/cq.mjs +21 -0
  196. package/packages/panda/styled-system/patterns/divider.d.ts +23 -0
  197. package/packages/panda/styled-system/patterns/divider.mjs +25 -0
  198. package/packages/panda/styled-system/patterns/flex.d.ts +27 -0
  199. package/packages/panda/styled-system/patterns/flex.mjs +26 -0
  200. package/packages/panda/styled-system/patterns/float.d.ts +24 -0
  201. package/packages/panda/styled-system/patterns/float.mjs +52 -0
  202. package/packages/panda/styled-system/patterns/grid-item.d.ts +26 -0
  203. package/packages/panda/styled-system/patterns/grid-item.mjs +25 -0
  204. package/packages/panda/styled-system/patterns/grid.d.ts +25 -0
  205. package/packages/panda/styled-system/patterns/grid.mjs +27 -0
  206. package/packages/panda/styled-system/patterns/hstack.d.ts +22 -0
  207. package/packages/panda/styled-system/patterns/hstack.mjs +24 -0
  208. package/packages/panda/styled-system/patterns/index.d.ts +21 -0
  209. package/packages/panda/styled-system/patterns/index.mjs +20 -0
  210. package/packages/panda/styled-system/patterns/link-overlay.d.ts +21 -0
  211. package/packages/panda/styled-system/patterns/link-overlay.mjs +24 -0
  212. package/packages/panda/styled-system/patterns/spacer.d.ts +21 -0
  213. package/packages/panda/styled-system/patterns/spacer.mjs +21 -0
  214. package/packages/panda/styled-system/patterns/square.d.ts +21 -0
  215. package/packages/panda/styled-system/patterns/square.mjs +24 -0
  216. package/packages/panda/styled-system/patterns/stack.d.ts +24 -0
  217. package/packages/panda/styled-system/patterns/stack.mjs +24 -0
  218. package/packages/panda/styled-system/patterns/visually-hidden.d.ts +21 -0
  219. package/packages/panda/styled-system/patterns/visually-hidden.mjs +18 -0
  220. package/packages/panda/styled-system/patterns/vstack.d.ts +22 -0
  221. package/packages/panda/styled-system/patterns/vstack.mjs +24 -0
  222. package/packages/panda/styled-system/patterns/wrap.d.ts +25 -0
  223. package/packages/panda/styled-system/patterns/wrap.mjs +25 -0
  224. package/packages/panda/styled-system/recipes/aeon-accordion.d.ts +32 -0
  225. package/packages/panda/styled-system/recipes/aeon-accordion.mjs +48 -0
  226. package/packages/panda/styled-system/recipes/aeon-async.d.ts +32 -0
  227. package/packages/panda/styled-system/recipes/aeon-async.mjs +56 -0
  228. package/packages/panda/styled-system/recipes/aeon-badge.d.ts +31 -0
  229. package/packages/panda/styled-system/recipes/aeon-badge.mjs +32 -0
  230. package/packages/panda/styled-system/recipes/aeon-button-group.d.ts +39 -0
  231. package/packages/panda/styled-system/recipes/aeon-button-group.mjs +37 -0
  232. package/packages/panda/styled-system/recipes/aeon-button.d.ts +39 -0
  233. package/packages/panda/styled-system/recipes/aeon-button.mjs +39 -0
  234. package/packages/panda/styled-system/recipes/aeon-checkbox.d.ts +28 -0
  235. package/packages/panda/styled-system/recipes/aeon-checkbox.mjs +48 -0
  236. package/packages/panda/styled-system/recipes/aeon-combobox.d.ts +32 -0
  237. package/packages/panda/styled-system/recipes/aeon-combobox.mjs +52 -0
  238. package/packages/panda/styled-system/recipes/aeon-dialog.d.ts +28 -0
  239. package/packages/panda/styled-system/recipes/aeon-dialog.mjs +60 -0
  240. package/packages/panda/styled-system/recipes/aeon-field.d.ts +32 -0
  241. package/packages/panda/styled-system/recipes/aeon-field.mjs +52 -0
  242. package/packages/panda/styled-system/recipes/aeon-menu.d.ts +28 -0
  243. package/packages/panda/styled-system/recipes/aeon-menu.mjs +52 -0
  244. package/packages/panda/styled-system/recipes/aeon-popover.d.ts +28 -0
  245. package/packages/panda/styled-system/recipes/aeon-popover.mjs +52 -0
  246. package/packages/panda/styled-system/recipes/aeon-scroll.d.ts +43 -0
  247. package/packages/panda/styled-system/recipes/aeon-scroll.mjs +63 -0
  248. package/packages/panda/styled-system/recipes/aeon-select.d.ts +32 -0
  249. package/packages/panda/styled-system/recipes/aeon-select.mjs +56 -0
  250. package/packages/panda/styled-system/recipes/aeon-switch.d.ts +28 -0
  251. package/packages/panda/styled-system/recipes/aeon-switch.mjs +48 -0
  252. package/packages/panda/styled-system/recipes/aeon-tabs.d.ts +28 -0
  253. package/packages/panda/styled-system/recipes/aeon-tabs.mjs +48 -0
  254. package/packages/panda/styled-system/recipes/aeon-toast.d.ts +28 -0
  255. package/packages/panda/styled-system/recipes/aeon-toast.mjs +48 -0
  256. package/packages/panda/styled-system/recipes/aeon-tooltip.d.ts +28 -0
  257. package/packages/panda/styled-system/recipes/aeon-tooltip.mjs +48 -0
  258. package/packages/panda/styled-system/recipes/create-recipe.mjs +82 -0
  259. package/packages/panda/styled-system/recipes/index.d.ts +18 -0
  260. package/packages/panda/styled-system/recipes/index.mjs +17 -0
  261. package/packages/panda/styled-system/styles.css +2157 -0
  262. package/packages/panda/styled-system/tokens/index.d.ts +9 -0
  263. package/packages/panda/styled-system/tokens/index.mjs +2156 -0
  264. package/packages/panda/styled-system/tokens/tokens.d.ts +60 -0
  265. package/packages/panda/styled-system/types/composition.d.ts +164 -0
  266. package/packages/panda/styled-system/types/conditions.d.ts +322 -0
  267. package/packages/panda/styled-system/types/csstype.d.ts +21298 -0
  268. package/packages/panda/styled-system/types/global.d.ts +20 -0
  269. package/packages/panda/styled-system/types/index.d.ts +8 -0
  270. package/packages/panda/styled-system/types/jsx.d.ts +52 -0
  271. package/packages/panda/styled-system/types/parts.d.ts +8 -0
  272. package/packages/panda/styled-system/types/pattern.d.ts +78 -0
  273. package/packages/panda/styled-system/types/prop-type.d.ts +240 -0
  274. package/packages/panda/styled-system/types/recipe.d.ts +181 -0
  275. package/packages/panda/styled-system/types/selectors.d.ts +59 -0
  276. package/packages/panda/styled-system/types/static-css.d.ts +56 -0
  277. package/packages/panda/styled-system/types/style-props.d.ts +7491 -0
  278. package/packages/panda/styled-system/types/system-types.d.ts +193 -0
  279. package/packages/panda/theme-runtime.css +842 -0
  280. package/packages/panda/tsconfig.json +8 -0
  281. package/packages/primitives/README.md +54 -0
  282. package/packages/primitives/package.json +41 -0
  283. package/packages/primitives/src/__tests__/floating-surface.test.ts +29 -0
  284. package/packages/primitives/src/index.ts +9 -0
  285. package/packages/primitives/src/machines/accordion.ts +56 -0
  286. package/packages/primitives/src/machines/async.ts +108 -0
  287. package/packages/primitives/src/machines/button.ts +66 -0
  288. package/packages/primitives/src/machines/dialog.ts +61 -0
  289. package/packages/primitives/src/machines/field.ts +85 -0
  290. package/packages/primitives/src/machines/popover.ts +52 -0
  291. package/packages/primitives/src/machines/tabs.ts +46 -0
  292. package/packages/primitives/src/machines/toast.ts +48 -0
  293. package/packages/primitives/src/machines/toggle.ts +61 -0
  294. package/packages/primitives/tsconfig.json +8 -0
  295. package/packages/primitives/vitest.config.ts +8 -0
  296. package/packages/react/README.md +65 -0
  297. package/packages/react/package.json +52 -0
  298. package/packages/react/src/accordion/index.tsx +179 -0
  299. package/packages/react/src/async/actions.tsx +22 -0
  300. package/packages/react/src/async/context.tsx +54 -0
  301. package/packages/react/src/async/index.tsx +21 -0
  302. package/packages/react/src/async/legacy-region.tsx +38 -0
  303. package/packages/react/src/async/readout.tsx +34 -0
  304. package/packages/react/src/async/root.tsx +39 -0
  305. package/packages/react/src/async/track.tsx +59 -0
  306. package/packages/react/src/avatar/avatar.test.tsx +27 -0
  307. package/packages/react/src/avatar/index.tsx +122 -0
  308. package/packages/react/src/button/index.tsx +70 -0
  309. package/packages/react/src/checkbox/index.tsx +180 -0
  310. package/packages/react/src/combobox/index.tsx +430 -0
  311. package/packages/react/src/dialog/dialog.test.tsx +50 -0
  312. package/packages/react/src/dialog/index.tsx +275 -0
  313. package/packages/react/src/field/index.tsx +172 -0
  314. package/packages/react/src/hooks/use-aeon-machine.ts +10 -0
  315. package/packages/react/src/hooks/use-anchor-position.ts +33 -0
  316. package/packages/react/src/hooks/use-focus-trap.ts +51 -0
  317. package/packages/react/src/hooks/use-layout-mode.ts +22 -0
  318. package/packages/react/src/hooks/use-outside-click.ts +19 -0
  319. package/packages/react/src/hooks/use-portalled.ts +16 -0
  320. package/packages/react/src/hooks/use-scroll-lock.ts +13 -0
  321. package/packages/react/src/index.ts +18 -0
  322. package/packages/react/src/menu/index.tsx +195 -0
  323. package/packages/react/src/popover/index.tsx +191 -0
  324. package/packages/react/src/scroll/index.tsx +98 -0
  325. package/packages/react/src/scroll/use-scroll-state.ts +30 -0
  326. package/packages/react/src/select/index.tsx +372 -0
  327. package/packages/react/src/select/select.test.tsx +60 -0
  328. package/packages/react/src/switch/index.tsx +215 -0
  329. package/packages/react/src/tabs/index.tsx +140 -0
  330. package/packages/react/src/toast/context.tsx +28 -0
  331. package/packages/react/src/toast/index.tsx +20 -0
  332. package/packages/react/src/toast/primitives.tsx +129 -0
  333. package/packages/react/src/toast/provider.tsx +111 -0
  334. package/packages/react/src/toast/toast-item.tsx +32 -0
  335. package/packages/react/src/tooltip/index.tsx +191 -0
  336. package/packages/react/src/utils/merge-props.ts +24 -0
  337. package/packages/react/tsconfig.json +8 -0
  338. package/packages/react/vitest.config.ts +9 -0
  339. package/packages/react/vitest.setup.ts +5 -0
  340. package/packages/react-scene/README.md +11 -0
  341. package/packages/react-scene/package.json +47 -0
  342. package/packages/react-scene/scene-3d.css +37 -0
  343. package/packages/react-scene/scene-room.css +95 -0
  344. package/packages/react-scene/src/index.ts +20 -0
  345. package/packages/react-scene/src/procedural-grid.tsx +35 -0
  346. package/packages/react-scene/src/scene-layer.tsx +38 -0
  347. package/packages/react-scene/src/scene-plane.tsx +69 -0
  348. package/packages/react-scene/src/scene-room.tsx +81 -0
  349. package/packages/react-scene/src/scene-root.tsx +49 -0
  350. package/packages/react-scene/src/scene-slot.tsx +41 -0
  351. package/packages/react-scene/src/scene-stage.tsx +37 -0
  352. package/packages/react-scene/src/scene-surface.tsx +20 -0
  353. package/packages/react-scene/src/signal-bars.tsx +57 -0
  354. package/packages/react-scene/src/use-signal-visualizer.ts +103 -0
  355. package/packages/react-scene/tsconfig.json +8 -0
  356. package/packages/scene/README.md +5 -0
  357. package/packages/scene/package.json +32 -0
  358. package/packages/scene/src/index.ts +2 -0
  359. package/packages/scene/src/room.ts +40 -0
  360. package/packages/scene/src/transform.ts +60 -0
  361. package/packages/scene/tsconfig.json +8 -0
  362. package/packages/signal/README.md +9 -0
  363. package/packages/signal/package.json +32 -0
  364. package/packages/signal/src/analyser.ts +113 -0
  365. package/packages/signal/src/bands.ts +33 -0
  366. package/packages/signal/src/index.ts +3 -0
  367. package/packages/signal/src/motion.ts +80 -0
  368. package/packages/signal/tsconfig.json +8 -0
  369. package/packages/site/README.md +19 -0
  370. package/packages/site/package.json +32 -0
  371. package/packages/site/src/index.ts +8 -0
  372. package/packages/site/src/open-graph.ts +90 -0
  373. package/packages/site/tsconfig.json +8 -0
  374. package/packages/solid/README.md +30 -0
  375. package/packages/solid/package.json +42 -0
  376. package/packages/solid/src/hooks/use-aeon-machine.ts +10 -0
  377. package/packages/solid/src/index.ts +2 -0
  378. package/packages/solid/src/switch/index.tsx +191 -0
  379. package/packages/solid/src/utils/merge-props.ts +3 -0
  380. package/packages/solid/tsconfig.json +10 -0
  381. package/packages/surface/README.md +10 -0
  382. package/packages/surface/package.json +33 -0
  383. package/packages/surface/src/index.ts +1 -0
  384. package/packages/surface/src/materials.ts +14 -0
  385. package/packages/surface/surface.css +113 -0
  386. package/packages/surface/tsconfig.json +8 -0
  387. package/packages/svelte/README.md +45 -0
  388. package/packages/svelte/package.json +49 -0
  389. package/packages/svelte/src/Switch.svelte +86 -0
  390. package/packages/svelte/src/SwitchControl.svelte +45 -0
  391. package/packages/svelte/src/SwitchHiddenInput.svelte +12 -0
  392. package/packages/svelte/src/SwitchLabel.svelte +9 -0
  393. package/packages/svelte/src/SwitchThumb.svelte +16 -0
  394. package/packages/svelte/src/hooks/use-aeon-machine.ts +23 -0
  395. package/packages/svelte/src/index.ts +2 -0
  396. package/packages/svelte/src/switch-context.ts +13 -0
  397. package/packages/svelte/tsconfig.json +8 -0
  398. package/packages/ui/README.md +63 -0
  399. package/packages/ui/package.json +45 -0
  400. package/packages/ui/src/accordion.tsx +27 -0
  401. package/packages/ui/src/async.tsx +43 -0
  402. package/packages/ui/src/badge.tsx +18 -0
  403. package/packages/ui/src/button.tsx +38 -0
  404. package/packages/ui/src/checkbox.tsx +24 -0
  405. package/packages/ui/src/cn.ts +1 -0
  406. package/packages/ui/src/combobox.tsx +29 -0
  407. package/packages/ui/src/dialog.tsx +32 -0
  408. package/packages/ui/src/field.tsx +33 -0
  409. package/packages/ui/src/index.ts +17 -0
  410. package/packages/ui/src/menu.tsx +25 -0
  411. package/packages/ui/src/popover.tsx +22 -0
  412. package/packages/ui/src/scroll.tsx +51 -0
  413. package/packages/ui/src/select.tsx +33 -0
  414. package/packages/ui/src/styles.css +2 -0
  415. package/packages/ui/src/switch.tsx +22 -0
  416. package/packages/ui/src/tabs.tsx +22 -0
  417. package/packages/ui/src/toast.tsx +36 -0
  418. package/packages/ui/src/tooltip.tsx +19 -0
  419. package/packages/ui/tsconfig.json +12 -0
  420. package/packages/vue/README.md +40 -0
  421. package/packages/vue/package.json +42 -0
  422. package/packages/vue/src/hooks/use-aeon-machine.ts +10 -0
  423. package/packages/vue/src/index.ts +2 -0
  424. package/packages/vue/src/switch/index.ts +208 -0
  425. package/packages/vue/src/utils/part-props.ts +8 -0
  426. package/packages/vue/tsconfig.json +8 -0
  427. package/pnpm-workspace.yaml +3 -0
  428. package/scripts/ensure-headless-built.mjs +25 -0
  429. package/tsconfig.base.json +21 -0
  430. package/vercel.json +12 -0
@@ -0,0 +1,114 @@
1
+ # Vite apps (headless, no Panda)
2
+
3
+ Use this for marketing sites and HandCash apps that keep their own CSS and only need `@aeon-ui/react`.
4
+
5
+ ## 1. Install runtime deps
6
+
7
+ ```bash
8
+ npm install @xstate/react xstate
9
+ ```
10
+
11
+ After `@aeon-ui/*` is on npm, also:
12
+
13
+ ```bash
14
+ npm install @aeon-ui/react @aeon-ui/core @aeon-ui/primitives
15
+ ```
16
+
17
+ Until publish, point Vite at a local clone (see below).
18
+
19
+ ## 2. Ensure packages are built
20
+
21
+ From the Aeon UI repo:
22
+
23
+ ```bash
24
+ pnpm run build:headless
25
+ ```
26
+
27
+ Or from any consumer `package.json`:
28
+
29
+ ```json
30
+ {
31
+ "scripts": {
32
+ "aeon:ensure": "node ../path/to/AeonUI/scripts/ensure-headless-built.mjs",
33
+ "prebuild": "npm run aeon:ensure && vite build"
34
+ }
35
+ }
36
+ ```
37
+
38
+ Set `AEON_UI_ROOT` in CI when the monorepo is not at `~/AeonUI`.
39
+
40
+ ## 3. Vite aliases (local clone)
41
+
42
+ ```ts
43
+ import path from 'node:path'
44
+ import { fileURLToPath } from 'node:url'
45
+
46
+ const root = path.dirname(fileURLToPath(import.meta.url))
47
+ const aeonRoot = process.env.AEON_UI_ROOT ?? path.resolve(root, '../../../AeonUI')
48
+
49
+ export default defineConfig({
50
+ resolve: {
51
+ alias: {
52
+ '@aeon-ui/core': path.join(aeonRoot, 'packages/core/dist/index.js'),
53
+ '@aeon-ui/primitives': path.join(aeonRoot, 'packages/primitives/dist/index.js'),
54
+ '@aeon-ui/react': path.join(aeonRoot, 'packages/react/dist/index.js'),
55
+ },
56
+ },
57
+ optimizeDeps: {
58
+ include: ['@aeon-ui/react', '@aeon-ui/core', '@aeon-ui/primitives', 'xstate', '@xstate/react'],
59
+ },
60
+ })
61
+ ```
62
+
63
+ Adjust `../../../AeonUI` to your layout.
64
+
65
+ ## 4. TypeScript paths
66
+
67
+ ```json
68
+ {
69
+ "compilerOptions": {
70
+ "paths": {
71
+ "@aeon-ui/core": ["../../../AeonUI/packages/core/dist/index.d.ts"],
72
+ "@aeon-ui/primitives": ["../../../AeonUI/packages/primitives/dist/index.d.ts"],
73
+ "@aeon-ui/react": ["../../../AeonUI/packages/react/dist/index.d.ts"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## 5. Style with data-aeon-*
80
+
81
+ ```css
82
+ [data-aeon-scope='field'][data-aeon-part='control'],
83
+ [data-aeon-scope='field'][data-aeon-part='textarea'] {
84
+ /* shared input styles */
85
+ }
86
+ ```
87
+
88
+ See [INTEGRATION.md](../INTEGRATION.md) and [STATES.md](../STATES.md).
89
+
90
+ ## 6. Toasts
91
+
92
+ Wrap the app (or layout) once:
93
+
94
+ ```tsx
95
+ import { Toast } from '@aeon-ui/react'
96
+
97
+ <Toast.Provider>
98
+ <App />
99
+ <Toast.Viewport placement="bottom-end" />
100
+ </Toast.Provider>
101
+ ```
102
+
103
+ Publish from anywhere under the tree:
104
+
105
+ ```tsx
106
+ const { publish } = useToast()
107
+ publish({ title: 'Saved', description: 'Changes are live.' })
108
+ ```
109
+
110
+ ## 7. Migrating from Ark UI
111
+
112
+ Full guide: **[MIGRATION_FROM_ARK.md](./MIGRATION_FROM_ARK.md)** (inventory, Next.js, Select/Dialog/Toast/Avatar, CSS selectors, verification).
113
+
114
+ Reference consumers: **spidercorp.xyz** (Vite), **soundbase.click** (Next.js).
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "aeon-ui-engine",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "scripts": {
6
+ "build": "pnpm --filter @aeon-ui/panda run codegen && pnpm -r run build",
7
+ "build:headless": "pnpm --filter @aeon-ui/core --filter @aeon-ui/primitives --filter @aeon-ui/react run build",
8
+ "codegen": "pnpm --filter @aeon-ui/panda codegen",
9
+ "dev": "pnpm --filter @aeon-ui/demo dev",
10
+ "typecheck": "pnpm -r run typecheck",
11
+ "test": "pnpm run test:headless",
12
+ "test:headless": "pnpm run build:headless && pnpm --filter @aeon-ui/core --filter @aeon-ui/primitives --filter @aeon-ui/react run test",
13
+ "changeset": "changeset",
14
+ "version-packages": "changeset version",
15
+ "release": "pnpm build && changeset publish"
16
+ },
17
+ "devDependencies": {
18
+ "@changesets/cli": "^2.29.0",
19
+ "typescript": "^5.8.3"
20
+ },
21
+ "packageManager": "pnpm@10.11.0",
22
+ "engines": {
23
+ "node": ">=20"
24
+ }
25
+ }
@@ -0,0 +1,69 @@
1
+ # @aeon-ui/core
2
+
3
+ **DOM contract and anatomy** — no React, no XState runtime in components.
4
+
5
+ Agents: read [AGENTS.md](../../AGENTS.md) and [docs/FILE_MAP.md](../../docs/FILE_MAP.md).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @aeon-ui/core
11
+ ```
12
+
13
+ Usually consumed via `@aeon-ui/react` or `@aeon-ui/ui`.
14
+
15
+ ## Exports
16
+
17
+ | Module | Purpose |
18
+ |--------|---------|
19
+ | `philosophy` | `UI_IS_FUNCTION_OF_STATE`, `AEON_PRINCIPLE` |
20
+ | `anatomy` | `buttonAnatomy`, `asyncAnatomy`, `fieldAnatomy`, … |
21
+ | `attrs` | `partAttrs`, `scopeAttrs`, `partOnlyAttrs`, `stateToAttr` |
22
+ | `machine` | `createAeonMachine` — XState `setup` helper |
23
+ | `scroll` | `getScrollSnapshot(element)` |
24
+ | `layout` | Normalized coords, `ResponsiveLayoutSpec`, `layoutModeAttrs` |
25
+ | `types` | Shared types |
26
+
27
+ ### Play-surface layout (coordinates)
28
+
29
+ ```ts
30
+ import {
31
+ playSurfaceAnatomy,
32
+ normFromClient,
33
+ layoutModeAttrs,
34
+ type ResponsiveLayoutSpec,
35
+ } from '@aeon-ui/core'
36
+ ```
37
+
38
+ See [docs/LAYOUT_COORDINATES.md](../../docs/LAYOUT_COORDINATES.md).
39
+
40
+ ## Anatomy
41
+
42
+ ```ts
43
+ import { asyncAnatomy, partAttrs } from '@aeon-ui/core'
44
+
45
+ partAttrs(asyncAnatomy.scope, asyncAnatomy.readout, {
46
+ state: 'loading',
47
+ })
48
+ // → data-aeon-scope="async" data-aeon-part="readout" data-aeon-state="loading"
49
+ ```
50
+
51
+ ## Parallel regions
52
+
53
+ ```ts
54
+ import { stateToAttr } from '@aeon-ui/core'
55
+
56
+ stateToAttr({ interaction: 'dirty', validation: 'invalid', submission: 'idle' })
57
+ // → "interaction:dirty validation:invalid submission:idle"
58
+ ```
59
+
60
+ ## Adding a scope
61
+
62
+ 1. Add `myAnatomy = anatomy('my', ['root', ...] as const)` in `src/anatomy.ts`.
63
+ 2. Use in React via `partAttrs`.
64
+ 3. Follow [docs/COMPONENT_CHECKLIST.md](../../docs/COMPONENT_CHECKLIST.md).
65
+
66
+ ## Related
67
+
68
+ - [STATES.md](../../STATES.md) — attribute contract
69
+ - [packages/primitives/README.md](../primitives/README.md) — machines
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@aeon-ui/core",
3
+ "version": "0.1.0",
4
+ "description": "Anatomy tokens, data-aeon attributes, and machine helpers for Aeon UI",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/GenericCPU/aeon-ui.git",
9
+ "directory": "packages/core"
10
+ },
11
+ "publishConfig": { "access": "public" },
12
+ "files": ["dist", "theme-transition.css", "README.md"],
13
+ "keywords": ["aeon-ui", "statechart", "xstate", "headless", "anatomy"],
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ },
22
+ "./theme-transition.css": "./theme-transition.css"
23
+ },
24
+ "scripts": {
25
+ "build": "tsup src/index.ts --format esm --dts --clean",
26
+ "typecheck": "tsc --noEmit",
27
+ "test": "vitest run"
28
+ },
29
+ "dependencies": {
30
+ "xstate": "^5.19.2"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.4.0",
34
+ "typescript": "^5.8.3",
35
+ "vitest": "^3.2.4"
36
+ }
37
+ }
@@ -0,0 +1,144 @@
1
+ /** Part keys for compound components — scope + named parts for styling and docs. */
2
+ export function anatomy<const T extends readonly string[]>(scope: string, parts: T) {
3
+ return Object.fromEntries(parts.map((p) => [p, p])) as Record<T[number], T[number]> & {
4
+ scope: typeof scope
5
+ }
6
+ }
7
+
8
+ export const buttonAnatomy = anatomy('button', [
9
+ 'root',
10
+ 'group',
11
+ 'label',
12
+ 'icon',
13
+ ] as const)
14
+
15
+ export const switchAnatomy = anatomy('switch', [
16
+ 'root',
17
+ 'control',
18
+ 'thumb',
19
+ 'label',
20
+ 'hiddenInput',
21
+ ] as const)
22
+
23
+ export const checkboxAnatomy = anatomy('checkbox', [
24
+ 'root',
25
+ 'control',
26
+ 'indicator',
27
+ 'label',
28
+ 'hiddenInput',
29
+ ] as const)
30
+
31
+ export const dialogAnatomy = anatomy('dialog', [
32
+ 'root',
33
+ 'trigger',
34
+ 'portal',
35
+ 'backdrop',
36
+ 'positioner',
37
+ 'content',
38
+ 'title',
39
+ 'description',
40
+ 'closeTrigger',
41
+ ] as const)
42
+
43
+ export const tabsAnatomy = anatomy('tabs', [
44
+ 'root',
45
+ 'list',
46
+ 'trigger',
47
+ 'content',
48
+ 'indicator',
49
+ ] as const)
50
+
51
+ export const accordionAnatomy = anatomy('accordion', [
52
+ 'root',
53
+ 'item',
54
+ 'itemTrigger',
55
+ 'itemContent',
56
+ 'itemIndicator',
57
+ ] as const)
58
+
59
+ /** Async data region — track shows every lifecycle state; readout + actions mirror snapshot. */
60
+ export const asyncAnatomy = anatomy('async', [
61
+ 'root',
62
+ 'track',
63
+ 'segment',
64
+ 'readout',
65
+ 'readoutRail',
66
+ 'readoutBody',
67
+ 'actions',
68
+ ] as const)
69
+
70
+ /** Form field — orthogonal interaction × validation × submission (see STATES.md). */
71
+ export const fieldAnatomy = anatomy('field', [
72
+ 'root',
73
+ 'label',
74
+ 'control',
75
+ 'textarea',
76
+ 'message',
77
+ 'hint',
78
+ ] as const)
79
+
80
+ /** Scroll viewport — overflow axis + edge position on data-aeon-state. */
81
+ export const scrollAnatomy = anatomy('scroll', ['root', 'viewport', 'content'] as const)
82
+
83
+ /**
84
+ * Play / game surface — mat shell with table, dice, and bank regions.
85
+ * Use with normalized layout coords (@see docs/LAYOUT_COORDINATES.md).
86
+ */
87
+ export const playSurfaceAnatomy = anatomy('play', ['mat', 'table', 'dice', 'bank'] as const)
88
+
89
+ export const selectAnatomy = anatomy('select', [
90
+ 'root',
91
+ 'trigger',
92
+ 'value',
93
+ 'icon',
94
+ 'positioner',
95
+ 'content',
96
+ 'item',
97
+ ] as const)
98
+
99
+ /** Typeahead listbox — extends select with filter input and empty state. */
100
+ export const comboboxAnatomy = anatomy('combobox', [
101
+ 'root',
102
+ 'input',
103
+ 'icon',
104
+ 'content',
105
+ 'item',
106
+ 'empty',
107
+ ] as const)
108
+
109
+ export const popoverAnatomy = anatomy('popover', [
110
+ 'root',
111
+ 'trigger',
112
+ 'positioner',
113
+ 'content',
114
+ 'arrow',
115
+ 'closeTrigger',
116
+ ] as const)
117
+
118
+ export const menuAnatomy = anatomy('menu', [
119
+ 'root',
120
+ 'trigger',
121
+ 'positioner',
122
+ 'content',
123
+ 'item',
124
+ 'separator',
125
+ ] as const)
126
+
127
+ export const tooltipAnatomy = anatomy('tooltip', [
128
+ 'root',
129
+ 'trigger',
130
+ 'positioner',
131
+ 'content',
132
+ 'arrow',
133
+ ] as const)
134
+
135
+ export const toastAnatomy = anatomy('toast', [
136
+ 'viewport',
137
+ 'root',
138
+ 'title',
139
+ 'description',
140
+ 'closeTrigger',
141
+ ] as const)
142
+
143
+ /** Profile image — loaded / loading / error on root `data-aeon-state`. */
144
+ export const avatarAnatomy = anatomy('avatar', ['root', 'image', 'fallback'] as const)
@@ -0,0 +1,47 @@
1
+ type AttrOptions = {
2
+ state?: string | string[]
3
+ disabled?: boolean
4
+ focus?: boolean
5
+ highlighted?: boolean
6
+ }
7
+
8
+ function stateFields(options?: AttrOptions) {
9
+ const states = options?.state
10
+ ? Array.isArray(options.state)
11
+ ? options.state.join(' ')
12
+ : options.state
13
+ : undefined
14
+
15
+ return {
16
+ ...(states ? { 'data-aeon-state': states } : {}),
17
+ ...(options?.disabled ? { 'data-disabled': '' } : {}),
18
+ ...(options?.focus ? { 'data-focus': '' } : {}),
19
+ ...(options?.highlighted ? { 'data-highlighted': '' } : {}),
20
+ }
21
+ }
22
+
23
+ /** Scope + part on the component root (e.g. accordion root). */
24
+ export function scopeAttrs(
25
+ scope: string,
26
+ part = 'root',
27
+ options?: AttrOptions,
28
+ ): Record<string, unknown> {
29
+ return {
30
+ 'data-aeon-scope': scope,
31
+ 'data-aeon-part': part,
32
+ ...stateFields(options),
33
+ }
34
+ }
35
+
36
+ /** Part only — use on children inside a scoped root. */
37
+ export function partOnlyAttrs(part: string, options?: AttrOptions): Record<string, unknown> {
38
+ return {
39
+ 'data-aeon-part': part,
40
+ ...stateFields(options),
41
+ }
42
+ }
43
+
44
+ /** Build data-aeon-* attributes for styling unstyled parts. */
45
+ export function partAttrs(scope: string, part: string, options?: AttrOptions): Record<string, unknown> {
46
+ return scopeAttrs(scope, part, options)
47
+ }
@@ -0,0 +1,8 @@
1
+ export * from './philosophy.js'
2
+ export * from './anatomy.js'
3
+ export * from './attrs.js'
4
+ export * from './machine.js'
5
+ export * from './types.js'
6
+ export * from './scroll.js'
7
+ export * from './layout.js'
8
+ export * from './theme.js'
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Responsive play-surface layout — logical coordinate plane + composition modes.
3
+ *
4
+ * Behavior stays in statecharts; **where** the user points is expressed in normalized
5
+ * coordinates (0–100) inside a measured region, independent of CSS grid vs overlay.
6
+ *
7
+ * @see docs/LAYOUT_COORDINATES.md
8
+ */
9
+
10
+ /** Point on the normalized plane (percent of region width/height). */
11
+ export type NormPoint = { readonly x: number; readonly y: number }
12
+
13
+ /** Axis-aligned bounds on the normalized plane (inclusive). */
14
+ export type NormRect = {
15
+ readonly xMin: number
16
+ readonly xMax: number
17
+ readonly yMin: number
18
+ readonly yMax: number
19
+ }
20
+
21
+ /** DOM mapping: y increases upward (throws, dice) vs downward (top-left UI). */
22
+ export type NormOrigin = 'bottom-left' | 'top-left'
23
+
24
+ export const NORM_PLANE = {
25
+ bottomLeft: 'bottom-left',
26
+ topLeft: 'top-left',
27
+ } as const satisfies Record<string, NormOrigin>
28
+
29
+ /** How regions are composed at a breakpoint — product maps to CSS grid / absolute. */
30
+ export type LayoutComposition = 'split' | 'stack' | 'overlay'
31
+
32
+ export interface RegionLayoutSlot {
33
+ /** Logical region id (matches anatomy part or app constant). */
34
+ readonly region: string
35
+ /** Grid area name / slot id for CSS `grid-template-areas`. */
36
+ readonly slot: string
37
+ readonly zIndex?: number
38
+ }
39
+
40
+ export interface LayoutCompositionSpec {
41
+ readonly id: string
42
+ readonly composition: LayoutComposition
43
+ readonly regions: readonly RegionLayoutSlot[]
44
+ /** Interaction bounds per region in **that region's** normalized plane. */
45
+ readonly bounds?: Readonly<Record<string, NormRect>>
46
+ }
47
+
48
+ export type LayoutMode = 'compact' | 'wide'
49
+
50
+ export interface ResponsiveLayoutSpec {
51
+ readonly modes: {
52
+ readonly compact: LayoutCompositionSpec
53
+ readonly wide: LayoutCompositionSpec
54
+ }
55
+ /**
56
+ * Media query that selects `compact` when matched (default: phone portrait).
57
+ * When it does not match, mode is `wide`.
58
+ */
59
+ readonly compactMq?: string
60
+ }
61
+
62
+ export const DEFAULT_COMPACT_MQ = '(max-width: 39.99rem)'
63
+
64
+ export function clampNorm(point: NormPoint, bounds: NormRect): NormPoint {
65
+ return {
66
+ x: Math.min(bounds.xMax, Math.max(bounds.xMin, point.x)),
67
+ y: Math.min(bounds.yMax, Math.max(bounds.yMin, point.y)),
68
+ }
69
+ }
70
+
71
+ export function normFromClient(
72
+ rect: DOMRectReadOnly,
73
+ clientX: number,
74
+ clientY: number,
75
+ options?: { origin?: NormOrigin; bounds?: NormRect },
76
+ ): NormPoint {
77
+ const origin = options?.origin ?? NORM_PLANE.bottomLeft
78
+ const w = rect.width || 1
79
+ const h = rect.height || 1
80
+ const x = ((clientX - rect.left) / w) * 100
81
+ const yFromTop = (clientY - rect.top) / h
82
+ const y =
83
+ origin === NORM_PLANE.bottomLeft ? (1 - yFromTop) * 100 : yFromTop * 100
84
+ const raw = { x, y }
85
+ return options?.bounds ? clampNorm(raw, options.bounds) : raw
86
+ }
87
+
88
+ export function clientFromNorm(
89
+ rect: DOMRectReadOnly,
90
+ point: NormPoint,
91
+ options?: { origin?: NormOrigin },
92
+ ): { clientX: number; clientY: number } {
93
+ const origin = options?.origin ?? NORM_PLANE.bottomLeft
94
+ const w = rect.width || 1
95
+ const h = rect.height || 1
96
+ const clientX = rect.left + (point.x / 100) * w
97
+ const yFromTop = origin === NORM_PLANE.bottomLeft ? 1 - point.y / 100 : point.y / 100
98
+ const clientY = rect.top + yFromTop * h
99
+ return { clientX, clientY }
100
+ }
101
+
102
+ /** Measure element; returns null if not connected. */
103
+ export function measureElement(el: Element | null | undefined): DOMRect | null {
104
+ if (!el || !('getBoundingClientRect' in el)) return null
105
+ const rect = el.getBoundingClientRect()
106
+ return rect.width > 0 && rect.height > 0 ? rect : null
107
+ }
108
+
109
+ /** Prefer a dedicated region rect; fall back to mat when lane not mounted. */
110
+ export function resolveRegionRect(
111
+ primary: DOMRect | null | undefined,
112
+ fallback: DOMRect | null | undefined,
113
+ ): DOMRect | null {
114
+ if (primary && primary.width > 0 && primary.height > 0) return primary
115
+ if (fallback && fallback.width > 0 && fallback.height > 0) return fallback
116
+ return null
117
+ }
118
+
119
+ export function matchLayoutMode(
120
+ spec: ResponsiveLayoutSpec,
121
+ mq: Pick<MediaQueryList, 'matches'> = getCompactMq(spec),
122
+ ): LayoutMode {
123
+ return mq.matches ? 'compact' : 'wide'
124
+ }
125
+
126
+ export function getCompactMq(spec: ResponsiveLayoutSpec): MediaQueryList {
127
+ const query = spec.compactMq ?? DEFAULT_COMPACT_MQ
128
+ if (typeof window === 'undefined' || !window.matchMedia) {
129
+ return { matches: false } as MediaQueryList
130
+ }
131
+ return window.matchMedia(query)
132
+ }
133
+
134
+ export function layoutCompositionForMode(
135
+ spec: ResponsiveLayoutSpec,
136
+ mode: LayoutMode,
137
+ ): LayoutCompositionSpec {
138
+ return spec.modes[mode]
139
+ }
140
+
141
+ export function regionBoundsForMode(
142
+ spec: ResponsiveLayoutSpec,
143
+ mode: LayoutMode,
144
+ regionId: string,
145
+ ): NormRect | undefined {
146
+ return spec.modes[mode].bounds?.[regionId]
147
+ }
148
+
149
+ /**
150
+ * Value for `data-aeon-layout-mode` on the mat root.
151
+ * Pair with `data-aeon-layout-composition` from the active spec.
152
+ */
153
+ export function layoutModeAttrs(mode: LayoutMode, composition: LayoutComposition): Record<string, string> {
154
+ return {
155
+ 'data-aeon-layout-mode': mode,
156
+ 'data-aeon-layout-composition': composition,
157
+ }
158
+ }
159
+
160
+ /** Spread a norm point inside bounds (keeps cluster off edges). */
161
+ export function insetNormCluster(
162
+ point: NormPoint,
163
+ bounds: NormRect,
164
+ inset: { x?: number; y?: number } = {},
165
+ ): NormPoint {
166
+ const padX = inset.x ?? 0
167
+ const padY = inset.y ?? 0
168
+ const halfX = (bounds.xMax - bounds.xMin) / 2
169
+ const halfY = (bounds.yMax - bounds.yMin) / 2
170
+ const capX = Math.min(padX, halfX - 0.5)
171
+ const capY = Math.min(padY, halfY - 0.5)
172
+ return {
173
+ x: Math.min(bounds.xMax - capX, Math.max(bounds.xMin + capX, point.x)),
174
+ y: Math.min(bounds.yMax - capY, Math.max(bounds.yMin + capY, point.y)),
175
+ }
176
+ }
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { stateToAttr } from './machine.js'
3
+
4
+ describe('stateToAttr', () => {
5
+ it('stringifies string states', () => {
6
+ expect(stateToAttr('open')).toBe('open')
7
+ })
8
+
9
+ it('flattens parallel regions', () => {
10
+ expect(
11
+ stateToAttr({
12
+ interaction: 'dirty',
13
+ validation: 'invalid',
14
+ submission: 'idle',
15
+ }),
16
+ ).toBe('interaction:dirty validation:invalid submission:idle')
17
+ })
18
+ })
@@ -0,0 +1,15 @@
1
+ import { setup, type ActorRefFrom, type AnyStateMachine, type SnapshotFrom } from 'xstate'
2
+
3
+ /** Re-export XState setup — encode UI behavior as executable statecharts. */
4
+ export { setup as createAeonMachine }
5
+
6
+ export type AeonSnapshot<M extends AnyStateMachine> = SnapshotFrom<M>
7
+ export type AeonActor<M extends AnyStateMachine> = ActorRefFrom<M>
8
+
9
+ /** Flatten nested state value for data-aeon-state attribute. */
10
+ export function stateToAttr(value: unknown): string {
11
+ if (value == null || typeof value === 'string') return String(value ?? '')
12
+ return Object.entries(value as Record<string, unknown>)
13
+ .map(([k, v]) => `${k}:${stateToAttr(v)}`)
14
+ .join(' ')
15
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Aeon north star: behavior is defined as explicit state first; the interface must
3
+ * express the **totality** of that definition — every stable condition the model allows,
4
+ * and nothing the model does not allow.
5
+ */
6
+ export const AEON_PRINCIPLE =
7
+ 'State is defined first. UI represents the totality of that definition.' as const
8
+
9
+ /** Shorthand used in docs and APIs. */
10
+ export const UI_IS_FUNCTION_OF_STATE = 'UI = f(state)' as const