footprint-explainable-ui 0.3.0 → 0.3.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.
Files changed (2) hide show
  1. package/README.md +259 -153
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # footprint-explainable-ui
2
2
 
3
- Themeable React components for visualizing [FootPrint](https://github.com/sanjay1909/footPrint) pipeline execution — time-travel debugging, flowchart overlays, narrative traces, and scope diffs.
3
+ Themeable React components for visualizing [FootPrint](https://github.com/footprintjs/footPrint) pipeline execution — time-travel debugging, flowchart overlays, subflow drill-down, narrative traces, and scope diffs.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,16 +8,44 @@ Themeable React components for visualizing [FootPrint](https://github.com/sanjay
8
8
  npm install footprint-explainable-ui
9
9
  ```
10
10
 
11
- Peer dependencies: `react >= 18`. For flowchart components, also install `@xyflow/react`.
11
+ **Peer dependencies:** `react >= 18`, `react-dom >= 18`
12
+
13
+ For flowchart components, also install:
14
+
15
+ ```bash
16
+ npm install @xyflow/react
17
+ ```
18
+
19
+ ## Entry Points
20
+
21
+ | Import path | What it provides |
22
+ |---|---|
23
+ | `footprint-explainable-ui` | Core components, themes, adapters |
24
+ | `footprint-explainable-ui/flowchart` | Flowchart visualization, subflow navigation (requires `@xyflow/react`) |
12
25
 
13
26
  ## Quick Start
14
27
 
15
- ### All-in-One Shell
28
+ ### 1. Convert FootPrint execution data to snapshots
16
29
 
17
- The `ExplainableShell` gives you a tabbed UI (Result | Explainable | AI-Compatible) with time-travel controls, Gantt timeline, scope diffs, and progressive narrative — out of the box.
30
+ ```typescript
31
+ import { FlowChartExecutor } from "footprint";
32
+ import { toVisualizationSnapshots } from "footprint-explainable-ui";
33
+
34
+ const executor = new FlowChartExecutor(chart);
35
+ await executor.run();
36
+
37
+ // Convert runtime snapshot → visualization snapshots
38
+ const snapshots = toVisualizationSnapshots(executor.getSnapshot());
39
+ ```
40
+
41
+ ### 2. Render with the all-in-one shell
18
42
 
19
43
  ```tsx
20
- import { ExplainableShell, FootprintTheme, warmDark } from "footprint-explainable-ui";
44
+ import {
45
+ ExplainableShell,
46
+ FootprintTheme,
47
+ warmDark,
48
+ } from "footprint-explainable-ui";
21
49
 
22
50
  function App({ snapshots, narrative, result }) {
23
51
  return (
@@ -33,22 +61,21 @@ function App({ snapshots, narrative, result }) {
33
61
  }
34
62
  ```
35
63
 
36
- ### Individual Components
37
-
38
- Every component works standalone. Mix and match:
64
+ ### 3. Or compose individual components
39
65
 
40
66
  ```tsx
41
67
  import {
42
- NarrativeTrace,
68
+ TimeTravelControls,
69
+ MemoryInspector,
43
70
  ScopeDiff,
44
71
  GanttTimeline,
45
- MemoryInspector,
46
- TimeTravelControls,
47
- ResultPanel,
72
+ NarrativeTrace,
48
73
  } from "footprint-explainable-ui";
49
74
 
50
75
  function MyDebugger({ snapshots }) {
51
76
  const [idx, setIdx] = useState(0);
77
+ const current = snapshots[idx];
78
+ const previous = idx > 0 ? snapshots[idx - 1] : null;
52
79
 
53
80
  return (
54
81
  <>
@@ -59,46 +86,200 @@ function MyDebugger({ snapshots }) {
59
86
  />
60
87
  <MemoryInspector snapshots={snapshots} selectedIndex={idx} />
61
88
  <ScopeDiff
62
- previous={idx > 0 ? snapshots[idx - 1].memory : null}
63
- current={snapshots[idx].memory}
89
+ previous={previous?.memory ?? null}
90
+ current={current.memory}
64
91
  hideUnchanged
65
92
  />
93
+ <NarrativeTrace narrative={snapshots.map(s => s.narrative)} />
66
94
  <GanttTimeline snapshots={snapshots} selectedIndex={idx} onSelect={setIdx} />
67
95
  </>
68
96
  );
69
97
  }
70
98
  ```
71
99
 
72
- ## Theming
100
+ ---
101
+
102
+ ## Flowchart Visualization
103
+
104
+ Import from `footprint-explainable-ui/flowchart`:
73
105
 
74
- ### Option 1: ThemeProvider
106
+ ```tsx
107
+ import {
108
+ StageNode,
109
+ specToReactFlow,
110
+ useSubflowNavigation,
111
+ SubflowBreadcrumb,
112
+ type SpecNode,
113
+ type ExecutionOverlay,
114
+ } from "footprint-explainable-ui/flowchart";
115
+ ```
75
116
 
76
- Wrap your app with `FootprintTheme` and pass a preset or custom tokens:
117
+ ### Static flowchart from pipeline spec
118
+
119
+ ```tsx
120
+ import { ReactFlow } from "@xyflow/react";
121
+ import "@xyflow/react/dist/style.css";
122
+ import { specToReactFlow, StageNode } from "footprint-explainable-ui/flowchart";
123
+
124
+ const nodeTypes = { stage: StageNode };
125
+
126
+ function PipelineChart({ spec }) {
127
+ const { nodes, edges } = specToReactFlow(spec);
128
+
129
+ return (
130
+ <ReactFlow
131
+ nodes={nodes}
132
+ edges={edges}
133
+ nodeTypes={nodeTypes}
134
+ fitView
135
+ />
136
+ );
137
+ }
138
+ ```
139
+
140
+ ### With execution overlay (time-travel)
141
+
142
+ The overlay highlights which stages have executed, which is active, and the execution path — like a Google Maps route overlay.
143
+
144
+ ```tsx
145
+ import { specToReactFlow, type ExecutionOverlay } from "footprint-explainable-ui/flowchart";
146
+
147
+ // Build overlay from your current time-travel position
148
+ const overlay: ExecutionOverlay = {
149
+ doneStages: new Set(["LoadOrder", "ProcessPayment"]),
150
+ activeStage: "ShipOrder",
151
+ executedStages: new Set(["LoadOrder", "ProcessPayment", "ShipOrder"]),
152
+ executionOrder: ["LoadOrder", "ProcessPayment", "ShipOrder"],
153
+ };
154
+
155
+ const { nodes, edges } = specToReactFlow(spec, overlay);
156
+ ```
157
+
158
+ **Tip:** Compute the overlay from your snapshots array and current index:
159
+
160
+ ```tsx
161
+ function buildOverlay(snapshots, idx): ExecutionOverlay {
162
+ const executionOrder = snapshots.slice(0, idx + 1).map(s => s.stageLabel);
163
+ const doneStages = new Set(snapshots.slice(0, idx).map(s => s.stageLabel));
164
+ const activeStage = snapshots[idx]?.stageLabel ?? null;
165
+ const executedStages = new Set([...doneStages]);
166
+ if (activeStage) executedStages.add(activeStage);
167
+ return { doneStages, activeStage, executedStages, executionOrder };
168
+ }
169
+ ```
170
+
171
+ ### Custom edge colors
172
+
173
+ ```tsx
174
+ const { nodes, edges } = specToReactFlow(spec, overlay, {
175
+ edgeExecuted: "#00ff88", // Completed path
176
+ edgeActive: "#ff6b6b", // Currently executing
177
+ });
178
+ ```
179
+
180
+ ### Subflow drill-down navigation
181
+
182
+ For pipelines with nested subflows, `useSubflowNavigation` manages a breadcrumb stack. Clicking a subflow node drills into its internal flowchart.
183
+
184
+ ```tsx
185
+ import {
186
+ useSubflowNavigation,
187
+ SubflowBreadcrumb,
188
+ specToReactFlow,
189
+ StageNode,
190
+ } from "footprint-explainable-ui/flowchart";
191
+ import { ReactFlow } from "@xyflow/react";
192
+
193
+ const nodeTypes = { stage: StageNode };
194
+
195
+ function DrillDownChart({ spec, overlay }) {
196
+ const subflowNav = useSubflowNavigation(spec);
197
+
198
+ // Get the current level's spec from breadcrumbs
199
+ const currentSpec = subflowNav.breadcrumbs[subflowNav.breadcrumbs.length - 1].spec;
200
+ const { nodes, edges } = specToReactFlow(currentSpec, overlay);
201
+
202
+ return (
203
+ <div>
204
+ {/* Breadcrumb bar: Pipeline > PaymentSubflow */}
205
+ {subflowNav.isInSubflow && (
206
+ <SubflowBreadcrumb
207
+ breadcrumbs={subflowNav.breadcrumbs}
208
+ onNavigate={subflowNav.navigateTo}
209
+ />
210
+ )}
211
+
212
+ <ReactFlow
213
+ nodes={nodes}
214
+ edges={edges}
215
+ nodeTypes={nodeTypes}
216
+ onNodeClick={(_, node) => subflowNav.handleNodeClick(node.id)}
217
+ fitView
218
+ />
219
+ </div>
220
+ );
221
+ }
222
+ ```
223
+
224
+ **`useSubflowNavigation` returns:**
225
+
226
+ | Property | Type | Description |
227
+ |---|---|---|
228
+ | `breadcrumbs` | `BreadcrumbEntry[]` | Stack from root to current level |
229
+ | `nodes` | `Node[]` | ReactFlow nodes for current level |
230
+ | `edges` | `Edge[]` | ReactFlow edges for current level |
231
+ | `handleNodeClick` | `(nodeId) => boolean` | Drills into subflow if applicable |
232
+ | `navigateTo` | `(level) => void` | Jump to breadcrumb level (0 = root) |
233
+ | `isInSubflow` | `boolean` | Whether we're inside a subflow |
234
+ | `currentSubflowNodeName` | `string \| null` | Name of the subflow node drilled into |
235
+
236
+ ### Extracting subflow execution data
237
+
238
+ When drilled into a subflow, extract its execution snapshots from the parent's memory:
239
+
240
+ ```tsx
241
+ import { toVisualizationSnapshots } from "footprint-explainable-ui";
242
+
243
+ // Find the parent stage that contains the subflow result
244
+ const parentSnap = parentSnapshots.find(s => s.stageLabel === subflowNav.currentSubflowNodeName);
245
+ const sfResult = parentSnap?.memory?.subflowResult;
246
+ const tc = sfResult?.treeContext;
247
+
248
+ if (tc?.stageContexts) {
249
+ const subflowSnapshots = toVisualizationSnapshots({
250
+ sharedState: tc.globalContext,
251
+ executionTree: tc.stageContexts,
252
+ commitLog: tc.history ?? [],
253
+ });
254
+
255
+ // Strip builder's "subflowId/" prefix from stage names
256
+ const prefix = sfResult.subflowId ? `${sfResult.subflowId}/` : null;
257
+ if (prefix) {
258
+ for (const snap of subflowSnapshots) {
259
+ if (snap.stageLabel.startsWith(prefix))
260
+ snap.stageLabel = snap.stageLabel.slice(prefix.length);
261
+ if (snap.stageName.startsWith(prefix))
262
+ snap.stageName = snap.stageName.slice(prefix.length);
263
+ }
264
+ }
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Theming
271
+
272
+ ### ThemeProvider
77
273
 
78
274
  ```tsx
79
275
  import { FootprintTheme, warmDark, warmLight, coolDark } from "footprint-explainable-ui";
80
276
 
81
- // Use a built-in preset
82
277
  <FootprintTheme tokens={warmDark}>
83
278
  <MyApp />
84
279
  </FootprintTheme>
85
-
86
- // Or customize
87
- <FootprintTheme tokens={{
88
- colors: {
89
- primary: "#e91e63",
90
- bgPrimary: "#121212",
91
- textPrimary: "#ffffff",
92
- },
93
- radius: "12px",
94
- }}>
95
- <MyApp />
96
- </FootprintTheme>
97
280
  ```
98
281
 
99
- ### Option 2: CSS Variables
100
-
101
- Set `--fp-*` CSS variables directly — no provider needed:
282
+ ### CSS Variables (no provider needed)
102
283
 
103
284
  ```css
104
285
  :root {
@@ -115,7 +296,7 @@ Set `--fp-*` CSS variables directly — no provider needed:
115
296
  ### Built-in Presets
116
297
 
117
298
  | Preset | Description |
118
- |--------|-------------|
299
+ |---|---|
119
300
  | `coolDark` | Default — indigo/slate dark theme |
120
301
  | `warmDark` | Charcoal-purple with warm text |
121
302
  | `warmLight` | Cream/peach light theme |
@@ -125,55 +306,36 @@ Set `--fp-*` CSS variables directly — no provider needed:
125
306
  ```typescript
126
307
  interface ThemeTokens {
127
308
  colors?: {
128
- primary?: string; // Accent color (buttons, highlights)
129
- success?: string; // Completed stages
130
- error?: string; // Error states
131
- warning?: string; // Warnings
132
- bgPrimary?: string; // Main background
133
- bgSecondary?: string;// Panel/card background
134
- bgTertiary?: string; // Hover/active background
135
- textPrimary?: string;// Main text
136
- textSecondary?: string;// Secondary text
137
- textMuted?: string; // Dimmed text
138
- border?: string; // Borders
309
+ primary?: string; // Accent (buttons, highlights)
310
+ success?: string; // Completed stages
311
+ error?: string; // Error states
312
+ warning?: string; // Warnings
313
+ bgPrimary?: string; // Main background
314
+ bgSecondary?: string; // Panel/card background
315
+ bgTertiary?: string; // Hover/active background
316
+ textPrimary?: string; // Main text
317
+ textSecondary?: string; // Secondary text
318
+ textMuted?: string; // Dimmed text
319
+ border?: string; // Borders
139
320
  };
140
- radius?: string; // Border radius
321
+ radius?: string;
141
322
  fontFamily?: {
142
- sans?: string; // UI text font
143
- mono?: string; // Code/data font
323
+ sans?: string; // UI text font
324
+ mono?: string; // Code/data font
144
325
  };
145
326
  }
146
327
  ```
147
328
 
148
- ## Size Variants
149
-
150
- All components accept a `size` prop: `"compact"`, `"default"`, or `"detailed"`.
151
-
152
- ```tsx
153
- <GanttTimeline snapshots={snapshots} size="compact" />
154
- <MemoryInspector snapshots={snapshots} size="detailed" />
155
- ```
156
-
157
- ## Unstyled Mode
158
-
159
- Strip all built-in styles and bring your own. Components render semantic `data-fp` attributes for CSS targeting:
160
-
161
- ```tsx
162
- <NarrativeTrace narrative={lines} unstyled className="my-narrative" />
163
- ```
329
+ ---
164
330
 
165
- ```css
166
- [data-fp="narrative-header"] { font-weight: bold; }
167
- [data-fp="narrative-step"] { padding-left: 2rem; }
168
- [data-fp="narrative-group"][data-latest="true"] { background: highlight; }
169
- ```
331
+ ## Components Reference
170
332
 
171
- ## Components
333
+ ### Core Components
172
334
 
173
335
  | Component | Description |
174
- |-----------|-------------|
336
+ |---|---|
175
337
  | `ExplainableShell` | Tabbed container: Result / Explainable / AI-Compatible |
176
- | `TimeTravelControls` | Play/pause, prev/next, tick-mark timeline |
338
+ | `TimeTravelControls` | Play/pause, prev/next, scrubber timeline |
177
339
  | `NarrativeTrace` | Collapsible stage groups with progressive reveal |
178
340
  | `NarrativeLog` | Simple timeline-style execution log |
179
341
  | `ScopeDiff` | Side-by-side scope changes (added/changed/removed) |
@@ -182,107 +344,51 @@ Strip all built-in styles and bring your own. Components render semantic `data-f
182
344
  | `GanttTimeline` | Horizontal duration timeline |
183
345
  | `SnapshotPanel` | All-in-one inspector (scrubber + memory + narrative + Gantt) |
184
346
 
185
- ### Flowchart Components (separate entry point)
186
-
187
- Requires `@xyflow/react` as a peer dependency. Import from `footprint-explainable-ui/flowchart`:
188
-
189
- ```bash
190
- npm install @xyflow/react
191
- ```
192
-
193
- ```tsx
194
- import {
195
- FlowchartView,
196
- StageNode,
197
- specToReactFlow,
198
- TimeTravelDebugger,
199
- } from "footprint-explainable-ui/flowchart";
200
- ```
347
+ ### Flowchart Components (`footprint-explainable-ui/flowchart`)
201
348
 
202
349
  | Export | Description |
203
- |--------|-------------|
350
+ |---|---|
204
351
  | `FlowchartView` | ReactFlow pipeline visualization with execution overlay |
205
352
  | `StageNode` | Custom node with state-aware coloring, step badges, pulse rings |
206
353
  | `specToReactFlow` | Convert pipeline spec → ReactFlow nodes/edges with path overlay |
207
354
  | `TimeTravelDebugger` | Full debugger with flowchart + all panels |
355
+ | `SubflowBreadcrumb` | Breadcrumb bar for subflow drill-down |
356
+ | `useSubflowNavigation` | Hook managing subflow drill-down navigation stack |
208
357
 
209
- ### `specToReactFlow` — Pipeline Spec to Flowchart
358
+ ### Adapters
210
359
 
211
- Converts a `builder.toSpec()` structure into ReactFlow nodes and edges. Supports two modes:
360
+ | Export | Description |
361
+ |---|---|
362
+ | `toVisualizationSnapshots` | Convert `FlowChartExecutor.getSnapshot()` → `StageSnapshot[]` |
363
+ | `createSnapshots` | Build `StageSnapshot[]` from simple arrays (testing/custom data) |
212
364
 
213
- ```tsx
214
- import { specToReactFlow } from "footprint-explainable-ui/flowchart";
215
- import type { ExecutionOverlay } from "footprint-explainable-ui/flowchart";
365
+ ---
216
366
 
217
- // 1. Static flowchart (no execution state)
218
- const { nodes, edges } = specToReactFlow(spec);
367
+ ## Size Variants
219
368
 
220
- // 2. With execution overlay (Google Maps-style path)
221
- const overlay: ExecutionOverlay = {
222
- doneStages: new Set(["ReceiveApp", "PullCredit"]),
223
- activeStage: "CalculateDTI",
224
- executedStages: new Set(["ReceiveApp", "PullCredit", "CalculateDTI"]),
225
- executionOrder: ["ReceiveApp", "PullCredit", "CalculateDTI"],
226
- };
227
- const { nodes, edges } = specToReactFlow(spec, overlay);
369
+ All components accept a `size` prop: `"compact"`, `"default"`, or `"detailed"`.
228
370
 
229
- // 3. Custom edge colors (overrides theme defaults)
230
- const { nodes, edges } = specToReactFlow(spec, overlay, {
231
- edgeExecuted: "#00ff88",
232
- edgeActive: "#ff6b6b",
233
- });
371
+ ```tsx
372
+ <GanttTimeline snapshots={snapshots} size="compact" />
373
+ <MemoryInspector snapshots={snapshots} size="detailed" />
234
374
  ```
235
375
 
236
- Edge colors default to the library's theme tokens (`success` for executed, `primary` for active). Override per-call via the `colors` parameter.
237
-
238
- ### `StageNode` — Theme-Aware Node
239
-
240
- `StageNode` reads all colors from `--fp-*` CSS variables:
241
- - **Default state**: uses `--fp-bg-secondary` background, `--fp-text-primary` text
242
- - **Active/done/error**: uses `--fp-color-primary` / `success` / `error` background
243
- - **Step badge**: shows execution order number on executed nodes
244
- - **Font**: uses `--fp-font-sans` for label text
376
+ ## Unstyled Mode
245
377
 
246
- Wrap your flowchart in `FootprintTheme` and the nodes match automatically:
378
+ Strip all built-in styles for full CSS control. Components render semantic `data-fp` attributes:
247
379
 
248
380
  ```tsx
249
- <FootprintTheme tokens={warmDark}>
250
- <ReactFlow nodes={nodes} edges={edges} nodeTypes={{ stage: StageNode }} />
251
- </FootprintTheme>
381
+ <NarrativeTrace narrative={lines} unstyled className="my-narrative" />
252
382
  ```
253
383
 
254
- ## Adapters
255
-
256
- Convert FootPrint runtime snapshots to the `StageSnapshot[]` format:
257
-
258
- ```typescript
259
- import { toVisualizationSnapshots } from "footprint-explainable-ui";
260
-
261
- const executor = new FlowChartExecutor(pipeline);
262
- await executor.run(scope);
263
-
264
- const snapshots = toVisualizationSnapshots(executor.getSnapshot());
384
+ ```css
385
+ [data-fp="narrative-header"] { font-weight: bold; }
386
+ [data-fp="narrative-step"] { padding-left: 2rem; }
387
+ [data-fp="narrative-group"][data-latest="true"] { background: highlight; }
265
388
  ```
266
389
 
267
- ## Rendering in Different Contexts
268
-
269
- The library is render-target agnostic. Use components in:
390
+ ---
270
391
 
271
- - **Inline content** — drop into any React layout
272
- - **Modal/dialog** — wrap in your modal component
273
- - **Sidebar panel** — use `size="compact"` for narrow panels
274
- - **Full-page dashboard** — use `ExplainableShell` with all tabs
275
- - **Embedded widget** — use `unstyled` mode + custom CSS
392
+ ## License
276
393
 
277
- ```tsx
278
- // In a modal
279
- <Dialog>
280
- <ExplainableShell snapshots={snapshots} narrative={narrative} size="compact" />
281
- </Dialog>
282
-
283
- // In a sidebar
284
- <aside style={{ width: 320 }}>
285
- <NarrativeTrace narrative={narrative} size="compact" />
286
- <GanttTimeline snapshots={snapshots} size="compact" />
287
- </aside>
288
- ```
394
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprint-explainable-ui",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Themeable React components for visualizing FootPrint pipeline execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",