From 4fe87d35e537f3d295a8985b27b3a23360afa2d5 Mon Sep 17 00:00:00 2001
From: bdbch <6538827+bdbch@users.noreply.github.com>
Date: Thu, 10 Aug 2023 20:30:56 -0700
Subject: [PATCH] add overrides to typography extension (#4287)
---
.../src/Extensions/Typography/React/index.jsx | 7 +-
.../TypographyWithOverrides/React/index.html | 0
.../TypographyWithOverrides/React/index.jsx | 25 +++
.../React/index.spec.js | 15 ++
.../TypographyWithOverrides/Vue/index.html | 0
.../TypographyWithOverrides/Vue/index.spec.js | 15 ++
.../TypographyWithOverrides/Vue/index.vue | 44 +++++
docs/api/extensions/typography.md | 18 ++
.../extension-typography/src/typography.ts | 176 +++++++++---------
9 files changed, 211 insertions(+), 89 deletions(-)
create mode 100644 demos/src/Extensions/TypographyWithOverrides/React/index.html
create mode 100644 demos/src/Extensions/TypographyWithOverrides/React/index.jsx
create mode 100644 demos/src/Extensions/TypographyWithOverrides/React/index.spec.js
create mode 100644 demos/src/Extensions/TypographyWithOverrides/Vue/index.html
create mode 100644 demos/src/Extensions/TypographyWithOverrides/Vue/index.spec.js
create mode 100644 demos/src/Extensions/TypographyWithOverrides/Vue/index.vue
diff --git a/demos/src/Extensions/Typography/React/index.jsx b/demos/src/Extensions/Typography/React/index.jsx
index 34d06f92a..002e59854 100644
--- a/demos/src/Extensions/Typography/React/index.jsx
+++ b/demos/src/Extensions/Typography/React/index.jsx
@@ -7,7 +7,12 @@ import React from 'react'
export default () => {
const editor = useEditor({
- extensions: [Document, Paragraph, Text, Typography],
+ extensions: [
+ Document,
+ Paragraph,
+ Text,
+ Typography,
+ ],
content: `
“I have been suffering from Typomania all my life, a sickness that is incurable but not lethal.”
— Erik Spiekermann, December 2008
diff --git a/demos/src/Extensions/TypographyWithOverrides/React/index.html b/demos/src/Extensions/TypographyWithOverrides/React/index.html
new file mode 100644
index 000000000..e69de29bb
diff --git a/demos/src/Extensions/TypographyWithOverrides/React/index.jsx b/demos/src/Extensions/TypographyWithOverrides/React/index.jsx
new file mode 100644
index 000000000..af305cbd7
--- /dev/null
+++ b/demos/src/Extensions/TypographyWithOverrides/React/index.jsx
@@ -0,0 +1,25 @@
+import Document from '@tiptap/extension-document'
+import Paragraph from '@tiptap/extension-paragraph'
+import Text from '@tiptap/extension-text'
+import Typography from '@tiptap/extension-typography'
+import { EditorContent, useEditor } from '@tiptap/react'
+import React from 'react'
+
+export default () => {
+ const editor = useEditor({
+ extensions: [
+ Document,
+ Paragraph,
+ Text,
+ Typography.configure({
+ rightArrow: '=====>',
+ }),
+ ],
+ content: `
+ “I have been suffering from Typomania all my life, a sickness that is incurable but not lethal.”
+ — Erik Spiekermann, December 2008
+ `,
+ })
+
+ return
+}
diff --git a/demos/src/Extensions/TypographyWithOverrides/React/index.spec.js b/demos/src/Extensions/TypographyWithOverrides/React/index.spec.js
new file mode 100644
index 000000000..8f3f99625
--- /dev/null
+++ b/demos/src/Extensions/TypographyWithOverrides/React/index.spec.js
@@ -0,0 +1,15 @@
+context('/src/Extensions/TypographyWithOverrides/React/', () => {
+ before(() => {
+ cy.visit('/src/Extensions/TypographyWithOverrides/React/')
+ })
+
+ beforeEach(() => {
+ cy.get('.tiptap').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+ })
+
+ it('should use correct override for rightArrow', () => {
+ cy.get('.tiptap').type('-> Hello!').should('contain', '=====> Hello!')
+ })
+})
diff --git a/demos/src/Extensions/TypographyWithOverrides/Vue/index.html b/demos/src/Extensions/TypographyWithOverrides/Vue/index.html
new file mode 100644
index 000000000..e69de29bb
diff --git a/demos/src/Extensions/TypographyWithOverrides/Vue/index.spec.js b/demos/src/Extensions/TypographyWithOverrides/Vue/index.spec.js
new file mode 100644
index 000000000..ec4851792
--- /dev/null
+++ b/demos/src/Extensions/TypographyWithOverrides/Vue/index.spec.js
@@ -0,0 +1,15 @@
+context('/src/Extensions/TypographyWithOverrides/Vue/', () => {
+ before(() => {
+ cy.visit('/src/Extensions/TypographyWithOverrides/Vue/')
+ })
+
+ beforeEach(() => {
+ cy.get('.tiptap').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+ })
+
+ it('should use correct override for rightArrow', () => {
+ cy.get('.tiptap').type('-> Hello!').should('contain', '=====> Hello!')
+ })
+})
diff --git a/demos/src/Extensions/TypographyWithOverrides/Vue/index.vue b/demos/src/Extensions/TypographyWithOverrides/Vue/index.vue
new file mode 100644
index 000000000..4912db8c4
--- /dev/null
+++ b/demos/src/Extensions/TypographyWithOverrides/Vue/index.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
diff --git a/docs/api/extensions/typography.md b/docs/api/extensions/typography.md
index aa3b068d9..56e441aa2 100644
--- a/docs/api/extensions/typography.md
+++ b/docs/api/extensions/typography.md
@@ -70,3 +70,21 @@ const editor = new Editor({
],
})
```
+
+### Overriding rules
+
+You can override the output of a rule by passing a string to the option you want to override.
+
+```js
+import { Editor } from '@tiptap/core'
+import Typography from '@tiptap/extension-typography'
+
+const editor = new Editor({
+ extensions: [
+ // Disable some included rules
+ Typography.configure({
+ oneHalf: "1 / 2", // this will insert "1 / 2" instead of the default "½"
+ }),
+ ],
+})
+```
diff --git a/packages/extension-typography/src/typography.ts b/packages/extension-typography/src/typography.ts
index 49c5b2379..4ce2f08ef 100644
--- a/packages/extension-typography/src/typography.ts
+++ b/packages/extension-typography/src/typography.ts
@@ -1,138 +1,138 @@
import { Extension, textInputRule } from '@tiptap/core'
export interface TypographyOptions {
- emDash: false,
- ellipsis: false,
- openDoubleQuote: false,
- closeDoubleQuote: false,
- openSingleQuote: false,
- closeSingleQuote: false,
- leftArrow: false,
- rightArrow: false,
- copyright: false,
- trademark: false,
- servicemark: false,
- registeredTrademark: false,
- oneHalf: false,
- plusMinus: false,
- notEqual: false,
- laquo: false,
- raquo: false,
- multiplication: false,
- superscriptTwo: false,
- superscriptThree: false,
- oneQuarter: false,
- threeQuarters: false,
+ emDash: false | string,
+ ellipsis: false | string,
+ openDoubleQuote: false | string,
+ closeDoubleQuote: false | string,
+ openSingleQuote: false | string,
+ closeSingleQuote: 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,
}
-export const emDash = textInputRule({
+export const emDash = (override?: string) => textInputRule({
find: /--$/,
- replace: '—',
+ replace: override ?? '—',
})
-export const ellipsis = textInputRule({
+export const ellipsis = (override?: string) => textInputRule({
find: /\.\.\.$/,
- replace: '…',
+ replace: override ?? '…',
})
-export const openDoubleQuote = textInputRule({
+export const openDoubleQuote = (override?: string) => textInputRule({
find: /(?:^|[\s{[(<'"\u2018\u201C])(")$/,
- replace: '“',
+ replace: override ?? '“',
})
-export const closeDoubleQuote = textInputRule({
+export const closeDoubleQuote = (override?: string) => textInputRule({
find: /"$/,
- replace: '”',
+ replace: override ?? '”',
})
-export const openSingleQuote = textInputRule({
+export const openSingleQuote = (override?: string) => textInputRule({
find: /(?:^|[\s{[(<'"\u2018\u201C])(')$/,
- replace: '‘',
+ replace: override ?? '‘',
})
-export const closeSingleQuote = textInputRule({
+export const closeSingleQuote = (override?: string) => textInputRule({
find: /'$/,
- replace: '’',
+ replace: override ?? '’',
})
-export const leftArrow = textInputRule({
+export const leftArrow = (override?: string) => textInputRule({
find: /<-$/,
- replace: '←',
+ replace: override ?? '←',
})
-export const rightArrow = textInputRule({
+export const rightArrow = (override?: string) => textInputRule({
find: /->$/,
- replace: '→',
+ replace: override ?? '→',
})
-export const copyright = textInputRule({
+export const copyright = (override?: string) => textInputRule({
find: /\(c\)$/,
- replace: '©',
+ replace: override ?? '©',
})
-export const trademark = textInputRule({
+export const trademark = (override?: string) => textInputRule({
find: /\(tm\)$/,
- replace: '™',
+ replace: override ?? '™',
})
-export const servicemark = textInputRule({
+export const servicemark = (override?: string) => textInputRule({
find: /\(sm\)$/,
- replace: '℠',
+ replace: override ?? '℠',
})
-export const registeredTrademark = textInputRule({
+export const registeredTrademark = (override?: string) => textInputRule({
find: /\(r\)$/,
- replace: '®',
+ replace: override ?? '®',
})
-export const oneHalf = textInputRule({
+export const oneHalf = (override?: string) => textInputRule({
find: /(?:^|\s)(1\/2)$/,
- replace: '½',
+ replace: override ?? '½',
})
-export const plusMinus = textInputRule({
+export const plusMinus = (override?: string) => textInputRule({
find: /\+\/-$/,
- replace: '±',
+ replace: override ?? '±',
})
-export const notEqual = textInputRule({
+export const notEqual = (override?: string) => textInputRule({
find: /!=$/,
- replace: '≠',
+ replace: override ?? '≠',
})
-export const laquo = textInputRule({
+export const laquo = (override?: string) => textInputRule({
find: /<<$/,
- replace: '«',
+ replace: override ?? '«',
})
-export const raquo = textInputRule({
+export const raquo = (override?: string) => textInputRule({
find: />>$/,
- replace: '»',
+ replace: override ?? '»',
})
-export const multiplication = textInputRule({
+export const multiplication = (override?: string) => textInputRule({
find: /\d+\s?([*x])\s?\d+$/,
- replace: '×',
+ replace: override ?? '×',
})
-export const superscriptTwo = textInputRule({
+export const superscriptTwo = (override?: string) => textInputRule({
find: /\^2$/,
- replace: '²',
+ replace: override ?? '²',
})
-export const superscriptThree = textInputRule({
+export const superscriptThree = (override?: string) => textInputRule({
find: /\^3$/,
- replace: '³',
+ replace: override ?? '³',
})
-export const oneQuarter = textInputRule({
+export const oneQuarter = (override?: string) => textInputRule({
find: /(?:^|\s)(1\/4)$/,
- replace: '¼',
+ replace: override ?? '¼',
})
-export const threeQuarters = textInputRule({
+export const threeQuarters = (override?: string) => textInputRule({
find: /(?:^|\s)(3\/4)$/,
- replace: '¾',
+ replace: override ?? '¾',
})
export const Typography = Extension.create({
@@ -142,91 +142,91 @@ export const Typography = Extension.create({
const rules = []
if (this.options.emDash !== false) {
- rules.push(emDash)
+ rules.push(emDash(this.options.emDash))
}
if (this.options.ellipsis !== false) {
- rules.push(ellipsis)
+ rules.push(ellipsis(this.options.ellipsis))
}
if (this.options.openDoubleQuote !== false) {
- rules.push(openDoubleQuote)
+ rules.push(openDoubleQuote(this.options.openDoubleQuote))
}
if (this.options.closeDoubleQuote !== false) {
- rules.push(closeDoubleQuote)
+ rules.push(closeDoubleQuote(this.options.closeDoubleQuote))
}
if (this.options.openSingleQuote !== false) {
- rules.push(openSingleQuote)
+ rules.push(openSingleQuote(this.options.openSingleQuote))
}
if (this.options.closeSingleQuote !== false) {
- rules.push(closeSingleQuote)
+ rules.push(closeSingleQuote(this.options.closeSingleQuote))
}
if (this.options.leftArrow !== false) {
- rules.push(leftArrow)
+ rules.push(leftArrow(this.options.leftArrow))
}
if (this.options.rightArrow !== false) {
- rules.push(rightArrow)
+ rules.push(rightArrow(this.options.rightArrow))
}
if (this.options.copyright !== false) {
- rules.push(copyright)
+ rules.push(copyright(this.options.copyright))
}
if (this.options.trademark !== false) {
- rules.push(trademark)
+ rules.push(trademark(this.options.trademark))
}
if (this.options.servicemark !== false) {
- rules.push(servicemark)
+ rules.push(servicemark(this.options.servicemark))
}
if (this.options.registeredTrademark !== false) {
- rules.push(registeredTrademark)
+ rules.push(registeredTrademark(this.options.registeredTrademark))
}
if (this.options.oneHalf !== false) {
- rules.push(oneHalf)
+ rules.push(oneHalf(this.options.oneHalf))
}
if (this.options.plusMinus !== false) {
- rules.push(plusMinus)
+ rules.push(plusMinus(this.options.plusMinus))
}
if (this.options.notEqual !== false) {
- rules.push(notEqual)
+ rules.push(notEqual(this.options.notEqual))
}
if (this.options.laquo !== false) {
- rules.push(laquo)
+ rules.push(laquo(this.options.laquo))
}
if (this.options.raquo !== false) {
- rules.push(raquo)
+ rules.push(raquo(this.options.raquo))
}
if (this.options.multiplication !== false) {
- rules.push(multiplication)
+ rules.push(multiplication(this.options.multiplication))
}
if (this.options.superscriptTwo !== false) {
- rules.push(superscriptTwo)
+ rules.push(superscriptTwo(this.options.superscriptTwo))
}
if (this.options.superscriptThree !== false) {
- rules.push(superscriptThree)
+ rules.push(superscriptThree(this.options.superscriptThree))
}
if (this.options.oneQuarter !== false) {
- rules.push(oneQuarter)
+ rules.push(oneQuarter(this.options.oneQuarter))
}
if (this.options.threeQuarters !== false) {
- rules.push(threeQuarters)
+ rules.push(threeQuarters(this.options.threeQuarters))
}
return rules