diff --git a/packages/editor/core/src/styles/editor.css b/packages/editor/core/src/styles/editor.css index b0d2a1021..d0ab0fce8 100644 --- a/packages/editor/core/src/styles/editor.css +++ b/packages/editor/core/src/styles/editor.css @@ -123,7 +123,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { outline: none; cursor: text; line-height: 1.2; - font-family: inherit; + font-family: "system-ui"; font-size: 14px; color: inherit; -moz-box-sizing: border-box; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 5bfba3b0f..190731fe0 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -25,7 +25,8 @@ import { DeleteImage } from "src/types/delete-image"; import { IMentionSuggestion } from "src/types/mention-suggestion"; import { RestoreImage } from "src/types/restore-image"; import { CustomLinkExtension } from "src/ui/extensions/custom-link"; -import { CustomCodeInlineExtension } from "./code-inline"; +import { CustomCodeInlineExtension } from "src/ui/extensions/code-inline"; +import { CustomTypographyExtension } from "src/ui/extensions/typography"; export const CoreEditorExtensions = ( mentionConfig: { @@ -79,6 +80,7 @@ export const CoreEditorExtensions = ( "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", }, }), + CustomTypographyExtension, ImageExtension(deleteFile, restoreFile, cancelUploadImage).configure({ HTMLAttributes: { class: "rounded-lg border border-custom-border-300", diff --git a/packages/editor/core/src/ui/extensions/typography/index.ts b/packages/editor/core/src/ui/extensions/typography/index.ts new file mode 100644 index 000000000..78af3c46e --- /dev/null +++ b/packages/editor/core/src/ui/extensions/typography/index.ts @@ -0,0 +1,109 @@ +import { Extension } from "@tiptap/core"; +import { + TypographyOptions, + emDash, + ellipsis, + leftArrow, + rightArrow, + copyright, + trademark, + servicemark, + registeredTrademark, + oneHalf, + plusMinus, + notEqual, + laquo, + raquo, + multiplication, + superscriptTwo, + superscriptThree, + oneQuarter, + threeQuarters, + impliesArrowRight, +} from "src/ui/extensions/typography/inputRules"; + +export const CustomTypographyExtension = Extension.create({ + name: "typography", + + addInputRules() { + const rules = []; + + if (this.options.emDash !== false) { + rules.push(emDash(this.options.emDash)); + } + + if (this.options.impliesArrowRight !== false) { + rules.push(impliesArrowRight(this.options.impliesArrowRight)); + } + + if (this.options.ellipsis !== false) { + rules.push(ellipsis(this.options.ellipsis)); + } + + 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; + }, +}); diff --git a/packages/editor/core/src/ui/extensions/typography/inputRules.ts b/packages/editor/core/src/ui/extensions/typography/inputRules.ts new file mode 100644 index 000000000..f528e9242 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/typography/inputRules.ts @@ -0,0 +1,137 @@ +import { textInputRule } from "@tiptap/core"; + +export interface TypographyOptions { + emDash: false | string; + ellipsis: false | string; + leftArrow: false | string; + rightArrow: false | string; + copyright: false | string; + trademark: false | string; + servicemark: false | string; + registeredTrademark: false | string; + oneHalf: false | string; + plusMinus: false | string; + notEqual: false | string; + laquo: false | string; + raquo: false | string; + multiplication: false | string; + superscriptTwo: false | string; + superscriptThree: false | string; + oneQuarter: false | string; + threeQuarters: false | string; + impliesArrowRight: false | string; +} + +export const emDash = (override?: string) => + textInputRule({ + find: /--$/, + replace: override ?? "—", + }); + +export const impliesArrowRight = (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 ellipsis = (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 ?? "¾", + });