@almadar/ui 2.45.0 → 2.46.1

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