aeon-ui-engine 1.3.0 → 1.3.5

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 (80) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/package.json +7 -2
  3. package/packages/react/src/combobox/index.tsx +13 -8
  4. package/packages/react/src/tooltip/index.tsx +48 -22
  5. package/packages/schemas/dist/index.d.ts +69 -24
  6. package/packages/schemas/dist/index.js +447 -49
  7. package/packages/schemas/json/appNav.json +146 -0
  8. package/packages/schemas/json/appShell.json +151 -0
  9. package/packages/schemas/json/avatar.json +130 -0
  10. package/packages/schemas/json/bar.json +126 -0
  11. package/packages/schemas/json/catalog.json +3163 -15
  12. package/packages/schemas/json/combobox.json +19 -7
  13. package/packages/schemas/json/composer.json +125 -0
  14. package/packages/schemas/json/content.json +167 -0
  15. package/packages/schemas/json/conversation.json +166 -0
  16. package/packages/schemas/json/entry.json +182 -0
  17. package/packages/schemas/json/identity.json +147 -0
  18. package/packages/schemas/json/listRow.json +131 -0
  19. package/packages/schemas/json/metricStrip.json +132 -0
  20. package/packages/schemas/json/nav.json +136 -0
  21. package/packages/schemas/json/panel.json +143 -0
  22. package/packages/schemas/json/pinInput.json +112 -0
  23. package/packages/schemas/json/profileHeader.json +138 -0
  24. package/packages/schemas/json/prompt.json +155 -0
  25. package/packages/schemas/json/radioGroup.json +130 -0
  26. package/packages/schemas/json/separator.json +105 -0
  27. package/packages/schemas/json/slider.json +147 -0
  28. package/packages/schemas/json/statusBanner.json +149 -0
  29. package/packages/schemas/json/stickyBar.json +153 -0
  30. package/packages/schemas/json/thread.json +129 -0
  31. package/packages/schemas/json/tooltip.json +21 -7
  32. package/packages/schemas/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  33. package/packages/schemas/prompts/cursorrules.md +6 -4
  34. package/packages/schemas/prompts/statecharts.md +23 -2
  35. package/packages/schemas/prompts/system.md +2 -2
  36. package/packages/schemas/registry/catalog.json +295 -4
  37. package/packages/schemas/registry/components/appNav.json +146 -0
  38. package/packages/schemas/registry/components/appShell.json +151 -0
  39. package/packages/schemas/registry/components/avatar.json +130 -0
  40. package/packages/schemas/registry/components/bar.json +126 -0
  41. package/packages/schemas/registry/components/combobox.json +19 -7
  42. package/packages/schemas/registry/components/composer.json +125 -0
  43. package/packages/schemas/registry/components/content.json +167 -0
  44. package/packages/schemas/registry/components/conversation.json +166 -0
  45. package/packages/schemas/registry/components/entry.json +182 -0
  46. package/packages/schemas/registry/components/identity.json +147 -0
  47. package/packages/schemas/registry/components/listRow.json +131 -0
  48. package/packages/schemas/registry/components/metricStrip.json +132 -0
  49. package/packages/schemas/registry/components/nav.json +136 -0
  50. package/packages/schemas/registry/components/panel.json +143 -0
  51. package/packages/schemas/registry/components/pinInput.json +112 -0
  52. package/packages/schemas/registry/components/profileHeader.json +138 -0
  53. package/packages/schemas/registry/components/prompt.json +155 -0
  54. package/packages/schemas/registry/components/radioGroup.json +130 -0
  55. package/packages/schemas/registry/components/separator.json +105 -0
  56. package/packages/schemas/registry/components/slider.json +147 -0
  57. package/packages/schemas/registry/components/statusBanner.json +149 -0
  58. package/packages/schemas/registry/components/stickyBar.json +153 -0
  59. package/packages/schemas/registry/components/thread.json +129 -0
  60. package/packages/schemas/registry/components/tooltip.json +21 -7
  61. package/packages/schemas/registry/machines/accordion.json +58 -0
  62. package/packages/schemas/registry/machines/appNav.json +108 -0
  63. package/packages/schemas/registry/machines/appShell.json +128 -0
  64. package/packages/schemas/registry/machines/contentRegion.json +314 -0
  65. package/packages/schemas/registry/machines/panel.json +131 -0
  66. package/packages/schemas/registry/machines/popover.json +143 -0
  67. package/packages/schemas/registry/machines/slider.json +151 -0
  68. package/packages/schemas/registry/machines/stickyBar.json +261 -0
  69. package/packages/schemas/registry/machines/tabs.json +58 -0
  70. package/packages/schemas/registry/machines/toast.json +89 -0
  71. package/packages/schemas/registry/machines/toggle.json +134 -0
  72. package/packages/schemas/scripts/emit.ts +23 -0
  73. package/packages/schemas/src/components.ts +429 -6
  74. package/packages/schemas/src/index.test.ts +83 -0
  75. package/packages/schemas/src/index.ts +1 -0
  76. package/packages/schemas/src/machine-id.ts +7 -0
  77. package/packages/schemas/src/prompts.ts +25 -4
  78. package/packages/schemas/src/registry.ts +28 -39
  79. package/scripts/bump-version.mjs +93 -0
  80. package/scripts/require-version-bump.mjs +70 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.5] - 2026-07-31
4
+
5
+ ### Added
6
+
7
+ - Layout schemas for Instant/agent surfaces: identity, profileHeader, metricStrip, listRow, entry, conversation (38 total schemas).
8
+
9
+ ### Fixed
10
+
11
+ - **Tooltip open/closed** — uses `popoverMachine` like Popover/Select/Combobox; openDelay / closeDelay / touchDuration stay React-local.
12
+ - Agent prompts and MACHINES/COMPONENTS/FILE_MAP now treat Tooltip as popover-family.
13
+
14
+ ## [1.3.4] - 2026-07-31
15
+
16
+ ### Fixed
17
+
18
+ - Instant/Build no longer shows chart-only stubs like “States: idle · discover · … Project faces in a second pass.” — projects concept/prompt faces while keeping the authored chart.
19
+
20
+ ## [1.3.3] - 2026-07-31
21
+
22
+ ### Fixed
23
+
24
+ - **Agent registry lag** — runtime `registry/catalog.json` now derives from `componentSchemas` (was stuck at 4 entries while schemas existed).
25
+ - **Machine emit coverage** — schema emit writes all 15 primitives machines (was only async/button/dialog/field), unlocking `validEvents` trees for popover family, slider, shells, etc.
26
+ - **Combobox open/closed** — uses `popoverMachine` like Select; query/highlight stay React-local.
27
+ - Stale docs claiming Select/Combobox were pure `useState`; checklist now requires schema + emit steps.
28
+
29
+ ### Added
30
+
31
+ - Component schemas for machine-backed and high-traffic surfaces: radioGroup, slider, content, panel, appShell, stickyBar, nav, appNav, prompt, statusBanner, pinInput, avatar, bar, separator, composer, thread (32 total).
32
+
33
+ ## [1.3.2] - 2026-07-31
34
+
35
+ ### Changed
36
+
37
+ - Restore state-first landing messaging (remove BETA chrome from hero, meta, and builder).
38
+
39
+ ## [1.3.1] - 2026-07-30
40
+
41
+ ### Changed
42
+
43
+ - Describe this release.
44
+
3
45
  All notable changes to **aeon-ui-engine** are documented here.
4
46
 
5
47
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aeon-ui-engine",
3
- "version": "1.3.0",
3
+ "version": "1.3.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,12 @@
35
35
  "test:headless": "pnpm run build:headless && pnpm --filter @aeon-ui/core --filter @aeon-ui/primitives --filter @aeon-ui/react run test",
36
36
  "changeset": "changeset",
37
37
  "version-packages": "changeset version",
38
- "release": "pnpm build && changeset publish"
38
+ "release": "pnpm build && changeset publish",
39
+ "version:patch": "node scripts/bump-version.mjs patch",
40
+ "version:minor": "node scripts/bump-version.mjs minor",
41
+ "version:major": "node scripts/bump-version.mjs major",
42
+ "version:push": "node scripts/bump-version.mjs patch --push",
43
+ "version:check": "node scripts/require-version-bump.mjs"
39
44
  },
40
45
  "devDependencies": {
41
46
  "@changesets/cli": "^2.29.0",
@@ -1,4 +1,5 @@
1
1
  import { comboboxAnatomy, partAttrs, partOnlyAttrs } from '@aeon-ui/core'
2
+ import { popoverMachine } from '@aeon-ui/primitives'
2
3
  import {
3
4
  createContext,
4
5
  forwardRef,
@@ -18,6 +19,7 @@ import {
18
19
  type MouseEvent,
19
20
  type ReactNode,
20
21
  } from 'react'
22
+ import { useAeonMachine } from '../hooks/use-aeon-machine.js'
21
23
  import { mergeProps } from '../utils/merge-props.js'
22
24
 
23
25
  interface RegisteredItem {
@@ -73,23 +75,27 @@ const Root = forwardRef<HTMLDivElement, ComboboxRootProps>(function ComboboxRoot
73
75
  { value, onValueChange, children, className, disabled },
74
76
  ref,
75
77
  ) {
76
- const [open, setOpenState] = useState(false)
78
+ const [snapshot, send] = useAeonMachine(popoverMachine, { input: { open: false } })
77
79
  const [query, setQuery] = useState('')
78
80
  const [highlightedValue, setHighlightedValue] = useState<string | null>(null)
79
81
  const [itemsVersion, setItemsVersion] = useState(0)
80
82
  const itemsRef = useRef<RegisteredItem[]>([])
81
83
  const listboxId = useId()
82
84
 
85
+ const open = disabled ? false : snapshot.matches('open')
86
+
83
87
  const setOpen = useCallback(
84
88
  (next: boolean) => {
85
89
  if (disabled) return
86
- setOpenState(next)
87
- if (!next) {
88
- setQuery('')
89
- setHighlightedValue(null)
90
+ if (next) {
91
+ send({ type: 'OPEN' })
92
+ return
90
93
  }
94
+ send({ type: 'CLOSE' })
95
+ setQuery('')
96
+ setHighlightedValue(null)
91
97
  },
92
- [disabled],
98
+ [disabled, send],
93
99
  )
94
100
 
95
101
  const registerItem = useCallback((item: RegisteredItem) => {
@@ -107,7 +113,7 @@ const Root = forwardRef<HTMLDivElement, ComboboxRootProps>(function ComboboxRoot
107
113
  const ctx = useMemo(
108
114
  () => ({
109
115
  value,
110
- open: disabled ? false : open,
116
+ open,
111
117
  query,
112
118
  listboxId,
113
119
  highlightedValue,
@@ -132,7 +138,6 @@ const Root = forwardRef<HTMLDivElement, ComboboxRootProps>(function ComboboxRoot
132
138
  registerItem,
133
139
  unregisterItem,
134
140
  getItems,
135
- disabled,
136
141
  ],
137
142
  )
138
143
 
@@ -1,7 +1,9 @@
1
1
  import { tooltipAnatomy, partAttrs } from '@aeon-ui/core'
2
+ import { popoverMachine } from '@aeon-ui/primitives'
2
3
  import {
3
4
  createContext,
4
5
  forwardRef,
6
+ useCallback,
5
7
  useContext,
6
8
  useEffect,
7
9
  useId,
@@ -15,6 +17,7 @@ import {
15
17
  type ReactNode,
16
18
  } from 'react'
17
19
  import { FloatingPositioner } from '../floating/FloatingPositioner.js'
20
+ import { useAeonMachine } from '../hooks/use-aeon-machine.js'
18
21
  import { useOutsideClick } from '../hooks/use-outside-click.js'
19
22
  import { usePrefersHover } from '../hooks/use-prefers-hover.js'
20
23
  import { mergeProps } from '../utils/merge-props.js'
@@ -76,8 +79,10 @@ const Root = forwardRef<HTMLDivElement, TooltipRootProps>(function TooltipRoot(
76
79
  },
77
80
  ref,
78
81
  ) {
79
- const [uncontrolled, setUncontrolled] = useState(defaultOpen)
80
- const resolvedOpen = open ?? uncontrolled
82
+ const [snapshot, send] = useAeonMachine(popoverMachine, {
83
+ input: { open: defaultOpen },
84
+ })
85
+ const resolvedOpen = open ?? snapshot.matches('open')
81
86
  const showTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
82
87
  const hideTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
83
88
  const triggerRef = useRef<HTMLSpanElement>(null)
@@ -87,6 +92,10 @@ const Root = forwardRef<HTMLDivElement, TooltipRootProps>(function TooltipRoot(
87
92
  const prefersHover = usePrefersHover()
88
93
  const [outsideClickEnabled, setOutsideClickEnabled] = useState(false)
89
94
 
95
+ useEffect(() => {
96
+ if (open !== undefined) send({ type: 'SET_OPEN', open })
97
+ }, [open, send])
98
+
90
99
  useEffect(() => {
91
100
  if (!resolvedOpen || prefersHover) {
92
101
  setOutsideClickEnabled(false)
@@ -97,52 +106,57 @@ const Root = forwardRef<HTMLDivElement, TooltipRootProps>(function TooltipRoot(
97
106
  return () => window.clearTimeout(id)
98
107
  }, [resolvedOpen, prefersHover, touchOutsideGraceMs])
99
108
 
100
- const setOpen = (next: boolean) => {
101
- if (open === undefined) setUncontrolled(next)
102
- onOpenChange?.(next)
103
- }
109
+ const setOpen = useCallback(
110
+ (next: boolean) => {
111
+ if (open === undefined) send({ type: next ? 'OPEN' : 'CLOSE' })
112
+ onOpenChange?.(next)
113
+ },
114
+ [open, send, onOpenChange],
115
+ )
104
116
 
105
117
  useEffect(() => {
106
118
  onOpenChange?.(resolvedOpen)
107
119
  }, [resolvedOpen, onOpenChange])
108
120
 
109
- const hideNow = () => {
121
+ const hideNow = useCallback(() => {
110
122
  if (showTimer.current !== undefined) clearTimeout(showTimer.current)
111
123
  if (hideTimer.current !== undefined) clearTimeout(hideTimer.current)
112
124
  setOpen(false)
113
- }
125
+ }, [setOpen])
114
126
 
115
- const showImmediately = () => {
127
+ const showImmediately = useCallback(() => {
116
128
  if (showTimer.current !== undefined) clearTimeout(showTimer.current)
117
129
  if (hideTimer.current !== undefined) clearTimeout(hideTimer.current)
118
130
  setOpen(true)
119
- if (!prefersHover) {
120
- if (touchDurationMs > 0) {
121
- hideTimer.current = setTimeout(() => hideNow(), touchDurationMs)
122
- }
131
+ if (!prefersHover && touchDurationMs > 0) {
132
+ hideTimer.current = setTimeout(() => hideNow(), touchDurationMs)
123
133
  }
124
- }
134
+ }, [setOpen, prefersHover, touchDurationMs, hideNow])
125
135
 
126
- const scheduleShow = () => {
136
+ const scheduleShow = useCallback(() => {
127
137
  if (hideTimer.current !== undefined) clearTimeout(hideTimer.current)
128
138
  showTimer.current = setTimeout(() => setOpen(true), openDelay)
129
- }
139
+ }, [setOpen, openDelay])
130
140
 
131
- const scheduleHide = () => {
141
+ const scheduleHide = useCallback(() => {
132
142
  if (showTimer.current !== undefined) clearTimeout(showTimer.current)
133
143
  if (closeDelay <= 0) {
134
144
  setOpen(false)
135
145
  return
136
146
  }
137
147
  hideTimer.current = setTimeout(() => setOpen(false), closeDelay)
138
- }
148
+ }, [setOpen, closeDelay])
139
149
 
140
- const toggleTouch = () => {
150
+ const toggleTouch = useCallback(() => {
141
151
  if (resolvedOpen) hideNow()
142
152
  else showImmediately()
143
- }
153
+ }, [resolvedOpen, hideNow, showImmediately])
144
154
 
145
- useOutsideClick([triggerRef, positionerRef], resolvedOpen && !prefersHover && outsideClickEnabled, hideNow)
155
+ useOutsideClick(
156
+ [triggerRef, positionerRef],
157
+ resolvedOpen && !prefersHover && outsideClickEnabled,
158
+ hideNow,
159
+ )
146
160
 
147
161
  const value = useMemo(
148
162
  () => ({
@@ -160,7 +174,19 @@ const Root = forwardRef<HTMLDivElement, TooltipRootProps>(function TooltipRoot(
160
174
  showOnFocus,
161
175
  prefersHover,
162
176
  }),
163
- [resolvedOpen, triggerId, contentId, openDelay, closeDelay, touchDurationMs, touchOutsideGraceMs, showOnFocus, prefersHover],
177
+ [
178
+ resolvedOpen,
179
+ setOpen,
180
+ triggerId,
181
+ contentId,
182
+ scheduleShow,
183
+ scheduleHide,
184
+ showImmediately,
185
+ hideNow,
186
+ toggleTouch,
187
+ showOnFocus,
188
+ prefersHover,
189
+ ],
164
190
  )
165
191
 
166
192
  return (
@@ -35,6 +35,28 @@ declare const componentSchemas: {
35
35
  readonly toast: JsonSchema;
36
36
  readonly scroll: JsonSchema;
37
37
  readonly progress: JsonSchema;
38
+ readonly radioGroup: JsonSchema;
39
+ readonly slider: JsonSchema;
40
+ readonly pinInput: JsonSchema;
41
+ readonly avatar: JsonSchema;
42
+ readonly content: JsonSchema;
43
+ readonly panel: JsonSchema;
44
+ readonly appShell: JsonSchema;
45
+ readonly stickyBar: JsonSchema;
46
+ readonly bar: JsonSchema;
47
+ readonly nav: JsonSchema;
48
+ readonly appNav: JsonSchema;
49
+ readonly prompt: JsonSchema;
50
+ readonly statusBanner: JsonSchema;
51
+ readonly separator: JsonSchema;
52
+ readonly composer: JsonSchema;
53
+ readonly thread: JsonSchema;
54
+ readonly identity: JsonSchema;
55
+ readonly profileHeader: JsonSchema;
56
+ readonly metricStrip: JsonSchema;
57
+ readonly listRow: JsonSchema;
58
+ readonly entry: JsonSchema;
59
+ readonly conversation: JsonSchema;
38
60
  };
39
61
  type ComponentSchemaId = keyof typeof componentSchemas;
40
62
  declare const catalog: {
@@ -63,6 +85,28 @@ declare const catalog: {
63
85
  readonly toast: JsonSchema;
64
86
  readonly scroll: JsonSchema;
65
87
  readonly progress: JsonSchema;
88
+ readonly radioGroup: JsonSchema;
89
+ readonly slider: JsonSchema;
90
+ readonly pinInput: JsonSchema;
91
+ readonly avatar: JsonSchema;
92
+ readonly content: JsonSchema;
93
+ readonly panel: JsonSchema;
94
+ readonly appShell: JsonSchema;
95
+ readonly stickyBar: JsonSchema;
96
+ readonly bar: JsonSchema;
97
+ readonly nav: JsonSchema;
98
+ readonly appNav: JsonSchema;
99
+ readonly prompt: JsonSchema;
100
+ readonly statusBanner: JsonSchema;
101
+ readonly separator: JsonSchema;
102
+ readonly composer: JsonSchema;
103
+ readonly thread: JsonSchema;
104
+ readonly identity: JsonSchema;
105
+ readonly profileHeader: JsonSchema;
106
+ readonly metricStrip: JsonSchema;
107
+ readonly listRow: JsonSchema;
108
+ readonly entry: JsonSchema;
109
+ readonly conversation: JsonSchema;
66
110
  };
67
111
  };
68
112
 
@@ -70,14 +114,18 @@ declare const catalog: {
70
114
  * Statecharts packaged as system-prompt fragments for AI coding agents.
71
115
  * Embed before code generation so agents cannot invent impossible UI states.
72
116
  */
73
- declare const AEON_SYSTEM_PROMPT = "# Aeon UI \u2014 agent system prompt\n\nYou are building UI with **Aeon UI**, a React component library powered by finite statecharts.\n\n## Order of work (mandatory)\n1. **Build the state machines first** \u2014 name every lifecycle the UX needs (states + events). Prefer machines from `@aeon-ui/primitives` (or documented prop projections such as Button `status`).\n2. **Then project UI from those machines** \u2014 compound parts, copy, and layout exist only to reflect the chart. Never invent UI for states that are not in a machine.\n3. **UI = f(state)** \u2014 the DOM exposes `data-aeon-scope`, `data-aeon-part`, `data-aeon-state`. Style targets those attributes. Do not drive the same concern with parallel React `useState` flags.\n\n## Non-negotiable rules\n1. Do not duplicate open/checked/lifecycle in `useState` when a machine exists in `@aeon-ui/primitives`.\n2. **Button `status` is a prop** (`idle|pending|success|failure|disabled`). Optional: drive it from `buttonLifecycleMachine` via `useAeonMachine` in app code.\n3. **Select / Menu / Popover** share `popoverMachine` \u2014 never fork another open/closed chart.\n4. **Combobox** and **Tooltip** use React state today \u2014 do not add floating machines without the component checklist.\n5. **Scroll** uses `getScrollSnapshot()` \u2014 no XState machine.\n6. If a machine lists N stable states, the UI must represent all N (totality).\n7. Prefer `@aeon-ui/react` (headless) or `@aeon-ui/ui` (styled). Relative TS imports use `.js` extensions inside the Aeon monorepo only.\n8. Primitives stay **universal** \u2014 never invent niche components (dating, colour-blind test, pong). Compose from generic parts.\n\n## DOM contract\nEvery interactive surface sets anatomy via `partAttrs` from `@aeon-ui/core`:\n- `data-aeon-scope` \u2014 family (`button`, `async`, `field`, \u2026)\n- `data-aeon-part` \u2014 anatomy key (`root`, `trigger`, \u2026)\n- `data-aeon-state` \u2014 allowed snapshot / prop state only\n\n## Before writing JSX\n1. Enumerate machines (or documented status props) for the flow \u2014 states and events.\n2. Read the component JSON Schema from `@aeon-ui/schemas` (or pasted catalog) and match parts to those charts.\n3. Compose with documented compound parts (`Dialog.Root`, `Field.Control`, \u2026).\n4. Wire events to machine events or documented props \u2014 never invent `isLoading && !isError && hasData` spaghetti when a named state exists.\n";
117
+ declare const AEON_SYSTEM_PROMPT = "# Aeon UI \u2014 agent system prompt\n\nYou are building UI with **Aeon UI**, a React component library powered by finite statecharts.\n\n## Order of work (mandatory)\n1. **Build the state machines first** \u2014 name every lifecycle the UX needs (states + events). Prefer machines from `@aeon-ui/primitives` (or documented prop projections such as Button `status`).\n2. **Then project UI from those machines** \u2014 compound parts, copy, and layout exist only to reflect the chart. Never invent UI for states that are not in a machine.\n3. **UI = f(state)** \u2014 the DOM exposes `data-aeon-scope`, `data-aeon-part`, `data-aeon-state`. Style targets those attributes. Do not drive the same concern with parallel React `useState` flags.\n\n## Non-negotiable rules\n1. Do not duplicate open/checked/lifecycle in `useState` when a machine exists in `@aeon-ui/primitives`.\n2. **Button `status` is a prop** (`idle|pending|success|failure|disabled`). Optional: drive it from `buttonLifecycleMachine` via `useAeonMachine` in app code.\n3. **Select / Menu / Popover / Combobox / Tooltip** share `popoverMachine` for open/closed \u2014 never fork another open/closed chart. Combobox keeps query/highlight in React; Tooltip keeps openDelay/closeDelay/touchDuration in React.\n4. **PinInput** digit buffer is React-local today \u2014 do not invent a pin machine without the component checklist.\n5. **Scroll** uses `getScrollSnapshot()` \u2014 no XState machine.\n6. If a machine lists N stable states, the UI must represent all N (totality).\n7. Prefer `@aeon-ui/react` (headless) or `@aeon-ui/ui` (styled). Relative TS imports use `.js` extensions inside the Aeon monorepo only.\n8. Primitives stay **universal** \u2014 never invent niche components (dating, colour-blind test, pong). Compose from generic parts.\n\n## DOM contract\nEvery interactive surface sets anatomy via `partAttrs` from `@aeon-ui/core`:\n- `data-aeon-scope` \u2014 family (`button`, `async`, `field`, \u2026)\n- `data-aeon-part` \u2014 anatomy key (`root`, `trigger`, \u2026)\n- `data-aeon-state` \u2014 allowed snapshot / prop state only\n\n## Before writing JSX\n1. Enumerate machines (or documented status props) for the flow \u2014 states and events.\n2. Read the component JSON Schema from `@aeon-ui/schemas` (or pasted catalog) and match parts to those charts.\n3. Compose with documented compound parts (`Dialog.Root`, `Field.Control`, \u2026).\n4. Wire events to machine events or documented props \u2014 never invent `isLoading && !isError && hasData` spaghetti when a named state exists.\n";
74
118
  declare const STATECHART_PROMPTS: {
75
119
  readonly async: "## Async region statechart\nStates: idle → loading → (success | empty | failure); REFRESH from success/empty/failure; STALE flag while success.\nEvents: FETCH, RESOLVE{data}, REJECT{error}, RESET, STALE, REFRESH.\nRule: Render track segments for idle, loading, success, empty, failure. Never hide empty/failure behind a generic spinner.";
76
120
  readonly field: "## Field parallel statechart\nRegions:\n- interaction: pristine | dirty\n- validation: valid | invalid\n- submission: idle | pending\nEvents: INPUT, BLUR, VALIDATE{valid}, SUBMIT, SUBMIT_DONE, SUBMIT_FAIL, RESET.\nRule: Do not collapse validation + submission into one `error` boolean. Message UI follows validation region; pending follows submission.";
77
121
  readonly button: "## Button lifecycle\nPreferred headless API: `status` prop ∈ idle | pending | success | failure | disabled.\nOptional machine: buttonLifecycleMachine with PRESS / RESOLVE / REJECT / RESET.\nRule: Pending must set aria-busy. Do not use disabled alone to mean \"saving\".";
78
122
  readonly dialog: "## Dialog statechart\nStates: open | closed. Events: OPEN, CLOSE, TOGGLE.\nRule: Backdrop click and Escape are CLOSE transitions. Title/Description are required for a11y when open.";
79
- readonly popoverFamily: "## Popover family (Popover, Menu, Select open state)\nMachine: popoverMachine — states open | closed.\nRule: Reuse this chart. Never create selectOpenMachine / menuOpenMachine forks.";
123
+ readonly popoverFamily: "## Popover family (Popover, Menu, Select, Combobox, Tooltip open state)\nMachine: popoverMachine — states open | closed.\nRule: Reuse this chart. Never create selectOpenMachine / menuOpenMachine / comboboxOpenMachine / tooltipOpenMachine forks.\nCombobox: query + highlight stay React-local; open/closed must still be popoverMachine.\nTooltip: openDelay / closeDelay / touchDuration stay React-local; open/closed must still be popoverMachine.";
80
124
  readonly toggle: "## Switch / Checkbox\nMachine: toggleMachine — checked | unchecked. Events: TOGGLE, CHECK, UNCHECK.\nRule: Hidden input stays in sync with snapshot for forms.";
125
+ readonly slider: "## Slider statechart\nMachine: sliderMachine — idle | dragging; value/min/max/step in context.\nEvents: SET_VALUE, STEP, POINTER_DOWN, POINTER_UP, HOME, END.\nRule: Disabled blocks SET_VALUE / drag; project idle vs dragging on data-aeon-state.";
126
+ readonly contentRegion: "## Content region statechart\nMachine: contentRegionMachine — idle → pending → (empty | error | ready) → loadingMore | success.\nEvents: LOAD, RESOLVE, REJECT, RETRY, LOAD_MORE, MORE_DONE, SUCCEED, RESET.\nRule: Every stable state has a slot. Pair with Async for fetch; do not hide empty/error behind a spinner.";
127
+ readonly toast: "## Toast item statechart\nMachine: toastMachine — hidden | visible. Events: SHOW, HIDE, DISMISS.\nRule: Provider list orchestration may use React; each toast item uses the machine.";
128
+ readonly stickyBar: "## StickyBar statechart\nMachine: stickyBarMachine — floating | docked | collapsed | hidden.\nEvents: DOCK, FLOAT, COLLAPSE, EXPAND, HIDE, SHOW, SET_OFFSET.\nRule: DOM scope is bar (bar anatomy zones). Do not invent a parallel sticky useState.";
81
129
  };
82
130
  /** Checkout-form example used on the landing "AI playground" proof. */
83
131
  declare const GENERATIVE_UI_EXAMPLE: {
@@ -247,6 +295,8 @@ type AgentEventBridge = ReturnType<typeof createAgentEventBridge>;
247
295
  * Fetch at runtime: GET https://aeon-ui.com/registry/catalog.json
248
296
  * Per component: GET https://aeon-ui.com/registry/components/{id}.json
249
297
  * Machines: GET https://aeon-ui.com/registry/machines/{id}.json
298
+ *
299
+ * Components are derived from `componentSchemas` — do not hand-maintain a parallel list.
250
300
  */
251
301
  type RegistryEntry = {
252
302
  id: string;
@@ -259,29 +309,24 @@ type RegistryEntry = {
259
309
  };
260
310
  declare const REGISTRY_BASE: "https://aeon-ui.com/registry";
261
311
  declare const registryCatalog: {
262
- readonly $id: "https://aeon-ui.com/registry/catalog.json";
263
- readonly version: "0.1.0";
264
- readonly principle: "UI = f(state)";
265
- readonly description: "Lightweight runtime registry — fetch Aeon component schemas and state-tree JSON on demand instead of bundling every primitive.";
266
- readonly endpoints: {
267
- readonly catalog: "https://aeon-ui.com/registry/catalog.json";
268
- readonly component: "https://aeon-ui.com/registry/components/{id}.json";
269
- readonly machine: "https://aeon-ui.com/registry/machines/{id}.json";
312
+ $id: string;
313
+ version: string;
314
+ principle: string;
315
+ description: string;
316
+ endpoints: {
317
+ catalog: string;
318
+ component: string;
319
+ machine: string;
270
320
  };
271
- readonly components: {
272
- id: string;
273
- title: string;
274
- scope: string;
275
- schemaUrl: string;
276
- machineUrl: string;
277
- runtime: string;
278
- description: string;
279
- }[];
280
- readonly client: {
281
- readonly fetchCatalog: "fetch('https://aeon-ui.com/registry/catalog.json').then(r => r.json())";
282
- readonly fetchComponent: "id => fetch(`https://aeon-ui.com/registry/components/${id}.json`).then(r => r.json())";
283
- readonly fetchMachine: "id => fetch(`https://aeon-ui.com/registry/machines/${id}.json`).then(r => r.json())";
321
+ components: RegistryEntry[];
322
+ client: {
323
+ fetchCatalog: string;
324
+ fetchComponent: string;
325
+ fetchMachine: string;
284
326
  };
285
327
  };
286
328
 
287
- export { AEON_SYSTEM_PROMPT, type AeonMachineSchema, type AeonSnapshotSchema, type AeonStateTreeNode, type AgentBridgeOptions, type AgentEventBridge, type AgentEventMap, type AgentStreamEvent, CURSOR_RULES_SNIPPET, type ComponentSchemaId, GENERATIVE_UI_EXAMPLE, type JsonSchema, REGISTRY_BASE, type RegistryEntry, STATECHART_PROMPTS, aeonInitialAgentContext, aeonSnapshotSchema, aeonToPrompt, aeonToSchema, catalog, componentSchema, componentSchemas, createAgentEventBridge, registryCatalog };
329
+ /** Map component schema `machine` export names → registry/machines/{id}.json ids. */
330
+ declare function machineRegistryId(machine: string | null | undefined): string | undefined;
331
+
332
+ export { AEON_SYSTEM_PROMPT, type AeonMachineSchema, type AeonSnapshotSchema, type AeonStateTreeNode, type AgentBridgeOptions, type AgentEventBridge, type AgentEventMap, type AgentStreamEvent, CURSOR_RULES_SNIPPET, type ComponentSchemaId, GENERATIVE_UI_EXAMPLE, type JsonSchema, REGISTRY_BASE, type RegistryEntry, STATECHART_PROMPTS, aeonInitialAgentContext, aeonSnapshotSchema, aeonToPrompt, aeonToSchema, catalog, componentSchema, componentSchemas, createAgentEventBridge, machineRegistryId, registryCatalog };