@almadar/ui 4.54.5 → 4.54.7

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.
@@ -51040,6 +51040,22 @@ function zoomReducer(state, action) {
51040
51040
  selectedTransition: action.transitionIndex
51041
51041
  };
51042
51042
  }
51043
+ case "JUMP_TO_TRAIT_CIRCUIT": {
51044
+ if (state.level !== "application" || state.animating) return state;
51045
+ return {
51046
+ ...state,
51047
+ level: "trait",
51048
+ selectedOrbital: action.orbital,
51049
+ selectedTrait: null,
51050
+ selectedTransition: null,
51051
+ animating: false,
51052
+ animationDirection: "in",
51053
+ animationTarget: null
51054
+ };
51055
+ }
51056
+ case "SELECT_TRAIT": {
51057
+ return { ...state, selectedTrait: action.trait };
51058
+ }
51043
51059
  case "ZOOM_OUT": {
51044
51060
  if (state.level === "application" || state.animating) return state;
51045
51061
  return {
@@ -51072,7 +51088,8 @@ function zoomReducer(state, action) {
51072
51088
  if (state.level === "trait") {
51073
51089
  return {
51074
51090
  ...state,
51075
- level: "orbital",
51091
+ level: "application",
51092
+ selectedOrbital: null,
51076
51093
  selectedTrait: null,
51077
51094
  animating: false,
51078
51095
  animationTarget: null
@@ -57464,8 +57481,8 @@ function isBackwardTransition(from, to, states) {
57464
57481
  if (fromIdx === -1 || toIdx === -1) return false;
57465
57482
  return toIdx < fromIdx;
57466
57483
  }
57467
- function findCrossLinks(orbitals) {
57468
- const links = [];
57484
+ function extractTraitWires(orbitals, scope) {
57485
+ const wires = [];
57469
57486
  const emitters = [];
57470
57487
  const listeners6 = [];
57471
57488
  for (const orb of orbitals) {
@@ -57481,11 +57498,14 @@ function findCrossLinks(orbitals) {
57481
57498
  const seen = /* @__PURE__ */ new Set();
57482
57499
  for (const em of emitters) {
57483
57500
  for (const li of listeners6) {
57484
- if (em.event !== li.event || em.orbital === li.orbital) continue;
57485
- const key = `${em.orbital}\u241F${li.orbital}\u241F${em.event}`;
57501
+ if (em.event !== li.event) continue;
57502
+ if (scope === "cross-orbital" && em.orbital === li.orbital) continue;
57503
+ if (scope === "intra-orbital" && em.orbital !== li.orbital) continue;
57504
+ if (scope === "intra-orbital" && em.trait === li.trait) continue;
57505
+ const key = scope === "cross-orbital" ? `${em.orbital}\u241F${li.orbital}\u241F${em.event}` : `${em.orbital}\u241F${em.trait}\u241F${li.trait}\u241F${em.event}`;
57486
57506
  if (seen.has(key)) continue;
57487
57507
  seen.add(key);
57488
- links.push({
57508
+ wires.push({
57489
57509
  emitterOrbital: em.orbital,
57490
57510
  listenerOrbital: li.orbital,
57491
57511
  event: em.event,
@@ -57494,7 +57514,10 @@ function findCrossLinks(orbitals) {
57494
57514
  });
57495
57515
  }
57496
57516
  }
57497
- return links;
57517
+ return wires;
57518
+ }
57519
+ function findCrossLinks(orbitals) {
57520
+ return extractTraitWires(orbitals, "cross-orbital");
57498
57521
  }
57499
57522
  function schemaToOverviewGraph(schema, mockData, behaviorMeta, layoutHint, orbitalStatus) {
57500
57523
  const orbitals = getOrbitals(schema);
@@ -57794,6 +57817,71 @@ function orbitalAliasToExpandedGraph(schema, orbitalName, alias, mockData) {
57794
57817
  mockData
57795
57818
  );
57796
57819
  }
57820
+ var TRAIT_CARD_SPACING_X = 480;
57821
+ var TRAIT_CARD_SPACING_Y = 380;
57822
+ function orbitalToTraitGraph(schema, orbitalName, _mockData) {
57823
+ const orbital = getOrbitals(schema).find((o) => o.name === orbitalName);
57824
+ if (!orbital) return { nodes: [], edges: [] };
57825
+ const traits2 = getTraits2(orbital);
57826
+ const nodes = [];
57827
+ const count = traits2.length;
57828
+ const cols = Math.max(1, Math.ceil(Math.sqrt(count)));
57829
+ for (let i = 0; i < traits2.length; i++) {
57830
+ const trait = traits2[i];
57831
+ const sm = getStateMachine2(trait);
57832
+ const transitions = (sm?.transitions ?? []).map((t) => ({
57833
+ event: t.event,
57834
+ fromState: Array.isArray(t.from) ? t.from.join("|") : t.from,
57835
+ toState: t.to
57836
+ }));
57837
+ const emits = getEmits2(trait);
57838
+ const listens = getListens2(trait);
57839
+ const linkedEntity = trait.linkedEntity ?? "";
57840
+ const row = Math.floor(i / cols);
57841
+ const col = i % cols;
57842
+ nodes.push({
57843
+ id: `trait-${orbitalName}-${trait.name}`,
57844
+ type: "traitCard",
57845
+ position: {
57846
+ x: col * TRAIT_CARD_SPACING_X,
57847
+ y: row * TRAIT_CARD_SPACING_Y
57848
+ },
57849
+ data: {
57850
+ kind: "trait-card",
57851
+ orbitalName,
57852
+ traitName: trait.name,
57853
+ linkedEntity,
57854
+ transitions,
57855
+ emits,
57856
+ listens,
57857
+ // `_fullSchema` carries the parsed schema to `TraitCardNode` so it
57858
+ // can run `parseTraitLevel(...)` and render the ELK-laid-out
57859
+ // state-machine flow chart inside the card. Mirrors the same
57860
+ // convention `OrbPreviewNode` uses for its embedded UI preview.
57861
+ _fullSchema: schema,
57862
+ // Required fields on PreviewNodeData — keep empty for trait cards.
57863
+ patterns: [],
57864
+ eventSources: []
57865
+ }
57866
+ });
57867
+ }
57868
+ const wires = extractTraitWires([orbital], "intra-orbital");
57869
+ const edges = wires.map((w) => ({
57870
+ id: `wire-${orbitalName}-${w.emitterTrait}-${w.listenerTrait}-${w.event}`,
57871
+ source: `trait-${orbitalName}-${w.emitterTrait}`,
57872
+ target: `trait-${orbitalName}-${w.listenerTrait}`,
57873
+ sourceHandle: `emit-${w.event}`,
57874
+ targetHandle: `listen-${w.event}`,
57875
+ type: "eventFlow",
57876
+ data: {
57877
+ event: w.event,
57878
+ isCrossOrbital: false,
57879
+ fromTrait: w.emitterTrait,
57880
+ toTrait: w.listenerTrait
57881
+ }
57882
+ }));
57883
+ return { nodes, edges };
57884
+ }
57797
57885
 
57798
57886
  // components/molecules/avl/OrbPreviewNode.tsx
57799
57887
  init_Box();
@@ -61832,11 +61920,225 @@ function TokenRow({ group, tokenKey, value, isColor, onPropChange }) {
61832
61920
  // components/organisms/avl/FlowCanvas.tsx
61833
61921
  init_Box();
61834
61922
  init_Typography();
61923
+
61924
+ // components/molecules/avl/TraitCardNode.tsx
61925
+ init_Box();
61926
+ init_Stack();
61927
+ init_Typography();
61928
+ init_Badge();
61929
+
61930
+ // components/organisms/avl/AvlTraitScene.tsx
61931
+ init_AvlState();
61932
+ init_AvlTransitionLane();
61933
+ init_AvlSwimLane();
61934
+ init_types();
61935
+ init_avl_elk_layout();
61936
+ var log19 = logger.createLogger("almadar:ui:avl:trait-scene");
61937
+ var SWIM_GUTTER2 = 120;
61938
+ var CENTER_W2 = 360;
61939
+ var AvlTraitScene = ({
61940
+ data,
61941
+ color = "var(--color-primary)",
61942
+ onTransitionClick
61943
+ }) => {
61944
+ const [layout, setLayout] = React96.useState(null);
61945
+ const dataKey = React96.useMemo(() => JSON.stringify(data), [data]);
61946
+ React96.useEffect(() => {
61947
+ computeTraitLayout(data).then(setLayout).catch((error) => {
61948
+ log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61949
+ });
61950
+ }, [dataKey]);
61951
+ if (!layout) {
61952
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx("text", { x: 300, y: 200, textAnchor: "middle", fill: color, fontSize: 12, opacity: 0.5, children: "Computing layout..." }) });
61953
+ }
61954
+ const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
61955
+ const machineOffsetX = hasExternal ? 0 : 30;
61956
+ const padding = 20;
61957
+ const availW = CENTER_W2 - padding * 2;
61958
+ const availH = 300;
61959
+ const scale = Math.min(1, availW / layout.width, availH / layout.height);
61960
+ const scaledW = layout.width * scale;
61961
+ const scaledH = layout.height * scale;
61962
+ const offsetX = padding + (availW - scaledW) / 2;
61963
+ const offsetY = 50 + (availH - scaledH) / 2;
61964
+ const machineHeight = scaledH + 100;
61965
+ const renderMachine = /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
61966
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
61967
+ /* @__PURE__ */ jsxRuntime.jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
61968
+ "linked to ",
61969
+ data.linkedEntity
61970
+ ] }),
61971
+ /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
61972
+ /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "traitArrowV2", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: exports.CONNECTION_COLORS.forward.color, opacity: 0.7 }) }),
61973
+ /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "traitArrowBack", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: exports.CONNECTION_COLORS.backward.color, opacity: 0.5 }) })
61974
+ ] }),
61975
+ /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
61976
+ layout.edges.map((edge) => {
61977
+ const conn = edge.isSelf ? exports.CONNECTION_COLORS.selfLoop : edge.isBackward ? exports.CONNECTION_COLORS.backward : exports.CONNECTION_COLORS.forward;
61978
+ const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
61979
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
61980
+ /* @__PURE__ */ jsxRuntime.jsx(
61981
+ "path",
61982
+ {
61983
+ d: edgePath(edge.points),
61984
+ fill: "none",
61985
+ stroke: conn.color,
61986
+ strokeWidth: conn.width,
61987
+ strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
61988
+ opacity: 0.5,
61989
+ markerEnd: marker
61990
+ }
61991
+ ),
61992
+ /* @__PURE__ */ jsxRuntime.jsx(
61993
+ exports.AvlTransitionLane,
61994
+ {
61995
+ x: edge.labelX,
61996
+ y: edge.labelY,
61997
+ event: edge.event,
61998
+ guard: edge.guardExpr,
61999
+ effects: edge.effects.map((e) => ({ type: e.type })),
62000
+ width: edge.labelW,
62001
+ isBackward: edge.isBackward,
62002
+ isSelfLoop: edge.isSelf,
62003
+ color,
62004
+ onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
62005
+ x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
62006
+ y: edge.labelY + offsetY
62007
+ }) : void 0
62008
+ }
62009
+ )
62010
+ ] }, edge.id);
62011
+ }),
62012
+ layout.nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx(
62013
+ exports.AvlState,
62014
+ {
62015
+ x: node.x,
62016
+ y: node.y,
62017
+ width: node.width,
62018
+ height: node.height,
62019
+ name: node.id,
62020
+ isInitial: node.isInitial,
62021
+ isTerminal: node.isTerminal,
62022
+ role: node.role,
62023
+ transitionCount: node.transitionCount,
62024
+ color
62025
+ }
62026
+ ) }, node.id))
62027
+ ] })
62028
+ ] });
62029
+ if (!hasExternal) {
62030
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
62031
+ }
62032
+ return /* @__PURE__ */ jsxRuntime.jsx(
62033
+ exports.AvlSwimLane,
62034
+ {
62035
+ listenedEvents: data.listenedEvents,
62036
+ emittedEvents: data.emittedEvents,
62037
+ centerWidth: CENTER_W2,
62038
+ height: machineHeight,
62039
+ color,
62040
+ children: renderMachine
62041
+ }
62042
+ );
62043
+ };
62044
+ AvlTraitScene.displayName = "AvlTraitScene";
62045
+
62046
+ // components/molecules/avl/TraitCardNode.tsx
62047
+ init_avl_schema_parser();
62048
+ var TraitCardSelectionContext = React96.createContext({
62049
+ selectTransition: () => {
62050
+ }
62051
+ });
62052
+ var CARD_WIDTH = 540;
62053
+ var SCENE_WIDTH = 600;
62054
+ var SCENE_HEIGHT = 400;
62055
+ var TraitCardNodeInner = (props) => {
62056
+ const data = props.data;
62057
+ const { selectTransition } = React96.useContext(TraitCardSelectionContext);
62058
+ const orbitalName = data.orbitalName;
62059
+ const traitName = data.traitName ?? "";
62060
+ const linkedEntity = data.linkedEntity ?? "";
62061
+ const transitions = data.transitions ?? [];
62062
+ const emits = data.emits ?? [];
62063
+ const listens = data.listens ?? [];
62064
+ const fullSchema = data._fullSchema;
62065
+ const traitLevelData = React96.useMemo(() => {
62066
+ if (!fullSchema) return null;
62067
+ return parseTraitLevel(fullSchema, orbitalName, traitName);
62068
+ }, [fullSchema, orbitalName, traitName]);
62069
+ return /* @__PURE__ */ jsxRuntime.jsxs(
62070
+ Box,
62071
+ {
62072
+ className: "bg-card border-2 border-border rounded-lg shadow-md p-4",
62073
+ style: { width: CARD_WIDTH, position: "relative" },
62074
+ children: [
62075
+ listens.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
62076
+ react.Handle,
62077
+ {
62078
+ type: "target",
62079
+ position: react.Position.Left,
62080
+ id: `listen-${event}`,
62081
+ style: { top: `${(i + 1) / (listens.length + 1) * 100}%` },
62082
+ "aria-label": `listens for ${event}`
62083
+ },
62084
+ `listen-${event}`
62085
+ )),
62086
+ emits.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
62087
+ react.Handle,
62088
+ {
62089
+ type: "source",
62090
+ position: react.Position.Right,
62091
+ id: `emit-${event}`,
62092
+ style: { top: `${(i + 1) / (emits.length + 1) * 100}%` },
62093
+ "aria-label": `emits ${event}`
62094
+ },
62095
+ `emit-${event}`
62096
+ )),
62097
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
62098
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", justify: "between", align: "center", children: [
62099
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h6", weight: "semibold", children: traitName }),
62100
+ linkedEntity ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", children: linkedEntity }) : null
62101
+ ] }),
62102
+ traitLevelData ? /* @__PURE__ */ jsxRuntime.jsx(
62103
+ "svg",
62104
+ {
62105
+ viewBox: `0 0 ${SCENE_WIDTH} ${SCENE_HEIGHT}`,
62106
+ style: { width: "100%", height: "auto", display: "block" },
62107
+ children: /* @__PURE__ */ jsxRuntime.jsx(
62108
+ AvlTraitScene,
62109
+ {
62110
+ data: traitLevelData,
62111
+ onTransitionClick: (idx) => {
62112
+ const t = transitions[idx];
62113
+ if (!t) return;
62114
+ selectTransition({
62115
+ orbitalName,
62116
+ traitName,
62117
+ transitionEvent: t.event,
62118
+ fromState: t.fromState,
62119
+ toState: t.toState,
62120
+ index: idx
62121
+ });
62122
+ }
62123
+ }
62124
+ )
62125
+ }
62126
+ ) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", children: "No state machine" })
62127
+ ] })
62128
+ ]
62129
+ }
62130
+ );
62131
+ };
62132
+ var TraitCardNode = React96__namespace.default.memo(TraitCardNodeInner);
62133
+ TraitCardNode.displayName = "TraitCardNode";
62134
+
62135
+ // components/organisms/avl/FlowCanvas.tsx
61835
62136
  init_useEventBus();
61836
62137
  var flowCanvasLog = logger.createLogger("almadar:ui:flow-canvas");
61837
62138
  var NODE_TYPES = {
61838
62139
  preview: OrbPreviewNode,
61839
- behaviorCompose: BehaviorComposeNode
62140
+ behaviorCompose: BehaviorComposeNode,
62141
+ traitCard: TraitCardNode
61840
62142
  };
61841
62143
  flowCanvasLog.debug("node-type-registry", () => ({
61842
62144
  registered: Object.keys(NODE_TYPES),
@@ -61877,7 +62179,8 @@ function FlowCanvasInner({
61877
62179
  }) {
61878
62180
  const NODE_TYPES2 = React96.useMemo(() => ({
61879
62181
  preview: OrbPreviewNode,
61880
- behaviorCompose: BehaviorComposeNode
62182
+ behaviorCompose: BehaviorComposeNode,
62183
+ traitCard: TraitCardNode
61881
62184
  }), []);
61882
62185
  const EDGE_TYPES_LOCAL = React96.useMemo(() => ({
61883
62186
  eventFlow: EventFlowEdge
@@ -61925,17 +62228,19 @@ function FlowCanvasInner({
61925
62228
  }
61926
62229
  }), [selectedPattern]);
61927
62230
  const [atBehaviorLevel, setAtBehaviorLevel] = React96.useState(composeLevel === "behavior");
61928
- const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges } = React96.useMemo(() => {
62231
+ const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges, traitExpandedNodes, traitExpandedEdges } = React96.useMemo(() => {
61929
62232
  const t = perfStart("compose-graph");
61930
62233
  const compose = composeLevel === "behavior" && behaviorEntries?.length ? behaviorsToComposeGraph(behaviorEntries, behaviorWires ?? [], layoutHint) : { nodes: [], edges: [] };
61931
62234
  const overview = schemaToOverviewGraph(parsedSchema, mockData, behaviorMeta, layoutHint, orbitalStatus);
61932
62235
  const expanded = expandedOrbital ? orbitalToExpandedGraph(parsedSchema, expandedOrbital, mockData) : { nodes: [], edges: [] };
61933
62236
  const behaviorExpanded = expandedOrbital && expandedBehaviorAlias ? orbitalAliasToExpandedGraph(parsedSchema, expandedOrbital, expandedBehaviorAlias, mockData) : { nodes: [], edges: [] };
62237
+ const traitExpanded = expandedOrbital ? orbitalToTraitGraph(parsedSchema, expandedOrbital) : { nodes: [], edges: [] };
61934
62238
  perfEnd("compose-graph", t, {
61935
62239
  composeNodes: compose.nodes.length,
61936
62240
  overviewNodes: overview.nodes.length,
61937
62241
  expandedNodes: expanded.nodes.length,
61938
62242
  behaviorExpandedNodes: behaviorExpanded.nodes.length,
62243
+ traitExpandedNodes: traitExpanded.nodes.length,
61939
62244
  orbitalCount: parsedSchema.orbitals?.length ?? 0
61940
62245
  });
61941
62246
  return {
@@ -61946,11 +62251,13 @@ function FlowCanvasInner({
61946
62251
  expandedNodes: expanded.nodes,
61947
62252
  expandedEdges: expanded.edges,
61948
62253
  behaviorExpandedNodes: behaviorExpanded.nodes,
61949
- behaviorExpandedEdges: behaviorExpanded.edges
62254
+ behaviorExpandedEdges: behaviorExpanded.edges,
62255
+ traitExpandedNodes: traitExpanded.nodes,
62256
+ traitExpandedEdges: traitExpanded.edges
61950
62257
  };
61951
62258
  }, [parsedSchema, expandedOrbital, expandedBehaviorAlias, behaviorMeta, layoutHint, composeLevel, behaviorEntries, behaviorWires, mockData, orbitalStatus]);
61952
- const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : expandedNodes;
61953
- const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : level === "behavior-expanded" ? behaviorExpandedEdges : expandedEdges;
62259
+ const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : level === "trait-expanded" ? traitExpandedNodes : expandedNodes;
62260
+ const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : level === "behavior-expanded" ? behaviorExpandedEdges : level === "trait-expanded" ? traitExpandedEdges : expandedEdges;
61954
62261
  const [nodes, setNodes, onNodesChange] = react.useNodesState(activeNodes);
61955
62262
  const [edges, setEdges, onEdgesChange] = react.useEdgesState(activeEdges);
61956
62263
  const reactFlow = react.useReactFlow();
@@ -62107,7 +62414,17 @@ function FlowCanvasInner({
62107
62414
  });
62108
62415
  }, [nodes, onEventWire, eventBus]);
62109
62416
  const screenSizeKeys = ["mobile", "tablet", "laptop", "wide"];
62110
- return /* @__PURE__ */ jsxRuntime.jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsxRuntime.jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
62417
+ const traitCardSelectionValue = React96.useMemo(() => ({
62418
+ selectTransition: (sel) => {
62419
+ onNodeClick?.({
62420
+ level: "transition",
62421
+ orbital: sel.orbitalName,
62422
+ trait: sel.traitName,
62423
+ transition: sel.transitionEvent
62424
+ });
62425
+ }
62426
+ }), [onNodeClick]);
62427
+ return /* @__PURE__ */ jsxRuntime.jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsxRuntime.jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsxRuntime.jsx(TraitCardSelectionContext.Provider, { value: traitCardSelectionValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
62111
62428
  Box,
62112
62429
  {
62113
62430
  className: `flex h-full ${className ?? ""}`,
@@ -62225,7 +62542,7 @@ function FlowCanvasInner({
62225
62542
  ] })
62226
62543
  ]
62227
62544
  }
62228
- ) }) });
62545
+ ) }) }) });
62229
62546
  }
62230
62547
  var FlowCanvas = (props) => {
62231
62548
  return /* @__PURE__ */ jsxRuntime.jsx(React96.Profiler, { id: "flow-canvas", onRender: profilerOnRender, children: /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(FlowCanvasInner, { ...props }) }) });
@@ -62349,122 +62666,6 @@ AvlCosmicZoom.displayName = "AvlCosmicZoom";
62349
62666
  init_avl_schema_parser();
62350
62667
  init_avl_zoom_state();
62351
62668
 
62352
- // components/organisms/avl/AvlTraitScene.tsx
62353
- init_AvlState();
62354
- init_AvlTransitionLane();
62355
- init_AvlSwimLane();
62356
- init_types();
62357
- init_avl_elk_layout();
62358
- var log19 = logger.createLogger("almadar:ui:avl:trait-scene");
62359
- var SWIM_GUTTER2 = 120;
62360
- var CENTER_W2 = 360;
62361
- var AvlTraitScene = ({
62362
- data,
62363
- color = "var(--color-primary)",
62364
- onTransitionClick
62365
- }) => {
62366
- const [layout, setLayout] = React96.useState(null);
62367
- const dataKey = React96.useMemo(() => JSON.stringify(data), [data]);
62368
- React96.useEffect(() => {
62369
- computeTraitLayout(data).then(setLayout).catch((error) => {
62370
- log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
62371
- });
62372
- }, [dataKey]);
62373
- if (!layout) {
62374
- return /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx("text", { x: 300, y: 200, textAnchor: "middle", fill: color, fontSize: 12, opacity: 0.5, children: "Computing layout..." }) });
62375
- }
62376
- const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
62377
- const machineOffsetX = hasExternal ? 0 : 30;
62378
- const padding = 20;
62379
- const availW = CENTER_W2 - padding * 2;
62380
- const availH = 300;
62381
- const scale = Math.min(1, availW / layout.width, availH / layout.height);
62382
- const scaledW = layout.width * scale;
62383
- const scaledH = layout.height * scale;
62384
- const offsetX = padding + (availW - scaledW) / 2;
62385
- const offsetY = 50 + (availH - scaledH) / 2;
62386
- const machineHeight = scaledH + 100;
62387
- const renderMachine = /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
62388
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
62389
- /* @__PURE__ */ jsxRuntime.jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
62390
- "linked to ",
62391
- data.linkedEntity
62392
- ] }),
62393
- /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
62394
- /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "traitArrowV2", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: exports.CONNECTION_COLORS.forward.color, opacity: 0.7 }) }),
62395
- /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "traitArrowBack", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto-start-reverse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: exports.CONNECTION_COLORS.backward.color, opacity: 0.5 }) })
62396
- ] }),
62397
- /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
62398
- layout.edges.map((edge) => {
62399
- const conn = edge.isSelf ? exports.CONNECTION_COLORS.selfLoop : edge.isBackward ? exports.CONNECTION_COLORS.backward : exports.CONNECTION_COLORS.forward;
62400
- const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
62401
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
62402
- /* @__PURE__ */ jsxRuntime.jsx(
62403
- "path",
62404
- {
62405
- d: edgePath(edge.points),
62406
- fill: "none",
62407
- stroke: conn.color,
62408
- strokeWidth: conn.width,
62409
- strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
62410
- opacity: 0.5,
62411
- markerEnd: marker
62412
- }
62413
- ),
62414
- /* @__PURE__ */ jsxRuntime.jsx(
62415
- exports.AvlTransitionLane,
62416
- {
62417
- x: edge.labelX,
62418
- y: edge.labelY,
62419
- event: edge.event,
62420
- guard: edge.guardExpr,
62421
- effects: edge.effects.map((e) => ({ type: e.type })),
62422
- width: edge.labelW,
62423
- isBackward: edge.isBackward,
62424
- isSelfLoop: edge.isSelf,
62425
- color,
62426
- onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
62427
- x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
62428
- y: edge.labelY + offsetY
62429
- }) : void 0
62430
- }
62431
- )
62432
- ] }, edge.id);
62433
- }),
62434
- layout.nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx(
62435
- exports.AvlState,
62436
- {
62437
- x: node.x,
62438
- y: node.y,
62439
- width: node.width,
62440
- height: node.height,
62441
- name: node.id,
62442
- isInitial: node.isInitial,
62443
- isTerminal: node.isTerminal,
62444
- role: node.role,
62445
- transitionCount: node.transitionCount,
62446
- color
62447
- }
62448
- ) }, node.id))
62449
- ] })
62450
- ] });
62451
- if (!hasExternal) {
62452
- return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
62453
- }
62454
- return /* @__PURE__ */ jsxRuntime.jsx(
62455
- exports.AvlSwimLane,
62456
- {
62457
- listenedEvents: data.listenedEvents,
62458
- emittedEvents: data.emittedEvents,
62459
- centerWidth: CENTER_W2,
62460
- height: machineHeight,
62461
- color,
62462
- children: renderMachine
62463
- }
62464
- );
62465
- };
62466
- AvlTraitScene.displayName = "AvlTraitScene";
62467
-
62468
62669
  // components/organisms/avl/AvlTransitionScene.tsx
62469
62670
  init_AvlEffect();
62470
62671
  init_types();
@@ -62951,26 +63152,34 @@ var AvlOrbitalsCosmicZoom = ({
62951
63152
  if (!highlightedOrbital) return;
62952
63153
  if (drilledForHighlightRef.current) return;
62953
63154
  drilledForHighlightRef.current = true;
62954
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: highlightedOrbital, targetPosition: { x: 0, y: 0 } });
62955
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63155
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: highlightedOrbital });
62956
63156
  }, [highlightedOrbital]);
62957
63157
  const breadcrumbs = React96.useMemo(() => getBreadcrumbs(state), [state]);
62958
63158
  const handleSelect = React96.useCallback(
62959
63159
  (name) => {
62960
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
62961
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63160
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: name });
62962
63161
  onOrbitalSelect?.(name);
62963
63162
  },
62964
63163
  [onOrbitalSelect]
62965
63164
  );
62966
- const handleTraitSelect = React96.useCallback((traitName) => {
62967
- dispatch({ type: "ZOOM_INTO_TRAIT", trait: traitName, targetPosition: { x: 0, y: 0 } });
62968
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62969
- }, []);
62970
- const handleTransitionSelect = React96.useCallback((transitionIndex) => {
63165
+ React96.useCallback((transitionIndex) => {
62971
63166
  dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex, targetPosition: { x: 0, y: 0 } });
62972
63167
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62973
63168
  }, []);
63169
+ const handleCanvasNodeClick = React96.useCallback(
63170
+ (ctx) => {
63171
+ if (ctx.level !== "transition" || !ctx.trait || !ctx.transition) return;
63172
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === ctx.orbital);
63173
+ const traitRef = orbital?.traits?.find((t) => core.isInlineTrait(t) && t.name === ctx.trait);
63174
+ if (!traitRef || !core.isInlineTrait(traitRef)) return;
63175
+ const idx = traitRef.stateMachine?.transitions?.findIndex((t) => t.event === ctx.transition) ?? -1;
63176
+ if (idx < 0) return;
63177
+ dispatch({ type: "SELECT_TRAIT", trait: ctx.trait });
63178
+ dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: idx, targetPosition: { x: 0, y: 0 } });
63179
+ Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63180
+ },
63181
+ [parsedSchema]
63182
+ );
62974
63183
  const handleZoomOut = React96.useCallback(() => {
62975
63184
  dispatch({ type: "ZOOM_OUT" });
62976
63185
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
@@ -62993,14 +63202,6 @@ var AvlOrbitalsCosmicZoom = ({
62993
63202
  window.addEventListener("keydown", onKey);
62994
63203
  return () => window.removeEventListener("keydown", onKey);
62995
63204
  }, [handleZoomOut, state.level]);
62996
- const orbitalLevelData = React96.useMemo(() => {
62997
- if (!state.selectedOrbital) return null;
62998
- return parseOrbitalLevel(parsedSchema, state.selectedOrbital);
62999
- }, [parsedSchema, state.selectedOrbital]);
63000
- const traitLevelData = React96.useMemo(() => {
63001
- if (!state.selectedOrbital || !state.selectedTrait) return null;
63002
- return parseTraitLevel(parsedSchema, state.selectedOrbital, state.selectedTrait);
63003
- }, [parsedSchema, state.selectedOrbital, state.selectedTrait]);
63004
63205
  const transitionLevelData = React96.useMemo(() => {
63005
63206
  if (!state.selectedOrbital || !state.selectedTrait || state.selectedTransition === null) return null;
63006
63207
  return parseTransitionLevel(
@@ -63010,6 +63211,12 @@ var AvlOrbitalsCosmicZoom = ({
63010
63211
  state.selectedTransition
63011
63212
  );
63012
63213
  }, [parsedSchema, state.selectedOrbital, state.selectedTrait, state.selectedTransition]);
63214
+ const scopedSchema = React96.useMemo(() => {
63215
+ if (!state.selectedOrbital) return null;
63216
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === state.selectedOrbital);
63217
+ if (!orbital) return null;
63218
+ return { ...parsedSchema, orbitals: [orbital] };
63219
+ }, [parsedSchema, state.selectedOrbital]);
63013
63220
  const [zoom, setZoom] = React96.useState(1);
63014
63221
  const [pan, setPan] = React96.useState({ x: 0, y: 0 });
63015
63222
  const dragStateRef = React96.useRef(null);
@@ -63057,6 +63264,7 @@ var AvlOrbitalsCosmicZoom = ({
63057
63264
  zoomRef.current = zoom;
63058
63265
  }, [zoom]);
63059
63266
  React96.useEffect(() => {
63267
+ if (state.level !== "application") return;
63060
63268
  const wrapper = transformWrapperRef.current;
63061
63269
  if (!wrapper) return;
63062
63270
  const wheelListener = (e) => {
@@ -63247,81 +63455,7 @@ var AvlOrbitalsCosmicZoom = ({
63247
63455
  }
63248
63456
  )
63249
63457
  ] }),
63250
- state.level === "orbital" && orbitalLevelData && /* @__PURE__ */ jsxRuntime.jsxs(
63251
- Box,
63252
- {
63253
- position: "absolute",
63254
- style: {
63255
- inset: 0,
63256
- paddingTop: 56,
63257
- paddingBottom: 24,
63258
- paddingLeft: 24,
63259
- paddingRight: 24,
63260
- display: "flex",
63261
- alignItems: "stretch",
63262
- justifyContent: "center",
63263
- gap: 24
63264
- },
63265
- children: [
63266
- /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { flex: 1, maxWidth: 720, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(
63267
- AvlOrbitalUnit,
63268
- {
63269
- entityName: orbitalLevelData.entity.name,
63270
- fields: orbitalLevelData.entity.fields.length,
63271
- persistence: orbitalLevelData.entity.persistence || "persistent",
63272
- traits: orbitalLevelData.traits.map((t) => ({ name: t.name })),
63273
- pages: orbitalLevelData.pages.map((p2) => ({ name: p2.name })),
63274
- color,
63275
- animated
63276
- }
63277
- ) }),
63278
- /* @__PURE__ */ jsxRuntime.jsxs(
63279
- Box,
63280
- {
63281
- style: {
63282
- width: 220,
63283
- padding: 12,
63284
- display: "flex",
63285
- flexDirection: "column",
63286
- gap: 8,
63287
- borderLeft: `1px solid ${color}`,
63288
- opacity: 0.95,
63289
- overflowY: "auto",
63290
- minHeight: 0
63291
- },
63292
- children: [
63293
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginBottom: 4 }, children: [
63294
- "Traits (",
63295
- orbitalLevelData.traits.length,
63296
- ")"
63297
- ] }),
63298
- orbitalLevelData.traits.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(Text, { variant: "small", style: { opacity: 0.6, color }, children: "No traits" }),
63299
- orbitalLevelData.traits.map((trait) => /* @__PURE__ */ jsxRuntime.jsx(
63300
- Button,
63301
- {
63302
- variant: "ghost",
63303
- size: "sm",
63304
- onClick: () => handleTraitSelect(trait.name),
63305
- action: "COSMIC_DRILL_TRAIT",
63306
- children: trait.name
63307
- },
63308
- trait.name
63309
- )),
63310
- orbitalLevelData.pages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63311
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginTop: 12 }, children: [
63312
- "Pages (",
63313
- orbitalLevelData.pages.length,
63314
- ")"
63315
- ] }),
63316
- orbitalLevelData.pages.map((page) => /* @__PURE__ */ jsxRuntime.jsx(Text, { variant: "small", style: { opacity: 0.7, color }, children: page.name }, page.name))
63317
- ] })
63318
- ]
63319
- }
63320
- )
63321
- ]
63322
- }
63323
- ),
63324
- state.level === "trait" && traitLevelData && /* @__PURE__ */ jsxRuntime.jsx(
63458
+ state.level === "trait" && scopedSchema && state.selectedOrbital && /* @__PURE__ */ jsxRuntime.jsx(
63325
63459
  Box,
63326
63460
  {
63327
63461
  position: "absolute",
@@ -63333,39 +63467,14 @@ var AvlOrbitalsCosmicZoom = ({
63333
63467
  paddingRight: 24
63334
63468
  },
63335
63469
  children: /* @__PURE__ */ jsxRuntime.jsx(
63336
- Box,
63470
+ FlowCanvas,
63337
63471
  {
63338
- ref: transformWrapperRef,
63339
- position: "relative",
63340
- onPointerDown: handlePointerDown,
63341
- onPointerMove: handlePointerMove,
63342
- onPointerUp: handlePointerUp,
63343
- onPointerCancel: handlePointerUp,
63344
- style: {
63345
- width: "100%",
63346
- height: "100%",
63347
- cursor: dragStateRef.current ? "grabbing" : "grab",
63348
- overflow: "hidden"
63349
- },
63350
- children: /* @__PURE__ */ jsxRuntime.jsx(
63351
- Box,
63352
- {
63353
- position: "absolute",
63354
- style: {
63355
- inset: 0,
63356
- transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
63357
- transformOrigin: "0 0"
63358
- },
63359
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 600 400", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
63360
- AvlTraitScene,
63361
- {
63362
- data: traitLevelData,
63363
- color,
63364
- onTransitionClick: (idx) => handleTransitionSelect(idx)
63365
- }
63366
- ) })
63367
- }
63368
- )
63472
+ schema: scopedSchema,
63473
+ initialLevel: "trait-expanded",
63474
+ initialOrbital: state.selectedOrbital,
63475
+ onNodeClick: handleCanvasNodeClick,
63476
+ width: "100%",
63477
+ height: "100%"
63369
63478
  }
63370
63479
  )
63371
63480
  }
@@ -63418,7 +63527,7 @@ var AvlOrbitalsCosmicZoom = ({
63418
63527
  )
63419
63528
  }
63420
63529
  ),
63421
- (state.level === "trait" || state.level === "transition") && /* @__PURE__ */ jsxRuntime.jsxs(
63530
+ state.level === "transition" && /* @__PURE__ */ jsxRuntime.jsxs(
63422
63531
  Box,
63423
63532
  {
63424
63533
  position: "absolute",