snapshot of https://github.com/ueberdosis/tiptap.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 21:11:02 +05:00
commit 083a46e93b
2115 changed files with 245958 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
export const name = 'Bullet List with Numeric Punctuation'
export const expectedInput = `
- 123
- 123
- 123
- 123
- 123.
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '123' }],
},
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '123' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '123' }],
},
],
},
],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '123' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '123.' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,70 @@
export const name = 'Bullet List'
export const expectedInput = `
- Item 1
- Item 2
- Subitem 1
- Subitem 2
- Item 3
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 2' }],
},
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 2' }],
},
],
},
],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 3' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,46 @@
import { createAtomBlockMarkdownSpec, Node } from '@tiptap/core'
export const name = 'Custom Atom'
export const expectedInput = `
:::custom-atom {label="Example"} :::
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'customAtom',
attrs: { label: 'Example' },
content: [],
},
],
}
export const extensions = [
Node.create({
name: 'customAtom',
group: 'block',
atom: true,
...createAtomBlockMarkdownSpec({
nodeName: 'customAtom',
name: 'custom-atom',
allowedAttributes: ['label'],
}),
parseHTML() {
return [
{
tag: 'div[data-type="custom-atom"]',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['div', { 'data-type': 'custom-atom', ...HTMLAttributes }]
},
}),
]

View File

@@ -0,0 +1,57 @@
import { createBlockMarkdownSpec, Node } from '@tiptap/core'
export const name = 'Custom Block'
export const expectedInput = `
:::custom-block
This is a node with **bold text**.
:::`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'customBlock',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This is a node with ' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'bold text' },
{ type: 'text', text: '.' },
],
},
],
},
],
}
export const extensions = [
Node.create({
name: 'customBlock',
group: 'block',
content: 'block+',
...createBlockMarkdownSpec({
nodeName: 'customBlock',
name: 'custom-block',
content: 'block',
}),
parseHTML() {
return [
{
tag: 'div[data-type="custom-block"]',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['div', { 'data-type': 'custom-block', ...HTMLAttributes }, 0]
},
}),
]

View File

@@ -0,0 +1,96 @@
import { createInlineMarkdownSpec, Node } from '@tiptap/core'
export const name = 'Custom Inline'
export const expectedInput = `
This is a [custom-inline type="bug" id="1234"] ticket.
This is a [custom-inline-tag icon="house"]Home[/custom-inline-tag] tag.
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This is a ' },
{
type: 'customInline',
attrs: { type: 'bug', id: '1234' },
},
{ type: 'text', text: ' ticket.' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This is a ' },
{
type: 'customInlineTag',
attrs: { icon: 'house' },
content: [{ type: 'text', text: 'Home' }],
},
{ type: 'text', text: ' tag.' },
],
},
],
}
export const extensions = [
Node.create({
name: 'customInline',
group: 'inline',
atom: true,
markdownTokenName: 'custom-inline',
...createInlineMarkdownSpec({
nodeName: 'customInline',
name: 'custom-inline',
selfClosing: true,
allowedAttributes: ['type', 'id'],
}),
parseHTML() {
return [
{
tag: 'span[data-type="custom-inline"]',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['span', { 'data-type': 'custom-inline', ...HTMLAttributes }]
},
}),
Node.create({
name: 'customInlineTag',
group: 'inline',
content: 'inline*',
markdownTokenName: 'custom-inline-tag',
...createInlineMarkdownSpec({
nodeName: 'customInlineTag',
name: 'custom-inline-tag',
allowedAttributes: ['icon'],
}),
parseHTML() {
return [
{
tag: 'span[data-type="custom-inline-tag"]',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['span', { 'data-type': 'custom-inline-tag', ...HTMLAttributes }, 0]
},
}),
]

View File

@@ -0,0 +1,31 @@
export const name = 'Hard Break with Marks'
export const expectedInput = `**Speaker:**
John Doe.
**Speaker:**
**John Doe**`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', marks: [{ type: 'bold' }], text: 'Speaker:' },
{ type: 'hardBreak' },
{ type: 'text', text: 'John Doe.' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', marks: [{ type: 'bold' }], text: 'Speaker:' },
{ type: 'hardBreak' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'John Doe' },
],
},
],
}
export const extensions = []

View File

@@ -0,0 +1,17 @@
export * as bulletList from './bullet-list.js'
export * as bulletListNumericPunctuation from './bullet-list-numeric-punctuation.js'
export * as customAtom from './custom-atom.js'
export * as customBlock from './custom-block.js'
export * as customInline from './custom-inline.js'
export * as hardBreakMarks from './hard-break-marks.js'
export * as linkWithTitle from './link-with-title.js'
export * as linkWithoutTitle from './link-without-title.js'
export * as mixedListTypes from './mixed-list-types.js'
export * as nestedNodes from './nested-nodes.js'
export * as orderedList from './ordered-list.js'
export * as orderedListSeparatedByBullet from './ordered-list-separated-by-bullet.js'
export * as orderedListWideMarker from './ordered-list-wide-marker.js'
export * as orderedListWithBulletList from './ordered-list-with-bullet-list.js'
export * as softBreakMarks from './soft-break-marks.js'
export * as taskList from './task-list.js'
export * as trailingWhitespaceMarks from './trailing-whitespace-marks.js'

View File

@@ -0,0 +1,29 @@
export const name = 'Link with Title'
export const expectedInput = `
[click here](https://example.com "Example Site")
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'click here',
marks: [
{
type: 'link',
attrs: {
href: 'https://example.com',
title: 'Example Site',
},
},
],
},
],
},
],
}

View File

@@ -0,0 +1,29 @@
export const name = 'Link without Title'
export const expectedInput = `
[click here](https://example.com)
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'click here',
marks: [
{
type: 'link',
attrs: {
href: 'https://example.com',
title: null,
},
},
],
},
],
},
],
}

View File

@@ -0,0 +1,53 @@
export const name = 'Mixed List Types'
export const expectedInput = `
- Test
- [ ] Test
- [ ] Test 2
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Test' }],
},
],
},
],
},
{
type: 'taskList',
content: [
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Test' }],
},
],
},
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Test 2' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,72 @@
import { createBlockMarkdownSpec, Node } from '@tiptap/core'
export const name = 'Nested Nodes'
export const expectedInput = `
:::custom-block
This is a node with **bold text**.
:::custom-block
And this is a nested block.
:::
:::`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'customBlock',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This is a node with ' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'bold text' },
{ type: 'text', text: '.' },
],
},
{
type: 'customBlock',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'And this is a nested block.' }],
},
],
},
],
},
],
}
export const extensions = [
Node.create({
name: 'customBlock',
group: 'block',
content: 'block+',
...createBlockMarkdownSpec({
nodeName: 'customBlock',
name: 'custom-block',
content: 'block',
}),
parseHTML() {
return [
{
tag: 'div[data-type="custom-block"]',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['div', { 'data-type': 'custom-block', ...HTMLAttributes }, 0]
},
}),
]

View File

@@ -0,0 +1,60 @@
export const name = 'Ordered List Separated by Bullet List'
export const expectedInput = `
1. one
- inner
2. two
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'one' }],
},
],
},
],
},
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'inner' }],
},
],
},
],
},
{
type: 'orderedList',
attrs: {
start: 2,
},
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'two' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,53 @@
export const name = 'Ordered List with a Wide Marker'
// `10. ` is four characters, so the nested list has to start at column four to
// stay a child of it.
export const expectedInput = `
10. ten
1. inner
11. eleven
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'orderedList',
attrs: { start: 10 },
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'ten' }],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'inner' }],
},
],
},
],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'eleven' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,50 @@
export const name = 'Ordered List with Nested Bullet List'
export const expectedInput = `
1. one
- inner
2. two
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'one' }],
},
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'inner' }],
},
],
},
],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'two' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,145 @@
export const name = 'Ordered List'
export const expectedInput = `
1. Item 1
2. Item 2
1. Subitem 1
2. Subitem 2
1. Subsubitem 1
2. Subsubitem 2
3. Item 3
1. Subitem 1
2. Subitem 2
1. Subsubitem 1
2. Subsubitem 2
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 2' }],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 2' }],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subsubitem 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subsubitem 2' }],
},
],
},
],
},
],
},
],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Item 3' }],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subitem 2' }],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subsubitem 1' }],
},
],
},
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subsubitem 2' }],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,30 @@
export const name = 'Soft Break with Marks'
export const expectedInput = `**Speaker:**
John Doe.
**Speaker:**
**John Doe**`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', marks: [{ type: 'bold' }], text: 'Speaker:' },
{ type: 'text', text: '\nJohn Doe.' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', marks: [{ type: 'bold' }], text: 'Speaker:' },
{ type: 'text', text: '\n' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'John Doe' },
],
},
],
}
export const extensions = []

View File

@@ -0,0 +1,113 @@
export const name = 'Task List'
export const expectedInput = `
- [ ] Task 1
- [x] Task 2
- [ ] Task 3
- [ ] Subtask 1
- [x] Subtask 2
- [ ] Subtask 2a
- [x] Subtask 2b
- [x] Task 4
`.trim()
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'taskList',
content: [
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Task 1' }],
},
],
},
{
type: 'taskItem',
attrs: { checked: true },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Task 2' }],
},
],
},
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Task 3' }],
},
{
type: 'taskList',
content: [
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subtask 1' }],
},
],
},
{
type: 'taskItem',
attrs: { checked: true },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subtask 2' }],
},
{
type: 'taskList',
content: [
{
type: 'taskItem',
attrs: { checked: false },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subtask 2a' }],
},
],
},
{
type: 'taskItem',
attrs: { checked: true },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Subtask 2b' }],
},
],
},
],
},
],
},
],
},
],
},
{
type: 'taskItem',
attrs: { checked: true },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Task 4' }],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,53 @@
export const name = 'Trailing Whitespace in Marks'
// The expected input is the correct markdown output (no spaces inside marks)
export const expectedInput = `**text** continues here
and **more text** here
also *italic text* works
and **bold** *italic* mixed`.trim()
// The JSON content simulates text with trailing/leading spaces inside marks
// which should be moved outside the mark delimiters in the output
export const expectedOutput = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', marks: [{ type: 'bold' }], text: 'text' },
{ type: 'text', text: ' continues here' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'and ' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'more text' },
{ type: 'text', text: ' here' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'also ' },
{ type: 'text', marks: [{ type: 'italic' }], text: 'italic text' },
{ type: 'text', text: ' works' },
],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'and ' },
{ type: 'text', marks: [{ type: 'bold' }], text: 'bold' },
{ type: 'text', text: ' ' },
{ type: 'text', marks: [{ type: 'italic' }], text: 'italic' },
{ type: 'text', text: ' mixed' },
],
},
],
}
export const extensions = []