footprint-explainable-ui 0.8.2 → 0.10.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.cjs CHANGED
@@ -3796,28 +3796,39 @@ var VLinePill = (0, import_react19.memo)(function VLinePill2({
3796
3796
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
3797
3797
  ] });
3798
3798
  });
3799
- var RIGHT_PANEL_LABELS = {
3800
- memory: "Memory",
3801
- narrative: "Narrative"
3802
- };
3803
3799
  var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
3804
3800
  snapshots,
3805
3801
  selectedIndex,
3806
3802
  narrativeEntries,
3807
3803
  narrative,
3808
3804
  size,
3809
- fillHeight
3805
+ fillHeight,
3806
+ extraViews
3810
3807
  }) {
3811
- const [rightPanel, setRightPanel] = (0, import_react19.useState)("memory");
3808
+ const builtInViews = [
3809
+ {
3810
+ id: "memory",
3811
+ name: "Memory",
3812
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
3813
+ },
3814
+ {
3815
+ id: "narrative",
3816
+ name: "Narrative",
3817
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, narrative, size, style: fillHeight ? { height: "100%" } : void 0 })
3818
+ }
3819
+ ];
3820
+ const allViews = [...builtInViews, ...extraViews ?? []];
3821
+ const [activeViewId, setActiveViewId] = (0, import_react19.useState)(allViews[0]?.id ?? "memory");
3822
+ const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
3812
3823
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
3813
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: ["memory", "narrative"].map((panel) => {
3814
- const active = rightPanel === panel;
3824
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
3825
+ const active = view.id === activeViewId;
3815
3826
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3816
3827
  "button",
3817
3828
  {
3818
- onClick: () => setRightPanel(panel),
3829
+ onClick: () => setActiveViewId(view.id),
3819
3830
  style: {
3820
- flex: 1,
3831
+ flex: allViews.length <= 3 ? 1 : void 0,
3821
3832
  padding: "6px 8px",
3822
3833
  fontSize: 11,
3823
3834
  fontWeight: active ? 600 : 400,
@@ -3828,17 +3839,15 @@ var DetailsContent = (0, import_react19.memo)(function DetailsContent2({
3828
3839
  cursor: "pointer",
3829
3840
  textTransform: "uppercase",
3830
3841
  letterSpacing: "0.06em",
3831
- fontFamily: "inherit"
3842
+ fontFamily: "inherit",
3843
+ whiteSpace: "nowrap"
3832
3844
  },
3833
- children: RIGHT_PANEL_LABELS[panel]
3845
+ children: view.name
3834
3846
  },
3835
- panel
3847
+ view.id
3836
3848
  );
3837
3849
  }) }),
3838
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
3839
- rightPanel === "memory" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots, selectedIndex, size, style: fillHeight ? { height: "100%" } : void 0 }),
3840
- rightPanel === "narrative" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries, narrative, size, style: fillHeight ? { height: "100%" } : void 0 })
3841
- ] })
3850
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
3842
3851
  ] });
3843
3852
  });
3844
3853
  function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narrativeEntries) {
@@ -3922,6 +3931,7 @@ function ExplainableShell({
3922
3931
  hideConsole = false,
3923
3932
  panelLabels,
3924
3933
  defaultExpanded,
3934
+ recorderViews,
3925
3935
  renderFlowchart,
3926
3936
  size = "default",
3927
3937
  unstyled = false,
@@ -3960,7 +3970,14 @@ function ExplainableShell({
3960
3970
  ro.observe(el);
3961
3971
  return () => ro.disconnect();
3962
3972
  }, []);
3963
- const [activeTab, setActiveTab] = (0, import_react19.useState)(defaultTab ?? tabs[0]);
3973
+ const builtInViews = [
3974
+ { id: "result", name: "Result" },
3975
+ { id: "memory", name: "Memory" },
3976
+ { id: "narrative", name: "Narrative" }
3977
+ ];
3978
+ const customViewIds = (recorderViews ?? []).map((v2) => ({ id: v2.id, name: v2.name }));
3979
+ const allTabs = [...builtInViews, ...customViewIds];
3980
+ const [activeTab, setActiveTab] = (0, import_react19.useState)(defaultTab ?? "memory");
3964
3981
  const [snapshotIdx, setSnapshotIdx] = (0, import_react19.useState)(0);
3965
3982
  const [drillDownStack, setDrillDownStack] = (0, import_react19.useState)([]);
3966
3983
  const [rightExpanded, setRightExpanded] = (0, import_react19.useState)(defaultExpanded?.details ?? true);
@@ -4081,14 +4098,10 @@ function ExplainableShell({
4081
4098
  },
4082
4099
  [spec, snapshots, narrativeEntries, snapshotIdx]
4083
4100
  );
4084
- const tabLabels = {
4085
- result: "Result",
4086
- explainable: "Explainable",
4087
- "ai-compatible": "AI-Compatible"
4088
- };
4101
+ const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
4089
4102
  if (unstyled) {
4090
4103
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
4091
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-fp": "shell-tabs", children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { "data-fp": "shell-tab", "data-active": tab === activeTab, onClick: () => handleTabChange(tab), children: tabLabels[tab] }, tab)) }),
4104
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
4092
4105
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
4093
4106
  activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
4094
4107
  (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
@@ -4102,7 +4115,18 @@ function ExplainableShell({
4102
4115
  ] })
4103
4116
  ] });
4104
4117
  }
4105
- const isVisualizationTab = activeTab === "explainable" || activeTab === "ai-compatible";
4118
+ const isVisualizationTab = activeTab !== "result";
4119
+ const activeRecorderRender = (0, import_react19.useMemo)(() => {
4120
+ if (activeTab === "result") return null;
4121
+ if (activeTab === "memory") {
4122
+ return ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: { height: "100%" } });
4123
+ }
4124
+ if (activeTab === "narrative") {
4125
+ return ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
4126
+ }
4127
+ const customView = recorderViews?.find((v2) => v2.id === activeTab);
4128
+ return customView?.render ?? null;
4129
+ }, [activeTab, recorderViews, activeNarrativeEntries, activeNarrative, size]);
4106
4130
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4107
4131
  "div",
4108
4132
  {
@@ -4121,17 +4145,18 @@ function ExplainableShell({
4121
4145
  },
4122
4146
  "data-fp": "explainable-shell",
4123
4147
  children: [
4124
- tabs.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: {
4148
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: {
4125
4149
  display: "flex",
4126
4150
  borderBottom: `1px solid ${theme.border}`,
4127
4151
  background: theme.bgSecondary,
4128
- flexShrink: 0
4129
- }, children: tabs.map((tab) => {
4130
- const active = tab === activeTab;
4152
+ flexShrink: 0,
4153
+ overflowX: "auto"
4154
+ }, children: allTabs.map((tab) => {
4155
+ const active = tab.id === activeTab;
4131
4156
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4132
4157
  "button",
4133
4158
  {
4134
- onClick: () => handleTabChange(tab),
4159
+ onClick: () => handleTabChange(tab.id),
4135
4160
  style: {
4136
4161
  padding: "6px 14px",
4137
4162
  fontSize: 11,
@@ -4143,11 +4168,12 @@ function ExplainableShell({
4143
4168
  border: "none",
4144
4169
  borderBottom: active ? `2px solid ${theme.primary}` : "2px solid transparent",
4145
4170
  cursor: "pointer",
4146
- fontFamily: "inherit"
4171
+ fontFamily: "inherit",
4172
+ whiteSpace: "nowrap"
4147
4173
  },
4148
- children: tabLabels[tab]
4174
+ children: tab.name
4149
4175
  },
4150
- tab
4176
+ tab.id
4151
4177
  );
4152
4178
  }) }),
4153
4179
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: [
@@ -4185,16 +4211,7 @@ function ExplainableShell({
4185
4211
  ) })
4186
4212
  ] }),
4187
4213
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
4188
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { maxHeight: 250, flexShrink: 0, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4189
- DetailsContent,
4190
- {
4191
- snapshots: activeSnapshots,
4192
- selectedIndex: safeIdx,
4193
- narrativeEntries: activeNarrativeEntries,
4194
- narrative: activeNarrative,
4195
- size
4196
- }
4197
- ) }),
4214
+ rightExpanded && activeRecorderRender && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { maxHeight: 250, flexShrink: 0, overflow: "auto" }, children: activeRecorderRender({ snapshots: activeSnapshots, selectedIndex: safeIdx }) }),
4198
4215
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
4199
4216
  timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
4200
4217
  ] })
@@ -4220,19 +4237,9 @@ function ExplainableShell({
4220
4237
  selectedIndex: safeIdx,
4221
4238
  onNodeClick: handleNodeClick
4222
4239
  }) }),
4223
- rightExpanded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { width: "38%", minWidth: 300, maxWidth: 500, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
4240
+ rightExpanded && activeRecorderRender ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { width: "38%", minWidth: 300, maxWidth: 500, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
4224
4241
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: rightLabel, expanded: true, onClick: () => toggleRight(false) }),
4225
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4226
- DetailsContent,
4227
- {
4228
- snapshots: activeSnapshots,
4229
- selectedIndex: safeIdx,
4230
- narrativeEntries: activeNarrativeEntries,
4231
- narrative: activeNarrative,
4232
- size,
4233
- fillHeight: true
4234
- }
4235
- )
4242
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeRecorderRender({ snapshots: activeSnapshots, selectedIndex: safeIdx }) })
4236
4243
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: rightLabel, expanded: false, onClick: () => toggleRight(true) })
4237
4244
  ] }),
4238
4245
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),