@almadar/ui 2.31.0 → 2.33.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 (78) hide show
  1. package/dist/avl/index.cjs +1049 -1086
  2. package/dist/avl/index.d.cts +352 -78
  3. package/dist/avl/index.d.ts +18 -3
  4. package/dist/avl/index.js +1029 -1086
  5. package/dist/components/atoms/index.d.ts +0 -1
  6. package/dist/components/index.cjs +1146 -1847
  7. package/dist/components/index.js +266 -952
  8. package/dist/components/molecules/avl/AvlBackwardEdge.d.ts +8 -0
  9. package/dist/components/molecules/avl/AvlBindingEdge.d.ts +9 -0
  10. package/dist/components/molecules/avl/AvlEventWireEdge.d.ts +14 -0
  11. package/dist/components/molecules/avl/AvlOrbitalNode.d.ts +12 -0
  12. package/dist/components/molecules/avl/AvlPageEdge.d.ts +8 -0
  13. package/dist/components/molecules/avl/AvlTransitionEdge.d.ts +16 -0
  14. package/dist/components/molecules/avl/BehaviorView.d.ts +12 -0
  15. package/dist/components/molecules/avl/DetailView.d.ts +13 -0
  16. package/dist/components/molecules/avl/MiniStateMachine.d.ts +14 -0
  17. package/dist/components/molecules/avl/ModuleCard.d.ts +14 -0
  18. package/dist/components/molecules/avl/SystemNode.d.ts +12 -0
  19. package/dist/components/molecules/avl/avl-canvas-types.d.ts +36 -0
  20. package/dist/components/molecules/avl/avl-elk-layout.d.ts +55 -0
  21. package/dist/components/molecules/avl/avl-flow-converter.d.ts +17 -0
  22. package/dist/components/molecules/avl/avl-story-schemas.d.ts +34 -0
  23. package/dist/components/molecules/avl/avl-zoom-band.d.ts +19 -0
  24. package/dist/components/molecules/avl/index.d.ts +15 -0
  25. package/dist/components/molecules/index.d.ts +0 -1
  26. package/dist/components/organisms/avl/AvlCosmicZoom.d.ts +10 -7
  27. package/dist/components/organisms/avl/FlowCanvas.d.ts +32 -0
  28. package/dist/components/organisms/avl/ZoomBreadcrumb.d.ts +16 -0
  29. package/dist/components/organisms/avl/ZoomLegend.d.ts +10 -0
  30. package/dist/components/organisms/avl/index.d.ts +5 -2
  31. package/dist/hooks/useUISlots.d.ts +2 -0
  32. package/dist/providers/index.cjs +148 -149
  33. package/dist/providers/index.js +39 -40
  34. package/dist/runtime/index.cjs +1045 -1020
  35. package/dist/runtime/index.js +260 -235
  36. package/package.json +2 -6
  37. package/dist/components/atoms/flow/FlowLabel.d.ts +0 -23
  38. package/dist/components/atoms/flow/FlowMinimap.d.ts +0 -28
  39. package/dist/components/atoms/flow/FlowNodeShell.d.ts +0 -25
  40. package/dist/components/atoms/flow/FlowPort.d.ts +0 -26
  41. package/dist/components/atoms/flow/FlowWire.d.ts +0 -39
  42. package/dist/components/atoms/flow/index.d.ts +0 -13
  43. package/dist/components/molecules/flow/BehaviorNode.d.ts +0 -28
  44. package/dist/components/molecules/flow/EffectNode.d.ts +0 -26
  45. package/dist/components/molecules/flow/EventWireEdge.d.ts +0 -23
  46. package/dist/components/molecules/flow/ExprNode.d.ts +0 -27
  47. package/dist/components/molecules/flow/FlowStateNode.d.ts +0 -18
  48. package/dist/components/molecules/flow/NodePalette.d.ts +0 -36
  49. package/dist/components/molecules/flow/OrbitalNode.d.ts +0 -31
  50. package/dist/components/molecules/flow/TransitionEdge.d.ts +0 -26
  51. package/dist/components/molecules/flow/index.d.ts +0 -8
  52. package/dist/components/molecules/svg/AIGenerates.d.ts +0 -7
  53. package/dist/components/molecules/svg/ClosedCircuit.d.ts +0 -7
  54. package/dist/components/molecules/svg/CommunityOwnership.d.ts +0 -7
  55. package/dist/components/molecules/svg/CompileAnywhere.d.ts +0 -7
  56. package/dist/components/molecules/svg/ComposableModels.d.ts +0 -7
  57. package/dist/components/molecules/svg/DescribeProveDeploy.d.ts +0 -7
  58. package/dist/components/molecules/svg/DomainGrid.d.ts +0 -7
  59. package/dist/components/molecules/svg/EventBus.d.ts +0 -7
  60. package/dist/components/molecules/svg/OrbitalUnit.d.ts +0 -7
  61. package/dist/components/molecules/svg/PlanVerifyRemember.d.ts +0 -7
  62. package/dist/components/molecules/svg/ProveCorrect.d.ts +0 -7
  63. package/dist/components/molecules/svg/ServiceLayers.d.ts +0 -7
  64. package/dist/components/molecules/svg/SharedReality.d.ts +0 -7
  65. package/dist/components/molecules/svg/StandardLibrary.d.ts +0 -7
  66. package/dist/components/molecules/svg/StateMachine.d.ts +0 -7
  67. package/dist/components/molecules/svg/WorldModel.d.ts +0 -7
  68. package/dist/components/molecules/svg/index.d.ts +0 -16
  69. package/dist/components/organisms/avl/AvlApplicationScene.d.ts +0 -17
  70. package/dist/components/organisms/avl/AvlOrbitalScene.d.ts +0 -21
  71. package/dist/flow/index.cjs +0 -3832
  72. package/dist/flow/index.d.cts +0 -367
  73. package/dist/flow/index.d.ts +0 -10
  74. package/dist/flow/index.js +0 -3793
  75. package/dist/illustrations/index.cjs +0 -7651
  76. package/dist/illustrations/index.d.cts +0 -544
  77. package/dist/illustrations/index.d.ts +0 -59
  78. package/dist/illustrations/index.js +0 -7594
package/dist/avl/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import React8, { createContext, useCallback, useContext, useMemo, useState, useEffect, useReducer, useRef } from 'react';
2
+ import React8, { createContext, useCallback, useContext, useMemo, useState, useEffect } from 'react';
3
3
  import '@react-three/drei';
4
+ import ELK from 'elkjs/lib/elk.bundled.js';
5
+ import { Handle, Position, getBezierPath, BaseEdge, EdgeLabelRenderer, ReactFlowProvider, useNodesState, useEdgesState, useReactFlow, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
4
6
  import '@react-three/fiber';
5
7
  import 'three';
6
- import ELK from 'elkjs/lib/elk.bundled.js';
7
8
 
8
9
  // components/atoms/avl/types.ts
9
10
  var AVL_OPERATOR_COLORS = {
@@ -685,7 +686,7 @@ var AvlEffect = ({
685
686
  className,
686
687
  showBackground = false
687
688
  }) => {
688
- const category = EFFECT_TYPE_TO_CATEGORY[effectType];
689
+ const category = EFFECT_TYPE_TO_CATEGORY[effectType] ?? "control";
689
690
  const catColors = EFFECT_CATEGORY_COLORS[category];
690
691
  const iconColor = showBackground ? catColors.color : color;
691
692
  return /* @__PURE__ */ jsxs("g", { className, opacity, children: [
@@ -3596,113 +3597,6 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
3596
3597
  function cn(...inputs) {
3597
3598
  return twMerge(clsx(inputs));
3598
3599
  }
3599
- var variantStyles = {
3600
- h1: "text-4xl font-bold tracking-tight text-foreground",
3601
- h2: "text-3xl font-bold tracking-tight text-foreground",
3602
- h3: "text-2xl font-bold text-foreground",
3603
- h4: "text-xl font-bold text-foreground",
3604
- h5: "text-lg font-bold text-foreground",
3605
- h6: "text-base font-bold text-foreground",
3606
- heading: "text-2xl font-bold text-foreground",
3607
- subheading: "text-lg font-semibold text-foreground",
3608
- body1: "text-base font-normal text-foreground",
3609
- body2: "text-sm font-normal text-foreground",
3610
- body: "text-base font-normal text-foreground",
3611
- caption: "text-xs font-normal text-muted-foreground",
3612
- overline: "text-xs uppercase tracking-wide font-bold text-muted-foreground",
3613
- small: "text-sm font-normal text-foreground",
3614
- large: "text-lg font-medium text-foreground",
3615
- label: "text-sm font-medium text-foreground"
3616
- };
3617
- var colorStyles = {
3618
- primary: "text-foreground",
3619
- secondary: "text-muted-foreground",
3620
- muted: "text-muted-foreground",
3621
- error: "text-error",
3622
- success: "text-success",
3623
- warning: "text-warning",
3624
- inherit: "text-inherit"
3625
- };
3626
- var weightStyles = {
3627
- light: "font-light",
3628
- normal: "font-normal",
3629
- medium: "font-medium",
3630
- semibold: "font-semibold",
3631
- bold: "font-bold"
3632
- };
3633
- var defaultElements = {
3634
- h1: "h1",
3635
- h2: "h2",
3636
- h3: "h3",
3637
- h4: "h4",
3638
- h5: "h5",
3639
- h6: "h6",
3640
- heading: "h2",
3641
- subheading: "h3",
3642
- body1: "p",
3643
- body2: "p",
3644
- body: "p",
3645
- caption: "span",
3646
- overline: "span",
3647
- small: "span",
3648
- large: "p",
3649
- label: "span"
3650
- };
3651
- var typographySizeStyles = {
3652
- xs: "text-xs",
3653
- sm: "text-sm",
3654
- md: "text-base",
3655
- lg: "text-lg",
3656
- xl: "text-xl",
3657
- "2xl": "text-2xl",
3658
- "3xl": "text-3xl"
3659
- };
3660
- var overflowStyles = {
3661
- visible: "overflow-visible",
3662
- hidden: "overflow-hidden",
3663
- wrap: "break-words overflow-hidden",
3664
- "clamp-2": "overflow-hidden line-clamp-2",
3665
- "clamp-3": "overflow-hidden line-clamp-3"
3666
- };
3667
- var Typography = ({
3668
- variant: variantProp,
3669
- level,
3670
- color = "primary",
3671
- align,
3672
- weight,
3673
- size,
3674
- truncate = false,
3675
- overflow,
3676
- as,
3677
- id,
3678
- className,
3679
- style,
3680
- content,
3681
- children
3682
- }) => {
3683
- const variant = variantProp ?? (level ? `h${level}` : "body1");
3684
- const Component = as || defaultElements[variant];
3685
- const Comp = Component;
3686
- return /* @__PURE__ */ jsx(
3687
- Comp,
3688
- {
3689
- id,
3690
- className: cn(
3691
- variantStyles[variant],
3692
- colorStyles[color],
3693
- weight && weightStyles[weight],
3694
- size && typographySizeStyles[size],
3695
- align && `text-${align}`,
3696
- truncate && "truncate overflow-hidden text-ellipsis",
3697
- overflow && overflowStyles[overflow],
3698
- className
3699
- ),
3700
- style,
3701
- children: children ?? content
3702
- }
3703
- );
3704
- };
3705
- Typography.displayName = "Typography";
3706
3600
  var EventBusContext = createContext(null);
3707
3601
 
3708
3602
  // hooks/useEventBus.ts
@@ -3972,83 +3866,6 @@ var Box = React8.forwardRef(
3972
3866
  }
3973
3867
  );
3974
3868
  Box.displayName = "Box";
3975
- var gapStyles = {
3976
- none: "gap-0",
3977
- xs: "gap-1",
3978
- sm: "gap-2",
3979
- md: "gap-4",
3980
- lg: "gap-6",
3981
- xl: "gap-8",
3982
- "2xl": "gap-12"
3983
- };
3984
- var alignStyles = {
3985
- start: "items-start",
3986
- center: "items-center",
3987
- end: "items-end",
3988
- stretch: "items-stretch",
3989
- baseline: "items-baseline"
3990
- };
3991
- var justifyStyles = {
3992
- start: "justify-start",
3993
- center: "justify-center",
3994
- end: "justify-end",
3995
- between: "justify-between",
3996
- around: "justify-around",
3997
- evenly: "justify-evenly"
3998
- };
3999
- var Stack = ({
4000
- direction = "vertical",
4001
- gap = "md",
4002
- align = "stretch",
4003
- justify = "start",
4004
- wrap = false,
4005
- reverse = false,
4006
- flex = false,
4007
- className,
4008
- style,
4009
- children,
4010
- as: Component = "div",
4011
- onClick,
4012
- onKeyDown,
4013
- role,
4014
- tabIndex,
4015
- action,
4016
- actionPayload,
4017
- responsive = false
4018
- }) => {
4019
- const eventBus = useEventBus();
4020
- const handleClick = (e) => {
4021
- if (action) {
4022
- eventBus.emit(`UI:${action}`, actionPayload ?? {});
4023
- }
4024
- onClick?.(e);
4025
- };
4026
- const isHorizontal = direction === "horizontal";
4027
- const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
4028
- const Comp = Component;
4029
- return /* @__PURE__ */ jsx(
4030
- Comp,
4031
- {
4032
- className: cn(
4033
- "flex",
4034
- directionClass,
4035
- gapStyles[gap],
4036
- alignStyles[align],
4037
- justifyStyles[justify],
4038
- wrap && "flex-wrap",
4039
- flex && "flex-1",
4040
- className
4041
- ),
4042
- style,
4043
- onClick: action || onClick ? handleClick : void 0,
4044
- onKeyDown,
4045
- role,
4046
- tabIndex,
4047
- children
4048
- }
4049
- );
4050
- };
4051
- var HStack = (props) => /* @__PURE__ */ jsx(Stack, { direction: "horizontal", ...props });
4052
3869
 
4053
3870
  // components/molecules/avl/avl-layout.ts
4054
3871
  function ringPositions(cx, cy, r2, count, startAngle = -Math.PI / 2) {
@@ -5600,6 +5417,31 @@ var AvlBehaviorGlyph = ({
5600
5417
  };
5601
5418
  AvlBehaviorGlyph.displayName = "AvlBehaviorGlyph";
5602
5419
 
5420
+ // components/molecules/avl/avl-canvas-types.ts
5421
+ var ZOOM_BAND_THRESHOLDS = {
5422
+ system: [0.1, 0.4],
5423
+ module: [0.4, 1],
5424
+ behavior: [1, 2.5],
5425
+ detail: [2.5, 5]
5426
+ };
5427
+ function computeZoomBand(zoom) {
5428
+ if (zoom < ZOOM_BAND_THRESHOLDS.module[0]) return "system";
5429
+ if (zoom < ZOOM_BAND_THRESHOLDS.behavior[0]) return "module";
5430
+ if (zoom < ZOOM_BAND_THRESHOLDS.detail[0]) return "behavior";
5431
+ return "detail";
5432
+ }
5433
+ function zoomProgress(zoom, band) {
5434
+ const [min, max] = ZOOM_BAND_THRESHOLDS[band];
5435
+ const clamped = Math.max(min, Math.min(max, zoom));
5436
+ const range = max - min;
5437
+ if (range === 0) return 1;
5438
+ return (clamped - min) / range;
5439
+ }
5440
+ var ZoomBandContext = createContext("module");
5441
+ function useZoomBand() {
5442
+ return useContext(ZoomBandContext);
5443
+ }
5444
+
5603
5445
  // components/organisms/avl/avl-schema-parser.ts
5604
5446
  function getEntity(orbital) {
5605
5447
  const entity = orbital.entity;
@@ -5851,508 +5693,57 @@ function parseTransitionLevel(schema, orbitalName, traitName, transitionIndex) {
5851
5693
  };
5852
5694
  }
5853
5695
 
5854
- // components/organisms/avl/avl-zoom-state.ts
5855
- var initialZoomState = {
5856
- level: "application",
5857
- selectedOrbital: null,
5858
- selectedTrait: null,
5859
- selectedTransition: null,
5860
- animating: false,
5861
- animationDirection: "in",
5862
- animationTarget: null
5863
- };
5864
- function zoomReducer(state, action) {
5865
- switch (action.type) {
5866
- case "ZOOM_INTO_ORBITAL": {
5867
- if (state.level !== "application" || state.animating) return state;
5868
- return {
5869
- ...state,
5870
- animating: true,
5871
- animationDirection: "in",
5872
- animationTarget: { x: action.targetPosition.x, y: action.targetPosition.y, scale: 3 },
5873
- selectedOrbital: action.orbital
5874
- };
5875
- }
5876
- case "ZOOM_INTO_TRAIT": {
5877
- if (state.level !== "orbital" || state.animating) return state;
5878
- return {
5879
- ...state,
5880
- animating: true,
5881
- animationDirection: "in",
5882
- animationTarget: { x: action.targetPosition.x, y: action.targetPosition.y, scale: 3 },
5883
- selectedTrait: action.trait
5884
- };
5885
- }
5886
- case "ZOOM_INTO_TRANSITION": {
5887
- if (state.level !== "trait" || state.animating) return state;
5888
- return {
5889
- ...state,
5890
- animating: true,
5891
- animationDirection: "in",
5892
- animationTarget: { x: action.targetPosition.x, y: action.targetPosition.y, scale: 3 },
5893
- selectedTransition: action.transitionIndex
5894
- };
5895
- }
5896
- case "ZOOM_OUT": {
5897
- if (state.level === "application" || state.animating) return state;
5898
- return {
5899
- ...state,
5900
- animating: true,
5901
- animationDirection: "out",
5902
- animationTarget: { x: 300, y: 200, scale: 0.3 }
5903
- };
5696
+ // components/molecules/avl/avl-flow-converter.ts
5697
+ var NODE_SPACING = 350;
5698
+ function schemaToFlowGraph(schema) {
5699
+ const appData = parseApplicationLevel(schema);
5700
+ const nodes = [];
5701
+ const edges = [];
5702
+ const count = appData.orbitals.length;
5703
+ const cols = Math.ceil(Math.sqrt(count));
5704
+ for (let i = 0; i < appData.orbitals.length; i++) {
5705
+ const orb = appData.orbitals[i];
5706
+ const orbitalDetail = parseOrbitalLevel(schema, orb.name);
5707
+ if (!orbitalDetail) continue;
5708
+ const traitDetails = {};
5709
+ for (const traitName of orb.traitNames) {
5710
+ const td = parseTraitLevel(schema, orb.name, traitName);
5711
+ if (td) traitDetails[traitName] = td;
5904
5712
  }
5905
- case "ANIMATION_COMPLETE": {
5906
- if (!state.animating) return state;
5907
- if (state.animationDirection === "in") {
5908
- const nextLevel = state.level === "application" ? "orbital" : state.level === "orbital" ? "trait" : "transition";
5909
- return {
5910
- ...state,
5911
- level: nextLevel,
5912
- animating: false,
5913
- animationTarget: null
5914
- };
5915
- }
5916
- if (state.level === "transition") {
5917
- return {
5918
- ...state,
5919
- level: "trait",
5920
- selectedTransition: null,
5921
- animating: false,
5922
- animationTarget: null
5923
- };
5924
- }
5925
- if (state.level === "trait") {
5926
- return {
5927
- ...state,
5928
- level: "orbital",
5929
- selectedTrait: null,
5930
- animating: false,
5931
- animationTarget: null
5932
- };
5933
- }
5934
- if (state.level === "orbital") {
5935
- return {
5936
- ...state,
5937
- level: "application",
5938
- selectedOrbital: null,
5939
- animating: false,
5940
- animationTarget: null
5941
- };
5713
+ const col = i % cols;
5714
+ const row = Math.floor(i / cols);
5715
+ nodes.push({
5716
+ id: orb.name,
5717
+ type: "orbital",
5718
+ position: { x: col * NODE_SPACING, y: row * NODE_SPACING },
5719
+ data: {
5720
+ orbitalName: orb.name,
5721
+ entityName: orb.entityName,
5722
+ persistence: orb.persistence,
5723
+ fields: orbitalDetail.entity.fields,
5724
+ traits: orbitalDetail.traits,
5725
+ pages: orbitalDetail.pages,
5726
+ traitDetails,
5727
+ externalLinks: orbitalDetail.externalLinks
5942
5728
  }
5943
- return state;
5944
- }
5945
- case "SWITCH_TRAIT": {
5946
- if (state.level !== "trait" || state.animating) return state;
5947
- return {
5948
- ...state,
5949
- selectedTrait: action.trait,
5950
- selectedTransition: null
5951
- };
5952
- }
5953
- case "RESET": {
5954
- return initialZoomState;
5955
- }
5956
- default:
5957
- return state;
5958
- }
5959
- }
5960
- function getBreadcrumbs(state) {
5961
- const crumbs = [{ label: "Application", level: "application" }];
5962
- if (state.selectedOrbital) {
5963
- crumbs.push({ label: state.selectedOrbital, level: "orbital" });
5964
- }
5965
- if (state.selectedTrait) {
5966
- crumbs.push({ label: state.selectedTrait, level: "trait" });
5967
- }
5968
- if (state.selectedTransition !== null) {
5969
- crumbs.push({ label: `Transition #${state.selectedTransition}`, level: "transition" });
5729
+ });
5970
5730
  }
5971
- return crumbs;
5972
- }
5973
- var AvlClickTarget = ({
5974
- x,
5975
- y,
5976
- width,
5977
- height,
5978
- onClick,
5979
- onHover,
5980
- cursor = "pointer",
5981
- glowColor = "var(--color-primary)",
5982
- label,
5983
- children
5984
- }) => {
5985
- const [hovering, setHovering] = useState(false);
5986
- const handleMouseEnter = useCallback(() => {
5987
- setHovering(true);
5988
- onHover?.(true);
5989
- }, [onHover]);
5990
- const handleMouseLeave = useCallback(() => {
5991
- setHovering(false);
5992
- onHover?.(false);
5993
- }, [onHover]);
5994
- const handleKeyDown = useCallback((e) => {
5995
- if (e.key === "Enter" || e.key === " ") {
5996
- e.preventDefault();
5997
- onClick();
5998
- }
5999
- }, [onClick]);
6000
- return /* @__PURE__ */ jsxs("g", { children: [
6001
- hovering && /* @__PURE__ */ jsx(
6002
- "rect",
6003
- {
6004
- x: x - 4,
6005
- y: y - 4,
6006
- width: width + 8,
6007
- height: height + 8,
6008
- rx: 8,
6009
- fill: glowColor,
6010
- opacity: 0.08
6011
- }
6012
- ),
6013
- children,
6014
- /* @__PURE__ */ jsx(
6015
- "rect",
6016
- {
6017
- x,
6018
- y,
6019
- width,
6020
- height,
6021
- fill: "transparent",
6022
- style: { cursor },
6023
- pointerEvents: "all",
6024
- onClick,
6025
- onMouseEnter: handleMouseEnter,
6026
- onMouseLeave: handleMouseLeave,
6027
- onKeyDown: handleKeyDown,
6028
- tabIndex: 0,
6029
- role: "button",
6030
- "aria-label": label
5731
+ for (const link of appData.crossLinks) {
5732
+ edges.push({
5733
+ id: `ew-${link.emitterOrbital}-${link.listenerOrbital}-${link.eventName}`,
5734
+ source: link.emitterOrbital,
5735
+ target: link.listenerOrbital,
5736
+ type: "eventWire",
5737
+ data: {
5738
+ edgeKind: "eventWire",
5739
+ event: link.eventName,
5740
+ fromTrait: link.emitterTrait,
5741
+ toTrait: link.listenerTrait
6031
5742
  }
6032
- )
6033
- ] });
6034
- };
6035
- AvlClickTarget.displayName = "AvlClickTarget";
6036
- var ORBITAL_R = 60;
6037
- var ENTITY_R = 14;
6038
- function bundleCrossLinks(links) {
6039
- const bundles = /* @__PURE__ */ new Map();
6040
- for (const link of links) {
6041
- const key = [link.emitterOrbital, link.listenerOrbital].sort().join("::");
6042
- if (!bundles.has(key)) bundles.set(key, []);
6043
- bundles.get(key).push(link);
5743
+ });
6044
5744
  }
6045
- return bundles;
5745
+ return { nodes, edges };
6046
5746
  }
6047
- var AvlApplicationScene = ({
6048
- data,
6049
- color = "var(--color-primary)",
6050
- onOrbitalClick
6051
- }) => {
6052
- const posMap = /* @__PURE__ */ new Map();
6053
- data.orbitals.forEach((o) => posMap.set(o.name, o.position));
6054
- const bundles = bundleCrossLinks(data.crossLinks);
6055
- return /* @__PURE__ */ jsxs("g", { children: [
6056
- Array.from(bundles.entries()).map(([key, links]) => {
6057
- const first = links[0];
6058
- const fromPos = posMap.get(first.emitterOrbital);
6059
- const toPos = posMap.get(first.listenerOrbital);
6060
- if (!fromPos || !toPos) return null;
6061
- const cp = curveControlPoint(fromPos.x, fromPos.y, toPos.x, toPos.y, 40);
6062
- const midX = cp.cpx;
6063
- const midY = cp.cpy;
6064
- return /* @__PURE__ */ jsxs("g", { opacity: 0.5, children: [
6065
- /* @__PURE__ */ jsx(
6066
- "path",
6067
- {
6068
- d: `M${fromPos.x},${fromPos.y} Q${midX},${midY} ${toPos.x},${toPos.y}`,
6069
- fill: "none",
6070
- stroke: color,
6071
- strokeWidth: 1.5,
6072
- strokeDasharray: "6 3",
6073
- markerEnd: "url(#cosmicArrow)"
6074
- }
6075
- ),
6076
- links.map((link, i) => /* @__PURE__ */ jsxs("g", { children: [
6077
- /* @__PURE__ */ jsx(
6078
- AvlEffect,
6079
- {
6080
- x: midX - 12,
6081
- y: midY - 10 + i * 16,
6082
- effectType: "emit",
6083
- size: 8,
6084
- color
6085
- }
6086
- ),
6087
- /* @__PURE__ */ jsx(
6088
- "text",
6089
- {
6090
- x: midX + 2,
6091
- y: midY - 6 + i * 16,
6092
- fill: color,
6093
- fontSize: 7,
6094
- opacity: 0.7,
6095
- children: link.eventName
6096
- }
6097
- )
6098
- ] }, `${key}-${i}`))
6099
- ] }, key);
6100
- }),
6101
- data.orbitals.map((orbital) => {
6102
- const { x, y } = orbital.position;
6103
- const traitAngleStart = -60;
6104
- const traitAngleStep = orbital.traitNames.length > 1 ? 120 / (orbital.traitNames.length - 1) : 0;
6105
- const pageAngleStart = -Math.PI / 3;
6106
- const pageAngleStep = orbital.pageNames.length > 1 ? Math.PI * 0.8 / (orbital.pageNames.length - 1) : 0;
6107
- return /* @__PURE__ */ jsxs("g", { children: [
6108
- /* @__PURE__ */ jsx(AvlOrbital, { cx: x, cy: y, r: ORBITAL_R, label: orbital.name, color }),
6109
- orbital.traitNames.map((trait, i) => /* @__PURE__ */ jsx(
6110
- AvlTrait,
6111
- {
6112
- cx: x,
6113
- cy: y,
6114
- rx: 25 + i * 10,
6115
- ry: 12 + i * 4,
6116
- rotation: traitAngleStart + i * traitAngleStep,
6117
- color,
6118
- opacity: 0.4
6119
- },
6120
- trait
6121
- )),
6122
- /* @__PURE__ */ jsx(
6123
- AvlEntity,
6124
- {
6125
- x,
6126
- y,
6127
- r: ENTITY_R,
6128
- fieldCount: orbital.fieldCount,
6129
- persistence: orbital.persistence,
6130
- color
6131
- }
6132
- ),
6133
- orbital.pageNames.map((page, i) => {
6134
- const angle = pageAngleStart + i * pageAngleStep;
6135
- const px = x + (ORBITAL_R + 12) * Math.cos(angle);
6136
- const py = y + (ORBITAL_R + 12) * Math.sin(angle);
6137
- return /* @__PURE__ */ jsx(AvlPage, { x: px, y: py, size: 6, label: page, color }, page);
6138
- }),
6139
- onOrbitalClick && /* @__PURE__ */ jsx(
6140
- AvlClickTarget,
6141
- {
6142
- x: x - ORBITAL_R,
6143
- y: y - ORBITAL_R,
6144
- width: ORBITAL_R * 2,
6145
- height: ORBITAL_R * 2,
6146
- onClick: () => onOrbitalClick(orbital.name, { x, y }),
6147
- label: `Orbital: ${orbital.name} (${orbital.traitNames.length} traits, ${orbital.pageNames.length} pages)`,
6148
- glowColor: color,
6149
- children: /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 0, height: 0, fill: "transparent" })
6150
- }
6151
- )
6152
- ] }, orbital.name);
6153
- }),
6154
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", { id: "cosmicArrow", viewBox: "0 0 10 10", refX: "8", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: color, opacity: 0.5 }) }) })
6155
- ] });
6156
- };
6157
- AvlApplicationScene.displayName = "AvlApplicationScene";
6158
- var CX = 300;
6159
- var CY = 200;
6160
- var VIEWBOX_H = 400;
6161
- var ORBITAL_R2 = 130;
6162
- var ENTITY_R2 = 24;
6163
- var AvlOrbitalScene = ({
6164
- data,
6165
- color = "var(--color-primary)",
6166
- highlightedTrait,
6167
- onTraitClick,
6168
- onTraitHighlight
6169
- }) => {
6170
- const traitAngleStart = -Math.PI / 3;
6171
- const traitAngleStep = data.traits.length > 1 ? Math.PI * 1.2 / (data.traits.length - 1) : 0;
6172
- const pageAngleStart = -Math.PI / 3;
6173
- const pageAngleStep = data.pages.length > 1 ? Math.PI * 0.8 / (data.pages.length - 1) : 0;
6174
- return /* @__PURE__ */ jsxs("g", { children: [
6175
- /* @__PURE__ */ jsx(AvlOrbital, { cx: CX, cy: CY, r: ORBITAL_R2, label: data.name, color }),
6176
- data.traits.map((trait, i) => {
6177
- const rotation = traitAngleStart + i * traitAngleStep;
6178
- const rotationDeg = rotation * 180 / Math.PI;
6179
- const baseRx = 55 + i * 20;
6180
- const baseRy = 24 + i * 8;
6181
- const labelX = CX - baseRx - 10;
6182
- const labelY = CY;
6183
- return /* @__PURE__ */ jsxs("g", { children: [
6184
- /* @__PURE__ */ jsx(
6185
- AvlTrait,
6186
- {
6187
- cx: CX,
6188
- cy: CY,
6189
- rx: baseRx,
6190
- ry: baseRy,
6191
- rotation: rotationDeg,
6192
- label: trait.name,
6193
- color,
6194
- opacity: highlightedTrait ? highlightedTrait === trait.name ? 1 : 0.25 : 0.7
6195
- }
6196
- ),
6197
- onTraitClick && /* @__PURE__ */ jsx(
6198
- AvlClickTarget,
6199
- {
6200
- x: CX - baseRx,
6201
- y: CY - baseRy,
6202
- width: baseRx * 2,
6203
- height: baseRy * 2,
6204
- onClick: () => onTraitClick(trait.name, { x: CX, y: CY }),
6205
- label: `Trait: ${trait.name} (${trait.stateCount} states)`,
6206
- glowColor: color,
6207
- children: /* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: 0, height: 0, fill: "transparent" })
6208
- }
6209
- ),
6210
- /* @__PURE__ */ jsxs(
6211
- "text",
6212
- {
6213
- x: labelX - 20,
6214
- y: labelY + 12,
6215
- textAnchor: "end",
6216
- fill: color,
6217
- fontSize: 7,
6218
- opacity: 0.4,
6219
- transform: `rotate(${-rotationDeg},${labelX - 20},${labelY + 12})`,
6220
- children: [
6221
- trait.stateCount,
6222
- "s ",
6223
- trait.eventCount,
6224
- "e"
6225
- ]
6226
- }
6227
- )
6228
- ] }, trait.name);
6229
- }),
6230
- /* @__PURE__ */ jsx(
6231
- AvlEntity,
6232
- {
6233
- x: CX,
6234
- y: CY,
6235
- r: ENTITY_R2,
6236
- fieldCount: data.entity.fields.length,
6237
- persistence: data.entity.persistence,
6238
- color
6239
- }
6240
- ),
6241
- /* @__PURE__ */ jsx("text", { x: CX, y: CY + ENTITY_R2 + 16, textAnchor: "middle", fill: color, fontSize: 10, fontWeight: "bold", children: data.entity.name }),
6242
- data.entity.fields.slice(0, 8).map((field, i) => {
6243
- const angle = -Math.PI / 2 + Math.PI * 2 * i / Math.min(data.entity.fields.length, 8);
6244
- const fx = CX + (ENTITY_R2 + 30) * Math.cos(angle);
6245
- const fy = CY + (ENTITY_R2 + 30) * Math.sin(angle);
6246
- return /* @__PURE__ */ jsx(
6247
- "text",
6248
- {
6249
- x: fx,
6250
- y: fy,
6251
- textAnchor: "middle",
6252
- dominantBaseline: "central",
6253
- fill: color,
6254
- fontSize: 7,
6255
- opacity: 0.5,
6256
- children: field.name
6257
- },
6258
- field.name
6259
- );
6260
- }),
6261
- data.pages.map((page, i) => {
6262
- const angle = pageAngleStart + i * pageAngleStep;
6263
- const px = CX + (ORBITAL_R2 + 15) * Math.cos(angle);
6264
- const py = CY + (ORBITAL_R2 + 15) * Math.sin(angle);
6265
- return /* @__PURE__ */ jsx(AvlPage, { x: px, y: py, label: page.route, color }, page.name);
6266
- }),
6267
- data.traits.length > 1 && /* @__PURE__ */ jsx("g", { children: data.traits.map((trait, i) => {
6268
- const pillW = 70;
6269
- const gap = 8;
6270
- const totalW = data.traits.length * pillW + (data.traits.length - 1) * gap;
6271
- const startX = CX - totalW / 2;
6272
- const px = startX + i * (pillW + gap);
6273
- const py = VIEWBOX_H - 30;
6274
- const isHighlighted = highlightedTrait === trait.name;
6275
- return /* @__PURE__ */ jsxs(
6276
- "g",
6277
- {
6278
- style: { cursor: "pointer" },
6279
- onClick: () => onTraitClick?.(trait.name, { x: CX, y: CY }),
6280
- onMouseEnter: () => onTraitHighlight?.(trait.name),
6281
- onMouseLeave: () => onTraitHighlight?.(null),
6282
- children: [
6283
- /* @__PURE__ */ jsx(
6284
- "rect",
6285
- {
6286
- x: px,
6287
- y: py,
6288
- width: pillW,
6289
- height: 22,
6290
- rx: 11,
6291
- fill: isHighlighted ? color : "transparent",
6292
- stroke: color,
6293
- strokeWidth: isHighlighted ? 1.5 : 0.8,
6294
- opacity: isHighlighted ? 0.15 : 0.3
6295
- }
6296
- ),
6297
- /* @__PURE__ */ jsx(
6298
- "text",
6299
- {
6300
- x: px + pillW / 2,
6301
- y: py + 14,
6302
- textAnchor: "middle",
6303
- fill: color,
6304
- fontSize: 8,
6305
- fontWeight: isHighlighted ? "bold" : "normal",
6306
- opacity: isHighlighted ? 1 : 0.6,
6307
- children: trait.name.length > 10 ? trait.name.slice(0, 9) + "\u2026" : trait.name
6308
- }
6309
- )
6310
- ]
6311
- },
6312
- `tab-${trait.name}`
6313
- );
6314
- }) }),
6315
- data.externalLinks.map((link, i) => {
6316
- const isOut = link.direction === "out";
6317
- const edgeX = isOut ? 580 : 20;
6318
- const y = 50 + i * 24;
6319
- return /* @__PURE__ */ jsxs("g", { opacity: 0.3, children: [
6320
- /* @__PURE__ */ jsx(
6321
- "line",
6322
- {
6323
- x1: isOut ? CX + ORBITAL_R2 + 10 : edgeX,
6324
- y1: y,
6325
- x2: isOut ? edgeX : CX - ORBITAL_R2 - 10,
6326
- y2: y,
6327
- stroke: color,
6328
- strokeWidth: 1,
6329
- strokeDasharray: "6 3"
6330
- }
6331
- ),
6332
- /* @__PURE__ */ jsxs(
6333
- "text",
6334
- {
6335
- x: isOut ? 585 : 5,
6336
- y: y + 4,
6337
- textAnchor: isOut ? "start" : "start",
6338
- fill: color,
6339
- fontSize: 7,
6340
- opacity: 0.7,
6341
- children: [
6342
- isOut ? "emit" : "listen",
6343
- ": ",
6344
- link.eventName,
6345
- " (",
6346
- link.targetOrbital,
6347
- ")"
6348
- ]
6349
- }
6350
- )
6351
- ] }, `ext-${i}`);
6352
- })
6353
- ] });
6354
- };
6355
- AvlOrbitalScene.displayName = "AvlOrbitalScene";
6356
5747
  function stateWidth(transitionCount) {
6357
5748
  if (transitionCount >= 5) return 160;
6358
5749
  if (transitionCount >= 3) return 130;
@@ -6360,7 +5751,7 @@ function stateWidth(transitionCount) {
6360
5751
  }
6361
5752
  var STATE_H = 40;
6362
5753
  var elk = new ELK();
6363
- async function computeLayout(data) {
5754
+ async function computeTraitLayout(data) {
6364
5755
  const transitionCounts = {};
6365
5756
  for (const s of data.states) transitionCounts[s.name] = 0;
6366
5757
  for (const t of data.transitions) {
@@ -6483,17 +5874,898 @@ function edgePath(points) {
6483
5874
  for (let i = 1; i < points.length; i++) d += ` L ${points[i].x},${points[i].y}`;
6484
5875
  return d;
6485
5876
  }
6486
- var SWIM_GUTTER = 120;
6487
- var CENTER_W = 360;
6488
- var AvlTraitScene = ({
6489
- data,
6490
- color = "var(--color-primary)",
6491
- onTransitionClick
6492
- }) => {
6493
- const [layout, setLayout] = useState(null);
5877
+ function toFieldKind(type) {
5878
+ const normalized = type.toLowerCase();
5879
+ if (["string", "number", "boolean", "date", "enum", "object", "array"].includes(normalized)) {
5880
+ return normalized;
5881
+ }
5882
+ return "string";
5883
+ }
5884
+ var SystemNode = ({ data }) => {
5885
+ const { orbitalName, fields, traits, pages, persistence } = data;
5886
+ const allStates = traits.flatMap((t) => {
5887
+ const detail = data.traitDetails[t.name];
5888
+ if (!detail) return [];
5889
+ return detail.states;
5890
+ });
5891
+ const fieldDots = fields.slice(0, 8);
5892
+ const stateChain = allStates.slice(0, 6);
5893
+ const pageDots = pages.slice(0, 3);
5894
+ const transitionCounts = {};
5895
+ for (const t of traits) {
5896
+ const detail = data.traitDetails[t.name];
5897
+ if (!detail) continue;
5898
+ for (const s of detail.states) transitionCounts[s.name] = 0;
5899
+ for (const tr of detail.transitions) {
5900
+ transitionCounts[tr.from] = (transitionCounts[tr.from] ?? 0) + 1;
5901
+ transitionCounts[tr.to] = (transitionCounts[tr.to] ?? 0) + 1;
5902
+ }
5903
+ }
5904
+ const maxTC = Math.max(...Object.values(transitionCounts), 0);
5905
+ return /* @__PURE__ */ jsxs(
5906
+ "div",
5907
+ {
5908
+ className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] px-3 py-2 shadow-sm",
5909
+ style: { minWidth: 160, maxWidth: 220 },
5910
+ children: [
5911
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left, className: "!w-2 !h-2 !bg-orange-400" }),
5912
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right, className: "!w-2 !h-2 !bg-orange-400" }),
5913
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-1", children: [
5914
+ /* @__PURE__ */ jsx("svg", { width: 14, height: 14, viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(AvlEntity, { x: 10, y: 10, r: 8, persistence }) }),
5915
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold text-[var(--color-foreground)] truncate flex-1", children: orbitalName })
5916
+ ] }),
5917
+ fieldDots.length > 0 && /* @__PURE__ */ jsx("svg", { width: fieldDots.length * 10 + 2, height: 10, viewBox: `0 0 ${fieldDots.length * 10 + 2} 10`, className: "mb-1", children: fieldDots.map((f, i) => /* @__PURE__ */ jsx(AvlFieldType, { x: i * 10 + 5, y: 5, kind: toFieldKind(f.type), size: 4 }, f.name)) }),
5918
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
5919
+ stateChain.length > 0 && /* @__PURE__ */ jsx("svg", { width: stateChain.length * 14 + 2, height: 10, viewBox: `0 0 ${stateChain.length * 14 + 2} 10`, children: stateChain.map((s, i) => {
5920
+ const tc = transitionCounts[s.name] ?? 0;
5921
+ const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
5922
+ return /* @__PURE__ */ jsxs(React8.Fragment, { children: [
5923
+ /* @__PURE__ */ jsx(AvlState, { x: i * 14 + 1, y: 1, width: 10, height: 8, name: "", role, isInitial: s.isInitial, isTerminal: s.isTerminal }),
5924
+ i < stateChain.length - 1 && /* @__PURE__ */ jsx("line", { x1: i * 14 + 12, y1: 5, x2: i * 14 + 15, y2: 5, stroke: "var(--color-border)", strokeWidth: 0.5 })
5925
+ ] }, s.name);
5926
+ }) }),
5927
+ pageDots.length > 0 && /* @__PURE__ */ jsx("svg", { width: pageDots.length * 10, height: 10, viewBox: `0 0 ${pageDots.length * 10} 10`, children: pageDots.map((p, i) => /* @__PURE__ */ jsx(AvlPage, { x: i * 10 + 4, y: 4, size: 5 }, p.name)) })
5928
+ ] })
5929
+ ]
5930
+ }
5931
+ );
5932
+ };
5933
+ SystemNode.displayName = "SystemNode";
5934
+ var NODE_W = 24;
5935
+ var NODE_H = 16;
5936
+ var GAP = 8;
5937
+ var ARROW_W = 16;
5938
+ var MiniStateMachine = ({ data, className }) => {
5939
+ const states = data.states;
5940
+ if (states.length === 0) return null;
5941
+ const transitionCounts = {};
5942
+ for (const s of states) transitionCounts[s.name] = 0;
5943
+ for (const t of data.transitions) {
5944
+ transitionCounts[t.from] = (transitionCounts[t.from] ?? 0) + 1;
5945
+ transitionCounts[t.to] = (transitionCounts[t.to] ?? 0) + 1;
5946
+ }
5947
+ const maxTC = Math.max(...Object.values(transitionCounts), 0);
5948
+ const effectTypes = /* @__PURE__ */ new Set();
5949
+ for (const t of data.transitions) {
5950
+ for (const e of t.effects) effectTypes.add(e.type);
5951
+ }
5952
+ const effectList = Array.from(effectTypes).slice(0, 6);
5953
+ const totalW = states.length * NODE_W + (states.length - 1) * (GAP + ARROW_W + GAP);
5954
+ const svgW = Math.max(totalW + 4, 60);
5955
+ const svgH = NODE_H + (effectList.length > 0 ? 18 : 4);
5956
+ return /* @__PURE__ */ jsxs("svg", { width: svgW, height: svgH, viewBox: `0 0 ${svgW} ${svgH}`, className, children: [
5957
+ states.map((s, i) => {
5958
+ const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
5959
+ const tc = transitionCounts[s.name] ?? 0;
5960
+ const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
5961
+ return /* @__PURE__ */ jsxs(React8.Fragment, { children: [
5962
+ /* @__PURE__ */ jsx(
5963
+ AvlState,
5964
+ {
5965
+ x,
5966
+ y: 0,
5967
+ width: NODE_W,
5968
+ height: NODE_H,
5969
+ name: "",
5970
+ role,
5971
+ isInitial: s.isInitial,
5972
+ isTerminal: s.isTerminal
5973
+ }
5974
+ ),
5975
+ i < states.length - 1 && /* @__PURE__ */ jsxs("g", { children: [
5976
+ /* @__PURE__ */ jsx(
5977
+ "line",
5978
+ {
5979
+ x1: x + NODE_W + GAP,
5980
+ y1: NODE_H / 2,
5981
+ x2: x + NODE_W + GAP + ARROW_W - 3,
5982
+ y2: NODE_H / 2,
5983
+ stroke: "var(--color-muted-foreground)",
5984
+ strokeWidth: 1,
5985
+ opacity: 0.4
5986
+ }
5987
+ ),
5988
+ /* @__PURE__ */ jsx(
5989
+ "polygon",
5990
+ {
5991
+ points: `${x + NODE_W + GAP + ARROW_W - 3},${NODE_H / 2 - 2.5} ${x + NODE_W + GAP + ARROW_W},${NODE_H / 2} ${x + NODE_W + GAP + ARROW_W - 3},${NODE_H / 2 + 2.5}`,
5992
+ fill: "var(--color-muted-foreground)",
5993
+ opacity: 0.4
5994
+ }
5995
+ )
5996
+ ] })
5997
+ ] }, s.name);
5998
+ }),
5999
+ effectList.length > 0 && /* @__PURE__ */ jsx("g", { children: effectList.map((et, i) => /* @__PURE__ */ jsx(
6000
+ AvlEffect,
6001
+ {
6002
+ x: 2 + i * 14,
6003
+ y: NODE_H + 4,
6004
+ effectType: et,
6005
+ size: 10,
6006
+ showBackground: true
6007
+ },
6008
+ et
6009
+ )) })
6010
+ ] });
6011
+ };
6012
+ MiniStateMachine.displayName = "MiniStateMachine";
6013
+ function toFieldKind2(type) {
6014
+ const normalized = type.toLowerCase();
6015
+ if (["string", "number", "boolean", "date", "enum", "object", "array"].includes(normalized)) {
6016
+ return normalized;
6017
+ }
6018
+ return "string";
6019
+ }
6020
+ var PERSISTENCE_BORDER = {
6021
+ persistent: "border-l-[3px] border-l-blue-500 border-solid",
6022
+ runtime: "border-l-[3px] border-l-blue-500 border-dashed",
6023
+ singleton: "border-l-[3px] border-l-blue-500 border-double",
6024
+ instance: "border-l-[3px] border-l-blue-500 border-dotted"
6025
+ };
6026
+ var PERSISTENCE_ICON = {
6027
+ persistent: "\u26C1",
6028
+ // ⛁ cylinder
6029
+ runtime: "\u27F3",
6030
+ // ⟳ cycle
6031
+ singleton: "\u25CE",
6032
+ // ◎ double ring
6033
+ instance: "\u22A1"
6034
+ // ⊡ box
6035
+ };
6036
+ var ModuleCard = ({ data }) => {
6037
+ const {
6038
+ orbitalName,
6039
+ entityName,
6040
+ persistence,
6041
+ fields,
6042
+ traits,
6043
+ pages,
6044
+ traitDetails,
6045
+ externalLinks
6046
+ } = data;
6047
+ const cols = Math.min(3, Math.max(2, Math.ceil(fields.length / 3)));
6048
+ return /* @__PURE__ */ jsxs(
6049
+ "div",
6050
+ {
6051
+ className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] shadow-sm overflow-hidden",
6052
+ style: { minWidth: 280, maxWidth: 400 },
6053
+ children: [
6054
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left, className: "!w-2.5 !h-2.5 !bg-orange-400" }),
6055
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right, className: "!w-2.5 !h-2.5 !bg-orange-400" }),
6056
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsx("span", { className: "text-[15px] font-bold text-[var(--color-foreground)]", children: orbitalName }) }),
6057
+ /* @__PURE__ */ jsxs("div", { className: `px-3 py-2 border-b border-[var(--color-border)] ${PERSISTENCE_BORDER[persistence] ?? ""}`, children: [
6058
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-1.5", children: [
6059
+ /* @__PURE__ */ jsx("svg", { width: 18, height: 18, viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(AvlEntity, { x: 10, y: 10, r: 8, persistence }) }),
6060
+ /* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold text-[var(--color-foreground)]", children: entityName }),
6061
+ /* @__PURE__ */ jsx("span", { className: "ml-auto text-[10px] opacity-50", title: persistence, children: PERSISTENCE_ICON[persistence] ?? "" })
6062
+ ] }),
6063
+ fields.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid gap-x-3 gap-y-0.5`, style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: fields.map((f) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
6064
+ /* @__PURE__ */ jsx("svg", { width: 14, height: 14, viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx(AvlFieldType, { x: 8, y: 8, kind: toFieldKind2(f.type), size: 6 }) }),
6065
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-[var(--color-muted-foreground)] truncate", children: f.name })
6066
+ ] }, f.name)) })
6067
+ ] }),
6068
+ traits.map((trait) => {
6069
+ const detail = traitDetails[trait.name];
6070
+ const traitEmits = externalLinks.filter((l) => l.direction === "out" && l.traitName === trait.name);
6071
+ const traitListens = externalLinks.filter((l) => l.direction === "in" && l.traitName === trait.name);
6072
+ return /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 border-b border-[var(--color-border)]", children: [
6073
+ /* @__PURE__ */ jsx("div", { className: "text-[12px] font-semibold text-[var(--color-foreground)] mb-1", children: trait.name }),
6074
+ detail && /* @__PURE__ */ jsx(MiniStateMachine, { data: detail, className: "mb-1" }),
6075
+ (traitEmits.length > 0 || traitListens.length > 0) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[9px] mt-1", children: [
6076
+ traitListens.map((l) => /* @__PURE__ */ jsxs("span", { style: { color: CONNECTION_COLORS.emitListen.color }, children: [
6077
+ "\u25C0~~",
6078
+ " ",
6079
+ l.eventName
6080
+ ] }, l.eventName)),
6081
+ traitListens.length > 0 && traitEmits.length > 0 && /* @__PURE__ */ jsx("span", { className: "flex-1" }),
6082
+ traitEmits.map((l) => /* @__PURE__ */ jsxs("span", { style: { color: CONNECTION_COLORS.emitListen.color }, className: "ml-auto", children: [
6083
+ l.eventName,
6084
+ " ",
6085
+ "~~\u25B6"
6086
+ ] }, l.eventName))
6087
+ ] })
6088
+ ] }, trait.name);
6089
+ }),
6090
+ pages.length > 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 flex items-center gap-2 flex-wrap", children: pages.map((p) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
6091
+ /* @__PURE__ */ jsx("svg", { width: 10, height: 10, viewBox: "0 0 12 12", children: /* @__PURE__ */ jsx(AvlPage, { x: 6, y: 6, size: 5 }) }),
6092
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono text-[var(--color-muted-foreground)]", children: p.route })
6093
+ ] }, p.name)) })
6094
+ ]
6095
+ }
6096
+ );
6097
+ };
6098
+ ModuleCard.displayName = "ModuleCard";
6099
+ var SWIM_GUTTER = 120;
6100
+ var CENTER_W = 360;
6101
+ var BehaviorView = ({ data }) => {
6102
+ const [layout, setLayout] = useState(null);
6103
+ const traitName = data.traits[0]?.name;
6104
+ const traitData = traitName ? data.traitDetails[traitName] : void 0;
6105
+ const dataKey = useMemo(() => JSON.stringify(traitData), [traitData]);
6106
+ useEffect(() => {
6107
+ if (!traitData) return;
6108
+ computeTraitLayout(traitData).then(setLayout).catch(console.error);
6109
+ }, [dataKey]);
6110
+ if (!traitData) {
6111
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: "No trait data" });
6112
+ }
6113
+ if (!layout) {
6114
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: "Computing layout..." });
6115
+ }
6116
+ const hasExternal = traitData.listenedEvents.length > 0 || traitData.emittedEvents.length > 0;
6117
+ const viewW = hasExternal ? SWIM_GUTTER + CENTER_W + SWIM_GUTTER : CENTER_W + 60;
6118
+ const machineOffsetX = hasExternal ? 0 : 30;
6119
+ const padding = 20;
6120
+ const availW = CENTER_W - padding * 2;
6121
+ const availH = 300;
6122
+ const scale = Math.min(1, availW / layout.width, availH / layout.height);
6123
+ const scaledH = layout.height * scale;
6124
+ const scaledW = layout.width * scale;
6125
+ const offsetX = padding + (availW - scaledW) / 2;
6126
+ const offsetY = 50 + (availH - scaledH) / 2;
6127
+ const machineHeight = scaledH + 100;
6128
+ const renderMachine = /* @__PURE__ */ jsxs("g", { children: [
6129
+ /* @__PURE__ */ jsx("text", { x: CENTER_W / 2, y: 20, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: 18, fontWeight: "700", fontFamily: "inherit", children: traitData.name }),
6130
+ /* @__PURE__ */ jsxs("text", { x: CENTER_W / 2, y: 36, textAnchor: "middle", fill: "var(--color-muted-foreground)", fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
6131
+ "on ",
6132
+ traitData.linkedEntity
6133
+ ] }),
6134
+ /* @__PURE__ */ jsxs("defs", { children: [
6135
+ /* @__PURE__ */ jsx("marker", { id: "bvArrow", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: CONNECTION_COLORS.forward.color, opacity: 0.7 }) }),
6136
+ /* @__PURE__ */ jsx("marker", { id: "bvArrowBack", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: CONNECTION_COLORS.backward.color, opacity: 0.5 }) })
6137
+ ] }),
6138
+ /* @__PURE__ */ jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
6139
+ layout.edges.map((edge) => {
6140
+ const conn = edge.isSelf ? CONNECTION_COLORS.selfLoop : edge.isBackward ? CONNECTION_COLORS.backward : CONNECTION_COLORS.forward;
6141
+ const marker = edge.isBackward || edge.isSelf ? "url(#bvArrowBack)" : "url(#bvArrow)";
6142
+ return /* @__PURE__ */ jsxs("g", { children: [
6143
+ /* @__PURE__ */ jsx(
6144
+ "path",
6145
+ {
6146
+ d: edgePath(edge.points),
6147
+ fill: "none",
6148
+ stroke: conn.color,
6149
+ strokeWidth: conn.width,
6150
+ strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
6151
+ opacity: 0.5,
6152
+ markerEnd: marker
6153
+ }
6154
+ ),
6155
+ /* @__PURE__ */ jsx(
6156
+ AvlTransitionLane,
6157
+ {
6158
+ x: edge.labelX,
6159
+ y: edge.labelY,
6160
+ event: edge.event,
6161
+ guard: edge.guardExpr,
6162
+ effects: edge.effects.map((e) => ({ type: e.type })),
6163
+ width: edge.labelW,
6164
+ isBackward: edge.isBackward,
6165
+ isSelfLoop: edge.isSelf
6166
+ }
6167
+ )
6168
+ ] }, edge.id);
6169
+ }),
6170
+ layout.nodes.map((node) => /* @__PURE__ */ jsx(
6171
+ AvlState,
6172
+ {
6173
+ x: node.x,
6174
+ y: node.y,
6175
+ width: node.width,
6176
+ height: node.height,
6177
+ name: node.id,
6178
+ isInitial: node.isInitial,
6179
+ isTerminal: node.isTerminal,
6180
+ role: node.role,
6181
+ transitionCount: node.transitionCount
6182
+ },
6183
+ node.id
6184
+ ))
6185
+ ] })
6186
+ ] });
6187
+ const svgH = machineHeight + 20;
6188
+ if (!hasExternal) {
6189
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] overflow-hidden", children: /* @__PURE__ */ jsx("svg", { width: viewW, height: svgH, viewBox: `0 0 ${viewW} ${svgH}`, children: /* @__PURE__ */ jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine }) }) });
6190
+ }
6191
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] overflow-hidden", children: /* @__PURE__ */ jsx("svg", { width: viewW, height: svgH, viewBox: `0 0 ${viewW} ${svgH}`, children: /* @__PURE__ */ jsx(
6192
+ AvlSwimLane,
6193
+ {
6194
+ listenedEvents: traitData.listenedEvents,
6195
+ emittedEvents: traitData.emittedEvents,
6196
+ centerWidth: CENTER_W,
6197
+ height: machineHeight,
6198
+ children: renderMachine
6199
+ }
6200
+ ) }) });
6201
+ };
6202
+ BehaviorView.displayName = "BehaviorView";
6203
+ var DetailView = ({ data }) => {
6204
+ const traitName = data.traits[0]?.name;
6205
+ const traitData = traitName ? data.traitDetails[traitName] : void 0;
6206
+ if (!traitData || traitData.transitions.length === 0) {
6207
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border-2 border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: "No transition data" });
6208
+ }
6209
+ const transition = traitData.transitions[0];
6210
+ const fromState = traitData.states.find((s) => s.name === transition.from);
6211
+ const toState = traitData.states.find((s) => s.name === transition.to);
6212
+ const transitionCounts = {};
6213
+ for (const s of traitData.states) transitionCounts[s.name] = 0;
6214
+ for (const t of traitData.transitions) {
6215
+ transitionCounts[t.from] = (transitionCounts[t.from] ?? 0) + 1;
6216
+ transitionCounts[t.to] = (transitionCounts[t.to] ?? 0) + 1;
6217
+ }
6218
+ const maxTC = Math.max(...Object.values(transitionCounts), 0);
6219
+ const fromRole = getStateRole(transition.from, fromState?.isInitial, fromState?.isTerminal, transitionCounts[transition.from] ?? 0, maxTC);
6220
+ const toRole = getStateRole(transition.to, toState?.isInitial, toState?.isTerminal, transitionCounts[transition.to] ?? 0, maxTC);
6221
+ const hasGuard = transition.guard != null;
6222
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-2 border-[var(--color-border)] bg-[var(--color-card)] overflow-hidden", style: { minWidth: 380, maxWidth: 500 }, children: [
6223
+ /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-[var(--color-border)] bg-[var(--color-background)]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
6224
+ /* @__PURE__ */ jsx("svg", { width: 90, height: 32, viewBox: "0 0 90 32", children: /* @__PURE__ */ jsx(AvlState, { x: 0, y: 0, width: 80, height: 28, name: transition.from, role: fromRole, isInitial: fromState?.isInitial, isTerminal: fromState?.isTerminal }) }),
6225
+ /* @__PURE__ */ jsxs("svg", { width: 24, height: 16, viewBox: "0 0 24 16", children: [
6226
+ /* @__PURE__ */ jsx("line", { x1: 0, y1: 8, x2: 18, y2: 8, stroke: "var(--color-muted-foreground)", strokeWidth: 2 }),
6227
+ /* @__PURE__ */ jsx("polygon", { points: "18,4 24,8 18,12", fill: "var(--color-muted-foreground)" })
6228
+ ] }),
6229
+ /* @__PURE__ */ jsx("svg", { width: 90, height: 32, viewBox: "0 0 90 32", children: /* @__PURE__ */ jsx(AvlState, { x: 0, y: 0, width: 80, height: 28, name: transition.to, role: toRole, isInitial: toState?.isInitial, isTerminal: toState?.isTerminal }) })
6230
+ ] }) }),
6231
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 space-y-3", children: [
6232
+ /* @__PURE__ */ jsxs("div", { children: [
6233
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wider text-[var(--color-muted-foreground)] mb-1", children: "Trigger" }),
6234
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6235
+ /* @__PURE__ */ jsx("svg", { width: 16, height: 16, viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx(AvlEvent, { x: 8, y: 8, size: 7 }) }),
6236
+ /* @__PURE__ */ jsx("span", { className: "text-[14px] font-semibold text-[var(--color-foreground)]", children: transition.event })
6237
+ ] })
6238
+ ] }),
6239
+ hasGuard && /* @__PURE__ */ jsxs("div", { children: [
6240
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wider text-[var(--color-muted-foreground)] mb-1", children: "Guard" }),
6241
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6242
+ /* @__PURE__ */ jsx("svg", { width: 14, height: 14, viewBox: "0 0 14 14", children: /* @__PURE__ */ jsx(AvlGuard, { x: 7, y: 7, size: 6 }) }),
6243
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-mono text-[var(--color-muted-foreground)] opacity-60", children: typeof transition.guard === "string" ? transition.guard : JSON.stringify(transition.guard) })
6244
+ ] })
6245
+ ] }),
6246
+ transition.effects.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
6247
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wider text-[var(--color-muted-foreground)] mb-1", children: "Effects" }),
6248
+ /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: transition.effects.map((effect, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5", children: [
6249
+ /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-[var(--color-muted-foreground)] w-3 text-right mt-0.5", children: [
6250
+ i + 1,
6251
+ "."
6252
+ ] }),
6253
+ /* @__PURE__ */ jsx("svg", { width: 18, height: 18, viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(AvlEffect, { x: 10, y: 10, effectType: effect.type, size: 8, showBackground: true }) }),
6254
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-[var(--color-foreground)]", children: effect.type })
6255
+ ] }, i)) })
6256
+ ] })
6257
+ ] })
6258
+ ] });
6259
+ };
6260
+ DetailView.displayName = "DetailView";
6261
+ var AvlOrbitalNode = (props) => {
6262
+ const band = useZoomBand();
6263
+ const data = props.data;
6264
+ switch (band) {
6265
+ case "system":
6266
+ return /* @__PURE__ */ jsx(SystemNode, { data });
6267
+ case "module":
6268
+ return /* @__PURE__ */ jsx(ModuleCard, { data });
6269
+ case "behavior":
6270
+ return /* @__PURE__ */ jsx(BehaviorView, { data });
6271
+ case "detail":
6272
+ return /* @__PURE__ */ jsx(DetailView, { data });
6273
+ }
6274
+ };
6275
+ AvlOrbitalNode.displayName = "AvlOrbitalNode";
6276
+ var AvlTransitionEdge = ({
6277
+ id,
6278
+ sourceX,
6279
+ sourceY,
6280
+ targetX,
6281
+ targetY,
6282
+ sourcePosition,
6283
+ targetPosition,
6284
+ data,
6285
+ markerEnd,
6286
+ style
6287
+ }) => {
6288
+ const [path, labelX, labelY] = getBezierPath({
6289
+ sourceX,
6290
+ sourceY,
6291
+ targetX,
6292
+ targetY,
6293
+ sourcePosition,
6294
+ targetPosition
6295
+ });
6296
+ const isBackward = targetX < sourceX;
6297
+ const connStyle = isBackward ? CONNECTION_COLORS.backward : CONNECTION_COLORS.forward;
6298
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6299
+ /* @__PURE__ */ jsx(
6300
+ BaseEdge,
6301
+ {
6302
+ id,
6303
+ path,
6304
+ markerEnd,
6305
+ style: {
6306
+ stroke: connStyle.color,
6307
+ strokeWidth: connStyle.width,
6308
+ strokeDasharray: connStyle.dash,
6309
+ ...style
6310
+ }
6311
+ }
6312
+ ),
6313
+ /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs(
6314
+ "div",
6315
+ {
6316
+ className: "absolute pointer-events-all nodrag nopan flex items-center gap-1",
6317
+ style: { transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)` },
6318
+ children: [
6319
+ data?.hasGuard && /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rotate-45 border border-amber-500 bg-amber-500/10 shrink-0", title: "Guard" }),
6320
+ /* @__PURE__ */ jsx("div", { className: "px-2 py-0.5 text-[10px] font-medium rounded-full bg-[var(--color-card)] border border-[var(--color-border)] text-[var(--color-foreground)] truncate max-w-[160px]", children: data?.event ?? "" }),
6321
+ data?.hasEffects && /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-violet-500/80 shrink-0", title: "Effects" })
6322
+ ]
6323
+ }
6324
+ ) })
6325
+ ] });
6326
+ };
6327
+ AvlTransitionEdge.displayName = "AvlTransitionEdge";
6328
+ var AvlEventWireEdge = ({
6329
+ id,
6330
+ sourceX,
6331
+ sourceY,
6332
+ targetX,
6333
+ targetY,
6334
+ sourcePosition,
6335
+ targetPosition,
6336
+ data,
6337
+ markerEnd,
6338
+ style
6339
+ }) => {
6340
+ const [path, labelX, labelY] = getBezierPath({
6341
+ sourceX,
6342
+ sourceY,
6343
+ targetX,
6344
+ targetY,
6345
+ sourcePosition,
6346
+ targetPosition
6347
+ });
6348
+ const isCompatible = data?.compatible !== false;
6349
+ const wireColor = isCompatible ? CONNECTION_COLORS.emitListen.color : "#EF4444";
6350
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6351
+ /* @__PURE__ */ jsx(
6352
+ BaseEdge,
6353
+ {
6354
+ id,
6355
+ path,
6356
+ markerEnd,
6357
+ style: {
6358
+ stroke: wireColor,
6359
+ strokeWidth: CONNECTION_COLORS.emitListen.width,
6360
+ strokeDasharray: CONNECTION_COLORS.emitListen.dash,
6361
+ ...style
6362
+ }
6363
+ }
6364
+ ),
6365
+ /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsx(
6366
+ "div",
6367
+ {
6368
+ className: "absolute pointer-events-all nodrag nopan",
6369
+ style: { transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)` },
6370
+ children: /* @__PURE__ */ jsx(
6371
+ "div",
6372
+ {
6373
+ className: "px-2 py-0.5 text-[10px] font-medium rounded-full border truncate max-w-[180px]",
6374
+ style: {
6375
+ color: wireColor,
6376
+ borderColor: wireColor,
6377
+ backgroundColor: `${wireColor}14`
6378
+ },
6379
+ children: data?.event ?? ""
6380
+ }
6381
+ )
6382
+ }
6383
+ ) })
6384
+ ] });
6385
+ };
6386
+ AvlEventWireEdge.displayName = "AvlEventWireEdge";
6387
+ var AvlBackwardEdge = ({
6388
+ id,
6389
+ sourceX,
6390
+ sourceY,
6391
+ targetX,
6392
+ targetY,
6393
+ sourcePosition,
6394
+ targetPosition,
6395
+ markerEnd,
6396
+ style
6397
+ }) => {
6398
+ const [path] = getBezierPath({
6399
+ sourceX,
6400
+ sourceY,
6401
+ targetX,
6402
+ targetY,
6403
+ sourcePosition,
6404
+ targetPosition
6405
+ });
6406
+ return /* @__PURE__ */ jsx(
6407
+ BaseEdge,
6408
+ {
6409
+ id,
6410
+ path,
6411
+ markerEnd,
6412
+ style: {
6413
+ stroke: CONNECTION_COLORS.backward.color,
6414
+ strokeWidth: CONNECTION_COLORS.backward.width,
6415
+ strokeDasharray: CONNECTION_COLORS.backward.dash,
6416
+ ...style
6417
+ }
6418
+ }
6419
+ );
6420
+ };
6421
+ AvlBackwardEdge.displayName = "AvlBackwardEdge";
6422
+ var PAGE_EDGE_COLOR = "#64748B";
6423
+ var AvlPageEdge = ({
6424
+ id,
6425
+ sourceX,
6426
+ sourceY,
6427
+ targetX,
6428
+ targetY,
6429
+ sourcePosition,
6430
+ targetPosition,
6431
+ markerEnd,
6432
+ style
6433
+ }) => {
6434
+ const [path] = getBezierPath({
6435
+ sourceX,
6436
+ sourceY,
6437
+ targetX,
6438
+ targetY,
6439
+ sourcePosition,
6440
+ targetPosition
6441
+ });
6442
+ return /* @__PURE__ */ jsx(
6443
+ BaseEdge,
6444
+ {
6445
+ id,
6446
+ path,
6447
+ markerEnd,
6448
+ style: {
6449
+ stroke: PAGE_EDGE_COLOR,
6450
+ strokeWidth: 1,
6451
+ ...style
6452
+ }
6453
+ }
6454
+ );
6455
+ };
6456
+ AvlPageEdge.displayName = "AvlPageEdge";
6457
+ var BINDING_COLOR = "#8B5CF6";
6458
+ var AvlBindingEdge = ({
6459
+ id,
6460
+ sourceX,
6461
+ sourceY,
6462
+ targetX,
6463
+ targetY,
6464
+ sourcePosition,
6465
+ targetPosition,
6466
+ markerEnd,
6467
+ style
6468
+ }) => {
6469
+ const [path, labelX, labelY] = getBezierPath({
6470
+ sourceX,
6471
+ sourceY,
6472
+ targetX,
6473
+ targetY,
6474
+ sourcePosition,
6475
+ targetPosition
6476
+ });
6477
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6478
+ /* @__PURE__ */ jsx(
6479
+ BaseEdge,
6480
+ {
6481
+ id,
6482
+ path,
6483
+ markerEnd,
6484
+ style: {
6485
+ stroke: BINDING_COLOR,
6486
+ strokeWidth: 1,
6487
+ strokeDasharray: "3 2",
6488
+ ...style
6489
+ }
6490
+ }
6491
+ ),
6492
+ /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsx(
6493
+ "div",
6494
+ {
6495
+ className: "absolute pointer-events-none nodrag nopan",
6496
+ style: { transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)` },
6497
+ children: /* @__PURE__ */ jsx(
6498
+ "span",
6499
+ {
6500
+ className: "text-[9px] font-mono font-medium",
6501
+ style: { color: BINDING_COLOR },
6502
+ children: "@"
6503
+ }
6504
+ )
6505
+ }
6506
+ ) })
6507
+ ] });
6508
+ };
6509
+ AvlBindingEdge.displayName = "AvlBindingEdge";
6510
+ var BAND_LABELS = {
6511
+ system: "System",
6512
+ module: "Module",
6513
+ behavior: "Behavior",
6514
+ detail: "Detail"
6515
+ };
6516
+ var BAND_ICONS = {
6517
+ system: "\u25C9",
6518
+ // ◉ filled circle
6519
+ module: "\u25C9",
6520
+ // ◉ filled circle
6521
+ behavior: "\u25CE",
6522
+ // ◎ double circle
6523
+ detail: "\u26A1"
6524
+ // ⚡ lightning
6525
+ };
6526
+ var ZoomBreadcrumb = ({
6527
+ band,
6528
+ applicationName,
6529
+ orbitalName,
6530
+ traitName,
6531
+ eventName
6532
+ }) => {
6533
+ const segments = [];
6534
+ if (applicationName) {
6535
+ segments.push({ icon: "\u25C9", label: applicationName });
6536
+ }
6537
+ segments.push({ icon: BAND_ICONS[band], label: BAND_LABELS[band] });
6538
+ if (orbitalName && (band === "module" || band === "behavior" || band === "detail")) {
6539
+ segments.push({ icon: "\u25C9", label: orbitalName });
6540
+ }
6541
+ if (traitName && (band === "behavior" || band === "detail")) {
6542
+ segments.push({ icon: "\u25CE", label: traitName });
6543
+ }
6544
+ if (eventName && band === "detail") {
6545
+ segments.push({ icon: "\u26A1", label: eventName });
6546
+ }
6547
+ return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-[var(--color-card)]/90 border border-[var(--color-border)] text-[11px] text-[var(--color-muted-foreground)] backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
6548
+ i > 0 && /* @__PURE__ */ jsx("span", { className: "opacity-40", children: ">" }),
6549
+ /* @__PURE__ */ jsx("span", { className: "opacity-60", children: seg.icon }),
6550
+ /* @__PURE__ */ jsx("span", { children: seg.label })
6551
+ ] }, i)) });
6552
+ };
6553
+ ZoomBreadcrumb.displayName = "ZoomBreadcrumb";
6554
+ var BAND_LEGENDS = {
6555
+ system: [
6556
+ { icon: "\u25C9", label: "Entity" },
6557
+ { icon: "\u25CF\u25B2\u25A0\u25C6", label: "Field types" },
6558
+ { icon: "\u25CF\u2501\u25CF", label: "State chain" },
6559
+ { icon: "\u25A0", label: "Page" },
6560
+ { icon: "\u2500 \u2500", label: "Event wire" }
6561
+ ],
6562
+ module: [
6563
+ { icon: "\u25C9", label: "Entity" },
6564
+ { icon: "\u26C1", label: "Persistence" },
6565
+ { icon: "\u25CF\u25B2\u25A0\u25C6\u25CB\u2B21\u2261", label: "Field types" },
6566
+ { icon: "\u2501\u25CF\u2501", label: "State machine" },
6567
+ { icon: "\u229E\u270E\u26C1\u{1F4E1}", label: "Effects" },
6568
+ { icon: "\u25A0", label: "Page" },
6569
+ { icon: "\u25C0\u301C\u301C / \u301C\u301C\u25B6", label: "Emit/Listen" }
6570
+ ],
6571
+ behavior: [
6572
+ { icon: "\u25CF green", label: "Initial state" },
6573
+ { icon: "\u25CF red", label: "Terminal state" },
6574
+ { icon: "\u25CF blue", label: "Hub state" },
6575
+ { icon: "\u26A1", label: "Event" },
6576
+ { icon: "\u25C7", label: "Guard" },
6577
+ { icon: "\u229E\u270E\u26C1\u{1F4E1}\u{1F514}", label: "Effects" },
6578
+ { icon: "\u2500 \u2500 orange", label: "Emit/Listen" }
6579
+ ],
6580
+ detail: [
6581
+ { icon: "\u26A1", label: "Trigger event" },
6582
+ { icon: "\u25C7", label: "Guard diamond" },
6583
+ { icon: "\u229E", label: "render-ui" },
6584
+ { icon: "\u270E", label: "set" },
6585
+ { icon: "\u26C1", label: "persist" },
6586
+ { icon: "\u{1F4E1}", label: "emit" },
6587
+ { icon: "@", label: "Binding" },
6588
+ { icon: "\u25CF\u25B2\u25A0", label: "Field types" }
6589
+ ]
6590
+ };
6591
+ var ZoomLegend = ({ band }) => {
6592
+ const [collapsed, setCollapsed] = useState(true);
6593
+ const items = BAND_LEGENDS[band];
6594
+ return /* @__PURE__ */ jsxs("div", { className: "absolute bottom-2 left-2 z-10", children: [
6595
+ /* @__PURE__ */ jsx(
6596
+ "button",
6597
+ {
6598
+ onClick: () => setCollapsed(!collapsed),
6599
+ className: "px-2 py-1 text-[10px] rounded-md bg-[var(--color-card)]/90 border border-[var(--color-border)] text-[var(--color-muted-foreground)] backdrop-blur-sm cursor-pointer hover:bg-[var(--color-card)]",
6600
+ children: collapsed ? "Legend" : "Hide"
6601
+ }
6602
+ ),
6603
+ !collapsed && /* @__PURE__ */ jsx("div", { className: "mt-1 px-2 py-1.5 rounded-md bg-[var(--color-card)]/95 border border-[var(--color-border)] backdrop-blur-sm space-y-0.5", children: items.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-[var(--color-muted-foreground)]", children: [
6604
+ /* @__PURE__ */ jsx("span", { className: "opacity-70 w-6 text-center", children: item.icon }),
6605
+ /* @__PURE__ */ jsx("span", { children: item.label })
6606
+ ] }, i)) })
6607
+ ] });
6608
+ };
6609
+ ZoomLegend.displayName = "ZoomLegend";
6610
+ var NODE_TYPES = {
6611
+ orbital: AvlOrbitalNode
6612
+ };
6613
+ var EDGE_TYPES = {
6614
+ transition: AvlTransitionEdge,
6615
+ eventWire: AvlEventWireEdge,
6616
+ backward: AvlBackwardEdge,
6617
+ page: AvlPageEdge,
6618
+ binding: AvlBindingEdge
6619
+ };
6620
+ function bandToZoomLevel(band) {
6621
+ switch (band) {
6622
+ case "system":
6623
+ return "application";
6624
+ case "module":
6625
+ return "orbital";
6626
+ case "behavior":
6627
+ return "trait";
6628
+ case "detail":
6629
+ return "transition";
6630
+ }
6631
+ }
6632
+ function FlowCanvasInner({
6633
+ schema: schemaProp,
6634
+ className,
6635
+ color = "var(--color-primary)",
6636
+ width = "100%",
6637
+ height = 500,
6638
+ onZoomChange,
6639
+ focusTarget,
6640
+ initialOrbital
6641
+ }) {
6642
+ const parsedSchema = useMemo(() => {
6643
+ if (typeof schemaProp === "string") return JSON.parse(schemaProp);
6644
+ return schemaProp;
6645
+ }, [schemaProp]);
6646
+ const { nodes: initialNodes, edges: initialEdges } = useMemo(
6647
+ () => schemaToFlowGraph(parsedSchema),
6648
+ [parsedSchema]
6649
+ );
6650
+ const [nodes, , onNodesChange] = useNodesState(initialNodes);
6651
+ const [edges, , onEdgesChange] = useEdgesState(initialEdges);
6652
+ const [band, setBand] = useState("module");
6653
+ const reactFlow = useReactFlow();
6654
+ const handleViewportChange = useCallback((viewport) => {
6655
+ const newBand = computeZoomBand(viewport.zoom);
6656
+ setBand((prev) => {
6657
+ if (prev !== newBand) {
6658
+ onZoomChange?.(bandToZoomLevel(newBand), {});
6659
+ return newBand;
6660
+ }
6661
+ return prev;
6662
+ });
6663
+ }, [onZoomChange]);
6664
+ useEffect(() => {
6665
+ if (!focusTarget) return;
6666
+ const targetNode = nodes.find(
6667
+ (n) => focusTarget.type === "orbital" && n.id === focusTarget.name
6668
+ );
6669
+ if (targetNode) {
6670
+ reactFlow.fitView({ nodes: [targetNode], duration: 500, padding: 0.5 });
6671
+ }
6672
+ }, [focusTarget, nodes, reactFlow]);
6673
+ useEffect(() => {
6674
+ if (!initialOrbital) return;
6675
+ const targetNode = nodes.find((n) => n.id === initialOrbital);
6676
+ if (targetNode) {
6677
+ requestAnimationFrame(() => {
6678
+ reactFlow.fitView({ nodes: [targetNode], duration: 0, padding: 0.3 });
6679
+ });
6680
+ }
6681
+ }, [initialOrbital]);
6682
+ return /* @__PURE__ */ jsx(ZoomBandContext.Provider, { value: band, children: /* @__PURE__ */ jsxs(
6683
+ Box,
6684
+ {
6685
+ className: `relative ${className ?? ""}`,
6686
+ style: { width, height, "--avl-color": color },
6687
+ children: [
6688
+ /* @__PURE__ */ jsxs(
6689
+ ReactFlow,
6690
+ {
6691
+ nodes,
6692
+ edges,
6693
+ nodeTypes: NODE_TYPES,
6694
+ edgeTypes: EDGE_TYPES,
6695
+ onNodesChange,
6696
+ onEdgesChange,
6697
+ onViewportChange: handleViewportChange,
6698
+ minZoom: 0.1,
6699
+ maxZoom: 5,
6700
+ fitView: true,
6701
+ nodesDraggable: true,
6702
+ elementsSelectable: true,
6703
+ proOptions: { hideAttribution: true },
6704
+ style: { background: "var(--color-background)" },
6705
+ children: [
6706
+ /* @__PURE__ */ jsx(
6707
+ Controls,
6708
+ {
6709
+ showInteractive: false,
6710
+ style: {
6711
+ background: "var(--color-card)",
6712
+ border: "1px solid var(--color-border)",
6713
+ borderRadius: "var(--radius-md)"
6714
+ }
6715
+ }
6716
+ ),
6717
+ /* @__PURE__ */ jsx(
6718
+ Background,
6719
+ {
6720
+ variant: BackgroundVariant.Dots,
6721
+ gap: 20,
6722
+ size: 1,
6723
+ color: "var(--color-border)"
6724
+ }
6725
+ )
6726
+ ]
6727
+ }
6728
+ ),
6729
+ /* @__PURE__ */ jsx(ZoomBreadcrumb, { band }),
6730
+ /* @__PURE__ */ jsx(ZoomLegend, { band })
6731
+ ]
6732
+ }
6733
+ ) });
6734
+ }
6735
+ var FlowCanvas = (props) => {
6736
+ return /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(FlowCanvasInner, { ...props }) });
6737
+ };
6738
+ FlowCanvas.displayName = "FlowCanvas";
6739
+ var AvlCosmicZoom = (props) => {
6740
+ return /* @__PURE__ */ jsx(
6741
+ FlowCanvas,
6742
+ {
6743
+ schema: props.schema,
6744
+ className: props.className,
6745
+ color: props.color,
6746
+ animated: props.animated,
6747
+ width: props.width,
6748
+ height: props.height ?? 400,
6749
+ onZoomChange: props.onZoomChange,
6750
+ focusTarget: props.focusTarget,
6751
+ initialOrbital: props.initialOrbital,
6752
+ initialTrait: props.initialTrait,
6753
+ stateCoverage: props.stateCoverage
6754
+ }
6755
+ );
6756
+ };
6757
+ AvlCosmicZoom.displayName = "AvlCosmicZoom";
6758
+ var SWIM_GUTTER2 = 120;
6759
+ var CENTER_W2 = 360;
6760
+ var AvlTraitScene = ({
6761
+ data,
6762
+ color = "var(--color-primary)",
6763
+ onTransitionClick
6764
+ }) => {
6765
+ const [layout, setLayout] = useState(null);
6494
6766
  const dataKey = useMemo(() => JSON.stringify(data), [data]);
6495
6767
  useEffect(() => {
6496
- computeLayout(data).then(setLayout).catch(console.error);
6768
+ computeTraitLayout(data).then(setLayout).catch(console.error);
6497
6769
  }, [dataKey]);
6498
6770
  if (!layout) {
6499
6771
  return /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("text", { x: 300, y: 200, textAnchor: "middle", fill: color, fontSize: 12, opacity: 0.5, children: "Computing layout..." }) });
@@ -6501,7 +6773,7 @@ var AvlTraitScene = ({
6501
6773
  const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
6502
6774
  const machineOffsetX = hasExternal ? 0 : 30;
6503
6775
  const padding = 20;
6504
- const availW = CENTER_W - padding * 2;
6776
+ const availW = CENTER_W2 - padding * 2;
6505
6777
  const availH = 300;
6506
6778
  const scale = Math.min(1, availW / layout.width, availH / layout.height);
6507
6779
  const scaledW = layout.width * scale;
@@ -6510,8 +6782,8 @@ var AvlTraitScene = ({
6510
6782
  const offsetY = 50 + (availH - scaledH) / 2;
6511
6783
  const machineHeight = scaledH + 100;
6512
6784
  const renderMachine = /* @__PURE__ */ jsxs("g", { children: [
6513
- /* @__PURE__ */ jsx("text", { x: CENTER_W / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
6514
- /* @__PURE__ */ jsxs("text", { x: CENTER_W / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
6785
+ /* @__PURE__ */ jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
6786
+ /* @__PURE__ */ jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
6515
6787
  "linked to ",
6516
6788
  data.linkedEntity
6517
6789
  ] }),
@@ -6549,7 +6821,7 @@ var AvlTraitScene = ({
6549
6821
  isSelfLoop: edge.isSelf,
6550
6822
  color,
6551
6823
  onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
6552
- x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER : machineOffsetX),
6824
+ x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
6553
6825
  y: edge.labelY + offsetY
6554
6826
  }) : void 0
6555
6827
  }
@@ -6581,7 +6853,7 @@ var AvlTraitScene = ({
6581
6853
  {
6582
6854
  listenedEvents: data.listenedEvents,
6583
6855
  emittedEvents: data.emittedEvents,
6584
- centerWidth: CENTER_W,
6856
+ centerWidth: CENTER_W2,
6585
6857
  height: machineHeight,
6586
6858
  color,
6587
6859
  children: renderMachine
@@ -6589,9 +6861,9 @@ var AvlTraitScene = ({
6589
6861
  );
6590
6862
  };
6591
6863
  AvlTraitScene.displayName = "AvlTraitScene";
6592
- var CX2 = 300;
6864
+ var CX = 300;
6593
6865
  var CARD_W = 440;
6594
- var CARD_X = CX2 - CARD_W / 2;
6866
+ var CARD_X = CX - CARD_W / 2;
6595
6867
  var SECTION_LEFT = CARD_X + 16;
6596
6868
  var CONTENT_LEFT = CARD_X + 24;
6597
6869
  function flattenEffect(node) {
@@ -6708,7 +6980,7 @@ var AvlTransitionScene = ({
6708
6980
  /* @__PURE__ */ jsx(
6709
6981
  "text",
6710
6982
  {
6711
- x: CX2,
6983
+ x: CX,
6712
6984
  y: cardY + 32,
6713
6985
  textAnchor: "middle",
6714
6986
  fill: color,
@@ -6826,397 +7098,68 @@ var AvlTransitionScene = ({
6826
7098
  ] });
6827
7099
  };
6828
7100
  AvlTransitionScene.displayName = "AvlTransitionScene";
6829
- var APPLICATION_ITEMS = [
6830
- {
6831
- label: "Orbital",
6832
- render: (x, y, c) => /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 8, fill: "none", stroke: c, strokeWidth: 1.5 })
6833
- },
6834
- {
6835
- label: "Entity",
6836
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6837
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: c, opacity: 0.2 }),
6838
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: "none", stroke: c, strokeWidth: 1.5 })
6839
- ] })
6840
- },
6841
- {
6842
- label: "Trait",
6843
- render: (x, y, c) => /* @__PURE__ */ jsx("ellipse", { cx: x, cy: y, rx: 10, ry: 5, fill: "none", stroke: c, strokeWidth: 1, strokeDasharray: "3 1.5" })
6844
- },
6845
- {
6846
- label: "Page",
6847
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 3, y: y - 3, width: 6, height: 6, fill: c, opacity: 0.3, stroke: c, strokeWidth: 1 })
6848
- },
6849
- {
6850
- label: "Event flow",
6851
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6852
- /* @__PURE__ */ jsx("line", { x1: x - 10, y1: y, x2: x + 10, y2: y, stroke: c, strokeWidth: 1, strokeDasharray: "4 2" }),
6853
- /* @__PURE__ */ jsx("polygon", { points: `${x + 10},${y} ${x + 6},${y - 3} ${x + 6},${y + 3}`, fill: c, opacity: 0.5 })
6854
- ] })
6855
- }
6856
- ];
6857
- var ORBITAL_ITEMS = [
6858
- {
6859
- label: "Orbital boundary",
6860
- render: (x, y, c) => /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 8, fill: "none", stroke: c, strokeWidth: 1.5 })
6861
- },
6862
- {
6863
- label: "Entity (nucleus)",
6864
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6865
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: c, opacity: 0.15 }),
6866
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: "none", stroke: c, strokeWidth: 2 }),
6867
- /* @__PURE__ */ jsx("line", { x1: x, y1: y - 7, x2: x, y2: y - 9, stroke: c, strokeWidth: 0.8, opacity: 0.5 })
6868
- ] })
6869
- },
6870
- {
6871
- label: "Trait ring",
6872
- render: (x, y, c) => /* @__PURE__ */ jsx("ellipse", { cx: x, cy: y, rx: 10, ry: 5, fill: "none", stroke: c, strokeWidth: 1, strokeDasharray: "3 1.5" })
6873
- },
6874
- {
6875
- label: "Page",
6876
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 3, y: y - 3, width: 6, height: 6, fill: c, opacity: 0.3, stroke: c, strokeWidth: 1 })
6877
- },
6878
- {
6879
- label: "External link",
6880
- render: (x, y, c) => /* @__PURE__ */ jsx("line", { x1: x - 8, y1: y, x2: x + 8, y2: y, stroke: c, strokeWidth: 1, strokeDasharray: "4 2", opacity: 0.4 })
6881
- }
6882
- ];
6883
- var TRAIT_ITEMS = [
6884
- {
6885
- label: "State",
6886
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 12, y: y - 6, width: 24, height: 12, rx: 6, fill: "none", stroke: c, strokeWidth: 1.5 })
6887
- },
6888
- {
6889
- label: "Initial state",
6890
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6891
- /* @__PURE__ */ jsx("circle", { cx: x - 10, cy: y, r: 3, fill: c }),
6892
- /* @__PURE__ */ jsx("rect", { x: x - 4, y: y - 6, width: 20, height: 12, rx: 6, fill: "none", stroke: c, strokeWidth: 1.5 })
6893
- ] })
6894
- },
6895
- {
6896
- label: "Transition",
6897
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6898
- /* @__PURE__ */ jsx("line", { x1: x - 10, y1: y, x2: x + 8, y2: y, stroke: c, strokeWidth: 1.2, opacity: 0.5 }),
6899
- /* @__PURE__ */ jsx("polygon", { points: `${x + 10},${y} ${x + 6},${y - 3} ${x + 6},${y + 3}`, fill: c, opacity: 0.5 })
6900
- ] })
6901
- },
6902
- {
6903
- label: "Event + effects",
6904
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 14, y: y - 7, width: 28, height: 14, rx: 3, fill: "var(--color-surface, white)", stroke: c, strokeWidth: 0.8 })
6905
- },
6906
- {
6907
- label: "Emit (external)",
6908
- render: (x, y, c) => /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 3, fill: c, opacity: 0.5, children: /* @__PURE__ */ jsx("animate", { attributeName: "r", values: "2;4;2", dur: "1.5s", repeatCount: "indefinite" }) })
6909
- }
6910
- ];
6911
- var TRANSITION_ITEMS = [
6912
- {
6913
- label: "State",
6914
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 12, y: y - 6, width: 24, height: 12, rx: 6, fill: "none", stroke: c, strokeWidth: 1.5 })
6915
- },
6916
- {
6917
- label: "Effect",
6918
- render: (x, y, c) => /* @__PURE__ */ jsxs("g", { children: [
6919
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: c, opacity: 0.15 }),
6920
- /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: "none", stroke: c, strokeWidth: 1 })
6921
- ] })
6922
- },
6923
- {
6924
- label: "Slot target",
6925
- render: (x, y, c) => /* @__PURE__ */ jsx("rect", { x: x - 10, y: y - 5, width: 20, height: 10, rx: 2, fill: c, opacity: 0.1, stroke: c, strokeWidth: 0.8 })
6926
- },
6927
- {
6928
- label: "Binding (@path)",
6929
- render: (x, y, c) => /* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 5, fill: "none", stroke: c, strokeWidth: 1, strokeDasharray: "2 1.5", opacity: 0.6 })
6930
- }
6931
- ];
6932
- var ITEMS_BY_LEVEL = {
6933
- application: APPLICATION_ITEMS,
6934
- orbital: ORBITAL_ITEMS,
6935
- trait: TRAIT_ITEMS,
6936
- transition: TRANSITION_ITEMS
6937
- };
6938
- var AvlLegend = ({
6939
- level,
6940
- color = "var(--color-primary)",
6941
- x = 10,
6942
- y = 360
7101
+ var AvlClickTarget = ({
7102
+ x,
7103
+ y,
7104
+ width,
7105
+ height,
7106
+ onClick,
7107
+ onHover,
7108
+ cursor = "pointer",
7109
+ glowColor = "var(--color-primary)",
7110
+ label,
7111
+ children
6943
7112
  }) => {
6944
- const items = ITEMS_BY_LEVEL[level];
6945
- const itemSpacing = 16;
6946
- const legendH = items.length * itemSpacing + 16;
6947
- return /* @__PURE__ */ jsxs("g", { opacity: 0.6, children: [
7113
+ const [hovering, setHovering] = useState(false);
7114
+ const handleMouseEnter = useCallback(() => {
7115
+ setHovering(true);
7116
+ onHover?.(true);
7117
+ }, [onHover]);
7118
+ const handleMouseLeave = useCallback(() => {
7119
+ setHovering(false);
7120
+ onHover?.(false);
7121
+ }, [onHover]);
7122
+ const handleKeyDown = useCallback((e) => {
7123
+ if (e.key === "Enter" || e.key === " ") {
7124
+ e.preventDefault();
7125
+ onClick();
7126
+ }
7127
+ }, [onClick]);
7128
+ return /* @__PURE__ */ jsxs("g", { children: [
7129
+ hovering && /* @__PURE__ */ jsx(
7130
+ "rect",
7131
+ {
7132
+ x: x - 4,
7133
+ y: y - 4,
7134
+ width: width + 8,
7135
+ height: height + 8,
7136
+ rx: 8,
7137
+ fill: glowColor,
7138
+ opacity: 0.08
7139
+ }
7140
+ ),
7141
+ children,
6948
7142
  /* @__PURE__ */ jsx(
6949
7143
  "rect",
6950
7144
  {
6951
7145
  x,
6952
- y: y - legendH + 10,
6953
- width: 130,
6954
- height: legendH,
6955
- rx: 6,
6956
- fill: "var(--color-surface, white)",
6957
- stroke: color,
6958
- strokeWidth: 0.5,
6959
- opacity: 0.8
7146
+ y,
7147
+ width,
7148
+ height,
7149
+ fill: "transparent",
7150
+ style: { cursor },
7151
+ pointerEvents: "all",
7152
+ onClick,
7153
+ onMouseEnter: handleMouseEnter,
7154
+ onMouseLeave: handleMouseLeave,
7155
+ onKeyDown: handleKeyDown,
7156
+ tabIndex: 0,
7157
+ role: "button",
7158
+ "aria-label": label
6960
7159
  }
6961
- ),
6962
- items.map((item, i) => {
6963
- const iy = y - legendH + 22 + i * itemSpacing;
6964
- return /* @__PURE__ */ jsxs("g", { children: [
6965
- item.render(x + 18, iy, color),
6966
- /* @__PURE__ */ jsx(
6967
- "text",
6968
- {
6969
- x: x + 35,
6970
- y: iy + 4,
6971
- fill: color,
6972
- fontSize: 8,
6973
- opacity: 0.8,
6974
- children: item.label
6975
- }
6976
- )
6977
- ] }, item.label);
6978
- })
7160
+ )
6979
7161
  ] });
6980
7162
  };
6981
- AvlLegend.displayName = "AvlLegend";
6982
- var VIEWBOX_W = 600;
6983
- var VIEWBOX_H2 = 400;
6984
- var ANIMATION_DURATION = 600;
6985
- var AvlCosmicZoom = ({
6986
- schema: schemaProp,
6987
- className,
6988
- color = "var(--color-primary)",
6989
- animated = true,
6990
- initialOrbital,
6991
- initialTrait,
6992
- onZoomChange,
6993
- width = "100%",
6994
- height = 400,
6995
- stateCoverage
6996
- }) => {
6997
- const schema = useMemo(() => {
6998
- if (typeof schemaProp === "string") {
6999
- try {
7000
- return JSON.parse(schemaProp);
7001
- } catch {
7002
- return { name: "Error", orbitals: [] };
7003
- }
7004
- }
7005
- return schemaProp;
7006
- }, [schemaProp]);
7007
- const [state, dispatch] = useReducer(zoomReducer, initialZoomState);
7008
- const sceneRef = useRef(null);
7009
- const [transitionStyle, setTransitionStyle] = useState({});
7010
- useEffect(() => {
7011
- if (initialOrbital) {
7012
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: initialOrbital, targetPosition: { x: VIEWBOX_W / 2, y: VIEWBOX_H2 / 2 } });
7013
- setTimeout(() => dispatch({ type: "ANIMATION_COMPLETE" }), 0);
7014
- if (initialTrait) {
7015
- setTimeout(() => {
7016
- dispatch({ type: "ZOOM_INTO_TRAIT", trait: initialTrait, targetPosition: { x: VIEWBOX_W / 2, y: VIEWBOX_H2 / 2 } });
7017
- setTimeout(() => dispatch({ type: "ANIMATION_COMPLETE" }), 0);
7018
- }, 10);
7019
- }
7020
- }
7021
- }, [initialOrbital, initialTrait]);
7022
- useEffect(() => {
7023
- onZoomChange?.(state.level, {
7024
- orbital: state.selectedOrbital ?? void 0,
7025
- trait: state.selectedTrait ?? void 0
7026
- });
7027
- }, [state.level, state.selectedOrbital, state.selectedTrait, onZoomChange]);
7028
- useEffect(() => {
7029
- if (!state.animating || !animated) {
7030
- if (state.animating) {
7031
- dispatch({ type: "ANIMATION_COMPLETE" });
7032
- }
7033
- setTransitionStyle({});
7034
- return;
7035
- }
7036
- const target = state.animationTarget;
7037
- if (!target) return;
7038
- if (state.animationDirection === "in") {
7039
- setTransitionStyle({
7040
- transform: `scale(${target.scale}) translate(${-(target.x - VIEWBOX_W / 2)}px, ${-(target.y - VIEWBOX_H2 / 2)}px)`,
7041
- transformOrigin: `${target.x}px ${target.y}px`,
7042
- transition: `transform ${ANIMATION_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${ANIMATION_DURATION}ms ease`,
7043
- opacity: 0.3
7044
- });
7045
- } else {
7046
- setTransitionStyle({
7047
- transform: `scale(${target.scale})`,
7048
- transformOrigin: "center center",
7049
- transition: `transform ${ANIMATION_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${ANIMATION_DURATION}ms ease`,
7050
- opacity: 0.3
7051
- });
7052
- }
7053
- const timer = setTimeout(() => {
7054
- dispatch({ type: "ANIMATION_COMPLETE" });
7055
- setTransitionStyle({});
7056
- }, ANIMATION_DURATION);
7057
- return () => clearTimeout(timer);
7058
- }, [state.animating, state.animationDirection, state.animationTarget, animated]);
7059
- const handleKeyDown = useCallback((e) => {
7060
- if (e.key === "Escape") {
7061
- dispatch({ type: "ZOOM_OUT" });
7062
- }
7063
- }, []);
7064
- const handleOrbitalClick = useCallback((name, pos) => {
7065
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: pos });
7066
- }, []);
7067
- const handleTraitClick = useCallback((name, pos) => {
7068
- dispatch({ type: "ZOOM_INTO_TRAIT", trait: name, targetPosition: pos });
7069
- }, []);
7070
- const handleTraitSwitch = useCallback((name) => {
7071
- dispatch({ type: "SWITCH_TRAIT", trait: name });
7072
- }, []);
7073
- const [highlightedTrait, setHighlightedTrait] = React8.useState(null);
7074
- const handleTransitionClick = useCallback((index, pos) => {
7075
- dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: index, targetPosition: pos });
7076
- }, []);
7077
- const handleBreadcrumbClick = useCallback((targetLevel) => {
7078
- const levelOrder = ["application", "orbital", "trait", "transition"];
7079
- const currentIdx = levelOrder.indexOf(state.level);
7080
- const targetIdx = levelOrder.indexOf(targetLevel);
7081
- if (targetIdx < currentIdx) {
7082
- dispatch({ type: "ZOOM_OUT" });
7083
- }
7084
- }, [state.level]);
7085
- const sceneContent = useMemo(() => {
7086
- switch (state.level) {
7087
- case "application": {
7088
- const data = parseApplicationLevel(schema);
7089
- return /* @__PURE__ */ jsx(
7090
- AvlApplicationScene,
7091
- {
7092
- data,
7093
- color,
7094
- onOrbitalClick: handleOrbitalClick
7095
- }
7096
- );
7097
- }
7098
- case "orbital": {
7099
- if (!state.selectedOrbital) return null;
7100
- const data = parseOrbitalLevel(schema, state.selectedOrbital);
7101
- if (!data) return null;
7102
- return /* @__PURE__ */ jsx(
7103
- AvlOrbitalScene,
7104
- {
7105
- data,
7106
- color,
7107
- highlightedTrait,
7108
- onTraitClick: handleTraitClick,
7109
- onTraitHighlight: setHighlightedTrait
7110
- }
7111
- );
7112
- }
7113
- case "trait": {
7114
- if (!state.selectedOrbital || !state.selectedTrait) return null;
7115
- const data = parseTraitLevel(schema, state.selectedOrbital, state.selectedTrait);
7116
- if (!data) return null;
7117
- return /* @__PURE__ */ jsx(
7118
- AvlTraitScene,
7119
- {
7120
- data,
7121
- color,
7122
- onTransitionClick: handleTransitionClick
7123
- }
7124
- );
7125
- }
7126
- case "transition": {
7127
- if (!state.selectedOrbital || !state.selectedTrait || state.selectedTransition === null) return null;
7128
- const data = parseTransitionLevel(schema, state.selectedOrbital, state.selectedTrait, state.selectedTransition);
7129
- if (!data) return null;
7130
- return /* @__PURE__ */ jsx(
7131
- AvlTransitionScene,
7132
- {
7133
- data,
7134
- color
7135
- }
7136
- );
7137
- }
7138
- default:
7139
- return null;
7140
- }
7141
- }, [state.level, state.selectedOrbital, state.selectedTrait, state.selectedTransition, schema, color, handleOrbitalClick, handleTraitClick, handleTransitionClick, highlightedTrait, setHighlightedTrait]);
7142
- const breadcrumbs = getBreadcrumbs(state);
7143
- return /* @__PURE__ */ jsxs(
7144
- Box,
7145
- {
7146
- className: `relative ${className ?? ""}`,
7147
- style: { width, height: typeof height === "number" ? `${height}px` : height },
7148
- onKeyDown: handleKeyDown,
7149
- tabIndex: 0,
7150
- children: [
7151
- /* @__PURE__ */ jsx(
7152
- HStack,
7153
- {
7154
- gap: "xs",
7155
- align: "center",
7156
- className: "absolute top-2 left-2 z-10 bg-surface/80 backdrop-blur rounded-md px-3 py-1.5",
7157
- children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
7158
- i > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mx-1", children: "/" }),
7159
- i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsx(
7160
- Box,
7161
- {
7162
- as: "span",
7163
- className: "cursor-pointer hover:underline",
7164
- onClick: () => handleBreadcrumbClick(crumb.level),
7165
- children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: crumb.label })
7166
- }
7167
- ) : /* @__PURE__ */ jsx(Typography, { variant: "small", color: "primary", className: "font-bold", children: crumb.label })
7168
- ] }, crumb.level))
7169
- }
7170
- ),
7171
- state.level === "trait" && state.selectedOrbital && (() => {
7172
- const orbData = parseOrbitalLevel(schema, state.selectedOrbital);
7173
- if (!orbData || orbData.traits.length <= 1) return null;
7174
- return /* @__PURE__ */ jsx(
7175
- HStack,
7176
- {
7177
- gap: "xs",
7178
- align: "center",
7179
- className: "absolute top-2 right-2 z-10 bg-surface/80 backdrop-blur rounded-md px-1.5 py-1",
7180
- children: orbData.traits.map((t) => /* @__PURE__ */ jsx(
7181
- Box,
7182
- {
7183
- as: "button",
7184
- className: `px-2.5 py-1 rounded-md text-xs font-medium transition-all cursor-pointer border-none ${t.name === state.selectedTrait ? "bg-primary text-primary-foreground" : "bg-transparent text-muted-foreground hover:text-foreground hover:bg-surface"}`,
7185
- onClick: () => handleTraitSwitch(t.name),
7186
- children: t.name
7187
- },
7188
- t.name
7189
- ))
7190
- }
7191
- );
7192
- })(),
7193
- state.level !== "application" && /* @__PURE__ */ jsx(
7194
- Typography,
7195
- {
7196
- variant: "small",
7197
- color: "muted",
7198
- className: "absolute bottom-2 right-2 z-10 bg-surface/60 backdrop-blur rounded px-2 py-1",
7199
- children: "Press Esc to zoom out"
7200
- }
7201
- ),
7202
- /* @__PURE__ */ jsxs(
7203
- "svg",
7204
- {
7205
- viewBox: `0 0 ${VIEWBOX_W} ${VIEWBOX_H2}`,
7206
- xmlns: "http://www.w3.org/2000/svg",
7207
- className: "w-full h-full",
7208
- role: "img",
7209
- "aria-label": `${schema.name} orbital visualization - ${state.level} level`,
7210
- children: [
7211
- /* @__PURE__ */ jsx("g", { ref: sceneRef, style: transitionStyle, children: sceneContent }),
7212
- /* @__PURE__ */ jsx(AvlLegend, { level: state.level, color })
7213
- ]
7214
- }
7215
- )
7216
- ]
7217
- }
7218
- );
7219
- };
7220
- AvlCosmicZoom.displayName = "AvlCosmicZoom";
7163
+ AvlClickTarget.displayName = "AvlClickTarget";
7221
7164
 
7222
- export { AVL_FIELD_TYPE_SHAPES, AVL_OPERATOR_COLORS, AvlApplication, AvlApplicationScene, AvlBehaviorGlyph, AvlBinding, AvlBindingRef, AvlClickTarget, AvlClosedCircuit, AvlCosmicZoom, AvlEffect, AvlEmitListen, AvlEntity, AvlEvent, AvlExprTree, AvlField, AvlFieldType, AvlGuard, AvlLiteral, AvlOperator, AvlOrbital, AvlOrbitalScene, AvlOrbitalUnit, AvlPage, AvlPersistence, AvlSExpr, AvlSlotMap, AvlState, AvlStateMachine, AvlSwimLane, AvlTrait, AvlTraitScene, AvlTransition, AvlTransitionLane, AvlTransitionScene, CONNECTION_COLORS, DOMAIN_COLORS, EFFECT_CATEGORY_COLORS, EFFECT_TYPE_TO_CATEGORY, STATE_COLORS, arcPath, curveControlPoint, getStateRole, gridPositions, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, radialPositions, ringPositions };
7165
+ export { AVL_FIELD_TYPE_SHAPES, AVL_OPERATOR_COLORS, AvlApplication, AvlBackwardEdge, AvlBehaviorGlyph, AvlBinding, AvlBindingEdge, AvlBindingRef, AvlClickTarget, AvlClosedCircuit, AvlCosmicZoom, AvlEffect, AvlEmitListen, AvlEntity, AvlEvent, AvlEventWireEdge, AvlExprTree, AvlField, AvlFieldType, AvlGuard, AvlLiteral, AvlOperator, AvlOrbital, AvlOrbitalNode, AvlOrbitalUnit, AvlPage, AvlPageEdge, AvlPersistence, AvlSExpr, AvlSlotMap, AvlState, AvlStateMachine, AvlSwimLane, AvlTrait, AvlTraitScene, AvlTransition, AvlTransitionEdge, AvlTransitionLane, AvlTransitionScene, BehaviorView, CONNECTION_COLORS, DOMAIN_COLORS, DetailView, EFFECT_CATEGORY_COLORS, EFFECT_TYPE_TO_CATEGORY, FlowCanvas, MiniStateMachine, ModuleCard, STATE_COLORS, SystemNode, ZOOM_BAND_THRESHOLDS, ZoomBandContext, ZoomBreadcrumb, ZoomLegend, arcPath, computeTraitLayout, computeZoomBand, curveControlPoint, edgePath, getStateRole, gridPositions, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, radialPositions, ringPositions, schemaToFlowGraph, useZoomBand, zoomProgress };