@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
@@ -1,5 +1,5 @@
1
- import { useRichTextEditorState } from './useRichTextEditorState';
2
- import { useRichTextEditorMentions } from './useRichTextEditorMentions';
3
- import { useRichTextEditorCommands } from './useRichTextEditorCommands';
4
- import { useRichTextEditorEvents } from './useRichTextEditorEvents';
1
+ import { type useRichTextEditorState } from './useRichTextEditorState';
2
+ import { type useRichTextEditorMentions } from './useRichTextEditorMentions';
3
+ import { type useRichTextEditorCommands } from './useRichTextEditorCommands';
4
+ import { type useRichTextEditorEvents } from './useRichTextEditorEvents';
5
5
  export declare function useRichTextEditorPresentation(context: Pick<ReturnType<typeof useRichTextEditorState>, 'theme' | 'addons' | 'imageLoadingPolicy' | 'androidInputOptions' | 'remoteSelections' | 'atoms' | 'atomState' | 'atomComponents' | 'warnedUnknownAtomTypesRef' | 'atomContentWidth' | 'atomPositions' | 'atomViewport' | 'virtualizeAtoms' | 'nativeAtomViewport' | 'selectedKeys' | 'editable' | 'atomsInteractive' | 'documentHandle' | 'activeState' | 'onRequestLink' | 'onRequestImage' | 'toolbarItemsSerializationCacheRef' | 'toolbarItems' | 'document' | 'toolbarPlacement' | 'showToolbar' | 'containerStyle' | 'style' | 'heightBehavior' | 'autoGrowHeight' | 'pushedUpdate' | 'editorId' | 'registeredToolbarFrames' | 'suppliedFocusPreservingFrames' | 'isFocused' | 'nativeViewRef' | 'refreshFocusPreservingFrames' | 'accessibilityLabel' | 'accessibilityHint' | 'placeholder' | 'autoFocus' | 'autoCapitalize' | 'autoCorrect' | 'keyboardType' | 'allowImageResizing' | 'toolbarFrameOwnerId' | 'onToolbarAction'> & Pick<ReturnType<typeof useRichTextEditorMentions>, 'mentionSuggestionTheme' | 'handleAddonEvent'> & Pick<ReturnType<typeof useRichTextEditorCommands>, 'runAtomAction' | 'updateAtomAttrs' | 'atomOwnerRef' | 'commandToggleMark' | 'commandToggleList' | 'commandToggleHeading' | 'commandToggleBlockquote' | 'commandInsertNode' | 'commandIndentListItem' | 'commandOutdentListItem' | 'openLinkRequest' | 'openImageRequest'> & Pick<ReturnType<typeof useRichTextEditorEvents>, 'handleEditorUpdate' | 'handleEditorError' | 'handleExternalTextCompositionEnd' | 'handleSelectionChange' | 'handleFocusChange' | 'handleContentHeightChange' | 'handleAtomLayout' | 'handleToolbarAction'>): import("react/jsx-runtime").JSX.Element | null;
@@ -19,10 +19,10 @@ const RichTextEditorNativeView_1 = require("./RichTextEditorNativeView");
19
19
  function useRichTextEditorPresentation(context) {
20
20
  const { theme, mentionSuggestionTheme, addons, imageLoadingPolicy, androidInputOptions, remoteSelections, atoms, atomState, atomComponents, warnedUnknownAtomTypesRef, runAtomAction, updateAtomAttrs, atomOwnerRef, atomContentWidth, atomPositions, atomViewport, virtualizeAtoms, nativeAtomViewport, selectedKeys, editable, atomsInteractive, documentHandle, activeState, onRequestLink, onRequestImage, toolbarItemsSerializationCacheRef, toolbarItems, document, toolbarPlacement, showToolbar, containerStyle, style, heightBehavior, autoGrowHeight, pushedUpdate, editorId, registeredToolbarFrames, suppliedFocusPreservingFrames, isFocused, nativeViewRef, refreshFocusPreservingFrames, accessibilityLabel, accessibilityHint, placeholder, autoFocus, autoCapitalize, autoCorrect, keyboardType, allowImageResizing, handleEditorUpdate, handleEditorError, handleExternalTextCompositionEnd, handleSelectionChange, handleFocusChange, handleContentHeightChange, handleAtomLayout, handleToolbarAction, handleAddonEvent, toolbarFrameOwnerId, commandToggleMark, commandToggleList, commandToggleHeading, commandToggleBlockquote, commandInsertNode, commandIndentListItem, commandOutdentListItem, openLinkRequest, openImageRequest, onToolbarAction, } = context;
21
21
  const themeJson = (0, react_1.useMemo)(() => (0, EditorTheme_1.serializeEditorTheme)(theme, mentionSuggestionTheme), [mentionSuggestionTheme, theme]);
22
- const addonsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(addons, (value) => (0, addons_1.serializeNormalizedEditorAddons)(value));
23
- const imageLoadingPolicyJson = (0, RichTextEditorSerialization_1.useSerializedValue)(imageLoadingPolicy, (value) => (0, ImageLoadingPolicy_1.serializeEditorImageLoadingPolicy)(value));
24
- const androidInputOptionsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(androidInputOptions, (value) => JSON.stringify(value));
25
- const remoteSelectionsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(remoteSelections, (selections) => (0, RichTextEditorSerialization_1.serializeRemoteSelections)(selections));
22
+ const addonsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(addons, value => (0, addons_1.serializeNormalizedEditorAddons)(value));
23
+ const imageLoadingPolicyJson = (0, RichTextEditorSerialization_1.useSerializedValue)(imageLoadingPolicy, value => (0, ImageLoadingPolicy_1.serializeEditorImageLoadingPolicy)(value));
24
+ const androidInputOptionsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(androidInputOptions, value => JSON.stringify(value));
25
+ const remoteSelectionsJson = (0, RichTextEditorSerialization_1.useSerializedValue)(remoteSelections, selections => (0, RichTextEditorSerialization_1.serializeRemoteSelections)(selections));
26
26
  const atomsJson = (0, react_1.useMemo)(() => {
27
27
  const supplied = (0, atoms_1.serializeEditorAtoms)(atoms);
28
28
  const serialized = supplied == null
@@ -38,8 +38,9 @@ function useRichTextEditorPresentation(context) {
38
38
  return serialized.nodeTypes.length === 0 ? undefined : JSON.stringify(serialized);
39
39
  }, [atomState.instances, atoms]);
40
40
  (0, react_1.useEffect)(() => {
41
- if (!__DEV__)
41
+ if (!__DEV__) {
42
42
  return;
43
+ }
43
44
  for (const instance of atomState.instances) {
44
45
  if (atomComponents.has(instance.nodeType) ||
45
46
  warnedUnknownAtomTypesRef.current.has(instance.nodeType)) {
@@ -48,20 +49,21 @@ function useRichTextEditorPresentation(context) {
48
49
  warnedUnknownAtomTypesRef.current.add(instance.nodeType);
49
50
  console.warn(`NativeRichTextEditor: rendering unknown atom type '${instance.nodeType}' as a chip`);
50
51
  }
51
- }, [atomComponents, atomState.instances]);
52
+ }, [atomComponents, atomState.instances, warnedUnknownAtomTypesRef]);
52
53
  const runAtomActionRef = (0, react_1.useRef)(runAtomAction);
53
54
  runAtomActionRef.current = runAtomAction;
54
55
  const invokeAtomAction = (0, react_1.useCallback)((...args) => runAtomActionRef.current(...args), []);
55
56
  const updateAtomAttrsRef = (0, react_1.useRef)(updateAtomAttrs);
56
57
  updateAtomAttrsRef.current = updateAtomAttrs;
57
58
  const invokeAtomAttrsUpdate = (0, react_1.useCallback)((owner, instance, documentVersion, attrs) => {
58
- if (owner !== atomOwnerRef.current)
59
+ if (owner !== atomOwnerRef.current) {
59
60
  return Promise.reject(new atomInstances_1.AtomUpdateAttrsError('not-ready', 'The editor has rebound.'));
61
+ }
60
62
  return updateAtomAttrsRef.current(instance.key, instance.nodeType, instance.docPos, documentVersion, instance.hasStableKey, attrs);
61
- }, []);
63
+ }, [atomOwnerRef]);
62
64
  const atomChildren = (0, react_1.useMemo)(() => atomContentWidth == null
63
65
  ? null
64
- : atomState.instances.map((instance) => {
66
+ : atomState.instances.map(instance => {
65
67
  const Component = atomComponents.get(instance.nodeType) ?? DefaultAtomChip_1.DefaultAtomChip;
66
68
  const position = atomPositions.get(instance.key);
67
69
  const width = position?.width ?? atomContentWidth;
@@ -70,10 +72,10 @@ function useRichTextEditorPresentation(context) {
70
72
  top: react_native_1.Platform.OS === 'android' ? (position?.hostY ?? 0) : 0,
71
73
  left: react_native_1.Platform.OS === 'android' ? (position?.hostX ?? 0) : 0,
72
74
  width,
73
- }, children: (0, jsx_runtime_1.jsx)(AtomHost_1.AtomHost, { nativeID: `${atomConstants_1.ATOM_CONTENT_NATIVE_ID_PREFIX}${instance.key}`, component: Component, width: width, estimatedHeight: (atoms ?? []).find((atom) => atom.name === instance.nodeType)
75
+ }, children: (0, jsx_runtime_1.jsx)(AtomHost_1.AtomHost, { nativeID: `${atomConstants_1.ATOM_CONTENT_NATIVE_ID_PREFIX}${instance.key}`, component: Component, width: width, estimatedHeight: (atoms ?? []).find(atom => atom.name === instance.nodeType)
74
76
  ?.estimatedHeight ?? atomInstances_1.DEFAULT_ATOM_CHIP_HEIGHT, visible: !position ||
75
77
  (0, AtomHost_1.atomIsVisible)(position.y, position.height ??
76
- (atoms ?? []).find((atom) => atom.name === instance.nodeType)?.estimatedHeight ??
78
+ (atoms ?? []).find(atom => atom.name === instance.nodeType)?.estimatedHeight ??
77
79
  atomInstances_1.DEFAULT_ATOM_CHIP_HEIGHT, atomViewport ??
78
80
  (virtualizeAtoms ? nativeAtomViewport : undefined)), atomProps: {
79
81
  attrs: instance.attrs,
@@ -82,7 +84,7 @@ function useRichTextEditorPresentation(context) {
82
84
  interactive: atomsInteractive,
83
85
  isViewer: false,
84
86
  nodeType: instance.nodeType,
85
- updateAttrs: (attrs) => invokeAtomAttrsUpdate(documentHandle, instance, atomState.documentVersion, attrs),
87
+ updateAttrs: attrs => invokeAtomAttrsUpdate(documentHandle, instance, atomState.documentVersion, attrs),
86
88
  editor: {
87
89
  select: () => invokeAtomAction(documentHandle, instance, atomState.documentVersion, 'select'),
88
90
  delete: () => invokeAtomAction(documentHandle, instance, atomState.documentVersion, 'delete'),
@@ -90,22 +92,21 @@ function useRichTextEditorPresentation(context) {
90
92
  focusAfter: () => invokeAtomAction(documentHandle, instance, atomState.documentVersion, 'after'),
91
93
  },
92
94
  } }) }, instance.key));
93
- }), [
95
+ }), [atomContentWidth,
96
+ atomState.instances,
97
+ atomState.documentVersion,
98
+ atomComponents,
99
+ atomPositions,
94
100
  atoms,
95
101
  atomViewport,
96
- documentHandle,
97
- invokeAtomAction,
98
102
  virtualizeAtoms,
99
103
  nativeAtomViewport,
100
- atomsInteractive,
101
- atomComponents,
102
- atomContentWidth,
103
- atomPositions,
104
- atomState.instances,
104
+ selectedKeys,
105
105
  editable,
106
+ atomsInteractive,
106
107
  invokeAtomAttrsUpdate,
107
- selectedKeys,
108
- ]);
108
+ documentHandle,
109
+ invokeAtomAction]);
109
110
  const isLinkActive = activeState.marks.link === true;
110
111
  const allowsLink = activeState.allowedMarks.includes('link');
111
112
  const canInsertImage = activeState.insertableNodes.includes(schemas_1.IMAGE_NODE_NAME);
@@ -139,8 +140,9 @@ function useRichTextEditorPresentation(context) {
139
140
  }
140
141
  // A room document awaiting the server renders nothing (loading), never an
141
142
  // unshared fallback paragraph.
142
- if (!document.isReady)
143
+ if (!document.isReady) {
143
144
  return null;
145
+ }
144
146
  const usesNativeKeyboardToolbar = toolbarPlacement === 'keyboard' && (react_native_1.Platform.OS === 'ios' || react_native_1.Platform.OS === 'android');
145
147
  const shouldRenderJsToolbar = showToolbar && !usesNativeKeyboardToolbar && editable;
146
148
  const inlineToolbarMarginTop = theme?.toolbar?.marginTop ?? 8;
@@ -1,5 +1,5 @@
1
1
  import { type EditorToolbarItem } from './EditorToolbar';
2
- import React from 'react';
2
+ import type React from 'react';
3
3
  import { type ReadonlyActiveState, type Selection } from './NativeEditorBridge';
4
4
  import { type AtomComponent } from './atoms';
5
5
  import { ExternalTextCompositionManager } from './ExternalTextComposition';
@@ -156,8 +156,8 @@ export declare function useRichTextEditorState({ documentHandle, documentRevisio
156
156
  toolbarItems: readonly EditorToolbarItem[];
157
157
  toolbarPlacement: import("./RichTextEditorTypes").RichTextEditorToolbarPlacement;
158
158
  showToolbar: boolean;
159
- containerStyle: RichTextEditorProps["containerStyle"];
160
- style: RichTextEditorProps["style"];
159
+ containerStyle: import("react-native").StyleProp<import("react-native").ViewStyle>;
160
+ style: import("react-native").StyleProp<import("react-native").ViewStyle>;
161
161
  autoGrowHeight: number | null;
162
162
  pushedUpdate: {
163
163
  json: string;
@@ -14,17 +14,18 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
14
14
  const addons = (0, react_1.useMemo)(() => (0, addons_1.normalizeEditorAddons)(addonDescriptors), [addonDescriptors]);
15
15
  (0, NativeEditorBridge_1._assertNativeEditorDocumentHandle)(documentHandle);
16
16
  const documentDescriptor = (0, NativeEditorBridge_1._getNativeEditorDocumentHandleDescriptor)(documentHandle);
17
- const registeredAtomTypeKey = JSON.stringify((atoms ?? []).map((atom) => atom.name));
18
- const registeredAtomTypes = (0, react_1.useMemo)(() => new Set((atoms ?? []).map((atom) => atom.name)), [registeredAtomTypeKey]);
17
+ const registeredAtomTypeKey = JSON.stringify((atoms ?? []).map(atom => atom.name));
18
+ const registeredAtomTypes = (0, react_1.useMemo)(() => new Set(JSON.parse(registeredAtomTypeKey)), [registeredAtomTypeKey]);
19
19
  const atomComponents = (0, react_1.useMemo)(() => {
20
20
  const components = new Map();
21
21
  for (const atom of atoms ?? []) {
22
- if (!components.has(atom.name))
22
+ if (!components.has(atom.name)) {
23
23
  components.set(atom.name, atom.component);
24
+ }
24
25
  }
25
26
  return components;
26
27
  }, [atoms]);
27
- const serializedValueJson = (0, RichTextEditorSerialization_1.useSerializedValue)(valueJSON, (doc) => (0, RichTextEditorSerialization_1.stringifyCachedJson)((0, schemas_1.normalizeDocumentJson)(doc, documentDescriptor)), valueJSONRevision);
28
+ const serializedValueJson = (0, RichTextEditorSerialization_1.useSerializedValue)(valueJSON, doc => (0, RichTextEditorSerialization_1.stringifyCachedJson)((0, schemas_1.normalizeDocumentJson)(doc, documentDescriptor)), valueJSONRevision);
28
29
  const controlledValueJSON = (0, react_1.useMemo)(() => serializedValueJson == null
29
30
  ? undefined
30
31
  : JSON.parse(serializedValueJson), [serializedValueJson]);
@@ -34,20 +35,21 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
34
35
  const externalCompositionManager = (0, react_1.useMemo)(() => new ExternalTextComposition_1.ExternalTextCompositionManager(editorId, () => nativeViewRef.current), [editorId]);
35
36
  const managerDisposalsRef = (0, react_1.useRef)(new Map());
36
37
  (0, react_1.useEffect)(() => {
37
- const pendingDisposal = managerDisposalsRef.current.get(externalCompositionManager);
38
+ const managerDisposals = managerDisposalsRef.current;
39
+ const pendingDisposal = managerDisposals.get(externalCompositionManager);
38
40
  if (pendingDisposal != null) {
39
41
  pendingDisposal.cancelled = true;
40
- managerDisposalsRef.current.delete(externalCompositionManager);
42
+ managerDisposals.delete(externalCompositionManager);
41
43
  }
42
44
  return () => {
43
45
  const token = { cancelled: false };
44
- managerDisposalsRef.current.set(externalCompositionManager, token);
46
+ managerDisposals.set(externalCompositionManager, token);
45
47
  void Promise.resolve().then(() => {
46
48
  if (token.cancelled ||
47
- managerDisposalsRef.current.get(externalCompositionManager) !== token) {
49
+ managerDisposals.get(externalCompositionManager) !== token) {
48
50
  return;
49
51
  }
50
- managerDisposalsRef.current.delete(externalCompositionManager);
52
+ managerDisposals.delete(externalCompositionManager);
51
53
  externalCompositionManager.dispose();
52
54
  });
53
55
  };
@@ -96,8 +98,9 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
96
98
  const pending = { manager: externalCompositionManager };
97
99
  pendingResetCancellationRef.current = pending;
98
100
  void externalCompositionManager.cancelForDocumentChange().then(() => {
99
- if (pendingResetCancellationRef.current !== pending)
101
+ if (pendingResetCancellationRef.current !== pending) {
100
102
  return;
103
+ }
101
104
  pendingResetCancellationRef.current = null;
102
105
  const latest = latestControlledValueRef.current;
103
106
  if (latest.manager !== externalCompositionManager ||
@@ -115,10 +118,11 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
115
118
  value: latest.value,
116
119
  valueJSON: latest.valueJSON,
117
120
  };
118
- setControlledResetRevision((revision) => revision + 1);
121
+ setControlledResetRevision(revision => revision + 1);
119
122
  }, (error) => {
120
- if (pendingResetCancellationRef.current !== pending)
123
+ if (pendingResetCancellationRef.current !== pending) {
121
124
  return;
125
+ }
122
126
  pendingResetCancellationRef.current = null;
123
127
  const latest = latestControlledValueRef.current;
124
128
  if (latest.manager !== externalCompositionManager ||
@@ -173,8 +177,9 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
173
177
  nativeErrorBindingRef.current = nativeErrorBinding;
174
178
  }
175
179
  return () => {
176
- if (nativeErrorBindingRef.current !== nativeErrorBinding)
180
+ if (nativeErrorBindingRef.current !== nativeErrorBinding) {
177
181
  return;
182
+ }
178
183
  nativeErrorBindingRef.current = {
179
184
  ...nativeErrorBinding,
180
185
  generation: nativeErrorBinding.generation + 1,
@@ -385,8 +390,8 @@ function useRichTextEditorState({ documentHandle, documentRevision, value, value
385
390
  toolbarItems,
386
391
  toolbarPlacement,
387
392
  showToolbar,
388
- containerStyle: containerStyle,
389
- style: style,
393
+ containerStyle,
394
+ style,
390
395
  autoGrowHeight,
391
396
  pushedUpdate,
392
397
  registeredToolbarFrames,
@@ -1,5 +1,5 @@
1
1
  import { type NativeEditorAtomicRenderSnapshot, type Selection } from './NativeEditorBridge';
2
- import { useRichTextEditorState } from './useRichTextEditorState';
2
+ import { type useRichTextEditorState } from './useRichTextEditorState';
3
3
  export declare function useRichTextEditorUpdates(context: Pick<ReturnType<typeof useRichTextEditorState>, 'atomStateRef' | 'setSelectedKeys' | 'bridge' | 'registeredAtomTypes' | 'setAtomState' | 'selectionRef' | 'document' | 'documentHandle' | 'atomSeedEditorIdRef' | 'editorId' | 'scalarSelectionRef' | 'activeStateRef' | 'setActiveState' | 'activeStateKeyRef' | 'onActiveStateChangeRef' | 'pushedUpdateBindingGenerationRef' | 'currentPushedUpdateEditorIdRef' | 'pushRevisionRef' | 'lastPushedEngineRevisionRef' | 'setPushedUpdate' | 'pendingFocusedRebindRef' | 'toolbarFrameOwnerId' | 'onFocusRef' | 'didRebindRevisionScope' | 'didObserveInitialRevisionRef' | 'lastNativeDrivenRevisionRef' | 'onLocalCommitRef'>): {
4
4
  refreshAtomsFromUpdate: (update: NativeEditorAtomicRenderSnapshot) => void;
5
5
  afterLocalEngineMutation: () => void;
@@ -10,8 +10,8 @@ function useRichTextEditorUpdates(context) {
10
10
  const { atomStateRef, setSelectedKeys, bridge, registeredAtomTypes, setAtomState, selectionRef, document, documentHandle, atomSeedEditorIdRef, editorId, scalarSelectionRef, activeStateRef, setActiveState, activeStateKeyRef, onActiveStateChangeRef, pushedUpdateBindingGenerationRef, currentPushedUpdateEditorIdRef, pushRevisionRef, lastPushedEngineRevisionRef, setPushedUpdate, pendingFocusedRebindRef, toolbarFrameOwnerId, onFocusRef, didRebindRevisionScope, didObserveInitialRevisionRef, lastNativeDrivenRevisionRef, onLocalCommitRef, } = context;
11
11
  const updateAtomSelection = (0, react_1.useCallback)((selection, instances = atomStateRef.current.instances) => {
12
12
  const next = (0, RichTextEditorSerialization_1.selectedAtomKeys)(selection, instances);
13
- setSelectedKeys((current) => ((0, RichTextEditorSerialization_1.equalStringSets)(current, next) ? current : next));
14
- }, []);
13
+ setSelectedKeys(current => ((0, RichTextEditorSerialization_1.equalStringSets)(current, next) ? current : next));
14
+ }, [atomStateRef, setSelectedKeys]);
15
15
  const refreshAtomsFromUpdate = (0, react_1.useCallback)((update) => {
16
16
  const previous = atomStateRef.current;
17
17
  const source = update.renderPatch != null &&
@@ -55,7 +55,12 @@ function useRichTextEditorUpdates(context) {
55
55
  setAtomState(next);
56
56
  }
57
57
  updateAtomSelection(selectionRef.current, next.instances);
58
- }, [bridge, registeredAtomTypes, updateAtomSelection]);
58
+ }, [atomStateRef,
59
+ bridge,
60
+ registeredAtomTypes,
61
+ selectionRef,
62
+ setAtomState,
63
+ updateAtomSelection]);
59
64
  (0, react_1.useEffect)(() => {
60
65
  const current = atomStateRef.current;
61
66
  const collection = (0, atomInstances_1.collectAtomInstanceBlocks)(current.blocks, registeredAtomTypes);
@@ -72,7 +77,11 @@ function useRichTextEditorUpdates(context) {
72
77
  setAtomState(next);
73
78
  }
74
79
  updateAtomSelection(selectionRef.current, instances);
75
- }, [registeredAtomTypes, updateAtomSelection]);
80
+ }, [atomStateRef,
81
+ registeredAtomTypes,
82
+ selectionRef,
83
+ setAtomState,
84
+ updateAtomSelection]);
76
85
  (0, react_1.useLayoutEffect)(() => {
77
86
  if (!document.isReady ||
78
87
  documentHandle.isDestroyed ||
@@ -81,10 +90,16 @@ function useRichTextEditorUpdates(context) {
81
90
  }
82
91
  atomSeedEditorIdRef.current = editorId;
83
92
  refreshAtomsFromUpdate(bridge.renderUpdate());
84
- }, [bridge, document.isReady, documentHandle, editorId, refreshAtomsFromUpdate]);
93
+ }, [atomSeedEditorIdRef,
94
+ bridge,
95
+ document.isReady,
96
+ documentHandle,
97
+ editorId,
98
+ refreshAtomsFromUpdate]);
85
99
  const applyTypedUpdateState = (0, react_1.useCallback)((update, isCurrent = () => true) => {
86
- if (!isCurrent())
100
+ if (!isCurrent()) {
87
101
  return false;
102
+ }
88
103
  selectionRef.current = update.selection;
89
104
  updateAtomSelection(update.selection);
90
105
  if (update.selection.type === 'text' &&
@@ -95,34 +110,47 @@ function useRichTextEditorUpdates(context) {
95
110
  head: update.selection.headScalar,
96
111
  };
97
112
  }
98
- if (!isCurrent())
113
+ if (!isCurrent()) {
99
114
  return false;
115
+ }
100
116
  const nextActiveState = update.activeState;
101
117
  activeStateRef.current = nextActiveState;
102
- if (!isCurrent())
118
+ if (!isCurrent()) {
103
119
  return false;
120
+ }
104
121
  setActiveState(nextActiveState);
105
- if (!isCurrent())
122
+ if (!isCurrent()) {
106
123
  return false;
124
+ }
107
125
  const key = (0, RichTextEditorSerialization_1.stringifyCachedJson)(nextActiveState);
108
126
  if (key !== activeStateKeyRef.current) {
109
- if (!isCurrent())
127
+ if (!isCurrent()) {
110
128
  return false;
129
+ }
111
130
  activeStateKeyRef.current = key;
112
- if (!isCurrent())
131
+ if (!isCurrent()) {
113
132
  return false;
133
+ }
114
134
  onActiveStateChangeRef.current?.(nextActiveState);
115
135
  }
116
136
  return isCurrent();
117
- }, [updateAtomSelection]);
137
+ }, [activeStateKeyRef,
138
+ activeStateRef,
139
+ onActiveStateChangeRef,
140
+ scalarSelectionRef,
141
+ selectionRef,
142
+ setActiveState,
143
+ updateAtomSelection]);
118
144
  const applyUpdateState = (0, react_1.useCallback)((updateJson) => {
119
- if (typeof updateJson !== 'string' || updateJson.length === 0)
145
+ if (typeof updateJson !== 'string' || updateJson.length === 0) {
120
146
  return null;
147
+ }
121
148
  let parsed;
122
149
  try {
123
150
  const candidate = JSON.parse(updateJson);
124
- if (!(0, RichTextEditorSerialization_1.isRecord)(candidate))
151
+ if (!(0, RichTextEditorSerialization_1.isRecord)(candidate)) {
125
152
  return null;
153
+ }
126
154
  parsed = candidate;
127
155
  }
128
156
  catch {
@@ -149,10 +177,16 @@ function useRichTextEditorUpdates(context) {
149
177
  }
150
178
  }
151
179
  return parsed;
152
- }, [applyTypedUpdateState]);
180
+ }, [activeStateKeyRef,
181
+ activeStateRef,
182
+ applyTypedUpdateState,
183
+ onActiveStateChangeRef,
184
+ selectionRef,
185
+ setActiveState]);
153
186
  const pushEngineUpdateToView = (0, react_1.useCallback)(() => {
154
- if (documentHandle.isDestroyed)
187
+ if (documentHandle.isDestroyed) {
155
188
  return;
189
+ }
156
190
  const sourceEditorId = documentHandle.editorId;
157
191
  const sourceBindingGeneration = pushedUpdateBindingGenerationRef.current;
158
192
  const isCurrentSource = () => {
@@ -170,38 +204,55 @@ function useRichTextEditorUpdates(context) {
170
204
  // renderUpdate can synchronously re-enter React and bind this
171
205
  // component to another handle. Do not let any side effect from A
172
206
  // reach B once that happens.
173
- if (!isCurrentSource())
207
+ if (!isCurrentSource()) {
174
208
  return;
209
+ }
175
210
  refreshAtomsFromUpdate(snapshot);
176
- if (!isCurrentSource())
211
+ if (!isCurrentSource()) {
177
212
  return;
213
+ }
178
214
  const updateJson = JSON.stringify(snapshot);
179
- if (!isCurrentSource())
215
+ if (!isCurrentSource()) {
180
216
  return;
217
+ }
181
218
  if (!applyTypedUpdateState(snapshot, isCurrentSource)) {
182
219
  return;
183
220
  }
184
- if (!isCurrentSource())
221
+ if (!isCurrentSource()) {
185
222
  return;
223
+ }
186
224
  lastPushedEngineRevisionRef.current = snapshot.documentVersion;
187
- if (!isCurrentSource())
225
+ if (!isCurrentSource()) {
188
226
  return;
227
+ }
189
228
  pushRevisionRef.current = allocation.revision;
190
- if (!isCurrentSource())
229
+ if (!isCurrentSource()) {
191
230
  return;
231
+ }
192
232
  setPushedUpdate({
193
233
  json: updateJson,
194
234
  resetJson: reset?.json,
195
235
  revision: allocation.revision,
196
236
  editorId: sourceEditorId,
197
237
  });
198
- if (bridge._pendingViewReset === reset)
238
+ if (bridge._pendingViewReset === reset) {
199
239
  bridge._pendingViewReset = null;
200
- }, [applyTypedUpdateState, bridge, documentHandle, refreshAtomsFromUpdate]);
240
+ }
241
+ }, [applyTypedUpdateState,
242
+ bridge,
243
+ currentPushedUpdateEditorIdRef,
244
+ documentHandle.editorId,
245
+ documentHandle.isDestroyed,
246
+ lastPushedEngineRevisionRef,
247
+ pushRevisionRef,
248
+ pushedUpdateBindingGenerationRef,
249
+ refreshAtomsFromUpdate,
250
+ setPushedUpdate]);
201
251
  (0, react_1.useLayoutEffect)(() => {
202
252
  const pending = pendingFocusedRebindRef.current;
203
- if (pending?.editorId !== editorId || !document.isReady)
253
+ if (pending?.editorId !== editorId || !document.isReady) {
204
254
  return;
255
+ }
205
256
  pendingFocusedRebindRef.current = null;
206
257
  const snapshot = bridge.renderUpdate();
207
258
  const anchor = Math.min(pending.anchor, snapshot.scalarLength);
@@ -220,35 +271,40 @@ function useRichTextEditorUpdates(context) {
220
271
  setSelection(collapsed ? 'after' : 'before');
221
272
  }
222
273
  catch (error) {
223
- if (!collapsed || !(0, RichTextEditorSerialization_1.isPositionInvalidError)(error))
274
+ if (!collapsed || !(0, RichTextEditorSerialization_1.isPositionInvalidError)(error)) {
224
275
  throw error;
276
+ }
225
277
  setSelection('before');
226
278
  }
227
279
  pushEngineUpdateToView();
228
280
  }
229
281
  catch (error) {
230
- if (!(0, RichTextEditorSerialization_1.isPositionInvalidError)(error))
282
+ if (!(0, RichTextEditorSerialization_1.isPositionInvalidError)(error)) {
231
283
  throw error;
284
+ }
232
285
  }
233
286
  (0, EditorToolbar_1.setActiveEditorToolbarFrameOwnerForEditor)(toolbarFrameOwnerId, true);
234
287
  onFocusRef.current?.();
235
- }, [bridge, document.isReady, editorId, pushEngineUpdateToView, toolbarFrameOwnerId]);
288
+ }, [bridge,
289
+ document.isReady,
290
+ editorId,
291
+ onFocusRef,
292
+ pendingFocusedRebindRef,
293
+ pushEngineUpdateToView,
294
+ toolbarFrameOwnerId]);
236
295
  // A pending update is owned by the handle that produced its snapshot.
237
296
  // Drop it when this component rebinds, so no old session state reaches
238
297
  // the next native view binding.
239
298
  (0, react_1.useEffect)(() => {
240
- setPushedUpdate((current) => {
241
- if (current == null || current.editorId === editorId)
299
+ setPushedUpdate(current => {
300
+ if (current == null || current.editorId === editorId) {
242
301
  return current;
302
+ }
243
303
  return null;
244
304
  });
245
- }, [editorId]);
305
+ }, [editorId, setPushedUpdate]);
246
306
  const pendingViewReset = bridge._pendingViewReset;
247
- // After a JS-driven engine change (controlled apply, remote commit,
248
- // document-API mutation) the view learns the new state here. Native-
249
- // driven commits (typing, native toolbar) already updated the view
250
- // through the adapter and are never echoed back. The first observed
251
- // revision is skipped: the view pulls the initial state natively on bind.
307
+ // Native commits already update the view; echo only subsequent JS-driven revisions.
252
308
  (0, react_1.useEffect)(() => {
253
309
  // The document hook refreshes its state after the rebind commit. Its
254
310
  // first render can therefore still contain A's revision; do not let
@@ -256,8 +312,9 @@ function useRichTextEditorUpdates(context) {
256
312
  if (didRebindRevisionScope) {
257
313
  return;
258
314
  }
259
- if (!document.isReady || document.documentRevision == null)
315
+ if (!document.isReady || document.documentRevision == null) {
260
316
  return;
317
+ }
261
318
  const revision = document.documentRevision;
262
319
  if (!pendingViewReset && !didObserveInitialRevisionRef.current) {
263
320
  didObserveInitialRevisionRef.current = true;
@@ -281,8 +338,7 @@ function useRichTextEditorUpdates(context) {
281
338
  }
282
339
  lastNativeDrivenRevisionRef.current = null;
283
340
  pushEngineUpdateToView();
284
- }, [
285
- pendingViewReset,
341
+ }, [pendingViewReset,
286
342
  didRebindRevisionScope,
287
343
  document.isReady,
288
344
  document.documentRevision,
@@ -291,12 +347,14 @@ function useRichTextEditorUpdates(context) {
291
347
  documentHandle,
292
348
  pushEngineUpdateToView,
293
349
  refreshAtomsFromUpdate,
294
- ]);
350
+ didObserveInitialRevisionRef,
351
+ lastPushedEngineRevisionRef,
352
+ lastNativeDrivenRevisionRef]);
295
353
  const afterLocalEngineMutation = (0, react_1.useCallback)(() => {
296
354
  onLocalCommitRef.current?.();
297
355
  pushEngineUpdateToView();
298
356
  document.refresh();
299
- }, [document, pushEngineUpdateToView]);
357
+ }, [document, onLocalCommitRef, pushEngineUpdateToView]);
300
358
  return {
301
359
  refreshAtomsFromUpdate,
302
360
  afterLocalEngineMutation,