mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 23:00:03 +00:00
fix(studio): hide the Slideshow tab and panel for non-slideshow compositions
The Slideshow tab rendered unconditionally, showing the branching editor for any composition regardless of whether it was actually a slideshow — a plain video comp offered a tab with nothing meaningful to edit. Gate it on the composition carrying the slideshow JSON island (<script type="application/hyperframes-slideshow+json">), the same definitive marker the CLI's `present` command already requires (it refuses to run without one). Presence-only, not full manifest validation, so a malformed island still surfaces the tab rather than disappearing entirely. Also bounce rightPanelTab off "slideshow" to "renders" if the active composition stops being a slideshow while that tab is open (e.g. switching files), since its button would otherwise vanish with no way back to it. Extracted the gating + scene-list derivation into useSlideshowTabState to keep StudioRightPanel.tsx under the 600-LOC gate.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import React, { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { useSlideshowTabState } from "./useSlideshowTabState";
|
||||
import type { RightPanelTab } from "../utils/studioHelpers";
|
||||
|
||||
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
const SLIDESHOW_HTML = `<html><body><script type="application/hyperframes-slideshow+json">{"slides":[]}</script></body></html>`;
|
||||
const PLAIN_HTML = `<html><body><div id="title">hi</div></body></html>`;
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
function renderHook(params: {
|
||||
editingFileContent: string | null | undefined;
|
||||
rightPanelTab: RightPanelTab;
|
||||
}) {
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
const root = createRoot(host);
|
||||
const setRightPanelTabCalls: RightPanelTab[] = [];
|
||||
let current: ReturnType<typeof useSlideshowTabState> | null = null;
|
||||
|
||||
function Harness() {
|
||||
current = useSlideshowTabState({
|
||||
editingFileContent: params.editingFileContent,
|
||||
previewIframeRef: { current: null },
|
||||
refreshKey: 0,
|
||||
rightPanelTab: params.rightPanelTab,
|
||||
setRightPanelTab: (tab) => setRightPanelTabCalls.push(tab),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
root.render(React.createElement(Harness));
|
||||
});
|
||||
|
||||
return {
|
||||
getState: (): ReturnType<typeof useSlideshowTabState> => {
|
||||
if (!current) throw new Error("useSlideshowTabState did not render");
|
||||
return current;
|
||||
},
|
||||
setRightPanelTabCalls,
|
||||
unmount: () => act(() => root.unmount()),
|
||||
};
|
||||
}
|
||||
|
||||
describe("useSlideshowTabState", () => {
|
||||
it("detects a slideshow composition via the JSON island", () => {
|
||||
const harness = renderHook({ editingFileContent: SLIDESHOW_HTML, rightPanelTab: "design" });
|
||||
expect(harness.getState().isSlideshowComposition).toBe(true);
|
||||
harness.unmount();
|
||||
});
|
||||
|
||||
it("reports false for a plain (non-slideshow) composition", () => {
|
||||
const harness = renderHook({ editingFileContent: PLAIN_HTML, rightPanelTab: "design" });
|
||||
expect(harness.getState().isSlideshowComposition).toBe(false);
|
||||
harness.unmount();
|
||||
});
|
||||
|
||||
it("reports false when there is no editing file yet", () => {
|
||||
const harness = renderHook({ editingFileContent: undefined, rightPanelTab: "design" });
|
||||
expect(harness.getState().isSlideshowComposition).toBe(false);
|
||||
harness.unmount();
|
||||
});
|
||||
|
||||
it("bounces rightPanelTab off 'slideshow' to 'renders' on a non-slideshow composition", () => {
|
||||
const harness = renderHook({ editingFileContent: PLAIN_HTML, rightPanelTab: "slideshow" });
|
||||
expect(harness.setRightPanelTabCalls).toEqual(["renders"]);
|
||||
harness.unmount();
|
||||
});
|
||||
|
||||
it("does not bounce when the composition is a slideshow", () => {
|
||||
const harness = renderHook({ editingFileContent: SLIDESHOW_HTML, rightPanelTab: "slideshow" });
|
||||
expect(harness.setRightPanelTabCalls).toEqual([]);
|
||||
harness.unmount();
|
||||
});
|
||||
|
||||
it("does not bounce a tab other than 'slideshow'", () => {
|
||||
const harness = renderHook({ editingFileContent: PLAIN_HTML, rightPanelTab: "renders" });
|
||||
expect(harness.setRightPanelTabCalls).toEqual([]);
|
||||
harness.unmount();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user