@almadar/ui 4.54.4 → 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.
@@ -13287,36 +13287,37 @@ var init_Popover = __esm({
13287
13287
  ...triggerProps
13288
13288
  }
13289
13289
  );
13290
+ const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxRuntime.jsxs(
13291
+ "div",
13292
+ {
13293
+ ref: popoverRef,
13294
+ className: cn(
13295
+ "fixed z-50 p-4",
13296
+ "bg-card border-2 border-border shadow-lg",
13297
+ positionClasses2[position],
13298
+ className
13299
+ ),
13300
+ style: computePopoverStyle(position, triggerRect, popoverWidth),
13301
+ role: "dialog",
13302
+ onMouseEnter: trigger === "hover" ? handleOpen : void 0,
13303
+ onMouseLeave: trigger === "hover" ? handleClose : void 0,
13304
+ children: [
13305
+ typeof content === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: content }) : content,
13306
+ showArrow && /* @__PURE__ */ jsxRuntime.jsx(
13307
+ "div",
13308
+ {
13309
+ className: cn(
13310
+ "absolute w-0 h-0 border-4",
13311
+ arrowClasses2[position]
13312
+ )
13313
+ }
13314
+ )
13315
+ ]
13316
+ }
13317
+ ) : null;
13290
13318
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13291
13319
  triggerElement,
13292
- isOpen && triggerRect && /* @__PURE__ */ jsxRuntime.jsxs(
13293
- "div",
13294
- {
13295
- ref: popoverRef,
13296
- className: cn(
13297
- "fixed z-50 p-4",
13298
- "bg-card border-2 border-border shadow-lg",
13299
- positionClasses2[position],
13300
- className
13301
- ),
13302
- style: computePopoverStyle(position, triggerRect, popoverWidth),
13303
- role: "dialog",
13304
- onMouseEnter: trigger === "hover" ? handleOpen : void 0,
13305
- onMouseLeave: trigger === "hover" ? handleClose : void 0,
13306
- children: [
13307
- typeof content === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: content }) : content,
13308
- showArrow && /* @__PURE__ */ jsxRuntime.jsx(
13309
- "div",
13310
- {
13311
- className: cn(
13312
- "absolute w-0 h-0 border-4",
13313
- arrowClasses2[position]
13314
- )
13315
- }
13316
- )
13317
- ]
13318
- }
13319
- )
13320
+ panel && typeof document !== "undefined" ? reactDom.createPortal(panel, document.body) : panel
13320
13321
  ] });
13321
13322
  };
13322
13323
  Popover.displayName = "Popover";
@@ -51039,6 +51040,22 @@ function zoomReducer(state, action) {
51039
51040
  selectedTransition: action.transitionIndex
51040
51041
  };
51041
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
+ }
51042
51059
  case "ZOOM_OUT": {
51043
51060
  if (state.level === "application" || state.animating) return state;
51044
51061
  return {
@@ -51071,7 +51088,8 @@ function zoomReducer(state, action) {
51071
51088
  if (state.level === "trait") {
51072
51089
  return {
51073
51090
  ...state,
51074
- level: "orbital",
51091
+ level: "application",
51092
+ selectedOrbital: null,
51075
51093
  selectedTrait: null,
51076
51094
  animating: false,
51077
51095
  animationTarget: null
@@ -57463,8 +57481,8 @@ function isBackwardTransition(from, to, states) {
57463
57481
  if (fromIdx === -1 || toIdx === -1) return false;
57464
57482
  return toIdx < fromIdx;
57465
57483
  }
57466
- function findCrossLinks(orbitals) {
57467
- const links = [];
57484
+ function extractTraitWires(orbitals, scope) {
57485
+ const wires = [];
57468
57486
  const emitters = [];
57469
57487
  const listeners6 = [];
57470
57488
  for (const orb of orbitals) {
@@ -57480,11 +57498,14 @@ function findCrossLinks(orbitals) {
57480
57498
  const seen = /* @__PURE__ */ new Set();
57481
57499
  for (const em of emitters) {
57482
57500
  for (const li of listeners6) {
57483
- if (em.event !== li.event || em.orbital === li.orbital) continue;
57484
- 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}`;
57485
57506
  if (seen.has(key)) continue;
57486
57507
  seen.add(key);
57487
- links.push({
57508
+ wires.push({
57488
57509
  emitterOrbital: em.orbital,
57489
57510
  listenerOrbital: li.orbital,
57490
57511
  event: em.event,
@@ -57493,7 +57514,10 @@ function findCrossLinks(orbitals) {
57493
57514
  });
57494
57515
  }
57495
57516
  }
57496
- return links;
57517
+ return wires;
57518
+ }
57519
+ function findCrossLinks(orbitals) {
57520
+ return extractTraitWires(orbitals, "cross-orbital");
57497
57521
  }
57498
57522
  function schemaToOverviewGraph(schema, mockData, behaviorMeta, layoutHint, orbitalStatus) {
57499
57523
  const orbitals = getOrbitals(schema);
@@ -57793,6 +57817,66 @@ function orbitalAliasToExpandedGraph(schema, orbitalName, alias, mockData) {
57793
57817
  mockData
57794
57818
  );
57795
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
+ }
57796
57880
 
57797
57881
  // components/molecules/avl/OrbPreviewNode.tsx
57798
57882
  init_Box();
@@ -61831,11 +61915,104 @@ function TokenRow({ group, tokenKey, value, isColor, onPropChange }) {
61831
61915
  // components/organisms/avl/FlowCanvas.tsx
61832
61916
  init_Box();
61833
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
61834
62010
  init_useEventBus();
61835
62011
  var flowCanvasLog = logger.createLogger("almadar:ui:flow-canvas");
61836
62012
  var NODE_TYPES = {
61837
62013
  preview: OrbPreviewNode,
61838
- behaviorCompose: BehaviorComposeNode
62014
+ behaviorCompose: BehaviorComposeNode,
62015
+ traitCard: TraitCardNode
61839
62016
  };
61840
62017
  flowCanvasLog.debug("node-type-registry", () => ({
61841
62018
  registered: Object.keys(NODE_TYPES),
@@ -61876,7 +62053,8 @@ function FlowCanvasInner({
61876
62053
  }) {
61877
62054
  const NODE_TYPES2 = React96.useMemo(() => ({
61878
62055
  preview: OrbPreviewNode,
61879
- behaviorCompose: BehaviorComposeNode
62056
+ behaviorCompose: BehaviorComposeNode,
62057
+ traitCard: TraitCardNode
61880
62058
  }), []);
61881
62059
  const EDGE_TYPES_LOCAL = React96.useMemo(() => ({
61882
62060
  eventFlow: EventFlowEdge
@@ -61924,17 +62102,19 @@ function FlowCanvasInner({
61924
62102
  }
61925
62103
  }), [selectedPattern]);
61926
62104
  const [atBehaviorLevel, setAtBehaviorLevel] = React96.useState(composeLevel === "behavior");
61927
- 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(() => {
61928
62106
  const t = perfStart("compose-graph");
61929
62107
  const compose = composeLevel === "behavior" && behaviorEntries?.length ? behaviorsToComposeGraph(behaviorEntries, behaviorWires ?? [], layoutHint) : { nodes: [], edges: [] };
61930
62108
  const overview = schemaToOverviewGraph(parsedSchema, mockData, behaviorMeta, layoutHint, orbitalStatus);
61931
62109
  const expanded = expandedOrbital ? orbitalToExpandedGraph(parsedSchema, expandedOrbital, mockData) : { nodes: [], edges: [] };
61932
62110
  const behaviorExpanded = expandedOrbital && expandedBehaviorAlias ? orbitalAliasToExpandedGraph(parsedSchema, expandedOrbital, expandedBehaviorAlias, mockData) : { nodes: [], edges: [] };
62111
+ const traitExpanded = expandedOrbital ? orbitalToTraitGraph(parsedSchema, expandedOrbital) : { nodes: [], edges: [] };
61933
62112
  perfEnd("compose-graph", t, {
61934
62113
  composeNodes: compose.nodes.length,
61935
62114
  overviewNodes: overview.nodes.length,
61936
62115
  expandedNodes: expanded.nodes.length,
61937
62116
  behaviorExpandedNodes: behaviorExpanded.nodes.length,
62117
+ traitExpandedNodes: traitExpanded.nodes.length,
61938
62118
  orbitalCount: parsedSchema.orbitals?.length ?? 0
61939
62119
  });
61940
62120
  return {
@@ -61945,11 +62125,13 @@ function FlowCanvasInner({
61945
62125
  expandedNodes: expanded.nodes,
61946
62126
  expandedEdges: expanded.edges,
61947
62127
  behaviorExpandedNodes: behaviorExpanded.nodes,
61948
- behaviorExpandedEdges: behaviorExpanded.edges
62128
+ behaviorExpandedEdges: behaviorExpanded.edges,
62129
+ traitExpandedNodes: traitExpanded.nodes,
62130
+ traitExpandedEdges: traitExpanded.edges
61949
62131
  };
61950
62132
  }, [parsedSchema, expandedOrbital, expandedBehaviorAlias, behaviorMeta, layoutHint, composeLevel, behaviorEntries, behaviorWires, mockData, orbitalStatus]);
61951
- const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : level === "behavior-expanded" ? behaviorExpandedNodes : expandedNodes;
61952
- 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;
61953
62135
  const [nodes, setNodes, onNodesChange] = react.useNodesState(activeNodes);
61954
62136
  const [edges, setEdges, onEdgesChange] = react.useEdgesState(activeEdges);
61955
62137
  const reactFlow = react.useReactFlow();
@@ -62106,7 +62288,17 @@ function FlowCanvasInner({
62106
62288
  });
62107
62289
  }, [nodes, onEventWire, eventBus]);
62108
62290
  const screenSizeKeys = ["mobile", "tablet", "laptop", "wide"];
62109
- 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(
62110
62302
  Box,
62111
62303
  {
62112
62304
  className: `flex h-full ${className ?? ""}`,
@@ -62224,7 +62416,7 @@ function FlowCanvasInner({
62224
62416
  ] })
62225
62417
  ]
62226
62418
  }
62227
- ) }) });
62419
+ ) }) }) });
62228
62420
  }
62229
62421
  var FlowCanvas = (props) => {
62230
62422
  return /* @__PURE__ */ jsxRuntime.jsx(React96.Profiler, { id: "flow-canvas", onRender: profilerOnRender, children: /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(FlowCanvasInner, { ...props }) }) });
@@ -62348,122 +62540,6 @@ AvlCosmicZoom.displayName = "AvlCosmicZoom";
62348
62540
  init_avl_schema_parser();
62349
62541
  init_avl_zoom_state();
62350
62542
 
62351
- // components/organisms/avl/AvlTraitScene.tsx
62352
- init_AvlState();
62353
- init_AvlTransitionLane();
62354
- init_AvlSwimLane();
62355
- init_types();
62356
- init_avl_elk_layout();
62357
- var log19 = logger.createLogger("almadar:ui:avl:trait-scene");
62358
- var SWIM_GUTTER2 = 120;
62359
- var CENTER_W2 = 360;
62360
- var AvlTraitScene = ({
62361
- data,
62362
- color = "var(--color-primary)",
62363
- onTransitionClick
62364
- }) => {
62365
- const [layout, setLayout] = React96.useState(null);
62366
- const dataKey = React96.useMemo(() => JSON.stringify(data), [data]);
62367
- React96.useEffect(() => {
62368
- computeTraitLayout(data).then(setLayout).catch((error) => {
62369
- log19.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
62370
- });
62371
- }, [dataKey]);
62372
- if (!layout) {
62373
- 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..." }) });
62374
- }
62375
- const hasExternal = data.listenedEvents.length > 0 || data.emittedEvents.length > 0;
62376
- const machineOffsetX = hasExternal ? 0 : 30;
62377
- const padding = 20;
62378
- const availW = CENTER_W2 - padding * 2;
62379
- const availH = 300;
62380
- const scale = Math.min(1, availW / layout.width, availH / layout.height);
62381
- const scaledW = layout.width * scale;
62382
- const scaledH = layout.height * scale;
62383
- const offsetX = padding + (availW - scaledW) / 2;
62384
- const offsetY = 50 + (availH - scaledH) / 2;
62385
- const machineHeight = scaledH + 100;
62386
- const renderMachine = /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
62387
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: CENTER_W2 / 2, y: 20, textAnchor: "middle", fill: color, fontSize: 20, fontWeight: "700", fontFamily: "inherit", children: data.name }),
62388
- /* @__PURE__ */ jsxRuntime.jsxs("text", { x: CENTER_W2 / 2, y: 38, textAnchor: "middle", fill: color, fontSize: 11, opacity: 0.5, fontFamily: "inherit", children: [
62389
- "linked to ",
62390
- data.linkedEntity
62391
- ] }),
62392
- /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
62393
- /* @__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 }) }),
62394
- /* @__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 }) })
62395
- ] }),
62396
- /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${offsetX},${offsetY}) scale(${scale})`, children: [
62397
- layout.edges.map((edge) => {
62398
- const conn = edge.isSelf ? exports.CONNECTION_COLORS.selfLoop : edge.isBackward ? exports.CONNECTION_COLORS.backward : exports.CONNECTION_COLORS.forward;
62399
- const marker = edge.isBackward || edge.isSelf ? "url(#traitArrowBack)" : "url(#traitArrowV2)";
62400
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
62401
- /* @__PURE__ */ jsxRuntime.jsx(
62402
- "path",
62403
- {
62404
- d: edgePath(edge.points),
62405
- fill: "none",
62406
- stroke: conn.color,
62407
- strokeWidth: conn.width,
62408
- strokeDasharray: conn.dash === "none" ? void 0 : conn.dash,
62409
- opacity: 0.5,
62410
- markerEnd: marker
62411
- }
62412
- ),
62413
- /* @__PURE__ */ jsxRuntime.jsx(
62414
- exports.AvlTransitionLane,
62415
- {
62416
- x: edge.labelX,
62417
- y: edge.labelY,
62418
- event: edge.event,
62419
- guard: edge.guardExpr,
62420
- effects: edge.effects.map((e) => ({ type: e.type })),
62421
- width: edge.labelW,
62422
- isBackward: edge.isBackward,
62423
- isSelfLoop: edge.isSelf,
62424
- color,
62425
- onTransitionClick: onTransitionClick ? () => onTransitionClick(edge.index, {
62426
- x: edge.labelX + offsetX + (hasExternal ? SWIM_GUTTER2 : machineOffsetX),
62427
- y: edge.labelY + offsetY
62428
- }) : void 0
62429
- }
62430
- )
62431
- ] }, edge.id);
62432
- }),
62433
- layout.nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx(
62434
- exports.AvlState,
62435
- {
62436
- x: node.x,
62437
- y: node.y,
62438
- width: node.width,
62439
- height: node.height,
62440
- name: node.id,
62441
- isInitial: node.isInitial,
62442
- isTerminal: node.isTerminal,
62443
- role: node.role,
62444
- transitionCount: node.transitionCount,
62445
- color
62446
- }
62447
- ) }, node.id))
62448
- ] })
62449
- ] });
62450
- if (!hasExternal) {
62451
- return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${machineOffsetX}, 0)`, children: renderMachine });
62452
- }
62453
- return /* @__PURE__ */ jsxRuntime.jsx(
62454
- exports.AvlSwimLane,
62455
- {
62456
- listenedEvents: data.listenedEvents,
62457
- emittedEvents: data.emittedEvents,
62458
- centerWidth: CENTER_W2,
62459
- height: machineHeight,
62460
- color,
62461
- children: renderMachine
62462
- }
62463
- );
62464
- };
62465
- AvlTraitScene.displayName = "AvlTraitScene";
62466
-
62467
62543
  // components/organisms/avl/AvlTransitionScene.tsx
62468
62544
  init_AvlEffect();
62469
62545
  init_types();
@@ -62950,26 +63026,34 @@ var AvlOrbitalsCosmicZoom = ({
62950
63026
  if (!highlightedOrbital) return;
62951
63027
  if (drilledForHighlightRef.current) return;
62952
63028
  drilledForHighlightRef.current = true;
62953
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: highlightedOrbital, targetPosition: { x: 0, y: 0 } });
62954
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63029
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: highlightedOrbital });
62955
63030
  }, [highlightedOrbital]);
62956
63031
  const breadcrumbs = React96.useMemo(() => getBreadcrumbs(state), [state]);
62957
63032
  const handleSelect = React96.useCallback(
62958
63033
  (name) => {
62959
- dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
62960
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
63034
+ dispatch({ type: "JUMP_TO_TRAIT_CIRCUIT", orbital: name });
62961
63035
  onOrbitalSelect?.(name);
62962
63036
  },
62963
63037
  [onOrbitalSelect]
62964
63038
  );
62965
- const handleTraitSelect = React96.useCallback((traitName) => {
62966
- dispatch({ type: "ZOOM_INTO_TRAIT", trait: traitName, targetPosition: { x: 0, y: 0 } });
62967
- Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62968
- }, []);
62969
- const handleTransitionSelect = React96.useCallback((transitionIndex) => {
63039
+ React96.useCallback((transitionIndex) => {
62970
63040
  dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex, targetPosition: { x: 0, y: 0 } });
62971
63041
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
62972
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
+ );
62973
63057
  const handleZoomOut = React96.useCallback(() => {
62974
63058
  dispatch({ type: "ZOOM_OUT" });
62975
63059
  Promise.resolve().then(() => dispatch({ type: "ANIMATION_COMPLETE" }));
@@ -62992,14 +63076,6 @@ var AvlOrbitalsCosmicZoom = ({
62992
63076
  window.addEventListener("keydown", onKey);
62993
63077
  return () => window.removeEventListener("keydown", onKey);
62994
63078
  }, [handleZoomOut, state.level]);
62995
- const orbitalLevelData = React96.useMemo(() => {
62996
- if (!state.selectedOrbital) return null;
62997
- return parseOrbitalLevel(parsedSchema, state.selectedOrbital);
62998
- }, [parsedSchema, state.selectedOrbital]);
62999
- const traitLevelData = React96.useMemo(() => {
63000
- if (!state.selectedOrbital || !state.selectedTrait) return null;
63001
- return parseTraitLevel(parsedSchema, state.selectedOrbital, state.selectedTrait);
63002
- }, [parsedSchema, state.selectedOrbital, state.selectedTrait]);
63003
63079
  const transitionLevelData = React96.useMemo(() => {
63004
63080
  if (!state.selectedOrbital || !state.selectedTrait || state.selectedTransition === null) return null;
63005
63081
  return parseTransitionLevel(
@@ -63009,6 +63085,12 @@ var AvlOrbitalsCosmicZoom = ({
63009
63085
  state.selectedTransition
63010
63086
  );
63011
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]);
63012
63094
  const [zoom, setZoom] = React96.useState(1);
63013
63095
  const [pan, setPan] = React96.useState({ x: 0, y: 0 });
63014
63096
  const dragStateRef = React96.useRef(null);
@@ -63056,6 +63138,7 @@ var AvlOrbitalsCosmicZoom = ({
63056
63138
  zoomRef.current = zoom;
63057
63139
  }, [zoom]);
63058
63140
  React96.useEffect(() => {
63141
+ if (state.level !== "application") return;
63059
63142
  const wrapper = transformWrapperRef.current;
63060
63143
  if (!wrapper) return;
63061
63144
  const wheelListener = (e) => {
@@ -63246,81 +63329,7 @@ var AvlOrbitalsCosmicZoom = ({
63246
63329
  }
63247
63330
  )
63248
63331
  ] }),
63249
- state.level === "orbital" && orbitalLevelData && /* @__PURE__ */ jsxRuntime.jsxs(
63250
- Box,
63251
- {
63252
- position: "absolute",
63253
- style: {
63254
- inset: 0,
63255
- paddingTop: 56,
63256
- paddingBottom: 24,
63257
- paddingLeft: 24,
63258
- paddingRight: 24,
63259
- display: "flex",
63260
- alignItems: "stretch",
63261
- justifyContent: "center",
63262
- gap: 24
63263
- },
63264
- children: [
63265
- /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { flex: 1, maxWidth: 720, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(
63266
- AvlOrbitalUnit,
63267
- {
63268
- entityName: orbitalLevelData.entity.name,
63269
- fields: orbitalLevelData.entity.fields.length,
63270
- persistence: orbitalLevelData.entity.persistence || "persistent",
63271
- traits: orbitalLevelData.traits.map((t) => ({ name: t.name })),
63272
- pages: orbitalLevelData.pages.map((p2) => ({ name: p2.name })),
63273
- color,
63274
- animated
63275
- }
63276
- ) }),
63277
- /* @__PURE__ */ jsxRuntime.jsxs(
63278
- Box,
63279
- {
63280
- style: {
63281
- width: 220,
63282
- padding: 12,
63283
- display: "flex",
63284
- flexDirection: "column",
63285
- gap: 8,
63286
- borderLeft: `1px solid ${color}`,
63287
- opacity: 0.95,
63288
- overflowY: "auto",
63289
- minHeight: 0
63290
- },
63291
- children: [
63292
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginBottom: 4 }, children: [
63293
- "Traits (",
63294
- orbitalLevelData.traits.length,
63295
- ")"
63296
- ] }),
63297
- orbitalLevelData.traits.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(Text, { variant: "small", style: { opacity: 0.6, color }, children: "No traits" }),
63298
- orbitalLevelData.traits.map((trait) => /* @__PURE__ */ jsxRuntime.jsx(
63299
- Button,
63300
- {
63301
- variant: "ghost",
63302
- size: "sm",
63303
- onClick: () => handleTraitSelect(trait.name),
63304
- action: "COSMIC_DRILL_TRAIT",
63305
- children: trait.name
63306
- },
63307
- trait.name
63308
- )),
63309
- orbitalLevelData.pages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63310
- /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "semibold", style: { color, marginTop: 12 }, children: [
63311
- "Pages (",
63312
- orbitalLevelData.pages.length,
63313
- ")"
63314
- ] }),
63315
- orbitalLevelData.pages.map((page) => /* @__PURE__ */ jsxRuntime.jsx(Text, { variant: "small", style: { opacity: 0.7, color }, children: page.name }, page.name))
63316
- ] })
63317
- ]
63318
- }
63319
- )
63320
- ]
63321
- }
63322
- ),
63323
- state.level === "trait" && traitLevelData && /* @__PURE__ */ jsxRuntime.jsx(
63332
+ state.level === "trait" && scopedSchema && state.selectedOrbital && /* @__PURE__ */ jsxRuntime.jsx(
63324
63333
  Box,
63325
63334
  {
63326
63335
  position: "absolute",
@@ -63332,39 +63341,14 @@ var AvlOrbitalsCosmicZoom = ({
63332
63341
  paddingRight: 24
63333
63342
  },
63334
63343
  children: /* @__PURE__ */ jsxRuntime.jsx(
63335
- Box,
63344
+ FlowCanvas,
63336
63345
  {
63337
- ref: transformWrapperRef,
63338
- position: "relative",
63339
- onPointerDown: handlePointerDown,
63340
- onPointerMove: handlePointerMove,
63341
- onPointerUp: handlePointerUp,
63342
- onPointerCancel: handlePointerUp,
63343
- style: {
63344
- width: "100%",
63345
- height: "100%",
63346
- cursor: dragStateRef.current ? "grabbing" : "grab",
63347
- overflow: "hidden"
63348
- },
63349
- children: /* @__PURE__ */ jsxRuntime.jsx(
63350
- Box,
63351
- {
63352
- position: "absolute",
63353
- style: {
63354
- inset: 0,
63355
- transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
63356
- transformOrigin: "0 0"
63357
- },
63358
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 600 400", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
63359
- AvlTraitScene,
63360
- {
63361
- data: traitLevelData,
63362
- color,
63363
- onTransitionClick: (idx) => handleTransitionSelect(idx)
63364
- }
63365
- ) })
63366
- }
63367
- )
63346
+ schema: scopedSchema,
63347
+ initialLevel: "trait-expanded",
63348
+ initialOrbital: state.selectedOrbital,
63349
+ onNodeClick: handleCanvasNodeClick,
63350
+ width: "100%",
63351
+ height: "100%"
63368
63352
  }
63369
63353
  )
63370
63354
  }
@@ -63417,7 +63401,7 @@ var AvlOrbitalsCosmicZoom = ({
63417
63401
  )
63418
63402
  }
63419
63403
  ),
63420
- (state.level === "trait" || state.level === "transition") && /* @__PURE__ */ jsxRuntime.jsxs(
63404
+ state.level === "transition" && /* @__PURE__ */ jsxRuntime.jsxs(
63421
63405
  Box,
63422
63406
  {
63423
63407
  position: "absolute",
@@ -63441,6 +63425,122 @@ var AvlOrbitalsCosmicZoom = ({
63441
63425
  );
63442
63426
  };
63443
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";
63444
63544
  var AvlClickTarget = ({
63445
63545
  x,
63446
63546
  y,