fix(studio): short-circuit slideshow-island detection with a substring check (review N2)

slideshowIslandRegex scanned the full file content on every editingFile
change even for the common non-slideshow case. Gate it behind a plain
substring check on SLIDESHOW_ISLAND_TYPE first — cheap, and avoids the
full-content RegExp pass for files that plainly have no island.

Added a test for the still-open behavior this preserves: a malformed
island (invalid JSON) still trips the substring check and the regex,
so the tab stays discoverable rather than silently disappearing.
This commit is contained in:
Vance Ingalls
2026-07-17 00:37:39 -07:00
parent a4167ede07
commit 53b3621437
2 changed files with 15 additions and 6 deletions
@@ -1,5 +1,5 @@
import { useEffect, useMemo, type MutableRefObject } from "react";
import { slideshowIslandRegex } from "@hyperframes/core/slideshow";
import { SLIDESHOW_ISLAND_TYPE, slideshowIslandRegex } from "@hyperframes/core/slideshow";
import type { SceneInfo } from "../components/panels/SlideshowPanel";
import type { IframeWindow } from "../player/lib/playbackTypes";
import type { RightPanelTab } from "../utils/studioHelpers";
@@ -27,11 +27,13 @@ export function useSlideshowTabState(params: {
// Presence-only (not full manifest validation): a malformed island should
// still surface the Slideshow tab so the user can see/fix it, rather than
// making the whole panel disappear.
const isSlideshowComposition = useMemo(
() => Boolean(editingFileContent && slideshowIslandRegex("i").test(editingFileContent)),
[editingFileContent],
);
// making the whole panel disappear. The plain substring check short-circuits
// the regex scan on every non-slideshow file (the common case) without
// paying for a full-content RegExp pass.
const isSlideshowComposition = useMemo(() => {
if (!editingFileContent || !editingFileContent.includes(SLIDESHOW_ISLAND_TYPE)) return false;
return slideshowIslandRegex("i").test(editingFileContent);
}, [editingFileContent]);
// Derive scene list from the live clip manifest in the preview iframe.
const slideshowScenes = useMemo<SceneInfo[]>(() => {