footprint-explainable-ui 0.27.0 → 0.28.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.
package/dist/index.d.cts CHANGED
@@ -731,6 +731,9 @@ interface ExplainableShellProps extends BaseComponentProps {
731
731
  selectedIndex: number;
732
732
  onNodeClick?: (indexOrId: number | string) => void;
733
733
  showStageId?: boolean;
734
+ /** Dependency-cone overlay (chart node id → BFS depth) — painted while
735
+ * the Inspector's Data Trace tab is open. Custom renderers may ignore it. */
736
+ sliceCone?: ReadonlyMap<string, number>;
734
737
  }) => React.ReactNode;
735
738
  /**
736
739
  * When true, render each node's stable `stageId` as a small monospace
@@ -1103,6 +1106,9 @@ interface InspectorPanelProps {
1103
1106
  selectedStageId?: string;
1104
1107
  /** Navigate to a stage when clicking a Data Trace frame. */
1105
1108
  onNavigateToStage?: (runtimeStageId: string) => void;
1109
+ /** Fires when the user switches tabs — lets the shell paint the chart's
1110
+ * dependency cone while the Data Trace tab is open. */
1111
+ onTabChange?: (tab: "state" | "trace") => void;
1106
1112
  }
1107
1113
  declare const InspectorPanel: react.NamedExoticComponent<InspectorPanelProps>;
1108
1114
 
package/dist/index.d.ts CHANGED
@@ -731,6 +731,9 @@ interface ExplainableShellProps extends BaseComponentProps {
731
731
  selectedIndex: number;
732
732
  onNodeClick?: (indexOrId: number | string) => void;
733
733
  showStageId?: boolean;
734
+ /** Dependency-cone overlay (chart node id → BFS depth) — painted while
735
+ * the Inspector's Data Trace tab is open. Custom renderers may ignore it. */
736
+ sliceCone?: ReadonlyMap<string, number>;
734
737
  }) => React.ReactNode;
735
738
  /**
736
739
  * When true, render each node's stable `stageId` as a small monospace
@@ -1103,6 +1106,9 @@ interface InspectorPanelProps {
1103
1106
  selectedStageId?: string;
1104
1107
  /** Navigate to a stage when clicking a Data Trace frame. */
1105
1108
  onNavigateToStage?: (runtimeStageId: string) => void;
1109
+ /** Fires when the user switches tabs — lets the shell paint the chart's
1110
+ * dependency cone while the Data Trace tab is open. */
1111
+ onTabChange?: (tab: "state" | "trace") => void;
1106
1112
  }
1107
1113
  declare const InspectorPanel: react.NamedExoticComponent<InspectorPanelProps>;
1108
1114
 
package/dist/index.js CHANGED
@@ -5025,6 +5025,7 @@ function TracedFlow({
5025
5025
  nodeTypes: userNodeTypes,
5026
5026
  edgeTypes: userEdgeTypes,
5027
5027
  coActiveStageIds,
5028
+ sliceCone,
5028
5029
  children,
5029
5030
  className,
5030
5031
  style
@@ -5126,6 +5127,38 @@ function TracedFlow({
5126
5127
  ),
5127
5128
  [positioned.edges, slice, colors]
5128
5129
  );
5130
+ const [coneRevealed, setConeRevealed] = useState10(false);
5131
+ useEffect10(() => {
5132
+ if (!sliceCone) return;
5133
+ setConeRevealed(false);
5134
+ const raf = requestAnimationFrame(() => setConeRevealed(true));
5135
+ return () => cancelAnimationFrame(raf);
5136
+ }, [sliceCone]);
5137
+ const conedNodes = useMemo10(() => {
5138
+ if (!sliceCone || sliceCone.size === 0) return reactFlowNodes;
5139
+ return reactFlowNodes.map((n) => {
5140
+ const depth = sliceCone.get(n.id);
5141
+ if (depth === void 0) {
5142
+ return { ...n, style: { ...n.style, opacity: 0.22, transition: "opacity 260ms ease" } };
5143
+ }
5144
+ return {
5145
+ ...n,
5146
+ style: {
5147
+ ...n.style,
5148
+ opacity: coneRevealed ? 1 : 0.22,
5149
+ transition: "opacity 320ms ease",
5150
+ transitionDelay: `${depth * 90}ms`
5151
+ }
5152
+ };
5153
+ });
5154
+ }, [reactFlowNodes, sliceCone, coneRevealed]);
5155
+ const conedEdges = useMemo10(() => {
5156
+ if (!sliceCone || sliceCone.size === 0) return reactFlowEdges;
5157
+ return reactFlowEdges.map((e) => {
5158
+ const inCone = sliceCone.has(e.source) && sliceCone.has(e.target);
5159
+ return inCone ? e : { ...e, style: { ...e.style, opacity: 0.12, transition: "opacity 260ms ease" } };
5160
+ });
5161
+ }, [reactFlowEdges, sliceCone]);
5129
5162
  const handleNodeClick = useCallback7(
5130
5163
  (_, node) => {
5131
5164
  const data = node.data ?? {};
@@ -5167,8 +5200,8 @@ function TracedFlow({
5167
5200
  /* @__PURE__ */ jsx21("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsxs18(
5168
5201
  ReactFlow,
5169
5202
  {
5170
- nodes: reactFlowNodes,
5171
- edges: reactFlowEdges,
5203
+ nodes: conedNodes,
5204
+ edges: conedEdges,
5172
5205
  nodeTypes: mergedNodeTypes,
5173
5206
  edgeTypes: mergedEdgeTypes,
5174
5207
  onNodeClick: handleNodeClick,
@@ -5361,9 +5394,14 @@ var InspectorPanel = memo5(function InspectorPanel2({
5361
5394
  dataTraceFrames,
5362
5395
  dataTraceNote,
5363
5396
  selectedStageId,
5364
- onNavigateToStage
5397
+ onNavigateToStage,
5398
+ onTabChange
5365
5399
  }) {
5366
- const [tab, setTab] = useState11("state");
5400
+ const [tab, setTabState] = useState11("state");
5401
+ const setTab = (t) => {
5402
+ setTabState(t);
5403
+ onTabChange?.(t);
5404
+ };
5367
5405
  const currentSnapshot = snapshots[selectedIndex];
5368
5406
  return /* @__PURE__ */ jsxs20(
5369
5407
  "div",
@@ -6020,12 +6058,10 @@ var RightPanel = memo8(function RightPanel2({
6020
6058
  recorderViews,
6021
6059
  autoRecorderViews,
6022
6060
  size,
6023
- onNavigateToStage
6061
+ onNavigateToStage,
6062
+ dataTrace,
6063
+ onInspectorTabChange
6024
6064
  }) {
6025
- const dataTrace = useMemo12(
6026
- () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, snapshots[selectedIndex]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6027
- [runtimeSnapshot, snapshots, selectedIndex]
6028
- );
6029
6065
  return /* @__PURE__ */ jsxs23(Fragment6, { children: [
6030
6066
  /* @__PURE__ */ jsx26("div", { style: {
6031
6067
  display: "flex",
@@ -6079,6 +6115,7 @@ var RightPanel = memo8(function RightPanel2({
6079
6115
  selectedIndex,
6080
6116
  dataTraceFrames: dataTrace.frames,
6081
6117
  dataTraceNote: dataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
6118
+ onTabChange: onInspectorTabChange,
6082
6119
  selectedStageId: snapshots[selectedIndex]?.runtimeStageId,
6083
6120
  onNavigateToStage
6084
6121
  }
@@ -6132,7 +6169,7 @@ function ExplainableShell({
6132
6169
  const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
6133
6170
  const tracedFlowRenderer = useMemo12(() => {
6134
6171
  if (!traceGraph) return void 0;
6135
- return ({ selectedIndex, snapshots: snapshots2, onNodeClick }) => {
6172
+ return ({ selectedIndex, snapshots: snapshots2, onNodeClick, sliceCone: sliceCone2 }) => {
6136
6173
  const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
6137
6174
  let overlayIdx = selectedIndex;
6138
6175
  if (activeRsid && runtimeOverlay) {
@@ -6156,6 +6193,7 @@ function ExplainableShell({
6156
6193
  {
6157
6194
  graph: traceGraph,
6158
6195
  overlay: runtimeOverlay ?? void 0,
6196
+ sliceCone: sliceCone2 ?? void 0,
6159
6197
  colors: traceColors || void 0,
6160
6198
  scrubIndex: overlayIdx,
6161
6199
  onNodeClick: (stageId) => onNodeClick?.(stageId),
@@ -6216,6 +6254,7 @@ function ExplainableShell({
6216
6254
  const [drillDownStack, setDrillDownStack] = useState14([]);
6217
6255
  const [rightExpanded, setRightExpanded] = useState14(defaultExpanded?.details ?? true);
6218
6256
  const [rightPanelMode, setRightPanelMode] = useState14("insights");
6257
+ const [inspectorTab, setInspectorTab] = useState14("state");
6219
6258
  const [leftExpanded, setLeftExpanded] = useState14(defaultExpanded?.topology ?? false);
6220
6259
  const [timelineExpanded, setTimelineExpanded] = useState14(defaultExpanded?.timeline ?? false);
6221
6260
  useEffect11(() => {
@@ -6251,6 +6290,21 @@ function ExplainableShell({
6251
6290
  }, [drillDownStack, snapshots]);
6252
6291
  const activeSnapshots = currentLevel.snapshots;
6253
6292
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
6293
+ const shellDataTrace = useMemo12(
6294
+ () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, activeSnapshots[safeIdx]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6295
+ [runtimeSnapshot, activeSnapshots, safeIdx]
6296
+ );
6297
+ const sliceCone = useMemo12(() => {
6298
+ if (rightPanelMode !== "what" || inspectorTab !== "trace") return void 0;
6299
+ if (shellDataTrace.frames.length < 2) return void 0;
6300
+ const cone = /* @__PURE__ */ new Map();
6301
+ for (const f of shellDataTrace.frames) {
6302
+ const stagePart = f.runtimeStageId.split("#")[0];
6303
+ const prev = cone.get(stagePart);
6304
+ if (prev === void 0 || f.depth < prev) cone.set(stagePart, f.depth);
6305
+ }
6306
+ return cone;
6307
+ }, [rightPanelMode, inspectorTab, shellDataTrace]);
6254
6308
  const activeNarrativeEntries = isInSubflow ? currentLevel.narrative : narrativeEntries;
6255
6309
  const breadcrumbs = useMemo12(() => {
6256
6310
  const root = { label: title || "Flowchart", spec: null, description: void 0 };
@@ -6334,7 +6388,7 @@ function ExplainableShell({
6334
6388
  (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ jsxs23(Fragment6, { children: [
6335
6389
  /* @__PURE__ */ jsx26(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
6336
6390
  isInSubflow && /* @__PURE__ */ jsx26(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6337
- traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
6391
+ traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId, ...sliceCone && { sliceCone } }),
6338
6392
  /* @__PURE__ */ jsx26(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
6339
6393
  /* @__PURE__ */ jsx26(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
6340
6394
  /* @__PURE__ */ jsx26(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
@@ -6453,7 +6507,8 @@ function ExplainableShell({
6453
6507
  snapshots: activeSnapshots,
6454
6508
  selectedIndex: safeIdx,
6455
6509
  onNodeClick: handleNodeClick,
6456
- showStageId
6510
+ showStageId,
6511
+ ...sliceCone && { sliceCone }
6457
6512
  }) }),
6458
6513
  showTreeSidebar && /* @__PURE__ */ jsxs23(Fragment6, { children: [
6459
6514
  /* @__PURE__ */ jsx26(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
@@ -6493,7 +6548,8 @@ function ExplainableShell({
6493
6548
  snapshots: activeSnapshots,
6494
6549
  selectedIndex: safeIdx,
6495
6550
  onNodeClick: handleNodeClick,
6496
- showStageId
6551
+ showStageId,
6552
+ ...sliceCone && { sliceCone }
6497
6553
  }) }) : /* @__PURE__ */ jsx26("div", { style: { flex: 1 } }),
6498
6554
  /* @__PURE__ */ jsx26(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6499
6555
  rightExpanded && /* @__PURE__ */ jsx26("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx26(
@@ -6501,6 +6557,8 @@ function ExplainableShell({
6501
6557
  {
6502
6558
  mode: rightPanelMode,
6503
6559
  onModeChange: setRightPanelMode,
6560
+ dataTrace: shellDataTrace,
6561
+ onInspectorTabChange: setInspectorTab,
6504
6562
  snapshots: activeSnapshots,
6505
6563
  selectedIndex: safeIdx,
6506
6564
  runtimeSnapshot,