Emdash source with visual editor image upload fix

Fixes:
1. media.ts: wrap placeholder generation in try-catch
2. toolbar.ts: check r.ok, display error message in popover
This commit is contained in:
2026-05-03 10:44:54 +07:00
parent 78f81bebb6
commit 2d1be52177
2352 changed files with 662964 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
import { screen } from "@testing-library/react";
import Focus from "@tiptap/extension-focus";
import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import * as React from "react";
import { describe, it, expect, vi } from "vitest";
import { render } from "./utils/render.js";
// Test wrapper to render editor with Focus extension
function TestEditor({ spotlightMode = false }: { spotlightMode?: boolean }) {
const editor = useEditor({
extensions: [
StarterKit,
Focus.configure({
className: "has-focus",
mode: "all",
}),
],
content: `
<p>First paragraph</p>
<p>Second paragraph</p>
<p>Third paragraph</p>
`,
immediatelyRender: true,
});
if (!editor) return <div data-testid="loading">Loading...</div>;
return (
<div className={spotlightMode ? "spotlight-mode" : ""} data-testid="editor-wrapper">
<style>{`
.spotlight-mode .ProseMirror > *:not(.has-focus) {
opacity: 0.3;
transition: opacity 0.2s ease;
}
.spotlight-mode .ProseMirror > .has-focus {
opacity: 1;
transition: opacity 0.2s ease;
}
`}</style>
<EditorContent editor={editor} data-testid="editor-content" />
</div>
);
}
describe("Editor Focus Mode", () => {
it("Focus extension is configured correctly", async () => {
void render(<TestEditor />);
// Wait for editor to initialize (not just loading state)
await vi.waitFor(
() => {
const wrapper = screen.queryByTestId("editor-wrapper");
expect(wrapper).toBeTruthy();
},
{ timeout: 2000 },
);
const editorContent = screen.getByTestId("editor-content");
expect(editorContent).toBeDefined();
// The editor should be rendered with ProseMirror
const proseMirror = editorContent.querySelector(".ProseMirror");
expect(proseMirror).toBeTruthy();
// Verify the editor has the correct structure (3 paragraphs)
const paragraphs = proseMirror?.querySelectorAll("p");
expect(paragraphs?.length).toBe(3);
});
it("spotlight mode applies CSS class to editor wrapper", async () => {
void render(<TestEditor spotlightMode={true} />);
// Wait for editor to initialize
await vi.waitFor(
() => {
const wrapper = screen.queryByTestId("editor-wrapper");
expect(wrapper).toBeTruthy();
},
{ timeout: 2000 },
);
const wrapper = screen.getByTestId("editor-wrapper");
expect(wrapper.classList.contains("spotlight-mode")).toBe(true);
});
it("non-spotlight mode does not have spotlight-mode class", async () => {
void render(<TestEditor spotlightMode={false} />);
// Wait for editor to initialize
await vi.waitFor(
() => {
const wrapper = screen.queryByTestId("editor-wrapper");
expect(wrapper).toBeTruthy();
},
{ timeout: 2000 },
);
const wrapper = screen.getByTestId("editor-wrapper");
expect(wrapper.classList.contains("spotlight-mode")).toBe(false);
});
});
describe("Distraction-free mode state", () => {
it("can toggle between focus modes", () => {
// Simple state test - verifies the type and state pattern works
type FocusMode = "normal" | "spotlight";
let focusMode: FocusMode = "normal";
// Toggle to spotlight
focusMode = "spotlight";
expect(focusMode).toBe("spotlight");
// Toggle back to normal
focusMode = "normal";
expect(focusMode).toBe("normal");
});
});