import { Extension, textInputRule } from '@tiptap/core' export interface TypographyOptions { /** * The em dash character. * @default '—' */ emDash: false | string /** * The ellipsis character. * @default '…' */ ellipsis: false | string /** * The open double quote character. * @default '“' */ openDoubleQuote: false | string /** * The close double quote character. * @default '”' */ closeDoubleQuote: false | string /** * The open single quote character. * @default '‘' */ openSingleQuote: false | string /** * The close single quote character. * @default '’' */ closeSingleQuote: false | string /** * The left arrow character. * @default '←' */ leftArrow: false | string /** * The right arrow character. * @default '→' */ rightArrow: false | string /** * The copyright character. * @default '©' */ copyright: false | string /** * The trademark character. * @default '™' */ trademark: false | string /** * The servicemark character. * @default '℠' */ servicemark: false | string /** * The registered trademark character. * @default '®' */ registeredTrademark: false | string /** * The one half character. * @default '½' */ oneHalf: false | string /** * The plus minus character. * @default '±' */ plusMinus: false | string /** * The not equal character. * @default '≠' */ notEqual: false | string /** * The laquo character. * @default '«' */ laquo: false | string /** * The raquo character. * @default '»' */ raquo: false | string /** * The multiplication character. * @default '×' */ multiplication: false | string /** * The superscript two character. * @default '²' */ superscriptTwo: false | string /** * The superscript three character. * @default '³' */ superscriptThree: false | string /** * The one quarter character. * @default '¼' */ oneQuarter: false | string /** * The three quarters character. * @default '¾' */ threeQuarters: false | string } export const emDash = (override?: string) => textInputRule({ find: /--$/, replace: override ?? '—', }) export const ellipsis = (override?: string) => textInputRule({ find: /\.\.\.$/, replace: override ?? '…', }) export const openDoubleQuote = (override?: string) => textInputRule({ find: /(?:^|[\s{[(<'"\u2018\u201C])(")$/, replace: override ?? '“', }) export const closeDoubleQuote = (override?: string) => textInputRule({ find: /"$/, replace: override ?? '”', }) export const openSingleQuote = (override?: string) => textInputRule({ find: /(?:^|[\s{[(<'"\u2018\u201C])(')$/, replace: override ?? '‘', }) export const closeSingleQuote = (override?: string) => textInputRule({ find: /'$/, replace: override ?? '’', }) export const leftArrow = (override?: string) => textInputRule({ find: /<-$/, replace: override ?? '←', }) export const rightArrow = (override?: string) => textInputRule({ find: /->$/, replace: override ?? '→', }) export const copyright = (override?: string) => textInputRule({ find: /\(c\)$/, replace: override ?? '©', }) export const trademark = (override?: string) => textInputRule({ find: /\(tm\)$/, replace: override ?? '™', }) export const servicemark = (override?: string) => textInputRule({ find: /\(sm\)$/, replace: override ?? '℠', }) export const registeredTrademark = (override?: string) => textInputRule({ find: /\(r\)$/, replace: override ?? '®', }) export const oneHalf = (override?: string) => textInputRule({ find: /(?:^|\s)(1\/2)\s$/, replace: override ?? '½', }) export const plusMinus = (override?: string) => textInputRule({ find: /\+\/-$/, replace: override ?? '±', }) export const notEqual = (override?: string) => textInputRule({ find: /!=$/, replace: override ?? '≠', }) export const laquo = (override?: string) => textInputRule({ find: /<<$/, replace: override ?? '«', }) export const raquo = (override?: string) => textInputRule({ find: />>$/, replace: override ?? '»', }) export const multiplication = (override?: string) => textInputRule({ find: /\d+\s?([*x])\s?\d+$/, replace: override ?? '×', }) export const superscriptTwo = (override?: string) => textInputRule({ find: /\^2$/, replace: override ?? '²', }) export const superscriptThree = (override?: string) => textInputRule({ find: /\^3$/, replace: override ?? '³', }) export const oneQuarter = (override?: string) => textInputRule({ find: /(?:^|\s)(1\/4)\s$/, replace: override ?? '¼', }) export const threeQuarters = (override?: string) => textInputRule({ find: /(?:^|\s)(3\/4)\s$/, replace: override ?? '¾', }) /** * This extension allows you to add typography replacements for specific characters. * @see https://www.tiptap.dev/api/extensions/typography */ export const Typography = Extension.create({ name: 'typography', addOptions() { return { closeDoubleQuote: '”', closeSingleQuote: '’', copyright: '©', ellipsis: '…', emDash: '—', laquo: '«', leftArrow: '←', multiplication: '×', notEqual: '≠', oneHalf: '½', oneQuarter: '¼', openDoubleQuote: '“', openSingleQuote: '‘', plusMinus: '±', raquo: '»', registeredTrademark: '®', rightArrow: '→', servicemark: '℠', superscriptThree: '³', superscriptTwo: '²', threeQuarters: '¾', trademark: '™', } }, addInputRules() { const rules = [] if (this.options.emDash !== false) { rules.push(emDash(this.options.emDash)) } if (this.options.ellipsis !== false) { rules.push(ellipsis(this.options.ellipsis)) } if (this.options.openDoubleQuote !== false) { rules.push(openDoubleQuote(this.options.openDoubleQuote)) } if (this.options.closeDoubleQuote !== false) { rules.push(closeDoubleQuote(this.options.closeDoubleQuote)) } if (this.options.openSingleQuote !== false) { rules.push(openSingleQuote(this.options.openSingleQuote)) } if (this.options.closeSingleQuote !== false) { rules.push(closeSingleQuote(this.options.closeSingleQuote)) } if (this.options.leftArrow !== false) { rules.push(leftArrow(this.options.leftArrow)) } if (this.options.rightArrow !== false) { rules.push(rightArrow(this.options.rightArrow)) } if (this.options.copyright !== false) { rules.push(copyright(this.options.copyright)) } if (this.options.trademark !== false) { rules.push(trademark(this.options.trademark)) } if (this.options.servicemark !== false) { rules.push(servicemark(this.options.servicemark)) } if (this.options.registeredTrademark !== false) { rules.push(registeredTrademark(this.options.registeredTrademark)) } if (this.options.oneHalf !== false) { rules.push(oneHalf(this.options.oneHalf)) } if (this.options.plusMinus !== false) { rules.push(plusMinus(this.options.plusMinus)) } if (this.options.notEqual !== false) { rules.push(notEqual(this.options.notEqual)) } if (this.options.laquo !== false) { rules.push(laquo(this.options.laquo)) } if (this.options.raquo !== false) { rules.push(raquo(this.options.raquo)) } if (this.options.multiplication !== false) { rules.push(multiplication(this.options.multiplication)) } if (this.options.superscriptTwo !== false) { rules.push(superscriptTwo(this.options.superscriptTwo)) } if (this.options.superscriptThree !== false) { rules.push(superscriptThree(this.options.superscriptThree)) } if (this.options.oneQuarter !== false) { rules.push(oneQuarter(this.options.oneQuarter)) } if (this.options.threeQuarters !== false) { rules.push(threeQuarters(this.options.threeQuarters)) } return rules }, })