@puredesktop/platform-editor 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +63 -0
- package/src/CollapsePanel.tsx +35 -0
- package/src/DocumentDiffView.tsx +130 -0
- package/src/DocumentEditor.test.ts +118 -0
- package/src/DocumentEditor.tsx +2631 -0
- package/src/alignedLineDiff.test.ts +52 -0
- package/src/alignedLineDiff.ts +67 -0
- package/src/collectionAssetSrc.ts +2 -0
- package/src/commentUtils.test.ts +350 -0
- package/src/commentUtils.ts +546 -0
- package/src/constants/toolKeys.ts +14 -0
- package/src/contentFormat.test.ts +27 -0
- package/src/contentFormat.ts +18 -0
- package/src/editorExtensions.ts +155 -0
- package/src/extensions/appliedChangeMark.ts +115 -0
- package/src/extensions/autoReviewPrompts.test.ts +529 -0
- package/src/extensions/autoReviewPrompts.ts +1442 -0
- package/src/extensions/collectionImage.ts +26 -0
- package/src/extensions/collectionImagePaste.ts +215 -0
- package/src/extensions/commentMark.ts +223 -0
- package/src/extensions/documentAssetIdentity.ts +54 -0
- package/src/extensions/figure.ts +92 -0
- package/src/extensions/footnote.ts +186 -0
- package/src/extensions/indexMarker.ts +88 -0
- package/src/extensions/mathEditing.ts +239 -0
- package/src/extensions/mermaidBlock.tsx +297 -0
- package/src/extensions/slashCommands.test.ts +170 -0
- package/src/extensions/slashCommands.ts +746 -0
- package/src/extensions/smartTypography.test.ts +74 -0
- package/src/extensions/smartTypography.ts +120 -0
- package/src/index.ts +137 -0
- package/src/insertCollectionImage.test.ts +60 -0
- package/src/insertCollectionImage.ts +63 -0
- package/src/insertInlineAssetKind.test.ts +67 -0
- package/src/insertInlineAssetKind.ts +49 -0
- package/src/mermaidPreview.test.ts +54 -0
- package/src/mermaidPreview.ts +115 -0
- package/src/styled.ts +676 -0
- package/src/toolbar/ToolBtn.tsx +63 -0
- package/src/toolbar/Toolbar.test.tsx +325 -0
- package/src/toolbar/Toolbar.tsx +624 -0
- package/src/toolbar/groups/HeadingGroup.tsx +153 -0
- package/src/toolbar/overlayTypes.ts +28 -0
- package/src/useEditorExtensions.ts +22 -0
- package/src/utils/markdownUtils.ts +331 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import StarterKit from '@tiptap/starter-kit'
|
|
2
|
+
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'
|
|
3
|
+
import { CharacterCount } from '@tiptap/extension-character-count'
|
|
4
|
+
import Placeholder from '@tiptap/extension-placeholder'
|
|
5
|
+
import { Mathematics } from '@tiptap/extension-mathematics'
|
|
6
|
+
import {
|
|
7
|
+
Table,
|
|
8
|
+
TableCell,
|
|
9
|
+
TableHeader,
|
|
10
|
+
TableRow,
|
|
11
|
+
} from '@tiptap/extension-table'
|
|
12
|
+
import { Subscript } from '@tiptap/extension-subscript'
|
|
13
|
+
import { Superscript } from '@tiptap/extension-superscript'
|
|
14
|
+
import { TaskList } from '@tiptap/extension-task-list'
|
|
15
|
+
import { TaskItem } from '@tiptap/extension-task-item'
|
|
16
|
+
import { TextAlign } from '@tiptap/extension-text-align'
|
|
17
|
+
import { Highlight } from '@tiptap/extension-highlight'
|
|
18
|
+
import { Image } from '@tiptap/extension-image'
|
|
19
|
+
import type { Extensions } from '@tiptap/react'
|
|
20
|
+
import { common, createLowlight } from 'lowlight'
|
|
21
|
+
import 'katex/dist/katex.min.css'
|
|
22
|
+
import { Figure } from './extensions/figure.js'
|
|
23
|
+
import { IndexMarker } from './extensions/indexMarker.js'
|
|
24
|
+
import { Footnote } from './extensions/footnote.js'
|
|
25
|
+
import { MathEditing } from './extensions/mathEditing.js'
|
|
26
|
+
import { MermaidBlock } from './extensions/mermaidBlock.js'
|
|
27
|
+
import { DocumentAssetIdentity } from './extensions/documentAssetIdentity.js'
|
|
28
|
+
import { SmartTypography } from './extensions/smartTypography.js'
|
|
29
|
+
import { CommentMark } from './extensions/commentMark.js'
|
|
30
|
+
import { AppliedChangeMark } from './extensions/appliedChangeMark.js'
|
|
31
|
+
import { AutoReviewPrompts } from './extensions/autoReviewPrompts.js'
|
|
32
|
+
|
|
33
|
+
const lowlight = createLowlight(common)
|
|
34
|
+
|
|
35
|
+
/** Optional markup capabilities — enable per app; no host or filesystem behavior. */
|
|
36
|
+
export interface EditorFeatures {
|
|
37
|
+
tables?: boolean
|
|
38
|
+
taskList?: boolean
|
|
39
|
+
highlight?: boolean
|
|
40
|
+
math?: boolean
|
|
41
|
+
figures?: boolean
|
|
42
|
+
mermaid?: boolean
|
|
43
|
+
footnotes?: boolean
|
|
44
|
+
smartTypography?: boolean
|
|
45
|
+
/** In-document review marks (toolbar must pass `enableComments` on DocumentEditor). */
|
|
46
|
+
comments?: boolean
|
|
47
|
+
/** Prompt batching and validated auto editorial mark application. */
|
|
48
|
+
autoReviewPrompts?: boolean
|
|
49
|
+
/** Book-style index markers (`a.ix`). */
|
|
50
|
+
indexMarkers?: boolean
|
|
51
|
+
/** `data-asset-id` on math/table nodes for external asset indexes. */
|
|
52
|
+
documentAssetIdentity?: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const DEFAULT_FEATURES: Required<EditorFeatures> = {
|
|
56
|
+
tables: true,
|
|
57
|
+
taskList: true,
|
|
58
|
+
highlight: true,
|
|
59
|
+
math: true,
|
|
60
|
+
figures: true,
|
|
61
|
+
mermaid: true,
|
|
62
|
+
footnotes: true,
|
|
63
|
+
smartTypography: true,
|
|
64
|
+
comments: false,
|
|
65
|
+
autoReviewPrompts: false,
|
|
66
|
+
indexMarkers: false,
|
|
67
|
+
documentAssetIdentity: false,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface BuildExtensionsOptions {
|
|
71
|
+
placeholder?: string
|
|
72
|
+
features?: EditorFeatures
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Build the shared TipTap extension set. Apps may concat further extensions
|
|
77
|
+
* (e.g. custom image paste) or pass the result to DocumentEditor.
|
|
78
|
+
*/
|
|
79
|
+
export function buildExtensions(opts: BuildExtensionsOptions = {}): Extensions {
|
|
80
|
+
const features = { ...DEFAULT_FEATURES, ...opts.features }
|
|
81
|
+
const extensions: Extensions = [
|
|
82
|
+
StarterKit.configure({
|
|
83
|
+
link: { openOnClick: false },
|
|
84
|
+
heading: { levels: [1, 2, 3] },
|
|
85
|
+
codeBlock: false,
|
|
86
|
+
}),
|
|
87
|
+
CodeBlockLowlight.configure({
|
|
88
|
+
lowlight,
|
|
89
|
+
defaultLanguage: 'plaintext',
|
|
90
|
+
}),
|
|
91
|
+
CharacterCount,
|
|
92
|
+
Subscript,
|
|
93
|
+
Superscript,
|
|
94
|
+
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
if (features.documentAssetIdentity) {
|
|
98
|
+
extensions.push(DocumentAssetIdentity)
|
|
99
|
+
}
|
|
100
|
+
if (features.tables) {
|
|
101
|
+
extensions.push(
|
|
102
|
+
Table.configure({ resizable: true }),
|
|
103
|
+
TableCell,
|
|
104
|
+
TableHeader,
|
|
105
|
+
TableRow,
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
if (features.taskList) {
|
|
109
|
+
extensions.push(TaskList, TaskItem.configure({ nested: true }))
|
|
110
|
+
}
|
|
111
|
+
if (features.highlight) {
|
|
112
|
+
extensions.push(Highlight)
|
|
113
|
+
}
|
|
114
|
+
if (features.math) {
|
|
115
|
+
extensions.push(
|
|
116
|
+
Mathematics.configure({
|
|
117
|
+
katexOptions: { throwOnError: false },
|
|
118
|
+
}),
|
|
119
|
+
MathEditing,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
if (features.figures) {
|
|
123
|
+
extensions.push(
|
|
124
|
+
Image.configure({ inline: false, allowBase64: false }),
|
|
125
|
+
Figure,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
if (features.mermaid) {
|
|
129
|
+
extensions.push(MermaidBlock)
|
|
130
|
+
}
|
|
131
|
+
if (features.indexMarkers) {
|
|
132
|
+
extensions.push(IndexMarker)
|
|
133
|
+
}
|
|
134
|
+
if (features.comments) {
|
|
135
|
+
extensions.push(CommentMark)
|
|
136
|
+
extensions.push(AppliedChangeMark)
|
|
137
|
+
}
|
|
138
|
+
if (features.autoReviewPrompts) {
|
|
139
|
+
extensions.push(AutoReviewPrompts)
|
|
140
|
+
}
|
|
141
|
+
if (features.footnotes) {
|
|
142
|
+
extensions.push(Footnote)
|
|
143
|
+
}
|
|
144
|
+
if (features.smartTypography) {
|
|
145
|
+
extensions.push(SmartTypography)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
extensions.push(
|
|
149
|
+
Placeholder.configure({
|
|
150
|
+
placeholder: opts.placeholder ?? 'Start writing…',
|
|
151
|
+
}),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return extensions
|
|
155
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Mark, mergeAttributes } from '@tiptap/core'
|
|
2
|
+
|
|
3
|
+
declare module '@tiptap/core' {
|
|
4
|
+
interface Commands<ReturnType> {
|
|
5
|
+
appliedChangeMark: {
|
|
6
|
+
setAppliedChangeMark: (attrs: {
|
|
7
|
+
originalText: string
|
|
8
|
+
replacementText: string
|
|
9
|
+
sourceCommentId?: string
|
|
10
|
+
sourceType?: string
|
|
11
|
+
actor?: string
|
|
12
|
+
createdAt?: string
|
|
13
|
+
}) => ReturnType
|
|
14
|
+
unsetAppliedChangeMark: () => ReturnType
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const AppliedChangeMark = Mark.create({
|
|
20
|
+
name: 'appliedChangeMark',
|
|
21
|
+
inclusive: false,
|
|
22
|
+
|
|
23
|
+
addAttributes() {
|
|
24
|
+
return {
|
|
25
|
+
originalText: {
|
|
26
|
+
default: null,
|
|
27
|
+
parseHTML: el => el.getAttribute('data-pm-applied-original'),
|
|
28
|
+
renderHTML: (attrs: { originalText?: string }) =>
|
|
29
|
+
attrs.originalText
|
|
30
|
+
? { 'data-pm-applied-original': attrs.originalText }
|
|
31
|
+
: {},
|
|
32
|
+
},
|
|
33
|
+
replacementText: {
|
|
34
|
+
default: null,
|
|
35
|
+
parseHTML: el => el.getAttribute('data-pm-applied-replacement'),
|
|
36
|
+
renderHTML: (attrs: { replacementText?: string }) =>
|
|
37
|
+
attrs.replacementText
|
|
38
|
+
? { 'data-pm-applied-replacement': attrs.replacementText }
|
|
39
|
+
: {},
|
|
40
|
+
},
|
|
41
|
+
sourceCommentId: {
|
|
42
|
+
default: null,
|
|
43
|
+
parseHTML: el => el.getAttribute('data-pm-applied-source-comment-id'),
|
|
44
|
+
renderHTML: (attrs: { sourceCommentId?: string }) =>
|
|
45
|
+
attrs.sourceCommentId
|
|
46
|
+
? { 'data-pm-applied-source-comment-id': attrs.sourceCommentId }
|
|
47
|
+
: {},
|
|
48
|
+
},
|
|
49
|
+
sourceType: {
|
|
50
|
+
default: null,
|
|
51
|
+
parseHTML: el => el.getAttribute('data-pm-applied-source-type'),
|
|
52
|
+
renderHTML: (attrs: { sourceType?: string }) =>
|
|
53
|
+
attrs.sourceType ? { 'data-pm-applied-source-type': attrs.sourceType } : {},
|
|
54
|
+
},
|
|
55
|
+
actor: {
|
|
56
|
+
default: null,
|
|
57
|
+
parseHTML: el => el.getAttribute('data-pm-applied-actor'),
|
|
58
|
+
renderHTML: (attrs: { actor?: string }) =>
|
|
59
|
+
attrs.actor ? { 'data-pm-applied-actor': attrs.actor } : {},
|
|
60
|
+
},
|
|
61
|
+
createdAt: {
|
|
62
|
+
default: null,
|
|
63
|
+
parseHTML: el => el.getAttribute('data-pm-applied-created-at'),
|
|
64
|
+
renderHTML: (attrs: { createdAt?: string }) =>
|
|
65
|
+
attrs.createdAt ? { 'data-pm-applied-created-at': attrs.createdAt } : {},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
parseHTML() {
|
|
71
|
+
return [{ tag: 'span[data-pm-applied-change="true"]' }]
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
renderHTML({ HTMLAttributes, mark }) {
|
|
75
|
+
const attrs = mark.attrs as {
|
|
76
|
+
originalText?: string
|
|
77
|
+
replacementText?: string
|
|
78
|
+
actor?: string
|
|
79
|
+
createdAt?: string
|
|
80
|
+
}
|
|
81
|
+
const title = [
|
|
82
|
+
attrs.actor ? `${attrs.actor} applied edit` : 'Applied edit',
|
|
83
|
+
attrs.originalText ? `Original: ${attrs.originalText}` : null,
|
|
84
|
+
attrs.replacementText ? `Replacement: ${attrs.replacementText}` : null,
|
|
85
|
+
attrs.createdAt ?? null,
|
|
86
|
+
]
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.join('\n')
|
|
89
|
+
return [
|
|
90
|
+
'span',
|
|
91
|
+
mergeAttributes(HTMLAttributes, {
|
|
92
|
+
'data-pm-applied-change': 'true',
|
|
93
|
+
class: 'applied-change-mark',
|
|
94
|
+
title,
|
|
95
|
+
}),
|
|
96
|
+
0,
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
addCommands() {
|
|
101
|
+
return {
|
|
102
|
+
setAppliedChangeMark:
|
|
103
|
+
attrs =>
|
|
104
|
+
({ commands, state }) => {
|
|
105
|
+
const { from, to } = state.selection
|
|
106
|
+
if (from === to) return false
|
|
107
|
+
return commands.setMark(this.name, attrs)
|
|
108
|
+
},
|
|
109
|
+
unsetAppliedChangeMark:
|
|
110
|
+
() =>
|
|
111
|
+
({ commands }) =>
|
|
112
|
+
commands.unsetMark(this.name),
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
})
|