You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
memos/web/src/components/MemoEditor/Editor/shortcuts.ts

71 lines
2.5 KiB
TypeScript

import type { EditorRefActions } from "./index";
const SHORTCUTS = {
BOLD: { key: "b", delimiter: "**" },
ITALIC: { key: "i", delimiter: "*" },
LINK: { key: "k" },
} as const;
const URL_PLACEHOLDER = "url";
const URL_REGEX = /^https?:\/\/[^\s]+$/;
const LINK_OFFSET = 3; // Length of "]()"
export function handleMarkdownShortcuts(event: React.KeyboardEvent, editor: EditorRefActions): void {
const key = event.key.toLowerCase();
if (key === SHORTCUTS.BOLD.key) {
event.preventDefault();
toggleTextStyle(editor, SHORTCUTS.BOLD.delimiter);
} else if (key === SHORTCUTS.ITALIC.key) {
event.preventDefault();
toggleTextStyle(editor, SHORTCUTS.ITALIC.delimiter);
} else if (key === SHORTCUTS.LINK.key) {
event.preventDefault();
insertHyperlink(editor);
}
}
export function insertHyperlink(editor: EditorRefActions, url?: string): void {
const cursorPosition = editor.getCursorPosition();
const selectedContent = editor.getSelectedContent();
const isUrlSelected = !url && URL_REGEX.test(selectedContent.trim());
if (isUrlSelected) {
editor.insertText(`[](${selectedContent})`);
editor.setCursorPosition(cursorPosition + 1, cursorPosition + 1);
return;
}
const href = url ?? URL_PLACEHOLDER;
editor.insertText(`[${selectedContent}](${href})`);
if (href === URL_PLACEHOLDER) {
const urlStart = cursorPosition + selectedContent.length + LINK_OFFSET;
editor.setCursorPosition(urlStart, urlStart + href.length);
}
}
function toggleTextStyle(editor: EditorRefActions, delimiter: string): void {
const cursorPosition = editor.getCursorPosition();
const selectedContent = editor.getSelectedContent();
const isStyled = selectedContent.startsWith(delimiter) && selectedContent.endsWith(delimiter);
if (isStyled) {
const unstyled = selectedContent.slice(delimiter.length, -delimiter.length);
editor.insertText(unstyled);
editor.setCursorPosition(cursorPosition, cursorPosition + unstyled.length);
} else {
editor.insertText(`${delimiter}${selectedContent}${delimiter}`);
editor.setCursorPosition(cursorPosition + delimiter.length, cursorPosition + delimiter.length + selectedContent.length);
}
}
export function hyperlinkHighlightedText(editor: EditorRefActions, url: string): void {
const selectedContent = editor.getSelectedContent();
const cursorPosition = editor.getCursorPosition();
editor.insertText(`[${selectedContent}](${url})`);
const newPosition = cursorPosition + selectedContent.length + url.length + 4;
editor.setCursorPosition(newPosition, newPosition);
}