Skip to content
8 changes: 8 additions & 0 deletions e2e-tests/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ test("should switch language and show options for each", async ({ page }) => {
await expect(
page.getByRole("combobox", { exact: true, name: "Front Matter" }),
).toBeVisible();

// `Math` Switch
await expect(
page.getByRole("switch", {
exact: true,
name: "Math",
}),
).toBeVisible();
});

// CSS
Expand Down
49 changes: 41 additions & 8 deletions e2e-tests/persistence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ async function getPersistedJavaScriptCode(page: Page): Promise<string> {
}

async function getPersistedExplorerState(page: Page): Promise<string> {
const persistedValue = await page.evaluate(
key => window.localStorage.getItem(key),
storageKey,
);
return page.evaluate(key => {
const storedValue = window.localStorage.getItem(key);

if (!persistedValue) {
throw new Error("Expected explorer state to be persisted");
}
if (!storedValue) {
throw new Error("No persisted state found in localStorage");
}

return persistedValue;
return storedValue;
}, storageKey);
}

async function getStoredHashValue(page: Page): Promise<string> {
Expand Down Expand Up @@ -163,3 +162,37 @@ test("should fall back to localStorage when a v2 hash is malformed", async ({

await expect(codeEditor).toContainText(fallbackCode);
});

test("should patch legacy Markdown options without math", async ({ page }) => {
await page.addInitScript(key => {
window.localStorage.setItem(
key,
JSON.stringify({
state: {
language: "markdown",
markdownOptions: {
markdownMode: "commonmark",
markdownFrontmatter: "off",
},
},
version: 0,
}),
);
}, storageKey);
await page.goto("/");

await expect
.poll(async () => {
const explorerState = JSON.parse(
await getPersistedExplorerState(page),
);
return explorerState.state.markdownOptions.markdownMath;
})
.toBe(false);

await page.getByRole("button", { name: "Language Options" }).click();

await expect(
page.getByRole("switch", { exact: true, name: "Math" }),
).toHaveAttribute("aria-checked", "false");
});
14 changes: 13 additions & 1 deletion src/components/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const JSONPanel: FC = () => {
const MarkdownPanel: FC = () => {
const explorer = useExplorer();
const { markdownOptions, setMarkdownOptions } = explorer;
const { markdownMode, markdownFrontmatter } = markdownOptions;
const { markdownMode, markdownFrontmatter, markdownMath } = markdownOptions;
return (
<>
<LabeledSelect
Expand Down Expand Up @@ -96,6 +96,18 @@ const MarkdownPanel: FC = () => {
items={markdownFrontmatters}
placeholder="Front Matter"
/>

<LabeledSwitch
id="markdownMath"
label="Math"
checked={markdownMath}
Comment thread
lumirlumir marked this conversation as resolved.
onCheckedChange={(value: boolean) => {
setMarkdownOptions({
...markdownOptions,
markdownMath: value,
});
}}
/>
</>
);
};
Expand Down
4 changes: 3 additions & 1 deletion src/hooks/use-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ export function useAST() {
}

case "markdown": {
const { markdownMode, markdownFrontmatter } = markdownOptions;
const { markdownMode, markdownFrontmatter, markdownMath } =
markdownOptions;
const language = markdown.languages[markdownMode];
astParseResult = language.parse(
{ body: code.markdown, path: "", physicalPath: "", bom: false },
Expand All @@ -76,6 +77,7 @@ export function useAST() {
markdownFrontmatter === "off"
? false
: markdownFrontmatter,
math: markdownMath,
Comment thread
lumirlumir marked this conversation as resolved.
},
},
);
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/use-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type JsonOptions = {
export type MarkdownOptions = {
markdownMode: MarkdownMode;
markdownFrontmatter: MarkdownFrontmatter;
markdownMath: boolean;
};

Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a new field to MarkdownOptions can break existing persisted state: zustand persist merges state shallowly, so older markdownOptions objects will overwrite defaultMarkdownOptions and may omit markdownMath, yielding undefined at runtime. Consider adding a persist version + migrate/custom merge, or patching rehydrated markdownOptions to include markdownMath: false when missing.

Suggested change
type PersistedMarkdownOptions = Omit<MarkdownOptions, "markdownMath"> & {
markdownMath?: boolean;
};
export const normalizeMarkdownOptions = (
markdownOptions?: PersistedMarkdownOptions,
): MarkdownOptions => ({
...defaultMarkdownOptions,
...markdownOptions,
markdownMath: markdownOptions?.markdownMath ?? false,
});

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll dig into this problem a bit more in the near future.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:

image

export type CssOptions = {
Expand Down Expand Up @@ -287,6 +288,27 @@ export const useExplorer = create<ExplorerState>()(
if (needsPatching) {
state.setCode(patchedCode);
}

state.setJsOptions({
...defaultJsOptions,
...state.jsOptions,
});
state.setJsonOptions({
...defaultJsonOptions,
...state.jsonOptions,
});
state.setMarkdownOptions({
...defaultMarkdownOptions,
...state.markdownOptions,
});
state.setCssOptions({
...defaultCssOptions,
...state.cssOptions,
});
state.setHtmlOptions({
...defaultHtmlOptions,
...state.htmlOptions,
});
},
},
),
Expand Down
1 change: 1 addition & 0 deletions src/lib/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ export const defaultJsonOptions: JsonOptions = {
export const defaultMarkdownOptions: MarkdownOptions = {
markdownMode: "commonmark",
markdownFrontmatter: "off",
markdownMath: false,
};

export const defaultCssOptions: CssOptions = {
Expand Down