footprint-explainable-ui 0.3.1 → 0.3.2

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 +169 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -389,6 +389,175 @@ Strip all built-in styles for full CSS control. Components render semantic `data
389
389
 
390
390
  ---
391
391
 
392
+ ## Example: Build a Pipeline Playground
393
+
394
+ A complete example combining flowchart, time-travel controls, detail panel, and Gantt timeline — the same pattern used by the [FootPrint Playground](https://footprintjs.github.io/footprint-playground/).
395
+
396
+ ```tsx
397
+ import { useState, useMemo } from "react";
398
+ import { ReactFlow } from "@xyflow/react";
399
+ import "@xyflow/react/dist/style.css";
400
+ import {
401
+ toVisualizationSnapshots,
402
+ GanttTimeline,
403
+ ScopeDiff,
404
+ NarrativeTrace,
405
+ MemoryInspector,
406
+ FootprintTheme,
407
+ warmDark,
408
+ } from "footprint-explainable-ui";
409
+ import {
410
+ StageNode,
411
+ specToReactFlow,
412
+ useSubflowNavigation,
413
+ SubflowBreadcrumb,
414
+ type ExecutionOverlay,
415
+ type SpecNode,
416
+ } from "footprint-explainable-ui/flowchart";
417
+ import { FlowChartExecutor } from "footprint";
418
+
419
+ const nodeTypes = { stage: StageNode };
420
+
421
+ // ─── Hook: time-travel + overlay + subflow drill-down ────────────────
422
+ function useFlowchartData(spec: SpecNode | null, vizSnapshots: any[] | null) {
423
+ const [snapshotIdx, setSnapshotIdx] = useState(0);
424
+ const subflowNav = useSubflowNavigation(spec);
425
+
426
+ const activeSnapshots = vizSnapshots; // extend with subflow logic as needed
427
+
428
+ // Compute execution overlay from current scrubber position
429
+ const overlay = useMemo<ExecutionOverlay | undefined>(() => {
430
+ if (!activeSnapshots) return undefined;
431
+ const executionOrder = activeSnapshots
432
+ .slice(0, snapshotIdx + 1)
433
+ .map((s) => s.stageLabel);
434
+ const doneStages = new Set(
435
+ activeSnapshots.slice(0, snapshotIdx).map((s) => s.stageLabel)
436
+ );
437
+ const activeStage = activeSnapshots[snapshotIdx]?.stageLabel ?? null;
438
+ const executedStages = new Set([...doneStages]);
439
+ if (activeStage) executedStages.add(activeStage);
440
+ return { doneStages, activeStage, executedStages, executionOrder };
441
+ }, [activeSnapshots, snapshotIdx]);
442
+
443
+ // Derive ReactFlow nodes/edges with overlay applied
444
+ const currentSpec =
445
+ subflowNav.breadcrumbs[subflowNav.breadcrumbs.length - 1]?.spec ?? null;
446
+ const flowData = useMemo(() => {
447
+ if (!currentSpec || !activeSnapshots) return null;
448
+ return specToReactFlow(currentSpec, overlay);
449
+ }, [currentSpec, activeSnapshots, overlay]);
450
+
451
+ return {
452
+ subflowNav,
453
+ activeSnapshots,
454
+ snapshotIdx,
455
+ setSnapshotIdx,
456
+ currentSnap: activeSnapshots?.[snapshotIdx] ?? null,
457
+ flowData,
458
+ };
459
+ }
460
+
461
+ // ─── Main component ──────────────────────────────────────────────────
462
+ function PipelinePlayground({ chart, spec }: { chart: any; spec: SpecNode }) {
463
+ const [snapshots, setSnapshots] = useState<any[] | null>(null);
464
+
465
+ async function run() {
466
+ const executor = new FlowChartExecutor(chart);
467
+ await executor.run();
468
+ setSnapshots(toVisualizationSnapshots(executor.getSnapshot()));
469
+ }
470
+
471
+ const { subflowNav, activeSnapshots, snapshotIdx, setSnapshotIdx, currentSnap, flowData } =
472
+ useFlowchartData(spec, snapshots);
473
+
474
+ return (
475
+ <FootprintTheme tokens={warmDark}>
476
+ <button onClick={run}>Run Pipeline</button>
477
+
478
+ {/* Flowchart with execution overlay */}
479
+ <div style={{ height: 400 }}>
480
+ {subflowNav.isInSubflow && (
481
+ <SubflowBreadcrumb
482
+ breadcrumbs={subflowNav.breadcrumbs}
483
+ onNavigate={subflowNav.navigateTo}
484
+ />
485
+ )}
486
+ {flowData && (
487
+ <ReactFlow
488
+ nodes={flowData.nodes}
489
+ edges={flowData.edges}
490
+ nodeTypes={nodeTypes}
491
+ onNodeClick={(_, node) => subflowNav.handleNodeClick(node.id)}
492
+ fitView
493
+ />
494
+ )}
495
+ </div>
496
+
497
+ {activeSnapshots && (
498
+ <>
499
+ {/* Time-travel scrubber */}
500
+ <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
501
+ <button
502
+ disabled={snapshotIdx <= 0}
503
+ onClick={() => setSnapshotIdx((i) => i - 1)}
504
+ >
505
+ Prev
506
+ </button>
507
+ <input
508
+ type="range"
509
+ min={0}
510
+ max={activeSnapshots.length - 1}
511
+ value={snapshotIdx}
512
+ onChange={(e) => setSnapshotIdx(Number(e.target.value))}
513
+ />
514
+ <button
515
+ disabled={snapshotIdx >= activeSnapshots.length - 1}
516
+ onClick={() => setSnapshotIdx((i) => i + 1)}
517
+ >
518
+ Next
519
+ </button>
520
+ <span>
521
+ {currentSnap?.stageLabel} ({snapshotIdx + 1}/{activeSnapshots.length})
522
+ </span>
523
+ </div>
524
+
525
+ {/* Detail panels */}
526
+ <MemoryInspector
527
+ snapshots={activeSnapshots}
528
+ selectedIndex={snapshotIdx}
529
+ />
530
+ <ScopeDiff
531
+ previous={snapshotIdx > 0 ? activeSnapshots[snapshotIdx - 1].memory : null}
532
+ current={currentSnap?.memory ?? {}}
533
+ hideUnchanged
534
+ />
535
+ <NarrativeTrace
536
+ narrative={activeSnapshots.map((s) => s.narrative)}
537
+ />
538
+ <GanttTimeline
539
+ snapshots={activeSnapshots}
540
+ selectedIndex={snapshotIdx}
541
+ onSelect={setSnapshotIdx}
542
+ />
543
+ </>
544
+ )}
545
+ </FootprintTheme>
546
+ );
547
+ }
548
+ ```
549
+
550
+ This gives you:
551
+ - Flowchart with Google Maps-style execution path overlay
552
+ - Click subflow nodes to drill down (breadcrumb navigation back)
553
+ - Prev/Next scrubber synced with flowchart highlighting
554
+ - Memory inspector, scope diffs, narrative trace, and Gantt timeline
555
+ - All themed via `FootprintTheme`
556
+
557
+ See the full implementation in the [footprint-playground](https://github.com/footprintjs/footprint-playground) repo.
558
+
559
+ ---
560
+
392
561
  ## License
393
562
 
394
563
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprint-explainable-ui",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Themeable React components for visualizing FootPrint pipeline execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",