@apollohg/react-native-rich-text-editor 2.0.0 → 2.0.2

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 (180) hide show
  1. package/README.md +8 -116
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/android/build.gradle +3 -0
  4. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
  5. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
  6. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
  7. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
  8. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
  9. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
  10. package/app.plugin.js +42 -39
  11. package/dist/AtomHost.js +18 -11
  12. package/dist/EditorAddon.js +4 -2
  13. package/dist/EditorAddonNormalization.js +17 -9
  14. package/dist/EditorMentionThemeNormalization.js +6 -3
  15. package/dist/EditorMentionThemeValidation.js +28 -11
  16. package/dist/EditorStyleSheetNormalization.js +85 -38
  17. package/dist/EditorStyleSheetTypes.d.ts +1 -1
  18. package/dist/EditorTheme.d.ts +4 -0
  19. package/dist/EditorTheme.js +5 -3
  20. package/dist/EditorToolbarComponent.d.ts +1 -1
  21. package/dist/EditorToolbarComponent.js +1 -1
  22. package/dist/EditorToolbarRegistry.js +5 -5
  23. package/dist/EditorToolbarTypes.d.ts +12 -12
  24. package/dist/EditorToolbarVisuals.js +1 -1
  25. package/dist/ExternalTextComposition.js +89 -43
  26. package/dist/ImageLoadingPolicy.d.ts +1 -1
  27. package/dist/NativeEditorBoundaryError.d.ts +7 -7
  28. package/dist/NativeEditorBoundaryError.js +9 -5
  29. package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
  30. package/dist/NativeEditorCollaborationTransport.js +28 -15
  31. package/dist/NativeEditorCreateConfig.js +11 -6
  32. package/dist/NativeEditorCreateJson.js +51 -25
  33. package/dist/NativeEditorCreateValidation.js +11 -6
  34. package/dist/NativeEditorDocumentBridge.d.ts +1 -1
  35. package/dist/NativeEditorDocumentBridge.js +32 -18
  36. package/dist/NativeEditorDocumentHandle.d.ts +4 -4
  37. package/dist/NativeEditorDocumentHandle.js +1 -1
  38. package/dist/NativeEditorLocalAwareness.js +25 -13
  39. package/dist/NativeEditorNativeModule.d.ts +8 -1
  40. package/dist/NativeEditorNativeModule.js +7 -5
  41. package/dist/NativeEditorRenderNormalization.js +66 -25
  42. package/dist/NativeEditorResultNormalization.js +53 -29
  43. package/dist/NativeEditorTypes.d.ts +10 -10
  44. package/dist/NativeEditorV2Decimal.js +6 -3
  45. package/dist/NativeProseViewer.js +11 -3
  46. package/dist/ResourceLimits.d.ts +2 -2
  47. package/dist/ResourceLimits.js +7 -2
  48. package/dist/RichTextEditor.js +1 -1
  49. package/dist/RichTextEditorNativeTypes.d.ts +1 -1
  50. package/dist/RichTextEditorNativeView.d.ts +1 -3
  51. package/dist/RichTextEditorSerialization.js +24 -14
  52. package/dist/RichTextEditorTypes.d.ts +1 -1
  53. package/dist/YjsCollaboration.d.ts +7 -7
  54. package/dist/YjsCollaboration.js +42 -26
  55. package/dist/addons.d.ts +4 -4
  56. package/dist/addons.js +3 -3
  57. package/dist/atomInstances.js +6 -3
  58. package/dist/atomUpdates.js +7 -4
  59. package/dist/atoms.js +20 -12
  60. package/dist/attributeValidation.js +55 -24
  61. package/dist/contentExpression.js +80 -42
  62. package/dist/listMarkers.d.ts +1 -1
  63. package/dist/listMarkers.js +1 -1
  64. package/dist/schemaDefinition.d.ts +1 -1
  65. package/dist/schemaDefinition.js +23 -14
  66. package/dist/schemaDocument.js +1 -1
  67. package/dist/schemaDocumentConstruction.js +25 -14
  68. package/dist/schemaNormalization.js +51 -29
  69. package/dist/schemaPresets.d.ts +1 -1
  70. package/dist/schemaPresets.js +9 -4
  71. package/dist/schemaResolution.js +46 -25
  72. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
  73. package/dist/useEditorToolbarInteractions.d.ts +2 -2
  74. package/dist/useEditorToolbarInteractions.js +45 -23
  75. package/dist/useEditorToolbarItems.d.ts +1 -1
  76. package/dist/useEditorToolbarItems.js +4 -3
  77. package/dist/useEditorToolbarPresentation.d.ts +3 -3
  78. package/dist/useEditorToolbarPresentation.js +4 -4
  79. package/dist/useEditorToolbarState.d.ts +1 -1
  80. package/dist/useEditorToolbarState.js +1 -1
  81. package/dist/useFocusPreservingFrames.js +11 -8
  82. package/dist/useNativeEditor.d.ts +1 -1
  83. package/dist/useNativeEditor.js +21 -11
  84. package/dist/useRichTextEditorCommands.d.ts +2 -2
  85. package/dist/useRichTextEditorCommands.js +59 -29
  86. package/dist/useRichTextEditorEvents.d.ts +3 -3
  87. package/dist/useRichTextEditorEvents.js +75 -32
  88. package/dist/useRichTextEditorMentions.d.ts +4 -4
  89. package/dist/useRichTextEditorMentions.js +48 -29
  90. package/dist/useRichTextEditorPresentation.d.ts +4 -4
  91. package/dist/useRichTextEditorPresentation.js +25 -23
  92. package/dist/useRichTextEditorState.d.ts +3 -3
  93. package/dist/useRichTextEditorState.js +20 -15
  94. package/dist/useRichTextEditorUpdates.d.ts +1 -1
  95. package/dist/useRichTextEditorUpdates.js +99 -41
  96. package/dist/useViewerAtoms.js +63 -36
  97. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  98. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  99. package/ios/EditorInteractionOverlays.swift +114 -122
  100. package/ios/EditorLayoutManager.swift +13 -3
  101. package/ios/EditorStyleSheet.swift +12 -1
  102. package/ios/EditorTextView+Images.swift +32 -10
  103. package/ios/EditorTextView.swift +1 -1
  104. package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
  105. package/ios/NativeToolbar+ButtonStyle.swift +17 -5
  106. package/ios/NativeToolbar+Diagnostics.swift +15 -0
  107. package/ios/RenderBridge+Atoms.swift +0 -1
  108. package/ios/RenderBridge+Attachments.swift +0 -29
  109. package/ios/RichTextEditorView.swift +4 -12
  110. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
  111. package/package.json +11 -3
  112. package/react-native.config.js +1 -1
  113. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  114. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  115. package/rust/android/x86/libeditor_core.so +0 -0
  116. package/rust/android/x86_64/libeditor_core.so +0 -0
  117. package/src/AtomHost.tsx +58 -28
  118. package/src/EditorAddon.ts +18 -8
  119. package/src/EditorAddonNormalization.ts +40 -11
  120. package/src/EditorMentionThemeNormalization.ts +15 -4
  121. package/src/EditorMentionThemeValidation.ts +51 -14
  122. package/src/EditorStyleSheet.ts +1 -0
  123. package/src/EditorStyleSheetNormalization.ts +195 -64
  124. package/src/EditorStyleSheetTypes.ts +1 -1
  125. package/src/EditorTheme.ts +13 -5
  126. package/src/EditorToolbarComponent.tsx +2 -1
  127. package/src/EditorToolbarRegistry.tsx +23 -13
  128. package/src/EditorToolbarTypes.tsx +12 -12
  129. package/src/EditorToolbarVisuals.tsx +6 -3
  130. package/src/EditorUpdateRevision.ts +1 -0
  131. package/src/ExternalTextComposition.ts +259 -49
  132. package/src/ImageLoadingPolicy.ts +3 -1
  133. package/src/NativeEditorBoundaryError.ts +38 -11
  134. package/src/NativeEditorCollaborationTransport.ts +108 -27
  135. package/src/NativeEditorCreateConfig.ts +92 -19
  136. package/src/NativeEditorCreateJson.ts +163 -26
  137. package/src/NativeEditorCreateValidation.ts +33 -12
  138. package/src/NativeEditorDocumentBridge.ts +111 -19
  139. package/src/NativeEditorDocumentHandle.ts +9 -4
  140. package/src/NativeEditorLocalAwareness.ts +70 -15
  141. package/src/NativeEditorNativeModule.ts +13 -9
  142. package/src/NativeEditorRenderNormalization.ts +128 -29
  143. package/src/NativeEditorResultNormalization.ts +143 -32
  144. package/src/NativeEditorTypes.ts +12 -11
  145. package/src/NativeEditorV2Decimal.ts +12 -3
  146. package/src/NativeProseViewer.tsx +46 -16
  147. package/src/ResourceLimits.ts +15 -8
  148. package/src/RichTextEditor.tsx +3 -1
  149. package/src/RichTextEditorNativeTypes.tsx +1 -1
  150. package/src/RichTextEditorNativeView.tsx +2 -8
  151. package/src/RichTextEditorSerialization.tsx +70 -24
  152. package/src/RichTextEditorTypes.tsx +1 -1
  153. package/src/YjsCollaboration.ts +143 -47
  154. package/src/addons.ts +12 -8
  155. package/src/atomInstances.ts +25 -5
  156. package/src/atomUpdates.ts +23 -6
  157. package/src/atoms.ts +85 -18
  158. package/src/attributeValidation.ts +97 -33
  159. package/src/contentExpression.ts +218 -63
  160. package/src/listMarkers.ts +1 -1
  161. package/src/schemaDefinition.ts +82 -20
  162. package/src/schemaDocument.ts +15 -1
  163. package/src/schemaDocumentConstruction.ts +80 -16
  164. package/src/schemaNormalization.ts +155 -41
  165. package/src/schemaPresets.ts +37 -31
  166. package/src/schemaResolution.ts +126 -27
  167. package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
  168. package/src/useEditorToolbarInteractions.tsx +85 -36
  169. package/src/useEditorToolbarItems.tsx +50 -22
  170. package/src/useEditorToolbarPresentation.tsx +81 -58
  171. package/src/useEditorToolbarState.tsx +8 -6
  172. package/src/useFocusPreservingFrames.ts +43 -15
  173. package/src/useNativeEditor.ts +111 -51
  174. package/src/useRichTextEditorCommands.tsx +127 -54
  175. package/src/useRichTextEditorEvents.tsx +144 -42
  176. package/src/useRichTextEditorMentions.tsx +118 -37
  177. package/src/useRichTextEditorPresentation.tsx +128 -114
  178. package/src/useRichTextEditorState.tsx +76 -40
  179. package/src/useRichTextEditorUpdates.tsx +207 -56
  180. package/src/useViewerAtoms.tsx +162 -66
@@ -28,11 +28,16 @@ export function schemaBoundaryError(limit: number, actual: number): NativeEditor
28
28
  /** Mirror native's invalid-schema fallback before constructing an empty doc. */
29
29
  export function utf8ByteLengthUpTo(value: string, maximum: number): number {
30
30
  let bytes = 0;
31
+
31
32
  for (const char of value) {
32
33
  const codePoint = char.codePointAt(0) ?? 0;
33
34
  bytes += codePoint <= 0x7f ? 1 : codePoint <= 0x7ff ? 2 : codePoint <= 0xffff ? 3 : 4;
34
- if (bytes > maximum) return bytes;
35
+
36
+ if (bytes > maximum) {
37
+ return bytes;
38
+ }
35
39
  }
40
+
36
41
  return bytes;
37
42
  }
38
43
 
@@ -43,16 +48,28 @@ export function forEachGroupToken(
43
48
  consumeToken?: () => boolean
44
49
  ): boolean {
45
50
  let tokenStart = -1;
51
+
46
52
  for (let index = 0; index <= group.length; index += 1) {
47
- if (index < group.length && consumeCharacter && !consumeCharacter()) return false;
53
+ if (index < group.length && consumeCharacter && !consumeCharacter()) {
54
+ return false;
55
+ }
56
+
48
57
  const isBoundary = index === group.length || /\s/.test(group[index]);
49
- if (!isBoundary && tokenStart < 0) tokenStart = index;
58
+
59
+ if (!isBoundary && tokenStart < 0) {
60
+ tokenStart = index;
61
+ }
62
+
50
63
  if (isBoundary && tokenStart >= 0) {
51
- if (consumeToken && !consumeToken()) return false;
64
+ if (consumeToken && !consumeToken()) {
65
+ return false;
66
+ }
67
+
52
68
  visit(group.slice(tokenStart, index));
53
69
  tokenStart = -1;
54
70
  }
55
71
  }
72
+
56
73
  return true;
57
74
  }
58
75
 
@@ -74,9 +91,12 @@ export function consumeSchemaWork(budget: SchemaWorkBudget): boolean {
74
91
  export function consumeSchemaWorkAmount(budget: SchemaWorkBudget, amount: number): boolean {
75
92
  if (amount > budget.limit - budget.work) {
76
93
  budget.exhausted = true;
94
+
77
95
  return false;
78
96
  }
97
+
79
98
  budget.work += amount;
99
+
80
100
  return true;
81
101
  }
82
102
 
@@ -88,34 +108,58 @@ export function collectOwnAttrs(
88
108
  value: unknown,
89
109
  budget: SchemaWorkBudget
90
110
  ): Array<[string, AttrSpec]> | null {
91
- if (value == null || typeof value !== 'object' || Array.isArray(value)) return [];
111
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
112
+ return [];
113
+ }
114
+
92
115
  const attrs: Array<[string, AttrSpec]> = [];
116
+
93
117
  for (const name in value) {
94
- if (!Object.prototype.hasOwnProperty.call(value, name)) continue;
95
- if (!consumeSchemaWork(budget)) return attrs;
96
- attrs.push([name, (value as Record<string, AttrSpec>)[name]]);
118
+ if (!Object.prototype.hasOwnProperty.call(value, name)) {
119
+ continue;
120
+ }
121
+
122
+ if (!consumeSchemaWork(budget)) {
123
+ return attrs;
124
+ }
125
+
126
+ attrs.push([ name, (value as Record<string, AttrSpec>)[name] ]);
97
127
  }
128
+
98
129
  return attrs;
99
130
  }
100
131
 
101
132
  export function isSafeHtmlTag(tag: string): boolean {
102
- if (tag.length === 0 || tag[0] < 'a' || tag[0] > 'z') return false;
133
+ if (tag.length === 0 || tag[0] < 'a' || tag[0] > 'z') {
134
+ return false;
135
+ }
136
+
103
137
  for (let index = 1; index < tag.length; index += 1) {
104
138
  const char = tag[index];
139
+
105
140
  if (!((char >= 'a' && char <= 'z') || (char >= '0' && char <= '9') || char === '-')) {
106
141
  return false;
107
142
  }
108
143
  }
144
+
109
145
  return true;
110
146
  }
111
147
 
112
148
  export function isSafeHtmlAttr(name: string): boolean {
113
- if (name.length === 0) return false;
149
+ if (name.length === 0) {
150
+ return false;
151
+ }
152
+
114
153
  const isAlpha = (char: string): boolean =>
115
154
  (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z');
116
- if (!(isAlpha(name[0]) || name[0] === '_' || name[0] === ':')) return false;
155
+
156
+ if (!(isAlpha(name[0]) || name[0] === '_' || name[0] === ':')) {
157
+ return false;
158
+ }
159
+
117
160
  for (let index = 1; index < name.length; index += 1) {
118
161
  const char = name[index];
162
+
119
163
  if (
120
164
  !(
121
165
  isAlpha(char) ||
@@ -129,21 +173,27 @@ export function isSafeHtmlAttr(name: string): boolean {
129
173
  return false;
130
174
  }
131
175
  }
176
+
132
177
  return true;
133
178
  }
134
179
 
135
180
  export function normalizeAttrs(value: unknown): Record<string, AttrSpec> {
136
- if (value == null || typeof value !== 'object' || Array.isArray(value)) return {};
181
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
182
+ return {};
183
+ }
184
+
137
185
  return Object.fromEntries(
138
- Object.entries(value).map(([name, rawSpec]) => {
186
+ Object.entries(value as Record<string, unknown>).map(([ name, rawSpec ]) => {
139
187
  if (rawSpec == null || typeof rawSpec !== 'object' || Array.isArray(rawSpec)) {
140
- return [name, {}];
188
+ return [ name, {} ];
141
189
  }
142
- validateAttributeSpec(rawSpec as AttrSpec, name);
190
+
191
+ validateAttributeSpec(rawSpec, name);
192
+
143
193
  return [
144
194
  name,
145
195
  Object.fromEntries(
146
- Object.entries(rawSpec).filter(([, entry]) => entry !== undefined)
196
+ Object.entries(rawSpec).filter(([ , entry ]) => entry !== undefined)
147
197
  ),
148
198
  ];
149
199
  })
@@ -151,15 +201,35 @@ export function normalizeAttrs(value: unknown): Record<string, AttrSpec> {
151
201
  }
152
202
 
153
203
  export function normalizeNodeJSONProjection(value: unknown): NodeJSONProjection | null | undefined {
154
- if (value === undefined) return undefined;
155
- if (value == null || typeof value !== 'object' || Array.isArray(value)) return null;
204
+ if (value === undefined) {
205
+ return undefined;
206
+ }
207
+
208
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
209
+ return null;
210
+ }
211
+
156
212
  const raw = value as Record<string, unknown>;
157
- if (typeof raw.type !== 'string' || raw.type.length === 0) return null;
158
- if (raw.attrs === undefined) return { type: raw.type };
159
- if (raw.attrs == null || typeof raw.attrs !== 'object' || Array.isArray(raw.attrs)) return null;
213
+
214
+ if (typeof raw.type !== 'string' || raw.type.length === 0) {
215
+ return null;
216
+ }
217
+
218
+ if (raw.attrs === undefined) {
219
+ return { type: raw.type };
220
+ }
221
+
222
+ if (raw.attrs == null || typeof raw.attrs !== 'object' || Array.isArray(raw.attrs)) {
223
+ return null;
224
+ }
225
+
160
226
  const attrs: Record<string, unknown> = {};
161
- for (const [name, attrValue] of Object.entries(raw.attrs)) {
162
- if (!isSafeHtmlAttr(name)) return null;
227
+
228
+ for (const [ name, attrValue ] of Object.entries(raw.attrs)) {
229
+ if (!isSafeHtmlAttr(name)) {
230
+ return null;
231
+ }
232
+
163
233
  if (
164
234
  attrValue !== null &&
165
235
  typeof attrValue !== 'string' &&
@@ -168,8 +238,10 @@ export function normalizeNodeJSONProjection(value: unknown): NodeJSONProjection
168
238
  ) {
169
239
  return null;
170
240
  }
241
+
171
242
  attrs[name] = attrValue;
172
243
  }
244
+
173
245
  return Object.keys(attrs).length === 0 ? { type: raw.type } : { type: raw.type, attrs };
174
246
  }
175
247
 
@@ -186,42 +258,62 @@ export function isSafeAtomHtmlAttr(name: string): boolean {
186
258
  }
187
259
 
188
260
  export function normalizeNodeHtmlRules(value: unknown): NodeHtmlRules | null | undefined {
189
- if (value === undefined) return undefined;
190
- if (value == null || typeof value !== 'object' || Array.isArray(value)) return null;
261
+ if (value === undefined) {
262
+ return undefined;
263
+ }
264
+
265
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
266
+ return null;
267
+ }
268
+
191
269
  const raw = value as Record<string, unknown>;
270
+
192
271
  if (
193
272
  Object.keys(raw).some(
194
- (key) => key !== 'tag' && key !== 'staticAttrs' && key !== 'attrMap'
273
+ key => key !== 'tag' && key !== 'staticAttrs' && key !== 'attrMap'
195
274
  ) ||
196
275
  typeof raw.tag !== 'string' ||
197
276
  !isSafeAtomHtmlTag(raw.tag)
198
277
  ) {
199
278
  return null;
200
279
  }
280
+
201
281
  const normalizeMap = (
202
282
  candidate: unknown,
203
283
  validateName: (name: string) => boolean
204
284
  ): Record<string, string> | null | undefined => {
205
- if (candidate === undefined) return undefined;
285
+ if (candidate === undefined) {
286
+ return undefined;
287
+ }
288
+
206
289
  if (candidate == null || typeof candidate !== 'object' || Array.isArray(candidate)) {
207
290
  return null;
208
291
  }
292
+
209
293
  const normalized: Record<string, string> = {};
210
- for (const [name, mapped] of Object.entries(candidate)) {
211
- if (!validateName(name) || typeof mapped !== 'string') return null;
294
+
295
+ for (const [ name, mapped ] of Object.entries(candidate)) {
296
+ if (!validateName(name) || typeof mapped !== 'string') {
297
+ return null;
298
+ }
299
+
212
300
  normalized[name] = mapped;
213
301
  }
302
+
214
303
  return normalized;
215
304
  };
305
+
216
306
  const staticAttrs = normalizeMap(raw.staticAttrs, isSafeAtomHtmlAttr);
217
307
  const attrMap = normalizeMap(raw.attrMap, isSafeHtmlAttr);
308
+
218
309
  if (
219
310
  staticAttrs === null ||
220
311
  attrMap === null ||
221
- (attrMap != null && Object.values(attrMap).some((name) => !isSafeAtomHtmlAttr(name)))
312
+ (attrMap != null && Object.values(attrMap).some(name => !isSafeAtomHtmlAttr(name)))
222
313
  ) {
223
314
  return null;
224
315
  }
316
+
225
317
  return {
226
318
  tag: raw.tag,
227
319
  ...(staticAttrs == null ? {} : { staticAttrs }),
@@ -234,20 +326,25 @@ export function projectionAttrsOverlap(
234
326
  right: Record<string, unknown>
235
327
  ): boolean {
236
328
  return Object.entries(left).every(
237
- ([name, value]) =>
329
+ ([ name, value ]) =>
238
330
  !Object.prototype.hasOwnProperty.call(right, name) || right[name] === value
239
331
  );
240
332
  }
241
333
 
242
334
  export function legacyHeadingProjectionName(projection: NodeJSONProjection): string | undefined {
243
- if (projection.type !== 'heading') return undefined;
335
+ if (projection.type !== 'heading') {
336
+ return undefined;
337
+ }
338
+
244
339
  const value = projection.attrs?.level;
245
340
  let level: number | undefined;
341
+
246
342
  if (typeof value === 'number' && Number.isInteger(value)) {
247
343
  level = value;
248
344
  } else if (typeof value === 'string' && value.length <= 3 && /^\+?\d+$/.test(value)) {
249
345
  level = Number(value);
250
346
  }
347
+
251
348
  return level != null && level >= 1 && level <= 6 ? `h${level}` : undefined;
252
349
  }
253
350
 
@@ -269,25 +366,31 @@ export function normalizeSchemaDefinition(
269
366
  return 'block';
270
367
  }
271
368
  };
369
+
272
370
  const nodes: NodeSpec[] = [];
371
+
273
372
  for (let nodeIndex = 0; nodeIndex < schema.nodes.length; nodeIndex += 1) {
274
373
  const rawNode = schema.nodes[nodeIndex];
374
+
275
375
  if (rawNode == null || typeof rawNode !== 'object' || typeof rawNode.name !== 'string') {
276
376
  return null;
277
377
  }
278
- const raw = rawNode as unknown as Record<string, unknown>;
378
+
379
+ const raw = rawNode;
279
380
  const htmlTag = typeof raw.htmlTag === 'string' ? raw.htmlTag : undefined;
280
381
  const html = normalizeNodeHtmlRules(raw.html);
281
382
  const attrs = normalizeAttrs(raw.attrs);
282
383
  const json = normalizeNodeJSONProjection(raw.json);
384
+
283
385
  if (
284
386
  (htmlTag != null && !isSafeHtmlTag(htmlTag)) ||
285
387
  html === null ||
286
388
  json === null ||
287
- Object.keys(attrs).some((name) => !isSafeHtmlAttr(name))
389
+ Object.keys(attrs).some(name => !isSafeHtmlAttr(name))
288
390
  ) {
289
391
  return null;
290
392
  }
393
+
291
394
  nodes.push({
292
395
  name: rawNode.name,
293
396
  content: typeof raw.content === 'string' ? raw.content : '',
@@ -306,29 +409,34 @@ export function normalizeSchemaDefinition(
306
409
  : {}),
307
410
  });
308
411
  }
309
- const nativeNodeNames = new Set(nodes.map((node) => node.name));
310
- const projectedNodes = nodes.filter((node) => node.json != null);
412
+
413
+ const nativeNodeNames = new Set(nodes.map(node => node.name));
414
+ const projectedNodes = nodes.filter(node => node.json != null);
415
+
311
416
  for (let index = 0; index < projectedNodes.length; index += 1) {
312
417
  const node = projectedNodes[index];
313
418
  const projection = node.json as NodeJSONProjection;
314
419
  const legacyHeadingName = legacyHeadingProjectionName(projection);
420
+
315
421
  if (
316
422
  nativeNodeNames.has(projection.type) ||
317
423
  RESERVED_WIRE_NODE_TYPES.has(projection.type) ||
318
424
  (legacyHeadingName != null &&
319
425
  legacyHeadingName !== node.name &&
320
426
  nativeNodeNames.has(legacyHeadingName)) ||
321
- Object.keys(projection.attrs ?? {}).some((name) =>
322
- Object.prototype.hasOwnProperty.call(node.attrs ?? {}, name)
323
- )
427
+ Object.keys(projection.attrs ?? {}).some(name =>
428
+ Object.prototype.hasOwnProperty.call(node.attrs ?? {}, name))
324
429
  ) {
325
430
  return null;
326
431
  }
432
+
327
433
  for (let previousIndex = 0; previousIndex < index; previousIndex += 1) {
328
434
  if (budget != null && !consumeSchemaWork(budget)) {
329
435
  throw schemaBoundaryError(budget.limit, budget.limit + 1);
330
436
  }
437
+
331
438
  const previous = projectedNodes[previousIndex];
439
+
332
440
  if (
333
441
  previous.json?.type === projection.type &&
334
442
  projectionAttrsOverlap(projection.attrs ?? {}, previous.json.attrs ?? {})
@@ -339,20 +447,25 @@ export function normalizeSchemaDefinition(
339
447
  }
340
448
 
341
449
  const marks: MarkSpec[] = [];
450
+
342
451
  for (let markIndex = 0; markIndex < schema.marks.length; markIndex += 1) {
343
452
  const rawMark = schema.marks[markIndex];
453
+
344
454
  if (rawMark == null || typeof rawMark !== 'object' || typeof rawMark.name !== 'string') {
345
455
  return null;
346
456
  }
347
- const raw = rawMark as unknown as Record<string, unknown>;
457
+
458
+ const raw = rawMark;
348
459
  const htmlTag = typeof raw.htmlTag === 'string' ? raw.htmlTag.toLowerCase() : undefined;
349
460
  const attrs = normalizeAttrs(raw.attrs);
461
+
350
462
  if (
351
463
  (htmlTag != null && !ALLOWED_MARK_HTML_TAGS.has(htmlTag)) ||
352
- Object.keys(attrs).some((name) => !isSafeHtmlAttr(name))
464
+ Object.keys(attrs).some(name => !isSafeHtmlAttr(name))
353
465
  ) {
354
466
  return null;
355
467
  }
468
+
356
469
  marks.push({
357
470
  name: rawMark.name,
358
471
  ...(Object.keys(attrs).length > 0 ? { attrs } : {}),
@@ -363,5 +476,6 @@ export function normalizeSchemaDefinition(
363
476
  : {}),
364
477
  });
365
478
  }
479
+
366
480
  return { nodes, marks };
367
481
  }
@@ -24,7 +24,7 @@ export interface ImageNodeAttributes {
24
24
  export interface ResolvedDocumentSchema {
25
25
  /** The schema itself, defaulted to {@link defaultSchema} when none was supplied. */
26
26
  schema: SchemaDefinition;
27
- /** Name of the node with `role: 'doc'` the `type` of a document's root. */
27
+ /** Name of the node with `role: 'doc'` : the `type` of a document's root. */
28
28
  documentNodeName: string;
29
29
  /** The smallest document this schema admits. Used by `clearContent()`. */
30
30
  emptyDocument: DocumentJSON;
@@ -38,7 +38,12 @@ export type DocumentDescriptorLimits = Pick<
38
38
  /** Node name the built-in image node is stored under. */
39
39
  export const IMAGE_NODE_NAME = 'image';
40
40
 
41
- export const HEADING_LEVELS = [1, 2, 3, 4, 5, 6] as const;
41
+ export const HEADING_LEVELS = [ 1,
42
+ 2,
43
+ 3,
44
+ 4,
45
+ 5,
46
+ 6 ] as const;
42
47
 
43
48
  /**
44
49
  * The built-in image node spec: a void block node carrying
@@ -57,15 +62,15 @@ export function imageSchemaNodeSpec(): SchemaNodeSpec {
57
62
  height: { default: null },
58
63
  },
59
64
  role: 'block',
60
- parseDOM: [{ tag: 'img' }],
61
- toDOM: ['img'],
65
+ parseDOM: [ { tag: 'img' } ],
66
+ toDOM: [ 'img' ],
62
67
  isVoid: true,
63
68
  deletableOnBackspace: false,
64
69
  };
65
70
  }
66
71
 
67
72
  export function imageNodeSpec(name: string = IMAGE_NODE_NAME): NodeSpec {
68
- return defineSchema({ nodes: { [name]: imageSchemaNodeSpec() } }).nodes[0]!;
73
+ return defineSchema({ nodes: { [name]: imageSchemaNodeSpec() } }).nodes[0];
69
74
  }
70
75
 
71
76
  /**
@@ -73,14 +78,15 @@ export function imageNodeSpec(name: string = IMAGE_NODE_NAME): NodeSpec {
73
78
  * already declares one. {@link tiptapCompatibleSchema} already includes it.
74
79
  */
75
80
  export function withImagesSchema(schema: SchemaDefinition): SchemaDefinition {
76
- const hasImageNode = schema.nodes.some((node) => node.name === IMAGE_NODE_NAME);
81
+ const hasImageNode = schema.nodes.some(node => node.name === IMAGE_NODE_NAME);
82
+
77
83
  if (hasImageNode) {
78
84
  return schema;
79
85
  }
80
86
 
81
87
  return {
82
88
  ...schema,
83
- nodes: [...schema.nodes, imageNodeSpec()],
89
+ nodes: [ ...schema.nodes, imageNodeSpec() ],
84
90
  };
85
91
  }
86
92
 
@@ -130,22 +136,22 @@ export const tiptapCompatibleSchemaSpec: SchemaSpec = {
130
136
  content: 'inline*',
131
137
  group: 'block',
132
138
  role: 'textBlock',
133
- parseDOM: [{ tag: 'p' }],
134
- toDOM: ['p', 0],
139
+ parseDOM: [ { tag: 'p' } ],
140
+ toDOM: [ 'p', 0 ],
135
141
  },
136
142
  heading: {
137
143
  content: 'inline*',
138
144
  group: 'block',
139
145
  role: 'heading',
140
146
  attrs: { level: { default: 1 } },
141
- parseDOM: HEADING_LEVELS.map((level) => ({
147
+ parseDOM: HEADING_LEVELS.map(level => ({
142
148
  tag: `h${level}`,
143
149
  attrs: { level },
144
150
  })),
145
151
  toDOM: {
146
152
  switchOn: 'level',
147
153
  cases: Object.fromEntries(
148
- HEADING_LEVELS.map((level) => [level, [`h${level}`, 0] as const])
154
+ HEADING_LEVELS.map(level => [ level, [ `h${level}`, 0 ] as const ])
149
155
  ),
150
156
  },
151
157
  },
@@ -153,62 +159,62 @@ export const tiptapCompatibleSchemaSpec: SchemaSpec = {
153
159
  content: 'block+',
154
160
  group: 'block',
155
161
  role: 'block',
156
- parseDOM: [{ tag: 'blockquote' }],
157
- toDOM: ['blockquote', 0],
162
+ parseDOM: [ { tag: 'blockquote' } ],
163
+ toDOM: [ 'blockquote', 0 ],
158
164
  },
159
165
  codeBlock: {
160
166
  attrs: { language: { default: null } },
161
167
  content: 'text*',
162
168
  group: 'block',
163
169
  role: 'textBlock',
164
- parseDOM: [{ tag: 'pre' }],
165
- toDOM: ['pre', 0],
170
+ parseDOM: [ { tag: 'pre' } ],
171
+ toDOM: [ 'pre', 0 ],
166
172
  },
167
173
  bulletList: {
168
174
  content: 'listItem+',
169
175
  group: 'block',
170
176
  role: 'list',
171
- parseDOM: [{ tag: 'ul' }],
172
- toDOM: ['ul', 0],
177
+ parseDOM: [ { tag: 'ul' } ],
178
+ toDOM: [ 'ul', 0 ],
173
179
  },
174
180
  orderedList: {
175
181
  content: 'listItem+',
176
182
  group: 'block',
177
183
  attrs: { start: { default: 1 } },
178
184
  role: 'list',
179
- parseDOM: [{ tag: 'ol' }],
180
- toDOM: ['ol', 0],
185
+ parseDOM: [ { tag: 'ol' } ],
186
+ toDOM: [ 'ol', 0 ],
181
187
  },
182
188
  listItem: {
183
189
  content: 'paragraph block*',
184
190
  role: 'listItem',
185
- parseDOM: [{ tag: 'li' }],
186
- toDOM: ['li', 0],
191
+ parseDOM: [ { tag: 'li' } ],
192
+ toDOM: [ 'li', 0 ],
187
193
  },
188
194
  hardBreak: {
189
195
  group: 'inline',
190
196
  role: 'hardBreak',
191
- parseDOM: [{ tag: 'br' }],
192
- toDOM: ['br'],
197
+ parseDOM: [ { tag: 'br' } ],
198
+ toDOM: [ 'br' ],
193
199
  isVoid: true,
194
200
  },
195
201
  horizontalRule: {
196
202
  group: 'block',
197
203
  role: 'block',
198
- parseDOM: [{ tag: 'hr' }],
199
- toDOM: ['hr'],
204
+ parseDOM: [ { tag: 'hr' } ],
205
+ toDOM: [ 'hr' ],
200
206
  isVoid: true,
201
207
  },
202
208
  [IMAGE_NODE_NAME]: imageSchemaNodeSpec(),
203
209
  text: { group: 'inline', role: 'text' },
204
210
  },
205
211
  marks: {
206
- bold: { parseDOM: [{ tag: 'strong' }], toDOM: ['strong', 0] },
207
- italic: { parseDOM: [{ tag: 'em' }], toDOM: ['em', 0] },
208
- underline: { parseDOM: [{ tag: 'u' }], toDOM: ['u', 0] },
209
- strike: { parseDOM: [{ tag: 's' }], toDOM: ['s', 0] },
210
- code: { parseDOM: [{ tag: 'code' }], toDOM: ['code', 0] },
211
- link: { attrs: { href: {} }, parseDOM: [{ tag: 'a' }], toDOM: ['a', 0] },
212
+ bold: { parseDOM: [ { tag: 'strong' } ], toDOM: [ 'strong', 0 ] },
213
+ italic: { parseDOM: [ { tag: 'em' } ], toDOM: [ 'em', 0 ] },
214
+ underline: { parseDOM: [ { tag: 'u' } ], toDOM: [ 'u', 0 ] },
215
+ strike: { parseDOM: [ { tag: 's' } ], toDOM: [ 's', 0 ] },
216
+ code: { parseDOM: [ { tag: 'code' } ], toDOM: [ 'code', 0 ] },
217
+ link: { attrs: { href: {} }, parseDOM: [ { tag: 'a' } ], toDOM: [ 'a', 0 ] },
212
218
  },
213
219
  };
214
220