Skip to content

Commit

Permalink
feat(text-style): add mergeNestedSpanStyles option to merge nested …
Browse files Browse the repository at this point in the history
…spans #5720 (#5897)
  • Loading branch information
mieze018 authored Dec 3, 2024
1 parent b5cb313 commit a0d2f28
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/tasty-sheep-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tiptap/extension-text-style": minor
---

Added `mergeNestedSpanStyles` option to the `TextStyle` extension to address issue #5720
83 changes: 82 additions & 1 deletion demos/src/Marks/TextStyle/React/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import './styles.scss'

import Bold from '@tiptap/extension-bold'
import { Color } from '@tiptap/extension-color'
import Document from '@tiptap/extension-document'
import { FontFamily } from '@tiptap/extension-font-family'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import TextStyle from '@tiptap/extension-text-style'
Expand All @@ -9,10 +12,88 @@ import React from 'react'

export default () => {
const editor = useEditor({
extensions: [Document, Paragraph, Text, TextStyle],
extensions: [
Document,
Paragraph,
Text,
TextStyle.configure({ mergeNestedSpanStyles: true }),
Color,
Bold,
FontFamily,
],
content: `
<p><span>This has a &lt;span&gt; tag without a style attribute, so it’s thrown away.</span></p>
<p><span style="">But this one is wrapped in a &lt;span&gt; tag with an inline style attribute, so it’s kept - even if it’s empty for now.</span></p>
<p>--- merge nested span styles option enabled ---</p>
<p>
<span style="color: #FF0000;">
<span style="font-family: serif;">
red serif
</span>
</span>
</p>
<p>
<span style="color: #FF0000;">
<span style="font-family: serif;">
<span style="color: #0000FF;">
blue serif
</span>
</span>
</span>
</p>
<p>
<span style="color: #00FF00;">
<span style="font-family: serif;">green serif </span>
<span style="font-family: serif;color: #ff0000;">red serif</span>
</span>
</p>
<p>
<span>
plain
<span style="color: #0000FF;">blue</span>
plain
<span style="color: #00FF00;">
green
<span style="font-family: serif;">green serif</span>
</span>
plain
</span>
</p>
<p>
<span style="color: #0000FF;">
blue
<span style="color: #00FF00;">
green
<span style="font-family: serif;">
green serif
<span style="color: #0000FF;">blue serif</span>
</span>
</span>
</span>
</p>
<p>
<strong>
strong
<span style="color: #0000FF;">
<strong>
strong blue
<span style="font-size: 24px;font-family: serif;">strong blue serif </span>
<span style="color: #00FF00;">
strong green
<span style="font-family: serif;">strong green serif</span>
</span>
</strong>
</span>
</strong>
</p>
`,
})

Expand Down
77 changes: 76 additions & 1 deletion demos/src/Marks/TextStyle/React/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,80 @@ context('/src/Marks/TextStyle/React/', () => {
cy.visit('/src/Marks/TextStyle/React/')
})

// TODO: Write tests
describe('mergeNestedSpanStyles', () => {
it('should merge styles of a span with one child span', () => {
cy.get('.tiptap > p:nth-child(4) > span')
.should('have.length', 1)
.and('have.text', 'red serif')
.and('have.attr', 'style', 'color: rgb(255, 0, 0); font-family: serif')
})
it('should merge styles of a span with one nested child span into the descendant span', () => {
cy.get('.tiptap > p:nth-child(5) > span')
.should('have.length', 1)
.and('have.text', 'blue serif')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
})
it('should merge styles of a span with multiple child spans into all child spans', () => {
cy.get('.tiptap > p:nth-child(6) > span').should('have.length', 2)
cy.get('.tiptap > p:nth-child(6) > span:nth-child(1)')
.should('have.text', 'green serif ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
cy.get('.tiptap > p:nth-child(6) > span:nth-child(2)')
.should('have.text', 'red serif')
.and('have.attr', 'style', 'color: rgb(255, 0, 0); font-family: serif')
})
it('should merge styles of descendant spans into each descendant span when the parent span has no style', () => {
cy.get('.tiptap > p:nth-child(7) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(7) > span:nth-child(1)')
.should('have.text', 'blue')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
cy.get('.tiptap > p:nth-child(7) > span:nth-child(2)')
.should('have.text', 'green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
cy.get('.tiptap > p:nth-child(7) > span:nth-child(3)')
.should('have.text', 'green serif')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
})
it('should merge styles of a span with nested root text and descendant spans into each descendant span', () => {
cy.get('.tiptap > p:nth-child(8) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(8) > span:nth-child(1)')
.should('have.text', 'blue ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(2)')
.should('have.text', 'green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(3)')
.should('have.text', 'green serif ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(4)')
.should('have.text', 'blue serif')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
})
it('should merge styles of descendant spans into each descendant span when the parent span has other tags', () => {
cy.get('.tiptap > p:nth-child(9) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(9) > :nth-child(1)')
.should('have.prop', 'tagName', 'STRONG')
.and('have.text', 'strong ')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(2)')
.should('have.text', 'strong blue ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(3)')
.should('have.text', 'strong blue serif ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(4)')
.should('have.text', 'strong green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(5)')
.should('have.text', 'strong green serif')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
.find('strong')
.should('exist')
})
})
})
77 changes: 76 additions & 1 deletion demos/src/Marks/TextStyle/Vue/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,80 @@ context('/src/Marks/TextStyle/Vue/', () => {
cy.visit('/src/Marks/TextStyle/Vue/')
})

// TODO: Write tests
describe('mergeNestedSpanStyles', () => {
it('should merge styles of a span with one child span', () => {
cy.get('.tiptap > p:nth-child(4) > span')
.should('have.length', 1)
.and('have.text', 'red serif')
.and('have.attr', 'style', 'color: rgb(255, 0, 0); font-family: serif')
})
it('should merge styles of a span with one nested child span into the descendant span', () => {
cy.get('.tiptap > p:nth-child(5) > span')
.should('have.length', 1)
.and('have.text', 'blue serif')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
})
it('should merge styles of a span with multiple child spans into all child spans', () => {
cy.get('.tiptap > p:nth-child(6) > span').should('have.length', 2)
cy.get('.tiptap > p:nth-child(6) > span:nth-child(1)')
.should('have.text', 'green serif ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
cy.get('.tiptap > p:nth-child(6) > span:nth-child(2)')
.should('have.text', 'red serif')
.and('have.attr', 'style', 'color: rgb(255, 0, 0); font-family: serif')
})
it('should merge styles of descendant spans into each descendant span when the parent span has no style', () => {
cy.get('.tiptap > p:nth-child(7) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(7) > span:nth-child(1)')
.should('have.text', 'blue')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
cy.get('.tiptap > p:nth-child(7) > span:nth-child(2)')
.should('have.text', 'green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
cy.get('.tiptap > p:nth-child(7) > span:nth-child(3)')
.should('have.text', 'green serif')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
})
it('should merge styles of a span with nested root text and descendant spans into each descendant span', () => {
cy.get('.tiptap > p:nth-child(8) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(8) > span:nth-child(1)')
.should('have.text', 'blue ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(2)')
.should('have.text', 'green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(3)')
.should('have.text', 'green serif ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
cy.get('.tiptap > p:nth-child(8) > span:nth-child(4)')
.should('have.text', 'blue serif')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
})
it('should merge styles of descendant spans into each descendant span when the parent span has other tags', () => {
cy.get('.tiptap > p:nth-child(9) > span').should('have.length', 4)
cy.get('.tiptap > p:nth-child(9) > :nth-child(1)')
.should('have.prop', 'tagName', 'STRONG')
.and('have.text', 'strong ')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(2)')
.should('have.text', 'strong blue ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255)')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(3)')
.should('have.text', 'strong blue serif ')
.and('have.attr', 'style', 'color: rgb(0, 0, 255); font-family: serif')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(4)')
.should('have.text', 'strong green ')
.and('have.attr', 'style', 'color: rgb(0, 255, 0)')
.find('strong')
.should('exist')
cy.get('.tiptap > p:nth-child(9) > span:nth-child(5)')
.should('have.text', 'strong green serif')
.and('have.attr', 'style', 'color: rgb(0, 255, 0); font-family: serif')
.find('strong')
.should('exist')
})
})
})
78 changes: 77 additions & 1 deletion demos/src/Marks/TextStyle/Vue/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
</template>

<script>
import Bold from '@tiptap/extension-bold'
import { Color } from '@tiptap/extension-color'
import Document from '@tiptap/extension-document'
import { FontFamily } from '@tiptap/extension-font-family'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import TextStyle from '@tiptap/extension-text-style'
Expand All @@ -28,11 +31,84 @@ export default {
Document,
Paragraph,
Text,
TextStyle,
TextStyle.configure({ mergeNestedSpanStyles: true }),
Color,
Bold,
FontFamily,
],
content: `
<p><span>This has a &lt;span&gt; tag without a style attribute, so it’s thrown away.</span></p>
<p><span style="">But this one is wrapped in a &lt;span&gt; tag with an inline style attribute, so it’s kept - even if it’s empty for now.</span></p>
<p>--- merge nested span styles option enabled ---</p>
<p>
<span style="color: #FF0000;">
<span style="font-family: serif;">
red serif
</span>
</span>
</p>
<p>
<span style="color: #FF0000;">
<span style="font-family: serif;">
<span style="color: #0000FF;">
blue serif
</span>
</span>
</span>
</p>
<p>
<span style="color: #00FF00;">
<span style="font-family: serif;">green serif </span>
<span style="font-family: serif;color: #ff0000;">red serif</span>
</span>
</p>
<p>
<span>
plain
<span style="color: #0000FF;">blue</span>
plain
<span style="color: #00FF00;">
green
<span style="font-family: serif;">green serif</span>
</span>
plain
</span>
</p>
<p>
<span style="color: #0000FF;">
blue
<span style="color: #00FF00;">
green
<span style="font-family: serif;">
green serif
<span style="color: #0000FF;">blue serif</span>
</span>
</span>
</span>
</p>
<p>
<strong>
strong
<span style="color: #0000FF;">
<strong>
strong blue
<span style="font-size: 24px;font-family: serif;">strong blue serif </span>
<span style="color: #00FF00;">
strong green
<span style="font-family: serif;">strong green serif</span>
</span>
</strong>
</span>
</strong>
</p>
`,
})
},
Expand Down
Loading

0 comments on commit a0d2f28

Please sign in to comment.