Skip to content

Commit

Permalink
feat: add plainBlockquote and plainParagraph extensions to restrict b…
Browse files Browse the repository at this point in the history
…lockquote formats
  • Loading branch information
robertu7 committed Jun 7, 2024
1 parent 06b1aed commit 9d455d8
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@matters/matters-editor",
"version": "0.2.5-alpha.1",
"version": "0.2.5-alpha.2",
"description": "Editor for matters.news",
"author": "https://github.com/thematters",
"homepage": "https://github.com/thematters/matters-editor",
Expand Down
6 changes: 4 additions & 2 deletions src/editors/extensions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Blockquote from '@tiptap/extension-blockquote'
import BulletList from '@tiptap/extension-bullet-list'
import Code from '@tiptap/extension-code'
import CodeBlock from '@tiptap/extension-code-block'
Expand All @@ -21,6 +20,8 @@ import { FigureImage } from './figureImage'
import { HorizontalRule } from './horizontalRule'
import { Link } from './link'
import { Mention, type MentionSuggestion } from './mention'
import { PlainBlockquote } from './plainBlockquote'
import { PlainParagraph } from './plainParagraph'

export * from './bold'
export * from './figureAudio'
Expand All @@ -39,14 +40,15 @@ const baseExtensions = (placeholder?: string) => [
// Basic Formats
Text,
Paragraph,
Blockquote,
HardBreak.configure({
HTMLAttributes: {
class: 'smart',
},
}),
// Custom Formats
Link,
PlainParagraph,
PlainBlockquote,
]

const baseArticleExtensions = (placeholder?: string) => [
Expand Down
83 changes: 83 additions & 0 deletions src/editors/extensions/plainBlockquote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { mergeAttributes, Node, wrappingInputRule } from '@tiptap/core'

export interface BlockquoteOptions {
/**
* HTML attributes to add to the blockquote element
* @default {}
* @example { class: 'foo' }
*/
HTMLAttributes: Record<string, any>
}

declare module '@tiptap/core' {
interface Commands<ReturnType> {
plainBlockQuote: {
setPlainBlockquote: () => ReturnType
}
}
}

/**
* Matches a blockquote to a `>` as input.
*/
export const inputRegex = /^\s*>\s$/

/**
* This extension allows you to create plain blockquotes,
* contains only plainParagraph.
*
* Forked from:
* @see https://tiptap.dev/api/nodes/blockquote
*/
export const PlainBlockquote = Node.create<BlockquoteOptions>({
name: 'plainBlockquote',

addOptions() {
return {
HTMLAttributes: {},
}
},

group: 'block',

content: 'plainBlock+',

defining: true,

parseHTML() {
return [{ tag: 'blockquote' }]
},

renderHTML({ HTMLAttributes }) {
return [
'blockquote',
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
0,
]
},

addCommands() {
return {
setPlainBlockquote:
() =>
({ chain }) => {
return chain().setPlainParagraph().wrapIn(this.name).run()
},
}
},

addKeyboardShortcuts() {
return {
'Mod-Shift-b': () => this.editor.commands.setPlainBlockquote(),
}
},

addInputRules() {
return [
wrappingInputRule({
find: inputRegex,
type: this.type,
}),
]
},
})
69 changes: 69 additions & 0 deletions src/editors/extensions/plainParagraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { mergeAttributes, Node } from '@tiptap/core'

export interface PlainParagraphOptions {
/**
* The HTML attributes for a plain paragraph node.
* @default {}
* @example { class: 'foo' }
*/
HTMLAttributes: Record<string, any>
}

declare module '@tiptap/core' {
interface Commands<ReturnType> {
plainParagraph: {
setPlainParagraph: () => ReturnType
}
}
}

/**
* This extension allows you to create
* plain paragraphs (only support plain text and hard break)
* for plainBlockquote extension.
*
* Forked from:
* @see https://www.tiptap.dev/api/nodes/paragraph
*/
export const PlainParagraph = Node.create<PlainParagraphOptions>({
name: 'plainParagraph',

// higher priority to override the default paragraph node
// https://github.com/ueberdosis/tiptap/blob/f635d7b4f511530496377a8ef051875e30e301a4/packages/extension-paragraph/src/paragraph.ts#L31
priority: 2000,

addOptions() {
return {
HTMLAttributes: { class: 'plain' },
}
},

group: 'plainBlock',

content: 'inline*',

marks: '',

defining: true,

parseHTML() {
return [{ tag: 'p[class="plain"]' }]
},

renderHTML({ HTMLAttributes }) {
return [
'p',
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
0,
]
},

addCommands() {
return {
setPlainParagraph:
() =>
({ commands }) =>
commands.setNode(this.name),
}
},
})
36 changes: 18 additions & 18 deletions src/transformers/normalize-sanitize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,18 @@ describe('Sanitize and normalize article', () => {
expectProcessArticleHTML(
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p></p>
<p>3</p>
<p class="plain">1</p>
<p class="plain">2</p>
<p class="plain"></p>
<p class="plain">3</p>
</blockquote>
`,
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p><br class="smart"></p>
<p>3</p>
<p class="plain">1</p>
<p class="plain">2</p>
<p class="plain"><br class="smart"></p>
<p class="plain">3</p>
</blockquote>
`,
{ maxHardBreaks: 1 },
Expand Down Expand Up @@ -252,20 +252,20 @@ describe('Sanitize and normalize comment', () => {
expectProcessCommentHTML(
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p>1<br>2</p>
<p>1<br><br>2</p>
<p>1<br><br></p>
<p class="plain">1</p>
<p class="plain">2</p>
<p class="plain">1<br>2</p>
<p class="plain">1<br><br>2</p>
<p class="plain">1<br><br></p>
</blockquote>
`,
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p>12</p>
<p>12</p>
<p>1</p>
<p class="plain">1</p>
<p class="plain">2</p>
<p class="plain">12</p>
<p class="plain">12</p>
<p class="plain">1</p>
</blockquote>
`,
{ maxHardBreaks: 0, maxSoftBreaks: 0 },
Expand Down
24 changes: 22 additions & 2 deletions src/transformers/normalize.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { stripIndent } from 'common-tags'
import { describe, expect, test } from 'vitest'

import { normalizeArticleHTML, normalizeCommentHTML } from './normalize'
Expand Down Expand Up @@ -288,8 +289,27 @@ describe('Normalization: Article', () => {
describe('Normalization: Comment', () => {
test('quote', () => {
expectNormalizeCommentHTML(
'<blockquote><p>abc</p></blockquote>',
'<blockquote><p>abc</p></blockquote>',
stripIndent`
<blockquote>
<p class="plain">hello,<br>world</p>
<p class="plain">how are you today</p>
<p class="plain"><strong>strong</strong></p>
<p>normal paragraph</p>
<h2>heading</h2>hello,world
</blockquote>
`,
'<blockquote><p class="plain">hello,<br class="smart">world</p><p class="plain">how are you today</p><p class="plain">strong</p><p class="plain">normal paragraph</p><p class="plain">heading</p><p class="plain">hello,world</p></blockquote>',
)

expectNormalizeCommentHTML(
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p>3</p>
</blockquote>
`,
'<blockquote><p class="plain">1 2 3</p></blockquote>',
)
})

Expand Down
6 changes: 5 additions & 1 deletion src/transformers/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,12 @@ export const rehypeSanitizeOptions: Schema = {
},
attributes: {
...defaultSchema.attributes,
p: [
// for plainParagraph extension
['className', 'plain'],
],
a: [
// classes
// for mention extension
['className', 'mention'],
'href',
'ref',
Expand Down
26 changes: 13 additions & 13 deletions src/transformers/sanitize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ describe('Sanitization: custom', () => {
// blockquote
expectSanitizeHTML(
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p></p>
<p>3</p>
</blockquote>
`,
<blockquote>
<p class="plain">1</p>
<p>2</p>
<p></p>
<p>3</p>
</blockquote>
`,
stripIndent`
<blockquote>
<p>1</p>
<p>2</p>
<p>3</p>
</blockquote>
`,
<blockquote>
<p class="plain">1</p>
<p>2</p>
<p>3</p>
</blockquote>
`,
{ maxHardBreaks: 0 },
)
})
Expand Down

0 comments on commit 9d455d8

Please sign in to comment.