mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-12 21:00:02 +08:00
feature: add subscript and superscript extensions, docs and tests
This commit is contained in:
parent
7387eaf51b
commit
3f57a13d19
42
docs/src/demos/Marks/Subscript/index.spec.js
Normal file
42
docs/src/demos/Marks/Subscript/index.spec.js
Normal file
@ -0,0 +1,42 @@
|
||||
context('/demos/Marks/Subscript', () => {
|
||||
before(() => {
|
||||
cy.visit('/demos/Marks/Subscript')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Example Text</p>')
|
||||
cy.get('.ProseMirror').type('{selectall}')
|
||||
})
|
||||
})
|
||||
|
||||
it('should transform inline style to sub tags', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p><span style="vertical-align: middle">Example Text</span></p>')
|
||||
expect(editor.getHTML()).to.eq('<p><sub>Example Text</sub></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('sould omit inline style with a different vertical align', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p><b style="vertical-align: middle">Example Text</b></p>')
|
||||
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('the button should make the selected text bold', () => {
|
||||
cy.get('button:first')
|
||||
.click()
|
||||
|
||||
cy.get('.ProseMirror')
|
||||
.find('sub')
|
||||
.should('contain', 'Example Text')
|
||||
})
|
||||
|
||||
it('the button should toggle the selected text bold', () => {
|
||||
cy.get('button:first').click()
|
||||
cy.get('.ProseMirror').type('{selectall}')
|
||||
cy.get('button:first').click()
|
||||
cy.get('.ProseMirror sub').should('not.exist')
|
||||
})
|
||||
})
|
49
docs/src/demos/Marks/Subscript/index.vue
Normal file
49
docs/src/demos/Marks/Subscript/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleSubscript().run()" :class="{ 'is-active': editor.isActive('subscript') }">
|
||||
subscript
|
||||
</button>
|
||||
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||
import Document from '@tiptap/extension-document'
|
||||
import Paragraph from '@tiptap/extension-paragraph'
|
||||
import Text from '@tiptap/extension-text'
|
||||
import Subscript from '@tiptap/extension-subscript'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Subscript,
|
||||
],
|
||||
content: `
|
||||
<p>This is regular text.</p>
|
||||
<p><sub>This is subscript.</sub></p>
|
||||
<p><span style="vertical-align: sub">And this.</span></p>
|
||||
`,
|
||||
})
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
}
|
||||
</script>
|
42
docs/src/demos/Marks/Superscript/index.spec.js
Normal file
42
docs/src/demos/Marks/Superscript/index.spec.js
Normal file
@ -0,0 +1,42 @@
|
||||
context('/demos/Marks/Superscript', () => {
|
||||
before(() => {
|
||||
cy.visit('/demos/Marks/Superscript')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Example Text</p>')
|
||||
cy.get('.ProseMirror').type('{selectall}')
|
||||
})
|
||||
})
|
||||
|
||||
it('should transform inline style to sup tags', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p><span style="vertical-align: super">Example Text</span></p>')
|
||||
expect(editor.getHTML()).to.eq('<p><sup>Example Text</sup></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('sould omit inline style with a different vertical align', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p><span style="vertical-align: middle">Example Text</span></p>')
|
||||
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('the button should make the selected text bold', () => {
|
||||
cy.get('button:first')
|
||||
.click()
|
||||
|
||||
cy.get('.ProseMirror')
|
||||
.find('sup')
|
||||
.should('contain', 'Example Text')
|
||||
})
|
||||
|
||||
it('the button should toggle the selected text bold', () => {
|
||||
cy.get('button:first').click()
|
||||
cy.get('.ProseMirror').type('{selectall}')
|
||||
cy.get('button:first').click()
|
||||
cy.get('.ProseMirror sup').should('not.exist')
|
||||
})
|
||||
})
|
49
docs/src/demos/Marks/Superscript/index.vue
Normal file
49
docs/src/demos/Marks/Superscript/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleSuperscript().run()" :class="{ 'is-active': editor.isActive('superscript') }">
|
||||
superscript
|
||||
</button>
|
||||
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||
import Document from '@tiptap/extension-document'
|
||||
import Paragraph from '@tiptap/extension-paragraph'
|
||||
import Text from '@tiptap/extension-text'
|
||||
import Superscript from '@tiptap/extension-superscript'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Superscript,
|
||||
],
|
||||
content: `
|
||||
<p>This is regular text.</p>
|
||||
<p><sup>This is superscript.</sup></p>
|
||||
<p><span style="vertical-align: super">And this.</span></p>
|
||||
`,
|
||||
})
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
}
|
||||
</script>
|
@ -7,12 +7,14 @@ One or multiple marks can be applied to [nodes](/api/nodes), for example to add
|
||||
|
||||
## List of supported marks
|
||||
| Title | Default Extension | Source Code |
|
||||
| ---------------------------------- | ----------------- | -------------------------------------------------------------------------------------------- |
|
||||
| ------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------- |
|
||||
| [Bold](/api/marks/bold) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-bold/) |
|
||||
| [Code](/api/marks/code) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-code/) |
|
||||
| [Highlight](/api/marks/highlight) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-highlight/) |
|
||||
| [Italic](/api/marks/italic) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-italic/) |
|
||||
| [Link](/api/marks/link) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-link/) |
|
||||
| [Strike](/api/marks/strike) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-strike/) |
|
||||
| [Subscript](/api/marks/subscript) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-subscript/) |
|
||||
| [Superscript](/api/marks/superscript) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-superscript/) |
|
||||
| [TextStyle](/api/marks/text-style) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-text-style/) |
|
||||
| [Underline](/api/marks/underline) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-underline/) |
|
||||
|
32
docs/src/docPages/api/marks/subscript.md
Normal file
32
docs/src/docPages/api/marks/subscript.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Subscript
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-subscript)
|
||||
[](https://npmcharts.com/compare/@tiptap/extension-subscript?minimal=true)
|
||||
|
||||
Use this extension to render text in <sub>subscript</sub>. If you pass `<sub>` or text with `vertical-align: sub` as inline style in the editor’s initial content, both will be normalized to a `<sub>` HTML tag.
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
# with npm
|
||||
npm install @tiptap/extension-subscript
|
||||
|
||||
# with Yarn
|
||||
yarn add @tiptap/extension-subscript
|
||||
```
|
||||
|
||||
## Settings
|
||||
| Option | Type | Default | Description |
|
||||
| -------------- | -------- | ------- | --------------------------------------------------------------------- |
|
||||
| HTMLAttributes | `Object` | `{}` | Custom HTML attributes that should be added to the rendered HTML tag. |
|
||||
|
||||
## Commands
|
||||
| Command | Parameters | Description |
|
||||
| --------------- | ---------- | ------------------------- |
|
||||
| setSubscript | — | Mark text as subscript. |
|
||||
| toggleSubscript | — | Toggle subscript mark. |
|
||||
| unsetSubscript | — | Remove subscript mark. |
|
||||
|
||||
## Source code
|
||||
[packages/extension-subscript/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-subscript/)
|
||||
|
||||
## Usage
|
||||
<demo name="Marks/Subscript" highlight="3-5,16,35" />
|
32
docs/src/docPages/api/marks/superscript.md
Normal file
32
docs/src/docPages/api/marks/superscript.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Superscript
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-superscript)
|
||||
[](https://npmcharts.com/compare/@tiptap/extension-superscript?minimal=true)
|
||||
|
||||
Use this extension to render text in <sup>superscript</sup>. If you pass `<sup>` or text with `vertical-align: super` as inline style in the editor’s initial content, both will be normalized to a `<sup>` HTML tag.
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
# with npm
|
||||
npm install @tiptap/extension-superscript
|
||||
|
||||
# with Yarn
|
||||
yarn add @tiptap/extension-superscript
|
||||
```
|
||||
|
||||
## Settings
|
||||
| Option | Type | Default | Description |
|
||||
| -------------- | -------- | ------- | --------------------------------------------------------------------- |
|
||||
| HTMLAttributes | `Object` | `{}` | Custom HTML attributes that should be added to the rendered HTML tag. |
|
||||
|
||||
## Commands
|
||||
| Command | Parameters | Description |
|
||||
| ----------------- | ---------- | ------------------------- |
|
||||
| setSuperscript | — | Mark text as superscript. |
|
||||
| toggleSuperscript | — | Toggle superscript mark. |
|
||||
| unsetSuperscript | — | Remove superscript mark. |
|
||||
|
||||
## Source code
|
||||
[packages/extension-superscript/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-superscript/)
|
||||
|
||||
## Usage
|
||||
<demo name="Marks/Superscript" highlight="3-5,17,36" />
|
@ -320,6 +320,12 @@
|
||||
link: /api/marks/link
|
||||
- title: Strike
|
||||
link: /api/marks/strike
|
||||
- title: Subscript
|
||||
link: /api/marks/subscript
|
||||
type: new
|
||||
- title: Superscript
|
||||
link: /api/marks/superscript
|
||||
type: new
|
||||
- title: TextStyle
|
||||
link: /api/marks/text-style
|
||||
- title: Underline
|
||||
|
14
packages/extension-subscript/README.md
Normal file
14
packages/extension-subscript/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# @tiptap/extension-superscript
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-superscript)
|
||||
[](https://npmcharts.com/compare/tiptap?minimal=true)
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-superscript)
|
||||
[](https://github.com/sponsors/ueberdosis)
|
||||
|
||||
## Introduction
|
||||
tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
|
||||
|
||||
## Official Documentation
|
||||
Documentation can be found on the [tiptap website](https://tiptap.dev).
|
||||
|
||||
## License
|
||||
tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
|
26
packages/extension-subscript/package.json
Normal file
26
packages/extension-subscript/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@tiptap/extension-subscript",
|
||||
"description": "subscript extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
"tiptap extension"
|
||||
],
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"main": "dist/tiptap-extension-subscript.cjs.js",
|
||||
"umd": "dist/tiptap-extension-subscript.umd.js",
|
||||
"module": "dist/tiptap-extension-subscript.esm.js",
|
||||
"types": "dist/packages/extension-subscript/src/index.d.ts",
|
||||
"files": [
|
||||
"src",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.0.0-beta.1"
|
||||
}
|
||||
}
|
5
packages/extension-subscript/src/index.ts
Normal file
5
packages/extension-subscript/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Subscript } from './subscript'
|
||||
|
||||
export * from './subscript'
|
||||
|
||||
export default Subscript
|
69
packages/extension-subscript/src/subscript.ts
Normal file
69
packages/extension-subscript/src/subscript.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Command, Mark, mergeAttributes } from '@tiptap/core'
|
||||
|
||||
export interface SubscriptExtensionOptions {
|
||||
HTMLAttributes: Object,
|
||||
}
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands {
|
||||
subscript: {
|
||||
/**
|
||||
* Set a subscript mark
|
||||
*/
|
||||
setSubscript: () => Command,
|
||||
/**
|
||||
* Toggle a subscript mark
|
||||
*/
|
||||
toggleSubscript: () => Command,
|
||||
/**
|
||||
* Unset a subscript mark
|
||||
*/
|
||||
unsetSubscript: () => Command,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Subscript = Mark.create<SubscriptExtensionOptions>({
|
||||
name: 'subscript',
|
||||
|
||||
defaultOptions: {
|
||||
HTMLAttributes: {},
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: 'sub',
|
||||
},
|
||||
{
|
||||
style: 'vertical-align',
|
||||
getAttrs(value) {
|
||||
// Don’t match this rule if the vertical align isn’t sub.
|
||||
if (value !== 'sub') {
|
||||
return false
|
||||
}
|
||||
|
||||
// If it falls through we’ll match, and this mark will be applied.
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['sub', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setSubscript: () => ({ commands }) => {
|
||||
return commands.setMark('subscript')
|
||||
},
|
||||
toggleSubscript: () => ({ commands }) => {
|
||||
return commands.toggleMark('subscript')
|
||||
},
|
||||
unsetSubscript: () => ({ commands }) => {
|
||||
return commands.unsetMark('subscript')
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
14
packages/extension-superscript/README.md
Normal file
14
packages/extension-superscript/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# @tiptap/extension-superscript
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-superscript)
|
||||
[](https://npmcharts.com/compare/tiptap?minimal=true)
|
||||
[](https://www.npmjs.com/package/@tiptap/extension-superscript)
|
||||
[](https://github.com/sponsors/ueberdosis)
|
||||
|
||||
## Introduction
|
||||
tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
|
||||
|
||||
## Official Documentation
|
||||
Documentation can be found on the [tiptap website](https://tiptap.dev).
|
||||
|
||||
## License
|
||||
tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
|
26
packages/extension-superscript/package.json
Normal file
26
packages/extension-superscript/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@tiptap/extension-superscript",
|
||||
"description": "superscript extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
"tiptap extension"
|
||||
],
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"main": "dist/tiptap-extension-superscript.cjs.js",
|
||||
"umd": "dist/tiptap-extension-superscript.umd.js",
|
||||
"module": "dist/tiptap-extension-superscript.esm.js",
|
||||
"types": "dist/packages/extension-superscript/src/index.d.ts",
|
||||
"files": [
|
||||
"src",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.0.0-beta.1"
|
||||
}
|
||||
}
|
5
packages/extension-superscript/src/index.ts
Normal file
5
packages/extension-superscript/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Superscript } from './superscript'
|
||||
|
||||
export * from './superscript'
|
||||
|
||||
export default Superscript
|
69
packages/extension-superscript/src/superscript.ts
Normal file
69
packages/extension-superscript/src/superscript.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Command, Mark, mergeAttributes } from '@tiptap/core'
|
||||
|
||||
export interface SuperscriptExtensionOptions {
|
||||
HTMLAttributes: Object,
|
||||
}
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands {
|
||||
superscript: {
|
||||
/**
|
||||
* Set a superscript mark
|
||||
*/
|
||||
setSuperscript: () => Command,
|
||||
/**
|
||||
* Toggle a superscript mark
|
||||
*/
|
||||
toggleSuperscript: () => Command,
|
||||
/**
|
||||
* Unset a superscript mark
|
||||
*/
|
||||
unsetSuperscript: () => Command,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Superscript = Mark.create<SuperscriptExtensionOptions>({
|
||||
name: 'superscript',
|
||||
|
||||
defaultOptions: {
|
||||
HTMLAttributes: {},
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: 'sup',
|
||||
},
|
||||
{
|
||||
style: 'vertical-align',
|
||||
getAttrs(value) {
|
||||
// Don’t match this rule if the vertical align isn’t super.
|
||||
if (value !== 'super') {
|
||||
return false
|
||||
}
|
||||
|
||||
// If it falls through we’ll match, and this mark will be applied.
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['sup', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setSuperscript: () => ({ commands }) => {
|
||||
return commands.setMark('superscript')
|
||||
},
|
||||
toggleSuperscript: () => ({ commands }) => {
|
||||
return commands.toggleMark('superscript')
|
||||
},
|
||||
unsetSuperscript: () => ({ commands }) => {
|
||||
return commands.unsetMark('superscript')
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue
Block a user