@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
package/dist/AtomHost.js CHANGED
@@ -40,8 +40,9 @@ const react_1 = __importStar(require("react"));
40
40
  const react_native_1 = require("react-native");
41
41
  const atomInstances_1 = require("./atomInstances");
42
42
  function atomIsVisible(y, height, viewport) {
43
- if (!viewport)
43
+ if (!viewport) {
44
44
  return true;
45
+ }
45
46
  if (![viewport.y, viewport.height, viewport.overscan ?? 200].every(Number.isFinite) ||
46
47
  viewport.height < 0 ||
47
48
  (viewport.overscan ?? 200) < 0) {
@@ -64,8 +65,9 @@ class AtomErrorBoundary extends react_1.default.Component {
64
65
  : { component: props.component, error: false };
65
66
  }
66
67
  render() {
67
- if (!this.state.error)
68
+ if (!this.state.error) {
68
69
  return this.props.children;
70
+ }
69
71
  return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { accessibilityRole: 'alert', style: { minHeight: 32, padding: 8 }, children: [(0, jsx_runtime_1.jsxs)(react_native_1.Text, { children: ["Unable to display ", this.props.nodeType] }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { accessibilityRole: 'button', onPress: () => this.setState({ error: false }), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { children: "Retry" }) })] }));
70
72
  }
71
73
  }
@@ -85,30 +87,35 @@ function AtomHost({ component: Component, atomProps, width, estimatedHeight, vis
85
87
  };
86
88
  }, []);
87
89
  const updateAttrs = (0, react_1.useCallback)(async (update) => {
88
- if (!mounted.current)
90
+ if (!mounted.current) {
89
91
  throw new atomInstances_1.AtomUpdateAttrsError('not-ready', 'The atom is unmounted.');
92
+ }
90
93
  const request = ++latestRequest.current;
91
- setPending((count) => count + 1);
94
+ setPending(count => count + 1);
92
95
  setUpdateError(null);
93
96
  try {
94
97
  await applyUpdate(update);
95
98
  }
96
99
  catch (error) {
97
- if (mounted.current && latestRequest.current === request)
100
+ if (mounted.current && latestRequest.current === request) {
98
101
  setUpdateError(error instanceof Error ? error : new Error(String(error)));
102
+ }
99
103
  throw error;
100
104
  }
101
105
  finally {
102
- if (mounted.current)
103
- setPending((count) => count - 1);
106
+ if (mounted.current) {
107
+ setPending(count => count - 1);
108
+ }
104
109
  }
105
110
  }, [applyUpdate]);
106
111
  const editor = (0, react_1.useMemo)(() => {
107
- if (!atomProps.editor)
112
+ if (!atomProps.editor) {
108
113
  return undefined;
114
+ }
109
115
  const guard = (action) => async () => {
110
- if (!mounted.current)
116
+ if (!mounted.current) {
111
117
  throw new atomInstances_1.AtomUpdateAttrsError('not-ready', 'The atom is unmounted.');
118
+ }
112
119
  return action();
113
120
  };
114
121
  return {
@@ -120,14 +127,14 @@ function AtomHost({ component: Component, atomProps, width, estimatedHeight, vis
120
127
  }, [atomProps.editor]);
121
128
  const retainedHeight = measurement.width === width ? measurement.height : estimatedHeight;
122
129
  const show = visible || focused || active || pending > 0 || atomProps.selected;
123
- return ((0, jsx_runtime_1.jsx)(react_native_1.View, { testID: 'atom-host', nativeID: nativeID, collapsable: false, pointerEvents: atomProps.interactive === false ? 'none' : 'box-none', accessibilityElementsHidden: !show, importantForAccessibility: !show ? 'no-hide-descendants' : 'auto', onFocus: () => setFocused(true), onBlur: () => setFocused(false), onLayout: (event) => {
130
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { testID: 'atom-host', nativeID: nativeID, collapsable: false, pointerEvents: atomProps.interactive === false ? 'none' : 'box-none', accessibilityElementsHidden: !show, importantForAccessibility: !show ? 'no-hide-descendants' : 'auto', onFocus: () => setFocused(true), onBlur: () => setFocused(false), onLayout: event => {
124
131
  onMeasure?.(event);
125
132
  const size = event.nativeEvent.layout;
126
133
  if (show &&
127
134
  Number.isFinite(size.height) &&
128
135
  size.height >= 0 &&
129
136
  Math.abs(size.width - width) <= 1) {
130
- setMeasurement((previous) => previous.width === width && previous.height === size.height
137
+ setMeasurement(previous => previous.width === width && previous.height === size.height
131
138
  ? previous
132
139
  : { width, height: size.height });
133
140
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createMentionsAddon = createMentionsAddon;
4
4
  function copyConfiguration(value, ancestors = new Set()) {
5
- if (value === null || typeof value !== 'object')
5
+ if (value === null || typeof value !== 'object') {
6
6
  return value;
7
- if (ancestors.has(value))
7
+ }
8
+ if (ancestors.has(value)) {
8
9
  throw new Error('Addon configuration must not contain cycles.');
10
+ }
9
11
  if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) {
10
12
  throw new Error('Addon configuration must contain only plain objects and arrays.');
11
13
  }
@@ -5,30 +5,38 @@ function isRecord(value) {
5
5
  return value !== null && typeof value === 'object' && !Array.isArray(value);
6
6
  }
7
7
  function normalizeEditorAddons(addons) {
8
- if (addons === undefined)
8
+ if (addons === undefined) {
9
9
  return {};
10
- if (!Array.isArray(addons))
10
+ }
11
+ if (!Array.isArray(addons)) {
11
12
  throw new Error('addons must be a flat readonly array.');
13
+ }
12
14
  const normalized = {};
13
15
  const ids = new Set();
14
16
  for (const [index, addon] of addons.entries()) {
15
- if (addon === false || addon === null || addon === undefined)
17
+ if (addon === false || addon === null || addon === undefined) {
16
18
  continue;
19
+ }
17
20
  const path = `addons[${index}]`;
18
- if (!isRecord(addon))
21
+ if (!isRecord(addon)) {
19
22
  throw new Error(`${path} must be an addon descriptor.`);
20
- if (addon.version !== 1)
23
+ }
24
+ if (addon.version !== 1) {
21
25
  throw new Error(`${path}.version must be 1.`);
26
+ }
22
27
  if (addon.capability !== 'mentions' && addon.capability !== 'code-highlighting') {
23
28
  throw new Error(`${path}.capability is unsupported.`);
24
29
  }
25
- if (addon.id !== addon.capability)
30
+ if (addon.id !== addon.capability) {
26
31
  throw new Error(`${path}.id must match its capability.`);
27
- if (ids.has(addon.capability))
28
- throw new Error(`${path}: duplicate addon id '${addon.id}'.`);
32
+ }
33
+ if (ids.has(addon.capability)) {
34
+ throw new Error(`${path}: duplicate addon id '${String(addon.id)}'.`);
35
+ }
29
36
  ids.add(addon.capability);
30
- if (!isRecord(addon.options))
37
+ if (!isRecord(addon.options)) {
31
38
  throw new Error(`${path}.options must be an object.`);
39
+ }
32
40
  if (addon.capability === 'mentions') {
33
41
  normalized.mentions = addon.options;
34
42
  }
@@ -4,12 +4,15 @@ exports.normalizeEditorMentionTheme = normalizeEditorMentionTheme;
4
4
  const EditorStyleSheetNormalization_1 = require("./EditorStyleSheetNormalization");
5
5
  const EditorMentionThemeValidation_1 = require("./EditorMentionThemeValidation");
6
6
  function normalizeEditorMentionTheme(theme) {
7
- if (theme === undefined)
7
+ if (theme === undefined) {
8
8
  return undefined;
9
- if (!(0, EditorMentionThemeValidation_1.validEditorMentionTheme)(theme))
9
+ }
10
+ if (!(0, EditorMentionThemeValidation_1.validEditorMentionTheme)(theme)) {
10
11
  throw new TypeError('Invalid mention theme');
11
- if (!theme.node)
12
+ }
13
+ if (!theme.node) {
12
14
  return theme;
15
+ }
13
16
  const node = theme.node;
14
17
  const { textColor, style: existingStyle, ...appearance } = node;
15
18
  const style = (0, EditorStyleSheetNormalization_1.normalizeEditorTheme)({
@@ -9,7 +9,7 @@ function isPlainRecord(value) {
9
9
  return value !== null && typeof value === 'object' && !Array.isArray(value);
10
10
  }
11
11
  function hasOnlyOwnKeys(value, fields) {
12
- return Reflect.ownKeys(value).every((key) => typeof key === 'string' && fields.includes(key));
12
+ return Reflect.ownKeys(value).every(key => typeof key === 'string' && fields.includes(key));
13
13
  }
14
14
  exports.MENTION_NODE_STRING_FIELDS = [
15
15
  'textColor',
@@ -41,7 +41,17 @@ exports.MENTION_SUGGESTIONS_NUMBER_FIELDS = [
41
41
  'borderWidth',
42
42
  'borderRadius',
43
43
  ];
44
- exports.EDITOR_MENTION_THEME_FONT_WEIGHTS = new Set(['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']);
44
+ exports.EDITOR_MENTION_THEME_FONT_WEIGHTS = new Set(['normal',
45
+ 'bold',
46
+ '100',
47
+ '200',
48
+ '300',
49
+ '400',
50
+ '500',
51
+ '600',
52
+ '700',
53
+ '800',
54
+ '900']);
45
55
  exports.EDITOR_MENTION_THEME_FIELDS = [
46
56
  'node',
47
57
  'suggestions',
@@ -52,12 +62,14 @@ function validMentionFontWeight(value) {
52
62
  exports.EDITOR_MENTION_THEME_FONT_WEIGHTS.has(value)));
53
63
  }
54
64
  function validMentionThemeSection(value, stringFields, numberFields, extraFields) {
55
- if (!isPlainRecord(value))
65
+ if (!isPlainRecord(value)) {
56
66
  return false;
57
- if (!hasOnlyOwnKeys(value, [...stringFields, ...numberFields, ...extraFields]))
67
+ }
68
+ if (!hasOnlyOwnKeys(value, [...stringFields, ...numberFields, ...extraFields])) {
58
69
  return false;
59
- return (stringFields.every((field) => value[field] === undefined || typeof value[field] === 'string') &&
60
- numberFields.every((field) => value[field] === undefined ||
70
+ }
71
+ return (stringFields.every(field => value[field] === undefined || typeof value[field] === 'string') &&
72
+ numberFields.every(field => value[field] === undefined ||
61
73
  (typeof value[field] === 'number' && Number.isFinite(value[field]))));
62
74
  }
63
75
  function validEditorMentionTheme(value) {
@@ -66,16 +78,19 @@ function validEditorMentionTheme(value) {
66
78
  }
67
79
  const { node, suggestions } = value;
68
80
  if (node !== undefined) {
69
- if (!isPlainRecord(node))
81
+ if (!isPlainRecord(node)) {
70
82
  return false;
83
+ }
71
84
  const { textColor, style, ...appearance } = node;
72
- if (textColor !== undefined && typeof textColor !== 'string')
85
+ if (textColor !== undefined && typeof textColor !== 'string') {
73
86
  return false;
87
+ }
74
88
  try {
75
89
  (0, EditorStyleSheetNormalization_1.normalizeEditorTheme)({ mention: [{ color: textColor }, appearance] });
76
90
  if (style !== undefined) {
77
- if (!isPlainRecord(style))
91
+ if (!isPlainRecord(style)) {
78
92
  return false;
93
+ }
79
94
  (0, EditorStyleSheetNormalization_1.normalizeEditorTheme)({ mention: style });
80
95
  }
81
96
  }
@@ -83,13 +98,15 @@ function validEditorMentionTheme(value) {
83
98
  return false;
84
99
  }
85
100
  }
86
- if (suggestions === undefined)
101
+ if (suggestions === undefined) {
87
102
  return true;
103
+ }
88
104
  if (!validMentionThemeSection(suggestions, exports.MENTION_SUGGESTIONS_STRING_FIELDS, exports.MENTION_SUGGESTIONS_NUMBER_FIELDS, ['option'])) {
89
105
  return false;
90
106
  }
91
107
  const option = suggestions.option;
92
- if (option === undefined)
108
+ if (option === undefined) {
93
109
  return true;
110
+ }
94
111
  return (validMentionThemeSection(option, exports.MENTION_OPTION_STRING_FIELDS, exports.MENTION_OPTION_NUMBER_FIELDS, ['fontWeight']) && validMentionFontWeight(option.fontWeight));
95
112
  }
@@ -22,14 +22,14 @@ const border = [
22
22
  'borderColor',
23
23
  'borderStyle',
24
24
  'borderRadius',
25
- ...sides.flatMap((side) => [`border${side}Width`, `border${side}Color`]),
26
- ...corners.map((corner) => `border${corner}Radius`),
25
+ ...sides.flatMap(side => [`border${side}Width`, `border${side}Color`]),
26
+ ...corners.map(corner => `border${corner}Radius`),
27
27
  ];
28
28
  const spacing = (prefix) => [
29
29
  prefix,
30
30
  `${prefix}Horizontal`,
31
31
  `${prefix}Vertical`,
32
- ...sides.map((side) => `${prefix}${side}`),
32
+ ...sides.map(side => `${prefix}${side}`),
33
33
  ];
34
34
  const surface = ['backgroundColor', ...border, ...spacing('padding')];
35
35
  const box = [...surface, ...spacing('margin')];
@@ -63,13 +63,27 @@ const fields = {
63
63
  italic: inline,
64
64
  underline: inline,
65
65
  strike: inline,
66
- mention: [...inline, ...border],
66
+ mention: [...inline, ...border, ...spacing('padding')],
67
67
  placeholder: typography,
68
68
  };
69
69
  const enums = {
70
70
  fontStyle: ['normal', 'italic'],
71
- fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
72
- textAlign: ['auto', 'left', 'right', 'center', 'justify'],
71
+ fontWeight: ['normal',
72
+ 'bold',
73
+ '100',
74
+ '200',
75
+ '300',
76
+ '400',
77
+ '500',
78
+ '600',
79
+ '700',
80
+ '800',
81
+ '900'],
82
+ textAlign: ['auto',
83
+ 'left',
84
+ 'right',
85
+ 'center',
86
+ 'justify'],
73
87
  textDecorationLine: ['none', 'underline', 'line-through', 'underline line-through'],
74
88
  textDecorationStyle: ['solid', 'double', 'dotted', 'dashed'],
75
89
  borderStyle: ['solid', 'dashed', 'dotted'],
@@ -79,39 +93,50 @@ function invalid(path, reason) {
79
93
  throw new TypeError(`Invalid editor style ${path}: ${reason}`);
80
94
  }
81
95
  function record(value) {
82
- if (value == null || typeof value !== 'object' || Array.isArray(value))
96
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
83
97
  return false;
98
+ }
84
99
  const prototype = Object.getPrototypeOf(value);
85
100
  return prototype === Object.prototype || prototype === null;
86
101
  }
87
102
  function normalizeEditorColor(value, path) {
88
- if (typeof value !== 'string')
103
+ if (typeof value !== 'string') {
89
104
  return invalid(path, 'expected a color string');
105
+ }
90
106
  const argb = (0, react_native_1.processColor)(value);
91
- if (typeof argb !== 'number')
107
+ if (typeof argb !== 'number') {
92
108
  return invalid(path, 'unrecognized color');
109
+ }
93
110
  const rgba = ((argb << 8) | (argb >>> 24)) >>> 0;
94
111
  return `#${rgba.toString(16).padStart(8, '0')}`;
95
112
  }
96
113
  function orderedMarker(value, path) {
97
- if (!record(value))
114
+ if (!record(value)) {
98
115
  return invalid(path, 'expected an ordered marker object');
116
+ }
99
117
  const result = {};
100
118
  for (const [key, entry] of Object.entries(value)) {
101
- if (key !== 'schemes' && key !== 'suffix')
119
+ if (key !== 'schemes' && key !== 'suffix') {
102
120
  invalid(`${path}.${key}`, 'unsupported property');
103
- if (entry === undefined)
121
+ }
122
+ if (entry === undefined) {
104
123
  continue;
124
+ }
105
125
  if (key === 'suffix') {
106
- if (entry !== '.' && entry !== ')')
126
+ if (entry !== '.' && entry !== ')') {
107
127
  invalid(`${path}.${key}`, 'expected . or )');
128
+ }
108
129
  result[key] = entry;
109
130
  }
110
131
  else {
111
- const schemes = ['decimal', 'lowerAlpha', 'upperAlpha', 'lowerRoman', 'upperRoman'];
132
+ const schemes = ['decimal',
133
+ 'lowerAlpha',
134
+ 'upperAlpha',
135
+ 'lowerRoman',
136
+ 'upperRoman'];
112
137
  if (!Array.isArray(entry) ||
113
138
  entry.length === 0 ||
114
- !entry.every((item) => typeof item === 'string' && schemes.includes(item))) {
139
+ !entry.every(item => typeof item === 'string' && schemes.includes(item))) {
115
140
  invalid(`${path}.${key}`, 'expected a nonempty array of numbering schemes');
116
141
  }
117
142
  result[key] = [...entry];
@@ -120,54 +145,68 @@ function orderedMarker(value, path) {
120
145
  return result;
121
146
  }
122
147
  function property(key, value, path) {
123
- if (value === undefined)
148
+ if (value === undefined) {
124
149
  return undefined;
125
- if (key === 'ordered')
150
+ }
151
+ if (key === 'ordered') {
126
152
  return orderedMarker(value, path);
127
- if (key === 'checked')
153
+ }
154
+ if (key === 'checked') {
128
155
  return normalizeStyle(value, checkbox, path);
129
- if (key === 'color' || key.endsWith('Color'))
156
+ }
157
+ if (key === 'color' || key.endsWith('Color')) {
130
158
  return normalizeEditorColor(value, path);
159
+ }
131
160
  if (key === 'fontFamily') {
132
- if (typeof value !== 'string' || value.length === 0)
161
+ if (typeof value !== 'string' || value.length === 0) {
133
162
  invalid(path, 'expected a nonempty font family');
163
+ }
134
164
  return value;
135
165
  }
136
166
  if (enums[key]) {
137
167
  const candidate = key === 'fontWeight' && typeof value === 'number' ? String(value) : value;
138
- if (typeof candidate !== 'string' || !enums[key].includes(candidate))
168
+ if (typeof candidate !== 'string' || !enums[key].includes(candidate)) {
139
169
  invalid(path, 'unsupported value');
170
+ }
140
171
  return candidate;
141
172
  }
142
- if (typeof value !== 'number' || !Number.isFinite(value))
173
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
143
174
  invalid(path, 'expected a finite number');
144
- if (['fontSize', 'lineHeight', 'size', 'scale'].includes(key) && value <= 0)
175
+ }
176
+ if (['fontSize', 'lineHeight', 'size', 'scale'].includes(key) && value <= 0) {
145
177
  invalid(path, 'expected a positive number');
146
- if (!key.startsWith('margin') && key !== 'letterSpacing' && value < 0)
178
+ }
179
+ if (!key.startsWith('margin') && key !== 'letterSpacing' && value < 0) {
147
180
  invalid(path, 'expected a nonnegative number');
181
+ }
148
182
  return value;
149
183
  }
150
184
  function normalizeStyle(value, allowed, path) {
151
185
  const raw = {};
152
186
  const ancestors = new Set();
153
187
  function append(entry, depth) {
154
- if (entry === false || entry == null)
188
+ if (entry === false || entry == null) {
155
189
  return;
156
- if (depth > 64)
190
+ }
191
+ if (depth > 64) {
157
192
  invalid(path, 'style arrays are nested too deeply');
193
+ }
158
194
  if (Array.isArray(entry)) {
159
- if (ancestors.has(entry))
195
+ if (ancestors.has(entry)) {
160
196
  invalid(path, 'cyclic style array');
197
+ }
161
198
  ancestors.add(entry);
162
- entry.forEach((item) => append(item, depth + 1));
199
+ entry.forEach(item => append(item, depth + 1));
163
200
  ancestors.delete(entry);
164
201
  return;
165
202
  }
166
- if (!record(entry))
203
+ if (!record(entry)) {
167
204
  invalid(path, 'expected a style object or array');
205
+ }
168
206
  for (const [key, field] of Object.entries(entry)) {
169
- if (!allowed.includes(key))
207
+ if (!allowed.includes(key)) {
170
208
  invalid(`${path}.${key}`, 'unsupported property');
209
+ }
171
210
  raw[key] = property(key, field, `${path}.${key}`);
172
211
  }
173
212
  }
@@ -177,8 +216,9 @@ function normalizeStyle(value, allowed, path) {
177
216
  for (const side of sides) {
178
217
  const axis = side === 'Top' || side === 'Bottom' ? 'Vertical' : 'Horizontal';
179
218
  const resolved = raw[`${prefix}${side}`] ?? raw[`${prefix}${axis}`] ?? raw[prefix];
180
- if (resolved !== undefined)
219
+ if (resolved !== undefined) {
181
220
  result[`${prefix}${side}`] = resolved;
221
+ }
182
222
  }
183
223
  delete result[prefix];
184
224
  delete result[`${prefix}Horizontal`];
@@ -187,40 +227,47 @@ function normalizeStyle(value, allowed, path) {
187
227
  for (const suffix of ['Width', 'Color']) {
188
228
  for (const side of sides) {
189
229
  const resolved = raw[`border${side}${suffix}`] ?? raw[`border${suffix}`];
190
- if (resolved !== undefined)
230
+ if (resolved !== undefined) {
191
231
  result[`border${side}${suffix}`] = resolved;
232
+ }
192
233
  }
193
234
  delete result[`border${suffix}`];
194
235
  }
195
236
  for (const corner of corners) {
196
237
  const resolved = raw[`border${corner}Radius`] ?? raw.borderRadius;
197
- if (resolved !== undefined)
238
+ if (resolved !== undefined) {
198
239
  result[`border${corner}Radius`] = resolved;
240
+ }
199
241
  }
200
242
  delete result.borderRadius;
201
243
  return result;
202
244
  }
203
245
  function normalizeEditorTheme(theme) {
204
- if (!record(theme))
246
+ if (!record(theme)) {
205
247
  invalid('theme', 'expected a named style map');
248
+ }
206
249
  const styles = {};
207
250
  const result = { version: 1 };
208
251
  for (const [key, value] of Object.entries(theme)) {
209
252
  if (key === 'toolbar') {
210
253
  if (value !== undefined) {
211
- if (!record(value))
254
+ if (!record(value)) {
212
255
  invalid('toolbar', 'expected toolbar configuration');
256
+ }
213
257
  result.toolbar = { ...value };
214
258
  }
215
259
  continue;
216
260
  }
217
- if (!Object.prototype.hasOwnProperty.call(fields, key))
261
+ if (!Object.prototype.hasOwnProperty.call(fields, key)) {
218
262
  invalid(key, 'unsupported element');
263
+ }
219
264
  const style = normalizeStyle(value, fields[key], key);
220
- if (Object.keys(style).length)
265
+ if (Object.keys(style).length) {
221
266
  styles[key] = style;
267
+ }
222
268
  }
223
- if (Object.keys(styles).length)
269
+ if (Object.keys(styles).length) {
224
270
  result.styles = styles;
271
+ }
225
272
  return result;
226
273
  }
@@ -91,7 +91,7 @@ export interface EditorHorizontalRuleStyle extends EditorBorderStyle, EditorMarg
91
91
  backgroundColor?: string;
92
92
  height?: number;
93
93
  }
94
- export interface EditorMentionStyle extends EditorInlineStyle, EditorBorderStyle {
94
+ export interface EditorMentionStyle extends EditorInlineStyle, EditorBorderStyle, EditorPaddingStyle {
95
95
  }
96
96
  export interface EditorStyleMap {
97
97
  content: EditorSurfaceStyle;
@@ -114,4 +114,8 @@ export interface EditorContentInsets {
114
114
  bottom?: number;
115
115
  left?: number;
116
116
  }
117
+ /**
118
+ * Mentions are configured on the mentions addon, not on EditorTheme; native
119
+ * still reads them from the theme payload.
120
+ */
117
121
  export declare function serializeEditorTheme(theme?: EditorTheme, mentionTheme?: EditorMentionTheme): string | undefined;
@@ -5,7 +5,7 @@ const EditorStyleSheetNormalization_1 = require("./EditorStyleSheetNormalization
5
5
  const EditorMentionThemeNormalization_1 = require("./EditorMentionThemeNormalization");
6
6
  function stripUndefined(value) {
7
7
  if (Array.isArray(value)) {
8
- return value.map((item) => stripUndefined(item)).filter((item) => item !== undefined);
8
+ return value.map(item => stripUndefined(item)).filter(item => item !== undefined);
9
9
  }
10
10
  if (value != null && typeof value === 'object') {
11
11
  const entries = Object.entries(value)
@@ -21,8 +21,10 @@ function stripUndefined(value) {
21
21
  }
22
22
  return value;
23
23
  }
24
- // Mentions are configured on the mentions addon, not on EditorTheme; native
25
- // still reads them from the theme payload.
24
+ /**
25
+ * Mentions are configured on the mentions addon, not on EditorTheme; native
26
+ * still reads them from the theme payload.
27
+ */
26
28
  function serializeEditorTheme(theme, mentionTheme) {
27
29
  const normalized = theme === undefined ? undefined : (0, EditorStyleSheetNormalization_1.normalizeEditorTheme)(theme);
28
30
  const cleanedTheme = normalized && (normalized.styles || normalized.toolbar)
@@ -1,7 +1,7 @@
1
1
  import { type EditorToolbarProps } from './EditorToolbarTypes';
2
2
  /**
3
3
  * A JavaScript formatting toolbar. `RichTextEditor` renders one for you
4
- * when `showToolbar` is set reach for this component directly only to place
4
+ * when `showToolbar` is set : reach for this component directly only to place
5
5
  * the toolbar somewhere the editor cannot, in which case wire every handler
6
6
  * to the editor's ref and feed it `activeState` and `historyState` from the
7
7
  * editor's callbacks.
@@ -7,7 +7,7 @@ const useEditorToolbarInteractions_1 = require("./useEditorToolbarInteractions")
7
7
  const useEditorToolbarPresentation_1 = require("./useEditorToolbarPresentation");
8
8
  /**
9
9
  * A JavaScript formatting toolbar. `RichTextEditor` renders one for you
10
- * when `showToolbar` is set reach for this component directly only to place
10
+ * when `showToolbar` is set : reach for this component directly only to place
11
11
  * the toolbar somewhere the editor cannot, in which case wire every handler
12
12
  * to the editor's ref and feed it `activeState` and `historyState` from the
13
13
  * editor's callbacks.
@@ -55,16 +55,16 @@ function areToolbarFrameListsEqual(left, right) {
55
55
  return left.every((frame, index) => areToolbarFramesEqual(frame, right[index]));
56
56
  }
57
57
  function notifyEditorToolbarFrameListeners() {
58
- exports.editorToolbarFrameListeners.forEach((listener) => listener());
58
+ exports.editorToolbarFrameListeners.forEach(listener => listener());
59
59
  }
60
60
  function notifyEditorToolbarMentionStateListeners() {
61
- exports.editorToolbarMentionStateListeners.forEach((listener) => listener());
61
+ exports.editorToolbarMentionStateListeners.forEach(listener => listener());
62
62
  }
63
63
  function getEditorToolbarFramesSnapshot(ownerId) {
64
64
  return Array.from(exports.editorToolbarFrames.values())
65
- .filter((registration) => registration.ownerId === ownerId ||
65
+ .filter(registration => registration.ownerId === ownerId ||
66
66
  (registration.ownerId == null && exports.activeEditorToolbarFrameOwnerId === ownerId))
67
- .map((registration) => registration.frame);
67
+ .map(registration => registration.frame);
68
68
  }
69
69
  function subscribeEditorToolbarMentionState(listener) {
70
70
  exports.editorToolbarMentionStateListeners.add(listener);
@@ -129,7 +129,7 @@ function useEditorToolbarFrames(ownerId) {
129
129
  (0, react_1.useEffect)(() => {
130
130
  const listener = () => {
131
131
  const nextFrames = getEditorToolbarFramesSnapshot(ownerId);
132
- setFrames((currentFrames) => areToolbarFrameListsEqual(currentFrames, nextFrames) ? currentFrames : nextFrames);
132
+ setFrames(currentFrames => areToolbarFrameListsEqual(currentFrames, nextFrames) ? currentFrames : nextFrames);
133
133
  };
134
134
  exports.editorToolbarFrameListeners.add(listener);
135
135
  listener();
@@ -34,9 +34,9 @@ export interface EditorToolbarMaterialIcon {
34
34
  /**
35
35
  * A toolbar button's icon:
36
36
  *
37
- * - `default` one of the package's built-in icons.
38
- * - `glyph` arbitrary text or an emoji, drawn as-is.
39
- * - `platform` per-platform native icons, with `fallbackText` when the
37
+ * - `default` : one of the package's built-in icons.
38
+ * - `glyph` : arbitrary text or an emoji, drawn as-is.
39
+ * - `platform` : per-platform native icons, with `fallbackText` when the
40
40
  * platform cannot resolve the named icon.
41
41
  */
42
42
  export type EditorToolbarIcon = {
@@ -67,14 +67,14 @@ export interface EditorToolbarButtonStyle {
67
67
  * name), an `icon`, an optional `key` (defaults to something derived from the
68
68
  * variant), and an optional `placement`.
69
69
  *
70
- * - `mark` toggles the named mark; active and enabled state come from the engine.
71
- * - `link` / `image` calls the editor's `onRequestLink` / `onRequestImage`.
72
- * - `heading` toggles the given heading level.
73
- * - `blockquote` toggles blockquote wrapping.
74
- * - `list` toggles the given list type.
75
- * - `command` runs an {@link EditorToolbarCommand}.
76
- * - `node` inserts the named node type, e.g. `'horizontalRule'`.
77
- * - `action` host-defined; calls `onToolbarAction` with its `key`, and the
70
+ * - `mark` : toggles the named mark; active and enabled state come from the engine.
71
+ * - `link` / `image` : calls the editor's `onRequestLink` / `onRequestImage`.
72
+ * - `heading` : toggles the given heading level.
73
+ * - `blockquote` : toggles blockquote wrapping.
74
+ * - `list` : toggles the given list type.
75
+ * - `command` : runs an {@link EditorToolbarCommand}.
76
+ * - `node` : inserts the named node type, e.g. `'horizontalRule'`.
77
+ * - `action` : host-defined; calls `onToolbarAction` with its `key`, and the
78
78
  * host supplies `isActive`/`isDisabled` since the engine knows nothing about it.
79
79
  */
80
80
  export type EditorToolbarLeafItem = ({
@@ -144,7 +144,7 @@ export type EditorToolbarLeafItem = ({
144
144
  /** What a group may contain. Groups do not nest. */
145
145
  export type EditorToolbarGroupChildItem = EditorToolbarLeafItem;
146
146
  /**
147
- * Several buttons collapsed behind one heading levels, say. The group
147
+ * Several buttons collapsed behind one : heading levels, say. The group
148
148
  * reports active when any child is active, and disabled when every child is.
149
149
  */
150
150
  export interface EditorToolbarGroupItem {
@@ -47,7 +47,7 @@ exports.DEFAULT_GLYPH_ICONS = {
47
47
  indentList: '→',
48
48
  outdentList: '←',
49
49
  lineBreak: '↵',
50
- horizontalRule: '',
50
+ horizontalRule: ':',
51
51
  undo: '↩',
52
52
  redo: '↪',
53
53
  };