editor: fix circular import that dropped PubScript nodes from schema
The TipTap node definitions imported their node-name constants from schema.ts, while schema.ts imported the nodes to build the schema. This circular dependency evaluated the nodes before the constants were assigned, leaving sceneBreak/footnote/footnoteArea/characterMention with name 'undefined' — so they never registered in PubScriptSchema. As a result <hr class="scene-break"> parsed as StarterKit's horizontalRule instead of a scene break. - Move node-name constants, groups, MentionAttrs, and colorAttribute into a new constants.ts module that both schema.ts and the node files import from, breaking the cycle. - Remove the redundant separate History extension (already in StarterKit), which also silenced a TipTap 'Duplicate extension names: undoRedo' warn. - Drop unused TipTap extension and prosemirror-* deps (all access goes through @tiptap/pm).
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* PubScript keyboard map — the shortcuts the writing surface exposes to the
|
||||
* user, plus the ProseMirror keymap additions. Kept separate from the editor
|
||||
* instance so the command palette and toolbar can render the same bindings.
|
||||
*
|
||||
* The TipTap/StarterKit keymap (bold/italic/lists/undo/redo) is registered by
|
||||
* the extensions themselves; this module documents the PubScript-level
|
||||
* shortcuts and provides the heading-cycle helper.
|
||||
*/
|
||||
import type { Editor as TipTapEditor } from "@tiptap/core";
|
||||
|
||||
import { SCENE_BREAK } from "./schema.js";
|
||||
|
||||
export interface ShortcutDef {
|
||||
id: string;
|
||||
label: string;
|
||||
/** Human-readable binding, platform-aware. */
|
||||
binding: string;
|
||||
/** Execute the shortcut on the given editor. */
|
||||
run: (editor: TipTapEditor) => boolean | void;
|
||||
}
|
||||
|
||||
const MOD = typeof navigator !== "undefined" && navigator.platform.toLowerCase().includes("mac")
|
||||
? "⌘"
|
||||
: "Ctrl";
|
||||
|
||||
/**
|
||||
* Cycle the paragraph at the cursor through Heading 3 → Heading 2 → Heading 1
|
||||
* → Normal. Used by the writing surface's "cycle heading" shortcut.
|
||||
*/
|
||||
export function cycleHeading(editor: TipTapEditor): boolean {
|
||||
const { state } = editor;
|
||||
const { from } = state.selection;
|
||||
const parent = state.doc.resolve(from).parent;
|
||||
|
||||
// Only cycle paragraph / heading blocks.
|
||||
if (parent.type.name !== "paragraph" && parent.type.name !== "heading") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const level = editor.isActive("heading") ? (editor.getAttributes("heading") as { level: number }).level : 0;
|
||||
// 0 == paragraph. Cycle paragraph -> H3 -> H2 -> H1 -> paragraph.
|
||||
const next = level === 0 ? 3 : level === 3 ? 0 : level - 1;
|
||||
|
||||
if (next === 0) {
|
||||
editor.commands.setNode("paragraph");
|
||||
} else {
|
||||
editor.commands.toggleMark("heading", { level: next });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The documented PubScript shortcuts. The toolbar and command palette render
|
||||
* these so the UI and the actual bindings never drift.
|
||||
*/
|
||||
export const pubScriptShortcuts: ShortcutDef[] = [
|
||||
{
|
||||
id: "cycle-heading",
|
||||
label: "Cycle heading",
|
||||
binding: `${MOD}⇧H`,
|
||||
run: (editor) => cycleHeading(editor),
|
||||
},
|
||||
{
|
||||
id: "scene-break",
|
||||
label: "Insert scene break",
|
||||
binding: `${MOD}⇧⏎`,
|
||||
run: (editor) => {
|
||||
editor.commands.insertContent({ type: SCENE_BREAK });
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "bold",
|
||||
label: "Bold",
|
||||
binding: `${MOD}B`,
|
||||
run: (editor) => editor.commands.toggleMark("bold"),
|
||||
},
|
||||
{
|
||||
id: "italic",
|
||||
label: "Italic",
|
||||
binding: `${MOD}I`,
|
||||
run: (editor) => editor.commands.toggleMark("italic"),
|
||||
},
|
||||
{
|
||||
id: "strike",
|
||||
label: "Strikethrough",
|
||||
binding: `${MOD}S`,
|
||||
run: (editor) => editor.commands.toggleMark("strike"),
|
||||
},
|
||||
{
|
||||
id: "undo",
|
||||
label: "Undo",
|
||||
binding: `${MOD}Z`,
|
||||
run: (editor) => editor.commands.undo(),
|
||||
},
|
||||
{
|
||||
id: "redo",
|
||||
label: "Redo",
|
||||
binding: `${MOD}⇧Z`,
|
||||
run: (editor) => editor.commands.redo(),
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user