@puredesktop/platform-editor 1.0.0-beta.1 → 2.1.0

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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/CollapsePanel.tsx +35 -35
  3. package/src/DocumentDiffView.tsx +130 -130
  4. package/src/DocumentEditor.test.ts +118 -118
  5. package/src/DocumentEditor.tsx +2651 -2631
  6. package/src/alignedLineDiff.test.ts +52 -52
  7. package/src/alignedLineDiff.ts +67 -67
  8. package/src/collectionAssetSrc.ts +2 -2
  9. package/src/commentUtils.test.ts +350 -350
  10. package/src/commentUtils.ts +546 -546
  11. package/src/constants/toolKeys.ts +14 -14
  12. package/src/contentFormat.test.ts +27 -27
  13. package/src/contentFormat.ts +18 -18
  14. package/src/editorExtensions.ts +155 -155
  15. package/src/extensions/appliedChangeMark.ts +115 -115
  16. package/src/extensions/autoReviewPrompts.test.ts +529 -529
  17. package/src/extensions/autoReviewPrompts.ts +1442 -1442
  18. package/src/extensions/collectionImage.ts +26 -26
  19. package/src/extensions/collectionImagePaste.ts +215 -215
  20. package/src/extensions/commentMark.ts +223 -223
  21. package/src/extensions/documentAssetIdentity.ts +54 -54
  22. package/src/extensions/figure.ts +92 -92
  23. package/src/extensions/footnote.ts +186 -186
  24. package/src/extensions/indexMarker.ts +88 -88
  25. package/src/extensions/mathEditing.ts +239 -239
  26. package/src/extensions/mermaidBlock.tsx +297 -297
  27. package/src/extensions/slashCommands.test.ts +170 -170
  28. package/src/extensions/slashCommands.ts +746 -746
  29. package/src/extensions/smartTypography.test.ts +74 -74
  30. package/src/extensions/smartTypography.ts +120 -120
  31. package/src/index.ts +138 -137
  32. package/src/insertCollectionImage.test.ts +60 -60
  33. package/src/insertCollectionImage.ts +63 -63
  34. package/src/insertInlineAssetKind.test.ts +67 -67
  35. package/src/insertInlineAssetKind.ts +49 -49
  36. package/src/mermaidPreview.test.ts +54 -54
  37. package/src/mermaidPreview.ts +115 -115
  38. package/src/styled.ts +697 -676
  39. package/src/toolbar/ToolBtn.tsx +77 -63
  40. package/src/toolbar/Toolbar.test.tsx +325 -325
  41. package/src/toolbar/Toolbar.tsx +662 -624
  42. package/src/toolbar/groups/HeadingGroup.tsx +175 -153
  43. package/src/toolbar/overlayTypes.ts +28 -28
  44. package/src/useEditorExtensions.ts +22 -22
  45. package/src/utils/markdownUtils.ts +331 -331
@@ -1,223 +1,223 @@
1
- import { Mark, mergeAttributes } from '@tiptap/core'
2
- import {
3
- normalizeCommentReviewStatus,
4
- normalizeCommentSeverity,
5
- normalizeCommentType,
6
- type CommentReviewStatus,
7
- type CommentSeverity,
8
- type CommentType,
9
- } from '../commentUtils.js'
10
-
11
- declare module '@tiptap/core' {
12
- interface Commands<ReturnType> {
13
- commentMark: {
14
- setCommentMark: (attrs: {
15
- commentId: string
16
- commentText: string
17
- author?: string
18
- createdAt?: string
19
- commentType?: CommentType
20
- subjectText?: string
21
- reviewStatus?: CommentReviewStatus
22
- severity?: CommentSeverity
23
- replies?: string
24
- resolvedAt?: string
25
- resolvedBy?: string
26
- }) => ReturnType
27
- unsetCommentMark: () => ReturnType
28
- }
29
- }
30
- }
31
-
32
- export const CommentMark = Mark.create({
33
- name: 'commentMark',
34
- inclusive: false,
35
- excludes: '',
36
-
37
- addAttributes() {
38
- return {
39
- commentId: {
40
- default: null,
41
- parseHTML: el => el.getAttribute('data-comment-id'),
42
- renderHTML: (attrs: { commentId?: string }) =>
43
- attrs.commentId ? { 'data-comment-id': attrs.commentId } : {},
44
- },
45
- commentText: {
46
- default: null,
47
- parseHTML: el => el.getAttribute('data-comment-text'),
48
- renderHTML: (attrs: { commentText?: string }) =>
49
- attrs.commentText ? { 'data-comment-text': attrs.commentText } : {},
50
- },
51
- author: {
52
- default: null,
53
- parseHTML: el => el.getAttribute('data-comment-author'),
54
- renderHTML: (attrs: { author?: string }) =>
55
- attrs.author ? { 'data-comment-author': attrs.author } : {},
56
- },
57
- createdAt: {
58
- default: null,
59
- parseHTML: el => el.getAttribute('data-comment-created-at'),
60
- renderHTML: (attrs: { createdAt?: string }) =>
61
- attrs.createdAt ? { 'data-comment-created-at': attrs.createdAt } : {},
62
- },
63
- commentType: {
64
- default: 'general',
65
- parseHTML: el =>
66
- normalizeCommentType(el.getAttribute('data-comment-type')),
67
- renderHTML: (attrs: { commentType?: string }) => ({
68
- 'data-comment-type': normalizeCommentType(attrs.commentType),
69
- }),
70
- },
71
- subjectText: {
72
- default: null,
73
- parseHTML: el => el.getAttribute('data-comment-subject'),
74
- renderHTML: (attrs: { subjectText?: string }) =>
75
- attrs.subjectText ? { 'data-comment-subject': attrs.subjectText } : {},
76
- },
77
- reviewStatus: {
78
- default: null,
79
- parseHTML: el => {
80
- const type = normalizeCommentType(el.getAttribute('data-comment-type'))
81
- return normalizeCommentReviewStatus(
82
- el.getAttribute('data-comment-review-status'),
83
- type,
84
- )
85
- },
86
- renderHTML: (attrs: {
87
- commentType?: string
88
- reviewStatus?: string
89
- }) => {
90
- const type = normalizeCommentType(attrs.commentType)
91
- const status =
92
- attrs.reviewStatus ??
93
- normalizeCommentReviewStatus(undefined, type)
94
- return { 'data-comment-review-status': status }
95
- },
96
- },
97
- severity: {
98
- default: null,
99
- parseHTML: el => {
100
- const type = normalizeCommentType(el.getAttribute('data-comment-type'))
101
- return normalizeCommentSeverity(
102
- el.getAttribute('data-comment-severity'),
103
- type,
104
- )
105
- },
106
- renderHTML: (attrs: { commentType?: string; severity?: string }) => {
107
- const type = normalizeCommentType(attrs.commentType)
108
- const severity =
109
- attrs.severity ?? normalizeCommentSeverity(undefined, type)
110
- return { 'data-comment-severity': severity }
111
- },
112
- },
113
- replies: {
114
- default: null,
115
- parseHTML: el => el.getAttribute('data-comment-replies'),
116
- renderHTML: (attrs: { replies?: string }) =>
117
- attrs.replies ? { 'data-comment-replies': attrs.replies } : {},
118
- },
119
- resolvedAt: {
120
- default: null,
121
- parseHTML: el => el.getAttribute('data-comment-resolved-at'),
122
- renderHTML: (attrs: { resolvedAt?: string }) =>
123
- attrs.resolvedAt
124
- ? { 'data-comment-resolved-at': attrs.resolvedAt }
125
- : {},
126
- },
127
- resolvedBy: {
128
- default: null,
129
- parseHTML: el => el.getAttribute('data-comment-resolved-by'),
130
- renderHTML: (attrs: { resolvedBy?: string }) =>
131
- attrs.resolvedBy
132
- ? { 'data-comment-resolved-by': attrs.resolvedBy }
133
- : {},
134
- },
135
- }
136
- },
137
-
138
- parseHTML() {
139
- return [
140
- {
141
- tag: 'span[data-comment-id]',
142
- getAttrs: el => ({
143
- commentId: (el as HTMLElement).getAttribute('data-comment-id'),
144
- commentText: (el as HTMLElement).getAttribute('data-comment-text'),
145
- author: (el as HTMLElement).getAttribute('data-comment-author'),
146
- createdAt: (el as HTMLElement).getAttribute(
147
- 'data-comment-created-at',
148
- ),
149
- commentType: normalizeCommentType(
150
- (el as HTMLElement).getAttribute('data-comment-type'),
151
- ),
152
- subjectText: (el as HTMLElement).getAttribute(
153
- 'data-comment-subject',
154
- ),
155
- reviewStatus: normalizeCommentReviewStatus(
156
- (el as HTMLElement).getAttribute('data-comment-review-status'),
157
- normalizeCommentType(
158
- (el as HTMLElement).getAttribute('data-comment-type'),
159
- ),
160
- ),
161
- severity: normalizeCommentSeverity(
162
- (el as HTMLElement).getAttribute('data-comment-severity'),
163
- normalizeCommentType(
164
- (el as HTMLElement).getAttribute('data-comment-type'),
165
- ),
166
- ),
167
- replies: (el as HTMLElement).getAttribute('data-comment-replies'),
168
- resolvedAt: (el as HTMLElement).getAttribute(
169
- 'data-comment-resolved-at',
170
- ),
171
- resolvedBy: (el as HTMLElement).getAttribute(
172
- 'data-comment-resolved-by',
173
- ),
174
- }),
175
- },
176
- ]
177
- },
178
-
179
- renderHTML({ HTMLAttributes, mark }) {
180
- const attrs = mark.attrs as {
181
- commentText?: string
182
- author?: string
183
- commentType?: string
184
- resolvedAt?: string
185
- reviewStatus?: string
186
- severity?: string
187
- }
188
- const commentType = normalizeCommentType(attrs.commentType)
189
- const title = attrs.author
190
- ? `${attrs.author}: ${attrs.commentText ?? ''}`
191
- : attrs.commentText ?? ''
192
- return [
193
- 'span',
194
- mergeAttributes(HTMLAttributes, {
195
- class: [
196
- 'comment-mark',
197
- `comment-mark--${commentType}`,
198
- attrs.resolvedAt ? 'comment-mark--resolved' : '',
199
- ]
200
- .filter(Boolean)
201
- .join(' '),
202
- title,
203
- }),
204
- 0,
205
- ]
206
- },
207
-
208
- addCommands() {
209
- return {
210
- setCommentMark:
211
- attrs =>
212
- ({ commands, state }) => {
213
- const { from, to } = state.selection
214
- if (from === to) return false
215
- return commands.setMark(this.name, attrs)
216
- },
217
- unsetCommentMark:
218
- () =>
219
- ({ commands }) =>
220
- commands.unsetMark(this.name),
221
- }
222
- },
223
- })
1
+ import { Mark, mergeAttributes } from '@tiptap/core'
2
+ import {
3
+ normalizeCommentReviewStatus,
4
+ normalizeCommentSeverity,
5
+ normalizeCommentType,
6
+ type CommentReviewStatus,
7
+ type CommentSeverity,
8
+ type CommentType,
9
+ } from '../commentUtils.js'
10
+
11
+ declare module '@tiptap/core' {
12
+ interface Commands<ReturnType> {
13
+ commentMark: {
14
+ setCommentMark: (attrs: {
15
+ commentId: string
16
+ commentText: string
17
+ author?: string
18
+ createdAt?: string
19
+ commentType?: CommentType
20
+ subjectText?: string
21
+ reviewStatus?: CommentReviewStatus
22
+ severity?: CommentSeverity
23
+ replies?: string
24
+ resolvedAt?: string
25
+ resolvedBy?: string
26
+ }) => ReturnType
27
+ unsetCommentMark: () => ReturnType
28
+ }
29
+ }
30
+ }
31
+
32
+ export const CommentMark = Mark.create({
33
+ name: 'commentMark',
34
+ inclusive: false,
35
+ excludes: '',
36
+
37
+ addAttributes() {
38
+ return {
39
+ commentId: {
40
+ default: null,
41
+ parseHTML: el => el.getAttribute('data-comment-id'),
42
+ renderHTML: (attrs: { commentId?: string }) =>
43
+ attrs.commentId ? { 'data-comment-id': attrs.commentId } : {},
44
+ },
45
+ commentText: {
46
+ default: null,
47
+ parseHTML: el => el.getAttribute('data-comment-text'),
48
+ renderHTML: (attrs: { commentText?: string }) =>
49
+ attrs.commentText ? { 'data-comment-text': attrs.commentText } : {},
50
+ },
51
+ author: {
52
+ default: null,
53
+ parseHTML: el => el.getAttribute('data-comment-author'),
54
+ renderHTML: (attrs: { author?: string }) =>
55
+ attrs.author ? { 'data-comment-author': attrs.author } : {},
56
+ },
57
+ createdAt: {
58
+ default: null,
59
+ parseHTML: el => el.getAttribute('data-comment-created-at'),
60
+ renderHTML: (attrs: { createdAt?: string }) =>
61
+ attrs.createdAt ? { 'data-comment-created-at': attrs.createdAt } : {},
62
+ },
63
+ commentType: {
64
+ default: 'general',
65
+ parseHTML: el =>
66
+ normalizeCommentType(el.getAttribute('data-comment-type')),
67
+ renderHTML: (attrs: { commentType?: string }) => ({
68
+ 'data-comment-type': normalizeCommentType(attrs.commentType),
69
+ }),
70
+ },
71
+ subjectText: {
72
+ default: null,
73
+ parseHTML: el => el.getAttribute('data-comment-subject'),
74
+ renderHTML: (attrs: { subjectText?: string }) =>
75
+ attrs.subjectText ? { 'data-comment-subject': attrs.subjectText } : {},
76
+ },
77
+ reviewStatus: {
78
+ default: null,
79
+ parseHTML: el => {
80
+ const type = normalizeCommentType(el.getAttribute('data-comment-type'))
81
+ return normalizeCommentReviewStatus(
82
+ el.getAttribute('data-comment-review-status'),
83
+ type,
84
+ )
85
+ },
86
+ renderHTML: (attrs: {
87
+ commentType?: string
88
+ reviewStatus?: string
89
+ }) => {
90
+ const type = normalizeCommentType(attrs.commentType)
91
+ const status =
92
+ attrs.reviewStatus ??
93
+ normalizeCommentReviewStatus(undefined, type)
94
+ return { 'data-comment-review-status': status }
95
+ },
96
+ },
97
+ severity: {
98
+ default: null,
99
+ parseHTML: el => {
100
+ const type = normalizeCommentType(el.getAttribute('data-comment-type'))
101
+ return normalizeCommentSeverity(
102
+ el.getAttribute('data-comment-severity'),
103
+ type,
104
+ )
105
+ },
106
+ renderHTML: (attrs: { commentType?: string; severity?: string }) => {
107
+ const type = normalizeCommentType(attrs.commentType)
108
+ const severity =
109
+ attrs.severity ?? normalizeCommentSeverity(undefined, type)
110
+ return { 'data-comment-severity': severity }
111
+ },
112
+ },
113
+ replies: {
114
+ default: null,
115
+ parseHTML: el => el.getAttribute('data-comment-replies'),
116
+ renderHTML: (attrs: { replies?: string }) =>
117
+ attrs.replies ? { 'data-comment-replies': attrs.replies } : {},
118
+ },
119
+ resolvedAt: {
120
+ default: null,
121
+ parseHTML: el => el.getAttribute('data-comment-resolved-at'),
122
+ renderHTML: (attrs: { resolvedAt?: string }) =>
123
+ attrs.resolvedAt
124
+ ? { 'data-comment-resolved-at': attrs.resolvedAt }
125
+ : {},
126
+ },
127
+ resolvedBy: {
128
+ default: null,
129
+ parseHTML: el => el.getAttribute('data-comment-resolved-by'),
130
+ renderHTML: (attrs: { resolvedBy?: string }) =>
131
+ attrs.resolvedBy
132
+ ? { 'data-comment-resolved-by': attrs.resolvedBy }
133
+ : {},
134
+ },
135
+ }
136
+ },
137
+
138
+ parseHTML() {
139
+ return [
140
+ {
141
+ tag: 'span[data-comment-id]',
142
+ getAttrs: el => ({
143
+ commentId: (el as HTMLElement).getAttribute('data-comment-id'),
144
+ commentText: (el as HTMLElement).getAttribute('data-comment-text'),
145
+ author: (el as HTMLElement).getAttribute('data-comment-author'),
146
+ createdAt: (el as HTMLElement).getAttribute(
147
+ 'data-comment-created-at',
148
+ ),
149
+ commentType: normalizeCommentType(
150
+ (el as HTMLElement).getAttribute('data-comment-type'),
151
+ ),
152
+ subjectText: (el as HTMLElement).getAttribute(
153
+ 'data-comment-subject',
154
+ ),
155
+ reviewStatus: normalizeCommentReviewStatus(
156
+ (el as HTMLElement).getAttribute('data-comment-review-status'),
157
+ normalizeCommentType(
158
+ (el as HTMLElement).getAttribute('data-comment-type'),
159
+ ),
160
+ ),
161
+ severity: normalizeCommentSeverity(
162
+ (el as HTMLElement).getAttribute('data-comment-severity'),
163
+ normalizeCommentType(
164
+ (el as HTMLElement).getAttribute('data-comment-type'),
165
+ ),
166
+ ),
167
+ replies: (el as HTMLElement).getAttribute('data-comment-replies'),
168
+ resolvedAt: (el as HTMLElement).getAttribute(
169
+ 'data-comment-resolved-at',
170
+ ),
171
+ resolvedBy: (el as HTMLElement).getAttribute(
172
+ 'data-comment-resolved-by',
173
+ ),
174
+ }),
175
+ },
176
+ ]
177
+ },
178
+
179
+ renderHTML({ HTMLAttributes, mark }) {
180
+ const attrs = mark.attrs as {
181
+ commentText?: string
182
+ author?: string
183
+ commentType?: string
184
+ resolvedAt?: string
185
+ reviewStatus?: string
186
+ severity?: string
187
+ }
188
+ const commentType = normalizeCommentType(attrs.commentType)
189
+ const title = attrs.author
190
+ ? `${attrs.author}: ${attrs.commentText ?? ''}`
191
+ : attrs.commentText ?? ''
192
+ return [
193
+ 'span',
194
+ mergeAttributes(HTMLAttributes, {
195
+ class: [
196
+ 'comment-mark',
197
+ `comment-mark--${commentType}`,
198
+ attrs.resolvedAt ? 'comment-mark--resolved' : '',
199
+ ]
200
+ .filter(Boolean)
201
+ .join(' '),
202
+ title,
203
+ }),
204
+ 0,
205
+ ]
206
+ },
207
+
208
+ addCommands() {
209
+ return {
210
+ setCommentMark:
211
+ attrs =>
212
+ ({ commands, state }) => {
213
+ const { from, to } = state.selection
214
+ if (from === to) return false
215
+ return commands.setMark(this.name, attrs)
216
+ },
217
+ unsetCommentMark:
218
+ () =>
219
+ ({ commands }) =>
220
+ commands.unsetMark(this.name),
221
+ }
222
+ },
223
+ })
@@ -1,54 +1,54 @@
1
- import { Extension } from '@tiptap/core'
2
- import { Plugin } from '@tiptap/pm/state'
3
-
4
- const ASSET_NODE_TYPES = new Set(['table', 'inlineMath', 'blockMath'])
5
-
6
- function createDocumentAssetId(kind: string): string {
7
- const id =
8
- globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2)
9
- return `asset_${kind}_${id}`
10
- }
11
-
12
- export const DocumentAssetIdentity = Extension.create({
13
- name: 'documentAssetIdentity',
14
-
15
- addGlobalAttributes() {
16
- return [
17
- {
18
- types: [...ASSET_NODE_TYPES],
19
- attributes: {
20
- assetId: {
21
- default: null,
22
- parseHTML: element =>
23
- element.getAttribute('data-asset-id')?.trim() || null,
24
- renderHTML: attributes => {
25
- const assetId = String(attributes.assetId ?? '').trim()
26
- return assetId ? { 'data-asset-id': assetId } : {}
27
- },
28
- },
29
- },
30
- },
31
- ]
32
- },
33
-
34
- addProseMirrorPlugins() {
35
- return [
36
- new Plugin({
37
- appendTransaction: (_transactions, _oldState, newState) => {
38
- let tr = newState.tr
39
- let changed = false
40
- newState.doc.descendants((node, pos) => {
41
- if (!ASSET_NODE_TYPES.has(node.type.name)) return
42
- if (node.attrs.assetId) return
43
- tr = tr.setNodeMarkup(pos, undefined, {
44
- ...node.attrs,
45
- assetId: createDocumentAssetId(node.type.name),
46
- })
47
- changed = true
48
- })
49
- return changed ? tr : null
50
- },
51
- }),
52
- ]
53
- },
54
- })
1
+ import { Extension } from '@tiptap/core'
2
+ import { Plugin } from '@tiptap/pm/state'
3
+
4
+ const ASSET_NODE_TYPES = new Set(['table', 'inlineMath', 'blockMath'])
5
+
6
+ function createDocumentAssetId(kind: string): string {
7
+ const id =
8
+ globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2)
9
+ return `asset_${kind}_${id}`
10
+ }
11
+
12
+ export const DocumentAssetIdentity = Extension.create({
13
+ name: 'documentAssetIdentity',
14
+
15
+ addGlobalAttributes() {
16
+ return [
17
+ {
18
+ types: [...ASSET_NODE_TYPES],
19
+ attributes: {
20
+ assetId: {
21
+ default: null,
22
+ parseHTML: element =>
23
+ element.getAttribute('data-asset-id')?.trim() || null,
24
+ renderHTML: attributes => {
25
+ const assetId = String(attributes.assetId ?? '').trim()
26
+ return assetId ? { 'data-asset-id': assetId } : {}
27
+ },
28
+ },
29
+ },
30
+ },
31
+ ]
32
+ },
33
+
34
+ addProseMirrorPlugins() {
35
+ return [
36
+ new Plugin({
37
+ appendTransaction: (_transactions, _oldState, newState) => {
38
+ let tr = newState.tr
39
+ let changed = false
40
+ newState.doc.descendants((node, pos) => {
41
+ if (!ASSET_NODE_TYPES.has(node.type.name)) return
42
+ if (node.attrs.assetId) return
43
+ tr = tr.setNodeMarkup(pos, undefined, {
44
+ ...node.attrs,
45
+ assetId: createDocumentAssetId(node.type.name),
46
+ })
47
+ changed = true
48
+ })
49
+ return changed ? tr : null
50
+ },
51
+ }),
52
+ ]
53
+ },
54
+ })