@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.
@@ -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,66 @@ 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
+ // Required fields on PreviewNodeData — keep empty for trait cards.
57858
+ patterns: [],
57859
+ eventSources: []
57860
+ }
57861
+ });
57862
+ }
57863
+ const wires = extractTraitWires([orbital], "intra-orbital");
57864
+ const edges = wires.map((w) => ({
57865
+ id: `wire-${orbitalName}-${w.emitterTrait}-${w.listenerTrait}-${w.event}`,
57866
+ source: `trait-${orbitalName}-${w.emitterTrait}`,
57867
+ target: `trait-${orbitalName}-${w.listenerTrait}`,
57868
+ sourceHandle: `emit-${w.event}`,
57869
+ targetHandle: `listen-${w.event}`,
57870
+ type: "eventFlow",
57871
+ data: {
57872
+ event: w.event,
57873
+ isCrossOrbital: false,
57874
+ fromTrait: w.emitterTrait,
57875
+ toTrait: w.listenerTrait
57876
+ }
57877
+ }));
57878
+ return { nodes, edges };
57879
+ }
57797
57880
 
57798
57881
  // components/molecules/avl/OrbPreviewNode.tsx
57799
57882
  init_Box();
@@ -61832,11 +61915,104 @@ function TokenRow({ group, tokenKey, value, isColor, onPropChange }) {
61832
61915
  // components/organisms/avl/FlowCanvas.tsx
61833
61916
  init_Box();
61834
61917
  init_Typography();
61918
+
61919
+ // components/molecules/avl/TraitCardNode.tsx
61920
+ init_Box();
61921
+ init_Stack();
61922
+ init_Typography();
61923
+ init_Button();
61924
+ init_Badge();
61925
+ var TraitCardSelectionContext = React96.createContext({
61926
+ selectTransition: () => {
61927
+ }
61928
+ });
61929
+ var CARD_WIDTH = 360;
61930
+ var CARD_MIN_HEIGHT = 200;
61931
+ var TraitCardNodeInner = (props) => {
61932
+ const data = props.data;
61933
+ const { selectTransition } = React96.useContext(TraitCardSelectionContext);
61934
+ const orbitalName = data.orbitalName;
61935
+ const traitName = data.traitName ?? "";
61936
+ const linkedEntity = data.linkedEntity ?? "";
61937
+ const transitions = data.transitions ?? [];
61938
+ const emits = data.emits ?? [];
61939
+ const listens = data.listens ?? [];
61940
+ return /* @__PURE__ */ jsxRuntime.jsxs(
61941
+ Box,
61942
+ {
61943
+ className: "bg-card border-2 border-border rounded-lg shadow-md p-4",
61944
+ style: { width: CARD_WIDTH, minHeight: CARD_MIN_HEIGHT, position: "relative" },
61945
+ children: [
61946
+ listens.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
61947
+ react.Handle,
61948
+ {
61949
+ type: "target",
61950
+ position: react.Position.Left,
61951
+ id: `listen-${event}`,
61952
+ style: { top: `${(i + 1) / (listens.length + 1) * 100}%` },
61953
+ "aria-label": `listens for ${event}`
61954
+ },
61955
+ `listen-${event}`
61956
+ )),
61957
+ emits.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
61958
+ react.Handle,
61959
+ {
61960
+ type: "source",
61961
+ position: react.Position.Right,
61962
+ id: `emit-${event}`,
61963
+ style: { top: `${(i + 1) / (emits.length + 1) * 100}%` },
61964
+ "aria-label": `emits ${event}`
61965
+ },
61966
+ `emit-${event}`
61967
+ )),
61968
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
61969
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", justify: "between", align: "center", children: [
61970
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h6", weight: "semibold", children: traitName }),
61971
+ linkedEntity ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", children: linkedEntity }) : null
61972
+ ] }),
61973
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", children: transitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", children: "No transitions" }) : transitions.map((t, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
61974
+ Button,
61975
+ {
61976
+ variant: "ghost",
61977
+ size: "sm",
61978
+ onClick: (e) => {
61979
+ e.stopPropagation();
61980
+ selectTransition({
61981
+ orbitalName,
61982
+ traitName,
61983
+ transitionEvent: t.event,
61984
+ fromState: t.fromState,
61985
+ toState: t.toState,
61986
+ index: idx
61987
+ });
61988
+ },
61989
+ children: [
61990
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "semibold", children: t.event }),
61991
+ /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", color: "muted", children: [
61992
+ " \xB7 ",
61993
+ t.fromState,
61994
+ " \u2192 ",
61995
+ t.toState
61996
+ ] })
61997
+ ]
61998
+ },
61999
+ `${t.event}-${t.fromState}-${t.toState}-${idx}`
62000
+ )) })
62001
+ ] })
62002
+ ]
62003
+ }
62004
+ );
62005
+ };
62006
+ var TraitCardNode = React96__namespace.default.memo(TraitCardNodeInner);
62007
+ TraitCardNode.displayName = "TraitCardNode";
62008
+
62009
+ // components/organisms/avl/FlowCanvas.tsx
61835
62010
  init_useEventBus();
61836
62011
  var flowCanvasLog = logger.createLogger("almadar:ui:flow-canvas");
61837
62012
  var NODE_TYPES = {
61838
62013
  preview: OrbPreviewNode,
61839
- behaviorCompose: BehaviorComposeNode
62014
+ behaviorCompose: BehaviorComposeNode,
62015
+ traitCard: TraitCardNode
61840
62016
  };
61841
62017
  flowCanvasLog.debug("node-type-registry", () => ({
61842
62018
  registered: Object.keys(NODE_TYPES),
@@ -61877,7 +62053,8 @@ function FlowCanvasInner({
61877
62053
  }) {
61878
62054
  const NODE_TYPES2 = React96.useMemo(() => ({
61879
62055
  preview: OrbPreviewNode,
61880
- behaviorCompose: BehaviorComposeNode
62056
+ behaviorCompose: BehaviorComposeNode,
62057
+ traitCard: TraitCardNode
61881
62058
  }), []);
61882
62059
  const EDGE_TYPES_LOCAL = React96.useMemo(() => ({
61883
62060
  eventFlow: EventFlowEdge
@@ -61925,17 +62102,19 @@ function FlowCanvasInner({
61925
62102
  }
61926
62103
  }), [selectedPattern]);
61927
62104
  const [atBehaviorLevel, setAtBehaviorLevel] = React96.useState(composeLevel === "behavior");
61928
- const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges } = React96.useMemo(() => {
62105
+ const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges, behaviorExpandedNodes, behaviorExpandedEdges, traitExpandedNodes, traitExpandedEdges } = React96.useMemo(() => {
61929
62106
  const t = perfStart("compose-graph");
61930
62107
  const compose = composeLevel === "behavior" && behaviorEntries?.length ? behaviorsToComposeGraph(behaviorEntries, behaviorWires ?? [], layoutHint) : { nodes: [], edges: [] };
61931
62108
  const overview = schemaToOverviewGraph(parsedSchema, mockData, behaviorMeta, layoutHint, orbitalStatus);
61932
62109
  const expanded = expandedOrbital ? orbitalToExpandedGraph(parsedSchema, expandedOrbital, mockData) : { nodes: [], edges: [] };
61933
62110
  const behaviorExpanded = expandedOrbital && expandedBehaviorAlias ? orbitalAliasToExpandedGraph(parsedSchema, expandedOrbital, expandedBehaviorAlias, mockData) : { nodes: [], edges: [] };
62111
+ const traitExpanded = expandedOrbital ? orbitalToTraitGraph(parsedSchema, expandedOrbital) : { nodes: [], edges: [] };
61934
62112
  perfEnd("compose-graph", t, {
61935
62113
  composeNodes: compose.nodes.length,
61936
62114
  overviewNodes: overview.nodes.length,
61937
62115
  expandedNodes: expanded.nodes.length,
61938
62116
  behaviorExpandedNodes: behaviorExpanded.nodes.length,
62117
+ traitExpandedNodes: traitExpanded.nodes.length,
61939
62118
  orbitalCount: parsedSchema.orbitals?.length ?? 0
61940
62119
  });
61941
62120
  return {
@@ -61946,11 +62125,13 @@ function FlowCanvasInner({
61946
62125
  expandedNodes: expanded.nodes,
61947
62126
  expandedEdges: expanded.edges,
61948
62127
  behaviorExpandedNodes: behaviorExpanded.nodes,
61949
- behaviorExpandedEdges: behaviorExpanded.edges
62128
+ behaviorExpandedEdges: behaviorExpanded.edges,
62129
+ traitExpandedNodes: traitExpanded.nodes,
62130
+ traitExpandedEdges: traitExpanded.edges
61950
62131
  };
61951
62132
  }, [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;
62133
+ const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : level === "trait-expanded" ? traitExpandedNodes : expandedNodes;
62134
+ const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : level === "behavior-expanded" ? behaviorExpandedEdges : level === "trait-expanded" ? traitExpandedEdges : expandedEdges;
61954
62135
  const [nodes, setNodes, onNodesChange] = react.useNodesState(activeNodes);
61955
62136
  const [edges, setEdges, onEdgesChange] = react.useEdgesState(activeEdges);
61956
62137
  const reactFlow = react.useReactFlow();
@@ -62107,7 +62288,17 @@ function FlowCanvasInner({
62107
62288
  });
62108
62289
  }, [nodes, onEventWire, eventBus]);
62109
62290
  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(
62291
+ const traitCardSelectionValue = React96.useMemo(() => ({
62292
+ selectTransition: (sel) => {
62293
+ onNodeClick?.({
62294
+ level: "transition",
62295
+ orbital: sel.orbitalName,
62296
+ trait: sel.traitName,
62297
+ transition: sel.transitionEvent
62298
+ });
62299
+ }
62300
+ }), [onNodeClick]);
62301
+ 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
62302
  Box,
62112
62303
  {
62113
62304
  className: `flex h-full ${className ?? ""}`,
@@ -62225,7 +62416,7 @@ function FlowCanvasInner({
62225
62416
  ] })
62226
62417
  ]
62227
62418
  }
62228
- ) }) });
62419
+ ) }) }) });
62229
62420
  }
62230
62421
  var FlowCanvas = (props) => {
62231
62422
  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 +62540,6 @@ AvlCosmicZoom.displayName = "AvlCosmicZoom";
62349
62540
  init_avl_schema_parser();
62350
62541
  init_avl_zoom_state();
62351
62542
 
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
62543
  // components/organisms/avl/AvlTransitionScene.tsx
62469
62544
  init_AvlEffect();
62470
62545
  init_types();
@@ -62951,26 +63026,34 @@ var AvlOrbitalsCosmicZoom = ({
62951
63026
  if (!highlightedOrbital) return;
62952
63027
  if (drilledForHighlightRef.current) return;
62953
63028
  drilledForHighlightRef.current = true;
62954
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: highlightedOrbital, targetPosition: { x: 0, y: 0 } });
62955
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63029
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: highlightedOrbital });
62956
63030
  }, [highlightedOrbital]);
62957
63031
  const breadcrumbs = React96.useMemo(() => getBreadcrumbs(state), [state]);
62958
63032
  const handleSelect = React96.useCallback(
62959
63033
  (name) => {
62960
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
62961
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63034
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: name });
62962
63035
  onOrbitalSelect?.(name);
62963
63036
  },
62964
63037
  [onOrbitalSelect]
62965
63038
  );
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) => {
63039
+ React96.useCallback((transitionIndex) => {
62971
63040
  dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex, targetPosition: { x: 0, y: 0 } });
62972
63041
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62973
63042
  }, []);
63043
+ const handleCanvasNodeClick = React96.useCallback(
63044
+ (ctx) => {
63045
+ if (ctx.level !== "transition" || !ctx.trait || !ctx.transition) return;
63046
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === ctx.orbital);
63047
+ const traitRef = orbital?.traits?.find((t) => core.isInlineTrait(t) && t.name === ctx.trait);
63048
+ if (!traitRef || !core.isInlineTrait(traitRef)) return;
63049
+ const idx = traitRef.stateMachine?.transitions?.findIndex((t) => t.event === ctx.transition) ?? -1;
63050
+ if (idx < 0) return;
63051
+ dispatch({ type: "SELECT_TRAIT", trait: ctx.trait });
63052
+ dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: idx, targetPosition: { x: 0, y: 0 } });
63053
+ Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63054
+ },
63055
+ [parsedSchema]
63056
+ );
62974
63057
  const handleZoomOut = React96.useCallback(() => {
62975
63058
  dispatch({ type: "ZOOM_OUT" });
62976
63059
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
@@ -62993,14 +63076,6 @@ var AvlOrbitalsCosmicZoom = ({
62993
63076
  window.addEventListener("keydown", onKey);
62994
63077
  return () => window.removeEventListener("keydown", onKey);
62995
63078
  }, [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
63079
  const transitionLevelData = React96.useMemo(() => {
63005
63080
  if (!state.selectedOrbital || !state.selectedTrait || state.selectedTransition === null) return null;
63006
63081
  return parseTransitionLevel(
@@ -63010,6 +63085,12 @@ var AvlOrbitalsCosmicZoom = ({
63010
63085
  state.selectedTransition
63011
63086
  );
63012
63087
  }, [parsedSchema, state.selectedOrbital, state.selectedTrait, state.selectedTransition]);
63088
+ const scopedSchema = React96.useMemo(() => {
63089
+ if (!state.selectedOrbital) return null;
63090
+ const orbital = parsedSchema.orbitals?.find((o) => o.name === state.selectedOrbital);
63091
+ if (!orbital) return null;
63092
+ return { ...parsedSchema, orbitals: [orbital] };
63093
+ }, [parsedSchema, state.selectedOrbital]);
63013
63094
  const [zoom, setZoom] = React96.useState(1);
63014
63095
  const [pan, setPan] = React96.useState({ x: 0, y: 0 });
63015
63096
  const dragStateRef = React96.useRef(null);
@@ -63057,6 +63138,7 @@ var AvlOrbitalsCosmicZoom = ({
63057
63138
  zoomRef.current = zoom;
63058
63139
  }, [zoom]);
63059
63140
  React96.useEffect(() => {
63141
+ if (state.level !== "application") return;
63060
63142
  const wrapper = transformWrapperRef.current;
63061
63143
  if (!wrapper) return;
63062
63144
  const wheelListener = (e) => {
@@ -63247,81 +63329,7 @@ var AvlOrbitalsCosmicZoom = ({
63247
63329
  }
63248
63330
  )
63249
63331
  ] }),
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(
63332
+ state.level === "trait" && scopedSchema && state.selectedOrbital && /* @__PURE__ */ jsxRuntime.jsx(
63325
63333
  Box,
63326
63334
  {
63327
63335
  position: "absolute",
@@ -63333,39 +63341,14 @@ var AvlOrbitalsCosmicZoom = ({
63333
63341
  paddingRight: 24
63334
63342
  },
63335
63343
  children: /* @__PURE__ */ jsxRuntime.jsx(
63336
- Box,
63344
+ FlowCanvas,
63337
63345
  {
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
- )
63346
+ schema: scopedSchema,
63347
+ initialLevel: "trait-expanded",
63348
+ initialOrbital: state.selectedOrbital,
63349
+ onNodeClick: handleCanvasNodeClick,
63350
+ width: "100%",
63351
+ height: "100%"
63369
63352
  }
63370
63353
  )
63371
63354
  }
@@ -63418,7 +63401,7 @@ var AvlOrbitalsCosmicZoom = ({
63418
63401
  )
63419
63402
  }
63420
63403
  ),
63421
- (state.level === "trait" || state.level === "transition") && /* @__PURE__ */ jsxRuntime.jsxs(
63404
+ state.level === "transition" && /* @__PURE__ */ jsxRuntime.jsxs(
63422
63405
  Box,
63423
63406
  {
63424
63407
  position: "absolute",
@@ -63442,6 +63425,122 @@ var AvlOrbitalsCosmicZoom = ({
63442
63425
  );
63443
63426
  };
63444
63427
  AvlOrbitalsCosmicZoom.displayName = "AvlOrbitalsCosmicZoom";
63428
+
63429
+ // components/organisms/avl/AvlTraitScene.tsx
63430
+ init_AvlState();
63431
+ init_AvlTransitionLane();
63432
+ init_AvlSwimLane();
63433
+ init_types();
63434
+ init_avl_elk_layout();
63435
+ var log19 = logger.createLogger("almadar:ui:avl:trait-scene");
63436
+ var SWIM_GUTTER2 = 120;
63437
+ var CENTER_W2 = 360;
63438
+ var AvlTraitScene = ({
63439
+ data,
63440
+ color = "var(--color-primary)",
63441
+ onTransitionClick
63442
+ }) => {
63443
+ const [layout, setLayout] = React96.useState(null);
63444
+ const dataKey = React96.useMemo(() => JSON.stringify(data), [data]);
63445
+ React96.useEffect(() => {
63446
+ computeTraitLayout(data).then(setLayout).catch((error) => {
63447
+ log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
63448
+ });
63449
+ }, [dataKey]);
63450
+ if (!layout) {
63451
+ 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..." }) });
63452
+ }
63453
+ const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
63454
+ const machineOffsetX = hasExternal ? 0 : 30;
63455
+ const padding = 20;
63456
+ const availW = CENTER_W2 - padding * 2;
63457
+ const availH = 300;
63458
+ const scale = Math.min(1, availW / layout.width, availH / layout.height);
63459
+ const scaledW = layout.width * scale;
63460
+ const scaledH = layout.height * scale;
63461
+ const offsetX = padding + (availW - scaledW) / 2;
63462
+ const offsetY = 50 + (availH - scaledH) / 2;
63463
+ const machineHeight = scaledH + 100;
63464
+ const renderMachine = /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
63465
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
63466
+ /* @__PURE__ */ jsxRuntime.jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
63467
+ "linked to ",
63468
+ data.linkedEntity
63469
+ ] }),
63470
+ /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
63471
+ /* @__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 }) }),
63472
+ /* @__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 }) })
63473
+ ] }),
63474
+ /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
63475
+ layout.edges.map((edge) => {
63476
+ const conn = edge.isSelf ? exports.CONNECTION_COLORS.selfLoop : edge.isBackward ? exports.CONNECTION_COLORS.backward : exports.CONNECTION_COLORS.forward;
63477
+ const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
63478
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
63479
+ /* @__PURE__ */ jsxRuntime.jsx(
63480
+ "path",
63481
+ {
63482
+ d: edgePath(edge.points),
63483
+ fill: "none",
63484
+ stroke: conn.color,
63485
+ strokeWidth: conn.width,
63486
+ strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
63487
+ opacity: 0.5,
63488
+ markerEnd: marker
63489
+ }
63490
+ ),
63491
+ /* @__PURE__ */ jsxRuntime.jsx(
63492
+ exports.AvlTransitionLane,
63493
+ {
63494
+ x: edge.labelX,
63495
+ y: edge.labelY,
63496
+ event: edge.event,
63497
+ guard: edge.guardExpr,
63498
+ effects: edge.effects.map((e) => ({ type: e.type })),
63499
+ width: edge.labelW,
63500
+ isBackward: edge.isBackward,
63501
+ isSelfLoop: edge.isSelf,
63502
+ color,
63503
+ onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
63504
+ x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
63505
+ y: edge.labelY + offsetY
63506
+ }) : void 0
63507
+ }
63508
+ )
63509
+ ] }, edge.id);
63510
+ }),
63511
+ layout.nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx(
63512
+ exports.AvlState,
63513
+ {
63514
+ x: node.x,
63515
+ y: node.y,
63516
+ width: node.width,
63517
+ height: node.height,
63518
+ name: node.id,
63519
+ isInitial: node.isInitial,
63520
+ isTerminal: node.isTerminal,
63521
+ role: node.role,
63522
+ transitionCount: node.transitionCount,
63523
+ color
63524
+ }
63525
+ ) }, node.id))
63526
+ ] })
63527
+ ] });
63528
+ if (!hasExternal) {
63529
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
63530
+ }
63531
+ return /* @__PURE__ */ jsxRuntime.jsx(
63532
+ exports.AvlSwimLane,
63533
+ {
63534
+ listenedEvents: data.listenedEvents,
63535
+ emittedEvents: data.emittedEvents,
63536
+ centerWidth: CENTER_W2,
63537
+ height: machineHeight,
63538
+ color,
63539
+ children: renderMachine
63540
+ }
63541
+ );
63542
+ };
63543
+ AvlTraitScene.displayName = "AvlTraitScene";
63445
63544
  var AvlClickTarget = ({
63446
63545
  x,
63447
63546
  y,