@almadar/ui 2.45.0 → 2.46.0

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.
@@ -12877,12 +12877,12 @@ function findCrossLinks(orbitals) {
12877
12877
  }
12878
12878
  return links;
12879
12879
  }
12880
- function schemaToOverviewGraph(schema, mockData) {
12880
+ function schemaToOverviewGraph(schema, mockData, behaviorMeta, layoutHint) {
12881
12881
  const orbitals = getOrbitals(schema);
12882
12882
  const nodes = [];
12883
12883
  const edges = [];
12884
12884
  const count = orbitals.length;
12885
- const cols = Math.ceil(Math.sqrt(count));
12885
+ const cols = layoutHint === "pipeline" ? count : Math.ceil(Math.sqrt(count));
12886
12886
  for (let i = 0; i < orbitals.length; i++) {
12887
12887
  const orb = orbitals[i];
12888
12888
  const entityInfo = getEntityInfo(orb);
@@ -12921,6 +12921,22 @@ function schemaToOverviewGraph(schema, mockData) {
12921
12921
  }
12922
12922
  }
12923
12923
  const eventSources = collectEventSources(initPatterns);
12924
+ for (const source of eventSources) {
12925
+ for (const trait of traits2) {
12926
+ const sm = getStateMachine2(trait);
12927
+ if (!sm) continue;
12928
+ const smEvents = trait.stateMachine?.events ?? [];
12929
+ const matchingEvent = smEvents.find((ev) => ev.key === source.event);
12930
+ if (matchingEvent?.payload && Array.isArray(matchingEvent.payload)) {
12931
+ source.payloadFields = matchingEvent.payload.map((p2) => ({
12932
+ name: String(p2.name ?? ""),
12933
+ type: String(p2.type ?? "string"),
12934
+ ...p2.required ? { required: true } : {}
12935
+ }));
12936
+ break;
12937
+ }
12938
+ }
12939
+ }
12924
12940
  const col = i % cols;
12925
12941
  const row = Math.floor(i / cols);
12926
12942
  nodes.push({
@@ -12932,6 +12948,7 @@ function schemaToOverviewGraph(schema, mockData) {
12932
12948
  patterns: initPatterns,
12933
12949
  eventSources,
12934
12950
  effectTypes: initEffectTypes,
12951
+ layer: behaviorMeta?.[orb.name]?.layer,
12935
12952
  stateRole: "initial",
12936
12953
  entityName: entityInfo.name,
12937
12954
  persistence: entityInfo.persistence,
@@ -47194,6 +47211,43 @@ OrbPreview.displayName = "OrbPreview";
47194
47211
 
47195
47212
  // components/molecules/avl/OrbPreviewNode.tsx
47196
47213
  init_useEventBus();
47214
+
47215
+ // components/molecules/avl/wire-validation.ts
47216
+ function validateWire(sourcePayload, targetPayload) {
47217
+ const warnings = [];
47218
+ if (!sourcePayload?.length && !targetPayload?.length) {
47219
+ return { valid: true, warnings };
47220
+ }
47221
+ if (sourcePayload?.length && !targetPayload?.length) {
47222
+ return { valid: true, warnings };
47223
+ }
47224
+ if (!sourcePayload?.length && targetPayload?.length) {
47225
+ const requiredFields = targetPayload.filter((f3) => f3.required);
47226
+ if (requiredFields.length > 0) {
47227
+ warnings.push(`Missing required fields: ${requiredFields.map((f3) => f3.name).join(", ")}`);
47228
+ }
47229
+ return { valid: warnings.length === 0, warnings };
47230
+ }
47231
+ const sourceFields = new Map(sourcePayload.map((f3) => [f3.name, f3]));
47232
+ for (const targetField of targetPayload) {
47233
+ const sourceField = sourceFields.get(targetField.name);
47234
+ if (!sourceField) {
47235
+ if (targetField.required) {
47236
+ warnings.push(`Missing required field: ${targetField.name} (${targetField.type})`);
47237
+ }
47238
+ } else if (sourceField.type !== targetField.type) {
47239
+ warnings.push(`Type mismatch: ${targetField.name} (source: ${sourceField.type}, target: ${targetField.type})`);
47240
+ }
47241
+ }
47242
+ return { valid: warnings.length === 0, warnings };
47243
+ }
47244
+ function formatPayloadTooltip(fields) {
47245
+ if (fields.length === 0) return "";
47246
+ const parts = fields.map(
47247
+ (f3) => `${f3.name}: ${f3.type}${f3.required ? " (req)" : ""}`
47248
+ );
47249
+ return `{ ${parts.join(", ")} }`;
47250
+ }
47197
47251
  var ScreenSizeContext = React125.createContext("tablet");
47198
47252
  var PatternSelectionContext = React125.createContext({ selected: null, select: () => {
47199
47253
  } });
@@ -47204,6 +47258,15 @@ var ROLE_COLORS = {
47204
47258
  error: { border: "#D97706", dot: "#F59E0B" },
47205
47259
  default: { border: "var(--color-border)", dot: "#6B7280" }
47206
47260
  };
47261
+ var LAYER_COLORS = {
47262
+ Infrastructure: "#3B82F6",
47263
+ Services: "#F59E0B",
47264
+ "UI Patterns": "#8B5CF6",
47265
+ Game: "#22C55E",
47266
+ ML: "#EC4899",
47267
+ Domain: "#6366F1",
47268
+ Community: "#6B7280"
47269
+ };
47207
47270
  var TARGET_HANDLE_STYLE = {
47208
47271
  background: "var(--color-primary)",
47209
47272
  width: 8,
@@ -47306,6 +47369,7 @@ var OrbPreviewNodeInner = (props) => {
47306
47369
  const role = data.stateRole ?? "default";
47307
47370
  const colors = ROLE_COLORS[role] ?? ROLE_COLORS.default;
47308
47371
  const eventSources = data.eventSources ?? [];
47372
+ const layerColor = data.layer ? LAYER_COLORS[data.layer] : void 0;
47309
47373
  const isExpanded = Boolean(data.traitName);
47310
47374
  const label = isExpanded ? `${data.transitionEvent ?? ""}` : data.orbitalName;
47311
47375
  const sublabel = isExpanded ? `${data.fromState ?? ""} \u2192 ${data.toState ?? ""}` : data.entityName ?? "";
@@ -47447,6 +47511,13 @@ var OrbPreviewNodeInner = (props) => {
47447
47511
  onMouseLeave: handleMouseLeave,
47448
47512
  children: [
47449
47513
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: SELECTION_STYLES }),
47514
+ layerColor && /* @__PURE__ */ jsxRuntime.jsx(
47515
+ Box,
47516
+ {
47517
+ style: { height: 3, backgroundColor: layerColor },
47518
+ title: data.layer
47519
+ }
47520
+ ),
47450
47521
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 px-3 py-1.5 border-b border-border/40 drag-handle cursor-grab", children: [
47451
47522
  /* @__PURE__ */ jsxRuntime.jsx(
47452
47523
  Box,
@@ -47468,7 +47539,7 @@ var OrbPreviewNodeInner = (props) => {
47468
47539
  color: "#F97316",
47469
47540
  border: "1px solid #F9731630"
47470
47541
  },
47471
- title: `${src.label ?? src.patternType} \u2192 ${src.event}`,
47542
+ title: `${src.label ?? src.patternType} \u2192 ${src.event}${src.payloadFields?.length ? ` ${formatPayloadTooltip(src.payloadFields)}` : ""}`,
47472
47543
  children: src.label ?? src.event
47473
47544
  },
47474
47545
  src.event
@@ -47502,7 +47573,7 @@ var OrbPreviewNodeInner = (props) => {
47502
47573
  type: "source",
47503
47574
  position: react.Position.Right,
47504
47575
  style: eventHandleStyle(src),
47505
- title: `${src.label ?? src.patternType}: ${src.event}`
47576
+ title: `${src.label ?? src.patternType}: ${src.event}${src.payloadFields?.length ? ` ${formatPayloadTooltip(src.payloadFields)}` : ""}`
47506
47577
  },
47507
47578
  `event-${src.event}`
47508
47579
  ))
@@ -47590,6 +47661,211 @@ var EventFlowEdgeInner = (props) => {
47590
47661
  var EventFlowEdge = React125__namespace.default.memo(EventFlowEdgeInner);
47591
47662
  EventFlowEdge.displayName = "EventFlowEdge";
47592
47663
 
47664
+ // components/molecules/avl/BehaviorComposeNode.tsx
47665
+ init_Box();
47666
+ init_Typography();
47667
+ var LAYER_COLORS2 = {
47668
+ Infrastructure: "#3B82F6",
47669
+ Services: "#F59E0B",
47670
+ "UI Patterns": "#8B5CF6",
47671
+ Game: "#22C55E",
47672
+ ML: "#EC4899",
47673
+ Domain: "#6366F1",
47674
+ Community: "#6B7280"
47675
+ };
47676
+ var NODE_WIDTH = 220;
47677
+ var TARGET_HANDLE_STYLE2 = {
47678
+ background: "var(--color-primary)",
47679
+ width: 8,
47680
+ height: 8,
47681
+ border: "2px solid var(--color-card)"
47682
+ };
47683
+ function eventHandleStyle2(source) {
47684
+ return {
47685
+ background: "#F97316",
47686
+ width: 10,
47687
+ height: 10,
47688
+ border: "2px solid var(--color-card)",
47689
+ top: `${source.positionHint * 100}%`,
47690
+ right: -5
47691
+ };
47692
+ }
47693
+ var BehaviorComposeNodeInner = (props) => {
47694
+ const data = props.data;
47695
+ const [hovered, setHovered] = React125.useState(false);
47696
+ const handleMouseEnter = React125.useCallback(() => setHovered(true), []);
47697
+ const handleMouseLeave = React125.useCallback(() => setHovered(false), []);
47698
+ const layerColor = data.layer ? LAYER_COLORS2[data.layer] : void 0;
47699
+ const connectableEvents = data.connectableEvents ?? [];
47700
+ return /* @__PURE__ */ jsxRuntime.jsxs(
47701
+ Box,
47702
+ {
47703
+ className: "rounded-lg border shadow-sm bg-card transition-all duration-200 overflow-hidden",
47704
+ style: {
47705
+ borderColor: hovered ? "var(--color-primary)" : "var(--color-border)",
47706
+ borderWidth: "1.5px",
47707
+ width: NODE_WIDTH
47708
+ },
47709
+ onMouseEnter: handleMouseEnter,
47710
+ onMouseLeave: handleMouseLeave,
47711
+ children: [
47712
+ layerColor && /* @__PURE__ */ jsxRuntime.jsx(
47713
+ Box,
47714
+ {
47715
+ style: { height: 3, backgroundColor: layerColor },
47716
+ title: data.layer
47717
+ }
47718
+ ),
47719
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 px-3 py-1.5 border-b border-border/40 drag-handle cursor-grab", children: [
47720
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col min-w-0 flex-1", children: [
47721
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-semibold truncate leading-tight text-[12px]", children: data.behaviorName }),
47722
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground truncate text-[10px] leading-tight", children: data.entityName })
47723
+ ] }),
47724
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "neutral", className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-[9px] text-inherit", children: data.level }) })
47725
+ ] }),
47726
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
47727
+ AvlBehaviorGlyph,
47728
+ {
47729
+ name: data.behaviorName,
47730
+ level: data.level,
47731
+ domain: data.domain,
47732
+ stateCount: data.stateCount,
47733
+ fieldCount: data.fieldCount,
47734
+ persistence: data.persistence,
47735
+ effectTypes: data.effectTypes,
47736
+ children: data.children,
47737
+ connections: data.connections,
47738
+ size: "sm",
47739
+ showLabels: false
47740
+ }
47741
+ ) }),
47742
+ connectableEvents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-wrap gap-0.5 px-2 pb-2", children: [
47743
+ connectableEvents.slice(0, 4).map((ev) => /* @__PURE__ */ jsxRuntime.jsx(
47744
+ Box,
47745
+ {
47746
+ className: "rounded-full px-1.5 py-0 text-[8px] font-medium leading-tight",
47747
+ style: {
47748
+ backgroundColor: "#F9731615",
47749
+ color: "#F97316",
47750
+ border: "1px solid #F9731630"
47751
+ },
47752
+ title: `${ev.event}${ev.payloadFields?.length ? ` ${formatPayloadTooltip(ev.payloadFields)}` : ""}`,
47753
+ children: ev.event
47754
+ },
47755
+ ev.event
47756
+ )),
47757
+ connectableEvents.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs(
47758
+ Box,
47759
+ {
47760
+ className: "rounded-full px-1.5 py-0 text-[8px] font-medium leading-tight",
47761
+ style: { color: "var(--color-muted-foreground)" },
47762
+ children: [
47763
+ "+",
47764
+ connectableEvents.length - 4
47765
+ ]
47766
+ }
47767
+ )
47768
+ ] }),
47769
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between px-2 pb-1.5", children: [
47770
+ /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "text-muted-foreground text-[9px]", children: [
47771
+ data.stateCount,
47772
+ " states"
47773
+ ] }),
47774
+ data.layer && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "neutral", className: "text-[8px]", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-[8px] text-inherit", children: data.layer }) })
47775
+ ] }),
47776
+ /* @__PURE__ */ jsxRuntime.jsx(
47777
+ react.Handle,
47778
+ {
47779
+ type: "target",
47780
+ position: react.Position.Left,
47781
+ style: TARGET_HANDLE_STYLE2
47782
+ }
47783
+ ),
47784
+ connectableEvents.map((ev) => /* @__PURE__ */ jsxRuntime.jsx(
47785
+ react.Handle,
47786
+ {
47787
+ id: `event-${ev.event}`,
47788
+ type: "source",
47789
+ position: react.Position.Right,
47790
+ style: eventHandleStyle2(ev),
47791
+ title: `${ev.event}${ev.payloadFields?.length ? ` ${formatPayloadTooltip(ev.payloadFields)}` : ""}`
47792
+ },
47793
+ `event-${ev.event}`
47794
+ ))
47795
+ ]
47796
+ }
47797
+ );
47798
+ };
47799
+ var BehaviorComposeNode = React125__namespace.default.memo(BehaviorComposeNodeInner);
47800
+ BehaviorComposeNode.displayName = "BehaviorComposeNode";
47801
+
47802
+ // components/molecules/avl/avl-behavior-compose-converter.ts
47803
+ var COMPOSE_SPACING = 320;
47804
+ function behaviorsToComposeGraph(entries, wires, layoutHint) {
47805
+ const nodes = [];
47806
+ const edges = [];
47807
+ const count = entries.length;
47808
+ const cols = layoutHint === "pipeline" ? count : Math.ceil(Math.sqrt(count));
47809
+ for (let i = 0; i < entries.length; i++) {
47810
+ const entry = entries[i];
47811
+ const col = i % cols;
47812
+ const row = Math.floor(i / cols);
47813
+ nodes.push({
47814
+ id: entry.behaviorName,
47815
+ type: "behaviorCompose",
47816
+ position: { x: col * COMPOSE_SPACING, y: row * COMPOSE_SPACING },
47817
+ data: {
47818
+ behaviorName: entry.behaviorName,
47819
+ level: entry.level,
47820
+ domain: entry.domain,
47821
+ layer: entry.layer,
47822
+ entityName: entry.entityName,
47823
+ stateCount: entry.stateCount,
47824
+ fieldCount: entry.fieldCount,
47825
+ persistence: entry.persistence,
47826
+ effectTypes: entry.effectTypes,
47827
+ children: entry.children,
47828
+ connections: entry.connections,
47829
+ connectableEvents: entry.connectableEvents,
47830
+ composableWith: entry.composableWith,
47831
+ orbitalNames: entry.orbitalNames
47832
+ }
47833
+ });
47834
+ }
47835
+ for (const wire of wires) {
47836
+ edges.push({
47837
+ id: `bw-${wire.sourceBehavior}-${wire.targetBehavior}-${wire.event}`,
47838
+ source: wire.sourceBehavior,
47839
+ target: wire.targetBehavior,
47840
+ sourceHandle: `event-${wire.event}`,
47841
+ type: "eventFlow",
47842
+ data: wire
47843
+ });
47844
+ }
47845
+ return { nodes, edges };
47846
+ }
47847
+ function registryEntryToCanvasEntry(entry, orbitalNames) {
47848
+ const events2 = entry.connectableEvents;
47849
+ const connectableEvents = events2.map((eventName, i) => ({
47850
+ event: eventName,
47851
+ payloadFields: entry.eventPayloads[eventName],
47852
+ positionHint: events2.length > 1 ? 0.1 + i * 0.8 / (events2.length - 1) : 0.5
47853
+ }));
47854
+ return {
47855
+ behaviorName: entry.name,
47856
+ level: entry.level,
47857
+ domain: entry.family,
47858
+ layer: entry.layer,
47859
+ entityName: entry.defaultEntity.name,
47860
+ stateCount: entry.complexity.states,
47861
+ fieldCount: entry.defaultEntity.fields.length,
47862
+ persistence: entry.defaultEntity.persistence,
47863
+ connectableEvents,
47864
+ composableWith: entry.composableWith,
47865
+ orbitalNames
47866
+ };
47867
+ }
47868
+
47593
47869
  // components/molecules/avl/index.ts
47594
47870
  init_Avl3DOrbitalNode();
47595
47871
  init_Avl3DCrossWire();
@@ -47702,6 +47978,7 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47702
47978
  const effectTypes = node.effectTypes ?? [];
47703
47979
  const guard = node.guard;
47704
47980
  const isExpanded = Boolean(traitName);
47981
+ const hasRenderUi = effectTypes.includes("render-ui");
47705
47982
  const patternType = selectedPattern?.patternType;
47706
47983
  const patternDef = React125.useMemo(() => patternType ? patterns.getPatternDefinition(patternType) : null, [patternType]);
47707
47984
  const isEntityPattern = patternType ? patterns.isEntityAwarePattern(patternType) : false;
@@ -47901,6 +48178,42 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47901
48178
  }
47902
48179
  )
47903
48180
  ] }),
48181
+ editable && !selectedPattern && !isExpanded && node.layer === "Services" && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
48182
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Service Mode") }),
48183
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "items-center", children: [
48184
+ /* @__PURE__ */ jsxRuntime.jsxs(
48185
+ Button,
48186
+ {
48187
+ variant: hasRenderUi ? "primary" : "ghost",
48188
+ size: "sm",
48189
+ className: "flex-1 text-[11px]",
48190
+ onClick: () => {
48191
+ if (!hasRenderUi) eventBus.emit("UI:SERVICE_MODE_TOGGLE", { orbitalName: node.orbitalName, standalone: true });
48192
+ },
48193
+ children: [
48194
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "monitor", size: "xs", className: "mr-1" }),
48195
+ t("Standalone")
48196
+ ]
48197
+ }
48198
+ ),
48199
+ /* @__PURE__ */ jsxRuntime.jsxs(
48200
+ Button,
48201
+ {
48202
+ variant: hasRenderUi ? "ghost" : "primary",
48203
+ size: "sm",
48204
+ className: "flex-1 text-[11px]",
48205
+ onClick: () => {
48206
+ if (hasRenderUi) eventBus.emit("UI:SERVICE_MODE_TOGGLE", { orbitalName: node.orbitalName, standalone: false });
48207
+ },
48208
+ children: [
48209
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "cpu", size: "xs", className: "mr-1" }),
48210
+ t("Embedded")
48211
+ ]
48212
+ }
48213
+ )
48214
+ ] }),
48215
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] mt-1", children: hasRenderUi ? t("Renders its own UI") : t("Headless, wired to other behaviors") })
48216
+ ] }),
47904
48217
  !selectedPattern && !isExpanded && traits2.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47905
48218
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "Traits" }),
47906
48219
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1", children: traits2.map((t2) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
@@ -48049,8 +48362,10 @@ OrbInspector.displayName = "OrbInspector";
48049
48362
  // components/organisms/avl/FlowCanvas.tsx
48050
48363
  init_Box();
48051
48364
  init_Typography();
48365
+ init_useEventBus();
48052
48366
  var NODE_TYPES = {
48053
- preview: OrbPreviewNode
48367
+ preview: OrbPreviewNode,
48368
+ behaviorCompose: BehaviorComposeNode
48054
48369
  };
48055
48370
  var EDGE_TYPES = {
48056
48371
  eventFlow: EventFlowEdge
@@ -48072,7 +48387,13 @@ function FlowCanvasInner({
48072
48387
  editable,
48073
48388
  onSchemaChange,
48074
48389
  onPatternDelete,
48075
- onEventWire
48390
+ onEventWire,
48391
+ behaviorMeta,
48392
+ layoutHint,
48393
+ onNodeSelect,
48394
+ composeLevel,
48395
+ behaviorEntries,
48396
+ behaviorWires
48076
48397
  }) {
48077
48398
  const parsedSchema = React125.useMemo(() => {
48078
48399
  if (typeof schemaProp === "string") return JSON.parse(schemaProp);
@@ -48094,18 +48415,22 @@ function FlowCanvasInner({
48094
48415
  if (p2) setSelectedNode(p2.nodeData);
48095
48416
  }
48096
48417
  }), [selectedPattern]);
48097
- const { overviewNodes, overviewEdges, expandedNodes, expandedEdges } = React125.useMemo(() => {
48098
- const overview = schemaToOverviewGraph(parsedSchema, mockData);
48418
+ const [atBehaviorLevel, setAtBehaviorLevel] = React125.useState(composeLevel === "behavior");
48419
+ const { composeNodes, composeEdges, overviewNodes, overviewEdges, expandedNodes, expandedEdges } = React125.useMemo(() => {
48420
+ const compose = composeLevel === "behavior" && behaviorEntries?.length ? behaviorsToComposeGraph(behaviorEntries, behaviorWires ?? [], layoutHint) : { nodes: [], edges: [] };
48421
+ const overview = schemaToOverviewGraph(parsedSchema, mockData, behaviorMeta, layoutHint);
48099
48422
  const expanded = expandedOrbital ? orbitalToExpandedGraph(parsedSchema, expandedOrbital, mockData) : { nodes: [], edges: [] };
48100
48423
  return {
48424
+ composeNodes: compose.nodes,
48425
+ composeEdges: compose.edges,
48101
48426
  overviewNodes: overview.nodes,
48102
48427
  overviewEdges: overview.edges,
48103
48428
  expandedNodes: expanded.nodes,
48104
48429
  expandedEdges: expanded.edges
48105
48430
  };
48106
- }, [parsedSchema, expandedOrbital]);
48107
- const activeNodes = level === "overview" ? overviewNodes : expandedNodes;
48108
- const activeEdges = level === "overview" ? overviewEdges : expandedEdges;
48431
+ }, [parsedSchema, expandedOrbital, behaviorMeta, layoutHint, composeLevel, behaviorEntries, behaviorWires]);
48432
+ const activeNodes = atBehaviorLevel && composeNodes.length > 0 ? composeNodes : level === "overview" ? overviewNodes : expandedNodes;
48433
+ const activeEdges = atBehaviorLevel && composeEdges.length > 0 ? composeEdges : level === "overview" ? overviewEdges : expandedEdges;
48109
48434
  const [nodes, setNodes, onNodesChange] = react.useNodesState(activeNodes);
48110
48435
  const [edges, setEdges, onEdgesChange] = react.useEdgesState(activeEdges);
48111
48436
  const reactFlow = react.useReactFlow();
@@ -48117,13 +48442,23 @@ function FlowCanvasInner({
48117
48442
  });
48118
48443
  }, [activeNodes, activeEdges, setNodes, setEdges, reactFlow]);
48119
48444
  const handleNodeDoubleClick = React125.useCallback((_, node) => {
48445
+ if (atBehaviorLevel && composeLevel === "behavior") {
48446
+ const d = node.data;
48447
+ if (d.orbitalNames?.length) {
48448
+ setExpandedOrbital(d.orbitalNames[0]);
48449
+ }
48450
+ setAtBehaviorLevel(false);
48451
+ setLevel("overview");
48452
+ onLevelChange?.("overview", d.behaviorName);
48453
+ return;
48454
+ }
48120
48455
  if (level === "overview") {
48121
48456
  const d = node.data;
48122
48457
  setExpandedOrbital(d.orbitalName ?? node.id);
48123
48458
  setLevel("expanded");
48124
48459
  onLevelChange?.("expanded", d.orbitalName ?? node.id);
48125
48460
  }
48126
- }, [level, onLevelChange]);
48461
+ }, [level, onLevelChange, atBehaviorLevel, composeLevel]);
48127
48462
  const handleNodeClick = React125.useCallback((_, node) => {
48128
48463
  const nodeData = node.data;
48129
48464
  if (level === "expanded") {
@@ -48139,6 +48474,7 @@ function FlowCanvasInner({
48139
48474
  level: "overview",
48140
48475
  orbital: nodeData.orbitalName ?? node.id
48141
48476
  });
48477
+ onNodeSelect?.(nodeData.orbitalName ?? node.id);
48142
48478
  }
48143
48479
  }, [level, expandedOrbital, onNodeClick]);
48144
48480
  const handleClosePanel = React125.useCallback(() => {
@@ -48152,6 +48488,9 @@ function FlowCanvasInner({
48152
48488
  setLevel("overview");
48153
48489
  setExpandedOrbital(void 0);
48154
48490
  onLevelChange?.("overview");
48491
+ } else if (level === "overview" && composeLevel === "behavior" && !atBehaviorLevel) {
48492
+ setAtBehaviorLevel(true);
48493
+ setExpandedOrbital(void 0);
48155
48494
  }
48156
48495
  } else if (e.key === "Delete" || e.key === "Backspace") {
48157
48496
  const target = e.target;
@@ -48174,8 +48513,13 @@ function FlowCanvasInner({
48174
48513
  setExpandedOrbital(void 0);
48175
48514
  setSelectedNode(null);
48176
48515
  onLevelChange?.("overview");
48516
+ } else if (level === "overview" && composeLevel === "behavior" && !atBehaviorLevel) {
48517
+ setAtBehaviorLevel(true);
48518
+ setExpandedOrbital(void 0);
48519
+ setSelectedNode(null);
48177
48520
  }
48178
- }, [level, onLevelChange, selectedNode]);
48521
+ }, [level, onLevelChange, selectedNode, composeLevel, atBehaviorLevel]);
48522
+ const eventBus = useEventBus();
48179
48523
  const handleConnect = React125.useCallback((connection) => {
48180
48524
  if (!connection.sourceHandle?.startsWith("event-") || !onEventWire) return;
48181
48525
  const eventName = connection.sourceHandle.replace("event-", "");
@@ -48184,6 +48528,19 @@ function FlowCanvasInner({
48184
48528
  if (!sourceNode || !targetNode) return;
48185
48529
  const srcData = sourceNode.data;
48186
48530
  const tgtData = targetNode.data;
48531
+ const sourceEventSource = srcData.eventSources?.find((es) => es.event === eventName);
48532
+ const sourcePayload = sourceEventSource?.payloadFields;
48533
+ const targetEventSource = tgtData.eventSources?.find((es) => es.event === eventName);
48534
+ const targetPayload = targetEventSource?.payloadFields;
48535
+ const validation = validateWire(sourcePayload, targetPayload);
48536
+ if (validation.warnings.length > 0) {
48537
+ eventBus.emit("UI:WIRE_VALIDATION_WARNING", {
48538
+ eventName,
48539
+ sourceOrbital: srcData.orbitalName,
48540
+ targetOrbital: tgtData.orbitalName,
48541
+ warnings: validation.warnings
48542
+ });
48543
+ }
48187
48544
  onEventWire({
48188
48545
  eventName,
48189
48546
  sourceOrbital: srcData.orbitalName ?? "",
@@ -48191,7 +48548,7 @@ function FlowCanvasInner({
48191
48548
  sourceTraitName: srcData.traitName,
48192
48549
  targetTraitName: tgtData.traitName
48193
48550
  });
48194
- }, [nodes, onEventWire]);
48551
+ }, [nodes, onEventWire, eventBus]);
48195
48552
  const screenSizeKeys = ["mobile", "tablet", "desktop"];
48196
48553
  return /* @__PURE__ */ jsxRuntime.jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsxRuntime.jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
48197
48554
  Box,
@@ -48878,6 +49235,7 @@ exports.AvlTransition = AvlTransition;
48878
49235
  exports.AvlTransitionEdge = AvlTransitionEdge;
48879
49236
  exports.AvlTransitionLane = AvlTransitionLane;
48880
49237
  exports.AvlTransitionScene = AvlTransitionScene;
49238
+ exports.BehaviorComposeNode = BehaviorComposeNode;
48881
49239
  exports.BehaviorView = BehaviorView;
48882
49240
  exports.DOMAIN_COLORS = DOMAIN_COLORS;
48883
49241
  exports.DetailView = DetailView;
@@ -48893,6 +49251,7 @@ exports.ZoomBandContext = ZoomBandContext;
48893
49251
  exports.ZoomBreadcrumb = ZoomBreadcrumb;
48894
49252
  exports.ZoomLegend = ZoomLegend;
48895
49253
  exports.arcPath = arcPath;
49254
+ exports.behaviorsToComposeGraph = behaviorsToComposeGraph;
48896
49255
  exports.computeTraitLayout = computeTraitLayout;
48897
49256
  exports.computeZoomBand = computeZoomBand;
48898
49257
  exports.curveControlPoint = curveControlPoint;
@@ -48905,6 +49264,7 @@ exports.parseOrbitalLevel = parseOrbitalLevel;
48905
49264
  exports.parseTraitLevel = parseTraitLevel;
48906
49265
  exports.parseTransitionLevel = parseTransitionLevel;
48907
49266
  exports.radialPositions = radialPositions;
49267
+ exports.registryEntryToCanvasEntry = registryEntryToCanvasEntry;
48908
49268
  exports.ringPositions = ringPositions;
48909
49269
  exports.schemaToFlowGraph = schemaToFlowGraph;
48910
49270
  exports.schemaToOverviewGraph = schemaToOverviewGraph;