import { LinkAttr, LinkAttrs, schema } from "./schema"; import { textblockTypeTextShortcut } from "./textshortcut/textblockTypeTextShortcut"; import { TextShortcut, TextShortcutPlugin } from "./textshortcut/TextShortcutPlugin"; import { wrappingTextShortcut } from "./textshortcut/wrappingTextShortcut"; export const textShortcutsPlugin = new TextShortcutPlugin([ wrappingTextShortcut(/^\s*([-+*])\s$/, schema.nodes.ul), wrappingTextShortcut(/^\s*(1\.)\s$/, schema.nodes.ol), wrappingTextShortcut(/^\s*>\s$/, schema.nodes.bq), textblockTypeTextShortcut(/^\s*(#+)\s$/, schema.nodes.h, match => ({ // The heading level is the number of #, capped at 2 (we only support two // levels of heading). l: Math.min(match[1].length, 2) })), new TextShortcut(/^(--|—)-$/, (state, _, start, end) => { return state.tr.replaceWith(start - 1, end, state.schema.nodes.hr.create()).scrollIntoView(); }), /** * http: https: mailto: URLs */ new TextShortcut(/(\ufffc|\s|^)((?:https?:\/\/|mailto:)[^\s]*)(?:\s|\u2403)$/, (state, match, start, end, insertText) => { const [, prefix, url] = match; const linkAttrs: LinkAttrs = { [LinkAttr.URL]: url }; const link = state.schema.marks.l.create(linkAttrs); const urlBeforePos = start + prefix.length; const urlAfterPos = end; const tr = state.tr; tr.addMark(urlBeforePos, urlAfterPos, link); if (url.startsWith("mailto:")) { tr.delete(urlBeforePos, urlBeforePos + "mailto:".length); } if (insertText.length > 0) { tr.insertText(insertText); } return tr; }), /** * Email address */ new TextShortcut( // Elaborate regex taken from http://emailregex.com/ /(\s|^)((([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,})))(\s)$/, (state, match, start) => { const [, prefix, email] = match; const suffix = match[match.length - 1]; const linkAttrs: LinkAttrs = { [LinkAttr.URL]: `mailto:${email}` }; const link = state.schema.marks.l.create(linkAttrs); const emailBeforePos = start + prefix.length; const emailAfterPos = emailBeforePos + email.length; const tr = state.tr; tr.addMark(emailBeforePos, emailAfterPos, link); if (suffix.length > 0) { tr.insertText(suffix); } return tr; } ), // “Smart” opening double quotes. new TextShortcut(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/, "“"), // “Smart” closing double quotes. new TextShortcut(/"$/, "”"), // “Smart” opening single quotes. new TextShortcut(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/, "‘"), // “Smart” closing single quotes. new TextShortcut(/'$/, "’"), // Converts three dots to an ellipsis character. new TextShortcut(/\.\.\.$/, "…"), // Converts double dashes to an emdash. new TextShortcut(/--$/, "—") ]);