@almadar/ui 4.54.5 → 4.54.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/avl/index.js CHANGED
@@ -50994,6 +50994,22 @@ function zoomReducer(state, action) {
50994
50994
  selectedTransition: action.transitionIndex
50995
50995
  };
50996
50996
  }
50997
+ case "JUMP_TO_TRAIT_CIRCUIT": {
50998
+ if (state.level !== "application" || state.animating) return state;
50999
+ return {
51000
+ ...state,
51001
+ level: "trait",
51002
+ selectedOrbital: action.orbital,
51003
+ selectedTrait: null,
51004
+ selectedTransition: null,
51005
+ animating: false,
51006
+ animationDirection: "in",
51007
+ animationTarget: null
51008
+ };
51009
+ }
51010
+ case "SELECT_TRAIT": {
51011
+ return { ...state, selectedTrait: action.trait };
51012
+ }
50997
51013
  case "ZOOM_OUT": {
50998
51014
  if (state.level === "application" || state.animating) return state;
50999
51015
  return {
@@ -51026,7 +51042,8 @@ function zoomReducer(state, action) {
51026
51042
  if (state.level === "trait") {
51027
51043
  return {
51028
51044
  ...state,
51029
- level: "orbital",
51045
+ level: "application",
51046
+ selectedOrbital: null,
51030
51047
  selectedTrait: null,
51031
51048
  animating: false,
51032
51049
  animationTarget: null
@@ -57418,8 +57435,8 @@ function isBackwardTransition(from, to, states) {
57418
57435
  if (fromIdx === -1 || toIdx === -1) return false;
57419
57436
  return toIdx < fromIdx;
57420
57437
  }
57421
- function findCrossLinks(orbitals) {
57422
- const links = [];
57438
+ function extractTraitWires(orbitals, scope) {
57439
+ const wires = [];
57423
57440
  const emitters = [];
57424
57441
  const listeners6 = [];
57425
57442
  for (const orb of orbitals) {
@@ -57435,11 +57452,14 @@ function findCrossLinks(orbitals) {
57435
57452
  const seen = /* @__PURE__ */ new Set();
57436
57453
  for (const em of emitters) {
57437
57454
  for (const li of listeners6) {
57438
- if (em.event !== li.event || em.orbital === li.orbital) continue;
57439
- const key = `${em.orbital}\u241F${li.orbital}\u241F${em.event}`;
57455
+ if (em.event !== li.event) continue;
57456
+ if (scope === "cross-orbital" && em.orbital === li.orbital) continue;
57457
+ if (scope === "intra-orbital" && em.orbital !== li.orbital) continue;
57458
+ if (scope === "intra-orbital" && em.trait === li.trait) continue;
57459
+ const key = scope === "cross-orbital" ? `${em.orbital}\u241F${li.orbital}\u241F${em.event}` : `${em.orbital}\u241F${em.trait}\u241F${li.trait}\u241F${em.event}`;
57440
57460
  if (seen.has(key)) continue;
57441
57461
  seen.add(key);
57442
- links.push({
57462
+ wires.push({
57443
57463
  emitterOrbital: em.orbital,
57444
57464
  listenerOrbital: li.orbital,
57445
57465
  event: em.event,
@@ -57448,7 +57468,10 @@ function findCrossLinks(orbitals) {
57448
57468
  });
57449
57469
  }
57450
57470
  }
57451
- return links;
57471
+ return wires;
57472
+ }
57473
+ function findCrossLinks(orbitals) {
57474
+ return extractTraitWires(orbitals, "cross-orbital");
57452
57475
  }
57453
57476
  function schemaToOverviewGraph(schema, mockData, behaviorMeta, layoutHint, orbitalStatus) {
57454
57477
  const orbitals = getOrbitals(schema);
@@ -57748,6 +57771,66 @@ function orbitalAliasToExpandedGraph(schema, orbitalName, alias, mockData) {
57748
57771
  mockData
57749
57772
  );
57750
57773
  }
57774
+ var TRAIT_CARD_SPACING_X = 480;
57775
+ var TRAIT_CARD_SPACING_Y = 380;
57776
+ function orbitalToTraitGraph(schema, orbitalName, _mockData) {
57777
+ const orbital = getOrbitals(schema).find((o) => o.name === orbitalName);
57778
+ if (!orbital) return { nodes: [], edges: [] };
57779
+ const traits2 = getTraits2(orbital);
57780
+ const nodes = [];
57781
+ const count = traits2.length;
57782
+ const cols = Math.max(1, Math.ceil(Math.sqrt(count)));
57783
+ for (let i = 0; i < traits2.length; i++) {
57784
+ const trait = traits2[i];
57785
+ const sm = getStateMachine2(trait);
57786
+ const transitions = (sm?.transitions ?? []).map((t) => ({
57787
+ event: t.event,
57788
+ fromState: Array.isArray(t.from) ? t.from.join("|") : t.from,
57789
+ toState: t.to
57790
+ }));
57791
+ const emits = getEmits2(trait);
57792
+ const listens = getListens2(trait);
57793
+ const linkedEntity = trait.linkedEntity ?? "";
57794
+ const row = Math.floor(i / cols);
57795
+ const col = i % cols;
57796
+ nodes.push({
57797
+ id: `trait-${orbitalName}-${trait.name}`,
57798
+ type: "traitCard",
57799
+ position: {
57800
+ x: col * TRAIT_CARD_SPACING_X,
57801
+ y: row * TRAIT_CARD_SPACING_Y
57802
+ },
57803
+ data: {
57804
+ kind: "trait-card",
57805
+ orbitalName,
57806
+ traitName: trait.name,
57807
+ linkedEntity,
57808
+ transitions,
57809
+ emits,
57810
+ listens,
57811
+ // Required fields on PreviewNodeData — keep empty for trait cards.
57812
+ patterns: [],
57813
+ eventSources: []
57814
+ }
57815
+ });
57816
+ }
57817
+ const wires = extractTraitWires([orbital], "intra-orbital");
57818
+ const edges = wires.map((w) => ({
57819
+ id: `wire-${orbitalName}-${w.emitterTrait}-${w.listenerTrait}-${w.event}`,
57820
+ source: `trait-${orbitalName}-${w.emitterTrait}`,
57821
+ target: `trait-${orbitalName}-${w.listenerTrait}`,
57822
+ sourceHandle: `emit-${w.event}`,
57823
+ targetHandle: `listen-${w.event}`,
57824
+ type: "eventFlow",
57825
+ data: {
57826
+ event: w.event,
57827
+ isCrossOrbital: false,
57828
+ fromTrait: w.emitterTrait,
57829
+ toTrait: w.listenerTrait
57830
+ }
57831
+ }));
57832
+ return { nodes, edges };
57833
+ }
57751
57834
 
57752
57835
  // components/molecules/avl/OrbPreviewNode.tsx
57753
57836
  init_Box();
@@ -61786,11 +61869,104 @@ function TokenRow({ group, tokenKey, value, isColor, onPropChange }) {
61786
61869
  // components/organisms/avl/FlowCanvas.tsx
61787
61870
  init_Box();
61788
61871
  init_Typography();
61872
+
61873
+ // components/molecules/avl/TraitCardNode.tsx
61874
+ init_Box();
61875
+ init_Stack();
61876
+ init_Typography();
61877
+ init_Button();
61878
+ init_Badge();
61879
+ var TraitCardSelectionContext = createContext({
61880
+ selectTransition: () => {
61881
+ }
61882
+ });
61883
+ var CARD_WIDTH = 360;
61884
+ var CARD_MIN_HEIGHT = 200;
61885
+ var TraitCardNodeInner = (props) => {
61886
+ const data = props.data;
61887
+ const { selectTransition } = useContext(TraitCardSelectionContext);
61888
+ const orbitalName = data.orbitalName;
61889
+ const traitName = data.traitName ?? "";
61890
+ const linkedEntity = data.linkedEntity ?? "";
61891
+ const transitions = data.transitions ?? [];
61892
+ const emits = data.emits ?? [];
61893
+ const listens = data.listens ?? [];
61894
+ return /* @__PURE__ */ jsxs(
61895
+ Box,
61896
+ {
61897
+ className: "bg-card border-2 border-border rounded-lg shadow-md p-4",
61898
+ style: { width: CARD_WIDTH, minHeight: CARD_MIN_HEIGHT, position: "relative" },
61899
+ children: [
61900
+ listens.map((event, i) => /* @__PURE__ */ jsx(
61901
+ Handle,
61902
+ {
61903
+ type: "target",
61904
+ position: Position.Left,
61905
+ id: `listen-${event}`,
61906
+ style: { top: `${(i + 1) / (listens.length + 1) * 100}%` },
61907
+ "aria-label": `listens for ${event}`
61908
+ },
61909
+ `listen-${event}`
61910
+ )),
61911
+ emits.map((event, i) => /* @__PURE__ */ jsx(
61912
+ Handle,
61913
+ {
61914
+ type: "source",
61915
+ position: Position.Right,
61916
+ id: `emit-${event}`,
61917
+ style: { top: `${(i + 1) / (emits.length + 1) * 100}%` },
61918
+ "aria-label": `emits ${event}`
61919
+ },
61920
+ `emit-${event}`
61921
+ )),
61922
+ /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
61923
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", justify: "between", align: "center", children: [
61924
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", weight: "semibold", children: traitName }),
61925
+ linkedEntity ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: linkedEntity }) : null
61926
+ ] }),
61927
+ /* @__PURE__ */ jsx(VStack, { gap: "xs", children: transitions.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "No transitions" }) : transitions.map((t, idx) => /* @__PURE__ */ jsxs(
61928
+ Button,
61929
+ {
61930
+ variant: "ghost",
61931
+ size: "sm",
61932
+ onClick: (e) => {
61933
+ e.stopPropagation();
61934
+ selectTransition({
61935
+ orbitalName,
61936
+ traitName,
61937
+ transitionEvent: t.event,
61938
+ fromState: t.fromState,
61939
+ toState: t.toState,
61940
+ index: idx
61941
+ });
61942
+ },
61943
+ children: [
61944
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "semibold", children: t.event }),
61945
+ /* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", children: [
61946
+ " \xB7 ",
61947
+ t.fromState,
61948
+ " \u2192 ",
61949
+ t.toState
61950
+ ] })
61951
+ ]
61952
+ },
61953
+ `${t.event}-${t.fromState}-${t.toState}-${idx}`
61954
+ )) })
61955
+ ] })
61956
+ ]
61957
+ }
61958
+ );
61959
+ };
61960
+ var TraitCardNode = React96__default.memo(TraitCardNodeInner);
61961
+ TraitCardNode.displayName = "TraitCardNode";
61962
+
61963
+ // components/organisms/avl/FlowCanvas.tsx
61789
61964
  init_useEventBus();
61790
61965
  var flowCanvasLog = createLogger("almadar:ui:flow-canvas");
61791
61966
  var NODE_TYPES = {
61792
61967
  preview: OrbPreviewNode,
61793
- behaviorCompose: BehaviorComposeNode
61968
+ behaviorCompose: BehaviorComposeNode,
61969
+ traitCard: TraitCardNode
61794
61970
  };
61795
61971
  flowCanvasLog.debug("node-type-registry", () => ({
61796
61972
  registered: Object.keys(NODE_TYPES),
@@ -61831,7 +62007,8 @@ function FlowCanvasInner({
61831
62007
  }) {
61832
62008
  const NODE_TYPES2 = useMemo(() => ({
61833
62009
  preview: OrbPreviewNode,
61834
- behaviorCompose: BehaviorComposeNode
62010
+ behaviorCompose: BehaviorComposeNode,
62011
+ traitCard: TraitCardNode
61835
62012
  }), []);
61836
62013
  const EDGE_TYPES_LOCAL = useMemo(() => ({
61837
62014
  eventFlow: EventFlowEdge
@@ -61879,17 +62056,19 @@ function FlowCanvasInner({
61879
62056
  }
61880
62057
  }), [selectedPattern]);
61881
62058
  const [atBehaviorLevel, setAtBehaviorLevel] = useState(composeLevel === "behavior");
61882
- const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges } = useMemo(() => {
62059
+ const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges, traitExpandedNodes, traitExpandedEdges } = useMemo(() => {
61883
62060
  const t = perfStart("compose-graph");
61884
62061
  const compose = composeLevel === "behavior" && behaviorEntries?.length ? behaviorsToComposeGraph(behaviorEntries, behaviorWires ?? [], layoutHint) : { nodes: [], edges: [] };
61885
62062
  const overview = schemaToOverviewGraph(parsedSchema, mockData, behaviorMeta, layoutHint, orbitalStatus);
61886
62063
  const expanded = expandedOrbital ? orbitalToExpandedGraph(parsedSchema, expandedOrbital, mockData) : { nodes: [], edges: [] };
61887
62064
  const behaviorExpanded = expandedOrbital && expandedBehaviorAlias ? orbitalAliasToExpandedGraph(parsedSchema, expandedOrbital, expandedBehaviorAlias, mockData) : { nodes: [], edges: [] };
62065
+ const traitExpanded = expandedOrbital ? orbitalToTraitGraph(parsedSchema, expandedOrbital) : { nodes: [], edges: [] };
61888
62066
  perfEnd("compose-graph", t, {
61889
62067
  composeNodes: compose.nodes.length,
61890
62068
  overviewNodes: overview.nodes.length,
61891
62069
  expandedNodes: expanded.nodes.length,
61892
62070
  behaviorExpandedNodes: behaviorExpanded.nodes.length,
62071
+ traitExpandedNodes: traitExpanded.nodes.length,
61893
62072
  orbitalCount: parsedSchema.orbitals?.length ?? 0
61894
62073
  });
61895
62074
  return {
@@ -61900,11 +62079,13 @@ function FlowCanvasInner({
61900
62079
  expandedNodes: expanded.nodes,
61901
62080
  expandedEdges: expanded.edges,
61902
62081
  behaviorExpandedNodes: behaviorExpanded.nodes,
61903
- behaviorExpandedEdges: behaviorExpanded.edges
62082
+ behaviorExpandedEdges: behaviorExpanded.edges,
62083
+ traitExpandedNodes: traitExpanded.nodes,
62084
+ traitExpandedEdges: traitExpanded.edges
61904
62085
  };
61905
62086
  }, [parsedSchema, expandedOrbital, expandedBehaviorAlias, behaviorMeta, layoutHint, composeLevel, behaviorEntries, behaviorWires, mockData, orbitalStatus]);
61906
- const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : expandedNodes;
61907
- const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : level === "behavior-expanded" ? behaviorExpandedEdges : expandedEdges;
62087
+ const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : level === "trait-expanded" ? traitExpandedNodes : expandedNodes;
62088
+ const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : level === "behavior-expanded" ? behaviorExpandedEdges : level === "trait-expanded" ? traitExpandedEdges : expandedEdges;
61908
62089
  const [nodes, setNodes, onNodesChange] = useNodesState(activeNodes);
61909
62090
  const [edges, setEdges, onEdgesChange] = useEdgesState(activeEdges);
61910
62091
  const reactFlow = useReactFlow();
@@ -62061,7 +62242,17 @@ function FlowCanvasInner({
62061
62242
  });
62062
62243
  }, [nodes, onEventWire, eventBus]);
62063
62244
  const screenSizeKeys = ["mobile", "tablet", "laptop", "wide"];
62064
- return /* @__PURE__ */ jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsxs(
62245
+ const traitCardSelectionValue = useMemo(() => ({
62246
+ selectTransition: (sel) => {
62247
+ onNodeClick?.({
62248
+ level: "transition",
62249
+ orbital: sel.orbitalName,
62250
+ trait: sel.traitName,
62251
+ transition: sel.transitionEvent
62252
+ });
62253
+ }
62254
+ }), [onNodeClick]);
62255
+ return /* @__PURE__ */ jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsx(TraitCardSelectionContext.Provider, { value: traitCardSelectionValue, children: /* @__PURE__ */ jsxs(
62065
62256
  Box,
62066
62257
  {
62067
62258
  className: `flex h-full ${className ?? ""}`,
@@ -62179,7 +62370,7 @@ function FlowCanvasInner({
62179
62370
  ] })
62180
62371
  ]
62181
62372
  }
62182
- ) }) });
62373
+ ) }) }) });
62183
62374
  }
62184
62375
  var FlowCanvas = (props) => {
62185
62376
  return /* @__PURE__ */ jsx(Profiler, { id: "flow-canvas", onRender: profilerOnRender, children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(FlowCanvasInner, { ...props }) }) });
@@ -62303,122 +62494,6 @@ AvlCosmicZoom.displayName = "AvlCosmicZoom";
62303
62494
  init_avl_schema_parser();
62304
62495
  init_avl_zoom_state();
62305
62496
 
62306
- // components/organisms/avl/AvlTraitScene.tsx
62307
- init_AvlState();
62308
- init_AvlTransitionLane();
62309
- init_AvlSwimLane();
62310
- init_types();
62311
- init_avl_elk_layout();
62312
- var log19 = createLogger("almadar:ui:avl:trait-scene");
62313
- var SWIM_GUTTER2 = 120;
62314
- var CENTER_W2 = 360;
62315
- var AvlTraitScene = ({
62316
- data,
62317
- color = "var(--color-primary)",
62318
- onTransitionClick
62319
- }) => {
62320
- const [layout, setLayout] = useState(null);
62321
- const dataKey = useMemo(() => JSON.stringify(data), [data]);
62322
- useEffect(() => {
62323
- computeTraitLayout(data).then(setLayout).catch((error) => {
62324
- log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
62325
- });
62326
- }, [dataKey]);
62327
- if (!layout) {
62328
- return /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("text", { x: 300, y: 200, textAnchor: "middle", fill: color, fontSize: 12, opacity: 0.5, children: "Computing layout..." }) });
62329
- }
62330
- const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
62331
- const machineOffsetX = hasExternal ? 0 : 30;
62332
- const padding = 20;
62333
- const availW = CENTER_W2 - padding * 2;
62334
- const availH = 300;
62335
- const scale = Math.min(1, availW / layout.width, availH / layout.height);
62336
- const scaledW = layout.width * scale;
62337
- const scaledH = layout.height * scale;
62338
- const offsetX = padding + (availW - scaledW) / 2;
62339
- const offsetY = 50 + (availH - scaledH) / 2;
62340
- const machineHeight = scaledH + 100;
62341
- const renderMachine = /* @__PURE__ */ jsxs("g", { children: [
62342
- /* @__PURE__ */ jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
62343
- /* @__PURE__ */ jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
62344
- "linked to ",
62345
- data.linkedEntity
62346
- ] }),
62347
- /* @__PURE__ */ jsxs("defs", { children: [
62348
- /* @__PURE__ */ jsx("marker", { id: "traitArrowV2", 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 }) }),
62349
- /* @__PURE__ */ jsx("marker", { id: "traitArrowBack", 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 }) })
62350
- ] }),
62351
- /* @__PURE__ */ jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
62352
- layout.edges.map((edge) => {
62353
- const conn = edge.isSelf ? CONNECTION_COLORS.selfLoop : edge.isBackward ? CONNECTION_COLORS.backward : CONNECTION_COLORS.forward;
62354
- const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
62355
- return /* @__PURE__ */ jsxs("g", { children: [
62356
- /* @__PURE__ */ jsx(
62357
- "path",
62358
- {
62359
- d: edgePath(edge.points),
62360
- fill: "none",
62361
- stroke: conn.color,
62362
- strokeWidth: conn.width,
62363
- strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
62364
- opacity: 0.5,
62365
- markerEnd: marker
62366
- }
62367
- ),
62368
- /* @__PURE__ */ jsx(
62369
- AvlTransitionLane,
62370
- {
62371
- x: edge.labelX,
62372
- y: edge.labelY,
62373
- event: edge.event,
62374
- guard: edge.guardExpr,
62375
- effects: edge.effects.map((e) => ({ type: e.type })),
62376
- width: edge.labelW,
62377
- isBackward: edge.isBackward,
62378
- isSelfLoop: edge.isSelf,
62379
- color,
62380
- onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
62381
- x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
62382
- y: edge.labelY + offsetY
62383
- }) : void 0
62384
- }
62385
- )
62386
- ] }, edge.id);
62387
- }),
62388
- layout.nodes.map((node) => /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx(
62389
- AvlState,
62390
- {
62391
- x: node.x,
62392
- y: node.y,
62393
- width: node.width,
62394
- height: node.height,
62395
- name: node.id,
62396
- isInitial: node.isInitial,
62397
- isTerminal: node.isTerminal,
62398
- role: node.role,
62399
- transitionCount: node.transitionCount,
62400
- color
62401
- }
62402
- ) }, node.id))
62403
- ] })
62404
- ] });
62405
- if (!hasExternal) {
62406
- return /* @__PURE__ */ jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
62407
- }
62408
- return /* @__PURE__ */ jsx(
62409
- AvlSwimLane,
62410
- {
62411
- listenedEvents: data.listenedEvents,
62412
- emittedEvents: data.emittedEvents,
62413
- centerWidth: CENTER_W2,
62414
- height: machineHeight,
62415
- color,
62416
- children: renderMachine
62417
- }
62418
- );
62419
- };
62420
- AvlTraitScene.displayName = "AvlTraitScene";
62421
-
62422
62497
  // components/organisms/avl/AvlTransitionScene.tsx
62423
62498
  init_AvlEffect();
62424
62499
  init_types();
@@ -62905,26 +62980,34 @@ var AvlOrbitalsCosmicZoom = ({
62905
62980
  if (!highlightedOrbital) return;
62906
62981
  if (drilledForHighlightRef.current) return;
62907
62982
  drilledForHighlightRef.current = true;
62908
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: highlightedOrbital, targetPosition: { x: 0, y: 0 } });
62909
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62983
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: highlightedOrbital });
62910
62984
  }, [highlightedOrbital]);
62911
62985
  const breadcrumbs = useMemo(() => getBreadcrumbs(state), [state]);
62912
62986
  const handleSelect = useCallback(
62913
62987
  (name) => {
62914
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
62915
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62988
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: name });
62916
62989
  onOrbitalSelect?.(name);
62917
62990
  },
62918
62991
  [onOrbitalSelect]
62919
62992
  );
62920
- const handleTraitSelect = useCallback((traitName) => {
62921
- dispatch({ type: "ZOOM_INTO_TRAIT", trait: traitName, targetPosition: { x: 0, y: 0 } });
62922
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62923
- }, []);
62924
- const handleTransitionSelect = useCallback((transitionIndex) => {
62993
+ useCallback((transitionIndex) => {
62925
62994
  dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex, targetPosition: { x: 0, y: 0 } });
62926
62995
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62927
62996
  }, []);
62997
+ const handleCanvasNodeClick = useCallback(
62998
+ (ctx) => {
62999
+ if (ctx.level !== "transition" || !ctx.trait || !ctx.transition) return;
63000
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === ctx.orbital);
63001
+ const traitRef = orbital?.traits?.find((t) => isInlineTrait(t) && t.name === ctx.trait);
63002
+ if (!traitRef || !isInlineTrait(traitRef)) return;
63003
+ const idx = traitRef.stateMachine?.transitions?.findIndex((t) => t.event === ctx.transition) ?? -1;
63004
+ if (idx < 0) return;
63005
+ dispatch({ type: "SELECT_TRAIT", trait: ctx.trait });
63006
+ dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: idx, targetPosition: { x: 0, y: 0 } });
63007
+ Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63008
+ },
63009
+ [parsedSchema]
63010
+ );
62928
63011
  const handleZoomOut = useCallback(() => {
62929
63012
  dispatch({ type: "ZOOM_OUT" });
62930
63013
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
@@ -62947,14 +63030,6 @@ var AvlOrbitalsCosmicZoom = ({
62947
63030
  window.addEventListener("keydown", onKey);
62948
63031
  return () => window.removeEventListener("keydown", onKey);
62949
63032
  }, [handleZoomOut, state.level]);
62950
- const orbitalLevelData = useMemo(() => {
62951
- if (!state.selectedOrbital) return null;
62952
- return parseOrbitalLevel(parsedSchema, state.selectedOrbital);
62953
- }, [parsedSchema, state.selectedOrbital]);
62954
- const traitLevelData = useMemo(() => {
62955
- if (!state.selectedOrbital || !state.selectedTrait) return null;
62956
- return parseTraitLevel(parsedSchema, state.selectedOrbital, state.selectedTrait);
62957
- }, [parsedSchema, state.selectedOrbital, state.selectedTrait]);
62958
63033
  const transitionLevelData = useMemo(() => {
62959
63034
  if (!state.selectedOrbital || !state.selectedTrait || state.selectedTransition === null) return null;
62960
63035
  return parseTransitionLevel(
@@ -62964,6 +63039,12 @@ var AvlOrbitalsCosmicZoom = ({
62964
63039
  state.selectedTransition
62965
63040
  );
62966
63041
  }, [parsedSchema, state.selectedOrbital, state.selectedTrait, state.selectedTransition]);
63042
+ const scopedSchema = useMemo(() => {
63043
+ if (!state.selectedOrbital) return null;
63044
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === state.selectedOrbital);
63045
+ if (!orbital) return null;
63046
+ return { ...parsedSchema, orbitals: [orbital] };
63047
+ }, [parsedSchema, state.selectedOrbital]);
62967
63048
  const [zoom, setZoom] = useState(1);
62968
63049
  const [pan, setPan] = useState({ x: 0, y: 0 });
62969
63050
  const dragStateRef = useRef(null);
@@ -63011,6 +63092,7 @@ var AvlOrbitalsCosmicZoom = ({
63011
63092
  zoomRef.current = zoom;
63012
63093
  }, [zoom]);
63013
63094
  useEffect(() => {
63095
+ if (state.level !== "application") return;
63014
63096
  const wrapper = transformWrapperRef.current;
63015
63097
  if (!wrapper) return;
63016
63098
  const wheelListener = (e) => {
@@ -63201,81 +63283,7 @@ var AvlOrbitalsCosmicZoom = ({
63201
63283
  }
63202
63284
  )
63203
63285
  ] }),
63204
- state.level === "orbital" && orbitalLevelData && /* @__PURE__ */ jsxs(
63205
- Box,
63206
- {
63207
- position: "absolute",
63208
- style: {
63209
- inset: 0,
63210
- paddingTop: 56,
63211
- paddingBottom: 24,
63212
- paddingLeft: 24,
63213
- paddingRight: 24,
63214
- display: "flex",
63215
- alignItems: "stretch",
63216
- justifyContent: "center",
63217
- gap: 24
63218
- },
63219
- children: [
63220
- /* @__PURE__ */ jsx(Box, { style: { flex: 1, maxWidth: 720, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(
63221
- AvlOrbitalUnit,
63222
- {
63223
- entityName: orbitalLevelData.entity.name,
63224
- fields: orbitalLevelData.entity.fields.length,
63225
- persistence: orbitalLevelData.entity.persistence || "persistent",
63226
- traits: orbitalLevelData.traits.map((t) => ({ name: t.name })),
63227
- pages: orbitalLevelData.pages.map((p2) => ({ name: p2.name })),
63228
- color,
63229
- animated
63230
- }
63231
- ) }),
63232
- /* @__PURE__ */ jsxs(
63233
- Box,
63234
- {
63235
- style: {
63236
- width: 220,
63237
- padding: 12,
63238
- display: "flex",
63239
- flexDirection: "column",
63240
- gap: 8,
63241
- borderLeft: `1px solid ${color}`,
63242
- opacity: 0.95,
63243
- overflowY: "auto",
63244
- minHeight: 0
63245
- },
63246
- children: [
63247
- /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginBottom: 4 }, children: [
63248
- "Traits (",
63249
- orbitalLevelData.traits.length,
63250
- ")"
63251
- ] }),
63252
- orbitalLevelData.traits.length === 0 && /* @__PURE__ */ jsx(Text, { variant: "small", style: { opacity: 0.6, color }, children: "No traits" }),
63253
- orbitalLevelData.traits.map((trait) => /* @__PURE__ */ jsx(
63254
- Button,
63255
- {
63256
- variant: "ghost",
63257
- size: "sm",
63258
- onClick: () => handleTraitSelect(trait.name),
63259
- action: "COSMIC_DRILL_TRAIT",
63260
- children: trait.name
63261
- },
63262
- trait.name
63263
- )),
63264
- orbitalLevelData.pages.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
63265
- /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginTop: 12 }, children: [
63266
- "Pages (",
63267
- orbitalLevelData.pages.length,
63268
- ")"
63269
- ] }),
63270
- orbitalLevelData.pages.map((page) => /* @__PURE__ */ jsx(Text, { variant: "small", style: { opacity: 0.7, color }, children: page.name }, page.name))
63271
- ] })
63272
- ]
63273
- }
63274
- )
63275
- ]
63276
- }
63277
- ),
63278
- state.level === "trait" && traitLevelData && /* @__PURE__ */ jsx(
63286
+ state.level === "trait" && scopedSchema && state.selectedOrbital && /* @__PURE__ */ jsx(
63279
63287
  Box,
63280
63288
  {
63281
63289
  position: "absolute",
@@ -63287,39 +63295,14 @@ var AvlOrbitalsCosmicZoom = ({
63287
63295
  paddingRight: 24
63288
63296
  },
63289
63297
  children: /* @__PURE__ */ jsx(
63290
- Box,
63298
+ FlowCanvas,
63291
63299
  {
63292
- ref: transformWrapperRef,
63293
- position: "relative",
63294
- onPointerDown: handlePointerDown,
63295
- onPointerMove: handlePointerMove,
63296
- onPointerUp: handlePointerUp,
63297
- onPointerCancel: handlePointerUp,
63298
- style: {
63299
- width: "100%",
63300
- height: "100%",
63301
- cursor: dragStateRef.current ? "grabbing" : "grab",
63302
- overflow: "hidden"
63303
- },
63304
- children: /* @__PURE__ */ jsx(
63305
- Box,
63306
- {
63307
- position: "absolute",
63308
- style: {
63309
- inset: 0,
63310
- transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
63311
- transformOrigin: "0 0"
63312
- },
63313
- children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 600 400", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
63314
- AvlTraitScene,
63315
- {
63316
- data: traitLevelData,
63317
- color,
63318
- onTransitionClick: (idx) => handleTransitionSelect(idx)
63319
- }
63320
- ) })
63321
- }
63322
- )
63300
+ schema: scopedSchema,
63301
+ initialLevel: "trait-expanded",
63302
+ initialOrbital: state.selectedOrbital,
63303
+ onNodeClick: handleCanvasNodeClick,
63304
+ width: "100%",
63305
+ height: "100%"
63323
63306
  }
63324
63307
  )
63325
63308
  }
@@ -63372,7 +63355,7 @@ var AvlOrbitalsCosmicZoom = ({
63372
63355
  )
63373
63356
  }
63374
63357
  ),
63375
- (state.level === "trait" || state.level === "transition") && /* @__PURE__ */ jsxs(
63358
+ state.level === "transition" && /* @__PURE__ */ jsxs(
63376
63359
  Box,
63377
63360
  {
63378
63361
  position: "absolute",
@@ -63396,6 +63379,122 @@ var AvlOrbitalsCosmicZoom = ({
63396
63379
  );
63397
63380
  };
63398
63381
  AvlOrbitalsCosmicZoom.displayName = "AvlOrbitalsCosmicZoom";
63382
+
63383
+ // components/organisms/avl/AvlTraitScene.tsx
63384
+ init_AvlState();
63385
+ init_AvlTransitionLane();
63386
+ init_AvlSwimLane();
63387
+ init_types();
63388
+ init_avl_elk_layout();
63389
+ var log19 = createLogger("almadar:ui:avl:trait-scene");
63390
+ var SWIM_GUTTER2 = 120;
63391
+ var CENTER_W2 = 360;
63392
+ var AvlTraitScene = ({
63393
+ data,
63394
+ color = "var(--color-primary)",
63395
+ onTransitionClick
63396
+ }) => {
63397
+ const [layout, setLayout] = useState(null);
63398
+ const dataKey = useMemo(() => JSON.stringify(data), [data]);
63399
+ useEffect(() => {
63400
+ computeTraitLayout(data).then(setLayout).catch((error) => {
63401
+ log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
63402
+ });
63403
+ }, [dataKey]);
63404
+ if (!layout) {
63405
+ return /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx("text", { x: 300, y: 200, textAnchor: "middle", fill: color, fontSize: 12, opacity: 0.5, children: "Computing layout..." }) });
63406
+ }
63407
+ const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
63408
+ const machineOffsetX = hasExternal ? 0 : 30;
63409
+ const padding = 20;
63410
+ const availW = CENTER_W2 - padding * 2;
63411
+ const availH = 300;
63412
+ const scale = Math.min(1, availW / layout.width, availH / layout.height);
63413
+ const scaledW = layout.width * scale;
63414
+ const scaledH = layout.height * scale;
63415
+ const offsetX = padding + (availW - scaledW) / 2;
63416
+ const offsetY = 50 + (availH - scaledH) / 2;
63417
+ const machineHeight = scaledH + 100;
63418
+ const renderMachine = /* @__PURE__ */ jsxs("g", { children: [
63419
+ /* @__PURE__ */ jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
63420
+ /* @__PURE__ */ jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
63421
+ "linked to ",
63422
+ data.linkedEntity
63423
+ ] }),
63424
+ /* @__PURE__ */ jsxs("defs", { children: [
63425
+ /* @__PURE__ */ jsx("marker", { id: "traitArrowV2", 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 }) }),
63426
+ /* @__PURE__ */ jsx("marker", { id: "traitArrowBack", 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 }) })
63427
+ ] }),
63428
+ /* @__PURE__ */ jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
63429
+ layout.edges.map((edge) => {
63430
+ const conn = edge.isSelf ? CONNECTION_COLORS.selfLoop : edge.isBackward ? CONNECTION_COLORS.backward : CONNECTION_COLORS.forward;
63431
+ const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
63432
+ return /* @__PURE__ */ jsxs("g", { children: [
63433
+ /* @__PURE__ */ jsx(
63434
+ "path",
63435
+ {
63436
+ d: edgePath(edge.points),
63437
+ fill: "none",
63438
+ stroke: conn.color,
63439
+ strokeWidth: conn.width,
63440
+ strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
63441
+ opacity: 0.5,
63442
+ markerEnd: marker
63443
+ }
63444
+ ),
63445
+ /* @__PURE__ */ jsx(
63446
+ AvlTransitionLane,
63447
+ {
63448
+ x: edge.labelX,
63449
+ y: edge.labelY,
63450
+ event: edge.event,
63451
+ guard: edge.guardExpr,
63452
+ effects: edge.effects.map((e) => ({ type: e.type })),
63453
+ width: edge.labelW,
63454
+ isBackward: edge.isBackward,
63455
+ isSelfLoop: edge.isSelf,
63456
+ color,
63457
+ onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
63458
+ x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
63459
+ y: edge.labelY + offsetY
63460
+ }) : void 0
63461
+ }
63462
+ )
63463
+ ] }, edge.id);
63464
+ }),
63465
+ layout.nodes.map((node) => /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx(
63466
+ AvlState,
63467
+ {
63468
+ x: node.x,
63469
+ y: node.y,
63470
+ width: node.width,
63471
+ height: node.height,
63472
+ name: node.id,
63473
+ isInitial: node.isInitial,
63474
+ isTerminal: node.isTerminal,
63475
+ role: node.role,
63476
+ transitionCount: node.transitionCount,
63477
+ color
63478
+ }
63479
+ ) }, node.id))
63480
+ ] })
63481
+ ] });
63482
+ if (!hasExternal) {
63483
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
63484
+ }
63485
+ return /* @__PURE__ */ jsx(
63486
+ AvlSwimLane,
63487
+ {
63488
+ listenedEvents: data.listenedEvents,
63489
+ emittedEvents: data.emittedEvents,
63490
+ centerWidth: CENTER_W2,
63491
+ height: machineHeight,
63492
+ color,
63493
+ children: renderMachine
63494
+ }
63495
+ );
63496
+ };
63497
+ AvlTraitScene.displayName = "AvlTraitScene";
63399
63498
  var AvlClickTarget = ({
63400
63499
  x,
63401
63500
  y,