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.
- package/.changeset/config.json +2 -1
- package/CHANGELOG.md +38 -0
- package/COMPONENTS.md +7 -2
- package/INTEGRATION.md +14 -0
- package/PUBLISHING.md +20 -0
- package/README.md +8 -4
- package/apps/demo/og.config.mjs +8 -3
- package/apps/demo/public/og-aeon-ui-engine.png +0 -0
- package/apps/demo/public/og.svg +2 -2
- package/apps/demo/scripts/generate-og-png.mjs +4 -2
- package/apps/demo/src/App.tsx +2 -2
- package/apps/demo/src/aeonDiagrams.ts +17 -75
- package/apps/demo/src/components/DiagramsSection.tsx +8 -9
- package/apps/demo/src/components/HeroInstall.tsx +7 -4
- package/apps/demo/src/components/LandingFaq.tsx +1 -1
- package/apps/demo/src/components/LandingFooter.tsx +8 -0
- package/apps/demo/src/components/LandingHeader.tsx +4 -2
- package/apps/demo/src/components/LayersSection.tsx +6 -10
- package/apps/demo/src/components/MermaidDiagram.tsx +5 -3
- package/apps/demo/src/components/PhilosophySection.tsx +0 -2
- package/apps/demo/src/components/PlaygroundBlock.tsx +3 -8
- package/apps/demo/src/components/PlaygroundControlsDemo.tsx +63 -0
- package/apps/demo/src/components/PlaygroundSection.tsx +7 -91
- package/apps/demo/src/components/ThemeSwitcher.tsx +13 -10
- package/apps/demo/src/demo-layout.css +29 -0
- package/apps/demo/src/landing.css +138 -89
- package/apps/demo/src/nav.ts +3 -3
- package/apps/demo/src/site.ts +99 -228
- package/docs/MACHINES.md +6 -1
- package/package.json +1 -1
- package/packages/core/src/anatomy.ts +23 -0
- package/packages/panda/panda.config.ts +19 -1
- package/packages/panda/src/recipes/button.ts +4 -4
- package/packages/panda/src/recipes/combobox.ts +1 -1
- package/packages/panda/src/recipes/index.ts +5 -0
- package/packages/panda/src/recipes/pin-input.ts +29 -0
- package/packages/panda/src/recipes/progress.ts +44 -0
- package/packages/panda/src/recipes/radio-group.ts +51 -0
- package/packages/panda/src/recipes/select.ts +3 -1
- package/packages/panda/src/recipes/separator.ts +35 -0
- package/packages/panda/src/recipes/slider.ts +57 -0
- package/packages/panda/src/theme/tokens.ts +5 -0
- package/packages/panda/styled-system/recipes/aeon-pin-input.d.ts +28 -0
- package/packages/panda/styled-system/recipes/aeon-pin-input.mjs +36 -0
- package/packages/panda/styled-system/recipes/aeon-progress.d.ts +28 -0
- package/packages/panda/styled-system/recipes/aeon-progress.mjs +44 -0
- package/packages/panda/styled-system/recipes/aeon-radio-group.d.ts +28 -0
- package/packages/panda/styled-system/recipes/aeon-radio-group.mjs +48 -0
- package/packages/panda/styled-system/recipes/aeon-separator.d.ts +31 -0
- package/packages/panda/styled-system/recipes/aeon-separator.mjs +41 -0
- package/packages/panda/styled-system/recipes/aeon-slider.d.ts +28 -0
- package/packages/panda/styled-system/recipes/aeon-slider.mjs +48 -0
- package/packages/panda/styled-system/recipes/index.d.ts +5 -0
- package/packages/panda/styled-system/recipes/index.mjs +5 -0
- package/packages/panda/styled-system/styles.css +233 -52
- package/packages/panda/styled-system/tokens/index.mjs +32 -0
- package/packages/panda/styled-system/tokens/tokens.d.ts +2 -2
- package/packages/panda/styled-system/types/conditions.d.ts +1 -1
- package/packages/primitives/src/index.ts +1 -0
- package/packages/primitives/src/machines/slider.ts +93 -0
- package/packages/react/src/checkbox/index.tsx +14 -0
- package/packages/react/src/floating/FloatingPositioner.tsx +59 -0
- package/packages/react/src/hooks/use-anchor-position.ts +33 -5
- package/packages/react/src/hooks/use-prefers-hover.ts +16 -0
- package/packages/react/src/index.ts +5 -0
- package/packages/react/src/menu/index.tsx +38 -11
- package/packages/react/src/pin-input/index.tsx +223 -0
- package/packages/react/src/popover/index.tsx +38 -11
- package/packages/react/src/progress/index.tsx +110 -0
- package/packages/react/src/radio-group/index.tsx +199 -0
- package/packages/react/src/select/index.tsx +51 -28
- package/packages/react/src/select/select.test.tsx +21 -0
- package/packages/react/src/separator/index.tsx +23 -0
- package/packages/react/src/slider/index.tsx +264 -0
- package/packages/react/src/toast/primitives.tsx +8 -1
- package/packages/react/src/toast/toast.test.tsx +40 -0
- package/packages/react/src/tooltip/index.tsx +124 -20
- package/packages/react/src/tooltip/tooltip.test.tsx +114 -0
- package/packages/site/README.md +1 -1
- package/packages/ui/src/index.ts +5 -0
- package/packages/ui/src/pin-input.tsx +16 -0
- package/packages/ui/src/progress.tsx +21 -0
- package/packages/ui/src/radio-group.tsx +24 -0
- package/packages/ui/src/select.tsx +3 -4
- package/packages/ui/src/separator.tsx +15 -0
- package/packages/ui/src/slider.tsx +24 -0
- package/apps/demo/public/og.png +0 -0
- package/apps/demo/src/components/SceneSection.tsx +0 -157
package/.changeset/config.json
CHANGED
|
@@ -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"
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
28
|
+
The monorepo is published on npm as **`aeon-ui-engine`**:
|
|
29
29
|
|
|
30
|
-
|
|
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
|
-
|
|
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
|
|
package/apps/demo/og.config.mjs
CHANGED
|
@@ -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
|
|
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:
|
|
16
|
+
imagePath: '/og-aeon-ui-engine.png',
|
|
17
|
+
imageAlt: `Aeon UI — Future-proof UI infrastructure (${npmInstallCommand})`,
|
|
14
18
|
themeColor: '#0c0e12',
|
|
19
|
+
npmInstallCommand,
|
|
15
20
|
}
|
|
Binary file
|
package/apps/demo/public/og.svg
CHANGED
|
@@ -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="
|
|
30
|
-
<text x="104" y="454" fill="#5eead4" font-family="IBM Plex Mono" font-size="
|
|
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',
|
|
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
|
|
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, {
|
package/apps/demo/src/App.tsx
CHANGED
|
@@ -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
|
|
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
|
|
12
|
+
chart["Statechart"]
|
|
13
13
|
snap["Snapshot"]
|
|
14
|
-
|
|
15
|
-
|
|
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:
|
|
22
|
-
|
|
23
|
-
loading -->
|
|
24
|
-
loading --> empty:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
empty -->
|
|
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: '
|
|
73
|
-
caption: 'Behavior is
|
|
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
|
|
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((
|
|
17
|
-
<article key={
|
|
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>{
|
|
20
|
-
<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={
|
|
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
|
-
|
|
28
|
+
Full machine definitions in{' '}
|
|
30
29
|
<a href={site.statesDocUrl} target="_blank" rel="noreferrer">
|
|
31
30
|
STATES.md
|
|
32
|
-
</a>
|
|
33
|
-
|
|
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
|
-
<
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
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="
|
|
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">
|
|
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((
|
|
23
|
+
{layers.map((layer, index) => (
|
|
25
24
|
<article
|
|
26
|
-
key={
|
|
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>{
|
|
36
|
-
<p>{
|
|
34
|
+
<h3>{layer.title}</h3>
|
|
35
|
+
<p>{layer.description}</p>
|
|
37
36
|
<ul>
|
|
38
|
-
{
|
|
39
|
-
<li key={
|
|
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:
|
|
25
|
-
rankSpacing:
|
|
24
|
+
nodeSpacing: 64,
|
|
25
|
+
rankSpacing: 72,
|
|
26
|
+
fontSize: 15,
|
|
26
27
|
},
|
|
27
28
|
flowchart: {
|
|
28
29
|
curve: 'basis',
|
|
29
|
-
padding:
|
|
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,
|
|
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
|
-
<
|
|
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
|
+
}
|