aeon-ui-engine 1.3.1 → 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 (78) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +1 -1
  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
@@ -278,23 +278,25 @@ var componentSchemas = {
278
278
  combobox: componentSchema({
279
279
  id: "https://aeon-ui.com/schemas/combobox.json",
280
280
  title: "Combobox",
281
- description: "Typeahead \u2014 React useState for open/query/highlight today. Do not add a duplicate floating machine without COMPONENT_CHECKLIST.",
281
+ description: "Open/closed via popoverMachine (same family as Select/Menu/Popover). Query, highlight, and item registry stay React-local for typeahead.",
282
282
  scope: "combobox",
283
283
  parts: ["root", "input", "icon", "content", "item", "empty"],
284
284
  states: ["open", "closed"],
285
- machine: null,
286
- runtime: "useState",
285
+ machine: "popoverMachine",
286
+ runtime: "useAeonMachine",
287
+ events: ["OPEN", "CLOSE", "TOGGLE", "ESCAPE", "POINTER_DOWN_OUTSIDE"],
287
288
  slots: { Root: "combobox.root", Input: "combobox.input", Content: "combobox.content", Item: "combobox.item" }
288
289
  }),
289
290
  tooltip: componentSchema({
290
291
  id: "https://aeon-ui.com/schemas/tooltip.json",
291
292
  title: "Tooltip",
292
- description: "Open via React useState. Touch tap toggles.",
293
+ description: "Open/closed via popoverMachine (same family as Popover/Select/Combobox). openDelay / closeDelay / touchDuration stay React-local.",
293
294
  scope: "tooltip",
294
295
  parts: ["root", "trigger", "positioner", "content", "arrow"],
295
296
  states: ["open", "closed"],
296
- machine: null,
297
- runtime: "useState",
297
+ machine: "popoverMachine",
298
+ runtime: "useAeonMachine",
299
+ events: ["OPEN", "CLOSE", "TOGGLE", "SET_OPEN", "ESCAPE", "POINTER_DOWN_OUTSIDE"],
298
300
  slots: { Root: "tooltip.root", Trigger: "tooltip.trigger", Content: "tooltip.content" }
299
301
  }),
300
302
  toast: componentSchema({
@@ -340,6 +342,398 @@ var componentSchemas = {
340
342
  indeterminate: { type: "boolean" }
341
343
  },
342
344
  slots: { Root: "progress.root", Track: "progress.track", Range: "progress.range", Label: "progress.label" }
345
+ }),
346
+ radioGroup: componentSchema({
347
+ id: "https://aeon-ui.com/schemas/radioGroup.json",
348
+ title: "RadioGroup",
349
+ description: "Single selection via tabsMachine (same chart family as Tabs/Nav).",
350
+ scope: "radioGroup",
351
+ parts: ["root", "item", "itemControl", "itemIndicator", "itemLabel"],
352
+ states: ["selected"],
353
+ machine: "tabsMachine",
354
+ runtime: "useAeonMachine",
355
+ events: ["SELECT"],
356
+ slots: {
357
+ Root: "radioGroup.root",
358
+ Item: "radioGroup.item",
359
+ ItemControl: "radioGroup.itemControl",
360
+ ItemLabel: "radioGroup.itemLabel"
361
+ }
362
+ }),
363
+ slider: componentSchema({
364
+ id: "https://aeon-ui.com/schemas/slider.json",
365
+ title: "Slider",
366
+ description: "Range control via sliderMachine \u2014 idle | dragging plus numeric value in context.",
367
+ scope: "slider",
368
+ parts: ["root", "track", "range", "thumb", "valueText"],
369
+ states: ["idle", "dragging"],
370
+ machine: "sliderMachine",
371
+ runtime: "useAeonMachine",
372
+ events: ["SET_VALUE", "STEP", "POINTER_DOWN", "POINTER_UP", "HOME", "END"],
373
+ slots: {
374
+ Root: "slider.root",
375
+ Track: "slider.track",
376
+ Range: "slider.range",
377
+ Thumb: "slider.thumb",
378
+ ValueText: "slider.valueText"
379
+ }
380
+ }),
381
+ pinInput: componentSchema({
382
+ id: "https://aeon-ui.com/schemas/pinInput.json",
383
+ title: "PinInput",
384
+ description: "OTP / PIN cells \u2014 React state for digit buffer; projects idle | complete on root.",
385
+ scope: "pinInput",
386
+ parts: ["root", "input"],
387
+ states: ["idle", "complete"],
388
+ machine: null,
389
+ runtime: "useState",
390
+ slots: { Root: "pinInput.root", Input: "pinInput.input" }
391
+ }),
392
+ avatar: componentSchema({
393
+ id: "https://aeon-ui.com/schemas/avatar.json",
394
+ title: "Avatar",
395
+ description: "Image load lifecycle in React; badge presence is a prop projection.",
396
+ scope: "avatar",
397
+ parts: ["root", "image", "fallback", "badge"],
398
+ states: ["idle", "loading", "loaded", "error"],
399
+ machine: null,
400
+ runtime: "useState",
401
+ slots: {
402
+ Root: "avatar.root",
403
+ Image: "avatar.image",
404
+ Fallback: "avatar.fallback",
405
+ Badge: "avatar.badge"
406
+ }
407
+ }),
408
+ content: componentSchema({
409
+ id: "https://aeon-ui.com/schemas/content.json",
410
+ title: "Content",
411
+ description: "Status-slotted body via contentRegionMachine (or Root state prop projection). Pair with Async for fetch.",
412
+ scope: "content",
413
+ parts: ["root", "toolbar", "body", "pending", "empty", "error", "success", "sentinel"],
414
+ states: ["idle", "pending", "empty", "error", "ready", "loadingMore", "success"],
415
+ machine: "contentRegionMachine",
416
+ runtime: "useAeonMachine",
417
+ events: ["LOAD", "RESOLVE", "REJECT", "RETRY", "LOAD_MORE", "MORE_DONE", "SUCCEED", "RESET"],
418
+ slots: {
419
+ Root: "content.root",
420
+ Pending: "content.pending",
421
+ Empty: "content.empty",
422
+ Error: "content.error",
423
+ Success: "content.success"
424
+ }
425
+ }),
426
+ panel: componentSchema({
427
+ id: "https://aeon-ui.com/schemas/panel.json",
428
+ title: "Panel",
429
+ description: "Collapsible layout region via panelMachine \u2014 expanded | collapsed.",
430
+ scope: "panel",
431
+ parts: ["group", "root", "trigger", "label", "content"],
432
+ states: ["expanded", "collapsed"],
433
+ machine: "panelMachine",
434
+ runtime: "useAeonMachine",
435
+ events: ["EXPAND", "COLLAPSE", "TOGGLE", "SET_EXPANDED"],
436
+ slots: {
437
+ Group: "panel.group",
438
+ Root: "panel.root",
439
+ Trigger: "panel.trigger",
440
+ Label: "panel.label",
441
+ Content: "panel.content"
442
+ }
443
+ }),
444
+ appShell: componentSchema({
445
+ id: "https://aeon-ui.com/schemas/appShell.json",
446
+ title: "AppShell",
447
+ description: "Application chrome frame via appShellMachine \u2014 idle | overlayOpen (+ dockVisible).",
448
+ scope: "appShell",
449
+ parts: ["root", "header", "subheader", "content", "aside", "footer", "dock", "scrim"],
450
+ states: ["idle", "overlayOpen"],
451
+ machine: "appShellMachine",
452
+ runtime: "useAeonMachine",
453
+ events: ["OPEN_OVERLAY", "CLOSE_OVERLAY", "SHOW_DOCK", "HIDE_DOCK", "SET_DOCK"],
454
+ slots: {
455
+ Root: "appShell.root",
456
+ Header: "appShell.header",
457
+ Content: "appShell.content",
458
+ Dock: "appShell.dock",
459
+ Scrim: "appShell.scrim"
460
+ }
461
+ }),
462
+ stickyBar: componentSchema({
463
+ id: "https://aeon-ui.com/schemas/stickyBar.json",
464
+ title: "StickyBar",
465
+ description: "Sticky/fixed chrome band via stickyBarMachine. DOM scope is bar (reuses bar anatomy zones).",
466
+ scope: "bar",
467
+ parts: ["root", "leading", "center", "trailing", "seam"],
468
+ states: ["floating", "docked", "collapsed", "hidden"],
469
+ machine: "stickyBarMachine",
470
+ runtime: "useAeonMachine",
471
+ events: ["DOCK", "FLOAT", "COLLAPSE", "EXPAND", "HIDE", "SHOW", "SET_OFFSET"],
472
+ slots: {
473
+ Root: "bar.root",
474
+ Leading: "bar.leading",
475
+ Center: "bar.center",
476
+ Trailing: "bar.trailing",
477
+ Seam: "bar.seam"
478
+ }
479
+ }),
480
+ bar: componentSchema({
481
+ id: "https://aeon-ui.com/schemas/bar.json",
482
+ title: "Bar",
483
+ description: "Three-zone toolbar layout (leading / center / trailing / seam). Sticky lifecycle uses StickyBar + stickyBarMachine.",
484
+ scope: "bar",
485
+ parts: ["root", "leading", "center", "trailing", "seam"],
486
+ states: ["idle"],
487
+ machine: null,
488
+ runtime: "layout",
489
+ slots: {
490
+ Root: "bar.root",
491
+ Leading: "bar.leading",
492
+ Center: "bar.center",
493
+ Trailing: "bar.trailing"
494
+ }
495
+ }),
496
+ nav: componentSchema({
497
+ id: "https://aeon-ui.com/schemas/nav.json",
498
+ title: "Nav",
499
+ description: "Navigational collection via tabsMachine; items project inactive | active | disabled.",
500
+ scope: "nav",
501
+ parts: ["root", "item", "indicator", "label", "icon", "badge"],
502
+ states: ["inactive", "active", "disabled"],
503
+ machine: "tabsMachine",
504
+ runtime: "useAeonMachine",
505
+ events: ["SELECT"],
506
+ slots: { Root: "nav.root", Item: "nav.item", Label: "nav.label", Icon: "nav.icon" }
507
+ }),
508
+ appNav: componentSchema({
509
+ id: "https://aeon-ui.com/schemas/appNav.json",
510
+ title: "AppNav",
511
+ description: "Section + detail stack via appNavMachine \u2014 list\u2192detail, settings drill-in.",
512
+ scope: "appNav",
513
+ parts: ["root", "rail", "section", "stage", "breadcrumb", "crumb", "back"],
514
+ states: ["section"],
515
+ machine: "appNavMachine",
516
+ runtime: "useAeonMachine",
517
+ events: ["SET_SECTION", "PUSH", "REPLACE", "POP", "POP_TO", "CLEAR", "RESET"],
518
+ slots: {
519
+ Root: "appNav.root",
520
+ Rail: "appNav.rail",
521
+ Stage: "appNav.stage",
522
+ Back: "appNav.back"
523
+ }
524
+ }),
525
+ prompt: componentSchema({
526
+ id: "https://aeon-ui.com/schemas/prompt.json",
527
+ title: "Prompt",
528
+ description: "Confirm / permission dialog composed on Dialog. Open/closed via dialogMachine; face via status prop.",
529
+ scope: "prompt",
530
+ parts: ["root", "eyebrow", "meta", "amount", "actions", "primary", "secondary"],
531
+ states: ["pending", "confirming", "dismissed", "confirmed"],
532
+ machine: "dialogMachine",
533
+ runtime: "status prop",
534
+ events: ["OPEN", "CLOSE", "TOGGLE"],
535
+ props: {
536
+ status: {
537
+ type: "string",
538
+ enum: ["pending", "confirming", "dismissed", "confirmed"],
539
+ default: "pending"
540
+ }
541
+ },
542
+ slots: {
543
+ Root: "prompt.root",
544
+ Primary: "prompt.primary",
545
+ Secondary: "prompt.secondary",
546
+ Actions: "prompt.actions"
547
+ }
548
+ }),
549
+ statusBanner: componentSchema({
550
+ id: "https://aeon-ui.com/schemas/statusBanner.json",
551
+ title: "StatusBanner",
552
+ description: "Non-blocking top-of-app notice \u2014 tone + optional status props project to data-aeon-state.",
553
+ scope: "statusBanner",
554
+ parts: ["root", "copy", "title", "body", "actions"],
555
+ states: ["info", "success", "warning", "danger", "neutral"],
556
+ machine: null,
557
+ runtime: "props",
558
+ props: {
559
+ tone: { type: "string", enum: ["info", "success", "warning", "danger", "neutral"] },
560
+ status: { type: "string", description: "Optional secondary token appended to data-aeon-state" }
561
+ },
562
+ slots: {
563
+ Root: "statusBanner.root",
564
+ Title: "statusBanner.title",
565
+ Body: "statusBanner.body",
566
+ Actions: "statusBanner.actions"
567
+ }
568
+ }),
569
+ separator: componentSchema({
570
+ id: "https://aeon-ui.com/schemas/separator.json",
571
+ title: "Separator",
572
+ description: "Static divider \u2014 orientation prop only.",
573
+ scope: "separator",
574
+ parts: ["root"],
575
+ states: ["horizontal", "vertical"],
576
+ machine: null,
577
+ runtime: "props",
578
+ slots: { Root: "separator.root" }
579
+ }),
580
+ composer: componentSchema({
581
+ id: "https://aeon-ui.com/schemas/composer.json",
582
+ title: "Composer",
583
+ description: "Compose chrome \u2014 root state prop idle | sending | disabled | error.",
584
+ scope: "composer",
585
+ parts: ["root", "input", "actions", "send"],
586
+ states: ["idle", "sending", "disabled", "error"],
587
+ machine: null,
588
+ runtime: "props",
589
+ slots: { Root: "composer.root", Input: "composer.input", Send: "composer.send" }
590
+ }),
591
+ thread: componentSchema({
592
+ id: "https://aeon-ui.com/schemas/thread.json",
593
+ title: "Thread",
594
+ description: "Message stream \u2014 item state prop mine | theirs | pending | failed.",
595
+ scope: "thread",
596
+ parts: ["root", "list", "item", "bubble", "meta", "day"],
597
+ states: ["mine", "theirs", "pending", "failed"],
598
+ machine: null,
599
+ runtime: "props",
600
+ slots: { Root: "thread.root", Item: "thread.item", Bubble: "thread.bubble" }
601
+ }),
602
+ identity: componentSchema({
603
+ id: "https://aeon-ui.com/schemas/identity.json",
604
+ title: "Identity",
605
+ description: "Avatar + title + subtitle strip \u2014 presentational layout, not a niche product scope.",
606
+ scope: "identity",
607
+ parts: ["root", "avatar", "title", "subtitle", "meta", "trailing"],
608
+ states: ["idle"],
609
+ machine: null,
610
+ runtime: "layout",
611
+ props: {
612
+ size: { type: "string", enum: ["sm", "md", "lg"] }
613
+ },
614
+ slots: {
615
+ Root: "identity.root",
616
+ Avatar: "identity.avatar",
617
+ Title: "identity.title",
618
+ Subtitle: "identity.subtitle",
619
+ Meta: "identity.meta",
620
+ Trailing: "identity.trailing"
621
+ }
622
+ }),
623
+ profileHeader: componentSchema({
624
+ id: "https://aeon-ui.com/schemas/profileHeader.json",
625
+ title: "ProfileHeader",
626
+ description: "Dense account header \u2014 identity \xB7 metrics \xB7 actions. Universal people chrome.",
627
+ scope: "profileHeader",
628
+ parts: ["root", "media", "identity", "metrics", "actions", "body"],
629
+ states: ["idle"],
630
+ machine: null,
631
+ runtime: "layout",
632
+ slots: {
633
+ Root: "profileHeader.root",
634
+ Media: "profileHeader.media",
635
+ Identity: "profileHeader.identity",
636
+ Metrics: "profileHeader.metrics",
637
+ Actions: "profileHeader.actions",
638
+ Body: "profileHeader.body"
639
+ }
640
+ }),
641
+ metricStrip: componentSchema({
642
+ id: "https://aeon-ui.com/schemas/metricStrip.json",
643
+ title: "MetricStrip",
644
+ description: "Dense value|label chips \u2014 cluster or loose density. Generic stats only.",
645
+ scope: "metricStrip",
646
+ parts: ["root", "chip", "value", "label"],
647
+ states: ["idle"],
648
+ machine: null,
649
+ runtime: "layout",
650
+ props: {
651
+ density: { type: "string", enum: ["cluster", "loose"] }
652
+ },
653
+ slots: {
654
+ Root: "metricStrip.root",
655
+ Chip: "metricStrip.chip",
656
+ Value: "metricStrip.value",
657
+ Label: "metricStrip.label"
658
+ }
659
+ }),
660
+ listRow: componentSchema({
661
+ id: "https://aeon-ui.com/schemas/listRow.json",
662
+ title: "ListRow",
663
+ description: "Settings / menu row \u2014 leading \xB7 label \xB7 trailing. Layout only.",
664
+ scope: "listRow",
665
+ parts: ["root", "leading", "label", "description", "trailing"],
666
+ states: ["idle"],
667
+ machine: null,
668
+ runtime: "layout",
669
+ slots: {
670
+ Root: "listRow.root",
671
+ Leading: "listRow.leading",
672
+ Label: "listRow.label",
673
+ Description: "listRow.description",
674
+ Trailing: "listRow.trailing"
675
+ }
676
+ }),
677
+ entry: componentSchema({
678
+ id: "https://aeon-ui.com/schemas/entry.json",
679
+ title: "Entry",
680
+ description: "Universal multi-value card (feed stack or listing split). Root state idle | selected | muted \u2014 never invent niche scopes.",
681
+ scope: "entry",
682
+ parts: [
683
+ "list",
684
+ "root",
685
+ "header",
686
+ "leading",
687
+ "heading",
688
+ "title",
689
+ "subtitle",
690
+ "meta",
691
+ "media",
692
+ "body",
693
+ "values",
694
+ "value",
695
+ "actions",
696
+ "footer"
697
+ ],
698
+ states: ["idle", "selected", "muted"],
699
+ machine: null,
700
+ runtime: "props",
701
+ props: {
702
+ state: { type: "string", enum: ["idle", "selected", "muted"], default: "idle" },
703
+ density: { type: "string", enum: ["compact", "cozy"] },
704
+ layout: { type: "string", enum: ["stack", "split"] }
705
+ },
706
+ slots: {
707
+ List: "entry.list",
708
+ Root: "entry.root",
709
+ Header: "entry.header",
710
+ Body: "entry.body",
711
+ Actions: "entry.actions",
712
+ Footer: "entry.footer"
713
+ }
714
+ }),
715
+ conversation: componentSchema({
716
+ id: "https://aeon-ui.com/schemas/conversation.json",
717
+ title: "Conversation",
718
+ description: "Inbox / DM list \u2014 item state prop idle | unread | selected. Universal messaging chrome.",
719
+ scope: "conversation",
720
+ parts: ["root", "item", "leading", "body", "title", "preview", "meta", "badge"],
721
+ states: ["idle", "unread", "selected"],
722
+ machine: null,
723
+ runtime: "props",
724
+ props: {
725
+ state: { type: "string", enum: ["idle", "unread", "selected"], default: "idle" }
726
+ },
727
+ slots: {
728
+ Root: "conversation.root",
729
+ Item: "conversation.item",
730
+ Leading: "conversation.leading",
731
+ Body: "conversation.body",
732
+ Title: "conversation.title",
733
+ Preview: "conversation.preview",
734
+ Meta: "conversation.meta",
735
+ Badge: "conversation.badge"
736
+ }
343
737
  })
344
738
  };
345
739
  var catalog = {
@@ -367,8 +761,8 @@ You are building UI with **Aeon UI**, a React component library powered by finit
367
761
  ## Non-negotiable rules
368
762
  1. Do not duplicate open/checked/lifecycle in \`useState\` when a machine exists in \`@aeon-ui/primitives\`.
369
763
  2. **Button \`status\` is a prop** (\`idle|pending|success|failure|disabled\`). Optional: drive it from \`buttonLifecycleMachine\` via \`useAeonMachine\` in app code.
370
- 3. **Select / Menu / Popover** share \`popoverMachine\` \u2014 never fork another open/closed chart.
371
- 4. **Combobox** and **Tooltip** use React state today \u2014 do not add floating machines without the component checklist.
764
+ 3. **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.
765
+ 4. **PinInput** digit buffer is React-local today \u2014 do not invent a pin machine without the component checklist.
372
766
  5. **Scroll** uses \`getScrollSnapshot()\` \u2014 no XState machine.
373
767
  6. If a machine lists N stable states, the UI must represent all N (totality).
374
768
  7. Prefer \`@aeon-ui/react\` (headless) or \`@aeon-ui/ui\` (styled). Relative TS imports use \`.js\` extensions inside the Aeon monorepo only.
@@ -405,12 +799,29 @@ Rule: Pending must set aria-busy. Do not use disabled alone to mean "saving".`,
405
799
  dialog: `## Dialog statechart
406
800
  States: open | closed. Events: OPEN, CLOSE, TOGGLE.
407
801
  Rule: Backdrop click and Escape are CLOSE transitions. Title/Description are required for a11y when open.`,
408
- popoverFamily: `## Popover family (Popover, Menu, Select open state)
802
+ popoverFamily: `## Popover family (Popover, Menu, Select, Combobox, Tooltip open state)
409
803
  Machine: popoverMachine \u2014 states open | closed.
410
- Rule: Reuse this chart. Never create selectOpenMachine / menuOpenMachine forks.`,
804
+ Rule: Reuse this chart. Never create selectOpenMachine / menuOpenMachine / comboboxOpenMachine / tooltipOpenMachine forks.
805
+ Combobox: query + highlight stay React-local; open/closed must still be popoverMachine.
806
+ Tooltip: openDelay / closeDelay / touchDuration stay React-local; open/closed must still be popoverMachine.`,
411
807
  toggle: `## Switch / Checkbox
412
808
  Machine: toggleMachine \u2014 checked | unchecked. Events: TOGGLE, CHECK, UNCHECK.
413
- Rule: Hidden input stays in sync with snapshot for forms.`
809
+ Rule: Hidden input stays in sync with snapshot for forms.`,
810
+ slider: `## Slider statechart
811
+ Machine: sliderMachine \u2014 idle | dragging; value/min/max/step in context.
812
+ Events: SET_VALUE, STEP, POINTER_DOWN, POINTER_UP, HOME, END.
813
+ Rule: Disabled blocks SET_VALUE / drag; project idle vs dragging on data-aeon-state.`,
814
+ contentRegion: `## Content region statechart
815
+ Machine: contentRegionMachine \u2014 idle \u2192 pending \u2192 (empty | error | ready) \u2192 loadingMore | success.
816
+ Events: LOAD, RESOLVE, REJECT, RETRY, LOAD_MORE, MORE_DONE, SUCCEED, RESET.
817
+ Rule: Every stable state has a slot. Pair with Async for fetch; do not hide empty/error behind a spinner.`,
818
+ toast: `## Toast item statechart
819
+ Machine: toastMachine \u2014 hidden | visible. Events: SHOW, HIDE, DISMISS.
820
+ Rule: Provider list orchestration may use React; each toast item uses the machine.`,
821
+ stickyBar: `## StickyBar statechart
822
+ Machine: stickyBarMachine \u2014 floating | docked | collapsed | hidden.
823
+ Events: DOCK, FLOAT, COLLAPSE, EXPAND, HIDE, SHOW, SET_OFFSET.
824
+ Rule: DOM scope is bar (bar anatomy zones). Do not invent a parallel sticky useState.`
414
825
  };
415
826
  var GENERATIVE_UI_EXAMPLE = {
416
827
  prompt: "Create a multi-step checkout form with error handling.",
@@ -627,8 +1038,29 @@ function createAgentEventBridge(actor, options) {
627
1038
  };
628
1039
  }
629
1040
 
1041
+ // src/machine-id.ts
1042
+ function machineRegistryId(machine) {
1043
+ if (machine == null) return void 0;
1044
+ if (machine === "createAsyncMachine") return "async";
1045
+ if (machine.endsWith("Machine")) return machine.slice(0, -"Machine".length);
1046
+ return machine;
1047
+ }
1048
+
630
1049
  // src/registry.ts
631
1050
  var REGISTRY_BASE = "https://aeon-ui.com/registry";
1051
+ function entryFromSchema(id, schema) {
1052
+ const x = schema["x-aeon"];
1053
+ const mid = machineRegistryId(x.machine);
1054
+ return {
1055
+ id,
1056
+ title: String(schema.title ?? id),
1057
+ scope: x.scope,
1058
+ schemaUrl: `${REGISTRY_BASE}/components/${id}.json`,
1059
+ ...mid ? { machineUrl: `${REGISTRY_BASE}/machines/${mid}.json` } : {},
1060
+ runtime: x.runtime,
1061
+ description: String(schema.description ?? "")
1062
+ };
1063
+ }
632
1064
  var registryCatalog = {
633
1065
  $id: `${REGISTRY_BASE}/catalog.json`,
634
1066
  version: "0.1.0",
@@ -639,44 +1071,9 @@ var registryCatalog = {
639
1071
  component: `${REGISTRY_BASE}/components/{id}.json`,
640
1072
  machine: `${REGISTRY_BASE}/machines/{id}.json`
641
1073
  },
642
- components: [
643
- {
644
- id: "button",
645
- title: "Button",
646
- scope: "button",
647
- schemaUrl: `${REGISTRY_BASE}/components/button.json`,
648
- machineUrl: `${REGISTRY_BASE}/machines/buttonLifecycle.json`,
649
- runtime: "status prop",
650
- description: "Action control with idle|pending|success|failure|disabled"
651
- },
652
- {
653
- id: "async",
654
- title: "Async",
655
- scope: "async",
656
- schemaUrl: `${REGISTRY_BASE}/components/async.json`,
657
- machineUrl: `${REGISTRY_BASE}/machines/async.json`,
658
- runtime: "useAeonMachine",
659
- description: "Fetch lifecycle region with full totality"
660
- },
661
- {
662
- id: "field",
663
- title: "Field",
664
- scope: "field",
665
- schemaUrl: `${REGISTRY_BASE}/components/field.json`,
666
- machineUrl: `${REGISTRY_BASE}/machines/field.json`,
667
- runtime: "useAeonMachine",
668
- description: "Parallel interaction \xD7 validation \xD7 submission"
669
- },
670
- {
671
- id: "dialog",
672
- title: "Dialog",
673
- scope: "dialog",
674
- schemaUrl: `${REGISTRY_BASE}/components/dialog.json`,
675
- machineUrl: `${REGISTRY_BASE}/machines/dialog.json`,
676
- runtime: "useAeonMachine",
677
- description: "Modal open/closed"
678
- }
679
- ],
1074
+ components: Object.entries(componentSchemas).map(
1075
+ ([id, schema]) => entryFromSchema(id, schema)
1076
+ ),
680
1077
  client: {
681
1078
  fetchCatalog: `fetch('${REGISTRY_BASE}/catalog.json').then(r => r.json())`,
682
1079
  fetchComponent: `id => fetch(\`${REGISTRY_BASE}/components/\${id}.json\`).then(r => r.json())`,
@@ -697,5 +1094,6 @@ export {
697
1094
  componentSchema,
698
1095
  componentSchemas,
699
1096
  createAgentEventBridge,
1097
+ machineRegistryId,
700
1098
  registryCatalog
701
1099
  };