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