aeon-ui-engine 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.changeset/config.json +2 -1
  2. package/CHANGELOG.md +38 -0
  3. package/COMPONENTS.md +7 -2
  4. package/INTEGRATION.md +14 -0
  5. package/PUBLISHING.md +20 -0
  6. package/README.md +8 -4
  7. package/apps/demo/og.config.mjs +8 -3
  8. package/apps/demo/public/og-aeon-ui-engine.png +0 -0
  9. package/apps/demo/public/og.svg +2 -2
  10. package/apps/demo/scripts/generate-og-png.mjs +4 -2
  11. package/apps/demo/src/App.tsx +2 -2
  12. package/apps/demo/src/aeonDiagrams.ts +17 -75
  13. package/apps/demo/src/components/DiagramsSection.tsx +8 -9
  14. package/apps/demo/src/components/HeroInstall.tsx +7 -4
  15. package/apps/demo/src/components/LandingFaq.tsx +1 -1
  16. package/apps/demo/src/components/LandingFooter.tsx +8 -0
  17. package/apps/demo/src/components/LandingHeader.tsx +4 -2
  18. package/apps/demo/src/components/LayersSection.tsx +6 -10
  19. package/apps/demo/src/components/MermaidDiagram.tsx +5 -3
  20. package/apps/demo/src/components/PhilosophySection.tsx +0 -2
  21. package/apps/demo/src/components/PlaygroundBlock.tsx +3 -8
  22. package/apps/demo/src/components/PlaygroundControlsDemo.tsx +63 -0
  23. package/apps/demo/src/components/PlaygroundSection.tsx +7 -91
  24. package/apps/demo/src/components/ThemeSwitcher.tsx +13 -10
  25. package/apps/demo/src/demo-layout.css +29 -0
  26. package/apps/demo/src/landing.css +138 -89
  27. package/apps/demo/src/nav.ts +3 -3
  28. package/apps/demo/src/site.ts +99 -228
  29. package/docs/MACHINES.md +6 -1
  30. package/package.json +1 -1
  31. package/packages/core/src/anatomy.ts +23 -0
  32. package/packages/panda/panda.config.ts +19 -1
  33. package/packages/panda/src/recipes/button.ts +4 -4
  34. package/packages/panda/src/recipes/combobox.ts +1 -1
  35. package/packages/panda/src/recipes/index.ts +5 -0
  36. package/packages/panda/src/recipes/pin-input.ts +29 -0
  37. package/packages/panda/src/recipes/progress.ts +44 -0
  38. package/packages/panda/src/recipes/radio-group.ts +51 -0
  39. package/packages/panda/src/recipes/select.ts +3 -1
  40. package/packages/panda/src/recipes/separator.ts +35 -0
  41. package/packages/panda/src/recipes/slider.ts +57 -0
  42. package/packages/panda/src/theme/tokens.ts +5 -0
  43. package/packages/panda/styled-system/recipes/aeon-pin-input.d.ts +28 -0
  44. package/packages/panda/styled-system/recipes/aeon-pin-input.mjs +36 -0
  45. package/packages/panda/styled-system/recipes/aeon-progress.d.ts +28 -0
  46. package/packages/panda/styled-system/recipes/aeon-progress.mjs +44 -0
  47. package/packages/panda/styled-system/recipes/aeon-radio-group.d.ts +28 -0
  48. package/packages/panda/styled-system/recipes/aeon-radio-group.mjs +48 -0
  49. package/packages/panda/styled-system/recipes/aeon-separator.d.ts +31 -0
  50. package/packages/panda/styled-system/recipes/aeon-separator.mjs +41 -0
  51. package/packages/panda/styled-system/recipes/aeon-slider.d.ts +28 -0
  52. package/packages/panda/styled-system/recipes/aeon-slider.mjs +48 -0
  53. package/packages/panda/styled-system/recipes/index.d.ts +5 -0
  54. package/packages/panda/styled-system/recipes/index.mjs +5 -0
  55. package/packages/panda/styled-system/styles.css +233 -52
  56. package/packages/panda/styled-system/tokens/index.mjs +32 -0
  57. package/packages/panda/styled-system/tokens/tokens.d.ts +2 -2
  58. package/packages/panda/styled-system/types/conditions.d.ts +1 -1
  59. package/packages/primitives/src/index.ts +1 -0
  60. package/packages/primitives/src/machines/slider.ts +93 -0
  61. package/packages/react/src/checkbox/index.tsx +14 -0
  62. package/packages/react/src/floating/FloatingPositioner.tsx +59 -0
  63. package/packages/react/src/hooks/use-anchor-position.ts +33 -5
  64. package/packages/react/src/hooks/use-prefers-hover.ts +16 -0
  65. package/packages/react/src/index.ts +5 -0
  66. package/packages/react/src/menu/index.tsx +38 -11
  67. package/packages/react/src/pin-input/index.tsx +223 -0
  68. package/packages/react/src/popover/index.tsx +38 -11
  69. package/packages/react/src/progress/index.tsx +110 -0
  70. package/packages/react/src/radio-group/index.tsx +199 -0
  71. package/packages/react/src/select/index.tsx +51 -28
  72. package/packages/react/src/select/select.test.tsx +21 -0
  73. package/packages/react/src/separator/index.tsx +23 -0
  74. package/packages/react/src/slider/index.tsx +264 -0
  75. package/packages/react/src/toast/primitives.tsx +8 -1
  76. package/packages/react/src/toast/toast.test.tsx +40 -0
  77. package/packages/react/src/tooltip/index.tsx +124 -20
  78. package/packages/react/src/tooltip/tooltip.test.tsx +114 -0
  79. package/packages/site/README.md +1 -1
  80. package/packages/ui/src/index.ts +5 -0
  81. package/packages/ui/src/pin-input.tsx +16 -0
  82. package/packages/ui/src/progress.tsx +21 -0
  83. package/packages/ui/src/radio-group.tsx +24 -0
  84. package/packages/ui/src/select.tsx +3 -4
  85. package/packages/ui/src/separator.tsx +15 -0
  86. package/packages/ui/src/slider.tsx +24 -0
  87. package/apps/demo/public/og.png +0 -0
  88. package/apps/demo/src/components/SceneSection.tsx +0 -157
@@ -3,6 +3,7 @@
3
3
  "changelog": "@changesets/cli/changelog",
4
4
  "commit": false,
5
5
  "fixed": [
6
+ ["aeon-ui-engine"],
6
7
  [
7
8
  "@aeon-ui/core",
8
9
  "@aeon-ui/primitives",
@@ -26,5 +27,5 @@
26
27
  "access": "public",
27
28
  "baseBranch": "main",
28
29
  "updateInternalDependencies": "patch",
29
- "ignore": ["@aeon-ui/demo", "aeon-ui-monorepo"]
30
+ "ignore": ["@aeon-ui/demo"]
30
31
  }
package/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to **aeon-ui-engine** are documented here.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.2] - 2026-06-02
9
+
10
+ ### Added
11
+
12
+ - Shared Panda tokens `controlMinHXs`, `controlMinHSm`, `controlMinHMd`, and `controlMinHLg` so compact control heights stay aligned across components.
13
+
14
+ ### Changed
15
+
16
+ - Button, select trigger, and combobox input recipes reference the shared control-height tokens instead of hardcoded `rem` values.
17
+ - Demo header toolbar uses `size="sm"` for buttons alongside the select (same compact tier) without page-level height overrides.
18
+
19
+ ## [1.0.1] - 2026-06-02
20
+
21
+ ### Changed
22
+
23
+ - Open Graph preview image shows `npm install aeon-ui-engine` and is served at `/og-aeon-ui-engine.png` for cache-friendly social sharing.
24
+ - Demo site copy standardized on the `aeon-ui-engine` npm package name.
25
+
26
+ ### Fixed
27
+
28
+ - Mobile header theme preset select shows a visible **Theme** label instead of chevron-only.
29
+
30
+ ## [1.0.0] - 2026-06-02
31
+
32
+ ### Added
33
+
34
+ - Initial npm release of **aeon-ui-engine** — monorepo bundle with headless statechart primitives, React bindings, Panda styled layer, and themes.
35
+
36
+ [1.0.2]: https://github.com/GenericCPU/aeon-ui/compare/v1.0.1...v1.0.2
37
+ [1.0.1]: https://github.com/GenericCPU/aeon-ui/compare/v1.0.0...v1.0.1
38
+ [1.0.0]: https://github.com/GenericCPU/aeon-ui/releases/tag/v1.0.0
package/COMPONENTS.md CHANGED
@@ -19,13 +19,18 @@ Status key: **Headless** (`@aeon-ui/react`) · **Styled** (`@aeon-ui/ui`) · **S
19
19
  | Scroll | ✓ | ✓ | **`getScrollSnapshot`** | overflow axis + edge position |
20
20
  | Menu | ✓ | ✓ | `popoverMachine` | open / closed |
21
21
  | Popover | ✓ | ✓ | `popoverMachine` | open / closed |
22
- | Tooltip | ✓ | ✓ | **React state** | open / closed |
22
+ | Tooltip | ✓ | ✓ | **React state** | open / closed; tap-to-toggle on touch |
23
23
  | Toast | ✓ | ✓ | `toastMachine` | hidden / visible |
24
24
  | Avatar | ✓ | — | **React state** | idle / loading / loaded / error |
25
+ | Separator | ✓ | ✓ | **static** | horizontal / vertical orientation |
26
+ | Progress | ✓ | ✓ | **props** | idle / loading / complete |
27
+ | RadioGroup | ✓ | ✓ | `tabsMachine` | one selected item |
28
+ | Slider | ✓ | ✓ | `sliderMachine` | idle / dragging + value |
29
+ | PinInput | ✓ | ✓ | **React state** | idle / complete |
25
30
 
26
31
  ## Planned (not shipped)
27
32
 
28
- Slider, Number Input, Date Picker, Tree View, Pin Input, File Upload, Carousel — tracked as the catalog grows; prefer explicit machines per component.
33
+ Number Input, Date Picker, Tree View, File Upload, Carousel, Toggle Group — tracked as the catalog grows; prefer explicit machines per component.
29
34
 
30
35
  ## Choosing a layer
31
36
 
package/INTEGRATION.md CHANGED
@@ -71,6 +71,20 @@ import { Menu, Button } from '@aeon-ui/ui'
71
71
  </button>
72
72
  ```
73
73
 
74
+ ## Styling stacks (Chakra, Park UI, Tark UI, Shark UI)
75
+
76
+ Aeon is **headless** like Ark UI — it does not ship adapters for Chakra v3, Park UI, Tark UI, or Shark UI, and that is intentional:
77
+
78
+ | Stack | Built on | Relationship to Aeon |
79
+ |-------|----------|----------------------|
80
+ | **Chakra UI v3** | Ark UI + Zag | Different primitive layer. Migrating **from** Ark **to** Aeon → [docs/MIGRATION_FROM_ARK.md](./docs/MIGRATION_FROM_ARK.md). |
81
+ | **Park UI** | Panda CSS + Ark | Aeon already pairs **Panda slot recipes + headless** in one repo (`@aeon-ui/ui`). Use Aeon styled or copy recipe patterns. |
82
+ | **Tark UI / Shark UI** | Ark + Tailwind | Style Aeon headless with Tailwind the same way — target `data-aeon-scope` / `data-aeon-part` / `data-aeon-state` (see Tailwind example above). |
83
+
84
+ **What works today:** `@aeon-ui/react` with any CSS system; `@aeon-ui/ui` for Panda-native defaults; thin wrappers in your repo (same pattern as Shark UI’s shadcn-style files).
85
+
86
+ **What we do not maintain:** drop-in replacement exports for Ark or Chakra recipe APIs — different anatomy prefix, machines, and compound part names.
87
+
74
88
  ## XState in your app
75
89
 
76
90
  Primitives use XState; your features can too. `useAeonMachine` is exported from `@aeon-ui/react` for shared machines.
package/PUBLISHING.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Publishing to npm
2
2
 
3
+ ## aeon-ui-engine (primary npm package)
4
+
5
+ The public install target is **`aeon-ui-engine`**, published from the **repo root**. Its semver is independent of internal `@aeon-ui/*` workspace versions (still `0.1.0` until those are released separately).
6
+
7
+ ### Release checklist (patch / minor / major)
8
+
9
+ 1. Update root **[CHANGELOG.md](./CHANGELOG.md)** under `## [X.Y.Z]` using [Keep a Changelog](https://keepachangelog.com/) sections: `Added`, `Changed`, `Fixed`, `Removed`, `Deprecated`, `Security`.
10
+ 2. Bump **`version`** in root **[package.json](./package.json)** (`1.0.1` → `1.0.2` = **patch** for fixes; **minor** for features; **major** for breaking changes).
11
+ 3. `pnpm build && pnpm typecheck`
12
+ 4. Commit: `Release aeon-ui-engine vX.Y.Z`
13
+ 5. Tag: `git tag vX.Y.Z`
14
+ 6. Publish: `npm publish --access public` (from repo root; requires `npm login`)
15
+ 7. Push: `git push && git push --tags`
16
+
17
+ Optional: add a Changeset with `"aeon-ui-engine": patch|minor|major` before step 2 if you use `pnpm version-packages` for the root package only (see `.changeset/config.json`).
18
+
19
+ ---
20
+
21
+ ## @aeon-ui/* scoped packages (future)
22
+
3
23
  Packages are versioned together at **0.1.0** (pre-release) using [Changesets](https://github.com/changesets/changesets).
4
24
 
5
25
  ## Packages
package/README.md CHANGED
@@ -21,15 +21,19 @@ Aeon UI models interactive behavior as executable [statecharts](https://www.thes
21
21
  | `@aeon-ui/solid` | Solid headless adapter (v0.1: Switch + `useAeonMachine`) |
22
22
  | `@aeon-ui/svelte` | Svelte headless adapter (v0.1: Switch + `useAeonMachine`) |
23
23
 
24
- **Catalog (React):** Button, Switch, Checkbox, Dialog, Tabs, Accordion, Select, **Combobox**, Async, Field, Scroll, **Menu**, **Popover**, **Tooltip**, **Toast** — see [COMPONENTS.md](./COMPONENTS.md). **Vue / Solid / Svelte:** reference Switch port; more components follow — [FRAMEWORKS.md](./FRAMEWORKS.md).
24
+ **Catalog (React):** Button, Switch, Checkbox, Dialog, Tabs, Accordion, Select, Combobox, Async, Field, Scroll, Menu, Popover, Tooltip, Toast, **Separator**, **Progress**, **RadioGroup**, **Slider**, **PinInput** — see [COMPONENTS.md](./COMPONENTS.md).
25
25
 
26
26
  ## Quick start
27
27
 
28
- **Early access** — DM FOR EARLY ACCESS (npm publish is wired via Changesets; public install docs ship when the scope is live).
28
+ The monorepo is published on npm as **`aeon-ui-engine`**:
29
29
 
30
- Open [https://github.com/GenericCPU/aeon-ui](https://github.com/GenericCPU/aeon-ui) for the repo. The marketing demo lives at [https://aeon-ui.com](https://aeon-ui.com) — set `VITE_SITE_ORIGIN` to that origin in Vercel so Open Graph previews resolve `og.png` correctly.
30
+ ```bash
31
+ npm install aeon-ui-engine
32
+ ```
33
+
34
+ Open [https://github.com/GenericCPU/aeon-ui](https://github.com/GenericCPU/aeon-ui) for the repo. The marketing demo lives at [https://aeon-ui.com](https://aeon-ui.com) — set `VITE_SITE_ORIGIN` to that origin in Vercel so Open Graph previews resolve the social image in `apps/demo/public/` correctly.
31
35
 
32
- When published: `pnpm add @aeon-ui/ui @aeon-ui/react @aeon-ui/panda`
36
+ After installing `aeon-ui-engine`, use the core, React, styled UI, and Panda layers included in the package.
33
37
 
34
38
  After changing recipes or tokens in `packages/panda`:
35
39
 
@@ -4,12 +4,17 @@ export const siteOrigin = (process.env.VITE_SITE_ORIGIN ?? 'https://aeon-ui.com'
4
4
  '',
5
5
  )
6
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
+
7
11
  export const og = {
8
12
  title: 'Aeon UI — Future-proof UI infrastructure',
9
13
  description:
10
- 'Statechart-driven headless primitives and a Panda CSS styled layer — dependable behavior, anatomy you can theme, built to last.',
14
+ 'Statechart-driven primitives and a styled layer you control — dependable behavior today, room to grow tomorrow. Built to last.',
11
15
  siteName: 'Aeon UI',
12
- imagePath: '/og.png',
13
- imageAlt: 'Aeon UI — Future-proof UI infrastructure for the web',
16
+ imagePath: '/og-aeon-ui-engine.png',
17
+ imageAlt: `Aeon UI — Future-proof UI infrastructure (${npmInstallCommand})`,
14
18
  themeColor: '#0c0e12',
19
+ npmInstallCommand,
15
20
  }
@@ -26,8 +26,8 @@
26
26
  <text x="80" y="340" fill="#94a3b8" font-family="Instrument Sans" font-size="36" font-weight="500">Future-proof UI infrastructure</text>
27
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
28
 
29
- <rect x="80" y="430" width="220" height="36" 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="15" font-weight="500">@aeon-ui/ui</text>
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
31
 
32
32
  <text x="80" y="548" fill="#94a3b8" font-family="Instrument Sans" font-size="17" font-weight="500">A project by</text>
33
33
  <text x="228" y="548" fill="#5eead4" font-family="Syne" font-size="22" font-weight="700">SpiderCorp</text>
@@ -5,11 +5,12 @@ import { dirname, join } from 'node:path'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { Resvg } from '@resvg/resvg-js'
7
7
  import wawoff2 from 'wawoff2'
8
+ import { og } from '../og.config.mjs'
8
9
 
9
10
  const require = createRequire(import.meta.url)
10
11
  const root = join(dirname(fileURLToPath(import.meta.url)), '..')
11
12
  const svgPath = join(root, 'public', 'og.svg')
12
- const outPath = join(root, 'public', 'og.png')
13
+ const outPath = join(root, 'public', og.imagePath.replace(/^\//, ''))
13
14
 
14
15
  /** @type {Array<[slug: string, pkg: string, file: string]>} */
15
16
  const FONT_SOURCES = [
@@ -40,7 +41,8 @@ async function loadFontFiles() {
40
41
  return fontFiles
41
42
  }
42
43
 
43
- const svg = readFileSync(svgPath, 'utf8')
44
+ const svgTemplate = readFileSync(svgPath, 'utf8')
45
+ const svg = svgTemplate.replaceAll('{{NPM_INSTALL_COMMAND}}', og.npmInstallCommand)
44
46
  const fontFiles = await loadFontFiles()
45
47
 
46
48
  const resvg = new Resvg(svg, {
@@ -17,10 +17,10 @@ export function App() {
17
17
  <LandingHeader />
18
18
  <main>
19
19
  <LandingHero />
20
+ <PhilosophySection />
21
+ <PlaygroundSection />
20
22
  <LayersSection />
21
23
  <DiagramsSection />
22
- <PlaygroundSection />
23
- <PhilosophySection />
24
24
  <LandingFaq />
25
25
  </main>
26
26
  <LandingFooter />
@@ -1,100 +1,42 @@
1
- /** Mermaid sources — kept in sync with @aeon-ui/primitives machines (STATES.md). */
1
+ /** Mermaid sources — kept in sync with aeon-ui-engine machines (STATES.md). */
2
2
 
3
3
  export type AeonDiagram = {
4
4
  id: string
5
5
  title: string
6
6
  caption: string
7
7
  source: string
8
- packageRef: string
9
8
  }
10
9
 
10
+ /** Model → snapshot → DOM. The north-star flow. */
11
11
  export const aeonNorthStarDiagram = `flowchart LR
12
- chart["Statechart\\n(XState)"]
12
+ chart["Statechart"]
13
13
  snap["Snapshot"]
14
- attr["data-aeon-state"]
15
- ui["UI = f(state)"]
16
- chart --> snap --> attr --> ui`
14
+ ui["UI"]
15
+ chart --> snap --> ui`
17
16
 
17
+ /** Main async path — full machine has reset/re-fetch edges in STATES.md. */
18
18
  export const asyncLifecycleDiagram = `stateDiagram-v2
19
19
  direction LR
20
20
  [*] --> idle
21
- idle --> loading: FETCH
22
- idle --> idle: RESET / clear
23
- loading --> success: RESOLVE
24
- loading --> empty: RESOLVE (empty)
25
- loading --> failure: REJECT
26
- success --> loading: FETCH
27
- empty --> loading: FETCH
28
- failure --> loading: FETCH
29
- success --> idle: RESET
30
- empty --> idle: RESET
31
- failure --> idle: RESET`
32
-
33
- export const buttonLifecycleDiagram = `stateDiagram-v2
34
- direction LR
35
- [*] --> idle
36
- idle --> pending: PRESS
37
- idle --> disabled: DISABLE
38
- pending --> success: SUCCEED
39
- pending --> failure: FAIL
40
- pending --> disabled: DISABLE
41
- success --> idle: RESET
42
- success --> pending: PRESS
43
- failure --> idle: RESET
44
- failure --> pending: PRESS
45
- disabled --> idle: ENABLE`
46
-
47
- export const fieldOrthogonalDiagram = `stateDiagram-v2
48
- direction TB
49
- state "interaction region" as interaction {
50
- direction LR
51
- [*] --> pristine
52
- pristine --> dirty: INPUT / BLUR
53
- dirty --> pristine: RESET
54
- }
55
- state "validation region" as validation {
56
- direction LR
57
- [*] --> valid
58
- valid --> invalid: VALIDATE invalid
59
- invalid --> valid: VALIDATE valid
60
- invalid --> valid: RESET
61
- }
62
- state "submission region" as submission {
63
- direction LR
64
- [*] --> idle
65
- idle --> pending: SUBMIT
66
- pending --> idle: SUBMIT_DONE / SUBMIT_FAIL
67
- }`
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`
68
28
 
69
29
  export const aeonDiagrams: AeonDiagram[] = [
70
30
  {
71
31
  id: 'north-star',
72
- title: 'North star',
73
- caption: 'Behavior is modeled first; the DOM expresses the snapshot — never the other way around.',
32
+ title: 'Model → UI',
33
+ caption: 'Behavior is defined once; the interface is its projection — structure, copy, and state attributes in agreement.',
74
34
  source: aeonNorthStarDiagram,
75
- packageRef: 'PHILOSOPHY.md',
76
35
  },
77
36
  {
78
37
  id: 'async',
79
- title: 'Async data region',
80
- caption:
81
- 'Sequential lifecycle from createAsyncMachine(): idle · loading · success · failure · empty, plus stale on success.',
38
+ title: 'Async region',
39
+ caption: 'A named lifecycle teams can reason about together — not an unnamed spinner behind a boolean.',
82
40
  source: asyncLifecycleDiagram,
83
- packageRef: '@aeon-ui/primitives — createAsyncMachine()',
84
- },
85
- {
86
- id: 'button',
87
- title: 'Button lifecycle',
88
- caption: 'Submit controls: pending, success, and failure are real states — not overloaded disabled.',
89
- source: buttonLifecycleDiagram,
90
- packageRef: '@aeon-ui/primitives — buttonLifecycleMachine',
91
- },
92
- {
93
- id: 'field',
94
- title: 'Field (orthogonal regions)',
95
- caption:
96
- 'Parallel regions flatten to one attribute: interaction:dirty validation:invalid submission:idle',
97
- source: fieldOrthogonalDiagram,
98
- packageRef: '@aeon-ui/primitives — fieldMachine',
99
41
  },
100
42
  ]
@@ -13,24 +13,23 @@ export function DiagramsSection() {
13
13
  </header>
14
14
 
15
15
  <div className="diagrams__grid">
16
- {aeonDiagrams.map((d) => (
17
- <article key={d.id} className="panel diagram-card" data-aeon-scope="diagrams">
16
+ {aeonDiagrams.map((diagram) => (
17
+ <article key={diagram.id} className="panel diagram-card" data-aeon-scope="diagrams">
18
18
  <header className="diagram-card__head">
19
- <h3>{d.title}</h3>
20
- <p>{d.caption}</p>
21
- <code className="diagram-card__ref">{d.packageRef}</code>
19
+ <h3>{diagram.title}</h3>
20
+ <p>{diagram.caption}</p>
22
21
  </header>
23
- <MermaidDiagram source={d.source} title={d.title} />
22
+ <MermaidDiagram source={diagram.source} title={diagram.title} />
24
23
  </article>
25
24
  ))}
26
25
  </div>
27
26
 
28
27
  <p className="diagrams__footnote">
29
- Charts match executable machines in the repo — see{' '}
28
+ Full machine definitions in{' '}
30
29
  <a href={site.statesDocUrl} target="_blank" rel="noreferrer">
31
30
  STATES.md
32
- </a>{' '}
33
- and the playground for live snapshots.
31
+ </a>
32
+ .
34
33
  </p>
35
34
  </div>
36
35
  </section>
@@ -2,9 +2,12 @@ import { site } from '../site.js'
2
2
 
3
3
  export function HeroInstallLine() {
4
4
  return (
5
- <p className="hero-install__line" data-aeon-scope="hero" data-aeon-part="install">
6
- <span className="hero-install__label">{site.heroInstallLabel}</span>
7
- <span className="hero-install__access">{site.heroInstallAccess}</span>
8
- </p>
5
+ <div className="hero-install" data-aeon-scope="hero" data-aeon-part="install">
6
+ <p className="hero-install__line">
7
+ <span className="hero-install__label">{site.heroInstallLabel}</span>
8
+ <code className="hero-install__command">{site.heroInstallCommand}</code>
9
+ </p>
10
+ <p className="hero-install__hint">{site.heroInstallHint}</p>
11
+ </div>
9
12
  )
10
13
  }
@@ -18,7 +18,7 @@ export function LandingFaq() {
18
18
  <Accordion.ItemTrigger value={item.id}>{item.question}</Accordion.ItemTrigger>
19
19
  <Accordion.ItemContent value={item.id}>
20
20
  <p>{item.answer}</p>
21
- <CodeExample code={item.example} />
21
+ {'example' in item && item.example ? <CodeExample code={item.example} /> : null}
22
22
  </Accordion.ItemContent>
23
23
  </Accordion.Item>
24
24
  ))}
@@ -10,6 +10,14 @@ export function LandingFooter() {
10
10
  © {year} {site.brand} · {site.tagline}
11
11
  </p>
12
12
  <p className="landing-footer__tag">
13
+ <a href={site.npmRegistryUrl} target="_blank" rel="noreferrer">
14
+ {site.npmPackage}
15
+ </a>
16
+ {' · '}
17
+ <a href={site.url} target="_blank" rel="noreferrer">
18
+ GitHub
19
+ </a>
20
+ {' · '}
13
21
  A project by{' '}
14
22
  <a href={site.studioUrl} target="_blank" rel="noreferrer">
15
23
  {site.studio}
@@ -46,11 +46,13 @@ export function LandingHeader() {
46
46
  <div className="landing-header__utilities">
47
47
  <ThemeSwitcher />
48
48
  <a href="#playground" className="landing-header__cta">
49
- <Button.Root size="xs">
49
+ <Button.Root size="sm" aria-label={site.heroCtaPrimary}>
50
50
  <span className="landing-header__cta-label landing-header__cta-label--long">
51
51
  {site.heroCtaPrimary}
52
52
  </span>
53
- <span className="landing-header__cta-label landing-header__cta-label--short">Demo</span>
53
+ <span className="landing-header__cta-label landing-header__cta-label--short" aria-hidden="true">
54
+ {site.headerCtaShort}
55
+ </span>
54
56
  </Button.Root>
55
57
  </a>
56
58
  </div>
@@ -1,5 +1,4 @@
1
1
  import { commitments, layers, site } from '../site.js'
2
- import { CodeExample } from './CodeExample.js'
3
2
 
4
3
  export function LayersSection() {
5
4
  return (
@@ -21,9 +20,9 @@ export function LayersSection() {
21
20
  </div>
22
21
 
23
22
  <div className="layers__grid" role="list">
24
- {layers.map((l, index) => (
23
+ {layers.map((layer, index) => (
25
24
  <article
26
- key={l.id}
25
+ key={layer.id}
27
26
  className="panel layer-card"
28
27
  role="listitem"
29
28
  data-aeon-scope="layers"
@@ -32,16 +31,13 @@ export function LayersSection() {
32
31
  <span className="layer-card__index" aria-hidden>
33
32
  {String(index + 1).padStart(2, '0')}
34
33
  </span>
35
- <h3>{l.title}</h3>
36
- <p>{l.description}</p>
34
+ <h3>{layer.title}</h3>
35
+ <p>{layer.description}</p>
37
36
  <ul>
38
- {l.highlights.map((h) => (
39
- <li key={h}>{h}</li>
37
+ {layer.highlights.map((highlight) => (
38
+ <li key={highlight}>{highlight}</li>
40
39
  ))}
41
40
  </ul>
42
- <div className="layer-card__example">
43
- <CodeExample code={l.example} />
44
- </div>
45
41
  </article>
46
42
  ))}
47
43
  </div>
@@ -21,12 +21,14 @@ function ensureMermaid(mermaid: typeof import('mermaid').default) {
21
21
  noteBorderColor: '#3d4556',
22
22
  },
23
23
  state: {
24
- nodeSpacing: 48,
25
- rankSpacing: 56,
24
+ nodeSpacing: 64,
25
+ rankSpacing: 72,
26
+ fontSize: 15,
26
27
  },
27
28
  flowchart: {
28
29
  curve: 'basis',
29
- padding: 12,
30
+ padding: 16,
31
+ htmlLabels: true,
30
32
  },
31
33
  })
32
34
  mermaidReady = true
@@ -1,6 +1,5 @@
1
1
  import { Button } from '@aeon-ui/ui'
2
2
  import { philosophyTenets, site } from '../site.js'
3
- import { CodeExample } from './CodeExample.js'
4
3
 
5
4
  export function PhilosophySection() {
6
5
  return (
@@ -17,7 +16,6 @@ export function PhilosophySection() {
17
16
  <article key={t.title} className="thesis__card">
18
17
  <h3>{t.title}</h3>
19
18
  <p>{t.body}</p>
20
- <CodeExample code={t.example} />
21
19
  </article>
22
20
  ))}
23
21
  </div>
@@ -1,23 +1,18 @@
1
1
  import type { ReactNode } from 'react'
2
- import { CodeExample } from './CodeExample.js'
3
2
 
4
3
  export interface PlaygroundBlockProps {
5
4
  title: string
6
5
  description: string
7
- example: string
8
6
  children: ReactNode
9
7
  last?: boolean
10
8
  }
11
9
 
12
- export function PlaygroundBlock({ title, description, example, children, last }: PlaygroundBlockProps) {
10
+ export function PlaygroundBlock({ title, description, children, last }: PlaygroundBlockProps) {
13
11
  return (
14
- <section
15
- className={`playground__block${last ? ' playground__block--last' : ''}`}
16
- >
12
+ <section className={`playground__block${last ? ' playground__block--last' : ''}`}>
17
13
  <h3 className="playground__block-title">{title}</h3>
18
14
  <p className="playground__block-sub">{description}</p>
19
- <CodeExample code={example} />
20
- {children}
15
+ <div className="playground__block-demo">{children}</div>
21
16
  </section>
22
17
  )
23
18
  }
@@ -0,0 +1,63 @@
1
+ import { Button, Checkbox, PinInput, RadioGroup, Slider, Switch } from '@aeon-ui/ui'
2
+ import { useState } from 'react'
3
+
4
+ export function PlaygroundControlsDemo() {
5
+ const [notifications, setNotifications] = useState(true)
6
+ const [emailDigest, setEmailDigest] = useState(false)
7
+ const [plan, setPlan] = useState('standard')
8
+ const [volume, setVolume] = useState(40)
9
+ const [pin, setPin] = useState('')
10
+
11
+ return (
12
+ <div className="playground-controls">
13
+ <Button.Group className="playground-button-row">
14
+ <Button.Root>Primary</Button.Root>
15
+ <Button.Root variant="outline">Outline</Button.Root>
16
+ <Button.Root variant="ghost">Ghost</Button.Root>
17
+ </Button.Group>
18
+
19
+ <div className="playground-controls__toggles">
20
+ <Switch.Root checked={notifications} onCheckedChange={setNotifications}>
21
+ <Switch.Control>
22
+ <Switch.Thumb />
23
+ </Switch.Control>
24
+ <Switch.Label>Notifications</Switch.Label>
25
+ </Switch.Root>
26
+
27
+ <Checkbox.Root checked={emailDigest} onCheckedChange={setEmailDigest}>
28
+ <Checkbox.Control>
29
+ <Checkbox.Indicator />
30
+ </Checkbox.Control>
31
+ <Checkbox.Label>Email digest</Checkbox.Label>
32
+ </Checkbox.Root>
33
+ </div>
34
+
35
+ <RadioGroup.Root value={plan} onValueChange={setPlan} className="playground-controls__radio">
36
+ <RadioGroup.Item value="standard">
37
+ <RadioGroup.ItemControl>
38
+ <RadioGroup.ItemIndicator />
39
+ </RadioGroup.ItemControl>
40
+ <RadioGroup.ItemLabel>Standard</RadioGroup.ItemLabel>
41
+ </RadioGroup.Item>
42
+ <RadioGroup.Item value="pro">
43
+ <RadioGroup.ItemControl>
44
+ <RadioGroup.ItemIndicator />
45
+ </RadioGroup.ItemControl>
46
+ <RadioGroup.ItemLabel>Pro</RadioGroup.ItemLabel>
47
+ </RadioGroup.Item>
48
+ </RadioGroup.Root>
49
+
50
+ <Slider.Root value={volume} onValueChange={setVolume} className="playground-controls__slider">
51
+ <Slider.Track>
52
+ <Slider.Range />
53
+ <Slider.Thumb />
54
+ </Slider.Track>
55
+ <Slider.ValueText>{volume}%</Slider.ValueText>
56
+ </Slider.Root>
57
+
58
+ <PinInput.Root length={4} value={pin} onValueChange={setPin}>
59
+ <PinInput.Group />
60
+ </PinInput.Root>
61
+ </div>
62
+ )
63
+ }